UNPKG

infusion

Version:

Infusion is an application framework for developing flexible stuff with JavaScript

149 lines (132 loc) 6.2 kB
/* Copyright The Infusion copyright holders See the AUTHORS.md file at the top-level directory of this distribution and at https://github.com/fluid-project/infusion/raw/master/AUTHORS.md. Licensed under the Educational Community License (ECL), Version 2.0 or the New BSD license. You may not use this file except in compliance with one these Licenses. You may obtain a copy of the ECL 2.0 License and BSD License at https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt */ var fluid_3_0_0 = fluid_3_0_0 || {}; (function ($, fluid) { "use strict"; /******************************************************************************* * fluid.textNodeParser * * Parses out the text nodes from a DOM element and its descendants *******************************************************************************/ fluid.defaults("fluid.textNodeParser", { gradeNames: ["fluid.component"], events: { onParsedTextNode: null, afterParse: null }, invokers: { parse: { funcName: "fluid.textNodeParser.parse", args: ["{that}", "{arguments}.0", "{arguments}.1", "{that}.events.afterParse.fire"] }, hasTextToRead: "fluid.textNodeParser.hasTextToRead", isWord: "fluid.textNodeParser.isWord", getLang: "fluid.textNodeParser.getLang" } }); /** * Tests if a string is a word; i.e. it has a value and is not only whitespace. * inspired by https://stackoverflow.com/a/2031143 * * @param {String} str - the String to test * * @return {Boolean} - `true` if a word, `false` otherwise. */ fluid.textNodeParser.isWord = function (str) { return fluid.isValue(str) && /\S/.test(str); }; /** * Determines if there is text in an element that should be read. * Will return false in the following conditions: * - elm is falsey (undefined, null, etc.) * - elm's offsetParent is falsey, unless elm is the `body` element * - elm has no text or only whitespace * - elm or an ancestor has "aria-hidden=true", unless the `acceptAriaHidden` parameter is set * * NOTE: Text added by pseudo elements (e.g. :before, :after) are not considered. * NOTE: This method is not supported in IE 11 because innerText returns the text for some hidden elements, * that is inconsistent with modern browsers. * * @param {jQuery|DomElement} elm - either a DOM node or a jQuery element * @param {Boolean} acceptAriaHidden - if set, will return `true` even if the `elm` or one of its ancestors has * `aria-hidden="true"`. * * @return {Boolean} - returns true if there is rendered text within the element and false otherwise. * (See conditions in description above) */ fluid.textNodeParser.hasTextToRead = function (elm, acceptAriaHidden) { elm = fluid.unwrap(elm); return elm && (elm.tagName.toLowerCase() === "body" || elm.offsetParent) && fluid.textNodeParser.isWord(elm.innerText) && (acceptAriaHidden || !$(elm).closest("[aria-hidden=\"true\"]").length); }; /** * Uses jQuery's `closest` method to find the closest element with a lang attribute, and returns the value. * * @param {jQuery|DomElement} elm - either a DOM node or a jQuery element * * @return {String|Undefined} - a valid BCP 47 language code if found, otherwise undefined. */ fluid.textNodeParser.getLang = function (elm) { return $(elm).closest("[lang]").attr("lang"); }; /** * The parsed information of text node, including: the node itself, its specified language, and its index within its * parent. * * @typedef {Object} TextNodeData * @property {DomNode} node - The current child node being parsed * @property {Integer} childIndex - The index of the child node being parsed relative to its parent * @property {String} lang - a valid BCP 47 language code */ /** * Recursively parses a DOM element and it's sub elements and fires the `onParsedTextNode` event for each text node * found. The event is fired with the text node, language and index of the text node in the list of its parent's * child nodes.. * * Note: elements that return `false` from `that.hasTextToRead` are ignored. * * @param {fluid.textNodeParser} that - an instance of the component * @param {jQuery|DomElement} elm - the DOM node to parse * @param {String} lang - a valid BCP 47 language code. * @param {Event} afterParseEvent - the event to fire after parsing has completed. * * @return {TextNodeData[]} the array of parsed elements. Only text nodes for elements that have passed the * `that.hasTextToRead` check will be included. */ fluid.textNodeParser.parse = function (that, elm, lang, afterParseEvent) { elm = fluid.unwrap(elm); var parsed = []; if (that.hasTextToRead(elm)) { var childNodes = elm.childNodes; var elementLang = elm.getAttribute("lang") || lang || that.getLang(elm); // This funny iteration is a fix for FLUID-6435 on IE11 Array.prototype.forEach.call(childNodes, function (childNode, childIndex) { if (childNode.nodeType === Node.TEXT_NODE) { var textNodeData = { node: childNode, lang: elementLang, childIndex: childIndex }; parsed.push(textNodeData); that.events.onParsedTextNode.fire(textNodeData); } else if (childNode.nodeType === Node.ELEMENT_NODE) { parsed = parsed.concat(fluid.textNodeParser.parse(that, childNode, elementLang)); } }); } if (afterParseEvent) { afterParseEvent(that, parsed); } return parsed; }; })(jQuery, fluid_3_0_0);