views:

63

answers:

4

I am trying to display text in a javascript tooltip

I keep getting unterminated string literals even though: a) the quotes are being slashed, b) there are no line breaks

The text I am trying to display is:

"No, we can't. This is going to be terrible."

(its a quotation from an individual and I want those quotes to display in the tooltip)

My tooltip function works like this

onMouseOver="Tip('string here')"

After I run the string through my function to clean for javascript

function jschars($str) {
        echo preg_replace("/\r?\n/", "\\n", addslashes($str));
}

It comes out looking like this in HTML:

onMouseOver="Tip('\"No, we can\'t. This is going to be terrible.\"')"

This gives me the error unterminated string literal for the first \ in Tip('\

I'm guessing its because im trying to put quotes directly inside the single quotes, how can I get around this for situations like this? (I have tried htmlspecial chars, such as replacing the " with & quot ; - I still get the error

+2  A: 

You should use htmlspecialchars() for this purpose. The problem is ", but HTML won't understand javascript quoting, so it stops at \".

function jschars($str) {
        echo htmlspecialchars(preg_replace("/\r?\n/", "\\n", $str), ENT_QUOTES);
}
Lekensteyn
That solves half the problem, anyway. Although from the question, I *think* he's already manually handled the second half.
T.J. Crowder
+5  A: 

It's because you're putting double-quotes inside the value of an XML (or html) element:

<div onMouseOver="Tip('\".......

the back-slash doesn't escape it from the context of xml/html. Technically, you'll need to entity-encode the string (after you javascript-escape it). Something like this:

<div onMouseOver="Tip('\&quot;No, we can\'t. This is going to be terrible.\&quot;')" >

Various browsers may or may not deal with that properly. A much better way to approach it would be to give the element an id (or a class, or some other way for you to select it), then add the mouse over handler from a standalone script.

Lee
+3  A: 

Because of the structure of what you're doing:

onMouseOver="Tip('string here')"

...you have to do two things:

  1. As Lekensteyn said, you need to use htmlspecialchars to turn any special HTML characters into character escapes. It does things like turn " into &quot;, which means you can safely enclose the attribute in " characters.

  2. But you're not just using this as an attribute, you're also putting it inside a string literal, which means you also need to do JavaScript escaping on the string. Otherwise, (in your case) a single ' character or backslash will mess up the string. So your jschars function also needs to (in order) A) Convert \ to \\, B) Convert ' to \'. That's the minimum, anyway, really you need a thorough "make this safe to put inside a JavaScript literal" function. From your question, I sort of had the impression you were doing this manually, but better to automate it for consistency.

Off-topic: Separately, I would recommend moving away from using attributes to attach handlers. Instead, look into attachEvent (IE) and addEventListener (W3C), or better yet look at a library like jQuery, Closure, Prototype, YUI, or any of several others that will smooth things out for you. For instance, attaching a mouseover handler to:

You can use this handler to handle the mouseover:

function handler() {
    Tip('Your message here');
}

...which you then hook up like this with raw DOM stuff (obviously you'd make a utility function for this):

var div = document.getElementById('foo');
if (div.attachEvent) {
    // Uses "onmouseover", not "mouseover"
    div.attachEvent('onmouseover', handler);
}
else if (div.addEventListener) {
    // Uses "mouseover", not "onmouseover"
    div.attachEvent('mouseover', handler, false);
}
else {
    // Fallback to old DOM0 stuff
    div.onmouseover = handler;
}

Here's how Prototype simplifies that hook-up process:

$('foo').observe('mouseover', handler);

Here's how jQuery does:

$('#foo').mouseover(handler);
T.J. Crowder
A: 

You could keep the string in javascript instead of HTML. eg:

<a onmouseover="Tip(this, 123)">choice</a>

Then something like:

var texts = {
  123:"No, we can't. This is going to be terrible.",
  ...
};

function Tip(elm, txtId){
  showTip(elm, texts[txtid];
}
Mic