upfront-editable
Version:
Friendly contenteditable API
137 lines (116 loc) • 4.3 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.replaceAllQuotes = replaceAllQuotes;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var doubleQuotePairs = [['«', '»'], // ch german, french
['»', '«'], // danish
['"', '"'], // danish, not specified
['“', '”'], // english US
['”', '”'], // swedish
['“', '“'], // chinese simplified
['„', '“'] // german
];
var singleQuotePairs = [['‘', '’'], // english UK
['‹', '›'], // ch german, french
['‚', '‘'], // german
['’', '’'], // swedish
['›', '‹'], // danish
["'", "'"], // danish, not specified
["\u2018", "\u2019"] // chinese simplified
];
var apostrophe = ['’', // german
"'" // default
];
var quotesRegex = /([‘’‹›‚'«»"“”„])(?![^<]*?>)/g; // whitespace end of tag, or any dash (normal, en or em-dash)
// or any opening double quote
var beforeOpeningQuote = /\s|[>\-–—«»”"“„]/; // whitespace begin of tag, or any dash (normal, en or em-dash)
// or any closing quote, or any punctuation
var afterClosingQuote = /\s|[<\-–—«»”"“‘’‹›'.;?:,]/;
var replacements;
function replaceAllQuotes(str, replaceQuotesRules) {
replacements = replaceQuotesRules || {};
replacements.quotes = replacements.quotes || [undefined, undefined];
replacements.singleQuotes = replacements.singleQuotes || [undefined, undefined];
var matches = getAllQuotes(str);
if (matches.length > 0) {
replaceMatchedQuotes(matches, 0);
return replaceExistingQuotes(str, matches);
}
return str;
}
function replaceMatchedQuotes(matches, position) {
while (position < matches.length) {
var closingTag = findClosingQuote(matches, position);
if (closingTag) {
matches[position].replace = closingTag.type === 'double' ? replacements.quotes[0] : replacements.singleQuotes[0];
matches[closingTag.position].replace = closingTag.type === 'double' ? replacements.quotes[1] : replacements.singleQuotes[1];
if (closingTag.position !== position + 1) {
var nestedMatches = matches.slice(position + 1, closingTag.position);
if (nestedMatches) {
replaceMatchedQuotes(nestedMatches, 0);
}
}
position = closingTag.position + 1;
} else {
matches[position].replace = replaceApostrophe(matches[position]["char"]);
position += 1;
}
}
}
function findClosingQuote(matches, position) {
if (position === matches.length - 1) return;
var current = matches[position];
var openingQuote = current["char"];
if (current.before && !beforeOpeningQuote.test(current.before)) return;
var possibleClosingSingleQuotes = getPossibleClosingQuotes(openingQuote, singleQuotePairs);
var possibleClosingDoubleQuotes = getPossibleClosingQuotes(openingQuote, doubleQuotePairs);
for (var i = position + 1; i < matches.length; i++) {
if (matches[i].after && afterClosingQuote.test(matches[i].after) || !matches[i].after) {
if (possibleClosingSingleQuotes.includes(matches[i]["char"])) {
return {
position: i,
type: 'single'
};
}
if (possibleClosingDoubleQuotes.includes(matches[i]["char"])) {
return {
position: i,
type: 'double'
};
}
}
}
}
function getPossibleClosingQuotes(openingQuote, pairs) {
return pairs.filter(function (quotePair) {
return quotePair[0] === openingQuote;
}).map(function (quotePair) {
return quotePair[1];
});
}
function replaceApostrophe(quote) {
if (apostrophe.includes(quote)) {
return replacements.apostrophe;
}
}
function getAllQuotes(str) {
return (0, _toConsumableArray2["default"])(str.matchAll(quotesRegex)).map(function (match) {
var index = match.index;
return {
"char": match[1],
before: index > 0 ? str[index - 1] : '',
after: index + 1 < str.length ? str[index + 1] : ''
};
});
}
function replaceExistingQuotes(str, matches) {
var index = 0;
return str.replace(quotesRegex, function (match) {
var replacement = matches[index].replace || matches[index]["char"];
index += 1;
return replacement;
});
}