Eduard Kuzmenko
3 years ago
2 changed files with 166 additions and 52 deletions
@ -0,0 +1,105 @@ |
|||||||
|
/* |
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/ |
||||||
|
|
||||||
|
export type IntersectionTarget = Element; |
||||||
|
export type IntersectionCallback = (entry: IntersectionObserverEntry) => void; |
||||||
|
|
||||||
|
export default class SuperIntersectionObserver { |
||||||
|
private observing: Map<IntersectionTarget, Set<IntersectionCallback>>; |
||||||
|
private observingQueue: SuperIntersectionObserver['observing']; |
||||||
|
private observer: IntersectionObserver; |
||||||
|
private freezedObservingNew: boolean; |
||||||
|
|
||||||
|
constructor(init?: IntersectionObserverInit) { |
||||||
|
this.observing = new Map(); |
||||||
|
this.observingQueue = new Map(); |
||||||
|
this.freezedObservingNew = false; |
||||||
|
|
||||||
|
this.observer = new IntersectionObserver((entries) => { |
||||||
|
const observing = this.observing; |
||||||
|
for(let i = 0, length = entries.length; i < length; ++i) { |
||||||
|
const entry = entries[i]; |
||||||
|
const callbacks = observing.get(entry.target); |
||||||
|
if(!callbacks) { |
||||||
|
debugger; |
||||||
|
} |
||||||
|
|
||||||
|
for(const callback of callbacks) { |
||||||
|
try { |
||||||
|
callback(entry); |
||||||
|
} catch(err) { |
||||||
|
console.error('intersection process callback error:', err); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}, init); |
||||||
|
} |
||||||
|
|
||||||
|
public disconnect() { |
||||||
|
this.observer.disconnect(); |
||||||
|
} |
||||||
|
|
||||||
|
public toggleObservingNew(value: boolean) { |
||||||
|
if(this.freezedObservingNew === value) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
this.freezedObservingNew = value; |
||||||
|
|
||||||
|
const queue = this.observingQueue; |
||||||
|
if(!value && queue.size) { |
||||||
|
for(const [target, callbacks] of queue) { |
||||||
|
for(const callback of callbacks) { |
||||||
|
this.observe(target, callback); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
queue.clear(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public has(target: IntersectionTarget, callback: IntersectionCallback, observing = this.observing) { |
||||||
|
const callbacks = observing.get(target); |
||||||
|
return !!(callbacks && callbacks.has(callback)); |
||||||
|
} |
||||||
|
|
||||||
|
public observe(target: IntersectionTarget, callback: IntersectionCallback) { |
||||||
|
if(this.freezedObservingNew && this.has(target, callback)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
const observing = this.freezedObservingNew ? this.observingQueue : this.observing; |
||||||
|
let callbacks = observing.get(target); |
||||||
|
if(callbacks && callbacks.has(callback)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if(!callbacks) { |
||||||
|
callbacks = new Set(); |
||||||
|
observing.set(target, callbacks); |
||||||
|
|
||||||
|
if(observing === this.observing) { |
||||||
|
this.observer.observe(target); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
callbacks.add(callback); |
||||||
|
} |
||||||
|
|
||||||
|
public unobserve(target: IntersectionTarget, callback: IntersectionCallback) { |
||||||
|
const observing = this.freezedObservingNew && !this.has(target, callback) ? this.observingQueue : this.observing; |
||||||
|
const callbacks = observing.get(target); |
||||||
|
if(!callbacks) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
callbacks.delete(callback); |
||||||
|
if(!callbacks.size) { |
||||||
|
observing.delete(target); |
||||||
|
this.observer.unobserve(target); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue