// ==UserScript== // @name SmartQuotes.js // @namespace http://tampermonkey.net/ // @version 0.1 // @description try to take over the world! // @author You // @match * // @grant none // ==/UserScript== (function() { (function (root, factory) { if (typeof define === 'function' && define.amd) { define(factory); } else if (typeof exports === 'object') { module.exports = factory(); } else { root.smartquotes = factory(); } } (this, function() { // The smartquotes function should just delegate to the other functions function smartquotes(context) { if (typeof document !== 'undefined' && typeof context === 'undefined') { var run = function() { smartquotes.element(document.body); }; // if called without arguments, run on the entire body after the document has loaded if (document.readyState !== 'loading') { // we're already ready run(); } else if (document.addEventListener) { document.addEventListener("DOMContentLoaded", run, false); } else { var readyStateCheckInterval = setInterval(function() { if (document.readyState !== 'loading') { clearInterval(readyStateCheckInterval); run(); } }, 10); } } else if (typeof context === 'string') { return smartquotes.string(context); } else { return smartquotes.element(context); } } smartquotes.string = function(str, retainLength) { return str .replace(/'''/g, '\u2034' + (retainLength ? '\u2063\u2063' : '')) // triple prime .replace(/(\W|^)"(\w)/g, '$1\u201c$2') // beginning " .replace(/(\u201c[^"]*)"([^"]*$|[^\u201c"]*\u201c)/g, '$1\u201d$2') // ending " .replace(/([^0-9])"/g,'$1\u201d') // remaining " at end of word .replace(/''/g, '\u2033' + (retainLength ? '\u2063' : '')) // double prime as two single quotes .replace(/(\W|^)'(\S)/g, '$1\u2018$2') // beginning ' .replace(/([a-z])'([a-z])/ig, '$1\u2019$2') // conjunction's possession .replace(/(\u2018)([0-9]{2}[^\u2019]*)(\u2018([^0-9]|$)|$|\u2019[a-z])/ig, '\u2019$2$3') // abbrev. years like '93 .replace(/((\u2018[^']*)|[a-z])'([^0-9]|$)/ig, '$1\u2019$3') // ending ' .replace(/(\B|^)\u2018(?=([^\u2018\u2019]*\u2019\b)*([^\u2018\u2019]*\B\W[\u2018\u2019]\b|[^\u2018\u2019]*$))/ig, '$1\u2019') // backwards apostrophe .replace(/"/g, '\u2033') // double prime .replace(/'/g, '\u2032'); // prime }; smartquotes.element = function(root) { var TEXT_NODE = typeof Element !== 'undefined' && Element.TEXT_NODE || 3; handleElement(root); function handleElement(el) { if (['CODE', 'PRE', 'SCRIPT', 'STYLE'].indexOf(el.nodeName.toUpperCase()) !== -1) { return; } var i, node, nodeInfo; var childNodes = el.childNodes; var textNodes = []; var text = ''; // compile all text first so we handle working around child nodes for (i = 0; i < childNodes.length; i++) { node = childNodes[i]; if (node.nodeType === TEXT_NODE || node.nodeName === '#text') { textNodes.push([node, text.length]); text += node.nodeValue || node.value; } else if (node.childNodes && node.childNodes.length) { text += handleElement(node); } } text = smartquotes.string(text, true); for (i in textNodes) { nodeInfo = textNodes[i]; if (nodeInfo[0].nodeValue) { nodeInfo[0].nodeValue = substring(text, nodeInfo[0].nodeValue, nodeInfo[1]); } else if (nodeInfo[0].value) { nodeInfo[0].value = substring(text, nodeInfo[0].value, nodeInfo[1]); } } return text; } function substring(text, value, position) { return text.substr(position, value.length).replace('\u2063', ''); } return root; }; return smartquotes; })); smartquotes(); })();