Skip to content
This repository has been archived by the owner on Oct 30, 2018. It is now read-only.

Commit

Permalink
Merge pull request #501 from slackhq/attributed-string-support
Browse files Browse the repository at this point in the history
Supporting Attributed String in SLKTextView
  • Loading branch information
Jacky Wu authored Aug 7, 2016
2 parents cd15799 + 0fa821c commit e5beed3
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 14 deletions.
62 changes: 62 additions & 0 deletions Source/SLKTextView+SLKAdditions.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)slk_insertTextAtCaretRange:(NSString *)text;

/**
Insert a string at the caret's position with stylization from the attributes.
@param text The string to be appended to the current text.
@param attributes The attributes used to stylize the text.
*/
- (void)slk_insertTextAtCaretRange:(NSString *)text
withAttributes:(NSDictionary<NSString *, id> *)attributes;

/**
Adds a string to a specific range.
Expand All @@ -56,6 +65,59 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (NSRange)slk_insertText:(NSString *)text inRange:(NSRange)range;

/**
Adds a string to a specific range, with stylization from the attributes.
@param text The string to be appended to the current text.
@param attributes The attributes used to stylize the text.
@param range The range where to insert text.
@return The range of the newly inserted text.
*/
- (NSRange)slk_insertText:(NSString *)text
withAttributes:(NSDictionary<NSString *, id> *)attributes
inRange:(NSRange)range;

/**
Sets the text attributes for the attributed string in the provided range.
@param attributes The attributes used to style NSAttributedString class.
@param range The range of the text that needs to be stylized by the given attributes.
@return An attributed string.
*/
- (NSAttributedString *)slk_setAttributes:(NSDictionary<NSString *, id> *)attributes
inRange:(NSRange)range;

/**
Inserts an attributed string at the caret's position.
@param attributedText The attributed string to be appended.
*/
- (void)slk_insertAttributedTextAtCaretRange:(NSAttributedString *)attributedText;

/**
Adds an attributed string to a specific range.
@param text The string to be appended to the current text.
@param range The range where to insert text.
@return The range of the newly inserted text.
*/
- (NSRange)slk_insertAttributedText:(NSAttributedString *)attributedText inRange:(NSRange)range;

/**
Removes all attributed string attributes from the text view, for the given range.
@param range The range to remove the attributes.
*/
- (void)slk_clearAllAttributesInRange:(NSRange)range;

/**
Returns a default attributed string, using the text view's font and text color.
@param text The string to be used for creating a new attributed string.
@return An attributed string.
*/
- (NSAttributedString *)slk_defaultAttributedStringForText:(NSString *)text;

/**
Registers the current text for future undo actions.
Expand Down
93 changes: 81 additions & 12 deletions Source/SLKTextView+SLKAdditions.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ @implementation SLKTextView (SLKAdditions)
- (void)slk_clearText:(BOOL)clearUndo
{
// Important to call self implementation, as SLKTextView overrides setText: to add additional features.
[self setText:nil];

[self setAttributedText:nil];

if (self.undoManagerEnabled && clearUndo) {
[self.undoManager removeAllActions];
Expand Down Expand Up @@ -66,34 +67,79 @@ - (void)slk_insertTextAtCaretRange:(NSString *)text
self.selectedRange = NSMakeRange(range.location, 0);
}

- (void)slk_insertTextAtCaretRange:(NSString *)text withAttributes:(NSDictionary<NSString *, id> *)attributes
{
NSRange range = [self slk_insertText:text withAttributes:attributes inRange:self.selectedRange];
self.selectedRange = NSMakeRange(range.location, 0);
}

- (NSRange)slk_insertText:(NSString *)text inRange:(NSRange)range
{
// Skip if the text is empty
if (text.length == 0) {
NSAttributedString *attributedText = [self slk_defaultAttributedStringForText:text];

return [self slk_insertAttributedText:attributedText inRange:range];
}

- (NSRange)slk_insertText:(NSString *)text withAttributes:(NSDictionary<NSString *, id> *)attributes inRange:(NSRange)range
{
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:attributes];

return [self slk_insertAttributedText:attributedText inRange:range];
}

- (NSAttributedString *)slk_setAttributes:(NSDictionary<NSString *, id> *)attributes
inRange:(NSRange)range
{
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText];

[attributedText setAttributes:attributes range:range];
[self setAttributedText:attributedText];

return self.attributedText;
}

- (void)slk_insertAttributedTextAtCaretRange:(NSAttributedString *)attributedText
{
NSRange range = [self slk_insertAttributedText:attributedText inRange:self.selectedRange];
self.selectedRange = NSMakeRange(range.location, 0);
}

- (NSRange)slk_insertAttributedText:(NSAttributedString *)attributedText inRange:(NSRange)range
{
// Skip if the attributed text is empty
if (attributedText.length == 0) {
return NSMakeRange(0, 0);
}

// Registers for undo management
[self slk_prepareForUndo:@"Text appending"];
[self slk_prepareForUndo:@"Attributed text appending"];

// Append the new string at the caret position
if (range.length == 0)
{
NSString *leftString = [self.text substringToIndex:range.location];
NSString *rightString = [self.text substringFromIndex: range.location];
NSAttributedString *leftAttributedString = [self.attributedText attributedSubstringFromRange:NSMakeRange(0, range.location)];

self.text = [NSString stringWithFormat:@"%@%@%@", leftString, text, rightString];
NSAttributedString *rightAttributedString = [self.attributedText attributedSubstringFromRange:NSMakeRange(range.location, self.attributedText.length-range.location)];

NSMutableAttributedString *newAttributedText = [NSMutableAttributedString new];
[newAttributedText appendAttributedString:leftAttributedString];
[newAttributedText appendAttributedString:attributedText];
[newAttributedText appendAttributedString:rightAttributedString];

[self setAttributedText:newAttributedText];
range.location += attributedText.length;

range.location += text.length;

return range;
}
// Some text is selected, so we replace it with the new text
else if (range.location != NSNotFound && range.length > 0)
{
self.text = [self.text stringByReplacingCharactersInRange:range withString:text];

range.location += text.length;
NSMutableAttributedString *mutableAttributeText = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText];

[mutableAttributeText replaceCharactersInRange:range withAttributedString:attributedText];

[self setAttributedText:mutableAttributeText];
range.location += self.attributedText.length;

return range;
}
Expand All @@ -102,6 +148,29 @@ - (NSRange)slk_insertText:(NSString *)text inRange:(NSRange)range
return self.selectedRange;
}

- (void)slk_clearAllAttributesInRange:(NSRange)range
{
NSMutableAttributedString *mutableAttributedText = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText];

[mutableAttributedText setAttributes:nil range:range];
[self setAttributedText:mutableAttributedText];
}

- (NSAttributedString *)slk_defaultAttributedStringForText:(NSString *)text
{
NSMutableDictionary *attributes = [NSMutableDictionary dictionary];

if (self.textColor) {
attributes[NSForegroundColorAttributeName] = self.textColor;
}

if (self.font) {
attributes[NSFontAttributeName] = self.font;
}

return [[NSAttributedString alloc] initWithString:text attributes:attributes];
}

- (void)slk_prepareForUndo:(NSString *)description
{
if (!self.undoManagerEnabled) {
Expand Down
13 changes: 11 additions & 2 deletions Source/SLKTextView.m
Original file line number Diff line number Diff line change
Expand Up @@ -452,12 +452,21 @@ - (void)setText:(NSString *)text
{
// Registers for undo management
[self slk_prepareForUndo:@"Text Set"];

[super setText:text];

if (text) {
[self setAttributedText:[self slk_defaultAttributedStringForText:text]];
} else {
[self setAttributedText:nil];
}

[[NSNotificationCenter defaultCenter] postNotificationName:UITextViewTextDidChangeNotification object:self];
}

- (NSString *)text
{
return self.attributedText.string;
}

- (void)setAttributedText:(NSAttributedString *)attributedText
{
// Registers for undo management
Expand Down

0 comments on commit e5beed3

Please sign in to comment.