javascriptjquerytwittersmart-quotes

Problem "smartening" and link-parsing the same text


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?


Solution

  • 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();