mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-02-22 04:30:33 +09:00
104 lines
2.7 KiB
JavaScript
104 lines
2.7 KiB
JavaScript
export function generateUUID() {
|
|
const template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
|
return template.replace(/[xy]/g, function(char) {
|
|
const rand = (Math.random() * 16) | 0
|
|
const value = char === "x" ? rand : ((rand & 0x3)|0x8)
|
|
return value.toString(16)
|
|
})
|
|
}
|
|
|
|
export function synchronize(fn) {
|
|
const monitorCallbacks = new WeakMap
|
|
return function(callback) {
|
|
let callbacks = monitorCallbacks.get(this)
|
|
if (!callbacks) {
|
|
monitorCallbacks.set(this, (callbacks = []))
|
|
}
|
|
callbacks.push(callback)
|
|
|
|
if (callbacks.length === 1) {
|
|
return fn.call(this, () => {
|
|
Array.from(callbacks).forEach((callback) => { callback?.() })
|
|
return monitorCallbacks.delete(this)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
export function transitionElementWithClass(element, className, callback) {
|
|
return applyClassAwaitingEvent(element, className, "transitionend", callback)
|
|
}
|
|
|
|
const applyClassAwaitingEvent = function(element, className, eventName, callback) {
|
|
let timeout
|
|
let uninstalled = false
|
|
|
|
const uninstall = function() {
|
|
if (!uninstalled) {
|
|
uninstalled = true
|
|
element.removeEventListener(eventName, uninstall)
|
|
return requestAnimationFrame(function() {
|
|
element.classList.remove(className)
|
|
return callback?.()
|
|
})
|
|
}
|
|
}
|
|
|
|
element.addEventListener(eventName, uninstall)
|
|
element.classList.add(className)
|
|
|
|
// Failsafe: If we don't receive a {transition,animation}end event
|
|
// for some reason, ensure that uninstall is still called.
|
|
const duration = getDuration(element, eventName)
|
|
if (duration) {
|
|
timeout = duration + 50
|
|
} else {
|
|
timeout = 50
|
|
}
|
|
|
|
return setTimeout(uninstall, timeout)
|
|
}
|
|
|
|
const getDuration = function(element, eventName) {
|
|
const type = eventName === "animationend" ? "animation" : "transition"
|
|
const duration = getComputedStyle(element)[`${type}Duration`]
|
|
|
|
if (duration) {
|
|
if (/ms/.test(duration)) {
|
|
return parseInt(duration, 10)
|
|
} else {
|
|
return parseFloat(duration) * 1000
|
|
}
|
|
}
|
|
}
|
|
|
|
export function getElementMargin(element) {
|
|
const result = {}
|
|
const style = window.getComputedStyle(element);
|
|
|
|
["Top", "Right", "Bottom", "Left"].forEach((side) => {
|
|
result[side.toLowerCase()] = parseInt(style[`margin${side}`], 10)
|
|
})
|
|
|
|
return result
|
|
}
|
|
|
|
export function getAbsolutePositionForOffsets({ top, right, bottom, left }) {
|
|
return {
|
|
top: top + window.scrollY,
|
|
right: right + window.scrollX,
|
|
bottom: bottom + window.scrollY,
|
|
left: left + window.scrollX
|
|
}
|
|
}
|
|
|
|
|
|
export function getViewportRect() {
|
|
return {
|
|
top: window.scrollY,
|
|
right: window.scrollX + window.innerWidth,
|
|
bottom: window.scrollY + window.innerHeight,
|
|
left: window.scrollX
|
|
}
|
|
}
|