Skip to content

Instantly share code, notes, and snippets.

@blasten
Created January 19, 2017 17:46
Show Gist options
  • Save blasten/efb299fc69ccdfa97c7cf398a955c6e1 to your computer and use it in GitHub Desktop.
Save blasten/efb299fc69ccdfa97c7cf398a955c6e1 to your computer and use it in GitHub Desktop.
! function(t, i) {
"object" == typeof exports && "undefined" != typeof module ? module.exports = i() : "function" == typeof define && define.amd ? define(i) : t.Layout = i()
}(this, function() {
"use strict";
function t(t) {
return new Promise(function(i, n) {
function s(h, o) {
try {
var r = t[o ? "throw" : "next"](h)
} catch (t) {
return void n(t)
}
r.done ? i(r.value) : Promise.resolve(r.value).then(s, e)
}
function e(t) {
s(t, 1)
}
s()
})
}
function i() {
return new Promise(function(t) {
window.requestAnimationFrame(t)
})
}
function n(t, i, n) {
return Math.max(i, Math.min(n, t))
}
function s(t, i, n) {
return ~~(t + (n - i) * (t / i))
}
function e(t, i, n, s, e, h) {
return e == x ? t <= n - h : i >= n + s + h
}
function h(t, i, n, s, e) {
if (n == x && i + 1 < s.length) {
let n = e.get(s[i + 1]);
return n.y - t.h
}
if (n == E && i > 0) {
let t = e.get(s[i - 1]);
return t.y + t.h
}
return t.y
}
function o(t, i) {
if (i.hasOwnProperty("props")) {
let n = i.props;
delete i.props, i.props = t, i.props = n
} else i.props = t
}
function r(t) {
const i = document;
return t !== i.body && t !== i.documentElement && t instanceof HTMLElement ? t : window
}
function u(t) {
return t === window ? window.pageYOffset : t.scrollTop
}
function c(t, i) {
t === window ? window.scrollTo(0, i) : t.scrollTop = i
}
function f(t) {
return t.getBoundingClientRect().height
}
function l(t, i) {
if (0 == t) return [];
let n = Array(t);
n[0] = [0, i(0)];
for (let s = 1; s < t; s++) {
let t = n[s - 1][1] + 1,
e = t + i(s);
n[s] = [t, e]
}
return n
}
function d(t, i) {
let n = 0,
s = i.length - 1;
for (; n <= s;) {
let e = n + s >> 1;
if (t < i[e][0]) s = e - 1;
else {
if (!(t > i[e][1])) return e;
n = e + 1
}
}
return null
}
function a(t, i, n) {
return Object.keys(t).reduce((s, e) => {
let h = t[e];
return h[i] <= n && (!s || n - h[i] < n - s[i]) ? h : s
}, null)
}
function p(t, i, n) {
t[i] || (t[i] = []), t[i].push(n)
}
function g(t, i) {
return t[i] ? t[i].pop() : null
}
function y() {
return document.createElement("div")
}
const m = t => {},
b = {},
w = -1,
x = 1,
E = 2,
F = 0;
class v {
constructor(t, i, n, s) {
this.a = t, this.b = n, this.c = s, this.d = i, this.e = 0, this.f = 0, this.g = [], this.i = {}
}
recycle(i) {
return t(function*() {
if (i) {
let t = Array(i.length);
i.forEach((i, n) => {
let s = i.dataset.id;
t[n] = this.i[s] ? null : s, this.j(i)
}), i === this.g && (this.g = []), yield this.k(E, Math.max(1, t.length), ++this.e), t.forEach(t => this.release(t))
} else yield this.k(x, 1, ++this.e), yield this.k(E, 1, ++this.e)
}.call(this))
}
k(i, n, s) {
return t(function*() {
if (this.e == s)
for (; !this.l(this.startMeta, this.endMeta, i);) {
let t = performance.now();
if (0 === (n = this.m(i, n))) break;
this.n = (performance.now() - t) / n, n = 1
}
}.call(this))
}
p(t) {
let i = t.dataset;
i.poolId || (i.poolId = F), this.i[i.id] || (this.q(t), p(this.d, i.poolId, t))
}
m(t, i) {
let n, s, e = 0,
h = this.g,
o = this.c,
r = this.r,
u = this.s,
c = this.t;
for (; t == E && (n = h[0]) && (s = this.c.get(n)) && r(n, s);) this.p(n), h.shift();
for (; t == x && (n = h[h.length - 1]) && (s = this.c.get(n)) && r(n, s);) this.p(n), h.pop();
for (; e < i && (n = this.u(t));) t == x ? h.unshift(n) : h.push(n), this.v(n), e++;
for (let f = e - 1; t == x && f >= 0; f--) u(h[f], o.get(h[f]), h, o, f, t);
for (let f = h.length - e; t == E && f < h.length; f++) u(h[f], o.get(h[f]), h, o, f, t);
for (let f = e - 1; t == x && f >= 0; f--) c(h[f], o.get(h[f]));
for (let f = h.length - e; t == E && f < h.length; f++) c(h[f], o.get(h[f]));
return e
}
v(t) {
let i = this.a;
void 0 !== t.parentNode && t.parentNode !== i && i.appendChild(t)
}
u(t) {
let i, n = this.w();
if (0 == n) return null;
if (0 == this.g.length) i = w;
else if (i = t == x ? this.startMeta.idx - 1 : this.endMeta.idx + 1, i < 0 || i >= n) return;
return this.x(i)
}
x(t) {
let i, n, s;
this.w();
return i = this.z(this.b[t] || {
idx: t,
id: t
}), s = this.A(i.idx, i), n = this.i[i.id] || g(this.d, s) || this.B(), this.b[i.idx] = i, this.c.set(n, i), n.dataset.id = i.id, n.dataset.poolId = s, n.style.pointerEvents = "", this.C(n, i.idx, i), n
}
has(t) {
return t >= this.startMeta.idx && t <= this.endMeta.idx
}
j(t) {
this.i[t.dataset.id] = t
}
keep(t) {
let i, n = this.b[t];
return n && (i = this.i[n.id]) ? (this.t(i, n), n.id) : (i = this.has(t) ? this.g[t - this.startMeta.idx] : this.x(t), this.j(i, !1), this.v(i, E), this.t(i, this.c.get(i)), i.dataset.id)
}
release(t) {
let i = this.i[t];
if (i) {
let n = this.c.get(i);
delete this.i[t], this.g[n.idx - this.startMeta.idx] === i ? this.t(i, n) : this.p(i)
}
}
q(t) {
let i = t.style;
i.position = "absolute", i.pointerEvents = "none", i.top = "-100000000px", i.bottom = ""
}
get startMeta() {
return this.c.get(this.g[0]) || b
}
get endMeta() {
return this.c.get(this.g[this.g.length - 1]) || b
}
get nodes() {
return this.g
}
B() {
return null
}
r(t, i) {
return !0
}
l(t, i, n) {
return !0
}
o(t, i, n) {
return !0
}
w() {
return 0
}
t(t, i) {}
s(t, i, n, s, e, h) {}
C(t, i, n) {}
A(t, i) {
return F
}
z(t) {
return b
}
}
class M extends HTMLElement {
constructor() {
super(), this.style.cssText = `
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
`, this.D = 0, this.F = 0, this.G = 0, this.H = !1, this.I = null, this.J = null, this.b = {}, this.d = {}, this.c = new WeakMap, this.K = this.K.bind(this), this.L = this.L.bind(this), this.M = this.M.bind(this);
const t = new v(this, this.d, this.b, this.c);
t.z = this.N.bind(this), t.r = this.O.bind(this), t.l = this.P.bind(this), t.o = this.Q.bind(this), t.A = this.R.bind(this), t.t = this.S.bind(this), t.s = this.T.bind(this), t.C = this.U.bind(this), t.w = (t => this.f), t.B = y, this.V = t, o({
numberOfSections: 0,
numberOfRowsInSection: t => 0,
poolIdForHeader: t => "header",
poolIdForRow: t => "row",
domForHeader: m,
domForRow: m,
heightForHeader: f,
heightForRow: f,
scrollingElement: document.scrollingElement,
bottom: !1,
idForRow: t => 0,
idForHeader: t => 0
}, this)
}
connectedCallback() {
return t(function*() {
window.addEventListener("resize", this.L), this.addEventListener("focus", this.M, !0)
}.call(this))
}
disconnectedCallback() {
window.removeEventListener("resize", this.L), this.removeEventListener("focus", this.M)
}
get props() {
return this.W
}
set props(t) {
let i = this.W,
n = Object.assign({}, i, t);
i && i.scrollingElement === n.scrollingElement || (i && r(i.scrollingElement).removeEventListener("scroll", this.K), r(n.scrollingElement).addEventListener("scroll", this.K)), this.W = n, this.X()
}
get f() {
const t = this.J;
return t && t.length > 0 ? t[t.length - 1][1] + 1 : 0
}
get Y() {
const t = this.f,
i = this.b[t - 1];
return i && this.D == i.D ? i.y + i.h : s(this.F, this.G, t)
}
get Z() {
return ~~(this.F / this.G)
}
k(i, n, s) {
return t(function*() {
if (this.H) {
let t = this.V;
this.$ = i, this._ = n, yield t.recycle(s), this.style.height = 0 == this.f ? "" : `${this.Y}px`;
let e = t.startMeta,
h = e.idx,
o = e.y;
if (e != b) {
(h > 0 && o < 0 || 0 == h && 0 != o) && (e.y = this.Z * h, c(this.props.scrollingElement, e.y + this.$ - o), yield t.recycle(t.nodes));
let i = this.J[e.aa],
n = this.props.bottom ? this.f - i[1] - 1 : i[0],
s = t.keep(n);
s != this.ba && (t.release(this.ba), this.ba = s)
}
}
}.call(this))
}
X() {
return t(function*() {
let t = this.props;
if (yield i(), this.props === t) {
let i = u(t.scrollingElement),
n = t.scrollingElement.clientHeight,
s = this.V;
this.J = l(t.numberOfSections, t.numberOfRowsInSection), this.D++, this.G = 0, this.F = 0, (this.H || 0 != this.f) && (!this.H && this.f > 0 ? (this.H = !0, yield this.k(i, n, Array.from(this.children))) : yield this.k(i, n, s.nodes))
}
}.call(this))
}
P(t, i, n) {
return e(t.y, i.y + i.h, this.$, this._, n, 0)
}
Q(t, i, n) {
return !0
}
O(t, i) {
return i.y + i.h < this.$ - this._ / 2 || i.y > this.$ + 1.5 * this._
}
ca(t) {
let i = this.J,
n = this.props.bottom,
s = n ? this.f - t.idx - 1 : t.idx,
e = d(s, i),
h = n ? s - i[e][0] : s - i[e][0] - 1,
o = s == i[e][n ? 1 : 0],
r = o ? this.props.idForHeader(e) : this.props.idForRow(e, h);
return {
idx: t.idx,
h: t.h || 0,
y: t.y || 0,
id: r,
D: t.D || -1,
da: o,
aa: e,
ea: h
}
}
N(t) {
if (t.idx != w) return this.ca(t);
let i = a(this.b, "y", this.$);
return this.ca(i && i.idx < this.f && !this.O(null, i) ? i : {
idx: n(~~(this.$ / this.Z), 0, this.f - 1),
h: 0,
y: this.$
})
}
S(t, i) {
if (t.style.position = "absolute", t.style.top = `${i.y}px`, t.style.left = "0px", t.style.right = "0px", i.da) {
let n = this.J,
s = this.V,
e = n[i.aa + 1],
h = t.firstElementChild;
if (e && s.has(e[0])) {
let n = this.b[e[0]];
t.style.height = `${n.y-i.y}px`, t.style.bottom = "auto"
} else t.style.height = "", t.style.bottom = "0px";
h.style.position = "sticky", h.style.top = "0px"
}
}
T(t, i, n, s, e, o) {
i.D != this.D && (i.h = i.da ? this.props.heightForHeader(t.firstElementChild, i.aa) : this.props.heightForRow(t, i.aa, i.ea)), i.y = h(i, e, o, n, s), i.D = this.D, this.F = this.F + i.h, this.G = this.G + 1
}
R(t, i) {
return i.da ? this.props.poolIdForHeader(i.aa) : this.props.poolIdForRow(i.aa, i.ea)
}
U(t, i, n) {
return n.da ? (t.firstElementChild || t.appendChild(y()), this.props.domForHeader(t.firstElementChild, n.aa)) : this.props.domForRow(t, n.aa, n.ea)
}
K() {
let t = this.props.scrollingElement;
this.k(u(t), t.clientHeight)
}
L() {
this.X()
}
M(t) {
let i = t.target;
for (; i && i != this && !this.c.has(i);) i = i.parentNode;
let n = this.c.get(i);
n && (this.fa && this.V.release(this.fa), this.fa = this.V.keep(n.idx))
}
}
return customElements.define("layout-vertical", M), {
LayoutVertical: M
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment