Skip to content

Commit

Permalink
Add check for 'HTMLElement' type (#80)
Browse files Browse the repository at this point in the history
* wip

* wip

* Apply formatting changes

* remove console log

* fix trailing comma setting

* Apply formatting changes

* bring back 'function' replacement

* simplify setting of single data field

* add function/HTMLElement test

* Apply formatting changes

* remove .only

Co-authored-by: KevinBatdorf <[email protected]>
Co-authored-by: Hugo Di Francesco <[email protected]>
  • Loading branch information
3 people authored Dec 2, 2020
1 parent 34b33dd commit 0ce5fff
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 38 deletions.
1 change: 1 addition & 0 deletions .prettierrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ module.exports = {
printWidth: 120,
singleQuote: true,
tabWidth: 4,
trailingComma: 'all',
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,52 @@ it('should add/remove hover overlay on component mouseenter/leave', () => {
})
cy.iframe('#target').find('[data-testid=hover-element]').should('not.exist')
})

it('should allow display read-only function/HTMLElement attributes', () => {
cy.visit('/')

cy.get('[data-testid=component-container]').first().should('be.visible').click()

cy.get('[data-testid=data-property-name]')
.should('be.visible')
.contains('myFunction')
.siblings('[data-testid=data-property-value-container]')
.should('contain.text', 'function')

cy.get('[data-testid=data-property-name]')
.contains('el')
.siblings('[data-testid=data-property-value-container]')
.should('contain.text', 'HTMLElement')
.as('elValue')
.click()

// check nested attributes
cy.get('[data-testid=data-property-name]')
.contains('name')
.as('elName')
.should('be.visible')
.siblings('[data-testid=data-property-value-container]')
.should('contain.text', 'div')
cy.get('[data-testid=data-property-name]')
.contains('attributes')
.as('elAttributes')
.should('be.visible')
.siblings('[data-testid=data-property-value-container]')
.should('contain.text', 'Array[1]')
cy.get('[data-testid=data-property-name]')
.contains('children')
.as('elChildren')
.should('be.visible')
.siblings('[data-testid=data-property-value-container]')
.should('contain.text', 'Array[5]')

// check they toggle off
cy.get('@elValue').click()

cy.get('@elName')
.should('not.be.visible')
.get('@elAttributes')
.should('not.be.visible')
.get('@elChildren')
.should('not.be.visible')
})
17 changes: 8 additions & 9 deletions packages/shell-chrome/assets/panel.html
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,9 @@ <h5 class="flex items-center px-2 leading-7 font-mono">
<a
:style="`margin-left: ${singleData.depth}px; `"
@click="alpineState.toggleDataAttribute(singleData)"
class="block px-1 rounded"
class="block px-1 rounded hover:bg-blue-100"
:class="{
'hover:bg-blue-100 cursor-pointer': !singleData.readOnly
'cursor-pointer': singleData.hasArrow
}"
x-show="singleData.isOpened"
>
Expand Down Expand Up @@ -302,12 +302,15 @@ <h5 class="flex items-center px-2 leading-7 font-mono">

<span class="text-black">:</span>

<div class="text-black ml-1" x-show="!singleData.inEditingMode">
<div
data-testid="data-property-value-container"
class="text-black ml-1"
x-show="!singleData.inEditingMode"
>
<template x-if="singleData.dataType == 'string'">
&quot;<span
class="text-red-700"
x-text="singleData.attributeValue"
data-testid="data-property-value"
></span
>&quot;
</template>
Expand All @@ -316,17 +319,13 @@ <h5 class="flex items-center px-2 leading-7 font-mono">
<span
class="text-blue-700"
x-text="singleData.attributeValue"
data-testid="data-property-value"
></span>
</template>

<template
x-if="['string', 'boolean'].includes(singleData.dataType) === false"
>
<span
x-text="singleData.attributeValue"
data-testid="data-property-value"
></span>
<span x-text="singleData.attributeValue"></span>
</template>
</div>
</h5>
Expand Down
27 changes: 11 additions & 16 deletions packages/shell-chrome/src/backend.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getComponentName, set, waitForAlpine } from './utils'
import { getComponentName, serializeHTMLElement, set, waitForAlpine } from './utils'

window.addEventListener('message', handshake)
window.__alpineDevtool = {}
Expand Down Expand Up @@ -76,17 +76,8 @@ function handleMessages(e) {
if (e.data.payload.action == 'editAttribute') {
Alpine.discoverComponents((component) => {
if (component.__alpineDevtool.id == e.data.payload.componentId) {
const data = component.__x.getUnobservedData()
const { attributeSequence, attributeValue } = e.data.payload

// nested path descriptor, eg. array.0.property needs to update array[0].property
if (attributeSequence.includes('.')) {
set(data, attributeSequence, attributeValue)
} else {
data[attributeSequence] = attributeValue
}

component.__x.$el.setAttribute('x-data', JSON.stringify(data))
set(component.__x.$data, attributeSequence, attributeValue)
}
setTimeout(() => {
window.__alpineDevtool.stopMutationObserver = false
Expand Down Expand Up @@ -127,10 +118,14 @@ function discoverComponents(isThroughMutation = false) {
}

const data = Object.entries(rootEl.__x.getUnobservedData()).reduce((acc, [key, value]) => {
const type = typeof value
acc[key] = {
value: type === 'function' ? 'function' : value,
type,
value:
value instanceof HTMLElement
? serializeHTMLElement(value)
: typeof value === 'function'
? 'function'
: value,
type: value instanceof HTMLElement ? 'HTMLElement' : typeof value,
}
return acc
}, {})
Expand Down Expand Up @@ -158,7 +153,7 @@ function discoverComponents(isThroughMutation = false) {
isThroughMutation: isThroughMutation,
},
},
'*'
'*',
)
}

Expand All @@ -171,7 +166,7 @@ function getAlpineVersion() {
type: 'set-version',
},
},
'*'
'*',
)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/shell-chrome/src/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function installProxy(tabId) {
} else {
console.log('injected proxy to tab ' + tabId)
}
}
},
)
}

