Files
dotfiles/dotfiles/.vscode-oss/extensions/yandeu.five-server-0.3.1-universal/dist/bundle/client/highlight.ts
2024-04-25 13:49:40 +01:00

408 lines
12 KiB
TypeScript

/* eslint-disable prefer-object-spread */
/* eslint-disable prefer-template */
/**
* @copyright
* Copyright (c) 2012 - present Adobe Systems Incorporated. All rights reserved. (https://github.com/adobe)
* Copyright (c) 2021 Yannick Deubel (https://github.com/yandeu)
*
* @license {@link https://github.com/yandeu/five-server/blob/main/LICENSE LICENSE}
*
* @description
* copied from https://github.com/adobe/brackets/blob/master/src/LiveDevelopment/Agents/RemoteFunctions.js
* previously licensed under MIT (https://github.com/adobe/brackets/blob/master/LICENSE)
*/
let _remoteHighlight
const HIGHLIGHT_CLASS_NAME = '__brackets-ld-highlight'
const config = {
experimental: false, // enable experimental features
debug: true, // enable debug output and helpers
autoConnect: false, // go live automatically after startup?
highlight: true, // enable highlighting?
highlightConfig: {
// the highlight configuration for the Inspector
borderColor: { r: 255, g: 229, b: 153, a: 0.66 },
contentColor: { r: 111, g: 168, b: 220, a: 0.55 },
marginColor: { r: 246, g: 178, b: 107, a: 0.66 },
paddingColor: { r: 147, g: 196, b: 125, a: 0.66 },
showInfo: true
},
remoteHighlight: {
animateStartValue: {
'background-color': 'rgba(0, 162, 255, 0.5)',
opacity: 0
},
animateEndValue: {
'background-color': 'rgb(106, 171, 233)', //'rgba(0, 162, 255, 0)',
opacity: 0.6
},
paddingStyling: {
//'border-width': '1px',
//'border-style': 'dashed',
//'border-color': 'rgba(0, 162, 255, 0.5)',
'background-color': 'rgb(156, 221, 156)'
},
marginStyling: {
'background-color': 'rgb(255 ,177 ,95)' // 'rgba(21, 165, 255, 0.58)'
},
borderColor: 'rgba(21, 165, 255, 0.85)',
showPaddingMargin: true
}
}
// Checks if the element is in Viewport in the client browser
function isInViewport(element) {
const rect = element.getBoundingClientRect()
const html = window.document.documentElement
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || html.clientHeight) &&
rect.right <= (window.innerWidth || html.clientWidth)
)
}
// set an event on a element
function _trigger(element, name, value, autoRemove?) {
// MOD(yandeu): Do not automatically remove the highlight.
/*
const key = 'data-ld-' + name
if (value !== undefined && value !== null) {
element.setAttribute(key, value)
if (autoRemove) {
window.setTimeout(element.removeAttribute.bind(element, key))
}
} else {
element.removeAttribute(key)
}
*/
}
// compute the screen offset of an element
function _screenOffset(element) {
const elemBounds = element.getBoundingClientRect(),
body = window.document.body
let offsetTop, offsetLeft
if (window.getComputedStyle(body).position === 'static') {
offsetLeft = elemBounds.left + window.pageXOffset
offsetTop = elemBounds.top + window.pageYOffset
} else {
const bodyBounds = body.getBoundingClientRect()
offsetLeft = elemBounds.left - bodyBounds.left
offsetTop = elemBounds.top - bodyBounds.top
}
return { left: offsetLeft, top: offsetTop }
}
// returns the distance from the top of the closest relatively positioned parent element
function getDocumentOffsetTop(element) {
return element.offsetTop + (element.offsetParent ? getDocumentOffsetTop(element.offsetParent) : 0)
}
// redraw active highlights
function redrawHighlights() {
if (_remoteHighlight) {
_remoteHighlight.redraw()
}
}
let req, timeout
const animateHighlight = function (time) {
if (req) {
window.cancelAnimationFrame(req)
window.clearTimeout(timeout)
}
req = window.requestAnimationFrame(redrawHighlights)
timeout = setTimeout(function () {
window.cancelAnimationFrame(req)
req = null
}, time * 1000)
}
export class Highlight {
trigger: boolean
elements: any[] = []
selector = '[data-highlight="true"]'
constructor(trigger: boolean) {
this.trigger = !!trigger
}
elementExists(element) {
let i
for (i in this.elements) {
if (this.elements[i] === element) {
return true
}
}
return false
}
makeHighlightDiv(element, doAnimation) {
const elementBounds = element.getBoundingClientRect(),
highlight = window.document.createElement('div'),
elementStyling = window.getComputedStyle(element),
transitionDuration = parseFloat(elementStyling.getPropertyValue('transition-duration')),
animationDuration = parseFloat(elementStyling.getPropertyValue('animation-duration'))
if (transitionDuration) {
animateHighlight(transitionDuration)
}
if (animationDuration) {
animateHighlight(animationDuration)
}
// Don't highlight elements with 0 width & height
if (elementBounds.width === 0 && elementBounds.height === 0) {
return
}
const realElBorder = {
right: elementStyling.getPropertyValue('border-right-width'),
left: elementStyling.getPropertyValue('border-left-width'),
top: elementStyling.getPropertyValue('border-top-width'),
bottom: elementStyling.getPropertyValue('border-bottom-width')
}
const borderBox = elementStyling.boxSizing === 'border-box'
let innerWidth = parseFloat(elementStyling.width),
innerHeight = parseFloat(elementStyling.height),
outerHeight = innerHeight,
outerWidth = innerWidth
if (!borderBox) {
innerWidth += parseFloat(elementStyling.paddingLeft) + parseFloat(elementStyling.paddingRight)
innerHeight += parseFloat(elementStyling.paddingTop) + parseFloat(elementStyling.paddingBottom)
;(outerWidth = innerWidth + parseFloat(realElBorder.right) + parseFloat(realElBorder.left)),
(outerHeight = innerHeight + parseFloat(realElBorder.bottom) + parseFloat(realElBorder.top))
}
const visualizations = {
horizontal: 'left, right',
vertical: 'top, bottom'
}
const drawPaddingRect = function (side) {
const elStyling = {}
if (visualizations.horizontal.indexOf(side) >= 0) {
elStyling['width'] = elementStyling.getPropertyValue('padding-' + side)
elStyling['height'] = innerHeight + 'px'
elStyling['top'] = 0
if (borderBox) {
elStyling['height'] = innerHeight - parseFloat(realElBorder.top) - parseFloat(realElBorder.bottom) + 'px'
}
} else {
elStyling['height'] = elementStyling.getPropertyValue('padding-' + side)
elStyling['width'] = innerWidth + 'px'
elStyling['left'] = 0
if (borderBox) {
elStyling['width'] = innerWidth - parseFloat(realElBorder.left) - parseFloat(realElBorder.right) + 'px'
}
}
elStyling[side] = 0
elStyling['position'] = 'absolute'
return elStyling
}
const drawMarginRect = function (side) {
const elStyling = {}
const margin = []
margin['right'] = parseFloat(elementStyling.getPropertyValue('margin-right'))
margin['top'] = parseFloat(elementStyling.getPropertyValue('margin-top'))
margin['bottom'] = parseFloat(elementStyling.getPropertyValue('margin-bottom'))
margin['left'] = parseFloat(elementStyling.getPropertyValue('margin-left'))
if (visualizations['horizontal'].indexOf(side) >= 0) {
elStyling['width'] = elementStyling.getPropertyValue('margin-' + side)
elStyling['height'] = outerHeight + margin['top'] + margin['bottom'] + 'px'
elStyling['top'] = '-' + (margin['top'] + parseFloat(realElBorder.top)) + 'px'
} else {
elStyling['height'] = elementStyling.getPropertyValue('margin-' + side)
elStyling['width'] = outerWidth + 'px'
elStyling['left'] = '-' + realElBorder.left
}
elStyling[side] = '-' + (margin[side] + parseFloat(realElBorder[side])) + 'px'
elStyling['position'] = 'absolute'
return elStyling
}
const setVisibility = function (el) {
if (!config.remoteHighlight.showPaddingMargin || parseInt(el.height, 10) <= 0 || parseInt(el.width, 10) <= 0) {
el.display = 'none'
} else {
el.display = 'block'
}
}
const paddingVisualizations = [
drawPaddingRect('top'),
drawPaddingRect('right'),
drawPaddingRect('bottom'),
drawPaddingRect('left')
]
const marginVisualizations = [
drawMarginRect('top'),
drawMarginRect('right'),
drawMarginRect('bottom'),
drawMarginRect('left')
]
const setupVisualizations = function (arr, config) {
let i
for (i = 0; i < arr.length; i++) {
setVisibility(arr[i])
// Applies to every visualisationElement (padding or margin div)
arr[i]['transform'] = 'none'
const el = window.document.createElement('div'),
styles = Object.assign({}, config, arr[i])
_setStyleValues(styles, el.style)
highlight.appendChild(el)
}
}
setupVisualizations(marginVisualizations, config.remoteHighlight.marginStyling)
setupVisualizations(paddingVisualizations, config.remoteHighlight.paddingStyling)
highlight.className = HIGHLIGHT_CLASS_NAME
const offset = _screenOffset(element)
let el = element,
offsetLeft = 0,
offsetTop = 0
// Probably the easiest way to get elements position without including transform
do {
offsetLeft += el.offsetLeft
offsetTop += el.offsetTop
el = el.offsetParent
} while (el)
const stylesToSet = {
left: offsetLeft + 'px',
top: offsetTop + 'px',
width: innerWidth + 'px',
height: innerHeight + 'px',
'z-index': 2000000,
margin: 0,
padding: 0,
position: 'absolute',
'pointer-events': 'none',
'box-shadow': '0 0 1px #fff',
'box-sizing': elementStyling.getPropertyValue('box-sizing'),
'border-right': elementStyling.getPropertyValue('border-right'),
'border-left': elementStyling.getPropertyValue('border-left'),
'border-top': elementStyling.getPropertyValue('border-top'),
'border-bottom': elementStyling.getPropertyValue('border-bottom'),
transform: elementStyling.getPropertyValue('transform'),
'transform-origin': elementStyling.getPropertyValue('transform-origin'),
'border-color': config.remoteHighlight.borderColor
}
const mergedStyles = Object.assign({}, stylesToSet)
const animateStartValues = config.remoteHighlight.animateStartValue
const animateEndValues = config.remoteHighlight.animateEndValue
const transitionValues = {
'transition-property': 'opacity, background-color, transform',
'transition-duration': '300ms, 2.3s'
}
function _setStyleValues(styleValues, obj) {
let prop
for (prop in styleValues) {
obj.setProperty(prop, styleValues[prop])
}
}
_setStyleValues(mergedStyles, highlight.style)
_setStyleValues(doAnimation ? animateStartValues : animateEndValues, highlight.style)
if (doAnimation) {
_setStyleValues(transitionValues, highlight.style)
window.setTimeout(function () {
_setStyleValues(animateEndValues, highlight.style)
}, 20)
}
window.document.body.appendChild(highlight)
}
add(element, doAnimation) {
if (this.elementExists(element) || element === window.document) {
return
}
if (this.trigger) {
_trigger(element, 'highlight', 1)
}
if ((!window.event || window.event instanceof MessageEvent) && !isInViewport(element)) {
let top = getDocumentOffsetTop(element)
if (top) {
top -= window.innerHeight / 2
window.scrollTo(0, top)
}
}
this.elements.push(element)
this.makeHighlightDiv(element, doAnimation)
}
clear() {
let i
const highlights = window.document.querySelectorAll('.' + HIGHLIGHT_CLASS_NAME),
body = window.document.body
for (i = 0; i < highlights.length; i++) {
body.removeChild(highlights[i])
}
if (this.trigger) {
for (i = 0; i < this.elements.length; i++) {
_trigger(this.elements[i], 'highlight', 0)
}
}
this.elements = []
}
redraw() {
let i, highlighted
// When redrawing a selector-based highlight, run a new selector
// query to ensure we have the latest set of elements to highlight.
if (this.selector) {
highlighted = window.document.querySelectorAll(this.selector)
} else {
highlighted = this.elements.slice(0)
}
this.clear()
for (i = 0; i < highlighted.length; i++) {
this.add(highlighted[i], false)
}
}
}