0

I've written a jQuery extension:

$.fn.mentionify = function() {
    return this.each(function() {
        var link = $(this);
        link.html(link.html().replace(/(^|[^@\w])@(\w{1,30})\b/g, '$1<span class="mention">@$2</span>'));
    });
}

which turns:

@username

but not:

name@website.com

into:

<span class="mention">@username</span>

But if I run it on an element twice, it encases the already existing spans in another span tag. How can I check for pre-existing spans?

Max Hudson
  • 9,961
  • 14
  • 57
  • 107

1 Answers1

0

Have it test a Regex to see if a span already exists.

function() {
    var link = $(this);
    if(/<span/.test(link.html()))
       return;
    link.html(link.html().replace(/(^|[^@\w])@(\w{1,30})\b/g, '$1<span class="mention">@$2</span>'));
}

Edit:

Okay so I finally understand what you're asking and what you're trying to do. However, I didn't come up with an answer in my attempt. But I'd rather not leave you empty handed, so I'm telling you what I went through. Hopefully this will help in some way.

Attempt 1

First, you are correct on needing to change your regex. But it's not possible with a single expression. Originally my idea was to check for the ending tag. This would match @test from <span>@test</span>@test2.

But this doesn't account for @ between two spans: <span></span>@test<span></span>. See the last line here https://regex101.com/r/zB3yI9/5.

To counter this, you would need to check for an opening tag right before. But what it was a nested span.... Again this is the same problem.

Attempt 2

I know now a Regex pattern isn't nearly complicated enough by itself. Instead you need to recursively traverse the DOM until you reach a simple workable string.

I wrote up a fiddle in jQuery to do this. http://jsfiddle.net/zf63hca2/

But I ran into a problem. jQuery only sees DOM objects and not the stray text around them.

Attempt 3

So the DOM can't help you, it has to be done with Regex. The hard way. I now know why they warned me not to Regex HTML. I'd write the code but my brain is about to melt. So instead here's the details on the steps.

  1. Recursively find all simple expressions, remove them from the string. A simple expression is an opening and closing span without an opening between.
  2. Keep repeating 1 until no more matches. This will account for nesting.
  3. You should be finally left with a bunch of strings without span tags.
  4. Match for Twitter accounts and replace.
  5. Work backwards and put the whole thing back together.

There's a Regex API that simplifies this process. XRegExp supports chaining. The advantage is you can also get the start and end index from each match.

TL;DR

If you really want to get this to work with DOM then by all means, go for it. But as of now, it can already build multiple Twitter links as long as the provided string contains no DOM.

Ayrit
  • 103
  • 1
  • 10
  • Actually, this only works if there is only one @ in the text. I need to test each @ for surrounding spans and add spans to the ones that don't have spans, ideally only those with `mention` classes. This leads me to believe my regex string in replace needs to be modified, but I have no idea how to modify it correctly. – Max Hudson Nov 07 '15 at 00:39
  • Send me some of the sample text you're passing through it. https://regex101.com/r/zB3yI9/1 – Ayrit Nov 07 '15 at 00:45
  • `@test @test2` – Max Hudson Nov 07 '15 at 00:47
  • Forgive me for this. It's always harder to read someone else's code. Walk me through it and provide a bit more code. The mentionify function first gets called from `___`. And loops through text that has `___`. – Ayrit Nov 07 '15 at 01:10
  • You could even do this: `$("@test @test2").mentionify();`. It should result in `@test @test2` – Max Hudson Nov 07 '15 at 01:11
  • 1
    how about this simpler solution... I replace `$1` with `$1` and then just run mentionify on that! – Max Hudson Nov 07 '15 at 17:09
  • So instead of finding a way to avoid the spans, you take them out completely. Afterwards Mentionify re-adds the spans which results in non-nested Twitter links. Wish I saw that last night. Kudos to you for thinking out of the box. *Cheers.* – Ayrit Nov 07 '15 at 20:19