diff --git a/RichTextEditor.xcodeproj/project.pbxproj b/RichTextEditor.xcodeproj/project.pbxproj index 236b1e9..b7442c5 100644 --- a/RichTextEditor.xcodeproj/project.pbxproj +++ b/RichTextEditor.xcodeproj/project.pbxproj @@ -46,7 +46,6 @@ 1583892C1735A5D7006DE713 /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1583892A1735A5D7006DE713 /* MainStoryboard_iPhone.storyboard */; }; 1583892F1735A5D7006DE713 /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1583892D1735A5D7006DE713 /* MainStoryboard_iPad.storyboard */; }; 158389321735A5D7006DE713 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 158389311735A5D7006DE713 /* ViewController.m */; }; - 1583893A1735A5D7006DE713 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 158389391735A5D7006DE713 /* SenTestingKit.framework */; }; 1583893B1735A5D7006DE713 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 158389121735A5D7006DE713 /* UIKit.framework */; }; 1583893C1735A5D7006DE713 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 158389141735A5D7006DE713 /* Foundation.framework */; }; 158389441735A5D7006DE713 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 158389421735A5D7006DE713 /* InfoPlist.strings */; }; @@ -172,8 +171,7 @@ 1583892E1735A5D7006DE713 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPad.storyboard; sourceTree = ""; }; 158389301735A5D7006DE713 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 158389311735A5D7006DE713 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; - 158389381735A5D7006DE713 /* RichTextEditorTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RichTextEditorTests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; - 158389391735A5D7006DE713 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; + 158389381735A5D7006DE713 /* RichTextEditorTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RichTextEditorTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 158389411735A5D7006DE713 /* RichTextEditorTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RichTextEditorTests-Info.plist"; sourceTree = ""; }; 158389431735A5D7006DE713 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 158389451735A5D7006DE713 /* RichTextEditorTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RichTextEditorTests.h; sourceTree = ""; }; @@ -216,6 +214,9 @@ 15C4133517A48C6D0073D047 /* buttoncenter.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = buttoncenter.png; sourceTree = ""; }; 15C4133617A48C6D0073D047 /* buttonleft.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = buttonleft.png; sourceTree = ""; }; 15C4133717A48C6D0073D047 /* buttonright.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = buttonright.png; sourceTree = ""; }; + 15C9AC7818A69C69006E6F27 /* RichTextEditorColorPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RichTextEditorColorPicker.h; sourceTree = ""; }; + 15C9AC7918A69E12006E6F27 /* RichTextEditorFontPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RichTextEditorFontPicker.h; sourceTree = ""; }; + 15C9AC7A18A69E6E006E6F27 /* RichTextEditorFontSizePicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RichTextEditorFontSizePicker.h; sourceTree = ""; }; 1AFAED6E17C7F9CA00E450B0 /* strikethrough@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "strikethrough@2x.png"; sourceTree = ""; }; 1AFAED6F17C7F9CA00E450B0 /* italic@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "italic@2x.png"; sourceTree = ""; }; 1AFAED7017C7F9CA00E450B0 /* underline@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "underline@2x.png"; sourceTree = ""; }; @@ -247,7 +248,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1583893A1735A5D7006DE713 /* SenTestingKit.framework in Frameworks */, 1583893B1735A5D7006DE713 /* UIKit.framework in Frameworks */, 1583893C1735A5D7006DE713 /* Foundation.framework in Frameworks */, ); @@ -268,10 +268,13 @@ 153F9585179F9953005B2487 /* RichTextEditorToolbar.m */, 15B6E20D17A4C2820015867C /* RichTextEditorToggleButton.h */, 15B6E20E17A4C2820015867C /* RichTextEditorToggleButton.m */, + 15C9AC7818A69C69006E6F27 /* RichTextEditorColorPicker.h */, 153F957D179F9953005B2487 /* RichTextEditorColorPickerViewController.h */, 153F957E179F9953005B2487 /* RichTextEditorColorPickerViewController.m */, + 15C9AC7918A69E12006E6F27 /* RichTextEditorFontPicker.h */, 153F957F179F9953005B2487 /* RichTextEditorFontPickerViewController.h */, 153F9580179F9953005B2487 /* RichTextEditorFontPickerViewController.m */, + 15C9AC7A18A69E6E006E6F27 /* RichTextEditorFontSizePicker.h */, 153F9581179F9953005B2487 /* RichTextEditorFontSizePickerViewController.h */, 153F9582179F9953005B2487 /* RichTextEditorFontSizePickerViewController.m */, 153F9583179F9953005B2487 /* RichTextEditorPopover.h */, @@ -391,7 +394,7 @@ isa = PBXGroup; children = ( 1583890E1735A5D7006DE713 /* RichTextEditor.app */, - 158389381735A5D7006DE713 /* RichTextEditorTests.octest */, + 158389381735A5D7006DE713 /* RichTextEditorTests.xctest */, ); name = Products; sourceTree = ""; @@ -403,7 +406,6 @@ 158389121735A5D7006DE713 /* UIKit.framework */, 158389141735A5D7006DE713 /* Foundation.framework */, 158389161735A5D7006DE713 /* CoreGraphics.framework */, - 158389391735A5D7006DE713 /* SenTestingKit.framework */, ); name = Frameworks; sourceTree = ""; @@ -509,8 +511,8 @@ ); name = RichTextEditorTests; productName = RichTextEditorTests; - productReference = 158389381735A5D7006DE713 /* RichTextEditorTests.octest */; - productType = "com.apple.product-type.bundle"; + productReference = 158389381735A5D7006DE713 /* RichTextEditorTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ @@ -518,7 +520,8 @@ 158389051735A5D7006DE713 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0450; + LastTestingUpgradeCheck = 0510; + LastUpgradeCheck = 0510; ORGANIZATIONNAME = "Aryan Ghassemi"; }; buildConfigurationList = 158389081735A5D7006DE713 /* Build configuration list for PBXProject "RichTextEditor" */; @@ -743,6 +746,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 6.0; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -800,13 +804,13 @@ FRAMEWORK_SEARCH_PATHS = ( "\"$(SDKROOT)/Developer/Library/Frameworks\"", "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", + "$(inherited)", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "RichTextEditor/RichTextEditor-Prefix.pch"; INFOPLIST_FILE = "RichTextEditorTests/RichTextEditorTests-Info.plist"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUNDLE_LOADER)"; - WRAPPER_EXTENSION = octest; }; name = Debug; }; @@ -817,13 +821,13 @@ FRAMEWORK_SEARCH_PATHS = ( "\"$(SDKROOT)/Developer/Library/Frameworks\"", "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", + "$(inherited)", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "RichTextEditor/RichTextEditor-Prefix.pch"; INFOPLIST_FILE = "RichTextEditorTests/RichTextEditorTests-Info.plist"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUNDLE_LOADER)"; - WRAPPER_EXTENSION = octest; }; name = Release; }; diff --git a/RichTextEditor.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/RichTextEditor.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..242f037 --- /dev/null +++ b/RichTextEditor.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/RichTextEditor.xcodeproj/project.xcworkspace/xcshareddata/RichTextEditor.xccheckout b/RichTextEditor.xcodeproj/project.xcworkspace/xcshareddata/RichTextEditor.xccheckout new file mode 100644 index 0000000..f3b529d --- /dev/null +++ b/RichTextEditor.xcodeproj/project.xcworkspace/xcshareddata/RichTextEditor.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + 5094D3CF-B317-41F7-9AA1-801D09780AE3 + IDESourceControlProjectName + RichTextEditor + IDESourceControlProjectOriginsDictionary + + D9C29B00-DAC9-49D9-839A-1500CC1E9C1A + http://github.com/aryaxt/iOS-Rich-Text-Editor.git + + IDESourceControlProjectPath + RichTextEditor.xcodeproj/project.xcworkspace + IDESourceControlProjectRelativeInstallPathDictionary + + D9C29B00-DAC9-49D9-839A-1500CC1E9C1A + ../.. + + IDESourceControlProjectURL + http://github.com/aryaxt/iOS-Rich-Text-Editor.git + IDESourceControlProjectVersion + 110 + IDESourceControlProjectWCCIdentifier + D9C29B00-DAC9-49D9-839A-1500CC1E9C1A + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + D9C29B00-DAC9-49D9-839A-1500CC1E9C1A + IDESourceControlWCCName + iOS-Rich-Text-Editor + + + + diff --git a/RichTextEditor.xcodeproj/project.xcworkspace/xcuserdata/aryaxt.xcuserdatad/UserInterfaceState.xcuserstate b/RichTextEditor.xcodeproj/project.xcworkspace/xcuserdata/aryaxt.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..a5d5c62 Binary files /dev/null and b/RichTextEditor.xcodeproj/project.xcworkspace/xcuserdata/aryaxt.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/RichTextEditor.xcodeproj/project.xcworkspace/xcuserdata/aryaxt.xcuserdatad/WorkspaceSettings.xcsettings b/RichTextEditor.xcodeproj/project.xcworkspace/xcuserdata/aryaxt.xcuserdatad/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..bfffcfe --- /dev/null +++ b/RichTextEditor.xcodeproj/project.xcworkspace/xcuserdata/aryaxt.xcuserdatad/WorkspaceSettings.xcsettings @@ -0,0 +1,10 @@ + + + + + HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges + + SnapshotAutomaticallyBeforeSignificantChanges + + + diff --git a/RichTextEditor.xcodeproj/xcuserdata/aryaxt.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist b/RichTextEditor.xcodeproj/xcuserdata/aryaxt.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist new file mode 100644 index 0000000..05301bc --- /dev/null +++ b/RichTextEditor.xcodeproj/xcuserdata/aryaxt.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist @@ -0,0 +1,5 @@ + + + diff --git a/RichTextEditor.xcodeproj/xcuserdata/aryaxt.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/RichTextEditor.xcodeproj/xcuserdata/aryaxt.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..1a2b502 --- /dev/null +++ b/RichTextEditor.xcodeproj/xcuserdata/aryaxt.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/RichTextEditor.xcodeproj/xcuserdata/aryaxt.xcuserdatad/xcschemes/RichTextEditor.xcscheme b/RichTextEditor.xcodeproj/xcuserdata/aryaxt.xcuserdatad/xcschemes/RichTextEditor.xcscheme new file mode 100644 index 0000000..3cf344b --- /dev/null +++ b/RichTextEditor.xcodeproj/xcuserdata/aryaxt.xcuserdatad/xcschemes/RichTextEditor.xcscheme @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RichTextEditor.xcodeproj/xcuserdata/aryaxt.xcuserdatad/xcschemes/xcschememanagement.plist b/RichTextEditor.xcodeproj/xcuserdata/aryaxt.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..051c7c6 --- /dev/null +++ b/RichTextEditor.xcodeproj/xcuserdata/aryaxt.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,27 @@ + + + + + SchemeUserState + + RichTextEditor.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 1583890D1735A5D7006DE713 + + primary + + + 158389371735A5D7006DE713 + + primary + + + + + diff --git a/RichTextEditor/Source/Assets/colorsOld.jpg b/RichTextEditor/Source/Assets/colorsOld.jpg new file mode 100644 index 0000000..20e8f2c Binary files /dev/null and b/RichTextEditor/Source/Assets/colorsOld.jpg differ diff --git a/RichTextEditor/Source/Categories/NSAttributedString+RichTextEditor.m b/RichTextEditor/Source/Categories/NSAttributedString+RichTextEditor.m index 15052e2..5c55114 100644 --- a/RichTextEditor/Source/Categories/NSAttributedString+RichTextEditor.m +++ b/RichTextEditor/Source/Categories/NSAttributedString+RichTextEditor.m @@ -33,6 +33,9 @@ @implementation NSAttributedString (RichTextEditor) - (NSRange)firstParagraphRangeFromTextRange:(NSRange)range { + if (self.string.length == 0) + return NSMakeRange(0, 0); + NSInteger start = -1; NSInteger end = -1; NSInteger length = 0; @@ -41,7 +44,7 @@ - (NSRange)firstParagraphRangeFromTextRange:(NSRange)range range.location-1 : range.location; - for (int i=startingRange ; i>=0 ; i--) + for (NSInteger i=startingRange ; i>=0 ; i--) { char c = [self.string characterAtIndex:i]; if (c == '\n') @@ -55,7 +58,7 @@ - (NSRange)firstParagraphRangeFromTextRange:(NSRange)range NSInteger moveForwardIndex = (range.location > start) ? range.location : start; - for (int i=moveForwardIndex; i<= self.string.length-1 ; i++) + for (NSInteger i=moveForwardIndex; i<= self.string.length-1 ; i++) { char c = [self.string characterAtIndex:i]; if (c == '\n') diff --git a/RichTextEditor/Source/Categories/UIFont+RichTextEditor.m b/RichTextEditor/Source/Categories/UIFont+RichTextEditor.m index 10b95ce..62f831b 100644 --- a/RichTextEditor/Source/Categories/UIFont+RichTextEditor.m +++ b/RichTextEditor/Source/Categories/UIFont+RichTextEditor.m @@ -58,10 +58,15 @@ + (UIFont *)fontWithName:(NSString *)name size:(CGFloat)size boldTrait:(BOOL)isB newFontRef = CTFontCreateCopyWithSymbolicTraits(fontWithoutTrait, 0.0, NULL, traits, traits); } + if (fontWithoutTrait) + CFRelease(fontWithoutTrait); + if (newFontRef) { NSString *fontNameKey = (__bridge NSString *)(CTFontCopyName(newFontRef, kCTFontPostScriptNameKey)); - return [UIFont fontWithName:fontNameKey size:CTFontGetSize(newFontRef)]; + CGFloat size = CTFontGetSize(newFontRef); + CFRelease(newFontRef); + return [UIFont fontWithName:fontNameKey size:size]; } return nil; diff --git a/RichTextEditor/Source/RichTextEditor.h b/RichTextEditor/Source/RichTextEditor.h index 80e1081..db84e3f 100644 --- a/RichTextEditor/Source/RichTextEditor.h +++ b/RichTextEditor/Source/RichTextEditor.h @@ -39,6 +39,9 @@ - (RichTextEditorFeature)featuresEnabledForRichTextEditor:(RichTextEditor *)richTextEditor; - (BOOL)shouldDisplayToolbarForRichTextEditor:(RichTextEditor *)richTextEditor; - (BOOL)shouldDisplayRichTextOptionsInMenuControllerForRichTextEditor:(RichTextEditor *)richTextEdiotor; +- (UIViewController *)colorPickerForRichTextEditor:(RichTextEditor *)richTextEdiotor withAction:(RichTextEditorColorPickerAction)action; +- (UIViewController *)fontPickerForRichTextEditor:(RichTextEditor *)richTextEdiotor; +- (UIViewController *)fontSizePickerForRichTextEditor:(RichTextEditor *)richTextEdiotor; @end @interface RichTextEditor : UITextView @@ -49,5 +52,6 @@ - (void)setBorderColor:(UIColor*)borderColor; - (void)setBorderWidth:(CGFloat)borderWidth; - (NSString *)htmlString; +- (void)setHtmlString:(NSString *)htmlString; @end diff --git a/RichTextEditor/Source/RichTextEditor.m b/RichTextEditor/Source/RichTextEditor.m index 86231e9..bd6b7e2 100644 --- a/RichTextEditor/Source/RichTextEditor.m +++ b/RichTextEditor/Source/RichTextEditor.m @@ -32,6 +32,7 @@ #import "UIView+RichTextEditor.h" #define RICHTEXTEDITOR_TOOLBAR_HEIGHT 40 +#define BULLET_STRING @"\t•\t" @interface RichTextEditor() @property (nonatomic, strong) RichTextEditorToolbar *toolBar; @@ -88,10 +89,16 @@ - (void)commonInitialization self.defaultIndentationSize = 15; [self setupMenuItems]; - - //If there is text already, then we do want to update the toolbar. Otherwise we don't. - if ([self hasText]) - [self updateToolbarState]; + [self updateToolbarState]; + + // When text changes check to see if we need to add bullet, or delete bullet on backspace + [[NSNotificationCenter defaultCenter] addObserverForName:UITextViewTextDidChangeNotification + object:self + queue:nil + usingBlock:^(NSNotification *n){ + [self applyBulletListIfApplicable]; + [self deleteBulletListWhenApplicable]; + }]; } #pragma mark - Override Methods - @@ -148,6 +155,24 @@ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender return [super canPerformAction:action withSender:sender]; } +- (void)setAttributedText:(NSAttributedString *)attributedText +{ + [super setAttributedText:attributedText]; + [self updateToolbarState]; +} + +- (void)setText:(NSString *)text +{ + [super setText:text]; + [self updateToolbarState]; +} + +- (void)setFont:(UIFont *)font +{ + [super setFont:font]; + [self updateToolbarState]; +} + #pragma mark - MenuController Methods - - (void)setupMenuItems @@ -163,9 +188,6 @@ - (void)setupMenuItems - (void)selectParagraph:(id)sender { - if (![self hasText]) - return; - NSRange range = [self.attributedText firstParagraphRangeFromTextRange:self.selectedRange]; [self setSelectedRange:range]; @@ -175,9 +197,41 @@ - (void)selectParagraph:(id)sender #pragma mark - Public Methods - +- (void)setHtmlString:(NSString *)htmlString +{ + if (!SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) + { + NSLog(@"Method setHtmlString is only supported on iOS 7 and above"); + return; + } + + NSError *error ; + NSData *data = [htmlString dataUsingEncoding:NSUTF8StringEncoding]; + NSAttributedString *str = [[NSAttributedString alloc] initWithData:data + + options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, + NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]} + documentAttributes:nil error:&error]; + + if (error) + NSLog(@"%@", error); + else + self.attributedText = str; +} + - (NSString *)htmlString { - return [self.attributedText htmlString]; + if (!SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) + { + NSLog(@"Method setHtmlString is only supported on iOS 7 and above"); + return nil; + } + + NSData *data = [self.attributedText dataFromRange:NSMakeRange(0, self.text.length) documentAttributes:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, + NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]} + error:nil]; + + return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; } - (void)setBorderColor:(UIColor *)borderColor @@ -192,6 +246,12 @@ - (void)setBorderWidth:(CGFloat)borderWidth #pragma mark - RichTextEditorToolbarDelegate Methods - +- (void)richTextEditorToolbarDidDismissViewController +{ + if (![self isFirstResponder]) + [self becomeFirstResponder]; +} + - (void)richTextEditorToolbarDidSelectBold { UIFont *font = [self fontAtIndex:self.selectedRange.location]; @@ -216,12 +276,18 @@ - (void)richTextEditorToolbarDidSelectFontWithName:(NSString *)fontName - (void)richTextEditorToolbarDidSelectTextBackgroundColor:(UIColor *)color { - [self applyAttrubutesToSelectedRange:color forKey:NSBackgroundColorAttributeName]; + if (color) + [self applyAttrubutesToSelectedRange:color forKey:NSBackgroundColorAttributeName]; + else + [self removeAttributeForKeyFromSelectedRange:NSBackgroundColorAttributeName]; } - (void)richTextEditorToolbarDidSelectTextForegroundColor:(UIColor *)color { - [self applyAttrubutesToSelectedRange:color forKey:NSForegroundColorAttributeName]; + if (color) + [self applyAttrubutesToSelectedRange:color forKey:NSForegroundColorAttributeName]; + else + [self removeAttributeForKeyFromSelectedRange:NSForegroundColorAttributeName]; } - (void)richTextEditorToolbarDidSelectUnderline @@ -317,9 +383,119 @@ - (void)richTextEditorToolbarDidSelectTextAlignment:(NSTextAlignment)textAlignme }]; } -- (void)richTextEditorToolbarDidSelectBulletPoint +- (void)richTextEditorToolbarDidSelectBulletList +{ + NSRange initialSelectedRange = self.selectedRange; + NSArray *rangeOfParagraphsInSelectedText = [self.attributedText rangeOfParagraphsFromTextRange:self.selectedRange]; + NSRange rangeOfFirstParagraphRange = [self.attributedText firstParagraphRangeFromTextRange:self.selectedRange]; + BOOL firstParagraphHasBullet = ([[[self.attributedText string] substringFromIndex:rangeOfFirstParagraphRange.location] hasPrefix:BULLET_STRING]) ? YES: NO; + + __block NSInteger rangeOffset = 0; + + [self enumarateThroughParagraphsInRange:self.selectedRange withBlock:^(NSRange paragraphRange){ + NSRange range = NSMakeRange(paragraphRange.location + rangeOffset, paragraphRange.length); + NSMutableAttributedString *currentAttributedString = [self.attributedText mutableCopy]; + NSDictionary *dictionary = [self dictionaryAtIndex:MAX((int)range.location-1, 0)]; + NSMutableParagraphStyle *paragraphStyle = [[dictionary objectForKey:NSParagraphStyleAttributeName] mutableCopy]; + + if (!paragraphStyle) + paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + + BOOL currentParagraphHasBullet = ([[[currentAttributedString string] substringFromIndex:range.location] hasPrefix:BULLET_STRING]) ? YES : NO; + + if (firstParagraphHasBullet != currentParagraphHasBullet) + return; + + if (currentParagraphHasBullet) + { + range = NSMakeRange(range.location, range.length - BULLET_STRING.length); + + [currentAttributedString deleteCharactersInRange:NSMakeRange(range.location, BULLET_STRING.length)]; + + paragraphStyle.firstLineHeadIndent = 0; + paragraphStyle.headIndent = 0; + + rangeOffset = rangeOffset - BULLET_STRING.length; + } + else + { + range = NSMakeRange(range.location, range.length + BULLET_STRING.length); + + // The bullet should be bold + NSMutableAttributedString *bulletAttributedString = [[NSMutableAttributedString alloc] initWithString:BULLET_STRING attributes:nil]; + [bulletAttributedString setAttributes:dictionary range:NSMakeRange(0, BULLET_STRING.length)]; + + [currentAttributedString insertAttributedString:bulletAttributedString atIndex:range.location]; + + CGSize expectedStringSize = [BULLET_STRING sizeWithFont:[dictionary objectForKey:NSFontAttributeName] + constrainedToSize:CGSizeMake(MAXFLOAT, MAXFLOAT) + lineBreakMode:NSLineBreakByWordWrapping]; + + paragraphStyle.firstLineHeadIndent = 0; + paragraphStyle.headIndent = expectedStringSize.width; + + rangeOffset = rangeOffset + BULLET_STRING.length; + } + + self.attributedText = currentAttributedString; + [self applyAttributes:paragraphStyle forKey:NSParagraphStyleAttributeName atRange:range]; + }]; + + // If paragraph is empty move cursor to front of bullet, so the user can start typing right away + if (rangeOfParagraphsInSelectedText.count == 1 && rangeOfFirstParagraphRange.length == 0) + { + [self setSelectedRange:NSMakeRange(rangeOfFirstParagraphRange.location + BULLET_STRING.length, 0)]; + } + else + { + if (initialSelectedRange.length == 0) + { + [self setSelectedRange:NSMakeRange(initialSelectedRange.location+rangeOffset, 0)]; + } + else + { + NSRange fullRange = [self fullRangeFromArrayOfParagraphRanges:rangeOfParagraphsInSelectedText]; + [self setSelectedRange:NSMakeRange(fullRange.location, fullRange.length+rangeOffset)]; + } + } +} + +- (void)richTextEditorToolbarDidSelectTextAttachment:(UIImage *)textAttachment +{ + NSTextAttachment *attachment = [[NSTextAttachment alloc] init]; + [attachment setImage:textAttachment]; + NSAttributedString *attributedStringAttachment = [NSAttributedString attributedStringWithAttachment:attachment]; + + NSDictionary *previousAttributes = [self dictionaryAtIndex:self.selectedRange.location]; + + NSMutableAttributedString *attributedString = [self.attributedText mutableCopy]; + [attributedString insertAttributedString:attributedStringAttachment atIndex:self.selectedRange.location]; + [attributedString addAttributes:previousAttributes range:NSMakeRange(self.selectedRange.location, 1)]; + self.attributedText = attributedString; +} + +- (UIViewController *)colorPickerForRichTextEditorToolbarWithAction:(RichTextEditorColorPickerAction)action +{ + if ([self.dataSource respondsToSelector:@selector(colorPickerForRichTextEditor:forAction:)]) + return [self.dataSource colorPickerForRichTextEditor:self withAction:action]; + + return nil; +} + +- (UIViewController *)fontPickerForRichTextEditorToolbar +{ + if ([self.dataSource respondsToSelector:@selector(fontPickerForRichTextEditor:)]) + return [self.dataSource fontPickerForRichTextEditor:self]; + + return nil; +} + +- (UIViewController *)fontSizePickerForRichTextEditorToolbar { - // TODO: implement this + if ([self.dataSource respondsToSelector:@selector(fontSizePickerForRichTextEditor:)]) + return [self.dataSource fontSizePickerForRichTextEditor:self]; + + return nil; } #pragma mark - Private Methods - @@ -342,9 +518,6 @@ - (CGRect)frameOfTextAtRange:(NSRange)range - (void)enumarateThroughParagraphsInRange:(NSRange)range withBlock:(void (^)(NSRange paragraphRange))block { - if (![self hasText]) - return; - NSArray *rangeOfParagraphsInSelectedText = [self.attributedText rangeOfParagraphsFromTextRange:self.selectedRange]; for (int i=0 ; i 0) + { + if ((int)range.location-2 >= 0 && [[self.attributedText.string substringFromIndex:range.location-2] hasPrefix:@"\t•"]) + { + // Get rid of bullet string + NSMutableAttributedString *mutableAttributedString = [self.attributedText mutableCopy]; + [mutableAttributedString deleteCharactersInRange:NSMakeRange(range.location-2, 2)]; + self.attributedText = mutableAttributedString; + NSRange newRange = NSMakeRange(range.location-2, 0); + [self setSelectedRange:newRange]; + + // Get rid of bullet indentation + NSRange rangeOfParagraph = [self.attributedText firstParagraphRangeFromTextRange:newRange]; + NSDictionary *dictionary = [self dictionaryAtIndex:newRange.location]; + NSMutableParagraphStyle *paragraphStyle = [[dictionary objectForKey:NSParagraphStyleAttributeName] mutableCopy]; + paragraphStyle.firstLineHeadIndent = 0; + paragraphStyle.headIndent = 0; + [self applyAttributes:paragraphStyle forKey:NSParagraphStyleAttributeName atRange:rangeOfParagraph]; + } + } +} + #pragma mark - RichTextEditorToolbarDataSource Methods - - (NSArray *)fontFamilySelectionForRichTextEditorToolbar diff --git a/RichTextEditor/Source/RichTextEditorColorPicker.h b/RichTextEditor/Source/RichTextEditorColorPicker.h new file mode 100644 index 0000000..6543efb --- /dev/null +++ b/RichTextEditor/Source/RichTextEditorColorPicker.h @@ -0,0 +1,31 @@ +// +// RichTextEditorColorPicker.h +// RichTextEditor +// +// Created by Aryan Gh on 2/8/14. +// Copyright (c) 2014 Aryan Ghassemi. All rights reserved. +// + +#import + +typedef enum { + RichTextEditorColorPickerActionTextForegroudColor, + RichTextEditorColorPickerActionTextBackgroundColor +}RichTextEditorColorPickerAction; + +@protocol RichTextEditorColorPickerViewControllerDelegate +- (void)richTextEditorColorPickerViewControllerDidSelectColor:(UIColor *)color withAction:(RichTextEditorColorPickerAction)action; +- (void)richTextEditorColorPickerViewControllerDidSelectClose; +@end + +@protocol RichTextEditorColorPickerViewControllerDataSource +- (BOOL)richTextEditorColorPickerViewControllerShouldDisplayToolbar; +@end + +@protocol RichTextEditorColorPicker + +@property (nonatomic, weak) id delegate; +@property (nonatomic, weak) id dataSource; +@property (nonatomic, assign) RichTextEditorColorPickerAction action; + +@end diff --git a/RichTextEditor/Source/RichTextEditorColorPickerViewController.h b/RichTextEditor/Source/RichTextEditorColorPickerViewController.h index 0bdaeb5..b844139 100644 --- a/RichTextEditor/Source/RichTextEditorColorPickerViewController.h +++ b/RichTextEditor/Source/RichTextEditorColorPickerViewController.h @@ -28,22 +28,9 @@ #import #import #import "UIView+RichTextEditor.h" +#import "RichTextEditorColorPicker.h" -typedef enum { - RichTextEditorColorPickerActionTextForegroudColor, - RichTextEditorColorPickerActionTextBackgroundColor -}RichTextEditorColorPickerAction; - -@protocol RichTextEditorColorPickerViewControllerDelegate -- (void)richTextEditorColorPickerViewControllerDidSelectColor:(UIColor *)color withAction:(RichTextEditorColorPickerAction)action; -- (void)richTextEditorColorPickerViewControllerDidSelectClose; -@end - -@protocol RichTextEditorColorPickerViewControllerDataSource -- (BOOL)richTextEditorColorPickerViewControllerShouldDisplayToolbar; -@end - -@interface RichTextEditorColorPickerViewController : UIViewController +@interface RichTextEditorColorPickerViewController : UIViewController @property (nonatomic, weak) id delegate; @property (nonatomic, weak) id dataSource; diff --git a/RichTextEditor/Source/RichTextEditorColorPickerViewController.m b/RichTextEditor/Source/RichTextEditorColorPickerViewController.m index a528cb0..efdfe54 100644 --- a/RichTextEditor/Source/RichTextEditorColorPickerViewController.m +++ b/RichTextEditor/Source/RichTextEditorColorPickerViewController.m @@ -37,19 +37,19 @@ - (void)viewDidLoad self.view.backgroundColor = [UIColor whiteColor]; - UIButton *btnClose = [[UIButton alloc] initWithFrame:CGRectMake(5, 5, 60, 30)]; - [btnClose addTarget:self action:@selector(closeSelected:) forControlEvents:UIControlEventTouchUpInside]; - [btnClose.titleLabel setFont:[UIFont boldSystemFontOfSize:12]]; - [btnClose setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; - [btnClose setTitle:@"Close" forState:UIControlStateNormal]; - [self.view addSubview:btnClose]; - - UIButton *btnDone = [[UIButton alloc] initWithFrame:CGRectMake(65, 5, 60, 30)]; + UIButton *btnDone = [[UIButton alloc] initWithFrame:CGRectMake(5, 5, 60, 30)]; [btnDone addTarget:self action:@selector(doneSelected:) forControlEvents:UIControlEventTouchUpInside]; [btnDone.titleLabel setFont:[UIFont boldSystemFontOfSize:12]]; [btnDone setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; - [btnDone setTitle:@"Done" forState:UIControlStateNormal]; + [btnDone setTitle:@"Select" forState:UIControlStateNormal]; [self.view addSubview:btnDone]; + + UIButton *btnClear = [[UIButton alloc] initWithFrame:CGRectMake(65, 5, 60, 30)]; + [btnClear addTarget:self action:@selector(clearSelected:) forControlEvents:UIControlEventTouchUpInside]; + [btnClear.titleLabel setFont:[UIFont boldSystemFontOfSize:12]]; + [btnClear setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [btnClear setTitle:@"Clear" forState:UIControlStateNormal]; + [self.view addSubview:btnClear]; self.selectedColorView = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width - 35 - 5, 5, 35, 30)]; self.selectedColorView.backgroundColor = [UIColor blackColor]; @@ -62,7 +62,7 @@ - (void)viewDidLoad self.colorsImageView.frame = CGRectMake(2, 40, self.view.frame.size.width-4, self.view.frame.size.height - 40 - 2); self.colorsImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.colorsImageView.layer.borderColor = [UIColor lightGrayColor].CGColor; - self.colorsImageView.layer.borderWidth = 1; + self.colorsImageView.layer.borderWidth = 0; [self.view addSubview:self.colorsImageView]; if ([self.dataSource richTextEditorColorPickerViewControllerShouldDisplayToolbar]) @@ -92,9 +92,14 @@ - (void)viewDidLoad target:self action:@selector(closeSelected:)]; + UIBarButtonItem *clearItem = [[UIBarButtonItem alloc] initWithTitle:@"Clear" + style:UIBarButtonItemStyleDone + target:self + action:@selector(clearSelected:)]; + UIBarButtonItem *selectedColorItem = [[UIBarButtonItem alloc] initWithCustomView:self.selectedColorView]; - [toolbar setItems:@[closeItem, flexibleSpaceItem, selectedColorItem, doneItem]]; + [toolbar setItems:@[doneItem, clearItem, flexibleSpaceItem ,selectedColorItem, flexibleSpaceItem , closeItem]]; [self.view addSubview:toolbar]; self.colorsImageView.frame = CGRectMake(2, toolbarHeight+2, self.view.frame.size.width-4, self.view.frame.size.height - (toolbarHeight+4)); @@ -114,7 +119,10 @@ - (void)viewDidLoad - (void)populateColorsForPoint:(CGPoint)point { - self.selectedColorView.backgroundColor = [self.colorsImageView colorOfPoint:point]; + CGPoint pointInView = [self.colorsImageView convertPoint:point toView:self.colorsImageView]; + + if (CGRectContainsPoint(self.colorsImageView.bounds, pointInView)) + self.selectedColorView.backgroundColor = [self.colorsImageView colorOfPoint:pointInView]; } #pragma mark - IBActions - @@ -129,6 +137,11 @@ - (IBAction)closeSelected:(id)sender [self.delegate richTextEditorColorPickerViewControllerDidSelectClose]; } +- (IBAction)clearSelected:(id)sender +{ + [self.delegate richTextEditorColorPickerViewControllerDidSelectColor:nil withAction:self.action]; +} + #pragma mark - Touch Detection - - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event diff --git a/RichTextEditor/Source/RichTextEditorFontPicker.h b/RichTextEditor/Source/RichTextEditorFontPicker.h new file mode 100644 index 0000000..c3262a6 --- /dev/null +++ b/RichTextEditor/Source/RichTextEditorFontPicker.h @@ -0,0 +1,26 @@ +// +// RichTextEditorFontPicker.h +// RichTextEditor +// +// Created by Aryan Gh on 2/8/14. +// Copyright (c) 2014 Aryan Ghassemi. All rights reserved. +// + +#import + +@protocol RichTextEditorFontPickerViewControllerDelegate +- (void)richTextEditorFontPickerViewControllerDidSelectFontWithName:(NSString *)fontName; +- (void)richTextEditorFontPickerViewControllerDidSelectClose; +@end + +@protocol RichTextEditorFontPickerViewControllerDataSource +- (NSArray *)richTextEditorFontPickerViewControllerCustomFontFamilyNamesForSelection; +- (BOOL)richTextEditorFontPickerViewControllerShouldDisplayToolbar; +@end + +@protocol RichTextEditorFontPicker + +@property (nonatomic, weak) id delegate; +@property (nonatomic, weak) id dataSource; + +@end diff --git a/RichTextEditor/Source/RichTextEditorFontPickerViewController.h b/RichTextEditor/Source/RichTextEditorFontPickerViewController.h index 39734a3..6115435 100644 --- a/RichTextEditor/Source/RichTextEditorFontPickerViewController.h +++ b/RichTextEditor/Source/RichTextEditorFontPickerViewController.h @@ -26,18 +26,9 @@ // THE SOFTWARE. #import +#import "RichTextEditorFontPicker.h" -@protocol RichTextEditorFontPickerViewControllerDelegate -- (void)richTextEditorFontPickerViewControllerDidSelectFontWithName:(NSString *)fontName; -- (void)richTextEditorFontPickerViewControllerDidSelectClose; -@end - -@protocol RichTextEditorFontPickerViewControllerDataSource -- (NSArray *)richTextEditorFontPickerViewControllerCustomFontFamilyNamesForSelection; -- (BOOL)richTextEditorFontPickerViewControllerShouldDisplayToolbar; -@end - -@interface RichTextEditorFontPickerViewController : UIViewController +@interface RichTextEditorFontPickerViewController : UIViewController @property (nonatomic, weak) id delegate; @property (nonatomic, weak) id dataSource; diff --git a/RichTextEditor/Source/RichTextEditorFontPickerViewController.m b/RichTextEditor/Source/RichTextEditorFontPickerViewController.m index 4d40174..6be6412 100644 --- a/RichTextEditor/Source/RichTextEditorFontPickerViewController.m +++ b/RichTextEditor/Source/RichTextEditorFontPickerViewController.m @@ -35,11 +35,10 @@ - (void)viewDidLoad NSArray *customizedFontFamilies = [self.dataSource richTextEditorFontPickerViewControllerCustomFontFamilyNamesForSelection]; - if (customizedFontFamilies) { + if (customizedFontFamilies) self.fontNames = customizedFontFamilies; - } else { + else self.fontNames = [[UIFont familyNames] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]; - } if ([self.dataSource richTextEditorFontPickerViewControllerShouldDisplayToolbar]) { diff --git a/RichTextEditor/Source/RichTextEditorFontSizePicker.h b/RichTextEditor/Source/RichTextEditorFontSizePicker.h new file mode 100644 index 0000000..f1917db --- /dev/null +++ b/RichTextEditor/Source/RichTextEditorFontSizePicker.h @@ -0,0 +1,26 @@ +// +// RichTextEditorFontSizePicker.h +// RichTextEditor +// +// Created by Aryan Gh on 2/8/14. +// Copyright (c) 2014 Aryan Ghassemi. All rights reserved. +// + +#import + +@protocol RichTextEditorFontSizePickerViewControllerDelegate +- (void)richTextEditorFontSizePickerViewControllerDidSelectFontSize:(NSNumber *)fontSize; +- (void)richTextEditorFontSizePickerViewControllerDidSelectClose; +@end + +@protocol RichTextEditorFontSizePickerViewControllerDataSource +- (BOOL)richTextEditorFontSizePickerViewControllerShouldDisplayToolbar; +- (NSArray *)richTextEditorFontSizePickerViewControllerCustomFontSizesForSelection; +@end + +@protocol RichTextEditorFontSizePicker + +@property (nonatomic, weak) id delegate; +@property (nonatomic, weak) id dataSource; + +@end diff --git a/RichTextEditor/Source/RichTextEditorFontSizePickerViewController.h b/RichTextEditor/Source/RichTextEditorFontSizePickerViewController.h index 70d6341..8ba4001 100644 --- a/RichTextEditor/Source/RichTextEditorFontSizePickerViewController.h +++ b/RichTextEditor/Source/RichTextEditorFontSizePickerViewController.h @@ -26,18 +26,9 @@ // THE SOFTWARE. #import +#import "RichTextEditorFontSizePicker.h" -@protocol RichTextEditorFontSizePickerViewControllerDelegate -- (void)richTextEditorFontSizePickerViewControllerDidSelectFontSize:(NSNumber *)fontSize; -- (void)richTextEditorFontSizePickerViewControllerDidSelectClose; -@end - -@protocol RichTextEditorFontSizePickerViewControllerDataSource -- (BOOL)richTextEditorFontSizePickerViewControllerShouldDisplayToolbar; -- (NSArray *)richTextEditorFontSizePickerViewControllerCustomFontSizesForSelection; -@end - -@interface RichTextEditorFontSizePickerViewController : UIViewController +@interface RichTextEditorFontSizePickerViewController : UIViewController @property (nonatomic, weak) id delegate; @property (nonatomic, weak) id dataSource; diff --git a/RichTextEditor/Source/RichTextEditorLinkPickerViewController.h b/RichTextEditor/Source/RichTextEditorLinkPickerViewController.h new file mode 100644 index 0000000..53a488b --- /dev/null +++ b/RichTextEditor/Source/RichTextEditorLinkPickerViewController.h @@ -0,0 +1,27 @@ +// +// RichTextEditorLinkPickerViewController.h +// RichTextEditor +// +// Created by Aryan Gh on 8/20/13. +// Copyright (c) 2013 Aryan Ghassemi. All rights reserved. +// + +#import + +@protocol RichTextEditorLinkPickerViewControllerDelegate +- (void)richTextEditorLinkPickerViewControllerDidSelectLinkWithTitle:(NSString *)title andUrl:(NSURL *)url; +- (void)richTextEditorLinkPickerViewControllerDidSelectClose; +@end + +@protocol RichTextEditorLinkPickerViewControllerDataSource +- (BOOL)RichTextEditorLinkPickerViewControllerShouldDisplayToolbar; +@end + +@interface RichTextEditorLinkPickerViewController : UIViewController + +@property (nonatomic, weak) id delegate; +@property (nonatomic, weak) id dataSource; +@property (nonatomic, strong) UITextField *txtTitle; +@property (nonatomic, strong) UITextField *txtUrl; + +@end diff --git a/RichTextEditor/Source/RichTextEditorLinkPickerViewController.m b/RichTextEditor/Source/RichTextEditorLinkPickerViewController.m new file mode 100644 index 0000000..0e1920d --- /dev/null +++ b/RichTextEditor/Source/RichTextEditorLinkPickerViewController.m @@ -0,0 +1,82 @@ +// +// RichTextEditorLinkPickerViewController.m +// RichTextEditor +// +// Created by Aryan Gh on 8/20/13. +// Copyright (c) 2013 Aryan Ghassemi. All rights reserved. +// + +#import "RichTextEditorLinkPickerViewController.h" + +@implementation RichTextEditorLinkPickerViewController + +#pragma mark - UIViewController Methods - + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor whiteColor]; + + UIButton *btnClose = [[UIButton alloc] initWithFrame:CGRectMake(5, 5, 60, 30)]; + [btnClose addTarget:self action:@selector(closeSelected:) forControlEvents:UIControlEventTouchUpInside]; + [btnClose.titleLabel setFont:[UIFont boldSystemFontOfSize:12]]; + [btnClose setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [btnClose setTitle:@"Close" forState:UIControlStateNormal]; + [self.view addSubview:btnClose]; + + UIButton *btnDone = [[UIButton alloc] initWithFrame:CGRectMake(65, 5, 60, 30)]; + [btnDone addTarget:self action:@selector(doneSelected:) forControlEvents:UIControlEventTouchUpInside]; + [btnDone.titleLabel setFont:[UIFont boldSystemFontOfSize:12]]; + [btnDone setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [btnDone setTitle:@"Done" forState:UIControlStateNormal]; + [self.view addSubview:btnDone]; + + self.txtTitle = [[UITextField alloc] initWithFrame:CGRectMake(5, 100, 300, 44)]; + [self.txtTitle setPlaceholder:@"Title"]; + [self.view addSubview:self.txtTitle]; + + self.txtUrl = [[UITextField alloc] initWithFrame:CGRectMake(5, 150, 300, 44)]; + [self.txtUrl setPlaceholder:@"Title"]; + [self.view addSubview:self.txtUrl]; + + if ([self.dataSource RichTextEditorLinkPickerViewControllerShouldDisplayToolbar]) + { + UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)]; + toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [self.view addSubview:toolbar]; + + UIBarButtonItem *flexibleSpaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace + target:nil + action:nil]; + + UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithTitle:@"Done" + style:UIBarButtonItemStyleDone + target:self + action:@selector(doneSelected:)]; + + UIBarButtonItem *closeItem = [[UIBarButtonItem alloc] initWithTitle:@"Close" + style:UIBarButtonItemStyleDone + target:self + action:@selector(closeSelected:)]; + + [toolbar setItems:@[doneItem, flexibleSpaceItem , closeItem]]; + [self.view addSubview:toolbar]; + } + + self.contentSizeForViewInPopover = CGSizeMake(300, 240); +} + +#pragma mark - IBActions - + +- (void)closeSelected:(id)sender +{ + [self.delegate richTextEditorLinkPickerViewControllerDidSelectClose]; +} + +- (void)doneSelected:(id)sender +{ + [self.delegate richTextEditorLinkPickerViewControllerDidSelectLinkWithTitle:self.txtTitle.text andUrl:[NSURL URLWithString:self.txtUrl.text]]; +} + +@end diff --git a/RichTextEditor/Source/RichTextEditorToolbar.h b/RichTextEditor/Source/RichTextEditorToolbar.h index ff6be4d..41b3b94 100644 --- a/RichTextEditor/Source/RichTextEditorToolbar.h +++ b/RichTextEditor/Source/RichTextEditorToolbar.h @@ -26,6 +26,11 @@ // THE SOFTWARE. #import +#import "RichTextEditorColorPicker.h" +#import "RichTextEditorFontPicker.h" +#import "RichTextEditorFontSizePicker.h" + +#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) typedef enum{ RichTextEditorToolbarPresentationStyleModal, @@ -53,15 +58,19 @@ typedef enum{ RichTextEditorFeatureTextForegroundColor = 1 << 11, RichTextEditorFeatureParagraphIndentation = 1 << 12, RichTextEditorFeatureParagraphFirstLineIndentation = 1 << 13, - RichTextEditorFeatureAll = 1 << 14 + RichTextEditorFeatureBulletList = 1 << 14, + RichTextEditorTextAttachment = 1 << 15, + RichTextEditorFeatureAll = 1 << 16 }RichTextEditorFeature; @protocol RichTextEditorToolbarDelegate +- (void)richTextEditorToolbarDidDismissViewController; - (void)richTextEditorToolbarDidSelectBold; - (void)richTextEditorToolbarDidSelectItalic; - (void)richTextEditorToolbarDidSelectUnderline; - (void)richTextEditorToolbarDidSelectStrikeThrough; -- (void)richTextEditorToolbarDidSelectBulletPoint; +- (void)richTextEditorToolbarDidSelectBulletList; +- (void)richTextEditorToolbarDidSelectTextAttachment:(UIImage *)textAttachment; - (void)richTextEditorToolbarDidSelectParagraphFirstLineHeadIndent; - (void)richTextEditorToolbarDidSelectParagraphIndentation:(ParagraphIndentation)paragraphIndentation; - (void)richTextEditorToolbarDidSelectFontSize:(NSNumber *)fontSize; @@ -79,6 +88,9 @@ typedef enum{ - (UIModalTransitionStyle)modalTransitionStyleForRichTextEditorToolbar; - (UIViewController *)firsAvailableViewControllerForRichTextEditorToolbar; - (RichTextEditorFeature)featuresEnabledForRichTextEditorToolbar; +- (UIViewController *)colorPickerForRichTextEditorToolbarWithAction:(RichTextEditorColorPickerAction)action; +- (UIViewController *)fontPickerForRichTextEditorToolbar; +- (UIViewController *)fontSizePickerForRichTextEditorToolbar; @end @interface RichTextEditorToolbar : UIScrollView diff --git a/RichTextEditor/Source/RichTextEditorToolbar.m b/RichTextEditor/Source/RichTextEditorToolbar.m index 7cc443d..9143d88 100644 --- a/RichTextEditor/Source/RichTextEditorToolbar.m +++ b/RichTextEditor/Source/RichTextEditorToolbar.m @@ -39,7 +39,7 @@ #define ITEM_TOP_AND_BOTTOM_BORDER 5 #define ITEM_WITH 40 -@interface RichTextEditorToolbar() +@interface RichTextEditorToolbar() @property (nonatomic, strong) id popover; @property (nonatomic, strong) RichTextEditorToggleButton *btnBold; @property (nonatomic, strong) RichTextEditorToggleButton *btnItalic; @@ -56,7 +56,8 @@ @interface RichTextEditorToolbar() *fontSizePicker = [self.dataSource fontSizePickerForRichTextEditorToolbar]; + + if (!fontSizePicker) + fontSizePicker = [[RichTextEditorFontSizePickerViewController alloc] init]; + fontSizePicker.delegate = self; fontSizePicker.dataSource = self; [self presentViewController:fontSizePicker fromView:sender]; @@ -186,8 +193,11 @@ - (void)fontSizeSelected:(UIButton *)sender - (void)fontSelected:(UIButton *)sender { - RichTextEditorFontPickerViewController *fontPicker= [[RichTextEditorFontPickerViewController alloc] init]; - fontPicker.fontNames = [self.dataSource fontFamilySelectionForRichTextEditorToolbar]; + UIViewController *fontPicker = [self.dataSource fontPickerForRichTextEditorToolbar]; + + if (!fontPicker) + fontPicker= [[RichTextEditorFontPickerViewController alloc] init]; + fontPicker.delegate = self; fontPicker.dataSource = self; [self presentViewController:fontPicker fromView:sender]; @@ -195,7 +205,11 @@ - (void)fontSelected:(UIButton *)sender - (void)textBackgroundColorSelected:(UIButton *)sender { - RichTextEditorColorPickerViewController *colorPicker = [[RichTextEditorColorPickerViewController alloc] init]; + UIViewController *colorPicker = [self.dataSource colorPickerForRichTextEditorToolbarWithAction:RichTextEditorColorPickerActionTextBackgroundColor]; + + if (!colorPicker) + colorPicker = [[RichTextEditorColorPickerViewController alloc] init]; + colorPicker.action = RichTextEditorColorPickerActionTextBackgroundColor; colorPicker.delegate = self; colorPicker.dataSource = self; @@ -204,7 +218,11 @@ - (void)textBackgroundColorSelected:(UIButton *)sender - (void)textForegroundColorSelected:(UIButton *)sender { - RichTextEditorColorPickerViewController *colorPicker = [[RichTextEditorColorPickerViewController alloc] init]; + UIViewController *colorPicker = [self.dataSource colorPickerForRichTextEditorToolbarWithAction:RichTextEditorColorPickerActionTextForegroudColor]; + + if (!colorPicker) + colorPicker = [[RichTextEditorColorPickerViewController alloc] init]; + colorPicker.action = RichTextEditorColorPickerActionTextForegroudColor; colorPicker.delegate = self; colorPicker.dataSource = self; @@ -221,16 +239,27 @@ - (void)textAlignmentSelected:(UIButton *)sender textAlignment = NSTextAlignmentCenter; else if (sender == self.btnTextAlignmentRight) textAlignment = NSTextAlignmentRight; - else if (sender == self.btnTextAlignmentJustified) + else textAlignment = NSTextAlignmentJustified; [self.delegate richTextEditorToolbarDidSelectTextAlignment:textAlignment]; } +- (void)textAttachmentSelected:(UIButton *)sender +{ + UIImagePickerController *vc = [[UIImagePickerController alloc] init]; + vc.delegate = self; + [self presentViewController:vc fromView:self.btnTextAttachment]; +} + #pragma mark - Private Methods - - (void)populateToolbar { + CGRect visibleRect; + visibleRect.origin = self.contentOffset; + visibleRect.size = self.bounds.size; + // Remove any existing subviews. for (UIView *subView in self.subviews) { @@ -250,6 +279,11 @@ - (void)populateToolbar if (features & RichTextEditorFeatureFont || features & RichTextEditorFeatureAll) { UIView *separatorView = [self separatorView]; + CGSize size = [self.btnFont sizeThatFits:CGSizeZero]; + CGRect rect = self.btnFont.frame; + rect.size.width = MAX(size.width + 25, 120); + self.btnFont.frame = rect; + [self addView:self.btnFont afterView:lastAddedView withSpacing:YES]; [self addView:separatorView afterView:self.btnFont withSpacing:YES]; lastAddedView = separatorView; @@ -380,6 +414,29 @@ - (void)populateToolbar [self addView:separatorView afterView:lastAddedView withSpacing:YES]; lastAddedView = separatorView; } + + // Bullet List + if (features & RichTextEditorFeatureBulletList || features & RichTextEditorFeatureAll) + { + [self addView:self.btnBulletList afterView:lastAddedView withSpacing:YES]; + lastAddedView = self.btnBulletList; + } + + // Separator view after color section + if (features & RichTextEditorFeatureBulletList || features & RichTextEditorFeatureAll) + { + UIView *separatorView = [self separatorView]; + [self addView:separatorView afterView:lastAddedView withSpacing:YES]; + lastAddedView = separatorView; + } + + if ((features & RichTextEditorFeatureBulletList || features & RichTextEditorFeatureAll) && SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) + { + [self addView:self.btnTextAttachment afterView:lastAddedView withSpacing:YES]; + lastAddedView = self.btnBulletList; + } + + [self scrollRectToVisible:visibleRect animated:NO]; } - (void)initializeButtons @@ -432,8 +489,8 @@ - (void)initializeButtons self.btnBackgroundColor = [self buttonWithImageNamed:@"backcolor.png" andSelector:@selector(textBackgroundColorSelected:)]; - self.btnBulletPoint = [self buttonWithImageNamed:@"bullist.png" - andSelector:@selector(bulletPointSelected:)]; + self.btnBulletList = [self buttonWithImageNamed:@"bullist.png" + andSelector:@selector(bulletListSelected:)]; self.btnParagraphIndent = [self buttonWithImageNamed:@"indent.png" andSelector:@selector(paragraphIndentSelected:)]; @@ -443,6 +500,9 @@ - (void)initializeButtons self.btnParagraphFirstLineHeadIndent = [self buttonWithImageNamed:@"firstLineIndent.png" andSelector:@selector(paragraphHeadIndentOutdentSelected:)]; + + self.btnTextAttachment = [self buttonWithImageNamed:@"image.png" + andSelector:@selector(textAttachmentSelected:)]; } - (RichTextEditorToggleButton *)buttonWithImageNamed:(NSString *)image width:(NSInteger)width andSelector:(SEL)selector @@ -550,6 +610,8 @@ - (void)dismissViewController { [self.popover dismissPopoverAnimated:YES]; } + + [self.delegate richTextEditorToolbarDidDismissViewController]; } #pragma mark - RichTextEditorColorPickerViewControllerDelegate & RichTextEditorColorPickerViewControllerDataSource Methods - @@ -624,4 +686,18 @@ - (BOOL)richTextEditorFontPickerViewControllerShouldDisplayToolbar return ([self.dataSource presentationStyleForRichTextEditorToolbar] == RichTextEditorToolbarPresentationStyleModal) ? YES: NO; } +#pragma mark - UIImagePickerViewControllerDelegate - + +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info +{ + UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; + [self.delegate richTextEditorToolbarDidSelectTextAttachment:image]; + [self dismissViewController]; +} + +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker +{ + [self dismissViewController]; +} + @end diff --git a/RichTextEditorTests/RichTextEditorTests.h b/RichTextEditorTests/RichTextEditorTests.h index fa927c9..0a14149 100644 --- a/RichTextEditorTests/RichTextEditorTests.h +++ b/RichTextEditorTests/RichTextEditorTests.h @@ -6,8 +6,8 @@ // Copyright (c) 2013 Aryan Ghassemi. All rights reserved. // -#import +#import -@interface RichTextEditorTests : SenTestCase +@interface RichTextEditorTests : XCTestCase @end diff --git a/RichTextEditorTests/RichTextEditorTests.m b/RichTextEditorTests/RichTextEditorTests.m index a27c475..14041c8 100644 --- a/RichTextEditorTests/RichTextEditorTests.m +++ b/RichTextEditorTests/RichTextEditorTests.m @@ -26,7 +26,7 @@ - (void)tearDown - (void)testExample { - STFail(@"Unit tests are not implemented yet in RichTextEditorTests"); + XCTFail(@"Unit tests are not implemented yet in RichTextEditorTests"); } @end