Skip to content

Commit d2a02d1

Browse files
committed
fix: catch eval error for non-existing elements
1 parent c926d9b commit d2a02d1

File tree

3 files changed

+72
-44
lines changed

3 files changed

+72
-44
lines changed

index.html

+6-3
Original file line numberDiff line numberDiff line change
@@ -1400,9 +1400,12 @@ <h3 class="font-bold font-mono">Multi Select:</h3>
14001400
:click="selectedTags = selectedTags.add(tag);
14011401
filteredTags = filteredTags.remove(selectedTag);
14021402
selectedTag = filteredTags.first"
1403-
:mouseover="selectedTag = tag"
1404-
:class="selectedTag == tag ? 'bg-blue-100 text-blue-700' : 'text-gray-700'"
1405-
class="font-mono font-semibold py-2 px-3 rounded cursor-pointer hover:bg-blue-100 hover:text-blue-700"
1403+
:mouseover="el.isHovering = true"
1404+
:mouseout="el.isHovering = false"
1405+
:class="(selectedTag == tag ? 'text-blue-700' : 'text-gray-700')
1406+
(selectedTag == tag ? 'bg-blue-100' : '')
1407+
(el.isHovering && selectedTag != tag ? 'bg-gray-50' : '')"
1408+
class="font-mono font-semibold py-2 px-3 rounded cursor-pointer"
14061409
:text="tag"
14071410
></li>
14081411
</ul>

lib/entity.js

+17-12
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ export default class Entity {
2626
return !!this.uuid
2727
}
2828

