User:Werson/smartQuotes.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
Documentation for this user script can be added at User:Werson/smartQuotes. |
// 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);