applib
Version:
Cross-platform JavaScript and CSS library for Wikimedia apps
198 lines (172 loc) • 6.26 kB
JavaScript
;
/**
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