Jump to content

User:Werson/smartQuotes.js

From Wikipedia, the free encyclopedia
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// 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
$(smartQuotes);