446 lines
8.2 KiB
JavaScript
446 lines
8.2 KiB
JavaScript
import ctEvents from 'ct-events'
|
|
import { isTouchDevice } from './frontend/helpers/is-touch-device'
|
|
import { isIosDevice } from './frontend/helpers/is-ios-device'
|
|
import $ from 'jquery'
|
|
|
|
const loadSingleEntryPoint = ({
|
|
els,
|
|
events,
|
|
forcedEvents,
|
|
load,
|
|
mount,
|
|
condition,
|
|
trigger,
|
|
}) => {
|
|
if (!els) {
|
|
els = []
|
|
}
|
|
|
|
if (!events) {
|
|
events = []
|
|
}
|
|
|
|
if (!forcedEvents) {
|
|
forcedEvents = []
|
|
}
|
|
|
|
if (!trigger) {
|
|
trigger = []
|
|
}
|
|
|
|
if (!mount) {
|
|
mount = ({ mount, el, ...everything }) =>
|
|
el ? mount(el, everything) : mount()
|
|
}
|
|
|
|
if (els && {}.toString.call(els) === '[object Function]') {
|
|
els = els()
|
|
}
|
|
|
|
const allEls = (Array.isArray(els) ? els : [els]).reduce(
|
|
(a, selector) => [
|
|
...a,
|
|
...(Array.isArray(selector)
|
|
? selector
|
|
: typeof selector === 'string'
|
|
? document.querySelectorAll(selector)
|
|
: [selector]),
|
|
],
|
|
[]
|
|
)
|
|
|
|
if (allEls.length === 0) {
|
|
return
|
|
}
|
|
|
|
if (
|
|
condition &&
|
|
!condition({
|
|
els,
|
|
allEls,
|
|
})
|
|
) {
|
|
return
|
|
}
|
|
|
|
if (trigger.length > 0) {
|
|
if (trigger.includes('click')) {
|
|
allEls.map((el) => {
|
|
if (el.hasLazyLoadClickListener) {
|
|
return
|
|
}
|
|
|
|
el.hasLazyLoadClickListener = true
|
|
|
|
el.addEventListener('click', (event) => {
|
|
event.preventDefault()
|
|
load().then((arg) => mount({ ...arg, event, el }))
|
|
})
|
|
})
|
|
}
|
|
|
|
if (trigger.includes('change')) {
|
|
allEls.map((el) => {
|
|
if (el.hasLazyLoadChangeListener) {
|
|
return
|
|
}
|
|
|
|
el.hasLazyLoadChangeListener = true
|
|
|
|
const cb = (event) => {
|
|
event.preventDefault()
|
|
load().then((arg) => mount({ ...arg, event, el }))
|
|
}
|
|
|
|
if ($) {
|
|
$(el).on('change', cb)
|
|
} else {
|
|
el.addEventListener('change', cb)
|
|
}
|
|
})
|
|
}
|
|
|
|
if (trigger.includes('scroll')) {
|
|
allEls.map((el) => {
|
|
if (el.hasLazyLoadScrollListener) {
|
|
return
|
|
}
|
|
|
|
el.hasLazyLoadScrollListener = true
|
|
|
|
setTimeout(() => {
|
|
let prevScroll = scrollY
|
|
|
|
let cb = (event) => {
|
|
if (Math.abs(scrollY - prevScroll) > 30) {
|
|
document.removeEventListener('scroll', cb)
|
|
|
|
load().then((arg) => {
|
|
return mount({ ...arg, event, el })
|
|
})
|
|
|
|
return
|
|
}
|
|
}
|
|
|
|
document.addEventListener('scroll', cb)
|
|
}, 500)
|
|
})
|
|
}
|
|
|
|
if (trigger.includes('slight-mousemove')) {
|
|
if (!document.body.hasSlightMousemoveListenerTheme) {
|
|
document.body.hasSlightMousemoveListenerTheme = true
|
|
|
|
const cb = (event) => {
|
|
allEls.map((el) => {
|
|
load().then((arg) => mount({ ...arg, el }))
|
|
})
|
|
}
|
|
|
|
document.addEventListener('mousemove', cb, { once: true })
|
|
// document.addEventListener('touchstart', cb, { once: true })
|
|
}
|
|
}
|
|
|
|
if (trigger.includes('input')) {
|
|
allEls.map((el) => {
|
|
if (el.hasLazyLoadInputListener) {
|
|
return
|
|
}
|
|
|
|
el.hasLazyLoadInputListener = true
|
|
|
|
el.addEventListener(
|
|
'input',
|
|
(event) => load().then((arg) => mount({ ...arg, el })),
|
|
{ once: true }
|
|
)
|
|
})
|
|
}
|
|
|
|
if (trigger.includes('hover-with-touch')) {
|
|
allEls.map((el) => {
|
|
if (el.hasLazyLoadMouseOverListener) {
|
|
return
|
|
}
|
|
|
|
if (el.dataset.autoplay && parseFloat(el.dataset.autoplay)) {
|
|
setTimeout(() => {
|
|
load().then((arg) =>
|
|
mount({
|
|
...arg,
|
|
el,
|
|
})
|
|
)
|
|
}, 10)
|
|
return
|
|
}
|
|
|
|
el.hasLazyLoadMouseOverListener = true
|
|
|
|
el.forcedMount = (data = {}) =>
|
|
load().then((arg) => mount({ ...arg, el, ...data }))
|
|
;['mouseover', ...(isTouchDevice() ? ['touchstart'] : [])].map(
|
|
(eventToRegister) => {
|
|
el.addEventListener(
|
|
eventToRegister,
|
|
(event) => {
|
|
load().then((arg) =>
|
|
mount({
|
|
...arg,
|
|
...(event.type === 'touchstart'
|
|
? { event }
|
|
: {}),
|
|
el,
|
|
})
|
|
)
|
|
},
|
|
{ once: true, passive: true }
|
|
)
|
|
}
|
|
)
|
|
})
|
|
}
|
|
|
|
if (trigger.includes('hover-with-click')) {
|
|
allEls.map((el) => {
|
|
if (el.hasLazyLoadClickHoverListener) {
|
|
return
|
|
}
|
|
|
|
el.hasLazyLoadClickHoverListener = true
|
|
|
|
const l = (event) => {
|
|
// iOS devices will prevent the click by default, no need
|
|
// to prevent it manually
|
|
if (!isIosDevice()) {
|
|
event.preventDefault()
|
|
}
|
|
|
|
load().then((arg) =>
|
|
mount({
|
|
...arg,
|
|
event,
|
|
el,
|
|
})
|
|
)
|
|
}
|
|
|
|
el.addEventListener(
|
|
isTouchDevice() ? 'click' : 'mouseover',
|
|
l,
|
|
{ once: true }
|
|
)
|
|
|
|
el.addEventListener('focus', l, { once: true })
|
|
})
|
|
}
|
|
|
|
if (trigger.includes('hover')) {
|
|
allEls.map((el) => {
|
|
if (el.hasLazyLoadMouseOverListener) {
|
|
return
|
|
}
|
|
|
|
el.hasLazyLoadHoverListener = true
|
|
|
|
el.addEventListener(
|
|
'mouseover',
|
|
(event) => {
|
|
load().then((arg) =>
|
|
mount({
|
|
...arg,
|
|
event,
|
|
el,
|
|
})
|
|
)
|
|
},
|
|
{ once: true }
|
|
)
|
|
})
|
|
}
|
|
|
|
if (trigger.includes('submit')) {
|
|
allEls.map((el) => {
|
|
if (el.hasLazyLoadSubmitListener) {
|
|
return
|
|
}
|
|
|
|
el.hasLazyLoadSubmitListener = true
|
|
|
|
el.addEventListener('submit', (event) => {
|
|
event.preventDefault()
|
|
load().then((arg) => mount({ ...arg, event, el }))
|
|
})
|
|
})
|
|
}
|
|
} else {
|
|
load().then((arg) => {
|
|
allEls.map((el) => {
|
|
mount({ ...arg, el })
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
export const onDocumentLoaded = (cb) => {
|
|
if (/comp|inter|loaded/.test(document.readyState)) {
|
|
cb()
|
|
} else {
|
|
document.addEventListener('DOMContentLoaded', cb, false)
|
|
}
|
|
}
|
|
|
|
export const handleEntryPoints = (mountEntryPoints, args) => {
|
|
const { immediate = false, skipEvents = false } = args || {}
|
|
|
|
if (!skipEvents) {
|
|
;[
|
|
...new Set(
|
|
mountEntryPoints.reduce(
|
|
(currentEvents, entry) => [
|
|
...currentEvents,
|
|
...(entry.events || []),
|
|
...(entry.forcedEvents || []),
|
|
],
|
|
[]
|
|
)
|
|
),
|
|
].map((distinctEvent) => {
|
|
ctEvents.on(distinctEvent, () => {
|
|
mountEntryPoints
|
|
.filter(
|
|
({ events = [] }) => events.indexOf(distinctEvent) > -1
|
|
)
|
|
.map((c) => loadSingleEntryPoint({ ...c, trigger: [] }))
|
|
|
|
mountEntryPoints
|
|
.filter(
|
|
({ forcedEvents = [] }) =>
|
|
forcedEvents.indexOf(distinctEvent) > -1
|
|
)
|
|
.map((entry) =>
|
|
loadSingleEntryPoint({
|
|
...entry,
|
|
...(entry.forcedEventsElsSkip
|
|
? {}
|
|
: {
|
|
els: ['body'],
|
|
}),
|
|
condition: () => true,
|
|
trigger: [],
|
|
})
|
|
)
|
|
})
|
|
})
|
|
}
|
|
|
|
const loadInitialEntryPoints = () => {
|
|
mountEntryPoints
|
|
.filter(({ onLoad = true }) => {
|
|
if ({}.toString.call(onLoad) === '[object Function]') {
|
|
return onLoad()
|
|
}
|
|
|
|
return !!onLoad
|
|
})
|
|
.map(loadSingleEntryPoint)
|
|
}
|
|
|
|
if (immediate) {
|
|
loadInitialEntryPoints()
|
|
} else {
|
|
onDocumentLoaded(loadInitialEntryPoints)
|
|
}
|
|
}
|
|
|
|
var loadCSS = function (href, before, media, attributes) {
|
|
var doc = document
|
|
var ss = doc.createElement('link')
|
|
var ref
|
|
|
|
if (before) {
|
|
ref = before
|
|
} else {
|
|
var refs = (doc.body || doc.getElementsByTagName('head')[0]).childNodes
|
|
ref = refs[refs.length - 1]
|
|
}
|
|
|
|
var sheets = doc.styleSheets
|
|
ss.rel = 'stylesheet'
|
|
ss.href = href
|
|
// ss.media = 'only x'
|
|
|
|
// ref.parentNode.insertBefore(ss, before ? ref : ref.nextSibling)
|
|
document.body.appendChild(ss)
|
|
|
|
var onloadcssdefined = function (cb) {
|
|
var resolvedHref = ss.href
|
|
var i = sheets.length
|
|
while (i--) {
|
|
if (sheets[i].href === resolvedHref) {
|
|
return cb()
|
|
}
|
|
}
|
|
setTimeout(function () {
|
|
onloadcssdefined(cb)
|
|
})
|
|
}
|
|
|
|
function loadCB() {
|
|
if (ss.addEventListener) {
|
|
ss.removeEventListener('load', loadCB)
|
|
}
|
|
// ss.media = media || 'all'
|
|
}
|
|
|
|
if (ss.addEventListener) {
|
|
ss.addEventListener('load', loadCB)
|
|
}
|
|
ss.onloadcssdefined = onloadcssdefined
|
|
onloadcssdefined(loadCB)
|
|
return ss
|
|
}
|
|
|
|
function onloadCSS(ss, callback) {
|
|
var called
|
|
|
|
function newcb() {
|
|
if (!called && callback) {
|
|
called = true
|
|
callback.call(ss)
|
|
}
|
|
}
|
|
|
|
if (ss.addEventListener) {
|
|
ss.addEventListener('load', newcb)
|
|
}
|
|
|
|
if (ss.attachEvent) {
|
|
ss.attachEvent('onload', newcb)
|
|
}
|
|
|
|
if ('isApplicationInstalled' in navigator && 'onloadcssdefined' in ss) {
|
|
ss.onloadcssdefined(newcb)
|
|
}
|
|
}
|
|
|
|
export const loadStyle = (src, hasDisable = false) =>
|
|
new Promise((resolve, reject) => {
|
|
if (document.querySelector(`[href="${src}"]`)) {
|
|
resolve()
|
|
return
|
|
}
|
|
|
|
requestAnimationFrame(() => {
|
|
const ss = loadCSS(src)
|
|
|
|
onloadCSS(ss, () => {
|
|
requestAnimationFrame(() => {
|
|
resolve()
|
|
})
|
|
})
|
|
})
|
|
})
|