Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
/*!
* jquery.visiblechange.js 0.7 // 2014.05.06 // tested with jQuery 1.11
*
* Copyright 2014 Andrey Shchekin for AffinityID
* Licensed under the terms of the MIT license.
*/
/*
* This plugin provides a new event 'visiblechange' that is raised when the
* visibility of the element changes. This includes direct change to visibility,
* or changes to parent visibility. However that sdoes not include element
* being "out-of-sight" due to the scrolling or other offsets.
*
* // basic usage:
* $(element).on('visiblechange', handler);
*
* // shortcut:
* $(element).visiblechange(handler);
*
* // unsubscribing:
* $(element).off('visiblechange');
*
* // handling:
* function handler(e) {
* console.log("visible:", e.visible);
* }
*
* Known limitations:
* 1. DOM changes are not handled -- movement of the element or its parents
* in the DOM tree can lead to unpredicatable results.
* 2. In the browsers that do not have MutationObservers, the poll interval
* is not configurable.
*/
(function($) {
var eventName = 'visiblechange'; // improves minification
$.event.special[eventName] = (function() {
var visibleDataKey = '__.' + eventName +'.data';
function setup() {
var $element = $(this);
var visible = $element.is(':visible');
var unobserve = window.MutationObserver
? observeWithMutationObserver($element)
: observeWithSetInterval($element);
$element.data(visibleDataKey, {
unobserve: unobserve,
oldVisible: visible
});
}
function observeWithMutationObserver($element) {
var observer = new MutationObserver(function() {
checkVisible($element);
});
$element.parents().addBack().each(function() {
observer.observe(this, {
attributes: true,
attributeFilter: ['style', 'class']
});
});
return function() {
return observer.disconnect();
};
}
function observeWithSetInterval($element) {
var timer = setInterval(function() {
checkVisible($element);
}, 500);
return function() { resetInterval(timer); };
}
function checkVisible($element) {
var data = $element.data(visibleDataKey);
var newVisible = $element.is(':visible');
if (newVisible === data.oldVisible)
return;
data.oldVisible = newVisible;
var event = $.Event(eventName);
event.visible = newVisible;
$element.trigger(event);
}
function teardown() {
var $element = $(this);
var data = $element.data(visibleDataKey);
data.unobserve();
$element.data(visibleDataKey, null);
}
return {
noBubble: true,
setup: setup,
teardown: teardown
};
})();
$.fn[eventName] = function(callback) {
this.on(eventName, callback);
};
})(window.jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment