Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/url support #46

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/RichTextEditor.xcodeproj/xcuserdata/

UserInterfaceState.xcuserstate

RichTextEditor.xccheckout
6 changes: 6 additions & 0 deletions RichTextEditor.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
1AFAED8617C804AB00E450B0 /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = 1AFAED8417C804AB00E450B0 /* [email protected] */; };
1AFAED8717C804AB00E450B0 /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = 1AFAED8517C804AB00E450B0 /* [email protected] */; };
1AFAED8917C80FC600E450B0 /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = 1AFAED8817C80FC600E450B0 /* [email protected] */; };
E1A1B1E1196ABAE900513A15 /* RichTextEditorInsertLinkViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E1A1B1E0196ABAE900513A15 /* RichTextEditorInsertLinkViewController.m */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -229,6 +230,8 @@
1AFAED8417C804AB00E450B0 /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
1AFAED8517C804AB00E450B0 /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
1AFAED8817C80FC600E450B0 /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
E1A1B1DF196ABAE800513A15 /* RichTextEditorInsertLinkViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RichTextEditorInsertLinkViewController.h; sourceTree = "<group>"; };
E1A1B1E0196ABAE900513A15 /* RichTextEditorInsertLinkViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RichTextEditorInsertLinkViewController.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -275,6 +278,8 @@
153F9581179F9953005B2487 /* RichTextEditorFontSizePickerViewController.h */,
153F9582179F9953005B2487 /* RichTextEditorFontSizePickerViewController.m */,
153F9583179F9953005B2487 /* RichTextEditorPopover.h */,
E1A1B1DF196ABAE800513A15 /* RichTextEditorInsertLinkViewController.h */,
E1A1B1E0196ABAE900513A15 /* RichTextEditorInsertLinkViewController.m */,
);
path = Source;
sourceTree = "<group>";
Expand Down Expand Up @@ -658,6 +663,7 @@
153F95A0179F9953005B2487 /* RichTextEditor.m in Sources */,
153F958C179F9953005B2487 /* UIView+RichTextEditor.m in Sources */,
153F959F179F9953005B2487 /* WETouchableView.m in Sources */,
E1A1B1E1196ABAE900513A15 /* RichTextEditorInsertLinkViewController.m in Sources */,
158389231735A5D7006DE713 /* AppDelegate.m in Sources */,
158389321735A5D7006DE713 /* ViewController.m in Sources */,
153F95A1179F9953005B2487 /* RichTextEditorColorPickerViewController.m in Sources */,
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified RichTextEditor/Source/Assets/link.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added RichTextEditor/Source/Assets/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@
- (NSRange)firstParagraphRangeFromTextRange:(NSRange)range;
- (NSArray *)rangeOfParagraphsFromTextRange:(NSRange)textRange;
- (NSString *)htmlString;
- (NSString *)simpleHtmlString;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,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')
Expand All @@ -55,7 +55,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')
Expand Down Expand Up @@ -131,7 +131,10 @@ - (NSString *)htmlString
BOOL hasUnderline = (!underline || underline.intValue == NSUnderlineStyleNone) ? NO :YES;
NSNumber *strikeThrough = [dictionary objectForKey:NSStrikethroughStyleAttributeName];
BOOL hasStrikeThrough = (!strikeThrough || strikeThrough.intValue == NSUnderlineStyleNone) ? NO :YES;

NSURL *url = [dictionary objectForKey:NSLinkAttributeName];



[fontString appendFormat:@"<font "];
[fontString appendFormat:@"face=\"%@\" ", font.familyName];

Expand All @@ -152,7 +155,12 @@ - (NSString *)htmlString
[fontString appendString:@">"];
[fontString appendString:[[self.string substringFromIndex:range.location] substringToIndex:range.length]];
[fontString appendString:@"</font>"];


if(url){
[fontString insertString:[NSString stringWithFormat:@"<a href=\"%@\">",[url absoluteString]] atIndex:0];
[fontString insertString:@"</a>" atIndex:fontString.length];
}

if ([font isBold])
{
[fontString insertString:@"<b>" atIndex:0];
Expand Down Expand Up @@ -187,6 +195,71 @@ - (NSString *)htmlString
return htmlString;
}

