Problem "smartening" and link-parsing the same text

225 Views Asked by At

I'm using jQuery, and a very simple script to replace quotes, apostrophes and double-dashes with their "smart" counterparts:

function smarten(a) {
  a = a.replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018");      // opening singles
  a = a.replace(/'/g, "\u2019");                             // closing singles & apostrophes
  a = a.replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201c"); // opening doubles
  a = a.replace(/"/g, "\u201d");                             // closing doubles
  a = a.replace(/--/g, "\u2014");                            // em-dashes
  return a
  };

I'm using this as a callback to TwitterJS, which parses links and produces a block like so:

<ul>
<li>Here's a link! <a href="http://www.foobar.com">http://www.foobar.com</a></li>
</ul>

The problem is that if I do this:

$('#tweet li').html(smarten($('#tweet li').html()))

it wrecks the links, and if I do this:

$('#tweet li').html(smarten($('#tweet li').text()))

it discards them altogether. Is there a smart, robust way to grab only the text (out of the <a> tag as well, if necessary), "smarten", and then put it back, without interfering with TwitterJS's link-parsing?

2

There are 2 best solutions below

1
On BEST ANSWER

Let's make a jQuery plugin:

jQuery.fn.smarten = (function(){

    function smartenNode(node) {
        if (node.nodeType === 3) {
            node.data = node.data
                .replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018")
                .replace(/'/g, "\u2019")
                .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201c")
                .replace(/"/g, "\u201d")
                .replace(/--/g, "\u2014");
        } else if (node.nodeType === 1) {
            if (node = node.firstChild) do {
                smartenNode(node);
            } while (node = node.nextSibling);
        }
    }

    return function() {
        return this.each(function(){
            smartenNode(this);
        });
    };

}());

Usage:

$('#tweet li').smarten();
0
On

Try:

$('#tweet li a').each( function() { $(this).text( smarten( $(this).text() ) ); } );