29+
isExists() {
30+
return document.documentElement.contains(this.element)
31+
}
32+
2933
getVariables() {
3034
this._getVariablesFromAttributes()
3135
this._getVariablesFromEvents()
@@ -91,19 +95,19 @@ export default class Entity {
9195

9296
this.variables.forEach((variable) => {
9397
if (variable.startsWith('el.') || variable === 'el') {
94-
if (this.uuid == null) {
95-
this.setAsParent()
98+
this.setAsParent()
9699

97-
if (!this.parent) this.parent = this.getParent()
100+
if (!this.parent) this.parent = this.getParent()
98101

99-
window[this.id] = MiniJS.state.create({}, this.id)
102+
if (window[this.uuid] == null) {
103+
window[this.uuid] = MiniJS.state.create({}, this.id)
100104
}
101105

102-
MiniJS.state.addDependency(this.id, this.id)
106+
MiniJS.state.addDependency(this.uuid, this.id)
103107

104108
if (variable !== 'el') {
105109
const [_, varName] = variable.split('.')
106-
MiniJS.state.addEntityDependency(this.id, varName, this.id)
110+
MiniJS.state.addEntityDependency(this.uuid, varName, this.id)
107111
}
108112
} else if (typeof window[variable] === 'function') {
109113
this.variables.splice(this.variables.indexOf(variable), 1)
@@ -127,9 +131,10 @@ export default class Entity {
127131
async _interpret(expr, options = {}) {
128132
const Engine = options.isClass ? ClassInterpreter : Interpreter
129133
const engine = new Engine(expr, options)
130-
const ids = { $: 'document.querySelector' }
131-
132-
if (this.parent?.uuid) ids.el = `proxyWindow['${this.parent.uuid}']`
134+
const ids = {
135+
$: 'document.querySelector',
136+
el: `proxyWindow['${this.uuid}']`,
137+
}
133138

134139
this.variables.forEach((variable) => {
135140
if (variable.startsWith('el.') || variable === 'el') return
@@ -226,10 +231,10 @@ export default class Entity {
226231

227232
unusedVariables.forEach((variable) => {
228233
if (variable.startsWith('el.') || variable === 'el') {
229-
delete window[this.id]
234+
delete window[this.uuid]
230235
const varName = variable.replace('el.', '')
231-
MiniJS.state.disposeDependency(this.id)
232-
MiniJS.state.disposeEntityDependency(this.id, varName)
236+
MiniJS.state.disposeDependency(this.uuid)
237+
MiniJS.state.disposeEntityDependency(this.uuid, varName)
233238
} else {
234239
delete window[variable]
235240
MiniJS.state.disposeDependency(variable)

lib/entity/attributes.js

+49-29
Original file line numberDiff line numberDiff line change
@@ -65,54 +65,74 @@ export class Attributes {
6565
const expr = this.base.element.getAttribute(':class')
6666
if (!expr) return
6767

68-
const updatedClassNames = await this.base._interpret(expr, {
69-
base: this.initialState.classList,
70-
isClass: true,
71-
})
72-
73-
this.base.element.setAttribute('class', updatedClassNames)
68+
try {
69+
const updatedClassNames = await this.base._interpret(expr, {
70+
base: this.initialState.classList,
71+
isClass: true,
72+
})
73+
74+
this.base.element.setAttribute('class', updatedClassNames)
75+
} catch (error) {
76+
if (!this.base.isExists()) return
77+
throw error
78+
}
7479
}
7580

7681
async evaluateText() {
7782
const textExpr = this.base.element.getAttribute(':text')
7883
if (!textExpr) return
7984

80-
const newText = await this.base._interpret(textExpr)
85+
try {
86+
const newText = await this.base._interpret(textExpr)
8187

82-
if (newText || newText == '') this.base.element.innerText = newText
88+
if (newText || newText == '') this.base.element.innerText = newText
89+
} catch (error) {
90+
if (!this.base.isExists()) return
91+
throw error
92+
}
8393
}
8494

8595
async evaluateValue() {
86-
const valueExpr = this.base.element.getAttribute(':value')
96+
try {
97+
const valueExpr = this.base.element.getAttribute(':value')
8798

88-
if (valueExpr) {
89-
const newValue = await this.base._interpret(valueExpr)
99+
if (valueExpr) {
100+
const newValue = await this.base._interpret(valueExpr)
90101

91-
if (this.base.element.value !== newValue && newValue != null)
92-
this.base.element.value = newValue
93-
}
102+
if (this.base.element.value !== newValue && newValue != null)
103+
this.base.element.value = newValue
104+
}
94105

95-
const checkedExpr = this.base.element.getAttribute(':checked')
106+
const checkedExpr = this.base.element.getAttribute(':checked')
96107

97-
if (checkedExpr) {
98-
const newValue = await this.base._interpret(checkedExpr)
108+
if (checkedExpr) {
109+
const newValue = await this.base._interpret(checkedExpr)
99110

100-
if (newValue) this.base.element.checked = newValue
111+
if (newValue) this.base.element.checked = newValue
112+
}
113+
} catch (error) {
114+
if (!this.base.isExists()) return
115+
throw error
101116
}
102117
}
103118

104119
async evaluateOtherAttributes() {
105-
for (const attr of this.dynamicAttributes) {
106-
if (Attributes.CUSTOM_ATTRIBUTES.includes(attr)) continue
107-
108-
const expr = this.base.element.getAttribute(attr)
109-
if (!expr) return
110-
111-
const newValue = await this.base._interpret(expr)
112-
const nativeAttr = attr.slice(1)
113-
114-
if (this.base.element[nativeAttr] !== newValue && newValue != null)
115-
this.base.element[nativeAttr] = newValue
120+
try {
121+
for (const attr of this.dynamicAttributes) {
122+
if (Attributes.CUSTOM_ATTRIBUTES.includes(attr)) continue
123+
124+
const expr = this.base.element.getAttribute(attr)
125+
if (!expr) return
126+
127+
const newValue = await this.base._interpret(expr)
128+
const nativeAttr = attr.slice(1)
129+
130+
if (this.base.element[nativeAttr] !== newValue && newValue != null)
131+
this.base.element[nativeAttr] = newValue
132+
}
133+
} catch (error) {
134+
if (!this.base.isExists()) return
135+
throw error
116136
}
117137
}
118138

0 commit comments

Comments
 (0)