NSRTFPboardType & paste into gmail browser window?

238 views Asked by At

I have a NSTextView which contains some text with attributes (syntax highlighting). I'm trying to have a copy option which keeps the syntax highlighting so that I can paste it into a gmail text window. Currently the highlighting does not appear when I copy paste it, however if I were to copy the following section directly from this stackoverflow page:

- (void) copyAsRTF
{
    NSPasteboard *pateboard = [NSPasteboard generalPasteboard];
    NSData * rtfData = [[self textStorage] RTFFromRange: [self selectedRange]
                                     documentAttributes: nil];

    if (rtfData)
    {
        NSString * test = [[NSString alloc] initWithData: rtfData
                                                encoding: NSUTF8StringEncoding];

        [pateboard declareTypes: @[NSRTFPboardType]
                          owner: self];

        [pateboard setData: rtfData
                   forType: NSRTFPboardType];
    } // End of we had data
} // End of copyAsRTF

And paste it into gmail, it will paste with full syntax highlight no problem. The above code is what I use for generating my RTF code and I can confirm that it does generate proper RTF as I have a test variable being generated.

Any ideas what I am doing wrong here? To my understanding this SHOULD work.

(I should note that I have tried in multiple browsers - Chrome, Safari and Firefox).

2

There are 2 answers

2
Sega-Zero On BEST ANSWER

As discovered in comments, in order to be working in chrome, you need to copy your text as html (public.html pasteboard type) or probably both html an rtf types.

1
Kyle On

Based on the comments with @Sega-Zero, I came up with the following (a bit sloppy, but it does the trick). For my specific needs, the html color & font should match the attributed string, so I enumerate that and create an html variable. This works in Safari, Chrome and Firefox.

#define PasteBoardTypeHTML          @"public.html"

- (void) copyAsRTF
{
    NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];

    // Get our RTF data
    NSData * rtfData = [[self textStorage] RTFFromRange: [self selectedRange]
                                     documentAttributes: nil];

    // Get the HTML for our current data
    NSData *htmlData = [[self htmlForRange: self.selectedRange] dataUsingEncoding: NSUTF8StringEncoding];

    NSMutableArray * clipboardTypes = [NSMutableArray array];
    if (nil != rtfData)
    {
        [clipboardTypes addObject: NSPasteboardTypeRTF];
    } // End of we have rtf

    if(nil != htmlData)
    {
        [clipboardTypes addObject: PasteBoardTypeHTML];
    } // End of we have html

    // Set our pasteboard types (types need to be declared before we call setData).
    [pasteboard declareTypes: clipboardTypes.copy
                       owner: self];

    if (rtfData)
    {
        [pasteboard setData: rtfData
                   forType: NSPasteboardTypeRTF];
    } // End of we have rtf

    if(htmlData)
    {
        [pasteboard setData: htmlData
                   forType: PasteBoardTypeHTML];
    } // End of we have html
} // End of copyAsRTF

- (NSString *) htmlForRange: (NSRange) range
{
    NSMutableString * htmlOutput = [NSMutableString stringWithString: @"<meta charset='utf-8'><pre>"];

    [[self textStorage] enumerateAttributesInRange: range
                                           options: 0
                                        usingBlock:
     ^(NSDictionary * attributes, NSRange range, BOOL * stop)
     {
         NSString * actualCode = [[self textStorage].string substringWithRange: range];
         actualCode = [self textToHtml: actualCode];

         NSMutableString * currentHtml = [NSMutableString stringWithString: @"<span"];
         NSColor * color = attributes[NSForegroundColorAttributeName];
         NSFont  * font  = attributes[NSFontAttributeName];

         NSMutableArray * fontStyles = [NSMutableArray array];

         if(nil != color)
         {
             NSString * fontColorStyle =
                [NSString stringWithFormat: @"color: %@;", [color hexadecimalValue]];

             [fontStyles addObject: fontColorStyle];
         } // End of we have a color

         if(nil != font)
         {
             NSString * fontDetailsStyle =
             [NSString stringWithFormat: @"font-family: %@;", font.familyName];
             [fontStyles addObject: fontDetailsStyle];
         } // End of we have a font

         if(nil != fontStyles && fontStyles.count > 0)
         {
             [currentHtml appendFormat: @" style=\"%@\"", [fontStyles componentsJoinedByString: @" "]];
         } // End of we have font styles

         [currentHtml appendString: @">"];

         [currentHtml appendString: actualCode];
         [currentHtml appendString: @"</span>"];

         // Add our section
         [htmlOutput appendString: currentHtml];
     }]; // End of attribute enumerations

    // End of html output
    [htmlOutput appendString: @"</pre></meta>"];

    return htmlOutput.copy;
} // End of htmlForRange:

- (NSString*)textToHtml:(NSString*)htmlString
{
    htmlString = [htmlString stringByReplacingOccurrencesOfString:@"&"  withString:@"&amp;"];
    htmlString = [htmlString stringByReplacingOccurrencesOfString:@"<"  withString:@"&lt;"];
    htmlString = [htmlString stringByReplacingOccurrencesOfString:@">"  withString:@"&gt;"];
    htmlString = [htmlString stringByReplacingOccurrencesOfString:@"""" withString:@"&quot;"];
    htmlString = [htmlString stringByReplacingOccurrencesOfString:@"'"  withString:@"&#039;"];
    htmlString = [htmlString stringByReplacingOccurrencesOfString:@"\n" withString:@"<br>"];
    return htmlString;
} // End of textToHtml: