DomUtils.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. Copyright (C) 2017 Cloudbase Solutions SRL
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. // @flow
  15. class DomUtils {
  16. static getScrollableParent(element: HTMLElement, includeHidden?: boolean): HTMLElement {
  17. let style = getComputedStyle(element)
  18. let excludeStaticParent = style.position === 'absolute'
  19. let overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/
  20. if (style.position === 'fixed') {
  21. return window
  22. }
  23. /* eslint no-cond-assign: off */
  24. for (let parent = element; (parent = parent.parentElement);) {
  25. style = getComputedStyle(parent)
  26. if (excludeStaticParent && style.position === 'static') {
  27. /* eslint no-continue: off */
  28. continue
  29. }
  30. if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) {
  31. let htmlEl: any = parent
  32. return htmlEl
  33. }
  34. }
  35. return window
  36. }
  37. static isElementInViewport(el: HTMLElement, scrollableParent: any): boolean {
  38. let rect = el.getBoundingClientRect()
  39. let scrollableRect = scrollableParent.getBoundingClientRect ? scrollableParent.getBoundingClientRect() : {
  40. top: 0,
  41. left: 0,
  42. bottom: scrollableParent.innerHeight ? scrollableParent.innerHeight : window.innerHeight,
  43. right: scrollableParent.innerWidth ? scrollableParent.innerWidth : window.innerWidth,
  44. }
  45. return (
  46. rect.top + rect.height >= scrollableRect.top &&
  47. rect.left >= scrollableRect.left &&
  48. rect.bottom - rect.height <= scrollableRect.bottom &&
  49. rect.right <= scrollableRect.right
  50. )
  51. }
  52. static getEventPath(event: Event): HTMLElement[] {
  53. let path = []
  54. let node = event.target
  55. // $FlowIgnore
  56. while (node !== document.body && node.parentNode) {
  57. path.push(node)
  58. // $FlowIgnore
  59. node = node.parentNode
  60. }
  61. // $FlowIgnore
  62. return path
  63. }
  64. /**
  65. * Copies specified text to clipboard
  66. * @param {string} text The text to copy
  67. * @return True if successful, false otherwise
  68. */
  69. static copyTextToClipboard(text: string): boolean {
  70. let textArea = document.createElement('textarea')
  71. textArea.style.position = 'fixed'
  72. textArea.style.top = '0'
  73. textArea.style.left = '0'
  74. textArea.style.width = '2em'
  75. textArea.style.height = '2em'
  76. textArea.style.padding = '0'
  77. textArea.style.border = 'none'
  78. textArea.style.outline = 'none'
  79. textArea.style.boxShadow = 'none'
  80. textArea.style.background = 'transparent'
  81. textArea.value = text
  82. if (document.body) document.body.appendChild(textArea)
  83. textArea.select()
  84. let successful
  85. try {
  86. successful = document.execCommand('copy')
  87. } catch (e) {
  88. successful = false
  89. } finally {
  90. if (document.body) document.body.removeChild(textArea)
  91. }
  92. return successful
  93. }
  94. static get urlHashPrefix() {
  95. return window.env.ENV === 'development' ? '#/' : ''
  96. }
  97. static download(text: string, fileName: string) {
  98. let href: string = `data:text/json;charset=utf-8,${encodeURIComponent(text)}`
  99. let downloadAnchorNode = document.createElement('a')
  100. downloadAnchorNode.setAttribute('href', href)
  101. downloadAnchorNode.setAttribute('download', fileName)
  102. if (document.body) {
  103. document.body.appendChild(downloadAnchorNode) // required for firefox
  104. }
  105. downloadAnchorNode.click()
  106. downloadAnchorNode.remove()
  107. }
  108. static jsonSyntaxHighlight(json: any) {
  109. json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
  110. return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g, (match) => {
  111. let cls = 'number'
  112. if (/^"/.test(match)) {
  113. if (/:$/.test(match)) {
  114. cls = 'key'
  115. } else {
  116. cls = 'string'
  117. }
  118. } else if (/true|false/.test(match)) {
  119. cls = 'boolean'
  120. } else if (/null/.test(match)) {
  121. cls = 'null'
  122. }
  123. return `<span class="${cls}">${match}</span>`
  124. })
  125. }
  126. }
  127. export default DomUtils