To recreate

- Insert one link
- type some text
- Insert the same name again

Result: mangled code because first instance is also replaced. Replace function should only replace the last occurence.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

rudiedirkx’s picture

Not the last occurrence. The relevant occurrence. The last occurence might not be the one you're typing on. It might not even be the same exact name you're typing. You might have search for @alber first and @alb second. You must somehow remember where the user was typing =)

askibinski’s picture

I tried the whole "remember where the user was typing" idea, but it was a complete nightmare. As far as I could see there is no ckeditor function for this and trying to figure it out yourself is very difficult.

But you are right it's not necessarily the last occurence.

So instead, I'm thinking (aloud) that we could use the methods (A,B,C):

example:

typed = "@rudie"

A: look for "@rudie" without a link surrounding it
B: just replace "@rudie" with the whole name without "@" thus removing the problem for next insert.
C: replace any occurence of "@rudie" BUT use a character entity for "@" (@)

I would prefer A or B.
C seems a bit dirty and I'm not sure if it at all works or if it would cause other problems.

rudiedirkx’s picture

I think B and C are flawed because I could already have added a user @rudiedirkx and then want to add a user @rudie by typing @rudi. The @rudie from the last @rudi would replace the "rudie" in @rudiedirkx, right?

A might work, IF you're always adding a link.

Tricky stuff.

Another idea: remember the element you're in. CKEditor has methods for that. I've used that in CKEditor 3 before. If you're typing inside a P, you can keep that P and replace only its content. There could still be several @mentions in that P, but that problem will always exist without remembering exactly where the cursos was.

askibinski’s picture

Right. Tricky stuff indeed. But [A] should cover 99% of all usecases I think. Except perhaps when an email adress starts with the same letters, but that seems like an edge case.

Anybody now how to enhance below regexp (js) to make it replace "only $typed when $typed is not already link (between a href tag)"?

...
  var regEx = new RegExp(typed, "ig"); // case insensitive replacement
  var replaced_text = body.replace(regEx, linkhtml);
...
mcoirault’s picture

I'm working on that regexp to fit the A case. If I can, I'll try to cover that e-mail edge case.

mcoirault’s picture

I'm struggling with that regex. Here is my work so far : http://www.rubular.com/r/sHOuAa7vpE

The point is to search for not(an opening <a>) @user not(a closing </a>).
Any clue how we could make those not(substring) work properly?

rudiedirkx’s picture

Status: Needs review » Active

Regex and HTML are always a bad idea (HTML is not regexable, that's why DOCTYPE/DTD was invented). I'm pretty sure it's easier to just remember where your cursor is (the element, not the position) and then text-replace its contents.

Otherwise MAYBE negative lookahead and </a> will do the trick. Nope. Negative lookahead will match until a zero-width match (like </a>). It won't stop the entire match. (I might be wrong.)

Maybe it is possible with regex if you make a few assumptions, like

  • no HTML inside the <A> tag
  • no unencoded < or > inside the <A> attributes
  • the matching string isn't at the end of the text
  • etc

but I don't know it.

askibinski’s picture

The element you say, not position. But the element will be most likely a <p> and contain multiple mentions... So that won't be 100% foolproof. In fact when I would just start typing and mention the same name twice in a row (without enter) it would fail.

I agree regex is not the best solution but I wonder if a slightly different approach might be easier/better:

When typing an "@", we could maybe put this character between a temporary span as a marker. For example: <span>@</span>.

Then, when inserting, we swap the span out. But it will be easy to locate the string because it will always be something like "<span>@</span>rudie". Or am I overlooking something?

Of course, on cancel/stop observing, the span should be swapped out too.

rudiedirkx’s picture

I fixed it! Beautifully too! Now all that's left is to position the caret so you can keep typing. I'll upload a patch in a minute.

rudiedirkx’s picture

Stupid Drupal file upload crashed after I typed a nice message, so fuck it. See attached patch.

askibinski’s picture

Status: Active » Needs review

Thanks! Will test it asap.

askibinski’s picture

Assigned: askibinski » Unassigned
Status: Active » Needs work

The replacing seems to work well indeed, solving this issues problem. However, the patch needs some work:

  • backspace throws js error
  • does not stop watching after # number of chars

Also I think the menu callback needs to have:

    'delivery callback' => 'drupal_json_output',
askibinski’s picture

Status: Needs work » Fixed

Fixed and comitted to dev!

I fixed above issues and also added a check to see if the view has results. If none, the html is not appended (else an empty container might appear).

askibinski’s picture

This resulted however, in a bug with IE9/10 (didn't test it with IE8) which now makes inserting multiple mentions in IE impossible:

#2033739: IE9+ replacement problems when inserting existing strings

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

Anonymous’s picture

Issue summary: View changes

bold