260
edits
No edit summary |
No edit summary |
||
| Line 781: | Line 781: | ||
}); | }); | ||
// ==UserScript== | |||
// @name MediaWiki Smart Single Quotes | |||
// @namespace http://your.local/ | |||
// @version 1.0 | |||
// @description Convert straight single quotes to typographic single quotes on MediaWiki pages (visual only). | |||
// @match https://wiki.ekatrafoundation.org/* | |||
// @grant none | |||
// ==/UserScript== | |||
(function ( | (function () { | ||
'use strict'; | 'use strict'; | ||
function convertSingleQuotesText(text) { | |||
function | |||
if (!text || text.indexOf("'") === -1) return text; | if (!text || text.indexOf("'") === -1) return text; | ||
text = text.replace(/([A-Za-z0-9])'([A-Za-z0-9])/g, "$1’$2"); // contractions/possessives | |||
text = text.replace(/([A-Za-z0-9])'([A-Za-z0-9])/g, "$1’$2"); | text = text.replace(/(^|[\s\(\[\{\<\u2014\u2013"“'«])'(?=\S)/g, "$1‘"); // opening quotes | ||
text = text.replace(/'/g, "’"); // remaining closing quotes | |||
text = text.replace(/(^|[\s\(\[\{\<\u2014\u2013"“'«])'(?=\S)/g, "$1‘"); | |||
text = text.replace(/'/g, "’"); | |||
return text; | return text; | ||
} | } | ||
function walkAndReplace(root) { | function walkAndReplace(root) { | ||
if (!root) return; | if (!root) return; | ||
try { | try { | ||
var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false); | var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false); | ||
var | var n; | ||
var blacklist = new Set(["CODE", "PRE", "SCRIPT", "STYLE", "TEXTAREA", "NOSCRIPT", "MATH", "INPUT | var blacklist = new Set(["CODE", "PRE", "SCRIPT", "STYLE", "TEXTAREA", "NOSCRIPT", "MATH", "INPUT"]); | ||
while (( | while ((n = walker.nextNode())) { | ||
var parent = | var parent = n.parentNode; | ||
if (!parent) continue; | if (!parent) continue; | ||
var anc = parent, skip = false; | var anc = parent, skip = false; | ||
while (anc && anc.nodeType === 1) { | while (anc && anc.nodeType === 1) { | ||
| Line 817: | Line 816: | ||
} | } | ||
if (skip) continue; | if (skip) continue; | ||
var | var orig = n.nodeValue; | ||
var | var rep = convertSingleQuotesText(orig); | ||
if ( | if (rep !== orig) n.nodeValue = rep; | ||
} | } | ||
} catch (e) { | } catch (e) { | ||
console.error('smartQuotes error', e); | |||
} | } | ||
} | } | ||
function applyOnce() { | |||
function | |||
var root = document.querySelector('.mw-parser-output') || document.body; | var root = document.querySelector('.mw-parser-output') || document.body; | ||
walkAndReplace(root); | walkAndReplace(root); | ||
} | } | ||
// | // run after window.load, also watch for AJAX content | ||
function | window.addEventListener('load', function () { | ||
setTimeout(applyOnce, 150); | |||
var obs = new MutationObserver(function (mutations) { | |||
mutations.forEach(function (m) { | |||
m.addedNodes && m.addedNodes.forEach(function (n) { | |||
if (n.nodeType === 1) walkAndReplace(n); | |||
else if (n.nodeType === 3 && n.parentNode) walkAndReplace(n.parentNode); | |||
}); | }); | ||
}); | }); | ||
}); | |||
obs.observe(document.body, { childList: true, subtree: true }); | |||
}, false); | |||
})(); | |||
} | |||
})( | |||