/*
Copyright (C) 2017 Cloudbase Solutions SRL
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
// @flow
class DomUtils {
static getScrollableParent(element: HTMLElement, includeHidden?: boolean): HTMLElement {
let style = getComputedStyle(element)
let excludeStaticParent = style.position === 'absolute'
let overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/
if (style.position === 'fixed') {
return window
}
/* eslint no-cond-assign: off */
for (let parent = element; (parent = parent.parentElement);) {
style = getComputedStyle(parent)
if (excludeStaticParent && style.position === 'static') {
/* eslint no-continue: off */
continue
}
if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) {
let htmlEl: any = parent
return htmlEl
}
}
return window
}
static isElementInViewport(el: HTMLElement, scrollableParent: any): boolean {
let rect = el.getBoundingClientRect()
let scrollableRect = scrollableParent.getBoundingClientRect ? scrollableParent.getBoundingClientRect() : {
top: 0,
left: 0,
bottom: scrollableParent.innerHeight ? scrollableParent.innerHeight : window.innerHeight,
right: scrollableParent.innerWidth ? scrollableParent.innerWidth : window.innerWidth,
}
return (
rect.top + rect.height >= scrollableRect.top &&
rect.left >= scrollableRect.left &&
rect.bottom - rect.height <= scrollableRect.bottom &&
rect.right <= scrollableRect.right
)
}
static getEventPath(event: Event): HTMLElement[] {
let path = []
let node = event.target
// $FlowIgnore
while (node !== document.body && node.parentNode) {
path.push(node)
// $FlowIgnore
node = node.parentNode
}
// $FlowIgnore
return path
}
/**
* Copies specified text to clipboard
* @param {string} text The text to copy
* @return True if successful, false otherwise
*/
static copyTextToClipboard(text: string): boolean {
let textArea = document.createElement('textarea')
textArea.style.position = 'fixed'
textArea.style.top = '0'
textArea.style.left = '0'
textArea.style.width = '2em'
textArea.style.height = '2em'
textArea.style.padding = '0'
textArea.style.border = 'none'
textArea.style.outline = 'none'
textArea.style.boxShadow = 'none'
textArea.style.background = 'transparent'
textArea.value = text
if (document.body) document.body.appendChild(textArea)
textArea.select()
let successful
try {
successful = document.execCommand('copy')
} catch (e) {
successful = false
} finally {
if (document.body) document.body.removeChild(textArea)
}
return successful
}
static get urlHashPrefix() {
return window.env.ENV === 'development' ? '#/' : ''
}
static download(text: string, fileName: string) {
let href: string = `data:text/json;charset=utf-8,${encodeURIComponent(text)}`
let downloadAnchorNode = document.createElement('a')
downloadAnchorNode.setAttribute('href', href)
downloadAnchorNode.setAttribute('download', fileName)
if (document.body) {
document.body.appendChild(downloadAnchorNode) // required for firefox
}
downloadAnchorNode.click()
downloadAnchorNode.remove()
}
static jsonSyntaxHighlight(json: any) {
json = json.replace(/&/g, '&').replace(//g, '>')
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g, (match) => {
let cls = 'number'
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'key'
} else {
cls = 'string'
}
} else if (/true|false/.test(match)) {
cls = 'boolean'
} else if (/null/.test(match)) {
cls = 'null'
}
return `${match}`
})
}
}
export default DomUtils