User:Werson/smartQuotes.js

From Wikipedia, the free encyclopedia

If a message on your talk page led you here, please be wary of who left it. Code that you insert on this page could contain malicious content capable of compromising your account. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. If this is a .js page, the code will be executed when previewing the page.
Note: After saving, you have to bypass your browser's cache to see the changes. In Internet Explorer and Firefox, hold down the Ctrl key and click the Refresh or Reload button. Opera users have to clear their caches through Tools→Preferences, see the instructions for Opera. Konqueror and Safari users can just click the Reload button.
// smartQuotes.js
// by Werson
// version 1.2, 2008-05-14
// works correctly in:
// · Firefox 2.0
// works somewhat in:
// · Safari 3.1 (doesn't skip PRE/TT/CODE sections)
// 
// I, Werson, the copyright holder of this work, hereby release it into the public domain. This applies worldwide.
// In case this is not legally possible, I grant any entity the right to use this work for any purpose,
// without any conditions, unless such conditions are required by law.
 
// take a string and replace all straight marks with curly marks,
//   applying some basic rules (it's almost always a closing mark,
//   so figure out the few cases where it's an opening mark)
function quoteReplace(data) {
 
  // single quotation marks,
  //   problematic because apostrophes (same codepoint as closing quotes,
  //   unfortunately) can come at the beginning of words, so we need to
  //   list likely examples of that
  data = data.replace(/'([Nn])(\W)/g, '’$1$2');    // Guns 'n' Roses, or Guns 'n Roses, should use apostrophes
  data = data.replace(/'(\d)0s/g, '’$10s');  // '80s, '90s, etc.
  data = data.replace(/'([Tt]is)/g, '’$1');  // 'Tis the season, etc.
  data = data.replace(/'([Tt]was)/g, '’$1');  // 'Twas the season, etc.
  data = data.replace(/^'s(\W)/g, '’s$1');   // [[John]]'s (links are separate nodes,
                                             //   so this would otherwise be seen as 'S...')
 
  // the rest of these are homologous to double quotation marks
  data = data.replace(/\s'/g, '');
  data = data.replace(/^'([\d\w])/g, '‘$1');
  data = data.replace(/(\W)"([\d\w])/g, '$1“$2');
  data = data.replace(/'/g, '’');
 
  // double quotation marks
  data = data.replace(/\s"/g, ' “');              // a closing mark will never be preceded by a space
  data = data.replace(/"([\d\w])/g, '“$1');      // a closing mark will never be at the beginning of a line
                                                    //   (and won't be after a link if it's followed by a letter)
  data = data.replace(/(\W)"([\d\w])/g, '$1“$2');          // a closing mark won't be after a punctuation mark
                                                   //  but before a letter
  data = data.replace(/"/g, '”');            // anything else is probably a closer
 
  return data;
}
 
// go through document and get all text nodes, then replace quotation marks
function smartQuotes() {
  if (document.URL.indexOf('action=history') < 1 && document.URL.indexOf('action=edit') < 1) {
    // title is a special case, as replacing the node text doesn't do anything
    document.title = quoteReplace(document.title);
    // use an XPATH to find all text nodes, and run each one through quoteReplace()
    //   but do not alter PRE, CODE, or TT elements, or any of their descendents
    //   (I don't know how to do this elegantly in XPath)
    var xPathResult = document.evaluate('.//*[name(.) != "PRE" and name(.) != "CODE" and name(.) != "TT"]/*[name(.) != "PRE" and name(.) != "CODE" and name(.) != "TT"]/*[name(.) != "PRE" and name(.) != "CODE" and name(.) != "TT"]/text()[normalize-space(.) != ""]', document.documentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    for (var i = 0, l = xPathResult.snapshotLength; i < l; i++) {
      var textNode = xPathResult.snapshotItem(i);
      textNode.data = quoteReplace(textNode.data);
    }
    // crappy way to do this
    var html = document.body.innerHTML;
    document.body.innerHTML = html.replace('”<a ', '“<a ');
  }
}
 
// initiate smartQuotes script
addOnloadHook(smartQuotes);