Detecting URLs in a TextView

For a while now, I’ve wanted to add a feature to Assignment Planner that detects when you’ve typed a URL into any of the notes fields and displays the URL as a link. Coincidentally, while I was adding LRFilterBar and (the newly released) LRCalendarView to Cocoadev’s ObjectLibrary, I caught a glance of BlackHole Media’s URLTextView, which gets close to what I was looking for.

The problem is that the example will take text from an NSTextField and add it to the NSTextView, looking for URLs before it does so. But, I needed an editable NSTextView which will look for URLs as you type them in. So, I added the following code to the subclass:

- (void)didChangeText
{
  NSMutableAttributedString* inputValue = [[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@", [self string]]] autorelease];
  [inputValue detectURLs:[NSColor blueColor]];
  [[self textStorage] setAttributedString:inputValue];
  [super didChangeText];
}

- (void)setString:(NSString *)aString
{
  [super setString:aString];
  [self didChangeText];
}

So the didChangeText function is called whenever the text inside of the NSTextView changes. We take the text inside of the view, analyze it for URLs using the NSMutableAttributedString additions that come with the URLTextView and then replace the contents with our new attributed string.

We override the setString: function so that when we first set the string of the textbox, the contents are analyzed right off the bat. I found that without it, when an assignment was selected, the notes showed up but without all of the links. Then any one change in the box would create the links. So adding this function fixes the problem.

The only other issue that I had with the URLTextView was that the included finger pointer that should appear when the cursor hovers over the link doesn’t display. But, I don’t have a big problem with it, since it’s quite clear that the blue underlined link is clickable. Otherwise, this is the perfect solution to the problem.

URLTextView is available at BlackHole Media’s Code page.



3 Responses to “Detecting URLs in a TextView”
  1. Logan Design :: Blog » Blog Archive » URLs in NSTextView Fix
    January 9th, 2007 at 4:34 pm

    [...] So, when messing around with Assignment Planner over the past couple of days, I realized that my example of having clickable URLs in an NSTextView that I previously blogged about has a minor flaw. When trying to edit text that was at the bottom of the NSTextView, it acted just fine. But if you tried to go back and edit something elsewhere, after each character you typed, the cursor would jump back to the end of your text. This simply has to do with the fact that after each character, we reset the attributed string in the view. So, to fix it, we just need to save the location of the insertion point before the string replacement and restore it afterwards. We can do this by changing didChangeText as follows… – (void)didChangeText {   int insertionPointerLocation = [self selectedRange].location; [...]

  2. Duncan Campbell
    January 16th, 2007 at 4:46 pm

    Hmmm.. your approach may not be so efficient if you get a large amount of text in your NSTextView – think about a 10MB textfile – you are running this code each time anything in the text changes on the entire string – this is going to make typing veeerry slow.

    You can restrict to checking just the current visible portion of text, but you will then need to fire this code in the scroll events also (since didChangeText: isn’t fired by scrolling).

  3. Logan
    January 16th, 2007 at 8:01 pm

    Yeah, Duncan, you’re definitely right. Replacing the text after ever time can get to be pretty inefficient.

    I think there are a couple of ways to fix it, besides what you mention. Maybe check for URLs every certain number of characters, instead of every character. Also, using an NSTimer and doing it on a time interval might work. But I think I like your solution the best. I’ll give it a try sometime to see how well it works.

    Thanks!

You can follow any responses to this entry through the RSS 2.0 feed. Responses are currently closed, but you can trackback from your own site.

:: RSS Feed :: Archive :: Categories :: Admin