-(NSString *)simpleHtmlString{
NSMutableString *htmlString = [NSMutableString string];
NSArray *paragraphRanges = [self rangeOfParagraphsFromTextRange:NSMakeRange(0, self.string.length-1)];

for (int i=0 ; i<paragraphRanges.count ; i++)
{
NSValue *value = [paragraphRanges objectAtIndex:i];
NSRange range = [value rangeValue];

[htmlString appendString:@"<p>"];


[self enumerateAttributesInRange:range
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
usingBlock:^(NSDictionary *dictionary, NSRange range, BOOL *stop){

NSMutableString *fontString = [NSMutableString string];
UIFont *font = [dictionary objectForKey:NSFontAttributeName];
NSNumber *underline = [dictionary objectForKey:NSUnderlineStyleAttributeName];
BOOL hasUnderline = (!underline || underline.intValue == NSUnderlineStyleNone) ? NO :YES;
NSNumber *strikeThrough = [dictionary objectForKey:NSStrikethroughStyleAttributeName];
BOOL hasStrikeThrough = (!strikeThrough || strikeThrough.intValue == NSUnderlineStyleNone) ? NO :YES;
NSURL *url = [dictionary objectForKey:NSLinkAttributeName];

[fontString appendString:[[self.string substringFromIndex:range.location] substringToIndex:range.length]];

if(url){
[fontString insertString:[NSString stringWithFormat:@"<a href=\"%@\">",[url absoluteString]] atIndex:0];
[fontString insertString:@"</a>" atIndex:fontString.length];
}

if ([font isBold])
{
[fontString insertString:@"<b>" atIndex:0];
[fontString insertString:@"</b>" atIndex:fontString.length];
}

if ([font isItalic])
{
[fontString insertString:@"<i>" atIndex:0];
[fontString insertString:@"</i>" atIndex:fontString.length];
}

if (hasUnderline)
{
[fontString insertString:@"<u>" atIndex:0];
[fontString insertString:@"</u>" atIndex:fontString.length];
}

if (hasStrikeThrough)
{
[fontString insertString:@"<strike>" atIndex:0];
[fontString insertString:@"</strike>" atIndex:fontString.length];
}


[htmlString appendString:fontString];
}];

[htmlString appendString:@"</p>"];
}

return htmlString;
}

#pragma mark - Helper Methods -

- (NSString *)htmlTextAlignmentString:(NSTextAlignment)textAlignment
Expand Down
107 changes: 96 additions & 11 deletions RichTextEditor/Source/RichTextEditor.m
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ - (void)commonInitialization
[self updateToolbarState];
}

-(void)setDataSource:(id<RichTextEditorDataSource>)dataSource{
_dataSource = dataSource;
[self setupMenuItems];
}

#pragma mark - Override Methods -

- (void)setSelectedTextRange:(UITextRange *)selectedTextRange
Expand Down Expand Up @@ -157,8 +162,36 @@ - (void)setupMenuItems
UIMenuItem *italicItem = [[UIMenuItem alloc] initWithTitle:@"Italic" action:@selector(richTextEditorToolbarDidSelectItalic)];
UIMenuItem *underlineItem = [[UIMenuItem alloc] initWithTitle:@"Underline" action:@selector(richTextEditorToolbarDidSelectUnderline)];
UIMenuItem *strikeThroughItem = [[UIMenuItem alloc] initWithTitle:@"Strike" action:@selector(richTextEditorToolbarDidSelectStrikeThrough)];

[[UIMenuController sharedMenuController] setMenuItems:@[selectParagraph, boldItem, italicItem, underlineItem, strikeThroughItem]];

RichTextEditorFeature features = [self featuresEnabledForRichTextEditorToolbar];
if(features == RichTextEditorFeatureAll){
[[UIMenuController sharedMenuController] setMenuItems:@[selectParagraph, boldItem, italicItem, underlineItem, strikeThroughItem]];
}else{
NSMutableArray *array = [NSMutableArray array];

if(features & RichTextEditorFeatureParagraphIndentation){
[array addObject:selectParagraph];
}

if(features & RichTextEditorFeatureBold){
[array addObject:boldItem];
}

if(features & RichTextEditorFeatureItalic){
[array addObject:italicItem];
}

if(features & RichTextEditorFeatureUnderline){
[array addObject:underlineItem];
}

if(features & RichTextEditorFeatureStrikeThrough){
[array addObject:strikeThroughItem];
}

[[UIMenuController sharedMenuController] setMenuItems:array];
}

}

- (void)selectParagraph:(id)sender
Expand Down Expand Up @@ -322,6 +355,38 @@ - (void)richTextEditorToolbarDidSelectBulletPoint
// TODO: implement this
}

- (void)richTextEditorToolbarDidInsertLink:(NSURL*) link displayText:(NSString*)displayText{

NSMutableAttributedString *attributedString = [self.attributedText mutableCopy];

NSMutableDictionary *attributes = [[self dictionaryAtIndex:self.selectedRange.location] mutableCopy];
UIFont *font = [attributes objectForKey:NSFontAttributeName];
font = [UIFont fontWithName:[font familyName] size:[font pointSize] boldTrait:NO italicTrait:NO];
[attributes setObject:font forKey:NSFontAttributeName];

NSMutableDictionary *cop = [attributes mutableCopy];
[cop setObject:link forKey:NSLinkAttributeName];
NSAttributedString *string = [[NSAttributedString alloc] initWithString:displayText attributes:cop];

NSRange oldRange = self.selectedRange;
oldRange.length = 0;
oldRange.location += displayText.length;

[attributedString insertAttributedString:string atIndex:self.selectedRange.location];

NSAttributedString *space = [[NSAttributedString alloc] initWithString:@" " attributes:attributes];
[attributedString insertAttributedString:space atIndex:oldRange.location];
oldRange.location += 1;

[self setAttributedText:attributedString];

[self updateToolbarState];
[self resignFirstResponder];
[self scrollRangeToVisible:oldRange];
[self becomeFirstResponder];
[self setSelectedRange:oldRange];
}

#pragma mark - Private Methods -

- (CGRect)frameOfTextAtRange:(NSRange)range
Expand Down Expand Up @@ -358,6 +423,11 @@ - (void)enumarateThroughParagraphsInRange:(NSRange)range withBlock:(void (^)(NSR
[self setSelectedRange:fullRange];
}

-(void)setAttributedText:(NSAttributedString *)attributedText{
[super setAttributedText:attributedText];
[self updateToolbarState];
}

- (void)updateToolbarState
{
// If no text exists or typing attributes is in progress update toolbar using typing attributes instead of selected text
Expand All @@ -367,10 +437,16 @@ - (void)updateToolbarState
}
else
{
int location = [self offsetFromPosition:self.beginningOfDocument toPosition:self.selectedTextRange.start];

if (location == self.text.length)
location --;
NSInteger location = [self offsetFromPosition:self.beginningOfDocument toPosition:self.selectedTextRange.start];
if(self.selectedRange.length > 0){
if (location == self.text.length)
location --;
}else{
if (location != 0)
location --;
}



[self.toolBar updateStateWithAttributes:[self.attributedText attributesAtIndex:location effectiveRange:nil]];
}
Expand All @@ -389,9 +465,13 @@ - (NSRange)fullRangeFromArrayOfParagraphRanges:(NSArray *)paragraphRanges
- (UIFont *)fontAtIndex:(NSInteger)index
{
// If index at end of string, get attributes starting from previous character
if (index == self.attributedText.string.length && [self hasText])
--index;

if(self.selectedRange.length > 0){
if (index == self.attributedText.string.length && [self hasText])
index --;
}else{
if (index != 0)
index --;
}
// If no text exists get font from typing attributes
NSDictionary *dictionary = ([self hasText])
? [self.attributedText attributesAtIndex:index effectiveRange:nil]
Expand All @@ -403,8 +483,13 @@ - (UIFont *)fontAtIndex:(NSInteger)index
- (NSDictionary *)dictionaryAtIndex:(NSInteger)index
{
// If index at end of string, get attributes starting from previous character
if (index == self.attributedText.string.length && [self hasText])
--index;
if(self.selectedRange.length > 0){
if (index == self.attributedText.string.length && [self hasText])
index --;
}else{
if (index != 0)
index --;
}

// If no text exists get font from typing attributes
return ([self hasText])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
#import <QuartzCore/QuartzCore.h>
#import "UIView+RichTextEditor.h"

typedef enum {
RichTextEditorColorPickerActionTextForegroudColor,
RichTextEditorColorPickerActionTextBackgroundColor
}RichTextEditorColorPickerAction;
typedef NS_ENUM(NSUInteger, RichTextEditorColorPickerAction) {
RichTextEditorColorPickerActionTextForegroudColor,
RichTextEditorColorPickerActionTextBackgroundColor
};

@protocol RichTextEditorColorPickerViewControllerDelegate <NSObject>
- (void)richTextEditorColorPickerViewControllerDidSelectColor:(UIColor *)color withAction:(RichTextEditorColorPickerAction)action;
Expand Down
27 changes: 27 additions & 0 deletions RichTextEditor/Source/RichTextEditorInsertLinkViewController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// RichTextEditorInsertLinkViewController.h
// RichTextEditor
//
// Created by Andreas Lillebø Holm on 07/07/14.
// Copyright (c) 2014 Aryan Ghassemi. All rights reserved.
//

#import <UIKit/UIKit.h>

@protocol RichTextEditorInsertLinkViewControllerDelegate <NSObject>

- (void)richTextEditorInsertLinkViewControllerInsertURL:(NSURL *)url withDisplayText:(NSString *)displayText;
- (void)richTextEditorInsertLinkViewControllerDidCancel;

@end

@interface RichTextEditorInsertLinkViewController : UIViewController

@property(nonatomic, weak) id<RichTextEditorInsertLinkViewControllerDelegate> delegate;

- (void)doneSelected:(id)sender;
- (void)closeSelected:(id)sender;

@end


Loading