Skip to content

Select component from dom tree #476

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Jan 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion shells/dev/target/Other.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default {
},
components: {
mine: {
render: h => h('div', null, 'mine'),
render: h => h('div', { class: 'mine' }, 'mine'),
data () {
return {
// testing all data types
Expand All @@ -50,3 +50,8 @@ export default {
}
}
</script>

<style lang="stylus">
.mine
display inline-block
</style>
41 changes: 36 additions & 5 deletions shells/dev/target/Target.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@
<input @keyup.enter="regex = new RegExp($event.target.value)"/>
<span>(Press enter to set)</span>
<br/>
<button class="add" @click="add">Add</button>
<button class="remove" @click="rm">Remove</button>
<button class="add" @mouseup="add">Add</button>
<button class="remove" @mousedown="rm">Remove</button>
<input v-model="localMsg">
<other v-for="item in items" :key="item" :id="item"></other>
<button @click="inspect">Inspect component</button>
<div>
<button
class="inspect"
@click="inspect"
@mouseover="over = true"
@mouseout="over = false"
>Inspect component</button>
<span v-if="over" class="over">Mouse over</span>
</div>
</div>
</template>

Expand All @@ -30,7 +38,8 @@ export default {
regex: /(a\w+b)/g,
nan: NaN,
infinity: Infinity,
negativeInfinity: -Infinity
negativeInfinity: -Infinity,
over: false
}
},
computed: {
Expand All @@ -46,7 +55,12 @@ export default {
},
methods: {
add () {
this.items.push(1, 2, 3)
const l = this.items.length
this.items.push(
l + 1,
l + 2,
l + 3
)
},
rm () {
this.items.pop()
Expand All @@ -57,3 +71,20 @@ export default {
}
}
</script>

<style lang="stylus" scoped>
.inspect
border solid 1px black
background #eee
color black
border-radius 2px
padding 6px 12px
cursor pointer
&:hover
border-color blue
color blue

.over
pointer-events none
margin-left 12px
</style>
93 changes: 93 additions & 0 deletions src/backend/component-selector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { highlight, unHighlight } from './highlighter'
import { findRelatedComponent } from './utils'

export default class ComponentSelector {
constructor (bridge, instanceMap) {
const self = this
self.bridge = bridge
self.instanceMap = instanceMap
self.bindMethods()

bridge.on('start-component-selector', self.startSelecting)
bridge.on('stop-component-selector', self.stopSelecting)
}

/**
* Adds event listeners for mouseover and mouseup
*/
startSelecting () {
document.body.addEventListener('mouseover', this.elementMouseOver, true)
document.body.addEventListener('click', this.elementClicked, true)
document.body.addEventListener('mouseout', this.cancelEvent, true)
document.body.addEventListener('mouseenter', this.cancelEvent, true)
document.body.addEventListener('mouseleave', this.cancelEvent, true)
document.body.addEventListener('mousedown', this.cancelEvent, true)
document.body.addEventListener('mouseup', this.cancelEvent, true)
}

/**
* Removes event listeners
*/
stopSelecting () {
document.body.removeEventListener('mouseover', this.elementMouseOver, true)
document.body.removeEventListener('click', this.elementClicked, true)
document.body.removeEventListener('mouseout', this.cancelEvent, true)
document.body.removeEventListener('mouseenter', this.cancelEvent, true)
document.body.removeEventListener('mouseleave', this.cancelEvent, true)
document.body.removeEventListener('mousedown', this.cancelEvent, true)
document.body.removeEventListener('mouseup', this.cancelEvent, true)

unHighlight()
}

/**
* Highlights a component on element mouse over
* @param {MouseEvent} e
*/
elementMouseOver (e) {
this.cancelEvent(e)

const el = e.target
if (el) {
this.selectedInstance = findRelatedComponent(el)
}

unHighlight()
if (this.selectedInstance) {
highlight(this.selectedInstance)
}
}

/**
* Selects an instance in the component view
* @param {MouseEvent} e
*/
elementClicked (e) {
this.cancelEvent(e)

if (this.selectedInstance) {
this.bridge.send('inspect-instance', this.selectedInstance.__VUE_DEVTOOLS_UID__)
}

this.stopSelecting()
}

/**
* Cancel a mouse event
* @param {MouseEvent} e
*/
cancelEvent (e) {
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)
}
}
23 changes: 21 additions & 2 deletions src/backend/highlighter.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import { inDoc } from '../util'
import { getInstanceName } from './index'

const overlay = document.createElement('div')
overlay.style.backgroundColor = 'rgba(104, 182, 255, 0.35)'
overlay.style.position = 'fixed'
overlay.style.zIndex = '99999999999999'
overlay.style.pointerEvents = 'none'
overlay.style.display = 'flex'
overlay.style.alignItems = 'center'
overlay.style.justifyContent = 'center'
overlay.style.borderRadius = '3px'
const overlayContent = document.createElement('div')
overlayContent.style.backgroundColor = 'rgba(104, 182, 255, 0.9)'
overlayContent.style.fontFamily = 'monospace'
overlayContent.style.fontSize = '11px'
overlayContent.style.padding = '2px 3px'
overlayContent.style.borderRadius = '3px'
overlayContent.style.color = 'white'
overlay.appendChild(overlayContent)

/**
* Highlight an instance.
Expand All @@ -16,7 +29,10 @@ export function highlight (instance) {
if (!instance) return
const rect = getInstanceRect(instance)
if (rect) {
showOverlay(rect)
let content = ''
const name = getInstanceName(instance)
name && (content = `<span style="opacity: .6;">&lt;</span>${name}<span style="opacity: .6;">&gt;</span>`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would replace this with

if (name) {
	content = ...
	showOverlay(...)
}

since it doesn't look like it's displaying anything otherwise

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can still show the component boundaries even if the component doesn't have a name (most certainly using an old version of vue-loader or vue).

showOverlay(rect, content)
}
}

Expand Down Expand Up @@ -107,11 +123,14 @@ function getTextRect (node) {
* @param {Rect}
*/

function showOverlay ({ width = 0, height = 0, top = 0, left = 0 }) {
function showOverlay ({ width = 0, height = 0, top = 0, left = 0 }, content = '') {
overlay.style.width = ~~width + 'px'
overlay.style.height = ~~height + 'px'
overlay.style.top = ~~top + 'px'
overlay.style.left = ~~left + 'px'

overlayContent.innerHTML = content

document.body.appendChild(overlay)
}

Expand Down
9 changes: 4 additions & 5 deletions src/backend/hook.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { findRelatedComponent } from './utils'

// this script is injected into every page.

/**
Expand Down Expand Up @@ -87,13 +89,10 @@ export function installHook (window) {
// Start recording context menu when Vue is detected
// event if Vue devtools are not loaded yet
document.addEventListener('contextmenu', event => {
let el = event.target
const el = event.target
if (el) {
// Search for parent that "is" a component instance
while (!el.__vue__ && el.parentElement) {
el = el.parentElement
}
const instance = el.__vue__
const instance = findRelatedComponent(el)
if (instance) {
window.__VUE_DEVTOOLS_CONTEXT_MENU_HAS_TARGET__ = true
window.__VUE_DEVTOOLS_CONTEXT_MENU_TARGET__ = instance
Expand Down
3 changes: 3 additions & 0 deletions src/backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { initVuexBackend } from './vuex'
import { initEventsBackend } from './events'
import { stringify, classify, camelize, set, parse } from '../util'
import path from 'path'
import ComponentSelector from './component-selector'

// Use a custom basename functions instead of the shimed version
// because it doesn't work on Windows
Expand Down Expand Up @@ -83,6 +84,8 @@ function connect () {

bridge.on('leave-instance', unHighlight)

new ComponentSelector(bridge, instanceMap)

// Get the instance id that is targeted by context menu
bridge.on('get-context-menu-target', () => {
const instance = window.__VUE_DEVTOOLS_CONTEXT_MENU_TARGET__
Expand Down
6 changes: 6 additions & 0 deletions src/backend/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export function findRelatedComponent (el) {
while (!el.__vue__ && el.parentElement) {
el = el.parentElement
}
return el.__vue__
}
2 changes: 0 additions & 2 deletions src/devtools/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,6 @@ export default {
background-color $background-color
display flex
flex-direction column
h1
color #42b983
.dark &
background-color $dark-background-color

Expand Down
4 changes: 3 additions & 1 deletion src/devtools/components/ActionHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@
display inline

.material-icons
font-size 18px
font-size 16px
margin-right 0
position relative
top 1px
color inherit
@media (min-width: $wide)
margin-right 5px
Expand Down
4 changes: 4 additions & 0 deletions src/devtools/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ function initApp (shell) {
store.commit('components/RECEIVE_INSTANCE_DETAILS', parse(details))
})

bridge.on('toggle-instance', payload => {
store.commit('components/TOGGLE_INSTANCE', parse(payload))
})

bridge.on('vuex:init', snapshot => {
store.commit('vuex/INIT', snapshot)
})
Expand Down
23 changes: 10 additions & 13 deletions src/devtools/mixins/key-nav.js → src/devtools/mixins/keyboard.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
const navMap = {
37: 'left',
38: 'up',
39: 'right',
40: 'down'
}
export const LEFT = 37
export const UP = 38
export const RIGHT = 39
export const DOWN = 40
export const S = 83
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you also type in Dvorak? 😆
Using Keycodes doesn't work across keyboards for letters

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? I just tried in Dvorak to be sure and it's working fine... 😕

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're completely right. I had recently a problem with keycodes but it's something a bit different, it only happens with the digits row


const activeInstances = []

document.addEventListener('keyup', e => {
if (e.target.tagName === 'INPUT') {
return
}
if (navMap[e.keyCode]) {
activeInstances.forEach(vm => {
if (vm.onKeyNav) {
vm.onKeyNav(navMap[e.keyCode])
}
})
}
activeInstances.forEach(vm => {
if (vm.onKeyUp) {
vm.onKeyUp(e)
}
})
})

export default {
Expand Down
8 changes: 8 additions & 0 deletions src/devtools/transitions.styl
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,11 @@
transform rotate(0deg)
100%
transform rotate(360deg)

@keyframes pulse
0%
opacity 1
50%
opacity .2
100%
opacity 1
4 changes: 2 additions & 2 deletions src/devtools/variables.styl
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ $orange = #DB6B00
$black = #000000

// The min-width to give icons text...
$wide = 820px
$wide = 1050px

// The min-height to give the tools a little more breathing room...
$tall = 300px
$tall = 350px

// Theme
$active-color = $darkerGreen
Expand Down
Loading