|
import { inDoc, isBrowser } from '@vue-devtools/shared-utils' |
|
import { isFragment } from './util' |
|
|
|
export function getComponentInstanceFromElement(element) { |
|
return element.__vueParentComponent |
|
} |
|
|
|
export function getRootElementsFromComponentInstance(instance) { |
|
if (isFragment(instance)) { |
|
return getFragmentRootElements(instance.subTree) |
|
} |
|
if (!instance.subTree) { |
|
return [] |
|
} |
|
return [instance.subTree.el] |
|
} |
|
|
|
function getFragmentRootElements(vnode): any[] { |
|
if (!vnode.children) { |
|
return [] |
|
} |
|
|
|
const list = [] |
|
|
|
for (let i = 0, l = vnode.children.length; i < l; i++) { |
|
const childVnode = vnode.children[i] |
|
if (childVnode.component) { |
|
list.push(...getRootElementsFromComponentInstance(childVnode.component)) |
|
} |
|
else if (childVnode.el) { |
|
list.push(childVnode.el) |
|
} |
|
} |
|
|
|
return list |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function getInstanceOrVnodeRect(instance) { |
|
const el = instance.subTree.el |
|
|
|
if (!isBrowser) { |
|
|
|
return |
|
} |
|
if (!inDoc(el)) { |
|
return |
|
} |
|
|
|
if (isFragment(instance)) { |
|
return addIframePosition(getFragmentRect(instance.subTree), getElWindow(el)) |
|
} |
|
else if (el.nodeType === 1) { |
|
return addIframePosition(el.getBoundingClientRect(), getElWindow(el)) |
|
} |
|
else if (instance.subTree.component) { |
|
return getInstanceOrVnodeRect(instance.subTree.component) |
|
} |
|
} |
|
|
|
function createRect() { |
|
const rect = { |
|
top: 0, |
|
bottom: 0, |
|
left: 0, |
|
right: 0, |
|
get width() { return rect.right - rect.left }, |
|
get height() { return rect.bottom - rect.top }, |
|
} |
|
return rect |
|
} |
|
|
|
function mergeRects(a, b) { |
|
if (!a.top || b.top < a.top) { |
|
a.top = b.top |
|
} |
|
if (!a.bottom || b.bottom > a.bottom) { |
|
a.bottom = b.bottom |
|
} |
|
if (!a.left || b.left < a.left) { |
|
a.left = b.left |
|
} |
|
if (!a.right || b.right > a.right) { |
|
a.right = b.right |
|
} |
|
return a |
|
} |
|
|
|
let range |
|
|
|
|
|
|
|
|
|
|
|
|
|
function getTextRect(node) { |
|
if (!isBrowser) { |
|
return |
|
} |
|
if (!range) { |
|
range = document.createRange() |
|
} |
|
|
|
range.selectNode(node) |
|
|
|
return range.getBoundingClientRect() |
|
} |
|
|
|
function getFragmentRect(vnode) { |
|
const rect = createRect() |
|
if (!vnode.children) { |
|
return rect |
|
} |
|
|
|
for (let i = 0, l = vnode.children.length; i < l; i++) { |
|
const childVnode = vnode.children[i] |
|
let childRect |
|
if (childVnode.component) { |
|
childRect = getInstanceOrVnodeRect(childVnode.component) |
|
} |
|
else if (childVnode.el) { |
|
const el = childVnode.el |
|
if (el.nodeType === 1 || el.getBoundingClientRect) { |
|
childRect = el.getBoundingClientRect() |
|
} |
|
else if (el.nodeType === 3 && el.data.trim()) { |
|
childRect = getTextRect(el) |
|
} |
|
} |
|
if (childRect) { |
|
mergeRects(rect, childRect) |
|
} |
|
} |
|
|
|
return rect |
|
} |
|
|
|
function getElWindow(el: HTMLElement) { |
|
return el.ownerDocument.defaultView |
|
} |
|
|
|
function addIframePosition(bounds, win: any) { |
|
if (win.__VUE_DEVTOOLS_IFRAME__) { |
|
const rect = mergeRects(createRect(), bounds) |
|
const iframeBounds = win.__VUE_DEVTOOLS_IFRAME__.getBoundingClientRect() |
|
rect.top += iframeBounds.top |
|
rect.bottom += iframeBounds.top |
|
rect.left += iframeBounds.left |
|
rect.right += iframeBounds.left |
|
if (win.parent) { |
|
return addIframePosition(rect, win.parent) |
|
} |
|
return rect |
|
} |
|
return bounds |
|
} |
|
|