UNPKG

applib

Version:

Cross-platform JavaScript and CSS library for Wikimedia apps

198 lines (172 loc) 6.26 kB
'use strict'; /** Tries to get an array of table header (TH) contents from a given table. If there are no TH elements in the table, an empty array is returned. @param {!Element} element Table or blob of HTML containing a table? @param {?string} pageTitle @return {!Array<string>} */ var getTableHeader = function getTableHeader(element, pageTitle) { var thArray = []; if (element.children === undefined || element.children === null) { return thArray; } for (var i = 0; i < element.children.length; i++) { var el = element.children[i]; if (el.tagName === 'TH') { // ok, we have a TH element! // However, if it contains more than two links, then ignore it, because // it will probably appear weird when rendered as plain text. var aNodes = el.querySelectorAll('a'); if (aNodes.length < 3) { // todo: remove nonstandard Element.innerText usage // Also ignore it if it's identical to the page title. if ((el.innerText && el.innerText.length || el.textContent.length) > 0 && el.innerText !== pageTitle && el.textContent !== pageTitle && el.innerHTML !== pageTitle) { thArray.push(el.innerText || el.textContent); } } } // if it's a table within a table, don't worry about it if (el.tagName === 'TABLE') { continue; } // recurse into children of this element var ret = getTableHeader(el, pageTitle); // did we get a list of TH from this child? if (ret.length > 0) { thArray = thArray.concat(ret); } } return thArray; }; var CollapseTable = { getTableHeader: getTableHeader }; /** * Returns closest ancestor of element which matches selector. * Similar to 'closest' methods as seen here: * https://api.jquery.com/closest/ * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest * @param {!Element} el Element * @param {!string} selector Selector to look for in ancestors of 'el' * @return {?HTMLElement} Closest ancestor of 'el' matching 'selector' */ var findClosest = function findClosest(el, selector) { while ((el = el.parentElement) && !el.matches(selector)) { // Intentionally empty. // Reminder: the parenthesis around 'el = el.parentElement' are also intentional. } return el; }; /** * Determines if element has a table ancestor. * @param {!Element} el Element * @return {boolean} Whether table ancestor of 'el' is found */ var isNestedInTable = function isNestedInTable(el) { return findClosest(el, 'table') !== null; }; var elementUtilities = { findClosest: findClosest, isNestedInTable: isNestedInTable }; /** * To widen an image element a css class called 'wideImageOverride' is applied to the image element, * however, ancestors of the image element can prevent the widening from taking effect. This method * makes minimal adjustments to ancestors of the image element being widened so the image widening * can take effect. * @param {!HTMLElement} el Element whose ancestors will be widened */ var widenAncestors = function widenAncestors(el) { while ((el = el.parentElement) && !el.classList.contains('content_block')) { // Reminder: the parenthesis around 'el = el.parentElement' are intentional. if (el.style.width) { el.style.width = '100%'; } if (el.style.maxWidth) { el.style.maxWidth = '100%'; } if (el.style.float) { el.style.float = 'none'; } } }; /** * Some images should not be widended. This method makes that determination. * @param {!HTMLElement} image The image in question * @return {boolean} Whether 'image' should be widened */ var shouldWidenImage = function shouldWidenImage(image) { // Images within a "<div class='noresize'>...</div>" should not be widened. // Example exhibiting links overlaying such an image: // 'enwiki > Counties of England > Scope and structure > Local government' if (elementUtilities.findClosest(image, "[class*='noresize']")) { return false; } // Side-by-side images should not be widened. Often their captions mention 'left' and 'right', so // we don't want to widen these as doing so would stack them vertically. // Examples exhibiting side-by-side images: // 'enwiki > Cold Comfort (Inside No. 9) > Casting' // 'enwiki > Vincent van Gogh > Letters' if (elementUtilities.findClosest(image, "div[class*='tsingle']")) { return false; } // Imagemaps, which expect images to be specific sizes, should not be widened. // Examples can be found on 'enwiki > Kingdom (biology)': // - first non lead image is an image map // - 'Three domains of life > Phylogenetic Tree of Life' image is an image map if (image.hasAttribute('usemap')) { return false; } // Images in tables should not be widened - doing so can horribly mess up table layout. if (elementUtilities.isNestedInTable(image)) { return false; } return true; }; /** * Removes barriers to images widening taking effect. * @param {!HTMLElement} image The image in question */ var makeRoomForImageWidening = function makeRoomForImageWidening(image) { widenAncestors(image); // Remove width and height attributes so wideImageOverride width percentages can take effect. image.removeAttribute('width'); image.removeAttribute('height'); }; /** * Widens the image. * @param {!HTMLElement} image The image in question */ var widenImage = function widenImage(image) { makeRoomForImageWidening(image); image.classList.add('wideImageOverride'); }; /** * Widens an image if the image is found to be fit for widening. * @param {!HTMLElement} image The image in question * @return {boolean} Whether or not 'image' was widened */ var maybeWidenImage = function maybeWidenImage(image) { if (shouldWidenImage(image)) { widenImage(image); return true; } return false; }; var WidenImage = { maybeWidenImage: maybeWidenImage, test: { shouldWidenImage: shouldWidenImage, widenAncestors: widenAncestors } }; var index = { CollapseTable: CollapseTable, WidenImage: WidenImage, test: { ElementUtilities: elementUtilities } }; module.exports = index; //# sourceMappingURL=applib.js.map