.forEach(span => span.classList.remove("theme-fg-contrast")); } /** * Retrieve the available width between a provided element left edge and a container right * edge. This used can be used as a max-width for inplace-editor (autocomplete) widgets * replacing Editor elements of the the markup-view; */ function getAutocompleteMaxWidth(element, container) { const elementRect = element.getBoundingClientRect(); const containerRect = container.getBoundingClientRect(); return containerRect.right - elementRect.left - 2; } /** * Parse attribute names and values from a string. * * @param {string} attr * The input string for which names/values are to be parsed. * @param {HTMLDocument} doc * A document that can be used to test valid attributes. * @return {Array} * An array of attribute names and their values. */ function parseAttributeValues(attr, doc) { attr = attr.trim(); const parseAndGetNode = str => { return new DOMParser().parseFromString(str, "text/html").body.childNodes[0]; }; // Handle bad user inputs by appending a " or ' if it fails to parse without // them. Also note that a SVG tag is used to make sure the HTML parser // preserves mixed-case attributes const el = parseAndGetNode("") || parseAndGetNode("') || parseAndGetNode(""); // Create
in new document to work around CSP blocking inline styles. const htmlDoc = doc.implementation.createHTMLDocument(); const div = htmlDoc.createElement("div"); const attributes = []; for (const { name, value } of el.attributes) { // Try to set on an element in the document, throws exception on bad input. // Prevents InvalidCharacterError - "String contains an invalid character". try { div.setAttribute(name, value); attributes.push({ name, value }); } catch (e) { // This may throw exceptions on bad input. // Prevents InvalidCharacterError - "String contains an invalid // character". } } return attributes; } module.exports = { flashElementOn, flashElementOff, getAutocompleteMaxWidth, parseAttributeValues, }; PK