Expand Down
4 changes: 1 addition & 3 deletions packages/shell-chrome/src/devtools/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ export default class State {
}

toggleDataAttribute(attribute) {
// don't toggle anything if the attribute is read-only
if (attribute.readOnly) return
if (attribute.hasArrow) {
let childrenIdLength = attribute.id.split('.').length + 1

Expand Down Expand Up @@ -163,7 +161,7 @@ export default class State {
if (this._hasNoDevtools('saveEditing')) return
clickedAttribute.attributeValue = convertInputDataToType(
clickedAttribute.inputType,
clickedAttribute.editAttributeValue
clickedAttribute.editAttributeValue,
)
clickedAttribute.inEditingMode = false

Expand Down
2 changes: 1 addition & 1 deletion packages/shell-chrome/src/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function proxy() {
source: 'alpine-devtools-proxy',
payload: payload,
},
'*'
'*',
)
}

Expand Down
40 changes: 35 additions & 5 deletions packages/shell-chrome/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,24 +87,52 @@ export function convertInputDataToType(inputType, value) {
}
}

function getAttributeValue(value, type) {
const overrides = {
function: 'function',
HTMLElement: 'HTMLElement',
}
if (overrides[type]) return overrides[type]
if (Array.isArray(value)) return `Array[${value.length}]`
if (value instanceof Object) return 'Object'
return value
}

// Thank you! https://stackoverflow.com/a/54273003/1437789
export function serializeHTMLElement(element) {
let object = {}
object.name = element.localName
object.attributes = []
object.children = []
Array.from(element.attributes).forEach((attribute) => {
object.attributes.push({ name: attribute.name, value: attribute.value })
})
Array.from(element.children).forEach((child) => {
object.children.push(serializeHTMLElement(child))
})

return object
}

export function flattenSingleAttribute(
flattenedData,
attributeName,
value,
type,
margin = 0,
id = '',
directParentId = ''
directParentId = '',
readOnlyChildren = type === 'HTMLElement',
) {
const generatedId = id ? id : attributeName

flattenedData.push({
attributeName: attributeName,
attributeValue: Array.isArray(value) ? `Array[${value.length}]` : value instanceof Object ? 'Object' : value,
attributeValue: getAttributeValue(value, type),
editAttributeValue: Array.isArray(value) ? 'Array' : value instanceof Object ? 'Object' : value,
depth: margin,
hasArrow: value instanceof Object,
readOnly: type === 'function',
readOnly: readOnlyChildren || ['undefined', 'function', 'HTMLElement'].includes(type),
dataType: type,
inputType: mapDataTypeToInputType(type),
id: generatedId,
Expand All @@ -124,7 +152,8 @@ export function flattenSingleAttribute(
typeof val,
margin + 10,
`${elementId}.${index}`,
elementId
elementId,
readOnlyChildren,
)
})
} else if (value instanceof Object) {
Expand All @@ -137,7 +166,8 @@ export function flattenSingleAttribute(
typeof objectValue,
margin + 10,
`${elementId}.${objectKey}`,
elementId
elementId,
readOnlyChildren,
)
})
}
Expand Down
2 changes: 1 addition & 1 deletion packages/simulator/dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function initProxy(window, targetWindow) {
source: 'alpine-devtools-proxy',
payload: (event.data && event.data.payload) || event.data,
},
'*'
'*',
)
return
}
Expand Down
10 changes: 9 additions & 1 deletion packages/simulator/example.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
</head>

<body>
<div x-data="{ bool: true, num: 5, str: 'string', arr: ['world', 'bar']}">
<div
x-data="{ el: $el, myFunction() { return true }, bool: true, num: 5, str: 'string', arr: ['world', 'bar'], nested: {array: [ { hello: 'world' }]}}"
>
<div>Bool, type: "<span x-text="typeof bool"></span>", value: "<span x-text="bool"></span>"</div>
<div>Num, type: "<span x-text="typeof num"></span>", value: "<span x-text="num"></span>"</div>
<div>Str, type: "<span x-text="typeof str"></span>", value: "<span x-text="str"></span>"</div>
Expand All @@ -20,6 +22,12 @@
></span
>"
</div>
<div>
Nested, type "<span x-text="typeof nested"></span>, value (stringified): "<span
x-text="JSON.stringify(nested)"
></span
>"
</div>
</div>
<div id="app" x-data="{ hello: 'world' }">
<span x-text="hello"></span>
Expand Down
2 changes: 1 addition & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ if (isWatch) {
console.info(`Copying asset "${filename}" to dist/chrome`)
fs.copyFileSync(
path.join('./packages/shell-chrome/assets/', filename),
path.join('./dist/chrome', filename)
path.join('./dist/chrome', filename),
)
} catch (e) {
console.error(e)
Expand Down

0 comments on commit 0ce5fff

Please sign in to comment.