File size: 3,456 Bytes
4d70170 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
import { BridgeEvents, isBrowser } from '@vue-devtools/shared-utils'
import type { BackendContext, DevtoolsBackend } from '@vue-devtools/app-backend-api'
import type { ComponentInstance } from '@vue/devtools-api'
import { highlight, unHighlight } from './highlighter'
export default class ComponentPicker {
ctx: BackendContext
selectedInstance: ComponentInstance
selectedBackend: DevtoolsBackend
constructor(ctx: BackendContext) {
this.ctx = ctx
this.bindMethods()
}
/**
* Adds event listeners for mouseover and mouseup
*/
startSelecting() {
if (!isBrowser) {
return
}
window.addEventListener('mouseover', this.elementMouseOver, true)
window.addEventListener('click', this.elementClicked, true)
window.addEventListener('mouseout', this.cancelEvent, true)
window.addEventListener('mouseenter', this.cancelEvent, true)
window.addEventListener('mouseleave', this.cancelEvent, true)
window.addEventListener('mousedown', this.cancelEvent, true)
window.addEventListener('mouseup', this.cancelEvent, true)
}
/**
* Removes event listeners
*/
stopSelecting() {
if (!isBrowser) {
return
}
window.removeEventListener('mouseover', this.elementMouseOver, true)
window.removeEventListener('click', this.elementClicked, true)
window.removeEventListener('mouseout', this.cancelEvent, true)
window.removeEventListener('mouseenter', this.cancelEvent, true)
window.removeEventListener('mouseleave', this.cancelEvent, true)
window.removeEventListener('mousedown', this.cancelEvent, true)
window.removeEventListener('mouseup', this.cancelEvent, true)
unHighlight()
}
/**
* Highlights a component on element mouse over
*/
async elementMouseOver(e: MouseEvent) {
this.cancelEvent(e)
const el = e.target
if (el) {
await this.selectElementComponent(el)
}
unHighlight()
if (this.selectedInstance) {
highlight(this.selectedInstance, this.selectedBackend, this.ctx)
}
}
async selectElementComponent(el) {
for (const backend of this.ctx.backends) {
const instance = await backend.api.getElementComponent(el)
if (instance) {
this.selectedInstance = instance
this.selectedBackend = backend
return
}
}
this.selectedInstance = null
this.selectedBackend = null
}
/**
* Selects an instance in the component view
*/
async elementClicked(e: MouseEvent) {
this.cancelEvent(e)
if (this.selectedInstance && this.selectedBackend) {
const parentInstances = await this.selectedBackend.api.walkComponentParents(this.selectedInstance)
this.ctx.bridge.send(BridgeEvents.TO_FRONT_COMPONENT_PICK, { id: this.selectedInstance.__VUE_DEVTOOLS_UID__, parentIds: parentInstances.map(i => i.__VUE_DEVTOOLS_UID__) })
}
else {
this.ctx.bridge.send(BridgeEvents.TO_FRONT_COMPONENT_PICK_CANCELED, null)
}
this.stopSelecting()
}
/**
* Cancel a mouse event
*/
cancelEvent(e: MouseEvent) {
e.stopImmediatePropagation()
e.preventDefault()
}
/**
* Bind class methods to the class scope to avoid rebind for event listeners
*/
bindMethods() {
this.startSelecting = this.startSelecting.bind(this)
this.stopSelecting = this.stopSelecting.bind(this)
this.elementMouseOver = this.elementMouseOver.bind(this)
this.elementClicked = this.elementClicked.bind(this)
}
}
|