is-in-viewport
Version:
An ultra-light jQuery plugin that tells you if an element is in the viewport but with a twist.
246 lines (231 loc) • 10.3 kB
JavaScript
function runIsInViewport(tol) {
$('#container > div.box').css('background-color', '#21221E').text('out of viewport')
$('#container > div.box:in-viewport(' + tol + ')').css('background-color', '#C5C7BC').text('in viewport')
}
function runIsInViewportWithJqueryNot(tol) {
$('#container > div.box').not(':in-viewport(' + tol + ')').css('background-color', '#21221E').text('out of viewport')
$('#container > div.box:in-viewport(' + tol + ')').css('background-color', '#C5C7BC').text('in viewport')
}
function runIsInViewportVariant(tol) {
$('#container > div.box').css('background-color', '#21221E').text('out of viewport')
$('#container > div.box').isInViewport({ tolerance: tol }).css('background-color', '#C5C7BC').text('in viewport')
}
var runner = function(runIsInViewportFn, type) {
describe('isInViewport using ' + type, function() {
describe('viewport is window', function() {
var div
var addContainer = function() {
var html = '<div id="container"><div class="box">1</div></div>'
$('body').prepend(html)
runIsInViewportFn(100)
div = $('.box')
}
var removeContainer = function() {
$('#container').remove()
}
before(addContainer)
after(removeContainer)
function top(y, tol) {
div.css('top', '0')
div.css('top', y + 'px')
runIsInViewportFn(tol)
}
function left(x, tol) {
div.css('left', '0')
div.css('left', x + 'px')
runIsInViewportFn(tol)
}
describe('when tolerance is 100', function() {
describe('div location vertically in viewport', function() {
describe('when bottom of div is outside tolerance region while top is inside', function() {
it('should return the text from div as "in viewport"', function() {
div.text().should.be.exactly('in viewport')
})
})
describe('when bottom of div is equal to tolerance ie it\'s on the edge of tolerance region', function() {
it('should return the text from div as "in viewport"', function() {
top(-100, 100)
div.text().should.be.exactly('in viewport')
})
})
describe('when bottom of div is inside tolerance region', function() {
it('should return the text from div as "out of viewport"', function() {
top(-150, 100)
div.text().should.be.exactly('out of viewport')
})
})
describe('when top of div is equal to tolerance ie it\'s on the edge of tolerance region', function() {
it('should return the text from div as "in viewport"', function() {
top(100, 100)
div.text().should.be.exactly('in viewport')
})
})
describe('when top of div is outside tolerance region', function() {
it('should return the text from div as "out of viewport"', function() {
top(101, 100)
div.text().should.be.exactly('out of viewport')
})
})
})
describe('div location horizontally in viewport', function() {
describe('when left is greater than viewport width', function() {
it('should return the text from div as "out of viewport"', function() {
top(0, 100)
left(99999, 100)
div.text().should.be.exactly('out of viewport')
})
})
describe('when left is greater than viewport left edge', function() {
it('should return the text from div as "out of viewport"', function() {
left(-99999, 100)
div.text().should.be.exactly('out of viewport')
})
})
describe('when left is lesser than viewport width', function() {
it('should return the text from div as "in viewport"', function() {
left(90, 100)
div.text().should.be.exactly('in viewport')
left(0, 100)
})
})
})
})
describe('when tolerance is 0', function() {
describe('div location vertically in viewport', function() {
describe('when div top is 0', function() {
it('should return the text from div as "in viewport"', function() {
top(0, 0)
left(0, 0)
div.text().should.be.exactly('in viewport')
})
})
describe('when div top < 0 but bottom > 0', function() {
it('should return the text from div as "in viewport"', function() {
top(-1, 0)
div.text().should.be.exactly('in viewport')
})
})
describe('when div bottom < 0', function() {
it('should return the text from div as "out of viewport"', function() {
top(-201, 0)
div.text().should.be.exactly('out of viewport')
})
})
describe('when div top > viewport height', function() {
it('should return the text from div as "out of viewport"', function() {
top(99999, 0)
div.text().should.be.exactly('out of viewport')
})
})
describe('when both divs are in viewport', function() {
describe('when two arbitrary functions are chained using .do/.run', function() {
describe('when the first fn changes inner text to done and second adds a class name given by inner text', function() {
it('should have added a class named "done" to both divs', function() {
removeContainer()
var html = '<div id="container"><div class="box">1</div><div class="box">2</div></div>'
$('body').prepend(html)
var divs = $('div.box:in-viewport')
var count = 0
divs.should.have.length(2, 'length isn\'t 2')
divs.run(function() {
this.text('done')
}).run(function() {
// value of this is a normal html node and not a jQuery object
// hence it is being converted to a jQuery object here
this.addClass(this.text())
})
$.each(divs, function(i, v) {
if ($(v).hasClass('done')) {
count++
}
})
count.should.be.exactly(2, 'both divs don\'t have "done" class')
})
})
})
describe('when values other than functions are passed to .do/.run', function() {
it('should throw an error', function() {
var divs = $('div.box:in-viewport')
divs.should.have.length(2, 'length isn\'t 2')
try {
divs.run('boooop')
} catch (e) {
e.message.should.be.exactly('isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions')
}
})
})
describe('when array containing mixed values is passed to .do/.run', function() {
it('should ignore all non-function values and execute the functions that are in the array', function() {
var divs = $('div.box:in-viewport')
var temp = 0
var faultyArray = [1, 'test', function() {
return ++temp
}]
divs.should.have.length(2, 'length isn\'t 2')
divs.run(faultyArray)
temp.should.be.exactly(2, 'The only function in faultyArray didn\'t run') // 2 since there are 2 divs
})
})
describe('when an array of functions is passed to .do/.run', function() {
it('should execute all of the functions', function() {
var divs = $('div.box:in-viewport')
var temp = 0
var fnArray = []
var tempFn = function() {
return ++temp
}
for (var i = 0; i < 4; i++) {
fnArray.push(tempFn)
}
divs.should.have.length(2, 'length isn\'t 2')
divs.run(fnArray)
temp.should.be.exactly(8, 'all four functions did not execute')
})
})
})
})
describe('div location horizontally in viewport', function() {
describe('when left is greater than viewport width', function() {
it('should return the text from div as "out of viewport"', function() {
removeContainer()
addContainer()
top(0, 0)
left(99999, 0)
div.text().should.be.exactly('out of viewport')
})
})
describe('when left is greater than viewport left edge', function() {
it('should return the text from div as "out of viewport"', function() {
left(-99999, 0)
div.text().should.be.exactly('out of viewport')
})
})
describe('when left is lesser than viewport width', function() {
it('should return the text from div as "in viewport"', function() {
left(90, 0)
div.text().should.be.exactly('in viewport')
left(0, 0)
})
})
})
})
describe('when tolerance is -100', function() {
it('should be window.height - abs(tolerance)', function() {
var winHt = $(window).height()
top(winHt - 100, -100)
div.text().should.be.exactly('in viewport')
})
})
describe('when tolerance is not a number', function() {
it('should return default tolerance to 0', function() {
top(0, 'ads')
left(0, 'ad')
div.text().should.be.exactly('in viewport')
})
})
})
})
}
runner(runIsInViewport, 'pseudo-selector')
runner(runIsInViewportVariant, 'exposed isInViewport function')
runner(runIsInViewportWithJqueryNot, 'jquery\'s .not selector')