/* * visible.js * A lightweight, modern library to detect when elements become visible or invisible in the viewport * * @author Hassan Raza * https://github.com/Hassanrkbiz/visible * @version 1.0.3 * @license MIT * @copyright Hassan Raza 2025 */ !function(e,t){"use strict";var s=function(e){if(!e||"object"!=typeof e)return{};if(!e.IntersectionObserver)return console.warn("visible.js: IntersectionObserver is not supported. Consider using a polyfill: https://github.com/w3c/IntersectionObserver/tree/master/polyfill"),{};const t={toElementsArray:t=>t?t instanceof Element?[t]:t===e||t===document?[document.documentElement]:t instanceof NodeList||t instanceof HTMLCollection?Array.from(t):Array.isArray(t)?t.filter((e=>e instanceof Element)):[]:[],mergeOptions(e,...t){const s={...e};return t.forEach((e=>{e&&"object"==typeof e&&Object.keys(e).forEach((t=>{void 0!==e[t]&&(s[t]=e[t])}))})),s},throttle(e,t){let s;return function(...i){s||(e.apply(this,i),s=!0,setTimeout((()=>s=!1),t))}},validateThreshold:e=>Array.isArray(e)?e.filter((e=>"number"==typeof e&&e>=0&&e<=1)):"number"==typeof e&&e>=0&&e<=1?[e]:[0],createId:()=>`visible_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,querySelectorAll(e,t=document){try{return Array.from(t.querySelectorAll(e))}catch(t){return console.error("visible.js: Invalid selector:",e),[]}},setupTimeout:(e,t,s)=>"number"==typeof t&&t>0?setTimeout((()=>{e(),"function"==typeof s&&s(null)}),t):null},s={root:null,rootMargin:"0px",threshold:0,once:!1,selector:null,data:null,onVisible:null,onInvisible:null,onEnter:null,onLeave:null,debug:!1},i={existing:!1,once:!1,timeout:null},o=new Map,n=new Map;class r{constructor(e={}){this.id=t.createId(),this.options=t.mergeOptions(s,e),this.observer=null,this.observedElements=new Map,this.isDestroyed=!1,this.options.threshold=t.validateThreshold(this.options.threshold),this._initialize(),o.set(this.id,this)}_initialize(){if(this.isDestroyed)return;const e={root:this.options.root,rootMargin:this.options.rootMargin,threshold:this.options.threshold};this._debug("Initializing observer with options:",e),this.observer=new IntersectionObserver(this._handleIntersection.bind(this),e)}_handleIntersection(e){this.isDestroyed||e.forEach((e=>{const t=e.target,s=this.observedElements.get(t);s&&s.callbacks.forEach((s=>{this._processCallback(e,t,s)}))}))}_processCallback(e,t,s){const{options:i,callback:o,state:n}=s,r=Array.isArray(i.threshold)?i.threshold[0]:i.threshold,l=e.isIntersecting&&e.intersectionRatio>=r;l!==n.wasVisible&&(n.wasVisible=l,l?(this._triggerCallback(o,t,e,i.data,"visible"),this._triggerCallback(i.onVisible,t,e,i.data,"visible"),this._triggerCallback(i.onEnter,t,e,i.data,"enter"),n.triggered=!0):(this._triggerCallback(i.onInvisible,t,e,i.data,"invisible"),this._triggerCallback(i.onLeave,t,e,i.data,"leave")),i.once&&n.triggered&&this.unobserve(t,o))}_triggerCallback(e,t,s,i,o){if("function"==typeof e)try{e.call(t,t,s,i),this._debug(`Triggered ${o} callback for element:`,t)}catch(e){console.error(`visible.js: Error in ${o} callback:`,e)}}_debug(...e){this.options.debug&&console.log("[visible.js]",...e)}observe(e,s={},i){if(this.isDestroyed)return console.warn("visible.js: Cannot observe on destroyed instance"),this;const o=t.toElementsArray(e),n=t.mergeOptions(this.options,s);return o.forEach((e=>{if(!(e instanceof Element))return;const t={callback:i,options:n,state:{wasVisible:!1,triggered:!1}};this.observedElements.has(e)||(this.observedElements.set(e,{callbacks:[]}),this.observer.observe(e)),this.observedElements.get(e).callbacks.push(t),this._debug("Observing element:",e)})),this}unobserve(e,s){if(this.isDestroyed)return this;return t.toElementsArray(e).forEach((e=>{const t=this.observedElements.get(e);t&&(s?(t.callbacks=t.callbacks.filter((e=>e.callback!==s)),0===t.callbacks.length&&(this.observer.unobserve(e),this.observedElements.delete(e))):(this.observer.unobserve(e),this.observedElements.delete(e)),this._debug("Unobserving element:",e))})),this}isVisible(e){const t=this.observedElements.get(e);return!!t&&t.callbacks.some((e=>e.state.wasVisible))}getObservedElements(){return Array.from(this.observedElements.keys())}updateOptions(e){return this.options=t.mergeOptions(this.options,e),this.disconnect(),this._initialize(),this.observedElements.forEach(((e,t)=>{this.observer.observe(t)})),this}disconnect(){return this.observer&&(this.observer.disconnect(),this.observer=null),this.observedElements.clear(),this}destroy(){this.disconnect(),o.delete(this.id),this.isDestroyed=!0,this._debug("Instance destroyed")}}class l{constructor(e,s,o){this.id=t.createId(),this.selector=e,this.options=t.mergeOptions(i,s),this.callback=o,this.visibleInstance=null,this.mutationObserver=null,this.timeoutId=null,this.processedElements=new Set,this.isDestroyed=!1,this._initialize()}_initialize(){this.visibleInstance=new r({root:this.options.root||null,rootMargin:this.options.rootMargin||"0px",threshold:this.options.threshold||0,once:this.options.once||!1,debug:this.options.debug||!1}),this.options.existing&&this._processExistingElements(),this._setupMutationObserver(),this.options.timeout&&(this.timeoutId=t.setupTimeout((()=>this.destroy()),this.options.timeout,this.callback))}_processExistingElements(){t.querySelectorAll(this.selector).forEach((e=>{this._observeElement(e)}))}_setupMutationObserver(){const e={childList:!0,subtree:!0};this.mutationObserver=new MutationObserver((e=>{e.forEach((e=>{"childList"===e.type&&e.addedNodes.forEach((e=>{e.nodeType===Node.ELEMENT_NODE&&this._checkNewElement(e)}))}))})),this.mutationObserver.observe(document.body||document.documentElement,e)}_checkNewElement(e){if(e.matches&&e.matches(this.selector)&&this._observeElement(e),e.querySelectorAll){t.querySelectorAll(this.selector,e).forEach((e=>{this._observeElement(e)}))}}_observeElement(e){this.isDestroyed||this.processedElements.has(e)||(this.processedElements.add(e),this.visibleInstance.observe(e,{once:this.options.once||!1,data:this.options.data||null,onVisible:this.options.onVisible||null,onInvisible:this.options.onInvisible||null,onEnter:this.options.onEnter||null,onLeave:this.options.onLeave||null},(e=>{try{this.callback(e),this.options.once&&this.destroy()}catch(e){console.error("visible.js: Error in document.visible callback:",e)}})))}destroy(){this.isDestroyed||(this.isDestroyed=!0,this.visibleInstance&&(this.visibleInstance.destroy(),this.visibleInstance=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null),this.timeoutId&&(clearTimeout(this.timeoutId),this.timeoutId=null),n.delete(this.id))}}r.create=function(e){return new r(e)},r.destroyAll=function(){o.forEach((e=>e.destroy())),o.clear(),n.forEach((e=>e.destroy())),n.clear()},r.getInstances=function(){return Array.from(o.values())},r.getDocumentWatchers=function(){return Array.from(n.values())},"undefined"!=typeof document&&(document.visible=function(e,t,s){"function"==typeof t&&(s=t,t={});const i=new l(e,t,s);return n.set(i.id,i),{destroy:()=>i.destroy(),id:i.id}},document.invisible=function(e,t,s){"function"==typeof t&&(s=t,t={});const i=new l(e,t,(e=>{new r({onInvisible:s,debug:t.debug||!1}).observe(e)}));return n.set(i.id,i),{destroy:()=>i.destroy(),id:i.id}},document.unobserveVisible=function(e){n.forEach((t=>{t.selector===e&&t.destroy()}))});const c="_visibleInstance";"undefined"!=typeof Element&&(Element.prototype.visible=function(e,t){return"function"==typeof e&&(t=e,e={}),this[c]||(this[c]=new r(e)),this[c].observe(this,e,t)},Element.prototype.invisible=function(e,s){"function"==typeof e&&(s=e,e={});const i=t.mergeOptions(e,{onInvisible:s});return this[c]||(this[c]=new r(i)),this[c].observe(this,i)},Element.prototype.unobserveVisible=function(e){return this[c]&&this[c].unobserve(this,e),this},Element.prototype.isElementVisible=function(){return!!this[c]&&this[c].isVisible(this)});if(void 0!==e.jQuery){const s=e.jQuery;s.fn.visible=function(e,t){return this.each((function(){"function"==typeof e&&(t=e,e={}),this[c]||(this[c]=new r(e)),this[c].observe(this,e,t)}))},s.fn.invisible=function(e,s){return this.each((function(){"function"==typeof e&&(s=e,e={});const i=t.mergeOptions(e,{onInvisible:s});this[c]||(this[c]=new r(i)),this[c].observe(this,i)}))},s.fn.unobserveVisible=function(e){return this.each((function(){this[c]&&this[c].unobserve(this,e)}))},s.fn.isVisible=function(){return this.length>0&&this[0].isElementVisible()}}return r}(e);"object"==typeof module&&"object"==typeof module.exports?module.exports=s:"function"==typeof define&&define.amd?define([],(function(){return s})):e.Visible=s}("undefined"!=typeof window?window:this),"undefined"!=typeof module&&module.exports&&(module.exports.Visible=module.exports);