From b46b2f048d0fae456afcf6bed09ec6dd5f0738dd Mon Sep 17 00:00:00 2001 From: daboe01 Date: Mon, 14 Nov 2016 23:09:04 +0100 Subject: [PATCH 01/10] fixed: native paste on chrome was not working as robustly as it should --- AppKit/CPTextView/CPTextView.j | 70 ++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/AppKit/CPTextView/CPTextView.j b/AppKit/CPTextView/CPTextView.j index 141bffa0b..9c0cc6696 100644 --- a/AppKit/CPTextView/CPTextView.j +++ b/AppKit/CPTextView/CPTextView.j @@ -84,17 +84,6 @@ _regexMatchesStringAtIndex=function(regex, string, index) return regex.exec(triplet) !== null; } -// these two functions are to support chrome rich native paste -_CPwalkTheDOM = function(node, func) -{ - func(node); - node = node.firstChild; - while (node) - { - _CPwalkTheDOM(node, func); - node = node.nextSibling; - } -} /* CPSelectionGranularity @@ -2506,30 +2495,51 @@ var _CPCopyPlaceholder = '-'; richtext, pasteboard = [CPPasteboard generalPasteboard], rtfdata = [CPAttributedString new], - _CPDOMParsefunction = function(node) + _CPDOMParsefunction = function(nodeArray) { - if (node.nodeType === 1 && node.nodeName === 'SPAN') + if (!nodeArray || !nodeArray.length) + return; + + var l = nodeArray.length; + + for (var i = 0; i < l; i++) { - var text = node.innerHTML, - style = window.getComputedStyle(node), - styleAttributes = @{}; + var nodes = nodeArray[i].childNodes, + m = nodes.length; - // extract color from the DOM - var rgbmatch = style.getPropertyValue('color').match(new RegExp(/rgb\((\d+)[, ]+(\d+)[, ]+(\d+)\)/)); + for (var j = 0; j < m; j++) + { + var node = nodes[j]; - if (rgbmatch) - [styleAttributes setObject:[CPColor colorWithRed:rgbmatch[1]/255.0 green:rgbmatch[2]/255.0 blue:rgbmatch[3]/255.0 alpha:1] - forKey:CPForegroundColorAttributeName]; + if(node.nodeName === 'SPAN') + { + var text = node.innerHTML, + style = window.getComputedStyle(node), + styleAttributes = @{}; - // extract font from the DOM + // extract color from the DOM + var rgbmatch = style.getPropertyValue('color').match(new RegExp(/rgb\((\d+)[, ]+(\d+)[, ]+(\d+)\)/)); - var fontname = style.getPropertyValue('font-family'), - fontsize = parseInt(style.getPropertyValue('font-size'), 10); + if (rgbmatch) + [styleAttributes setObject:[CPColor colorWithRed:rgbmatch[1]/255.0 green:rgbmatch[2]/255.0 blue:rgbmatch[3]/255.0 alpha:1] + forKey:CPForegroundColorAttributeName]; - if (fontname && fontsize) - [styleAttributes setObject:[CPFont fontWithName:fontname size:fontsize italic:NO] forKey:CPFontAttributeName]; + // extract font from the DOM - [rtfdata appendAttributedString:[[[CPAttributedString alloc] initWithString:text attributes:styleAttributes] _stringByParsingHTMLEntities]]; + var fontname = style.getPropertyValue('font-family'), + fontsize = parseInt(style.getPropertyValue('font-size'), 10); + + if (fontname && fontsize) + [styleAttributes setObject:[CPFont fontWithName:fontname size:fontsize italic:NO] forKey:CPFontAttributeName]; + + [rtfdata appendAttributedString:[[[CPAttributedString alloc] initWithString:text attributes:styleAttributes] _stringByParsingHTMLEntities]]; + } + else if (node.nodeName === '#text') + [rtfdata appendAttributedString:[[CPAttributedString alloc] initWithString:node.nodeValue attributes:@{}]]; + + if (l > 1) + [rtfdata appendAttributedString:[[CPAttributedString alloc] initWithString:"\n" attributes:@{}]]; + } } }; @@ -2547,7 +2557,7 @@ var _CPCopyPlaceholder = '-'; { if (elem.childNodes && elem.childNodes.length > 0) { - _CPwalkTheDOM(elem, _CPDOMParsefunction); + _CPDOMParsefunction(elem.getElementsByTagName("p")); [pasteboard declareTypes:[CPRTFPboardType] owner:nil]; [pasteboard setString:[_CPRTFProducer produceRTF:rtfdata documentAttributes:@{}] forType:CPRTFPboardType]; @@ -2574,9 +2584,11 @@ var _CPCopyPlaceholder = '-'; { e.preventDefault(); _CPNativeInputField.innerHTML = richtext; - _CPwalkTheDOM(_CPNativeInputField, _CPDOMParsefunction); + _CPDOMParsefunction(_CPNativeInputField.getElementsByTagName("p")); [pasteboard declareTypes:[CPRTFPboardType] owner:nil]; + var rtf = [_CPRTFProducer produceRTF:rtfdata documentAttributes:@{}]; + debugger [pasteboard setString:[_CPRTFProducer produceRTF:rtfdata documentAttributes:@{}] forType:CPRTFPboardType]; [[[CPApp keyWindow] firstResponder] paste:self]; From 3c27e57b19fb15202aed1dad7f5380ccf511b657 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Tue, 15 Nov 2016 21:02:04 +0100 Subject: [PATCH 02/10] fixed: native rich pasting curly braces crashed chrome --- AppKit/CPTextView/CPTextView.j | 7 ++----- AppKit/CPTextView/_CPRTFParser.j | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/AppKit/CPTextView/CPTextView.j b/AppKit/CPTextView/CPTextView.j index 9c0cc6696..ff57506a0 100644 --- a/AppKit/CPTextView/CPTextView.j +++ b/AppKit/CPTextView/CPTextView.j @@ -2536,10 +2536,9 @@ var _CPCopyPlaceholder = '-'; } else if (node.nodeName === '#text') [rtfdata appendAttributedString:[[CPAttributedString alloc] initWithString:node.nodeValue attributes:@{}]]; - - if (l > 1) - [rtfdata appendAttributedString:[[CPAttributedString alloc] initWithString:"\n" attributes:@{}]]; } + if (l > 1) + [rtfdata appendAttributedString:[[CPAttributedString alloc] initWithString:"\n" attributes:@{}]]; } }; @@ -2587,8 +2586,6 @@ var _CPCopyPlaceholder = '-'; _CPDOMParsefunction(_CPNativeInputField.getElementsByTagName("p")); [pasteboard declareTypes:[CPRTFPboardType] owner:nil]; - var rtf = [_CPRTFProducer produceRTF:rtfdata documentAttributes:@{}]; - debugger [pasteboard setString:[_CPRTFProducer produceRTF:rtfdata documentAttributes:@{}] forType:CPRTFPboardType]; [[[CPApp keyWindow] firstResponder] paste:self]; diff --git a/AppKit/CPTextView/_CPRTFParser.j b/AppKit/CPTextView/_CPRTFParser.j index f1f94db99..43dbfa6f1 100644 --- a/AppKit/CPTextView/_CPRTFParser.j +++ b/AppKit/CPTextView/_CPRTFParser.j @@ -514,7 +514,7 @@ var kRgsymRtf = { return [self _applyPropChange:sym parameter:param]; case kRTFParserType_char: - if((param + '') !== 'NaN' && (param + '').length) + if((param + '') !== 'NaN' && (param + '') !== 'null' && (param + '').length) _currentParseIndex -= (param + '').length; return [self _checkChar:sym parameter:param]; From 38cddf029bc5d2c1aaa1695b055017e391b023c1 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Fri, 9 Dec 2016 21:32:21 +0100 Subject: [PATCH 03/10] fixed: rich native pasting was not using the rtf pasteboard type on chrome --- AppKit/CPTextView/CPTextView.j | 146 +-------------------------------- 1 file changed, 4 insertions(+), 142 deletions(-) diff --git a/AppKit/CPTextView/CPTextView.j b/AppKit/CPTextView/CPTextView.j index ff57506a0..2251851e0 100644 --- a/AppKit/CPTextView/CPTextView.j +++ b/AppKit/CPTextView/CPTextView.j @@ -2493,119 +2493,18 @@ var _CPCopyPlaceholder = '-'; { var nativeClipboard = (e.originalEvent || e).clipboardData, richtext, - pasteboard = [CPPasteboard generalPasteboard], - rtfdata = [CPAttributedString new], - _CPDOMParsefunction = function(nodeArray) - { - if (!nodeArray || !nodeArray.length) - return; + pasteboard = [CPPasteboard generalPasteboard]; - var l = nodeArray.length; - - for (var i = 0; i < l; i++) - { - var nodes = nodeArray[i].childNodes, - m = nodes.length; - - for (var j = 0; j < m; j++) - { - var node = nodes[j]; - - if(node.nodeName === 'SPAN') - { - var text = node.innerHTML, - style = window.getComputedStyle(node), - styleAttributes = @{}; - - // extract color from the DOM - var rgbmatch = style.getPropertyValue('color').match(new RegExp(/rgb\((\d+)[, ]+(\d+)[, ]+(\d+)\)/)); - - if (rgbmatch) - [styleAttributes setObject:[CPColor colorWithRed:rgbmatch[1]/255.0 green:rgbmatch[2]/255.0 blue:rgbmatch[3]/255.0 alpha:1] - forKey:CPForegroundColorAttributeName]; - - // extract font from the DOM - - var fontname = style.getPropertyValue('font-family'), - fontsize = parseInt(style.getPropertyValue('font-size'), 10); - - if (fontname && fontsize) - [styleAttributes setObject:[CPFont fontWithName:fontname size:fontsize italic:NO] forKey:CPFontAttributeName]; - - [rtfdata appendAttributedString:[[[CPAttributedString alloc] initWithString:text attributes:styleAttributes] _stringByParsingHTMLEntities]]; - } - else if (node.nodeName === '#text') - [rtfdata appendAttributedString:[[CPAttributedString alloc] initWithString:node.nodeValue attributes:@{}]]; - } - if (l > 1) - [rtfdata appendAttributedString:[[CPAttributedString alloc] initWithString:"\n" attributes:@{}]]; - } - }; - - // this is the native rich safari path - // the detection leverages the observation that safari puts a lot of cryptic types on the pasteboard (16 or so) - // this is not the case with any other browser that i have seen so far. - // safari does not currently provide data for any of the rich types that it advertises, though. - // for this reason, we have to let the paste execute and collect data from the DOM afterwards - // i did not get this working so far. the event is not forwarded for reasons that are beyond my understanding :-( - // for this reason, i disabled the code path so at least the plain content gets pasted - if (NO && nativeClipboard.types.length > 10) - { - // http://stackoverflow.com/questions/2176861/javascript-get-clipboard-data-on-paste-event-cross-browser/6804718#6804718 - function waitForPastedData(elem) - { - if (elem.childNodes && elem.childNodes.length > 0) - { - _CPDOMParsefunction(elem.getElementsByTagName("p")); - [pasteboard declareTypes:[CPRTFPboardType] owner:nil]; - [pasteboard setString:[_CPRTFProducer produceRTF:rtfdata documentAttributes:@{}] forType:CPRTFPboardType]; - - [[[CPApp keyWindow] firstResponder] paste:self]; - elem.innerHTML = _CPCopyPlaceholder; - } - else - { - setTimeout(function() - { - waitForPastedData(elem) - }, 20); - } - } - - waitForPastedData(_CPNativeInputField); - - return true; - } - - // this is the native rich chrome path: - // we have to construct an CPAttributedString whilst walking the dom and looking at the CSS attributes - if (richtext = nativeClipboard.getData('text/html')) - { - e.preventDefault(); - _CPNativeInputField.innerHTML = richtext; - _CPDOMParsefunction(_CPNativeInputField.getElementsByTagName("p")); - - [pasteboard declareTypes:[CPRTFPboardType] owner:nil]; - [pasteboard setString:[_CPRTFProducer produceRTF:rtfdata documentAttributes:@{}] forType:CPRTFPboardType]; - - [[[CPApp keyWindow] firstResponder] paste:self]; - _CPNativeInputField.innerHTML = _CPCopyPlaceholder; - return false; - } - - // this is the rich FF codepath (here we can use RTF directly) + // this is the rich chrome / FF codepath (where we can use RTF directly) if (richtext = nativeClipboard.getData('text/rtf')) { e.preventDefault(); [pasteboard declareTypes:[CPRTFPboardType] owner:nil]; [pasteboard setString:richtext forType:CPRTFPboardType]; - // prevent dom-flickering (settimeout does not work here) + // prevent dom-flickering (necessary only in FF) var currentFirstResponder = [[CPApp keyWindow] firstResponder]; - - setTimeout(function(){ // prevent dom-flickering (only FF) - [currentFirstResponder paste:self]; - }, 20); + [currentFirstResponder insertText:[[_CPRTFParser new] parseRTF:richtext]] return false; } @@ -2724,40 +2623,3 @@ var _CPCopyPlaceholder = '-'; } @end - -@implementation CPAttributedString(_MinimalHTMLParser) - --(void) _setRegularExpression:(JSObject)re toFontTrait:(CPFontTrait)aTrait -{ - var match; - while (match = re.exec(_string)) - { - var attribs = [[self attributesAtIndex:match.index effectiveRange:nil] copy], - font = [attribs objectForKey:CPFontAttributeName]; - [attribs setObject:[[CPFontManager sharedFontManager] convertFont:font toHaveTrait:aTrait] forKey:CPFontAttributeName] - [self setAttributes:attribs range:CPMakeRange(match.index, match[0].length)]; - } -} - --(void) _replaceEveryOccurenceOfRegularExpression:(JSObject)re withString:(CPString)aString -{ - var match; - while (match = re.exec(_string)) - [self replaceCharactersInRange:CPMakeRange(match.index, match[0].length) withString:aString]; -} - - --(CPAttributedString) _stringByParsingHTMLEntities -{ - [self _setRegularExpression:/(.+?)<\/b>/gi toFontTrait:CPFontBoldTrait]; - [self _setRegularExpression:/(.+?)<\/i>/gi toFontTrait:CPFontItalicTrait]; - [self _replaceEveryOccurenceOfRegularExpression:/<[^>]+>/i withString:'']; - [self _replaceEveryOccurenceOfRegularExpression:/</i withString:'<']; - [self _replaceEveryOccurenceOfRegularExpression:/>/i withString:'>']; - [self _replaceEveryOccurenceOfRegularExpression:/&/i withString:'&']; - [self _replaceEveryOccurenceOfRegularExpression:/ /i withString:' ']; - - return self; -} - -@end From b966c8cb0b1e4c6a635454a417a4e3fd0c87fe3b Mon Sep 17 00:00:00 2001 From: daboe01 Date: Fri, 9 Dec 2016 21:35:42 +0100 Subject: [PATCH 04/10] formatting --- AppKit/CPTextView/CPTextView.j | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/AppKit/CPTextView/CPTextView.j b/AppKit/CPTextView/CPTextView.j index 2251851e0..467618a58 100644 --- a/AppKit/CPTextView/CPTextView.j +++ b/AppKit/CPTextView/CPTextView.j @@ -2502,9 +2502,7 @@ var _CPCopyPlaceholder = '-'; [pasteboard declareTypes:[CPRTFPboardType] owner:nil]; [pasteboard setString:richtext forType:CPRTFPboardType]; - // prevent dom-flickering (necessary only in FF) - var currentFirstResponder = [[CPApp keyWindow] firstResponder]; - [currentFirstResponder insertText:[[_CPRTFParser new] parseRTF:richtext]] + [[[CPApp keyWindow] firstResponder] insertText:[[_CPRTFParser new] parseRTF:richtext]] return false; } From 30c1093c2f6e1e04f489a3dd7190300a81bf2ef3 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Fri, 9 Dec 2016 23:45:16 +0100 Subject: [PATCH 05/10] fixed: rich native pasting caused FF to flicker --- AppKit/CPTextView/CPTextView.j | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/AppKit/CPTextView/CPTextView.j b/AppKit/CPTextView/CPTextView.j index 467618a58..8df2deb19 100644 --- a/AppKit/CPTextView/CPTextView.j +++ b/AppKit/CPTextView/CPTextView.j @@ -2502,7 +2502,13 @@ var _CPCopyPlaceholder = '-'; [pasteboard declareTypes:[CPRTFPboardType] owner:nil]; [pasteboard setString:richtext forType:CPRTFPboardType]; - [[[CPApp keyWindow] firstResponder] insertText:[[_CPRTFParser new] parseRTF:richtext]] + // prevent flickering in FF + if (CPBrowserIsEngine(CPGeckoBrowserEngine)) + setTimeout(function(){ + [[[CPApp keyWindow] firstResponder] insertText:[[_CPRTFParser new] parseRTF:richtext]] + }, 20); + else + [[[CPApp keyWindow] firstResponder] insertText:[[_CPRTFParser new] parseRTF:richtext]] return false; } From 378c14d790ebfefd92d418df2fbbb6e535ec6faa Mon Sep 17 00:00:00 2001 From: daboe01 Date: Fri, 9 Dec 2016 23:53:08 +0100 Subject: [PATCH 06/10] formatting --- AppKit/CPTextView/CPTextView.j | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/AppKit/CPTextView/CPTextView.j b/AppKit/CPTextView/CPTextView.j index 8df2deb19..c31c3fd6c 100644 --- a/AppKit/CPTextView/CPTextView.j +++ b/AppKit/CPTextView/CPTextView.j @@ -2493,7 +2493,7 @@ var _CPCopyPlaceholder = '-'; { var nativeClipboard = (e.originalEvent || e).clipboardData, richtext, - pasteboard = [CPPasteboard generalPasteboard]; + pasteboard = [CPPasteboard generalPasteboard]; // this is the rich chrome / FF codepath (where we can use RTF directly) if (richtext = nativeClipboard.getData('text/rtf')) @@ -2502,12 +2502,11 @@ var _CPCopyPlaceholder = '-'; [pasteboard declareTypes:[CPRTFPboardType] owner:nil]; [pasteboard setString:richtext forType:CPRTFPboardType]; - // prevent flickering in FF if (CPBrowserIsEngine(CPGeckoBrowserEngine)) setTimeout(function(){ [[[CPApp keyWindow] firstResponder] insertText:[[_CPRTFParser new] parseRTF:richtext]] }, 20); - else + else [[[CPApp keyWindow] firstResponder] insertText:[[_CPRTFParser new] parseRTF:richtext]] return false; From 9d7d8ddde9793d7019170ac08cd4beea67202466 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Sun, 11 Dec 2016 14:05:51 +0100 Subject: [PATCH 07/10] fixed: native rich pasting pasted rich text into plain textviews --- AppKit/CPText.j | 5 ++++ AppKit/CPTextView/CPTextView.j | 42 ++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/AppKit/CPText.j b/AppKit/CPText.j index da3e47a8b..1475aaee4 100644 --- a/AppKit/CPText.j +++ b/AppKit/CPText.j @@ -155,6 +155,11 @@ CPKernAttributeName = @"CPKernAttributeName"; [pasteboard setString:[[self stringValue] substringWithRange:selectedRange] forType:CPStringPboardType]; } +- (id)_plainStringForPasting +{ + return [[CPPasteboard generalPasteboard] stringForType:CPStringPboardType]; +} + - (id)_stringForPasting { var pasteboard = [CPPasteboard generalPasteboard], diff --git a/AppKit/CPTextView/CPTextView.j b/AppKit/CPTextView/CPTextView.j index c31c3fd6c..5f23d0f2d 100644 --- a/AppKit/CPTextView/CPTextView.j +++ b/AppKit/CPTextView/CPTextView.j @@ -375,15 +375,10 @@ var kDelegateRespondsTo_textShouldBeginEditing [pasteboard setString:richData forType:CPRTFPboardType]; } -- (void)paste:(id)sender +- (void)_pasteString:(id)stringForPasting { - if (![sender isKindOfClass:_CPNativeInputManager] && [[CPApp currentEvent] type] != CPAppKitDefined) - return - - var stringForPasting = [self _stringForPasting]; - if (!stringForPasting) - return; + return; if (_copySelectionGranularity > 0 && _selectionRange.location > 0) { @@ -426,6 +421,21 @@ var kDelegateRespondsTo_textShouldBeginEditing } } } +- (void)pasteAsPlainText:(id)sender +{ + if (![sender isKindOfClass:_CPNativeInputManager] && [[CPApp currentEvent] type] != CPAppKitDefined) + return + + [self _pasteString:[self _plainStringForPasting]]; +} + +- (void)paste:(id)sender +{ + if (![sender isKindOfClass:_CPNativeInputManager] && [[CPApp currentEvent] type] != CPAppKitDefined) + return + + [self _pasteString:[self _stringForPasting]]; +} #pragma mark - #pragma mark Responders method @@ -672,6 +682,8 @@ var kDelegateRespondsTo_textShouldBeginEditing if (!isAttributed) aString = [[CPAttributedString alloc] initWithString:aString attributes:_typingAttributes]; + else if (![self isRichText]) + aString = [[CPAttributedString alloc] initWithString:string attributes:_typingAttributes]; var undoManager = [[self window] undoManager]; [undoManager setActionName:@"Replace/insert text"]; @@ -2496,18 +2508,14 @@ var _CPCopyPlaceholder = '-'; pasteboard = [CPPasteboard generalPasteboard]; // this is the rich chrome / FF codepath (where we can use RTF directly) - if (richtext = nativeClipboard.getData('text/rtf')) + if ((richtext = nativeClipboard.getData('text/rtf')) && !(!!window.event.shiftKey)) { e.preventDefault(); - [pasteboard declareTypes:[CPRTFPboardType] owner:nil]; - [pasteboard setString:richtext forType:CPRTFPboardType]; - if (CPBrowserIsEngine(CPGeckoBrowserEngine)) - setTimeout(function(){ - [[[CPApp keyWindow] firstResponder] insertText:[[_CPRTFParser new] parseRTF:richtext]] - }, 20); - else - [[[CPApp keyWindow] firstResponder] insertText:[[_CPRTFParser new] parseRTF:richtext]] + // setTimeout to prevent flickering in FF + setTimeout(function(){ + [[[CPApp keyWindow] firstResponder] insertText:[[_CPRTFParser new] parseRTF:richtext]] + }, 20); return false; } @@ -2515,7 +2523,7 @@ var _CPCopyPlaceholder = '-'; // plain is the same in all browsers... var data = e.clipboardData.getData('text/plain'), - cappString = [pasteboard stringForType:CPStringPboardType]; + cappString = [pasteboard stringForType:CPStringPboardType]; if (cappString != data) { From d2a5e126ae1befa4151755728636a9ff31de8df0 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Sun, 11 Dec 2016 22:42:43 +0100 Subject: [PATCH 08/10] fixed: native rich text was parsed when pasted into plain textview + newline fix in rtf parser --- AppKit/CPTextView/CPTextView.j | 13 ++++++++----- AppKit/CPTextView/_CPRTFParser.j | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/AppKit/CPTextView/CPTextView.j b/AppKit/CPTextView/CPTextView.j index 5f23d0f2d..e1db58e22 100644 --- a/AppKit/CPTextView/CPTextView.j +++ b/AppKit/CPTextView/CPTextView.j @@ -2505,16 +2505,21 @@ var _CPCopyPlaceholder = '-'; { var nativeClipboard = (e.originalEvent || e).clipboardData, richtext, - pasteboard = [CPPasteboard generalPasteboard]; + pasteboard = [CPPasteboard generalPasteboard], + currentFirstResponder = [[CPApp keyWindow] firstResponder], + isPlain = NO; + + if ([currentFirstResponder respondsToSelector:@selector(isRichText)] && ![currentFirstResponder isRichText]) + isPlain = YES; // this is the rich chrome / FF codepath (where we can use RTF directly) - if ((richtext = nativeClipboard.getData('text/rtf')) && !(!!window.event.shiftKey)) + if ((richtext = nativeClipboard.getData('text/rtf')) && !(!!window.event.shiftKey) && !isPlain) { e.preventDefault(); // setTimeout to prevent flickering in FF setTimeout(function(){ - [[[CPApp keyWindow] firstResponder] insertText:[[_CPRTFParser new] parseRTF:richtext]] + [currentFirstResponder insertText:[[_CPRTFParser new] parseRTF:richtext]] }, 20); return false; @@ -2530,8 +2535,6 @@ var _CPCopyPlaceholder = '-'; [pasteboard declareTypes:[CPStringPboardType] owner:nil]; [pasteboard setString:data forType:CPStringPboardType]; } - - var currentFirstResponder = [[CPApp keyWindow] firstResponder]; setTimeout(function(){ // prevent dom-flickering (only needed for FF) [currentFirstResponder paste:self]; diff --git a/AppKit/CPTextView/_CPRTFParser.j b/AppKit/CPTextView/_CPRTFParser.j index 43dbfa6f1..ab48fb117 100644 --- a/AppKit/CPTextView/_CPRTFParser.j +++ b/AppKit/CPTextView/_CPRTFParser.j @@ -657,6 +657,8 @@ var kRgsymRtf = { } - (CPAttributedString)parseRTF:(CPString)rtf { + rtf = rtf.replace(/\\\n/g, "\\par\n") + if (rtf.length == 0) return ''; From 61848c5e2408ece7017cb3baeae46dd1945120f2 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Mon, 12 Dec 2016 20:29:19 +0100 Subject: [PATCH 09/10] fixed: selection was not properly restored upon undo/redo --- AppKit/CPTextView/CPTextView.j | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/AppKit/CPTextView/CPTextView.j b/AppKit/CPTextView/CPTextView.j index e1db58e22..e87d8fffc 100644 --- a/AppKit/CPTextView/CPTextView.j +++ b/AppKit/CPTextView/CPTextView.j @@ -662,14 +662,15 @@ var kDelegateRespondsTo_textShouldBeginEditing [self setNeedsDisplay:YES]; } -- (void)_replaceCharactersInRange:aRange withAttributedString:(CPString)aString +- (void)_replaceCharactersInRange:(CPRange)aRange withAttributedString:(CPString)aString selectionRange:(CPRange)selectionRange { [[[[self window] undoManager] prepareWithInvocationTarget:self] _replaceCharactersInRange:CPMakeRange(aRange.location, [aString length]) - withAttributedString:[_textStorage attributedSubstringFromRange:CPMakeRangeCopy(aRange)]]; + withAttributedString:[_textStorage attributedSubstringFromRange:CPMakeRangeCopy(aRange)] + selectionRange:CPMakeRangeCopy(_selectionRange)]; [_textStorage replaceCharactersInRange:aRange withAttributedString:aString]; - [self _fixupReplaceForRange:CPMakeRange(CPMaxRange(aRange), 0)]; + [self _fixupReplaceForRange:selectionRange]; } - (void)insertText:(CPString)aString @@ -690,7 +691,8 @@ var kDelegateRespondsTo_textShouldBeginEditing [[undoManager prepareWithInvocationTarget:self] _replaceCharactersInRange:CPMakeRange(_selectionRange.location, [aString length]) - withAttributedString:[_textStorage attributedSubstringFromRange:CPMakeRangeCopy(_selectionRange)]]; + withAttributedString:[_textStorage attributedSubstringFromRange:CPMakeRangeCopy(_selectionRange)] + selectionRange:CPMakeRangeCopy(_selectionRange)]; [_textStorage replaceCharactersInRange:CPMakeRangeCopy(_selectionRange) withAttributedString:aString]; @@ -1449,7 +1451,9 @@ var kDelegateRespondsTo_textShouldBeginEditing changedRange = CPIntersectionRange(CPMakeRange(0, [_layoutManager numberOfCharacters]), changedRange); - [[[_window undoManager] prepareWithInvocationTarget:self] _replaceCharactersInRange:CPMakeRange(changedRange.location, 0) withAttributedString:[_textStorage attributedSubstringFromRange:CPMakeRangeCopy(changedRange)]]; + [[[_window undoManager] prepareWithInvocationTarget:self] _replaceCharactersInRange:CPMakeRange(changedRange.location, 0) + withAttributedString:[_textStorage attributedSubstringFromRange:CPMakeRangeCopy(changedRange)] + selectionRange:CPMakeRangeCopy(_selectionRange)]; [_textStorage deleteCharactersInRange:CPMakeRangeCopy(changedRange)]; [self setSelectedRange:CPMakeRange(changedRange.location, 0)]; From b2383a084a7eb0170699117fad1fda4c70c05909 Mon Sep 17 00:00:00 2001 From: daboe01 Date: Mon, 12 Dec 2016 22:32:00 +0100 Subject: [PATCH 10/10] fixed: wrong name in CPTextView manual test --- Tests/Manual/CPTextView/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Manual/CPTextView/index.html b/Tests/Manual/CPTextView/index.html index e08fb0b01..5069921db 100644 --- a/Tests/Manual/CPTextView/index.html +++ b/Tests/Manual/CPTextView/index.html @@ -1,7 +1,7 @@