Created
June 30, 2017 12:50
-
-
Save bennypowers/80cfb099afc578d6e601dbde1ac9a180 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Author: Jason Farrell | |
* Author URI: http://useallfive.com/ | |
* | |
* Description: Checks if a DOM element is truly visible. | |
* Package URL: https://github.com/UseAllFive/true-visibility | |
*/ | |
function isVisible(node) { | |
'use strict'; | |
/** | |
* Checks if a DOM element is visible. Takes into | |
* consideration its parents and overflow. | |
* | |
* @param (el) the DOM element to check if is visible | |
* | |
* These params are optional that are sent in recursively, | |
* you typically won't use these: | |
* | |
* @param (t) Top corner position number | |
* @param (r) Right corner position number | |
* @param (b) Bottom corner position number | |
* @param (l) Left corner position number | |
* @param (w) Element width number | |
* @param (h) Element height number | |
*/ | |
function _isVisible(el, t, r, b, l, w, h) { | |
var p = el.parentNode, | |
VISIBLE_PADDING = 2; | |
if ( !_elementInDocument(el) ) { | |
return false; | |
} | |
//-- Return true for document node | |
if ( 9 === p.nodeType ) { | |
return true; | |
} | |
//-- Return false if our element is invisible | |
if ( | |
'0' === _getStyle(el, 'opacity') || | |
'none' === _getStyle(el, 'display') || | |
'hidden' === _getStyle(el, 'visibility') | |
) { | |
return false; | |
} | |
if ( | |
'undefined' === typeof(t) || | |
'undefined' === typeof(r) || | |
'undefined' === typeof(b) || | |
'undefined' === typeof(l) || | |
'undefined' === typeof(w) || | |
'undefined' === typeof(h) | |
) { | |
t = el.offsetTop; | |
l = el.offsetLeft; | |
b = t + el.offsetHeight; | |
r = l + el.offsetWidth; | |
w = el.offsetWidth; | |
h = el.offsetHeight; | |
} | |
//-- If we have a parent, let's continue: | |
if ( p ) { | |
//-- Check if the parent can hide its children. | |
if ( ('hidden' === _getStyle(p, 'overflow') || 'scroll' === _getStyle(p, 'overflow')) ) { | |
//-- Only check if the offset is different for the parent | |
if ( | |
//-- If the target element is to the right of the parent elm | |
l + VISIBLE_PADDING > p.offsetWidth + p.scrollLeft || | |
//-- If the target element is to the left of the parent elm | |
l + w - VISIBLE_PADDING < p.scrollLeft || | |
//-- If the target element is under the parent elm | |
t + VISIBLE_PADDING > p.offsetHeight + p.scrollTop || | |
//-- If the target element is above the parent elm | |
t + h - VISIBLE_PADDING < p.scrollTop | |
) { | |
//-- Our target element is out of bounds: | |
return false; | |
} | |
} | |
//-- Add the offset parent's left/top coords to our element's offset: | |
if ( el.offsetParent === p ) { | |
l += p.offsetLeft; | |
t += p.offsetTop; | |
} | |
//-- Let's recursively check upwards: | |
return _isVisible(p, t, r, b, l, w, h); | |
} | |
return true; | |
} | |
//-- Cross browser method to get style properties: | |
function _getStyle(el, property) { | |
if ( window.getComputedStyle ) { | |
return document.defaultView.getComputedStyle(el, null)[property]; | |
} | |
if ( el.currentStyle ) { | |
return el.currentStyle[property]; | |
} | |
} | |
function _elementInDocument(element) { | |
while (element = element.parentNode) { | |
if (element == document) { | |
return true; | |
} | |
} | |
return false; | |
} | |
return _isVisible(node); | |
} | |
chai.Assertion.addProperty('visible', function() { | |
var el = flag(this, 'object'); | |
var actual = isVisible(el); | |
this.assert( | |
actual !== false | |
, 'expected ' + elToString(el) + ' to be visible, but it was not' | |
, 'expected ' + elToString(el) + ' to not be visible, but it was' | |
, actual | |
) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment