diff --git a/Example/BonMot.xcodeproj/project.pbxproj b/Example/BonMot.xcodeproj/project.pbxproj index d7f70ee1..33cd9420 100644 --- a/Example/BonMot.xcodeproj/project.pbxproj +++ b/Example/BonMot.xcodeproj/project.pbxproj @@ -21,8 +21,6 @@ 730361E31C9B5CDD00987809 /* BONHumanReadableStringTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 730361E11C9B5CD300987809 /* BONHumanReadableStringTestCase.m */; }; CD64F15E1CA4DAC800042559 /* BONFigureTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = CD64F15D1CA4DAC800042559 /* BONFigureTestCase.m */; }; CD6DEFE11BF6ADF900676E2D /* BONBaseTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6DEFD61BF6ADF900676E2D /* BONBaseTestCase.m */; }; - CD6DEFE31BF6ADF900676E2D /* BONTextableTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6DEFD71BF6ADF900676E2D /* BONTextableTestCase.m */; }; - CD6DEFE51BF6ADF900676E2D /* BONChainEmptyTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6DEFD81BF6ADF900676E2D /* BONChainEmptyTestCase.m */; }; CD6DEFE71BF6ADF900676E2D /* BONDebugStringTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6DEFD91BF6ADF900676E2D /* BONDebugStringTestCase.m */; }; CD6DEFE91BF6ADF900676E2D /* BONDictionaryEqualityTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6DEFDA1BF6ADF900676E2D /* BONDictionaryEqualityTestCase.m */; }; CD6DEFEB1BF6ADF900676E2D /* BONIndentSpacerTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6DEFDB1BF6ADF900676E2D /* BONIndentSpacerTestCase.m */; }; @@ -66,7 +64,13 @@ CD6DF05A1BF6B98500676E2D /* NSDictionary+BONEquality.m in Sources */ = {isa = PBXBuildFile; fileRef = CD6DF04F1BF6B53100676E2D /* NSDictionary+BONEquality.m */; }; CD78701E1CA5F8EC00B2714F /* EBGaramond12-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = CD6DF03E1BF6AFAA00676E2D /* EBGaramond12-Regular.otf */; }; CDE658581C24ADD8009C7D09 /* BONUnderlineAndStrikethroughTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = CDE658571C24ADD8009C7D09 /* BONUnderlineAndStrikethroughTestCase.m */; }; + EC2F199E1CEA324900D9F1FE /* BONTagStylesTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = EC2F199C1CEA324300D9F1FE /* BONTagStylesTestCase.m */; }; + EC2F19A11CEBBAF900D9F1FE /* BONTagTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = EC2F199F1CEBBA9E00D9F1FE /* BONTagTestCase.m */; }; + EC433DB31C88B7D9001B3ABE /* BONTagMakeTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = EC433DB11C88B65B001B3ABE /* BONTagMakeTestCase.m */; }; EC433DB61C88BBDE001B3ABE /* BONUIKitUtilitiesTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = EC433DB41C88BBDB001B3ABE /* BONUIKitUtilitiesTestCase.m */; }; + EC433DB91C88DE5F001B3ABE /* TagStylesCell.m in Sources */ = {isa = PBXBuildFile; fileRef = EC433DB81C88DE5F001B3ABE /* TagStylesCell.m */; }; + EC433DBB1C88DEF7001B3ABE /* TagStylesCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = EC433DBA1C88DEF7001B3ABE /* TagStylesCell.xib */; }; + ECD4DB6B1CE3EA2700079675 /* BONTagComplexMakeTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = ECD4DB691CE3EA1F00079675 /* BONTagComplexMakeTestCase.m */; }; F6E9CEC93164745FB8BEB8FC /* Pods_BonMot_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E8BB0552A748FFBA2BD0BE4 /* Pods_BonMot_Example.framework */; }; /* End PBXBuildFile section */ @@ -166,7 +170,14 @@ CDE658571C24ADD8009C7D09 /* BONUnderlineAndStrikethroughTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BONUnderlineAndStrikethroughTestCase.m; sourceTree = ""; }; CFD6D97A946F2FEF294F4BBB /* Pods_BonMot_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BonMot_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EBE7037465B0F6F184875C40 /* Pods-BonMot_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BonMot_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-BonMot_Example/Pods-BonMot_Example.release.xcconfig"; sourceTree = ""; }; + EC2F199C1CEA324300D9F1FE /* BONTagStylesTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BONTagStylesTestCase.m; sourceTree = ""; }; + EC2F199F1CEBBA9E00D9F1FE /* BONTagTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BONTagTestCase.m; sourceTree = ""; }; + EC433DB11C88B65B001B3ABE /* BONTagMakeTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BONTagMakeTestCase.m; sourceTree = ""; }; EC433DB41C88BBDB001B3ABE /* BONUIKitUtilitiesTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BONUIKitUtilitiesTestCase.m; sourceTree = ""; }; + EC433DB71C88DE5F001B3ABE /* TagStylesCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TagStylesCell.h; sourceTree = ""; }; + EC433DB81C88DE5F001B3ABE /* TagStylesCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TagStylesCell.m; sourceTree = ""; }; + EC433DBA1C88DEF7001B3ABE /* TagStylesCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TagStylesCell.xib; sourceTree = ""; }; + ECD4DB691CE3EA1F00079675 /* BONTagComplexMakeTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BONTagComplexMakeTestCase.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -281,6 +292,10 @@ CD6DEFDA1BF6ADF900676E2D /* BONDictionaryEqualityTestCase.m */, 730361E11C9B5CD300987809 /* BONHumanReadableStringTestCase.m */, CD6DEFDB1BF6ADF900676E2D /* BONIndentSpacerTestCase.m */, + EC2F199C1CEA324300D9F1FE /* BONTagStylesTestCase.m */, + EC433DB11C88B65B001B3ABE /* BONTagMakeTestCase.m */, + ECD4DB691CE3EA1F00079675 /* BONTagComplexMakeTestCase.m */, + EC2F199F1CEBBA9E00D9F1FE /* BONTagTestCase.m */, CD6DEFDC1BF6ADF900676E2D /* BONPropertyClobberingTestCase.m */, CD6DEFDD1BF6ADF900676E2D /* BONTextAlignmentConstraintTestCase.m */, CD6DEFDE1BF6ADF900676E2D /* BONTextAlignmentTestCase.m */, @@ -360,6 +375,9 @@ CD6DF01D1BF6AE8200676E2D /* SpecialCharactersCell.h */, CD6DF01E1BF6AE8200676E2D /* SpecialCharactersCell.m */, CD6DF01F1BF6AE8200676E2D /* SpecialCharactersCell.xib */, + EC433DB71C88DE5F001B3ABE /* TagStylesCell.h */, + EC433DB81C88DE5F001B3ABE /* TagStylesCell.m */, + EC433DBA1C88DEF7001B3ABE /* TagStylesCell.xib */, CD6DF0201BF6AE8200676E2D /* TrackingCell.h */, CD6DF0211BF6AE8200676E2D /* TrackingCell.m */, CD6DF0221BF6AE8200676E2D /* TrackingCell.xib */, @@ -428,7 +446,7 @@ isa = PBXProject; attributes = { CLASSPREFIX = ""; - LastSwiftUpdateCheck = 0710; + LastSwiftUpdateCheck = 0730; LastUpgradeCheck = 0710; ORGANIZATIONNAME = "Zev Eisenberg"; }; @@ -467,6 +485,7 @@ CD6DF0251BF6AE8200676E2D /* BaselineCapHeightCell.xib in Resources */, CD6DF04D1BF6B50800676E2D /* Launch Screen.xib in Resources */, CD6DF0311BF6AE8200676E2D /* InlineImagesCell.xib in Resources */, + EC433DBB1C88DEF7001B3ABE /* TagStylesCell.xib in Resources */, CD6DF0351BF6AE8200676E2D /* ProgrammaticBaselineCapHeightCell.xib in Resources */, CD6DF02F1BF6AE8200676E2D /* IndentationCell.xib in Resources */, 6003F598195388D20070C39A /* InfoPlist.strings in Resources */, @@ -609,6 +628,7 @@ CD6DF02C1BF6AE8200676E2D /* FigureStyleCell.m in Sources */, CD6DF04A1BF6B37E00676E2D /* DummyAssetClass.m in Sources */, CD6DF0591BF6B7AF00676E2D /* DashedHairlineView.m in Sources */, + EC433DB91C88DE5F001B3ABE /* TagStylesCell.m in Sources */, CD6DF0381BF6AE8200676E2D /* TrackingCell.m in Sources */, CD6DF0231BF6AE8200676E2D /* AbstractCell.m in Sources */, CD6DEFF61BF6AE4C00676E2D /* AppDelegate.m in Sources */, @@ -624,15 +644,17 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + EC2F199E1CEA324900D9F1FE /* BONTagStylesTestCase.m in Sources */, EC433DB61C88BBDE001B3ABE /* BONUIKitUtilitiesTestCase.m in Sources */, + EC2F19A11CEBBAF900D9F1FE /* BONTagTestCase.m in Sources */, CD6DF05A1BF6B98500676E2D /* NSDictionary+BONEquality.m in Sources */, CD6DF04B1BF6B37E00676E2D /* DummyAssetClass.m in Sources */, 730361E31C9B5CDD00987809 /* BONHumanReadableStringTestCase.m in Sources */, - CD6DEFE51BF6ADF900676E2D /* BONChainEmptyTestCase.m in Sources */, + ECD4DB6B1CE3EA2700079675 /* BONTagComplexMakeTestCase.m in Sources */, CD6DEFED1BF6ADF900676E2D /* BONPropertyClobberingTestCase.m in Sources */, CD6DEFF11BF6ADF900676E2D /* BONTextAlignmentTestCase.m in Sources */, CD6DEFE11BF6ADF900676E2D /* BONBaseTestCase.m in Sources */, - CD6DEFE31BF6ADF900676E2D /* BONTextableTestCase.m in Sources */, + EC433DB31C88B7D9001B3ABE /* BONTagMakeTestCase.m in Sources */, CDE658581C24ADD8009C7D09 /* BONUnderlineAndStrikethroughTestCase.m in Sources */, CD6DEFF31BF6ADF900676E2D /* BONTrackingTestCase.m in Sources */, CD64F15E1CA4DAC800042559 /* BONFigureTestCase.m in Sources */, diff --git a/Example/BonMot.xcodeproj/xcshareddata/xcschemes/BonMot-Example.xcscheme b/Example/BonMot.xcodeproj/xcshareddata/xcschemes/BonMot-Example.xcscheme index 5fe6e4d7..301b5c4c 100644 --- a/Example/BonMot.xcodeproj/xcshareddata/xcschemes/BonMot-Example.xcscheme +++ b/Example/BonMot.xcodeproj/xcshareddata/xcschemes/BonMot-Example.xcscheme @@ -28,7 +28,7 @@ buildForAnalyzing = "YES"> diff --git a/Example/BonMot/Cells/TagStylesCell.h b/Example/BonMot/Cells/TagStylesCell.h new file mode 100644 index 00000000..3fd450ca --- /dev/null +++ b/Example/BonMot/Cells/TagStylesCell.h @@ -0,0 +1,13 @@ +// +// TagStylesCell.h +// BonMot +// +// Created by Nora Trapp on 3/3/16. +// Copyright © 2016 Zev Eisenberg. All rights reserved. +// + +#import "AbstractCell.h" + +@interface TagStylesCell : AbstractCell + +@end diff --git a/Example/BonMot/Cells/TagStylesCell.m b/Example/BonMot/Cells/TagStylesCell.m new file mode 100644 index 00000000..71e28e6f --- /dev/null +++ b/Example/BonMot/Cells/TagStylesCell.m @@ -0,0 +1,41 @@ +// +// TagStylesCell.m +// BonMot +// +// Created by Nora Trapp on 3/3/16. +// Copyright © 2016 Zev Eisenberg. All rights reserved. +// + +#import "TagStylesCell.h" + +@interface TagStylesCell () + +@property (weak, nonatomic) IBOutlet UILabel *label; + +@end + +@implementation TagStylesCell + ++ (NSString *)title +{ + return @"Tag Styles"; +} + +- (void)awakeFromNib +{ + [super awakeFromNib]; + + BONChain *boldChain = BONChain.new.fontNameAndSize(@"Baskerville-Bold", 15); + BONChain *italicChain = BONChain.new.fontNameAndSize(@"Baskerville-Italic", 15); + + BONChain *baseChain = BONChain.new.fontNameAndSize(@"Baskerville", 17) + .tagStyles(@{ @"bold" : boldChain, + @"italic" : italicChain }) + .string(@"This text contains a \\ tag.\nThis text contains an \\ tag."); + + self.label.attributedText = baseChain.attributedString; + + [self.label layoutIfNeeded]; // For auto-sizing cells +} + +@end diff --git a/Example/BonMot/Cells/TagStylesCell.xib b/Example/BonMot/Cells/TagStylesCell.xib new file mode 100644 index 00000000..531b254f --- /dev/null +++ b/Example/BonMot/Cells/TagStylesCell.xib @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/BonMot/RootViewController.m b/Example/BonMot/RootViewController.m index f23161f3..b2b8b902 100644 --- a/Example/BonMot/RootViewController.m +++ b/Example/BonMot/RootViewController.m @@ -20,6 +20,7 @@ #import "SpecialCharactersCell.h" #import "BaselineOffsetCell.h" #import "ConcatenationCell.h" +#import "TagStylesCell.h" @interface RootViewController () @@ -48,6 +49,7 @@ - (void)viewDidLoad [SpecialCharactersCell class], [BaselineOffsetCell class], [ConcatenationCell class], + [TagStylesCell class] ]; for (Class CellClass in self.cellClasses) { diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 13bf0dcc..19b9d0de 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -11,7 +11,7 @@ DEPENDENCIES: EXTERNAL SOURCES: BonMot: - :path: "../" + :path: ../ SPEC CHECKSUMS: BonMot: e8d7b8920dc9363291c308e853ccb5784d5de4bd diff --git a/Example/Pods/Headers/Private/BonMot/BONTag.h b/Example/Pods/Headers/Private/BonMot/BONTag.h new file mode 120000 index 00000000..b2872707 --- /dev/null +++ b/Example/Pods/Headers/Private/BonMot/BONTag.h @@ -0,0 +1 @@ +../../../../../Pod/Classes/BONTag.h \ No newline at end of file diff --git a/Example/Pods/Headers/Private/BonMot/BONTag_Private.h b/Example/Pods/Headers/Private/BonMot/BONTag_Private.h new file mode 120000 index 00000000..92a7f9cf --- /dev/null +++ b/Example/Pods/Headers/Private/BonMot/BONTag_Private.h @@ -0,0 +1 @@ +../../../../../Pod/Classes/BONTag_Private.h \ No newline at end of file diff --git a/Example/Pods/Manifest.lock b/Example/Pods/Manifest.lock index 13bf0dcc..19b9d0de 100644 --- a/Example/Pods/Manifest.lock +++ b/Example/Pods/Manifest.lock @@ -11,7 +11,7 @@ DEPENDENCIES: EXTERNAL SOURCES: BonMot: - :path: "../" + :path: ../ SPEC CHECKSUMS: BonMot: e8d7b8920dc9363291c308e853ccb5784d5de4bd diff --git a/Example/Pods/Pods.xcodeproj/project.pbxproj b/Example/Pods/Pods.xcodeproj/project.pbxproj index f3077bea..91c0a080 100644 --- a/Example/Pods/Pods.xcodeproj/project.pbxproj +++ b/Example/Pods/Pods.xcodeproj/project.pbxproj @@ -10,54 +10,33 @@ 46 objects - 00D954F3747AA02DCA0A3809CFCD2B17 + 0080E3345719F60099A110B1C33C05F2 fileRef - FAB64E9029A05F73B2B4A250B105E030 - isa - PBXBuildFile - settings - - ATTRIBUTES - - Public - - - - 01E1BE6EC18457D2F88E270800F860C3 - - fileRef - 085FB431F3FE96089534EAAC6FE8BDF8 - isa - PBXBuildFile - settings - - ATTRIBUTES - - Public - - - - 0219B207E1DFB298AE0638868013EE2A - - fileRef - C3B7BDF5CE5CB8F095FE12DA55D9A9BB + 17E86E730C75BDA8893FD85A83CD3723 isa PBXBuildFile - 085FB431F3FE96089534EAAC6FE8BDF8 + 055C51A91D330461B7E2BE7BCD601A5B includeInIndex 1 isa PBXFileReference lastKnownFileType - sourcecode.c.h + sourcecode.c.objc path - BONSpecial.h + BONTag.m sourceTree <group> + 06821309EE78916F536F3C35B4FAA4B2 + + fileRef + D4B83982FE17B01A0A18B9382CE242A7 + isa + PBXBuildFile + 0918C87910956FED935D88D6DB334CFB includeInIndex @@ -71,12 +50,32 @@ sourceTree <group> - 0E4C967D9164B39B23F7D8574CADABE0 + 0D51A7EEC01DE4DFD00FAFC8910C3101 fileRef - D744BF15A46AA8823523F480524DA6D1 + 7C6D0196353D8E5AC65F6AC29B7C8777 isa PBXBuildFile + settings + + ATTRIBUTES + + Public + + + + 104DDEC1C49A667B0F3B8AD43A9B20D2 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + BONCompatibility.h + sourceTree + <group> 10BC01F663CA7849D1A21B7F337370F0 @@ -125,7 +124,7 @@ children - BE8601DA8860F7392B95146FC34AA1C7 + 684EC576FF4124037A49D8AB0E73113E isa PBXGroup @@ -134,29 +133,30 @@ sourceTree <group> - 13394710B1F81A23CB801EC414777F81 + 1511D8A08DEB71B22A57C315F7151F13 includeInIndex 1 isa PBXFileReference - lastKnownFileType - sourcecode.c.h path - BonMot.h + BonMot.modulemap sourceTree <group> - 1511D8A08DEB71B22A57C315F7151F13 + 160CA269F2AAB7710B6A6740751DA459 - includeInIndex - 1 + fileRef + 47FFC4B90C298DBEA36FB326D190DBAB isa - PBXFileReference - path - BonMot.modulemap - sourceTree - <group> + PBXBuildFile + settings + + ATTRIBUTES + + Public + + 179F4E16F04D6C2B2FCF3166BA15B72A @@ -220,41 +220,21 @@ name Release - 18340F12838DEE43507667CC74401EB1 - - children - - 6E7E5AF37923BFA48D6994B9BFC6535F - C3B7BDF5CE5CB8F095FE12DA55D9A9BB - - isa - PBXGroup - name - iOS - sourceTree - <group> - - 1BB8C8B0D6FFC76CF6E70FF4AAFD9A79 + 17C1148DA9BA0313110FC2436C3C936F - includeInIndex - 1 + fileRef + A8EE48AA815968BBE1E66AB3493C1EAA isa - PBXFileReference - lastKnownFileType - sourcecode.c.objc - path - BONChain.m - sourceTree - <group> + PBXBuildFile - 20A63EF13894B3AA22B933560AA53F18 + 17E3669F8B32E52BE6C792E64AED7DA7 fileRef - 71C80B4B47FA325B1D150662D2EF15C2 + 6E7E5AF37923BFA48D6994B9BFC6535F isa PBXBuildFile - 212D5BC776EC758921C6BA007E2B182E + 17E86E730C75BDA8893FD85A83CD3723 includeInIndex 1 @@ -263,38 +243,38 @@ lastKnownFileType sourcecode.c.objc path - BONText.m + NSAttributedString+BonMotUtilities.m sourceTree <group> - 223A0AE1B4C1AB6C22803C3F6F4E7C36 + 18340F12838DEE43507667CC74401EB1 - fileRef - 946B30FF1BFF268E9AA4A27BAC2E5ECD + children + + 6E7E5AF37923BFA48D6994B9BFC6535F + C3B7BDF5CE5CB8F095FE12DA55D9A9BB + isa - PBXBuildFile - settings - - ATTRIBUTES - - Public - - + PBXGroup + name + iOS + sourceTree + <group> - 26DAE09174C6886D8EFBA0B3C9BF3BDB + 19F16EEB16822AFB8041C4343BE170DA includeInIndex 1 isa PBXFileReference lastKnownFileType - sourcecode.c.objc + sourcecode.c.h path - Pods-BonMot_Tests-dummy.m + BonMot.h sourceTree <group> - 28D4FDE16DE8250F25DC730765DC221B + 1F7D0CFA4095C319AEDC668D27E01781 includeInIndex 1 @@ -303,11 +283,11 @@ lastKnownFileType sourcecode.c.h path - BONCompatibility.h + NSAttributedString+BonMotUtilities.h sourceTree <group> - 29A9CD70F27600DBF695A88C9FF0AF50 + 1FBDCB556EABB04AC7BF1AE02CCFD08D includeInIndex 1 @@ -316,11 +296,25 @@ lastKnownFileType sourcecode.c.objc path - NSAttributedString+BonMotUtilities.m + BONSpecial.m sourceTree <group> - 2AA3029BF1F6DE94522F0133B389D5F1 + 216E0E24328F1BE6ACC478A93004F78B + + fileRef + BCCC75202C930C2B7DD65DF3E5EEDF8D + isa + PBXBuildFile + settings + + ATTRIBUTES + + Public + + + + 26DAE09174C6886D8EFBA0B3C9BF3BDB includeInIndex 1 @@ -329,14 +323,14 @@ lastKnownFileType sourcecode.c.objc path - BONSpecial.m + Pods-BonMot_Tests-dummy.m sourceTree <group> - 2C763DD88B7C65E2E698491B831F3F3D + 2BF8A970211510DABEA917F79FBE0240 fileRef - 13394710B1F81A23CB801EC414777F81 + 9CC10C208517AA62B5773BA59C750FCB isa PBXBuildFile settings @@ -385,17 +379,10 @@ sourceTree <group> - 304E716C2718C5366409757C167F395B - - fileRef - 65E326689AAFF02F1507650324813E89 - isa - PBXBuildFile - - 32467CAF5979C65E3DB3C11F76C85B53 + 323FBE9C4D2D6E9803B27A7332776538 fileRef - 7656BC2502D0F175B42AA5251C923450 + 1F7D0CFA4095C319AEDC668D27E01781 isa PBXBuildFile settings @@ -432,10 +419,23 @@ sourceTree <group> - 382422134FD5BE7524B02520A21D6690 + 38A2136A23298CA3E69A4E692A4317E9 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + BONText.m + sourceTree + <group> + + 38F8823CD9270173773704F2E964D6BB fileRef - 29A9CD70F27600DBF695A88C9FF0AF50 + 61712505D3A454DA4C6DB55A419A8F77 isa PBXBuildFile @@ -463,28 +463,6 @@ sourceTree <group> - 420D64DDCD3ADF1EC24AF6BB68D18AFC - - buildActionMask - 2147483647 - files - - FC8B3E0621B411FD79396927F3D0BC13 - 478830357B13B6F648D4E1ED203CD27A - 9ECD0A9EB5DCC43C18F291D874BE6207 - 73F001AAAAAB975ABFFA01EAF7E8FCBC - A357495232D4BF470F4CE2BC59C9FC09 - 382422134FD5BE7524B02520A21D6690 - AE93C94C5CFC1F805B75EE4FD8FFD8E3 - 0E4C967D9164B39B23F7D8574CADABE0 - 304E716C2718C5366409757C167F395B - 20A63EF13894B3AA22B933560AA53F18 - - isa - PBXSourcesBuildPhase - runOnlyForDeploymentPostprocessing - 0 - 433CD3331B6C3787F473C941B61FC68F children @@ -518,12 +496,18 @@ isa PBXBuildFile - 478830357B13B6F648D4E1ED203CD27A + 47FFC4B90C298DBEA36FB326D190DBAB - fileRef - D4B83982FE17B01A0A18B9382CE242A7 + includeInIndex + 1 isa - PBXBuildFile + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + BONChain.h + sourceTree + <group> 4C4450E89E7003A9B4F4B4AA685F16EA @@ -562,6 +546,35 @@ sourceTree <group> + 4F5FFDF0F9B2BE42D4027C887021A16F + + buildActionMask + 2147483647 + files + + 160CA269F2AAB7710B6A6740751DA459 + 88A895FA00365308CE594B482FF5FEC4 + 69F31D72D1D25BFE2ACE445415C13988 + 8EDCFA33B79E29125AFB799A710C0DB5 + 6A11AA127CAD88D0423AFDA9D76F657D + 6AFBB9136CA124A7592C60C3219064D2 + D09F361B9D1EE649D7E855E3A4727820 + E3C1E20D4E3714E84B74E812591B9970 + 96413C2DBE2E96EBC51E56737CFCBA6A + AD22D5D55F424595890CEBFBC370239C + 216E0E24328F1BE6ACC478A93004F78B + C9426127C7D9364DA549FFA1CBAAE21E + 323FBE9C4D2D6E9803B27A7332776538 + 0D51A7EEC01DE4DFD00FAFC8910C3101 + F70AB5068C980C99E1D3CB1D0EEC3356 + 2BF8A970211510DABEA917F79FBE0240 + FB5E82DA859C42DFF27B99BDC321C21F + + isa + PBXHeadersBuildPhase + runOnlyForDeploymentPostprocessing + 0 + 51D4DC924673736C887833A213B8733A includeInIndex @@ -588,19 +601,6 @@ runOnlyForDeploymentPostprocessing 0 - 53BEB5EF5FD30BA79950A4BD482E3F3B - - includeInIndex - 1 - isa - PBXFileReference - lastKnownFileType - sourcecode.c.h - path - UIImage+BonMotUtilities.h - sourceTree - <group> - 55572D20A461EDABEAD1B8C1D03101A2 explicitFileType @@ -678,118 +678,190 @@ name Debug - 621B433020566394142071265EABE9A0 + 60209B4FEFC22D3FDD07669CBB7A5D4A - includeInIndex - 1 + fileRef + 055C51A91D330461B7E2BE7BCD601A5B isa - PBXFileReference - lastKnownFileType - text.script.sh - path - Pods-BonMot_Example-resources.sh - sourceTree - <group> + PBXBuildFile - 6300608DB9CA45054481077A506554A4 + 61712505D3A454DA4C6DB55A419A8F77 includeInIndex 1 isa PBXFileReference lastKnownFileType - sourcecode.c.h + sourcecode.c.objc path - UITextView+BonMotUtilities.h + BONChain.m sourceTree <group> - 65E326689AAFF02F1507650324813E89 + 621B433020566394142071265EABE9A0 includeInIndex 1 isa PBXFileReference lastKnownFileType - sourcecode.c.objc + text.script.sh path - UITextField+BonMotUtilities.m + Pods-BonMot_Example-resources.sh sourceTree <group> - 690A840FE201A4B932BB6539F2BA5173 + 6300608DB9CA45054481077A506554A4 includeInIndex 1 isa PBXFileReference + lastKnownFileType + sourcecode.c.h path - Pods-BonMot_Tests.modulemap + UITextView+BonMotUtilities.h sourceTree <group> - 6C3A2FADB025B64FEEAE2DFC85035890 + 65901492A3F64EDD919D5D15AE892F84 - explicitFileType - wrapper.framework - includeInIndex - 0 - isa - PBXFileReference - name - Pods_BonMot_Tests.framework - path - Pods_BonMot_Tests.framework - sourceTree - BUILT_PRODUCTS_DIR + baseConfigurationReference + 907B9450CCC329D3E8FFEB42C73C99EE + buildSettings + + CODE_SIGN_IDENTITY[sdk=iphoneos*] + iPhone Developer + CURRENT_PROJECT_VERSION + 1 + DEFINES_MODULE + YES + DYLIB_COMPATIBILITY_VERSION + 1 + DYLIB_CURRENT_VERSION + 1 + DYLIB_INSTALL_NAME_BASE + @rpath + ENABLE_STRICT_OBJC_MSGSEND + YES + GCC_PREFIX_HEADER + Target Support Files/BonMot/BonMot-prefix.pch + INFOPLIST_FILE + Target Support Files/BonMot/Info.plist + INSTALL_PATH + $(LOCAL_LIBRARY_DIR)/Frameworks + IPHONEOS_DEPLOYMENT_TARGET + 8.0 + LD_RUNPATH_SEARCH_PATHS + + $(inherited) + @executable_path/Frameworks + @loader_path/Frameworks + + MODULEMAP_FILE + Target Support Files/BonMot/BonMot.modulemap + MTL_ENABLE_DEBUG_INFO + NO + PRODUCT_NAME + BonMot + SDKROOT + iphoneos + SKIP_INSTALL + YES + TARGETED_DEVICE_FAMILY + 1,2 + VERSIONING_SYSTEM + apple-generic + VERSION_INFO_PREFIX + + + isa + XCBuildConfiguration + name + Release - 6E7E5AF37923BFA48D6994B9BFC6535F + 65E326689AAFF02F1507650324813E89 + includeInIndex + 1 isa PBXFileReference lastKnownFileType - wrapper.framework + sourcecode.c.objc + path + UITextField+BonMotUtilities.m + sourceTree + <group> + + 684EC576FF4124037A49D8AB0E73113E + + children + + 19F16EEB16822AFB8041C4343BE170DA + FD46195AAC067287FDF6898C915D60C0 + + isa + PBXGroup name - Foundation.framework + Pod path - Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/Foundation.framework + Pod sourceTree - DEVELOPER_DIR + <group> - 71C80B4B47FA325B1D150662D2EF15C2 + 6868B12CE64A02DC58A825D43FCD6AED includeInIndex 1 isa PBXFileReference lastKnownFileType - sourcecode.c.objc + sourcecode.c.h path - UITextView+BonMotUtilities.m + BONTag_Private.h sourceTree <group> - 726940D4C81A5A90179226804F99A3A0 + 690A840FE201A4B932BB6539F2BA5173 includeInIndex 1 isa PBXFileReference - lastKnownFileType - sourcecode.c.h path - BONChain.h + Pods-BonMot_Tests.modulemap sourceTree <group> - 73F001AAAAAB975ABFFA01EAF7E8FCBC + 69F31D72D1D25BFE2ACE445415C13988 fileRef - 212D5BC776EC758921C6BA007E2B182E + CA7D9F5FC702DA9A09A5F3128839B84A isa PBXBuildFile + settings + + ATTRIBUTES + + Public + + - 7656BC2502D0F175B42AA5251C923450 + 6A11AA127CAD88D0423AFDA9D76F657D + + fileRef + 19F16EEB16822AFB8041C4343BE170DA + isa + PBXBuildFile + settings + + ATTRIBUTES + + Public + + + + 6A767B48037B33454A2A30879F170FDE includeInIndex 1 @@ -798,39 +870,14 @@ lastKnownFileType sourcecode.c.h path - NSAttributedString+BonMotUtilities.h + BONSpecial.h sourceTree <group> - 7960D5870921BF8F1FE6568BBEB009B5 - - buildConfigurationList - 9DA064760DB15CDFD92BBF5A6F53276A - buildPhases - - 420D64DDCD3ADF1EC24AF6BB68D18AFC - 806F7E65027C5EA011501EEDA6C86696 - C7AC1A115C88CDA55C8F507E58A1DDBF - - buildRules - - dependencies - - isa - PBXNativeTarget - name - BonMot - productName - BonMot - productReference - 987B388AEB3482E871DC28F0AE48017A - productType - com.apple.product-type.framework - - 79C19A2B453E4B0567FF6F03C5B1B0EA + 6AFBB9136CA124A7592C60C3219064D2 fileRef - 53BEB5EF5FD30BA79950A4BD482E3F3B + 6A767B48037B33454A2A30879F170FDE isa PBXBuildFile settings @@ -841,6 +888,47 @@ + 6C3A2FADB025B64FEEAE2DFC85035890 + + explicitFileType + wrapper.framework + includeInIndex + 0 + isa + PBXFileReference + name + Pods_BonMot_Tests.framework + path + Pods_BonMot_Tests.framework + sourceTree + BUILT_PRODUCTS_DIR + + 6E7E5AF37923BFA48D6994B9BFC6535F + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + Foundation.framework + path + Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.0.sdk/System/Library/Frameworks/Foundation.framework + sourceTree + DEVELOPER_DIR + + 71C80B4B47FA325B1D150662D2EF15C2 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + UITextView+BonMotUtilities.m + sourceTree + <group> + 7AA4AFFEF440529E9D52D5EAC848B442 includeInIndex @@ -854,6 +942,19 @@ sourceTree <group> + 7C6D0196353D8E5AC65F6AC29B7C8777 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + UIImage+BonMotUtilities.h + sourceTree + <group> + 7DB346D0F39D3F0E887471402A8071AB children @@ -869,95 +970,33 @@ sourceTree <group> - 806F7E65027C5EA011501EEDA6C86696 + 7FE1C74423FCE3D210EDB21FE1B4AC15 buildActionMask 2147483647 files - 9256FE898C951D38DA2ACB8BE4AC0C49 - 0219B207E1DFB298AE0638868013EE2A + 17E3669F8B32E52BE6C792E64AED7DA7 + 9D19B2AC9B6CBC83D7017C1DBD745057 isa PBXFrameworksBuildPhase runOnlyForDeploymentPostprocessing 0 - 82CA6517CFCBD1CC5D4D001E9D7A6427 + 80B3B962FB551BA93445CCBECA715AC8 fileRef - 6E7E5AF37923BFA48D6994B9BFC6535F + 38A2136A23298CA3E69A4E692A4317E9 isa PBXBuildFile - 840456DBAF5B6C919D75BBE641E11DDD - - baseConfigurationReference - 907B9450CCC329D3E8FFEB42C73C99EE - buildSettings - - CODE_SIGN_IDENTITY[sdk=iphoneos*] - iPhone Developer - CURRENT_PROJECT_VERSION - 1 - DEFINES_MODULE - YES - DYLIB_COMPATIBILITY_VERSION - 1 - DYLIB_CURRENT_VERSION - 1 - DYLIB_INSTALL_NAME_BASE - @rpath - ENABLE_STRICT_OBJC_MSGSEND - YES - GCC_PREFIX_HEADER - Target Support Files/BonMot/BonMot-prefix.pch - INFOPLIST_FILE - Target Support Files/BonMot/Info.plist - INSTALL_PATH - $(LOCAL_LIBRARY_DIR)/Frameworks - IPHONEOS_DEPLOYMENT_TARGET - 8.0 - LD_RUNPATH_SEARCH_PATHS - - $(inherited) - @executable_path/Frameworks - @loader_path/Frameworks - - MODULEMAP_FILE - Target Support Files/BonMot/BonMot.modulemap - MTL_ENABLE_DEBUG_INFO - YES - PRODUCT_NAME - BonMot - SDKROOT - iphoneos - SKIP_INSTALL - YES - TARGETED_DEVICE_FAMILY - 1,2 - VERSIONING_SYSTEM - apple-generic - VERSION_INFO_PREFIX - - - isa - XCBuildConfiguration - name - Debug - - 854FD81E8C8A6D67C6177C34537726A8 + 82CA6517CFCBD1CC5D4D001E9D7A6427 - includeInIndex - 1 + fileRef + 6E7E5AF37923BFA48D6994B9BFC6535F isa - PBXFileReference - lastKnownFileType - sourcecode.c.objc - path - UIImage+BonMotUtilities.m - sourceTree - <group> + PBXBuildFile 881C9B3E63E37A68AED32A58F7C155D3 @@ -979,6 +1018,20 @@ sourceTree <group> + 88A895FA00365308CE594B482FF5FEC4 + + fileRef + 104DDEC1C49A667B0F3B8AD43A9B20D2 + isa + PBXBuildFile + settings + + ATTRIBUTES + + Public + + + 88E07F9197F21D50F764DBA2D8F1C787 containerPortal @@ -988,7 +1041,7 @@ proxyType 1 remoteGlobalIDString - 7960D5870921BF8F1FE6568BBEB009B5 + 936C2599775DA43BC28A7798C3663474 remoteInfo BonMot @@ -1005,20 +1058,6 @@ sourceTree <group> - 8B63557B3C823AE3067A0A62BC06400A - - fileRef - 6300608DB9CA45054481077A506554A4 - isa - PBXBuildFile - settings - - ATTRIBUTES - - Public - - - 8CC583263BA5A300A8153C1A29EAB54E includeInIndex @@ -1067,6 +1106,20 @@ sourceTree <group> + 8EDCFA33B79E29125AFB799A710C0DB5 + + fileRef + 10BC01F663CA7849D1A21B7F337370F0 + isa + PBXBuildFile + settings + + ATTRIBUTES + + Public + + + 907B9450CCC329D3E8FFEB42C73C99EE includeInIndex @@ -1080,10 +1133,42 @@ sourceTree <group> - 91095713BC69DBA99E10B37AADC85750 + 936C2599775DA43BC28A7798C3663474 + + buildConfigurationList + AC0079E3C3B20A676835CB2D0B1573A9 + buildPhases + + CB0AE9160D3D0094A5DAE320035944A6 + 7FE1C74423FCE3D210EDB21FE1B4AC15 + 4F5FFDF0F9B2BE42D4027C887021A16F + + buildRules + + dependencies + + isa + PBXNativeTarget + name + BonMot + productName + BonMot + productReference + 987B388AEB3482E871DC28F0AE48017A + productType + com.apple.product-type.framework + + 95FE86EF52CFAE2CC062808BF065C3D7 fileRef - 8CC583263BA5A300A8153C1A29EAB54E + B40764AE97F30C2BAAD83E38C5B52A6D + isa + PBXBuildFile + + 96413C2DBE2E96EBC51E56737CFCBA6A + + fileRef + FC5E1EE731C93D8B60AB0AEA8CEF4500 isa PBXBuildFile settings @@ -1094,26 +1179,13 @@ - 9256FE898C951D38DA2ACB8BE4AC0C49 + 96647DB5078B8E474BF86755E8A3557A fileRef - 6E7E5AF37923BFA48D6994B9BFC6535F + D744BF15A46AA8823523F480524DA6D1 isa PBXBuildFile - 946B30FF1BFF268E9AA4A27BAC2E5ECD - - includeInIndex - 1 - isa - PBXFileReference - lastKnownFileType - sourcecode.c.h - path - BONTextable.h - sourceTree - <group> - 987B388AEB3482E871DC28F0AE48017A explicitFileType @@ -1175,26 +1247,68 @@ isa PBXBuildFile - 9DA064760DB15CDFD92BBF5A6F53276A + 9D19B2AC9B6CBC83D7017C1DBD745057 - buildConfigurations - - 840456DBAF5B6C919D75BBE641E11DDD - B95F26D83A85C76C3949416F60C7E1E1 - - defaultConfigurationIsVisible - 0 - defaultConfigurationName - Release + fileRef + C3B7BDF5CE5CB8F095FE12DA55D9A9BB isa - XCConfigurationList + PBXBuildFile - 9ECD0A9EB5DCC43C18F291D874BE6207 + 9DA7495C431B48DDE89B63D01FC1BC30 - fileRef - 2AA3029BF1F6DE94522F0133B389D5F1 + baseConfigurationReference + 907B9450CCC329D3E8FFEB42C73C99EE + buildSettings + + CODE_SIGN_IDENTITY[sdk=iphoneos*] + iPhone Developer + CURRENT_PROJECT_VERSION + 1 + DEFINES_MODULE + YES + DYLIB_COMPATIBILITY_VERSION + 1 + DYLIB_CURRENT_VERSION + 1 + DYLIB_INSTALL_NAME_BASE + @rpath + ENABLE_STRICT_OBJC_MSGSEND + YES + GCC_PREFIX_HEADER + Target Support Files/BonMot/BonMot-prefix.pch + INFOPLIST_FILE + Target Support Files/BonMot/Info.plist + INSTALL_PATH + $(LOCAL_LIBRARY_DIR)/Frameworks + IPHONEOS_DEPLOYMENT_TARGET + 8.0 + LD_RUNPATH_SEARCH_PATHS + + $(inherited) + @executable_path/Frameworks + @loader_path/Frameworks + + MODULEMAP_FILE + Target Support Files/BonMot/BonMot.modulemap + MTL_ENABLE_DEBUG_INFO + YES + PRODUCT_NAME + BonMot + SDKROOT + iphoneos + SKIP_INSTALL + YES + TARGETED_DEVICE_FAMILY + 1,2 + VERSIONING_SYSTEM + apple-generic + VERSION_INFO_PREFIX + + isa - PBXBuildFile + XCBuildConfiguration + name + Debug A03AFD7A68BE8224BF54B742392FB216 @@ -1218,14 +1332,14 @@ proxyType 1 remoteGlobalIDString - 7960D5870921BF8F1FE6568BBEB009B5 + 936C2599775DA43BC28A7798C3663474 remoteInfo BonMot - A357495232D4BF470F4CE2BC59C9FC09 + A42782D2876C5E4DF94A9F5A68D9AC59 fileRef - B40764AE97F30C2BAAD83E38C5B52A6D + 1FBDCB556EABB04AC7BF1AE02CCFD08D isa PBXBuildFile @@ -1236,7 +1350,7 @@ name BonMot target - 7960D5870921BF8F1FE6568BBEB009B5 + 936C2599775DA43BC28A7798C3663474 targetProxy 88E07F9197F21D50F764DBA2D8F1C787 @@ -1326,6 +1440,19 @@ name Debug + A8EE48AA815968BBE1E66AB3493C1EAA + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + UIImage+BonMotUtilities.m + sourceTree + <group> + AA8AFAE9DD36173AD2A960E6AA0A0B21 buildConfigurations @@ -1340,27 +1467,34 @@ isa XCConfigurationList - AE604A23841D67F0735CD4518EB98573 + AC0079E3C3B20A676835CB2D0B1573A9 + + buildConfigurations + + 9DA7495C431B48DDE89B63D01FC1BC30 + 65901492A3F64EDD919D5D15AE892F84 + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + AD22D5D55F424595890CEBFBC370239C fileRef - 9CC10C208517AA62B5773BA59C750FCB + B0F2F8A5622AF131C09AB271FA889955 isa PBXBuildFile settings ATTRIBUTES - Public + Private - AE93C94C5CFC1F805B75EE4FD8FFD8E3 - - fileRef - 854FD81E8C8A6D67C6177C34537726A8 - isa - PBXBuildFile - B0AFE2D343DE0EA96E89CE31EF4A1EC4 isa @@ -1368,10 +1502,23 @@ name BonMot target - 7960D5870921BF8F1FE6568BBEB009B5 + 936C2599775DA43BC28A7798C3663474 targetProxy A106EC63441BF09009E975CB16456475 + B0F2F8A5622AF131C09AB271FA889955 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + BONText_Private.h + sourceTree + <group> + B40764AE97F30C2BAAD83E38C5B52A6D includeInIndex @@ -1400,62 +1547,6 @@ sourceTree <group> - B95F26D83A85C76C3949416F60C7E1E1 - - baseConfigurationReference - 907B9450CCC329D3E8FFEB42C73C99EE - buildSettings - - CODE_SIGN_IDENTITY[sdk=iphoneos*] - iPhone Developer - CURRENT_PROJECT_VERSION - 1 - DEFINES_MODULE - YES - DYLIB_COMPATIBILITY_VERSION - 1 - DYLIB_CURRENT_VERSION - 1 - DYLIB_INSTALL_NAME_BASE - @rpath - ENABLE_STRICT_OBJC_MSGSEND - YES - GCC_PREFIX_HEADER - Target Support Files/BonMot/BonMot-prefix.pch - INFOPLIST_FILE - Target Support Files/BonMot/Info.plist - INSTALL_PATH - $(LOCAL_LIBRARY_DIR)/Frameworks - IPHONEOS_DEPLOYMENT_TARGET - 8.0 - LD_RUNPATH_SEARCH_PATHS - - $(inherited) - @executable_path/Frameworks - @loader_path/Frameworks - - MODULEMAP_FILE - Target Support Files/BonMot/BonMot.modulemap - MTL_ENABLE_DEBUG_INFO - NO - PRODUCT_NAME - BonMot - SDKROOT - iphoneos - SKIP_INSTALL - YES - TARGETED_DEVICE_FAMILY - 1,2 - VERSIONING_SYSTEM - apple-generic - VERSION_INFO_PREFIX - - - isa - XCBuildConfiguration - name - Release - BA6428E9F66FD5A23C0A2E06ED26CD2F includeInIndex @@ -1488,19 +1579,29 @@ sourceTree <group> - BE8601DA8860F7392B95146FC34AA1C7 + BB09BD8F14BEF9FC69FEB912DCCED55C - children - - 13394710B1F81A23CB801EC414777F81 - ED3DCC7B86AC9F7CF038A2160156040E - + includeInIndex + 1 isa - PBXGroup - name - Pod + PBXFileReference + lastKnownFileType + sourcecode.c.h path - Pod + BONTag.h + sourceTree + <group> + + BCCC75202C930C2B7DD65DF3E5EEDF8D + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + BONTextable.h sourceTree <group> @@ -1570,32 +1671,19 @@ sourceTree <group> - C7AC1A115C88CDA55C8F507E58A1DDBF + C9426127C7D9364DA549FFA1CBAAE21E - buildActionMask - 2147483647 - files - - F522BE1C9B2D42743D52239BE44E1CC5 - CE30C228369D6FD5AEC0AB99341AA4CF - EF3639A79EE8F73A22918377F0B42D82 - D39213E93EC1038DC1113AA269E845AF - 2C763DD88B7C65E2E698491B831F3F3D - 01E1BE6EC18457D2F88E270800F860C3 - 00D954F3747AA02DCA0A3809CFCD2B17 - D57F5373D6DC1FBDE880D03BC460552E - 223A0AE1B4C1AB6C22803C3F6F4E7C36 - 91095713BC69DBA99E10B37AADC85750 - 32467CAF5979C65E3DB3C11F76C85B53 - 79C19A2B453E4B0567FF6F03C5B1B0EA - D1BB6107B193D42B208AE41C084B7438 - AE604A23841D67F0735CD4518EB98573 - 8B63557B3C823AE3067A0A62BC06400A - + fileRef + 8CC583263BA5A300A8153C1A29EAB54E isa - PBXHeadersBuildPhase - runOnlyForDeploymentPostprocessing - 0 + PBXBuildFile + settings + + ATTRIBUTES + + Public + + CA7D9F5FC702DA9A09A5F3128839B84A @@ -1610,6 +1698,29 @@ sourceTree <group> + CB0AE9160D3D0094A5DAE320035944A6 + + buildActionMask + 2147483647 + files + + 38F8823CD9270173773704F2E964D6BB + 06821309EE78916F536F3C35B4FAA4B2 + A42782D2876C5E4DF94A9F5A68D9AC59 + 60209B4FEFC22D3FDD07669CBB7A5D4A + 80B3B962FB551BA93445CCBECA715AC8 + 95FE86EF52CFAE2CC062808BF065C3D7 + 0080E3345719F60099A110B1C33C05F2 + 17C1148DA9BA0313110FC2436C3C936F + 96647DB5078B8E474BF86755E8A3557A + CEB8563653F8C3F6F2EC101EBA790485 + CCE0D044A452AF00A504EC9739EEA80A + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + CB2FD0FB92AFB48BF4840DB66DE560C8 includeInIndex @@ -1623,6 +1734,13 @@ sourceTree <group> + CCE0D044A452AF00A504EC9739EEA80A + + fileRef + 71C80B4B47FA325B1D150662D2EF15C2 + isa + PBXBuildFile + CDA4F5B325BBC8347176E2207B0430BF baseConfigurationReference @@ -1685,10 +1803,17 @@ name Release - CE30C228369D6FD5AEC0AB99341AA4CF + CEB8563653F8C3F6F2EC101EBA790485 + + fileRef + 65E326689AAFF02F1507650324813E89 + isa + PBXBuildFile + + D09F361B9D1EE649D7E855E3A4727820 fileRef - 28D4FDE16DE8250F25DC730765DC221B + BB09BD8F14BEF9FC69FEB912DCCED55C isa PBXBuildFile settings @@ -1725,34 +1850,6 @@ runOnlyForDeploymentPostprocessing 0 - D1BB6107B193D42B208AE41C084B7438 - - fileRef - 10BE4F0AA4813318BC4FB1C492F89E90 - isa - PBXBuildFile - settings - - ATTRIBUTES - - Public - - - - D39213E93EC1038DC1113AA269E845AF - - fileRef - 10BC01F663CA7849D1A21B7F337370F0 - isa - PBXBuildFile - settings - - ATTRIBUTES - - Public - - - D41D8CD98F00B204E9800998ECF8427E attributes @@ -1788,7 +1885,7 @@ targets - 7960D5870921BF8F1FE6568BBEB009B5 + 936C2599775DA43BC28A7798C3663474 E84C4E74F02AFF5309A6A3817A638C1F C6A0921570F1E8C9ECC7B63F726B4556 @@ -1806,20 +1903,6 @@ sourceTree <group> - D57F5373D6DC1FBDE880D03BC460552E - - fileRef - E1927D7CD5C58406A4D41F8C171BF93B - isa - PBXBuildFile - settings - - ATTRIBUTES - - Private - - - D628178EF8FFEF0FD32001265F6CC679 buildConfigurations @@ -1949,19 +2032,6 @@ name Debug - E1927D7CD5C58406A4D41F8C171BF93B - - includeInIndex - 1 - isa - PBXFileReference - lastKnownFileType - sourcecode.c.h - path - BONText_Private.h - sourceTree - <group> - E25641E248FCA33FB78676B255411C8B includeInIndex @@ -1982,6 +2052,20 @@ isa PBXBuildFile + E3C1E20D4E3714E84B74E812591B9970 + + fileRef + 6868B12CE64A02DC58A825D43FCD6AED + isa + PBXBuildFile + settings + + ATTRIBUTES + + Private + + + E40A36D2E548722345E1738CFBAB4824 includeInIndex @@ -2048,33 +2132,6 @@ sourceTree <group> - ED3DCC7B86AC9F7CF038A2160156040E - - children - - 726940D4C81A5A90179226804F99A3A0 - 1BB8C8B0D6FFC76CF6E70FF4AAFD9A79 - 28D4FDE16DE8250F25DC730765DC221B - 085FB431F3FE96089534EAAC6FE8BDF8 - 2AA3029BF1F6DE94522F0133B389D5F1 - FAB64E9029A05F73B2B4A250B105E030 - 212D5BC776EC758921C6BA007E2B182E - E1927D7CD5C58406A4D41F8C171BF93B - 946B30FF1BFF268E9AA4A27BAC2E5ECD - 7656BC2502D0F175B42AA5251C923450 - 29A9CD70F27600DBF695A88C9FF0AF50 - 53BEB5EF5FD30BA79950A4BD482E3F3B - 854FD81E8C8A6D67C6177C34537726A8 - - isa - PBXGroup - name - Classes - path - Classes - sourceTree - <group> - ED562394440514D7886F9C32296C2260 children @@ -2089,24 +2146,10 @@ sourceTree <group> - EF3639A79EE8F73A22918377F0B42D82 - - fileRef - CA7D9F5FC702DA9A09A5F3128839B84A - isa - PBXBuildFile - settings - - ATTRIBUTES - - Public - - - - F522BE1C9B2D42743D52239BE44E1CC5 + F70AB5068C980C99E1D3CB1D0EEC3356 fileRef - 726940D4C81A5A90179226804F99A3A0 + 10BE4F0AA4813318BC4FB1C492F89E90 isa PBXBuildFile settings @@ -2131,19 +2174,6 @@ - FAB64E9029A05F73B2B4A250B105E030 - - includeInIndex - 1 - isa - PBXFileReference - lastKnownFileType - sourcecode.c.h - path - BONText.h - sourceTree - <group> - FB45FFD90572718D82AB9092B750F0CA buildSettings @@ -2212,12 +2242,62 @@ name Release - FC8B3E0621B411FD79396927F3D0BC13 + FB5E82DA859C42DFF27B99BDC321C21F fileRef - 1BB8C8B0D6FFC76CF6E70FF4AAFD9A79 + 6300608DB9CA45054481077A506554A4 isa PBXBuildFile + settings + + ATTRIBUTES + + Public + + + + FC5E1EE731C93D8B60AB0AEA8CEF4500 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + BONText.h + sourceTree + <group> + + FD46195AAC067287FDF6898C915D60C0 + + children + + 47FFC4B90C298DBEA36FB326D190DBAB + 61712505D3A454DA4C6DB55A419A8F77 + 104DDEC1C49A667B0F3B8AD43A9B20D2 + 6A767B48037B33454A2A30879F170FDE + 1FBDCB556EABB04AC7BF1AE02CCFD08D + BB09BD8F14BEF9FC69FEB912DCCED55C + 055C51A91D330461B7E2BE7BCD601A5B + 6868B12CE64A02DC58A825D43FCD6AED + FC5E1EE731C93D8B60AB0AEA8CEF4500 + 38A2136A23298CA3E69A4E692A4317E9 + B0F2F8A5622AF131C09AB271FA889955 + BCCC75202C930C2B7DD65DF3E5EEDF8D + 1F7D0CFA4095C319AEDC668D27E01781 + 17E86E730C75BDA8893FD85A83CD3723 + 7C6D0196353D8E5AC65F6AC29B7C8777 + A8EE48AA815968BBE1E66AB3493C1EAA + + isa + PBXGroup + name + Classes + path + Classes + sourceTree + <group> FEC4B2323A49EDD7A9FE32C85F2DE364 diff --git a/Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/BonMot.xcscheme b/Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/BonMot.xcscheme index a784c97d..49c32ed6 100644 --- a/Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/BonMot.xcscheme +++ b/Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/BonMot.xcscheme @@ -14,7 +14,7 @@ buildForArchiving = "YES"> diff --git a/Example/Pods/Target Support Files/BonMot/BonMot-umbrella.h b/Example/Pods/Target Support Files/BonMot/BonMot-umbrella.h index 638c08bc..46810c1c 100644 --- a/Example/Pods/Target Support Files/BonMot/BonMot-umbrella.h +++ b/Example/Pods/Target Support Files/BonMot/BonMot-umbrella.h @@ -4,6 +4,7 @@ #import "BONChain.h" #import "BONCompatibility.h" #import "BONSpecial.h" +#import "BONTag.h" #import "BONText.h" #import "BONTextable.h" #import "NSAttributedString+BonMotUtilities.h" diff --git a/Example/Pods/Target Support Files/BonMot/BonMot.modulemap b/Example/Pods/Target Support Files/BonMot/BonMot.modulemap index 43546d1f..f0217cf1 100644 --- a/Example/Pods/Target Support Files/BonMot/BonMot.modulemap +++ b/Example/Pods/Target Support Files/BonMot/BonMot.modulemap @@ -4,5 +4,6 @@ framework module BonMot { export * module * { export * } + private header "BONTag_Private.h" private header "BONText_Private.h" } diff --git a/Example/Tests/BONTagComplexMakeTestCase.m b/Example/Tests/BONTagComplexMakeTestCase.m new file mode 100644 index 00000000..6240d000 --- /dev/null +++ b/Example/Tests/BONTagComplexMakeTestCase.m @@ -0,0 +1,406 @@ +// +// BONTagComplexMakeTestCase.m +// BonMot +// +// Created by Nora Trapp on 3/3/16. +// Copyright © 2016 Zev Eisenberg. All rights reserved. +// + +#import "BONBaseTestCase.h" + +@import BonMot; + +@interface BONTagComplexMakeTestCase : BONBaseTestCase + +@end + +@implementation BONTagComplexMakeTestCase + +- (void)testSingleTagSingleStyle +{ + BONChain *chain = BONChain.new.string(@"Hello, [i]world(i)!") + .tagComplexStyles(@[ BONTagComplexMake(@"[i]", @"(i)", @"qwerty", BONChain.new.font([UIFont italicSystemFontOfSize:16])) ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 7) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 5) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 1) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMultipleTagsSingleStyle +{ + BONChain *chain = BONChain.new.string(@"[i]Hello(i), [i]world(i)!") + .tagComplexStyles(@[ BONTagComplexMake(@"[i]", @"(i)", @"qwerty", BONChain.new.font([UIFont italicSystemFontOfSize:16])) ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 5) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(5, 2) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 5) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 1) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testSingleTagMultipleStyles +{ + BONChain *chain = BONChain.new.string(@"Hello, >bb<*!") + .tagComplexStyles(@[ + BONTagComplexMake(@"[i]", @"(i)", @"qwerty", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagComplexMake(@">b<", @">b<*", @"qwerty", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 7) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 1) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMultipleTagsMultipleStyles +{ + BONChain *chain = BONChain.new.string(@">bb<*, [i]world(i)!") + .tagComplexStyles(@[ + BONTagComplexMake(@"[i]", @"(i)", @"qwerty", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagComplexMake(@">b<", @">b<*", @"qwerty", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(5, 2) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 5) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 1) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testInterleavedTags +{ + BONChain *chain = BONChain.new.string(@">bb<*, world(i)!") + .tagComplexStyles(@[ + BONTagComplexMake(@"[i]", @"(i)", @"qwerty", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagComplexMake(@">b<", @">b<*", @"qwerty", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello[i], world(i)!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 8) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(8, 11) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testNestedTags +{ + BONChain *chain = BONChain.new.string(@">b<[i]Hello(i)>b<*, world!") + .tagComplexStyles(@[ + BONTagComplexMake(@"[i]", @"(i)", @"qwerty", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagComplexMake(@">b<", @">b<*", @"qwerty", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"[i]Hello(i), world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 11) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(11, 8) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMixedOrdering +{ + BONChain *chain = BONChain.new.string(@">bb<*[i]lo(i), >bb<*[i]ld!(i)") + .tagComplexStyles(@[ + BONTagComplexMake(@"[i]", @"(i)", @"qwerty", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagComplexMake(@">b<", @">b<*", @"qwerty", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 3) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(3, 2) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(5, 2) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 3) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(10, 3) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testEscapedStartTag +{ + BONChain *chain = BONChain.new.string(@"qwerty(b)(b)Hello[/b], world!") + .tagComplexStyles(@[ + BONTagComplexMake(@"(i)", @"[/i]", @"qwerty", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagComplexMake(@"(b)", @"[/b]", @"qwerty", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"(b)Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 3) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(3, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(8, 8) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMultipleEscapedStartTag +{ + BONChain *chain = BONChain.new.string(@"qwerty(b)(b)Hello[/b]qwerty(b), world!") + .tagComplexStyles(@[ + BONTagComplexMake(@"(i)", @"[/i]", @"qwerty", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagComplexMake(@"(b)", @"[/b]", @"qwerty", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"(b)Hello(b), world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 3) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(3, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(8, 11) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMultipleEscapedEndTag +{ + BONChain *chain = BONChain.new.string(@"qwerty[/b](b)Hello[/b]qwerty[/b], world!") + .tagComplexStyles(@[ + BONTagComplexMake(@"(i)", @"[/i]", @"qwerty", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagComplexMake(@"(b)", @"[/b]", @"qwerty", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"[/b]Hello[/b], world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 4) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(4, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(9, 12) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testNestedEscapedEndTag +{ + BONChain *chain = BONChain.new.string(@"(b)Helloqwerty[/b][/b], world!") + .tagComplexStyles(@[ + BONTagComplexMake(@"(i)", @"[/i]", @"qwerty", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagComplexMake(@"(b)", @"[/b]", @"qwerty", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello[/b], world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 9) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(9, 8) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testInterleavedEscapedEndTag +{ + BONChain *chain = BONChain.new.string(@"qwerty[/b]asdfgh[/i]qwerty[/b](i)Helloasdfgh[/i][/i], world!") + .tagComplexStyles(@[ + BONTagComplexMake(@"(i)", @"[/i]", @"asdfgh", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagComplexMake(@"(b)", @"[/b]", @"qwerty", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"[/b][/i][/b]Hello[/i], world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 12) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 9) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(21, 8) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +@end diff --git a/Example/Tests/BONTagMakeTestCase.m b/Example/Tests/BONTagMakeTestCase.m new file mode 100644 index 00000000..61d219da --- /dev/null +++ b/Example/Tests/BONTagMakeTestCase.m @@ -0,0 +1,406 @@ +// +// BONTagMakeTestCase.m +// BonMot +// +// Created by Nora Trapp on 3/3/16. +// Copyright © 2016 Zev Eisenberg. All rights reserved. +// + +#import "BONBaseTestCase.h" + +@import BonMot; + +@interface BONTagMakeTestCase : BONBaseTestCase + +@end + +@implementation BONTagMakeTestCase + +- (void)testSingleTagSingleStyle +{ + BONChain *chain = BONChain.new.string(@"Hello, world!") + .tagComplexStyles(@[ BONTagMake(@"i", BONChain.new.font([UIFont italicSystemFontOfSize:16])) ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 7) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 5) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 1) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMultipleTagsSingleStyle +{ + BONChain *chain = BONChain.new.string(@"Hello, world!") + .tagComplexStyles(@[ BONTagMake(@"i", BONChain.new.font([UIFont italicSystemFontOfSize:16])) ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 5) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(5, 2) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 5) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 1) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testSingleTagMultipleStyles +{ + BONChain *chain = BONChain.new.string(@"Hello, world!") + .tagComplexStyles(@[ + BONTagMake(@"i", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagMake(@"b", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 7) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 1) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMultipleTagsMultipleStyles +{ + BONChain *chain = BONChain.new.string(@"Hello, world!") + .tagComplexStyles(@[ + BONTagMake(@"i", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagMake(@"b", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(5, 2) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 5) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 1) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testInterleavedTags +{ + BONChain *chain = BONChain.new.string(@"Hello, world!") + .tagComplexStyles(@[ + BONTagMake(@"i", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagMake(@"b", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 8) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(8, 12) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testNestedTags +{ + BONChain *chain = BONChain.new.string(@"Hello, world!") + .tagComplexStyles(@[ + BONTagMake(@"i", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagMake(@"b", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 12) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 8) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMixedOrdering +{ + BONChain *chain = BONChain.new.string(@"Hello, world!") + .tagComplexStyles(@[ + BONTagMake(@"i", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagMake(@"b", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 3) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(3, 2) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(5, 2) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 3) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(10, 3) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testEscapedStartTag +{ + BONChain *chain = BONChain.new.string(@"\\Hello, world!") + .tagComplexStyles(@[ + BONTagMake(@"i", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagMake(@"b", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 3) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(3, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(8, 8) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMultipleEscapedStartTag +{ + BONChain *chain = BONChain.new.string(@"\\Hello\\, world!") + .tagComplexStyles(@[ + BONTagMake(@"i", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagMake(@"b", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 3) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(3, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(8, 11) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMultipleEscapedEndTag +{ + BONChain *chain = BONChain.new.string(@"\\Hello\\, world!") + .tagComplexStyles(@[ + BONTagMake(@"i", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagMake(@"b", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 4) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(4, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(9, 12) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testNestedEscapedEndTag +{ + BONChain *chain = BONChain.new.string(@"Hello\\, world!") + .tagComplexStyles(@[ + BONTagMake(@"i", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagMake(@"b", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 9) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(9, 8) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testInterleavedEscapedEndTag +{ + BONChain *chain = BONChain.new.string(@"\\\\\\Hello\\, world!") + .tagComplexStyles(@[ + BONTagMake(@"i", BONChain.new.font([UIFont italicSystemFontOfSize:16])), + BONTagMake(@"b", BONChain.new.font([UIFont boldSystemFontOfSize:16])), + ]); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 12) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 9) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(21, 8) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +@end diff --git a/Example/Tests/BONTagStylesTestCase.m b/Example/Tests/BONTagStylesTestCase.m new file mode 100644 index 00000000..41e0a2ea --- /dev/null +++ b/Example/Tests/BONTagStylesTestCase.m @@ -0,0 +1,406 @@ +// +// BONTagStylesTestCase.m +// BonMot +// +// Created by Nora Trapp on 5/16/16. +// Copyright © 2016 Zev Eisenberg. All rights reserved. +// + +#import "BONBaseTestCase.h" + +@import BonMot; + +@interface BONTagStylesTestCase : BONBaseTestCase + +@end + +@implementation BONTagStylesTestCase + +- (void)testSingleTagSingleStyle +{ + BONChain *chain = BONChain.new.string(@"Hello, world!") + .tagStyles(@{ @"i" : BONChain.new.font([UIFont italicSystemFontOfSize:16]) }); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 7) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 5) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 1) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMultipleTagsSingleStyle +{ + BONChain *chain = BONChain.new.string(@"Hello, world!") + .tagStyles(@{ @"i" : BONChain.new.font([UIFont italicSystemFontOfSize:16]) }); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 5) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(5, 2) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 5) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 1) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testSingleTagMultipleStyles +{ + BONChain *chain = BONChain.new.string(@"Hello, world!") + .tagStyles(@{ + @"i" : BONChain.new.font([UIFont italicSystemFontOfSize:16]), + @"b" : BONChain.new.font([UIFont boldSystemFontOfSize:16]), + }); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 7) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 1) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMultipleTagsMultipleStyles +{ + BONChain *chain = BONChain.new.string(@"Hello, world!") + .tagStyles(@{ + @"i" : BONChain.new.font([UIFont italicSystemFontOfSize:16]), + @"b" : BONChain.new.font([UIFont boldSystemFontOfSize:16]), + }); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(5, 2) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 5) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 1) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testInterleavedTags +{ + BONChain *chain = BONChain.new.string(@"Hello, world!") + .tagStyles(@{ + @"i" : BONChain.new.font([UIFont italicSystemFontOfSize:16]), + @"b" : BONChain.new.font([UIFont boldSystemFontOfSize:16]), + }); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 8) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(8, 12) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testNestedTags +{ + BONChain *chain = BONChain.new.string(@"Hello, world!") + .tagStyles(@{ + @"i" : BONChain.new.font([UIFont italicSystemFontOfSize:16]), + @"b" : BONChain.new.font([UIFont boldSystemFontOfSize:16]), + }); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 12) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 8) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMixedOrdering +{ + BONChain *chain = BONChain.new.string(@"Hello, world!") + .tagStyles(@{ + @"i" : BONChain.new.font([UIFont italicSystemFontOfSize:16]), + @"b" : BONChain.new.font([UIFont boldSystemFontOfSize:16]), + }); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 3) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(3, 2) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(5, 2) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(7, 3) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(10, 3) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testEscapedStartTag +{ + BONChain *chain = BONChain.new.string(@"\\Hello, world!") + .tagStyles(@{ + @"i" : BONChain.new.font([UIFont italicSystemFontOfSize:16]), + @"b" : BONChain.new.font([UIFont boldSystemFontOfSize:16]), + }); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 3) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(3, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(8, 8) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMultipleEscapedStartTag +{ + BONChain *chain = BONChain.new.string(@"\\Hello\\, world!") + .tagStyles(@{ + @"i" : BONChain.new.font([UIFont italicSystemFontOfSize:16]), + @"b" : BONChain.new.font([UIFont boldSystemFontOfSize:16]), + }); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 3) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(3, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(8, 11) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testMultipleEscapedEndTag +{ + BONChain *chain = BONChain.new.string(@"\\Hello\\, world!") + .tagStyles(@{ + @"i" : BONChain.new.font([UIFont italicSystemFontOfSize:16]), + @"b" : BONChain.new.font([UIFont boldSystemFontOfSize:16]), + }); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 4) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(4, 5) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(9, 12) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testNestedEscapedEndTag +{ + BONChain *chain = BONChain.new.string(@"Hello\\, world!") + .tagStyles(@{ + @"i" : BONChain.new.font([UIFont italicSystemFontOfSize:16]), + @"b" : BONChain.new.font([UIFont boldSystemFontOfSize:16]), + }); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 9) : @{ + NSFontAttributeName : [UIFont boldSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(9, 8) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +- (void)testInterleavedEscapedEndTag +{ + BONChain *chain = BONChain.new.string(@"\\\\\\Hello\\, world!") + .tagStyles(@{ + @"i" : BONChain.new.font([UIFont italicSystemFontOfSize:16]), + @"b" : BONChain.new.font([UIFont boldSystemFontOfSize:16]), + }); + + NSAttributedString *attributedString = chain.attributedString; + + XCTAssertEqualObjects(attributedString.string, @"Hello, world!"); + + NSParagraphStyle *defaultParagraphStyle = [[NSParagraphStyle alloc] init]; + + NSDictionary *controlAttributes = @{ + BONValueFromRange(0, 12) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(12, 9) : @{ + NSFontAttributeName : [UIFont italicSystemFontOfSize:16], + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + + BONValueFromRange(21, 8) : @{ + NSParagraphStyleAttributeName : defaultParagraphStyle, + }, + }; + + BONAssertAttributedStringHasAttributes(attributedString, controlAttributes); +} + +@end diff --git a/Example/Tests/BONTagTestCase.m b/Example/Tests/BONTagTestCase.m new file mode 100644 index 00000000..694f5357 --- /dev/null +++ b/Example/Tests/BONTagTestCase.m @@ -0,0 +1,83 @@ +// +// BONTagTestCase.m +// BonMot +// +// Created by Nora Trapp on 5/17/16. +// Copyright © 2016 Zev Eisenberg. All rights reserved. +// + +#import "BONBaseTestCase.h" +@import BonMot; + +@interface BONTag () + +@property (strong, nonatomic, BONNonnull) BONGeneric(NSMutableArray, NSValue *) * ranges; + ++ (BONNonnull BONGeneric(NSArray, NSValue *) *)escapedRangesInString:(NSString *BONCNonnull *BONCNonnull)string withTags:(BONNonnull BONGeneric(NSArray, BONTag *) *)tags; ++ (NSRange)firstOccurrenceOfString:(BONNonnull NSString *)string inString:(BONNonnull NSString *)stringToSearch ignoringRanges:(BONNonnull BONGeneric(NSArray, NSValue *) *)escapedRanges inRange:(NSRange)range; ++ (BONNonnull BONGeneric(NSArray, BONTag *) *)rangesInString:(NSString *BONCNonnull *BONCNonnull)string betweenTags:(BONNonnull BONGeneric(NSArray, BONTag *) *)tags; +@end + +@import BonMot; + +@interface BONTagTestCase : BONBaseTestCase + +@end + +@implementation BONTagTestCase + +- (void)testEscapedRangesInString +{ + NSString *string = @"This is a \\ string that \\ has \\escaped characters."; + NSArray *ranges = [BONTag escapedRangesInString:&string withTags:@[ BONTagMake(@"b", BONChain.new) ]]; + + NSString *stringWithoutEscapes = @"This is a string that has \\escaped characters."; + XCTAssertEqualObjects(string, stringWithoutEscapes); + + NSArray *escapedRanges = @[ [NSValue valueWithRange:NSMakeRange(10, 3)], [NSValue valueWithRange:NSMakeRange(26, 4)] ]; + XCTAssertEqualObjects(ranges, escapedRanges); +} + +- (void)testMixedEscapeStrings +{ + NSString *string = @"This is a \\ string that \\ has \\escaped ~escaped characters."; + NSArray *ranges = [BONTag escapedRangesInString:&string withTags:@[ BONTagMake(@"b", BONChain.new), BONTagComplexMake(@"escaped", @"escaped", @"~", BONChain.new) ]]; + + NSString *stringWithoutEscapes = @"This is a string that has \\escaped escaped characters."; + XCTAssertEqualObjects(string, stringWithoutEscapes); + + NSArray *escapedRanges = @[ [NSValue valueWithRange:NSMakeRange(10, 3)], [NSValue valueWithRange:NSMakeRange(26, 4)], [NSValue valueWithRange:NSMakeRange(44, 7)] ]; + XCTAssertEqualObjects(ranges, escapedRanges); +} + +- (void)testFirstOccurenceOfString +{ + NSString *string = @"This is a \\ string that \\ has \\escaped characters."; + NSRange range = [BONTag firstOccurrenceOfString:@"" inString:string ignoringRanges:@[] inRange:NSMakeRange(0, string.length)]; + + XCTAssertTrue(NSEqualRanges(range, NSMakeRange(11, 3))); +} + +- (void)testFirstOccurenceOfStringWithIgnoredRange +{ + NSString *string = @"This is a \\ string that \\ has \\escaped characters."; + NSArray *ignoredRanges = @[ [NSValue valueWithRange:NSMakeRange(8, 3)] ]; + NSRange range = [BONTag firstOccurrenceOfString:@"" inString:string ignoringRanges:ignoredRanges inRange:NSMakeRange(0, string.length)]; + + XCTAssertTrue(NSEqualRanges(range, NSMakeRange(15, 3))); +} + +- (void)testRangesBetweenTags +{ + NSString *string = @"This is a tagged string."; + NSArray *tags = [BONTag rangesInString:&string betweenTags:@[ BONTagMake(@"b", BONChain.new) ]]; + + NSString *stringWithoutTags = @"This is a tagged string."; + XCTAssertEqualObjects(string, stringWithoutTags); + + NSArray *tagRanges = @[ [NSValue valueWithRange:NSMakeRange(10, 6)] ]; + BONTag *resultTag = tags.firstObject; + XCTAssertEqualObjects(resultTag.ranges, tagRanges); +} + +@end diff --git a/Pod/BonMot.h b/Pod/BonMot.h index 3cd1219c..208e10b3 100644 --- a/Pod/BonMot.h +++ b/Pod/BonMot.h @@ -10,3 +10,4 @@ #import "BONChain.h" #import "BONSpecial.h" #import "UIImage+BonMotUtilities.h" +#import "BONTag.h" diff --git a/Pod/Classes/BONChain.h b/Pod/Classes/BONChain.h index f2d0829c..0a69a353 100644 --- a/Pod/Classes/BONChain.h +++ b/Pod/Classes/BONChain.h @@ -14,6 +14,7 @@ BON_ASSUME_NONNULL_BEGIN @class BONChain; +@class BONTag; typedef BONChain *BONCNonnull (^BONChainFontNameAndSize)(NSString *BONCNonnull fontName, CGFloat fontSize); typedef BONChain *BONCNonnull (^BONChainFont)(UIFont *BONCNullable font); @@ -44,6 +45,9 @@ typedef BONChain *BONCNonnull (^BONChainUnderlineColor)(UIColor *BONCNullable co typedef BONChain *BONCNonnull (^BONChainStrikethroughStyle)(NSUnderlineStyle style); typedef BONChain *BONCNonnull (^BONChainStrikethroughColor)(UIColor *BONCNullable color); +typedef BONChain *BONCNonnull (^BONTagStyles)(BONGeneric(NSDictionary, NSString *, id) * BONCNullable styles); +typedef BONChain *BONCNonnull (^BONTagComplexStyles)(BONGeneric(NSArray, BONTag *) * BONCNullable styles); + @interface BONChain : NSObject @property (copy, nonatomic, readonly) NSAttributedString *attributedString; @@ -94,6 +98,19 @@ typedef BONChain *BONCNonnull (^BONChainStrikethroughColor)(UIColor *BONCNullabl @property (copy, nonatomic, readonly) BONChainStrikethroughStyle strikethroughStyle; @property (copy, nonatomic, readonly) BONChainStrikethroughColor strikethroughColor; +/** + * Assign @p BONTextables to use in styling substrings surrounded by given tags. + * For example, ["b": boldChain] would apply the @p boldChain + * to any substring surrounded by and remove the tags from the resulting + * attributed string. Nested tagging is not supported. + */ +@property (copy, nonatomic, readonly) BONTagStyles tagStyles; + +/** + * Assign an array of @p BONTags to use in styling substrings. + */ +@property (copy, nonatomic, readonly) BONTagComplexStyles tagComplexStyles; + // concatenation - (void)appendLink:(id)link; - (void)appendLink:(id)link separator:(BONNullable NSString *)separator; diff --git a/Pod/Classes/BONChain.m b/Pod/Classes/BONChain.m index 6dba4990..c49d0b44 100644 --- a/Pod/Classes/BONChain.m +++ b/Pod/Classes/BONChain.m @@ -10,6 +10,7 @@ #import "BONText.h" #import "BONText_Private.h" +#import "BONTag.h" @interface BONChain () @@ -353,6 +354,28 @@ - (BONChainStrikethroughColor)strikethroughColor return [strikethroughColorBlock copy]; } +- (BONTagStyles)tagStyles +{ + BONTagStyles tagStylesBlock = ^(BONGeneric(NSDictionary, NSString *, id)*tagStyles) { + __typeof(self) newChain = self.copyWithoutNextText; + newChain.text.tagStyles = BONTagsFromDictionary(tagStyles); + return newChain; + }; + + return [tagStylesBlock copy]; +} + +- (BONTagComplexStyles)tagComplexStyles +{ + BONTagComplexStyles tagStylesBlock = ^(BONGeneric(NSArray, BONTag *)*tagStyles) { + __typeof(self) newChain = self.copyWithoutNextText; + newChain.text.tagStyles = tagStyles; + return newChain; + }; + + return [tagStylesBlock copy]; +} + - (void)appendLink:(id)link { [self appendLink:link separator:nil]; diff --git a/Pod/Classes/BONTag.h b/Pod/Classes/BONTag.h new file mode 100644 index 00000000..5257365f --- /dev/null +++ b/Pod/Classes/BONTag.h @@ -0,0 +1,73 @@ +// +// BONTag.h +// BonMot +// +// Created by Nora Trapp on 5/11/16. +// Copyright © 2015 Zev Eisenberg. All rights reserved. +// + +#import +#import "BONCompatibility.h" + +@protocol BONTextable; + +@interface BONTag : NSObject + +@property (copy, nonatomic, readonly, BONNonnull) NSString *startTag; +@property (copy, nonatomic, readonly, BONNonnull) NSString *endTag; +@property (copy, nonatomic, readonly, BONNonnull) NSString *escapeString; +@property (copy, nonatomic, readonly, BONNonnull) id textable; + +- (BONNonnull instancetype)initWithStartTag:(BONNonnull NSString *)startTag endTag:(BONNonnull NSString *)endTag escapeString:(BONNonnull NSString *)escapeString textable:(BONNonnull id)textable; +- (BONNonnull instancetype)initWithTag:(BONNonnull NSString *)tag textable:(BONNonnull id)textable; + +@end + +/** + * Create a tag with a custom start/end/escape combination. + * + * @param startTag The start tag. + * @param endTag The end tag. + * @param escapeString The escape string. + * @param textable The style to apply. + * + * @return A @p BONTag instance representing the tag. + */ +NS_INLINE BONTag *BONCNonnull BONTagComplexMake(NSString *BONCNonnull startTag, NSString *BONCNonnull endTag, NSString *BONCNonnull escapeString, id BONCNonnull textable) NS_SWIFT_UNAVAILABLE("Use BONTag(startTag:endTag:escapeString:textable:)") +{ + return [[BONTag alloc] initWithStartTag:startTag endTag:endTag escapeString:escapeString textable:textable]; +} + +/** + * Create a tag using the default start and end formats and using \ as an escape character. Example: + * @code + * Normal String + * String with escaped \ + * @endcode + * + * @param tag The tag string. + * @param textable The style to apply. + * + * @return A @p BONTag instance representing the tag. + */ +NS_INLINE BONTag *BONCNonnull BONTagMake(NSString *BONCNonnull tag, id BONCNonnull textable) NS_SWIFT_UNAVAILABLE("Use BONTag(tag:textable:)") +{ + return [[BONTag alloc] initWithTag:tag textable:textable]; +} + +/** + * Create an array of tag objects from a dictionary of ["tag": textable] + * + * @param dictionary A dictionary of tags mapped to textables. + * + * @return An array of @p BONTag objects representing the tags in the dictionary. + */ +NS_INLINE BONGeneric(NSArray, BONTag *) * BONCNonnull BONTagsFromDictionary(BONGeneric(NSDictionary, NSString *, id) * BONCNonnull dictionary) +{ + NSMutableArray *tags = [NSMutableArray array]; + for (NSString *key in dictionary) { + id textable = dictionary[key]; + [tags addObject:BONTagMake(key, textable)]; + } + return tags; +} diff --git a/Pod/Classes/BONTag.m b/Pod/Classes/BONTag.m new file mode 100644 index 00000000..fd9b1a2d --- /dev/null +++ b/Pod/Classes/BONTag.m @@ -0,0 +1,239 @@ +// +// BONTag.m +// BonMot +// +// Created by Nora Trapp on 5/11/16. +// Copyright © 2015 Zev Eisenberg. All rights reserved. +// + +#import "BONTag_Private.h" +#import "BONMot.h" + +static NSString *const kBONTagDefaultStartPrefix = @"<"; +static NSString *const kBONTagDefaultStartSuffix = @">"; +static NSString *const kBONTagDefaultEndPrefix = @""; +static NSString *const kBONTagDefaultEscapeString = @"\\"; + +@interface BONTag () + +@property (copy, nonatomic) NSString *startTag; +@property (copy, nonatomic) NSString *endTag; +@property (copy, nonatomic) NSString *escapeString; +@property (copy, nonatomic) id textable; + +@end + +@implementation BONTag + +- (instancetype)initWithStartTag:(NSString *)startTag endTag:(NSString *)endTag escapeString:(NSString *)escapeString textable:(id)textable +{ + self = [super init]; + if (self) { + self.startTag = startTag; + self.endTag = endTag; + self.escapeString = escapeString; + self.textable = textable; + self.ranges = [NSMutableArray array]; + } + + return self; +} + +- (instancetype)initWithTag:(NSString *)tag textable:(id)textable +{ + NSString *startTag = [NSString stringWithFormat:@"%@%@%@", kBONTagDefaultStartPrefix, tag, kBONTagDefaultStartSuffix]; + NSString *endTag = [NSString stringWithFormat:@"%@%@%@", kBONTagDefaultEndPrefix, tag, kBONTagDefaultEndSuffix]; + + return [self initWithStartTag:startTag endTag:endTag escapeString:(NSString *)kBONTagDefaultEscapeString textable:textable]; +} + +- (id)copyWithZone:(NSZone *)zone +{ + __typeof(self) tag = [[self.class alloc] init]; + + tag.startTag = self.startTag; + tag.endTag = self.endTag; + tag.escapeString = self.escapeString; + tag.textable = self.textable; + tag.ranges = self.ranges; + + return tag; +} + +- (NSString *)description +{ + NSString *description = [NSString stringWithFormat:@"<%@: %p, startTag: %@, endTag: %@, textable: <%@: %p>>", NSStringFromClass(self.class), self, self.startTag, self.endTag, NSStringFromClass(self.textable.class), self.textable]; + + return description; +} + +#pragma mark - Tag Matching + ++ (BONGeneric(NSArray, NSValue *) *)escapedRangesInString:(NSString **)string withTags:(BONGeneric(NSArray, BONTag *) *)tags +{ + NSParameterAssert(string); + NSParameterAssert(tags); + + NSMutableArray *escapedRanges = [NSMutableArray array]; + + NSString *theString = *string; + + NSRange searchRange = NSMakeRange(0, theString.length); + + // Iterate over the string, finding each escape in order, until there are no more escape strings + while (YES) { + BONTag *nextTag; + NSRange nextEscapeRange; + NSRange nextEscapedTagRange; + + // Find the next escape string + for (BONTag *tag in tags) { + NSRange escapeRange = [theString rangeOfString:tag.escapeString options:0 range:searchRange]; + + if (escapeRange.location != NSNotFound) { + if (!nextTag || (escapeRange.location < nextEscapeRange.location)) { + // Check if this character is escaping a start or end tag + for (NSString *tagString in @[ tag.startTag, tag.endTag ]) { + // Check if there is room for this tag to exist after the escape character + if ((NSInteger)(NSMaxRange(escapeRange) + tagString.length) < theString.length) { + // Check if the following characters are actually the tag + NSRange potentialEscapedTagRange = NSMakeRange(NSMaxRange(escapeRange), tagString.length); + if ([[theString substringWithRange:potentialEscapedTagRange] isEqualToString:tagString]) { + nextTag = tag; + nextEscapeRange = escapeRange; + nextEscapedTagRange = potentialEscapedTagRange; + } + } + } + } + } + } + + if (!nextTag) { + break; + } + + // Strip escape characters + theString = [theString stringByReplacingOccurrencesOfString:nextTag.escapeString withString:@"" options:0 range:nextEscapeRange]; + NSRange range = NSMakeRange(nextEscapeRange.location, nextEscapedTagRange.length); + + [escapedRanges addObject:[NSValue valueWithRange:range]]; + + searchRange = NSMakeRange(NSMaxRange(range), theString.length - NSMaxRange(range)); + } + + *string = theString; + + return escapedRanges; +} + ++ (NSRange)firstOccurrenceOfString:(NSString *)string inString:(NSString *)stringToSearch ignoringRanges:(BONGeneric(NSArray, NSValue *) *)escapedRanges inRange:(NSRange)range +{ + NSParameterAssert(string); + NSParameterAssert(stringToSearch); + NSParameterAssert(escapedRanges); + + NSRange searchRange = range; + + while (YES) { + NSRange stringRange = [stringToSearch rangeOfString:string options:0 range:searchRange]; + + // Ignore this match + if ([escapedRanges containsObject:[NSValue valueWithRange:stringRange]]) { + searchRange = NSMakeRange(NSMaxRange(stringRange), stringToSearch.length - NSMaxRange(stringRange)); + continue; + } + + return stringRange; + } +} + ++ (BONGeneric(NSArray, BONTag *) *)rangesInString:(NSString **)string betweenTags:(BONGeneric(NSArray, BONTag *) *)tags +{ + NSParameterAssert(string); + NSParameterAssert(tags); + + BONGeneric(NSArray, NSValue *)*escapedRanges = [BONTag escapedRangesInString:string withTags:tags]; + + BONGeneric(NSArray, BONTag *)*tagsWithRanges = [[NSArray alloc] initWithArray:tags copyItems:YES]; + + NSString *theString = *string; + + NSRange searchRange = NSMakeRange(0, theString.length); + + // Iterate over the string, finding each tag in order, until there are no more tags + while (YES) { + BONTag *nextTag; + NSRange nextStartTagRange; + NSRange nextEndTagRange; + + // Find the next start tag + for (BONTag *tag in tagsWithRanges) { + NSRange startTagRange = [BONTag firstOccurrenceOfString:tag.startTag inString:theString ignoringRanges:escapedRanges inRange:searchRange]; + NSRange endTagRange = [BONTag firstOccurrenceOfString:tag.endTag inString:theString ignoringRanges:escapedRanges inRange:searchRange]; + if (startTagRange.location != NSNotFound && endTagRange.location != NSNotFound) { + if (!nextTag || (startTagRange.location < nextStartTagRange.location)) { + nextTag = tag; + nextStartTagRange = startTagRange; + nextEndTagRange = endTagRange; + } + } + } + + if (!nextTag) { + break; + } + + NSRange range = NSMakeRange(NSMaxRange(nextStartTagRange), nextEndTagRange.location - NSMaxRange(nextStartTagRange)); + + // Strip valid tags + range.location -= nextTag.startTag.length; + + theString = [theString stringByReplacingOccurrencesOfString:nextTag.startTag withString:@"" options:0 range:nextStartTagRange]; + nextStartTagRange.length = 0; + + nextEndTagRange.location -= nextTag.startTag.length; + theString = [theString stringByReplacingOccurrencesOfString:nextTag.endTag withString:@"" options:0 range:nextEndTagRange]; + nextEndTagRange.length = 0; + + [nextTag.ranges addObject:[NSValue valueWithRange:range]]; + + searchRange = NSMakeRange(NSMaxRange(nextEndTagRange), theString.length - NSMaxRange(nextEndTagRange)); + } + + *string = theString; + + return tagsWithRanges; +} + +#pragma mark - Equality + +- (BOOL)isEqualToTag:(BONTag *)tag +{ + return [tag.startTag isEqualToString:self.startTag] && + [tag.endTag isEqualToString:self.endTag] && + [tag.textable isEqual:self.textable] && + [tag.escapeString isEqualToString:self.escapeString] && + [tag.ranges isEqualToArray:self.ranges]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[BONTag class]]) { + return NO; + } + + return [self isEqualToTag:(BONTag *)object]; +} + +- (NSUInteger)hash +{ + return self.startTag.hash ^ self.endTag.hash ^ self.textable.hash ^ self.escapeString.hash ^ self.ranges.hash; +} + +@end diff --git a/Pod/Classes/BONTag_Private.h b/Pod/Classes/BONTag_Private.h new file mode 100644 index 00000000..861f8d04 --- /dev/null +++ b/Pod/Classes/BONTag_Private.h @@ -0,0 +1,47 @@ +// +// BONTag_Private.h +// BonMot +// +// Created by Nora Trapp on 5/11/16. +// Copyright © 2015 Zev Eisenberg. All rights reserved. +// + +#import "BONTag.h" + +@interface BONTag () + +@property (strong, nonatomic, BONNonnull) BONGeneric(NSMutableArray, NSValue *) * ranges; + +/** + * Finds all escaped tags within a given string. + * + * @param string The @p string to search. The @p string will be mutated to strip escape characters. + * @param tags The tags to search for. + * + * @return An array of ranges representing the escaped tags. + */ ++ (BONNonnull BONGeneric(NSArray, NSValue *) *)escapedRangesInString:(NSString *BONCNonnull *BONCNonnull)string withTags:(BONNonnull BONGeneric(NSArray, BONTag *) *)tags; + +/** + * Search through a string to find the next matching string that is not in an escaped range. + * + * @param string The string to look for. + * @param stringToSearch The string to search within. + * @param escapedRanges The ranges to ignore matches within. + * @param range The range of @p string to search. + * + * @return The range of the matched string. If the string is not found, location will be @p NSNotFound. + */ ++ (NSRange)firstOccurrenceOfString:(BONNonnull NSString *)string inString:(BONNonnull NSString *)stringToSearch ignoringRanges:(BONNonnull BONGeneric(NSArray, NSValue *) *)escapedRanges inRange:(NSRange)range; + +/** + * Find all tagged strings within a given string. + * + * @param string The @p string to search. The @p string will be mutated to strip valid tags. + * @param tags The tags to search for. + * + * @return An array of tags with the matching ranges defined. + */ ++ (BONNonnull BONGeneric(NSArray, BONTag *) *)rangesInString:(NSString *BONCNonnull *BONCNonnull)string betweenTags:(BONNonnull BONGeneric(NSArray, BONTag *) *)tags; + +@end diff --git a/Pod/Classes/BONText.h b/Pod/Classes/BONText.h index 0f305e6f..ae3f6081 100644 --- a/Pod/Classes/BONText.h +++ b/Pod/Classes/BONText.h @@ -24,6 +24,7 @@ typedef NS_ENUM(NSUInteger, BONFigureSpacing) { }; @class BONText; +@class BONTag; @interface BONText : NSObject @@ -84,6 +85,11 @@ typedef NS_ENUM(NSUInteger, BONFigureSpacing) { @property (nonatomic) NSUnderlineStyle strikethroughStyle; @property (strong, nonatomic, BONNullable) UIColor *strikethroughColor; +/** + * An array of @p BONTag objects to use in styling substrings. + */ +@property (strong, nonatomic, BONNullable) BONGeneric(NSArray, BONTag *) * tagStyles; + // Getting Values Out @property (copy, nonatomic, readonly, BONNonnull) NSAttributedString *attributedString; diff --git a/Pod/Classes/BONText.m b/Pod/Classes/BONText.m index 152d4a36..1479af79 100644 --- a/Pod/Classes/BONText.m +++ b/Pod/Classes/BONText.m @@ -9,6 +9,7 @@ #import "BONText.h" #import "BONText_Private.h" #import "BONSpecial.h" +#import "BONTag_Private.h" @import CoreText.SFNTLayoutTypes; @@ -72,6 +73,8 @@ - (NSAttributedString *)attributedStringLastConcatenant:(BOOL)lastConcatenant { NSMutableAttributedString *mutableAttributedString = nil; + NSString *string = self.string; + if (self.image) { NSAssert(!self.string, @"If self.image is non-nil, self.string must be nil"); NSTextAttachment *attachment = [[NSTextAttachment alloc] init]; @@ -89,11 +92,26 @@ - (NSAttributedString *)attributedStringLastConcatenant:(BOOL)lastConcatenant [mutableAttributedString appendAttributedString:[[NSAttributedString alloc] initWithString:@"\t" attributes:self.attributes]]; } } - else if (self.string) { - mutableAttributedString = [[NSMutableAttributedString alloc] initWithString:self.string + else if (string) { + // If there is tag styling applied, strip the tags from the string and identify the ranges to apply the tag-based chains to. + BONGeneric(NSArray, BONTag *)*rangesPerTag = nil; + + if (self.tagStyles) { + rangesPerTag = [BONTag rangesInString:&string betweenTags:self.tagStyles]; + } + + mutableAttributedString = [[NSMutableAttributedString alloc] initWithString:string attributes:self.attributes]; - if (lastConcatenant && self.string.length > 0) { - NSRange lastCharacterRange = NSMakeRange(self.string.length - 1, 1); + + for (BONTag *tag in rangesPerTag) { + BONStringDict *attributes = tag.textable.text.attributes; + for (NSValue *value in tag.ranges) { + [mutableAttributedString setAttributes:attributes range:value.rangeValue]; + } + } + + if (lastConcatenant && string.length > 0) { + NSRange lastCharacterRange = NSMakeRange(string.length - 1, 1); [mutableAttributedString removeAttribute:NSKernAttributeName range:lastCharacterRange]; } else { @@ -114,8 +132,8 @@ - (NSAttributedString *)attributedStringLastConcatenant:(BOOL)lastConcatenant if (self.image) { indentation += self.image.size.width; } - else if (self.string) { - NSAttributedString *measurementString = [[NSAttributedString alloc] initWithString:self.string attributes:self.attributes]; + else if (string) { + NSAttributedString *measurementString = [[NSAttributedString alloc] initWithString:string attributes:self.attributes]; CGRect boundingRect = [measurementString boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil]; @@ -409,6 +427,8 @@ - (id)copyWithZone:(NSZone *)zone text.strikethroughStyle = self.strikethroughStyle; text.strikethroughColor = self.strikethroughColor; + text.tagStyles = self.tagStyles; + return text; } diff --git a/Pod/UIKit/BonMot+UIKit.h b/Pod/UIKit/BonMot+UIKit.h index e10f4771..656a4b5e 100644 --- a/Pod/UIKit/BonMot+UIKit.h +++ b/Pod/UIKit/BonMot+UIKit.h @@ -3,7 +3,7 @@ // BonMot // // Created by Nora Trapp on 3/10/16. -// +// Copyright © 2015 Zev Eisenberg. All rights reserved. // #import "BONTextAlignmentConstraint.h" diff --git a/Pod/UIKit/Classes/UILabel+BonMotUtilities.h b/Pod/UIKit/Classes/UILabel+BonMotUtilities.h index 3b5aef65..ab3ad7ff 100644 --- a/Pod/UIKit/Classes/UILabel+BonMotUtilities.h +++ b/Pod/UIKit/Classes/UILabel+BonMotUtilities.h @@ -3,7 +3,7 @@ // BonMot // // Created by Nora Trapp on 3/2/16. -// +// Copyright © 2015 Zev Eisenberg. All rights reserved. // @import UIKit; diff --git a/Pod/UIKit/Classes/UILabel+BonMotUtilities.m b/Pod/UIKit/Classes/UILabel+BonMotUtilities.m index 77766652..3969ffb7 100644 --- a/Pod/UIKit/Classes/UILabel+BonMotUtilities.m +++ b/Pod/UIKit/Classes/UILabel+BonMotUtilities.m @@ -3,7 +3,7 @@ // BonMot // // Created by Nora Trapp on 3/2/16. -// +// Copyright © 2015 Zev Eisenberg. All rights reserved. // #import "BonMot.h" diff --git a/Pod/UIKit/Classes/UITextField+BonMotUtilities.h b/Pod/UIKit/Classes/UITextField+BonMotUtilities.h index b9bcb896..51fadfc4 100644 --- a/Pod/UIKit/Classes/UITextField+BonMotUtilities.h +++ b/Pod/UIKit/Classes/UITextField+BonMotUtilities.h @@ -3,7 +3,7 @@ // BonMot // // Created by Nora Trapp on 3/2/16. -// +// Copyright © 2015 Zev Eisenberg. All rights reserved. // @import UIKit; diff --git a/Pod/UIKit/Classes/UITextField+BonMotUtilities.m b/Pod/UIKit/Classes/UITextField+BonMotUtilities.m index 94e88e68..b2a23143 100644 --- a/Pod/UIKit/Classes/UITextField+BonMotUtilities.m +++ b/Pod/UIKit/Classes/UITextField+BonMotUtilities.m @@ -3,7 +3,7 @@ // BonMot // // Created by Nora Trapp on 3/2/16. -// +// Copyright © 2015 Zev Eisenberg. All rights reserved. // #import "BonMot.h" diff --git a/Pod/UIKit/Classes/UITextView+BonMotUtilities.h b/Pod/UIKit/Classes/UITextView+BonMotUtilities.h index ddcce300..9578df3e 100644 --- a/Pod/UIKit/Classes/UITextView+BonMotUtilities.h +++ b/Pod/UIKit/Classes/UITextView+BonMotUtilities.h @@ -3,7 +3,7 @@ // BonMot // // Created by Nora Trapp on 3/2/16. -// +// Copyright © 2015 Zev Eisenberg. All rights reserved. // @import UIKit; diff --git a/Pod/UIKit/Classes/UITextView+BonMotUtilities.m b/Pod/UIKit/Classes/UITextView+BonMotUtilities.m index 17531209..128f31ad 100644 --- a/Pod/UIKit/Classes/UITextView+BonMotUtilities.m +++ b/Pod/UIKit/Classes/UITextView+BonMotUtilities.m @@ -3,7 +3,7 @@ // BonMot // // Created by Nora Trapp on 3/2/16. -// +// Copyright © 2015 Zev Eisenberg. All rights reserved. // #import "BonMot.h" diff --git a/README.md b/README.md index 7c2fe0c8..ebc03697 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ BonMot uses attributed strings to give you control over the following typographi - Figure case (uppercase vs. lowercase numbers) - Figure spacing (monospace vs. proportional numbers) - Inline Images with optional multi-line paragraph alignment +- Tag parsing (excluding nested tags) Think something is missing? Please [file an issue](https://github.com/Raizlabs/BonMot/issues) (or add a +1 if one already exists). @@ -267,6 +268,45 @@ Prints this: {image24x36}{noBreakSpace}Monday{enDash}Friday ``` +## Tag Styles + +BonMot can style text between arbirtrary tags using a `` format and `\` as an escape character. This allows you to apply styles to substrings of localized strings, whose position, order, and even existence may change from language to language. + +```objc +BONChain *boldChain = BONChain.new.fontNameAndSize(@"Baskerville-Bold", 15.0f); +BONChain *italicChain = BONChain.new.fontNameAndSize(@"Baskerville-Italic", 15.0f); + +BONChain *chain = BONChain.new.fontNameAndSize(@"Baskerville", 17.0f) + .tagStyles( @{ @"bold": boldChain, @"italic": italicChain } ) + .string(@"This text contains a \\ tag.\nThis text contains an \\ tag."); + +NSAttributedString *string = chain.attributedString; +``` + +Outputs: + + + +BonMot can also style text between any arbitrary start and end strings using any escape string. + +```objc +BONChain *boldChain = BONChain.new.fontNameAndSize(@"Baskerville-Bold", 15.0f); +BONChain *italicChain = BONChain.new.fontNameAndSize(@"Baskerville-Italic", 15.0f); + +BONChain *chain = BONChain.new.fontNameAndSize(@"Baskerville", 17.0f) +.tagComplexStyles(@[BONTagComplexMake(@"~start~", @"!end", @"escape", boldChain)]) +.string(@"~start~This text is wrapped in a escape~start~ tag.!end"); + +NSAttributedString *string = chain.attributedString; +``` + +Outputs: + + + +**Note:** Tag styles do not support nested or interleaved tags. The first tag matched will be applied, any additional tags between the start end end will be ignored. + + ## Contributing Issues and pull requests are welcome! Please format all code using [`clang-format`](http://clang.llvm.org/docs/ClangFormat.html) and the included `.clang-format` configuration file. diff --git a/readme-images/arbitrary-tag-styling.png b/readme-images/arbitrary-tag-styling.png new file mode 100644 index 00000000..3de039d8 Binary files /dev/null and b/readme-images/arbitrary-tag-styling.png differ diff --git a/readme-images/tag-styling.png b/readme-images/tag-styling.png new file mode 100644 index 00000000..56eb475c Binary files /dev/null and b/readme-images/tag-styling.png differ