You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
81 lines
2.7 KiB
81 lines
2.7 KiB
/** |
|
* @file |
|
* Cosmetic fix: converts straight quotes to typographic (curly) quotes |
|
* in rendered field markup, on page load / AJAX render. |
|
* |
|
* IMPORTANT: This is a display-only patch. It does NOT change the stored |
|
* field data in the database — it only rewrites text nodes in the DOM |
|
* after render. Treat it as a stopgap until the migrated content itself |
|
* is corrected; remove this once that's done. |
|
* |
|
* Adjust SELECTOR below to match whichever field wrappers actually need |
|
* this (e.g. body fields, specific content types). Keep it as narrow as |
|
* you reasonably can — this walks every text node inside each match. |
|
*/ |
|
(function (Drupal, once) { |
|
"use strict"; |
|
|
|
// CHANGE THIS to target only the fields that need it. |
|
const SELECTOR = ".field--name-field-history-note"; |
|
|
|
// Tags whose text content should never be touched. |
|
const SKIP_TAGS = new Set([ |
|
"SCRIPT", |
|
"STYLE", |
|
"TEXTAREA", |
|
"INPUT", |
|
"CODE", |
|
"PRE", |
|
]); |
|
|
|
/** |
|
* Converts straight quotes/apostrophes in a string to curly equivalents. |
|
* |
|
* Heuristic (same logic SmartyPants-style tools use): |
|
* - A straight double quote at the start of the string, or preceded by |
|
* whitespace / an opening bracket / a dash, is an OPENING quote. |
|
* Everything else is a CLOSING quote. |
|
* - A straight single quote in the same "opening" positions becomes an |
|
* opening single quote (‘); every other straight single quote — |
|
* including apostrophes in contractions like don't — becomes the |
|
* closing/apostrophe glyph (’), which is correct either way. |
|
*/ |
|
function smartenQuotes(text) { |
|
text = text.replace(/(^|[\s([{\-\u2014])"/g, "$1\u201C"); // opening “ |
|
text = text.replace(/"/g, "\u201D"); // remaining → ” |
|
text = text.replace(/(^|[\s([{\-\u2014])'/g, "$1\u2018"); // opening ‘ |
|
text = text.replace(/'/g, "\u2019"); // remaining → ’ (also apostrophes) |
|
return text; |
|
} |
|
|
|
function fixTextNodesIn(root) { |
|
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, { |
|
acceptNode: function (node) { |
|
if (SKIP_TAGS.has(node.parentNode.nodeName)) { |
|
return NodeFilter.FILTER_REJECT; |
|
} |
|
if (!/["']/.test(node.nodeValue)) { |
|
return NodeFilter.FILTER_SKIP; |
|
} |
|
return NodeFilter.FILTER_ACCEPT; |
|
}, |
|
}); |
|
|
|
const nodes = []; |
|
let n; |
|
while ((n = walker.nextNode())) { |
|
nodes.push(n); |
|
} |
|
nodes.forEach(function (node) { |
|
node.nodeValue = smartenQuotes(node.nodeValue); |
|
}); |
|
} |
|
|
|
Drupal.behaviors.smartQuotesCosmetic = { |
|
attach: function (context) { |
|
once("smart-quotes-cosmetic", SELECTOR, context).forEach(function (el) { |
|
fixTextNodesIn(el); |
|
}); |
|
}, |
|
}; |
|
})(Drupal, once);
|
|
|