glass-easel-devtools-panel 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +2 -0
- package/dist/app.d.ts +0 -0
- package/dist/bootstrap.d.ts +5 -0
- package/dist/bootstrap.js +3 -0
- package/dist/bootstrap.js.LICENSE.txt +1 -0
- package/dist/events.d.ts +41 -0
- package/dist/global_components/image/image.d.ts +1 -0
- package/dist/global_components/index.d.ts +2 -0
- package/dist/global_components/view/view.d.ts +1 -0
- package/dist/index.css +17 -0
- package/dist/message_channel.d.ts +11 -0
- package/dist/pages/detail/detail.d.ts +1 -0
- package/dist/pages/detail/section.d.ts +0 -0
- package/dist/pages/detail/value.d.ts +1 -0
- package/dist/pages/index/index.d.ts +1 -0
- package/dist/pages/store.d.ts +9 -0
- package/dist/pages/tree/element.d.ts +1 -0
- package/dist/resources/logo_256.png +0 -0
- package/dist/utils.d.ts +4 -0
- package/package.json +21 -0
- package/src/app.ts +1 -0
- package/src/app.wxss +1 -0
- package/src/bootstrap.ts +80 -0
- package/src/events.ts +97 -0
- package/src/global_components/image/image.json +3 -0
- package/src/global_components/image/image.ts +1 -0
- package/src/global_components/image/image.wxml +1 -0
- package/src/global_components/image/image.wxss +3 -0
- package/src/global_components/index.ts +12 -0
- package/src/global_components/view/view.json +3 -0
- package/src/global_components/view/view.ts +40 -0
- package/src/global_components/view/view.wxml +14 -0
- package/src/global_components/view/view.wxss +0 -0
- package/src/message_channel.ts +70 -0
- package/src/pages/common.wxss +12 -0
- package/src/pages/detail/detail.json +7 -0
- package/src/pages/detail/detail.ts +190 -0
- package/src/pages/detail/detail.wxml +179 -0
- package/src/pages/detail/detail.wxss +84 -0
- package/src/pages/detail/section.json +3 -0
- package/src/pages/detail/section.ts +17 -0
- package/src/pages/detail/section.wxml +8 -0
- package/src/pages/detail/section.wxss +47 -0
- package/src/pages/detail/value.json +3 -0
- package/src/pages/detail/value.ts +107 -0
- package/src/pages/detail/value.wxml +7 -0
- package/src/pages/detail/value.wxss +44 -0
- package/src/pages/index/index.json +6 -0
- package/src/pages/index/index.ts +121 -0
- package/src/pages/index/index.wxml +29 -0
- package/src/pages/index/index.wxss +75 -0
- package/src/pages/store.ts +33 -0
- package/src/pages/tree/element.json +6 -0
- package/src/pages/tree/element.ts +295 -0
- package/src/pages/tree/element.wxml +47 -0
- package/src/pages/tree/element.wxss +113 -0
- package/src/resources/logo_256.png +0 -0
- package/src/utils.ts +16 -0
- package/src.d.ts +10 -0
- package/tsconfig.json +11 -0
- package/typings/miniprogram.d.ts +6 -0
- package/webpack.config.js +79 -0
- package/webpack.dev.config.js +12 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { DeepCopyKind } from 'glass-easel'
|
|
2
|
+
import { autorun } from 'mobx-miniprogram'
|
|
3
|
+
import { protocol, sendRequest } from '../../message_channel'
|
|
4
|
+
import { store } from '../store'
|
|
5
|
+
import { attributeModified } from '../../events'
|
|
6
|
+
|
|
7
|
+
const DEFAULT_NODE_DATA = {
|
|
8
|
+
glassEaselNodeType: 0,
|
|
9
|
+
virtual: true,
|
|
10
|
+
is: '',
|
|
11
|
+
id: '',
|
|
12
|
+
class: '',
|
|
13
|
+
slot: '',
|
|
14
|
+
slotName: undefined,
|
|
15
|
+
slotValues: undefined,
|
|
16
|
+
eventBindings: [],
|
|
17
|
+
dataset: [],
|
|
18
|
+
marks: [],
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
Component()
|
|
22
|
+
.options({
|
|
23
|
+
dataDeepCopy: DeepCopyKind.None,
|
|
24
|
+
propertyPassingDeepCopy: DeepCopyKind.None,
|
|
25
|
+
})
|
|
26
|
+
.data(() => ({
|
|
27
|
+
nodeId: 0 as protocol.NodeId,
|
|
28
|
+
nodeTypeName: '',
|
|
29
|
+
info: DEFAULT_NODE_DATA as protocol.dom.GetGlassEaselAttributes['response'],
|
|
30
|
+
boxModel: null as null | protocol.dom.GetBoxModel['response'],
|
|
31
|
+
boxModelCollapsed: false,
|
|
32
|
+
styles: null as null | protocol.css.GetMatchedStylesForNode['response'],
|
|
33
|
+
styleCollapsed: false,
|
|
34
|
+
computedStyles: null as null | { name: string; value: string }[],
|
|
35
|
+
computedStyleCollapsed: true,
|
|
36
|
+
}))
|
|
37
|
+
.init(({ self, data, setData, lifetime, method }) => {
|
|
38
|
+
lifetime('attached', () => {
|
|
39
|
+
autorun(async () => {
|
|
40
|
+
const nodeId = store.selectedNodeId
|
|
41
|
+
if (!nodeId) {
|
|
42
|
+
setData({ info: DEFAULT_NODE_DATA })
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// register attributes listeners
|
|
47
|
+
updateListener(nodeId)
|
|
48
|
+
|
|
49
|
+
// fetch normal attributes
|
|
50
|
+
const info = await sendRequest('DOM.getGlassEaselAttributes', { nodeId })
|
|
51
|
+
if (store.selectedNodeId !== nodeId) return
|
|
52
|
+
let nodeTypeName = 'Node (unknown)'
|
|
53
|
+
if (info.glassEaselNodeType === protocol.dom.GlassEaselNodeType.Component) {
|
|
54
|
+
nodeTypeName = 'Component'
|
|
55
|
+
} else if (info.glassEaselNodeType === protocol.dom.GlassEaselNodeType.NativeNode) {
|
|
56
|
+
nodeTypeName = 'Native Node'
|
|
57
|
+
} else if (info.glassEaselNodeType === protocol.dom.GlassEaselNodeType.VirtualNode) {
|
|
58
|
+
nodeTypeName = 'Virtual Node'
|
|
59
|
+
} else if (info.glassEaselNodeType === protocol.dom.GlassEaselNodeType.TextNode) {
|
|
60
|
+
nodeTypeName = 'Text Node'
|
|
61
|
+
}
|
|
62
|
+
setData({ nodeId, nodeTypeName, info })
|
|
63
|
+
|
|
64
|
+
// fetch box model
|
|
65
|
+
if (!data.boxModelCollapsed) {
|
|
66
|
+
await refreshBoxModel()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// fetch style
|
|
70
|
+
if (!data.styleCollapsed) {
|
|
71
|
+
await refreshStyles()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// fetch computed style
|
|
75
|
+
if (!data.computedStyleCollapsed) {
|
|
76
|
+
await refreshComputedStyles()
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
let listeningNodeId = 0
|
|
82
|
+
const updateListenerFunc = (args: protocol.dom.AttributeModified['detail']) => {
|
|
83
|
+
const { name, value, detail, nameType } = args
|
|
84
|
+
if (nameType === 'attribute') {
|
|
85
|
+
const index = data.info.normalAttributes?.map((x) => x.name).indexOf(name) ?? -1
|
|
86
|
+
if (index >= 0) {
|
|
87
|
+
self.groupUpdates(() => {
|
|
88
|
+
self.replaceDataOnPath(
|
|
89
|
+
['info', 'normalAttributes', index, 'value'],
|
|
90
|
+
detail as unknown as never,
|
|
91
|
+
)
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
} else if (nameType === 'component-property') {
|
|
95
|
+
const index = data.info.properties?.map((x) => x.name).indexOf(name) ?? -1
|
|
96
|
+
if (index >= 0) {
|
|
97
|
+
self.groupUpdates(() => {
|
|
98
|
+
self.replaceDataOnPath(
|
|
99
|
+
['info', 'properties', index, 'value'],
|
|
100
|
+
detail as unknown as never,
|
|
101
|
+
)
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
} else if (nameType === 'slot-value') {
|
|
105
|
+
const index = data.info.slotValues?.map((x) => x.name).indexOf(name) ?? -1
|
|
106
|
+
if (index >= 0) {
|
|
107
|
+
self.groupUpdates(() => {
|
|
108
|
+
self.replaceDataOnPath(
|
|
109
|
+
['info', 'slotValues', index, 'value'],
|
|
110
|
+
detail as unknown as never,
|
|
111
|
+
)
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
} else if (nameType === 'dataset' && name.startsWith('data:')) {
|
|
115
|
+
const index = data.info.dataset.map((x) => x.name).indexOf(name.slice(5)) ?? -1
|
|
116
|
+
if (index >= 0) {
|
|
117
|
+
self.groupUpdates(() => {
|
|
118
|
+
self.replaceDataOnPath(['info', 'dataset', index, 'value'], detail)
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
} else if (nameType === 'mark' && name.startsWith('mark:')) {
|
|
122
|
+
const index = data.info.marks.map((x) => x.name).indexOf(name.slice(5)) ?? -1
|
|
123
|
+
if (index >= 0) {
|
|
124
|
+
self.groupUpdates(() => {
|
|
125
|
+
self.replaceDataOnPath(['info', 'marks', index, 'value'], detail)
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
} else if (nameType === 'external-class') {
|
|
129
|
+
const index = data.info.externalClasses?.map((x) => x.name).indexOf(name) ?? -1
|
|
130
|
+
if (index >= 0) {
|
|
131
|
+
self.groupUpdates(() => {
|
|
132
|
+
self.replaceDataOnPath(
|
|
133
|
+
['info', 'externalClasses', index, 'value'],
|
|
134
|
+
value as unknown as never,
|
|
135
|
+
)
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
} else if (name === 'slot') {
|
|
139
|
+
self.groupUpdates(() => {
|
|
140
|
+
self.replaceDataOnPath(['info', 'slot'], value)
|
|
141
|
+
})
|
|
142
|
+
} else if (name === 'id') {
|
|
143
|
+
self.groupUpdates(() => {
|
|
144
|
+
self.replaceDataOnPath(['info', 'id'], value)
|
|
145
|
+
})
|
|
146
|
+
} else if (name === 'class') {
|
|
147
|
+
self.groupUpdates(() => {
|
|
148
|
+
self.replaceDataOnPath(['info', 'class'], value)
|
|
149
|
+
})
|
|
150
|
+
} else if (name === 'name') {
|
|
151
|
+
self.groupUpdates(() => {
|
|
152
|
+
self.replaceDataOnPath(['info', 'slotName'], value)
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const updateListener = (nodeId: protocol.NodeId) => {
|
|
157
|
+
if (listeningNodeId) {
|
|
158
|
+
attributeModified.removeListener(listeningNodeId, updateListenerFunc)
|
|
159
|
+
}
|
|
160
|
+
if (nodeId) {
|
|
161
|
+
attributeModified.addListener(nodeId, updateListenerFunc)
|
|
162
|
+
}
|
|
163
|
+
listeningNodeId = nodeId
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const refreshBoxModel = method(async () => {
|
|
167
|
+
const nodeId = store.selectedNodeId
|
|
168
|
+
const boxModel = data.info.virtual ? null : await sendRequest('DOM.getBoxModel', { nodeId })
|
|
169
|
+
setData({ boxModel })
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
const refreshStyles = method(async () => {
|
|
173
|
+
const nodeId = store.selectedNodeId
|
|
174
|
+
const styles = data.info.virtual
|
|
175
|
+
? null
|
|
176
|
+
: await sendRequest('CSS.getMatchedStylesForNode', { nodeId })
|
|
177
|
+
setData({ styles })
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
const refreshComputedStyles = method(async () => {
|
|
181
|
+
const nodeId = store.selectedNodeId
|
|
182
|
+
const computedStyles = data.info.virtual
|
|
183
|
+
? null
|
|
184
|
+
: (await sendRequest('CSS.getComputedStyleForNode', { nodeId })).computedStyle
|
|
185
|
+
setData({ computedStyles })
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
return { refreshBoxModel, refreshStyles, refreshComputedStyles }
|
|
189
|
+
})
|
|
190
|
+
.register()
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
<detail-section class="section" title="{{ nodeTypeName }}">
|
|
2
|
+
<block wx:if="{{ info.glassEaselNodeType === 0x102 }}">
|
|
3
|
+
<view wx:if="{{ info.id }}" class="section-item">
|
|
4
|
+
<view class="section-key-core">id</view> = <value primitive-value="{{ info.id }}" node-id="{{ nodeId }}" />
|
|
5
|
+
</view>
|
|
6
|
+
<view wx:if="{{ info.class }}" class="section-item">
|
|
7
|
+
<view class="section-key-core">class</view> = <value primitive-value="{{ info.class }}" node-id="{{ nodeId }}" />
|
|
8
|
+
</view>
|
|
9
|
+
<view wx:if="{{ info.slot }}" class="section-item">
|
|
10
|
+
<view class="section-key-core">slot</view> = <value primitive-value="{{ info.slot }}" node-id="{{ nodeId }}" />
|
|
11
|
+
</view>
|
|
12
|
+
</block>
|
|
13
|
+
<block wx:elif="{{ info.glassEaselNodeType === 0x103 }}">
|
|
14
|
+
<view class="section-item">
|
|
15
|
+
<view class="section-key-core">is</view> = <value primitive-value="{{ info.is }}" node-id="{{ nodeId }}" />
|
|
16
|
+
</view>
|
|
17
|
+
<view wx:if="{{ info.id }}" class="section-item">
|
|
18
|
+
<view class="section-key-core">id</view> = <value primitive-value="{{ info.id }}" node-id="{{ nodeId }}" />
|
|
19
|
+
</view>
|
|
20
|
+
<view wx:if="{{ info.class }}" class="section-item">
|
|
21
|
+
<view class="section-key-core">class</view> = <value primitive-value="{{ info.class }}" node-id="{{ nodeId }}" />
|
|
22
|
+
</view>
|
|
23
|
+
<view wx:if="{{ info.slot }}" class="section-item">
|
|
24
|
+
<view class="section-key-core">slot</view> = <value primitive-value="{{ info.slot }}" node-id="{{ nodeId }}" />
|
|
25
|
+
</view>
|
|
26
|
+
</block>
|
|
27
|
+
<block wx:elif="{{ info.glassEaselNodeType === 0x104 }}">
|
|
28
|
+
<view class="section-item">
|
|
29
|
+
<view class="section-key-core">is</view> = <value primitive-value="{{ info.is }}" node-id="{{ nodeId }}" />
|
|
30
|
+
</view>
|
|
31
|
+
<view wx:if="{{ info.id }}" class="section-item">
|
|
32
|
+
<view class="section-key-core">id</view> = <value primitive-value="{{ info.id }}" node-id="{{ nodeId }}" />
|
|
33
|
+
</view>
|
|
34
|
+
<view wx:if="{{ info.slot }}" class="section-item">
|
|
35
|
+
<view class="section-key-core">slot</view> = <value primitive-value="{{ info.slot }}" node-id="{{ nodeId }}" />
|
|
36
|
+
</view>
|
|
37
|
+
</block>
|
|
38
|
+
</detail-section>
|
|
39
|
+
|
|
40
|
+
<view hidden="{{ info.slotName === undefined }}">
|
|
41
|
+
<detail-section class="section" title="slot">
|
|
42
|
+
<view class="section-item">
|
|
43
|
+
<view class="section-key-core">name</view> = <value primitive-value="{{ info.slotName }}" node-id="{{ nodeId }}" />
|
|
44
|
+
</view>
|
|
45
|
+
<view wx:for="{{ info.slotValues ?? [] }}" class="section-item">
|
|
46
|
+
<view class="section-key">{{ item.name }}</view> = <value value="{{ item.value }}" node-id="{{ nodeId }}" />
|
|
47
|
+
</view>
|
|
48
|
+
</detail-section>
|
|
49
|
+
</view>
|
|
50
|
+
|
|
51
|
+
<view hidden="{{ !info.normalAttributes }}">
|
|
52
|
+
<detail-section class="section" title="attributes">
|
|
53
|
+
<block wx:if="{{ info.normalAttributes.length }}">
|
|
54
|
+
<view wx:for="{{ info.normalAttributes }}" class="section-item">
|
|
55
|
+
<view class="section-key">{{ item.name }}</view> = <value value="{{ item.value }}" node-id="{{ nodeId }}" attribute="{{ item.name }}" />
|
|
56
|
+
</view>
|
|
57
|
+
</block>
|
|
58
|
+
<view wx:else class="section-empty">empty</view>
|
|
59
|
+
</detail-section>
|
|
60
|
+
</view>
|
|
61
|
+
|
|
62
|
+
<view hidden="{{ !info.properties }}">
|
|
63
|
+
<detail-section class="section" title="properties">
|
|
64
|
+
<block wx:if="{{ info.properties.length }}">
|
|
65
|
+
<view wx:for="{{ info.properties }}" class="section-item">
|
|
66
|
+
<view class="section-key">{{ item.name }}</view> = <value value="{{ item.value }}" node-id="{{ nodeId }}" attribute="{{ item.name }}" />
|
|
67
|
+
</view>
|
|
68
|
+
</block>
|
|
69
|
+
<view wx:else class="section-empty">empty</view>
|
|
70
|
+
</detail-section>
|
|
71
|
+
</view>
|
|
72
|
+
|
|
73
|
+
<view hidden="{{ !info.externalClasses }}">
|
|
74
|
+
<detail-section class="section" title="external classes">
|
|
75
|
+
<block wx:if="{{ info.externalClasses.length }}">
|
|
76
|
+
<view wx:for="{{ info.externalClasses }}" class="section-item">
|
|
77
|
+
<view class="section-key">{{ item.name }}</view> = <value primitive-value="{{ item.value }}" node-id="{{ nodeId }}" attribute="{{ item.name }}" />
|
|
78
|
+
</view>
|
|
79
|
+
</block>
|
|
80
|
+
<view wx:else class="section-empty">empty</view>
|
|
81
|
+
</detail-section>
|
|
82
|
+
</view>
|
|
83
|
+
|
|
84
|
+
<detail-section class="section" title="dataset" collapsed>
|
|
85
|
+
<block wx:if="{{ info.dataset.length }}">
|
|
86
|
+
<view wx:for="{{ info.dataset }}" class="section-item">
|
|
87
|
+
<view class="section-key">{{ item.name }}</view> = <value value="{{ item.value }}" node-id="{{ nodeId }}" attribute="data:{{ item.name }}" />
|
|
88
|
+
</view>
|
|
89
|
+
</block>
|
|
90
|
+
<view wx:else class="section-empty">empty</view>
|
|
91
|
+
</detail-section>
|
|
92
|
+
|
|
93
|
+
<detail-section class="section" title="marks" collapsed>
|
|
94
|
+
<block wx:if="{{ info.marks.length }}">
|
|
95
|
+
<view wx:for="{{ info.marks }}" class="section-item">
|
|
96
|
+
<view class="section-key">{{ item.name }}</view> = <value value="{{ item.value }}" node-id="{{ nodeId }}" attribute="mark:{{ item.name }}" />
|
|
97
|
+
</view>
|
|
98
|
+
</block>
|
|
99
|
+
<view wx:else class="section-empty">empty</view>
|
|
100
|
+
</detail-section>
|
|
101
|
+
|
|
102
|
+
<detail-section
|
|
103
|
+
class="section"
|
|
104
|
+
title="box model"
|
|
105
|
+
show-refresh
|
|
106
|
+
model:collapsed="{{ boxModelCollapsed }}"
|
|
107
|
+
catch:refresh="refreshBoxModel"
|
|
108
|
+
>
|
|
109
|
+
<block wx:if="{{ !boxModelCollapsed && boxModel }}">
|
|
110
|
+
<view class="box-model">
|
|
111
|
+
<view class="box-model-margin">
|
|
112
|
+
<view class="box-model-text">{{ boxModel.border[1] - boxModel.margin[1] }}</view>
|
|
113
|
+
<view class="box-model-line">
|
|
114
|
+
<view class="box-model-text">{{ boxModel.border[0] - boxModel.margin[0] }}</view>
|
|
115
|
+
<view class="box-model-border">
|
|
116
|
+
<view class="box-model-text">{{ boxModel.padding[1] - boxModel.border[1] }}</view>
|
|
117
|
+
<view class="box-model-line">
|
|
118
|
+
<view class="box-model-text">{{ boxModel.padding[0] - boxModel.border[0] }}</view>
|
|
119
|
+
<view class="box-model-padding">
|
|
120
|
+
<view class="box-model-text">{{ boxModel.content[1] - boxModel.padding[1] }}</view>
|
|
121
|
+
<view class="box-model-line">
|
|
122
|
+
<view class="box-model-text">{{ boxModel.content[0] - boxModel.padding[0] }}</view>
|
|
123
|
+
<view class="box-model-content">
|
|
124
|
+
<view class="box-model-text">{{ boxModel.width }}</view>x<view class="box-model-text">{{ boxModel.height }}</view>
|
|
125
|
+
</view>
|
|
126
|
+
<view class="box-model-text">{{ boxModel.padding[4] - boxModel.content[4] }}</view>
|
|
127
|
+
</view>
|
|
128
|
+
<view class="box-model-text">{{ boxModel.padding[5] - boxModel.content[5] }}</view>
|
|
129
|
+
</view>
|
|
130
|
+
<view class="box-model-text">{{ boxModel.border[4] - boxModel.padding[4] }}</view>
|
|
131
|
+
</view>
|
|
132
|
+
<view class="box-model-text">{{ boxModel.border[5] - boxModel.padding[5] }}</view>
|
|
133
|
+
</view>
|
|
134
|
+
<view class="box-model-text">{{ boxModel.margin[4] - boxModel.border[4] }}</view>
|
|
135
|
+
</view>
|
|
136
|
+
<view class="box-model-text">{{ boxModel.margin[5] - boxModel.border[5] }}</view>
|
|
137
|
+
</view>
|
|
138
|
+
</view>
|
|
139
|
+
</block>
|
|
140
|
+
</detail-section>
|
|
141
|
+
|
|
142
|
+
<detail-section
|
|
143
|
+
class="section"
|
|
144
|
+
title="style"
|
|
145
|
+
show-refresh
|
|
146
|
+
model:collapsed="{{ styleCollapsed }}"
|
|
147
|
+
catch:refresh="refreshStyles"
|
|
148
|
+
>
|
|
149
|
+
<block wx:if="{{ !styleCollapsed && styles }}">
|
|
150
|
+
<view wx:if="{{ styles.crossOriginFailing }}">Failed to display styles due to inaccessable style sheets. This happens when style sheets are cross-origin served, or the page is visited as a local file.</view>
|
|
151
|
+
<view wx:if="{{ styles.inlineStyle.cssProperties.length }}" class="style-rule">
|
|
152
|
+
<view class="style-rule-prefix">Inline Style</view>
|
|
153
|
+
<view wx:for="{{ styles.inlineStyle.cssProperties }}" class="section-item">
|
|
154
|
+
<view class="section-key">{{ item.name }}</view>: <view class="section-value">{{ item.value }}</view> <view wx:if="{{ item.important }}" class="section-value-extra">{{ item.important ? '!important' : '' }}</view>
|
|
155
|
+
</view>
|
|
156
|
+
</view>
|
|
157
|
+
<view wx:for="{{ styles.matchedCSSRules }}" class="style-rule {{ item.rule.inactive ? 'style-rule_inactive' : '' }}">
|
|
158
|
+
<view wx:for="{{ item.rule.media ?? [] }}" class="style-rule-prefix">{{ item.text }}</view>
|
|
159
|
+
<view class="style-rule-title">{{ item.rule.selectorList.text }}</view>
|
|
160
|
+
<view wx:for="{{ item.rule.style.cssProperties }}" class="section-item">
|
|
161
|
+
<view class="section-key">{{ item.name }}</view>: <view class="section-value">{{ item.value }}</view> <view wx:if="{{ item.important }}" class="section-value-extra">{{ item.important ? '!important' : '' }}</view>
|
|
162
|
+
</view>
|
|
163
|
+
</view>
|
|
164
|
+
</block>
|
|
165
|
+
</detail-section>
|
|
166
|
+
|
|
167
|
+
<detail-section
|
|
168
|
+
class="section"
|
|
169
|
+
title="computed style"
|
|
170
|
+
show-refresh
|
|
171
|
+
model:collapsed="{{ computedStyleCollapsed }}"
|
|
172
|
+
catch:refresh="refreshComputedStyles"
|
|
173
|
+
>
|
|
174
|
+
<block wx:if="{{ !computedStyleCollapsed && computedStyles }}">
|
|
175
|
+
<view wx:for="{{ computedStyles }}" class="section-item">
|
|
176
|
+
<view class="section-key">{{ item.name }}</view>: <view class="section-value">{{ item.value }}</view>
|
|
177
|
+
</view>
|
|
178
|
+
</block>
|
|
179
|
+
</detail-section>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
@import url('../common.wxss');
|
|
2
|
+
|
|
3
|
+
:host {
|
|
4
|
+
display: block;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.section {
|
|
8
|
+
margin-bottom: 5px;
|
|
9
|
+
color: @common-text;
|
|
10
|
+
}
|
|
11
|
+
.section-item {
|
|
12
|
+
white-space: nowrap;
|
|
13
|
+
user-select: text;
|
|
14
|
+
}
|
|
15
|
+
.section-key {
|
|
16
|
+
display: inline;
|
|
17
|
+
color: @property-name;
|
|
18
|
+
}
|
|
19
|
+
.section-key-core {
|
|
20
|
+
display: inline;
|
|
21
|
+
color: @core-attribute-name;
|
|
22
|
+
}
|
|
23
|
+
.section-value {
|
|
24
|
+
display: inline;
|
|
25
|
+
color: @attribute-value;
|
|
26
|
+
}
|
|
27
|
+
.section-value-extra {
|
|
28
|
+
color: @important-text;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.section-empty {
|
|
32
|
+
text-align: center;
|
|
33
|
+
font-style: italic;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.box-model {
|
|
37
|
+
margin: 0 auto;
|
|
38
|
+
}
|
|
39
|
+
.box-model-text {
|
|
40
|
+
flex: none;
|
|
41
|
+
text-align: center;
|
|
42
|
+
white-space: nowrap;
|
|
43
|
+
color: @important-text;
|
|
44
|
+
margin: 1px;
|
|
45
|
+
}
|
|
46
|
+
.box-model-content {
|
|
47
|
+
display: flex;
|
|
48
|
+
border: 1px solid #888;
|
|
49
|
+
padding: 1px;
|
|
50
|
+
}
|
|
51
|
+
.box-model-padding {
|
|
52
|
+
border: 1px solid #888;
|
|
53
|
+
padding: 1px;
|
|
54
|
+
background: @primary-bg;
|
|
55
|
+
}
|
|
56
|
+
.box-model-border {
|
|
57
|
+
border: 1px solid #888;
|
|
58
|
+
padding: 1px;
|
|
59
|
+
background: @secondary-bg;
|
|
60
|
+
}
|
|
61
|
+
.box-model-margin {
|
|
62
|
+
padding: 1px;
|
|
63
|
+
}
|
|
64
|
+
.box-model-line {
|
|
65
|
+
display: flex;
|
|
66
|
+
justify-content: center;
|
|
67
|
+
align-items: center;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.style-rule {
|
|
71
|
+
padding-left: 1em;
|
|
72
|
+
margin: 5px 0;
|
|
73
|
+
}
|
|
74
|
+
.style-rule_inactive {
|
|
75
|
+
text-decoration: line-through @important-text;
|
|
76
|
+
}
|
|
77
|
+
.style-rule-prefix {
|
|
78
|
+
margin-left: -1em;
|
|
79
|
+
font-style: italic;
|
|
80
|
+
}
|
|
81
|
+
.style-rule-title {
|
|
82
|
+
margin-left: -1em;
|
|
83
|
+
color: @important-text;
|
|
84
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Component()
|
|
2
|
+
.property('title', String)
|
|
3
|
+
.property('collapsed', Boolean)
|
|
4
|
+
.property('showRefresh', Boolean)
|
|
5
|
+
.init(({ self, data, setData, listener }) => {
|
|
6
|
+
const toggleBody = listener(() => {
|
|
7
|
+
setData({ collapsed: !data.collapsed })
|
|
8
|
+
if (!data.collapsed) {
|
|
9
|
+
self.triggerEvent('refresh', null, {})
|
|
10
|
+
}
|
|
11
|
+
})
|
|
12
|
+
const refresh = listener(() => {
|
|
13
|
+
self.triggerEvent('refresh', null, {})
|
|
14
|
+
})
|
|
15
|
+
return { toggleBody, refresh }
|
|
16
|
+
})
|
|
17
|
+
.register()
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<view class="title" catch:tap="toggleBody">
|
|
2
|
+
<view class="arrow {{ collapsed ? '' : 'arrow_open' }}">▶</view>
|
|
3
|
+
<view class="title-text">{{ title }}</view>
|
|
4
|
+
<view wx:if="{{ !collapsed && showRefresh }}" class="title-refresh" hover-class="title-refresh_hover" catch:tap="refresh">⟳</view>
|
|
5
|
+
</view>
|
|
6
|
+
<view class="body {{ collapsed ? 'body_collapsed' : '' }}">
|
|
7
|
+
<slot />
|
|
8
|
+
</view>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
@import url('../common.wxss');
|
|
2
|
+
|
|
3
|
+
:host {
|
|
4
|
+
display: block;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.title {
|
|
8
|
+
padding: 0 5px;
|
|
9
|
+
background: @secondary-bg;
|
|
10
|
+
color: @important-text;
|
|
11
|
+
line-height: 1.5;
|
|
12
|
+
white-space: nowrap;
|
|
13
|
+
}
|
|
14
|
+
.title-text {
|
|
15
|
+
display: inline-block;
|
|
16
|
+
}
|
|
17
|
+
.title-refresh {
|
|
18
|
+
display: inline-block;
|
|
19
|
+
font-size: 1.5em;
|
|
20
|
+
width: 1em;
|
|
21
|
+
height: 1em;
|
|
22
|
+
line-height: 1;
|
|
23
|
+
text-align: center;
|
|
24
|
+
margin-left: 0.5em;
|
|
25
|
+
}
|
|
26
|
+
.title-refresh_hover {
|
|
27
|
+
background-color: @hover-bg;
|
|
28
|
+
}
|
|
29
|
+
.arrow {
|
|
30
|
+
display: inline-block;
|
|
31
|
+
width: 1em;
|
|
32
|
+
height: 1.5em;
|
|
33
|
+
text-align: center;
|
|
34
|
+
transition: transform 200ms ease;
|
|
35
|
+
margin-right: 0.25em;
|
|
36
|
+
}
|
|
37
|
+
.arrow_open {
|
|
38
|
+
transform: rotate(90deg);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.body {
|
|
42
|
+
padding: 0 5px;
|
|
43
|
+
overflow: hidden;
|
|
44
|
+
}
|
|
45
|
+
.body_collapsed {
|
|
46
|
+
height: 0;
|
|
47
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import * as glassEasel from 'glass-easel'
|
|
2
|
+
import { type protocol } from 'glass-easel-devtools-agent'
|
|
3
|
+
import { sendRequest } from '../../message_channel'
|
|
4
|
+
|
|
5
|
+
Component()
|
|
6
|
+
.options({
|
|
7
|
+
virtualHost: true,
|
|
8
|
+
dataDeepCopy: glassEasel.DeepCopyKind.None,
|
|
9
|
+
propertyPassingDeepCopy: glassEasel.DeepCopyKind.None,
|
|
10
|
+
})
|
|
11
|
+
.property('primitiveValue', null)
|
|
12
|
+
.property('value', {
|
|
13
|
+
type: Object,
|
|
14
|
+
value: null as null | protocol.GlassEaselVar,
|
|
15
|
+
})
|
|
16
|
+
.property('varName', String)
|
|
17
|
+
.property('nodeId', Number)
|
|
18
|
+
.property('attribute', String)
|
|
19
|
+
.data(() => ({
|
|
20
|
+
slices: [] as { dynamic: boolean; str: string }[],
|
|
21
|
+
allowInspect: false,
|
|
22
|
+
updateHighlight: false,
|
|
23
|
+
}))
|
|
24
|
+
.init(({ self, data, setData, observer, method }) => {
|
|
25
|
+
let prevNodeId = 0
|
|
26
|
+
observer(['value', 'primitiveValue'], () => {
|
|
27
|
+
const v: protocol.GlassEaselVar = data.value ?? {
|
|
28
|
+
type: 'primitive',
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
30
|
+
value: data.primitiveValue,
|
|
31
|
+
}
|
|
32
|
+
if (!v) {
|
|
33
|
+
setData({ slices: [], allowInspect: false })
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
if (data.nodeId === prevNodeId) {
|
|
37
|
+
updatedAni()
|
|
38
|
+
} else {
|
|
39
|
+
prevNodeId = data.nodeId
|
|
40
|
+
}
|
|
41
|
+
if (v.type === 'primitive') {
|
|
42
|
+
if (v.value === null) {
|
|
43
|
+
setData({ slices: [{ dynamic: true, str: 'null' }], allowInspect: false })
|
|
44
|
+
} else if (v.value === undefined) {
|
|
45
|
+
setData({ slices: [{ dynamic: true, str: 'undefined' }], allowInspect: false })
|
|
46
|
+
} else if (typeof v.value === 'string') {
|
|
47
|
+
setData({
|
|
48
|
+
slices: [
|
|
49
|
+
{ dynamic: false, str: '"' },
|
|
50
|
+
{ dynamic: true, str: v.value },
|
|
51
|
+
{ dynamic: false, str: '"' },
|
|
52
|
+
],
|
|
53
|
+
allowInspect: false,
|
|
54
|
+
})
|
|
55
|
+
} else {
|
|
56
|
+
setData({ slices: [{ dynamic: true, str: String(v.value) }], allowInspect: false })
|
|
57
|
+
}
|
|
58
|
+
} else if (v.type === 'symbol') {
|
|
59
|
+
setData({
|
|
60
|
+
slices: [
|
|
61
|
+
{ dynamic: false, str: 'Symbol(' },
|
|
62
|
+
{ dynamic: true, str: v.value },
|
|
63
|
+
{ dynamic: false, str: ')' },
|
|
64
|
+
],
|
|
65
|
+
allowInspect: false,
|
|
66
|
+
})
|
|
67
|
+
} else if (v.type === 'function') {
|
|
68
|
+
setData({ slices: [{ dynamic: true, str: 'Function' }], allowInspect: data.nodeId > 0 })
|
|
69
|
+
} else if (v.type === 'object') {
|
|
70
|
+
setData({ slices: [{ dynamic: true, str: 'Object' }], allowInspect: data.nodeId > 0 })
|
|
71
|
+
} else if (v.type === 'array') {
|
|
72
|
+
setData({ slices: [{ dynamic: true, str: 'Array' }], allowInspect: data.nodeId > 0 })
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
let updateAniEndTimeout = 0
|
|
77
|
+
const updatedAni = method(() => {
|
|
78
|
+
setTimeout(() => {
|
|
79
|
+
if (data.updateHighlight) {
|
|
80
|
+
setData({ updateHighlight: false })
|
|
81
|
+
updatedAni()
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
if (updateAniEndTimeout) {
|
|
85
|
+
clearTimeout(updateAniEndTimeout)
|
|
86
|
+
updateAniEndTimeout = 0
|
|
87
|
+
}
|
|
88
|
+
self.setData({ updateHighlight: true, varName: '' })
|
|
89
|
+
updateAniEndTimeout = setTimeout(() => {
|
|
90
|
+
updateAniEndTimeout = 0
|
|
91
|
+
setData({ updateHighlight: false })
|
|
92
|
+
}, 1000)
|
|
93
|
+
}, 200)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
const useInConsole = method(async () => {
|
|
97
|
+
const { nodeId, attribute } = data
|
|
98
|
+
const { varName } = await sendRequest('DOM.useGlassEaselAttributeInConsole', {
|
|
99
|
+
nodeId,
|
|
100
|
+
attribute,
|
|
101
|
+
})
|
|
102
|
+
self.setData({ varName })
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
return { useInConsole }
|
|
106
|
+
})
|
|
107
|
+
.register()
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<view class="wrapper {{ updateHighlight ? 'updated' : '' }}">
|
|
2
|
+
<view wx:for="{{ slices }}" class="slice {{ item.dynamic ? 'slice_dynamic' : '' }}">{{ item.str }}</view>
|
|
3
|
+
</view>
|
|
4
|
+
<block wx:if="{{ allowInspect }}">
|
|
5
|
+
<view wx:if="{{ varName }}" class="var-name">={{ varName }}</view>
|
|
6
|
+
<view wx:else class="var-name" hover-class="var-name_hover" catch:tap="useInConsole">↖</view>
|
|
7
|
+
</block>
|