//<source lang="javascript">
// [[User:Werson/smartQuotes.js]]
// version 1.2, 2008-05-14
//
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('.//body//text()[not(ancestor::pre or ancestor::code or ancestor::input or ancestor::textarea) and (normalize-space(.) != "")]', document.documentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
// .//*[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(.) != ""]
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);
//</source>