1
0
mirror of https://git.sr.ht/~cadence/bibliogram synced 2025-06-27 23:58:22 +00:00
bibliogram/src/site/html/static/js/pagination.js
Cadence Ember c2d7aca1cb
Replace all profile fetching methods with IWeb
The previous HTML method is gone due to a page restructure. It was
able to consistently bypass Instagram's blocking.

The IWeb method has a few hundred uses per X time for selfhosters, and
a couple dozen uses per X time for servers. This will likely change in
the future. There is no known way to bypass Instagram's IWeb blocking.

Feel free to look for a way.

Further timeline pages are still blocked. The "next page" button
defaults to not automatically loading when scrolled, since it will
basically never work anyway. Users running personal instances may be
able to get a couple of uses out of it.
2022-07-25 01:57:44 +12:00

108 lines
2.5 KiB
JavaScript

import {ElemJS, q} from "./elemjs/elemjs.js"
import {quota} from "./quota.js"
class FreezeWidth extends ElemJS {
freeze(text) {
this.element.style.width = window.getComputedStyle(this.element).width
this.oldText = this.element.textContent
this.text(text)
}
unfreeze() {
this.element.style.width = ""
this.text(this.oldText)
}
}
const intersectionThreshold = 0
class NextPageController {
constructor() {
this.instance = null
this.activatedCallbacks = []
}
add() {
const nextPage = q("#next-page")
if (nextPage) {
this.instance = new NextPage(nextPage, this)
} else {
this.instance = null
}
this.activatedCallbacks.forEach(c => c())
}
addActivatedCallback(callback) {
this.activatedCallbacks.push(callback)
}
async activate() {
if (this.instance) await this.instance.activate()
}
}
class NextPage extends FreezeWidth {
constructor(container, controller) {
super(container)
this.controller = controller
this.clicked = false
this.nextPageNumber = +this.element.getAttribute("data-page")
this.auto = this.element.getAttribute("data-auto")
this.attribute("href", "javascript:void(0)")
this.event("click", event => this.onClick(event))
this.observer = new IntersectionObserver(entries => this.onIntersect(entries), {rootMargin: "0px", threshold: intersectionThreshold})
if (this.auto !== "off") {
this.observer.observe(this.element)
}
}
onClick(event) {
if (event) event.preventDefault()
if (this.fetching) return
this.class("clicked")
this.fetch()
}
/**
* @param {IntersectionObserverEntry[]} entries
*/
onIntersect(entries) {
if (entries.some(entry => entry.isIntersecting && entry.intersectionRatio >= intersectionThreshold)) {
if (this.fetching) return
this.class("disabled")
this.class("clicked")
this.fetch()
}
}
fetch() {
if (this.fetching) return
this.fetching = true
this.freeze(this.element.getAttribute("data-loading-text"))
const type = this.element.getAttribute("data-type")
return fetch(`/fragment/user/${this.element.getAttribute("data-username")}/${this.nextPageNumber}?type=${type}`).then(res => {
if (res.status === 200) {
quota.change(-1)
}
return res.text()
}).then(text => {
q("#next-page-container").remove()
this.observer.disconnect()
q("#timeline").insertAdjacentHTML("beforeend", text)
this.controller.add()
})
}
activate() {
if (this.fetching) return
this.class("disabled")
return this.fetch()
}
}
const controller = new NextPageController()
controller.add()
export {controller}