firefly-compiler 0.4.81 → 0.4.82
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/compiler/Parser.ff +44 -3
- package/compiler/Token.ff +8 -4
- package/compiler/Tokenizer.ff +2 -2
- package/core/JsSystem.ff +12 -0
- package/core/JsValue.ff +6 -0
- package/lux/Lux.ff +76 -52
- package/lux/TestDry.ff +2 -1
- package/output/js/ff/compiler/Parser.mjs +78 -12
- package/output/js/ff/compiler/Token.mjs +82 -74
- package/output/js/ff/compiler/Tokenizer.mjs +4 -4
- package/output/js/ff/core/JsSystem.mjs +32 -0
- package/output/js/ff/core/JsValue.mjs +16 -0
- package/package.json +1 -1
- package/vscode/client/package-lock.json +544 -544
- package/vscode/package.json +1 -1
- package/vscode/syntaxes/firefly.tmLanguage.json +5 -0
package/compiler/Parser.ff
CHANGED
|
@@ -1025,11 +1025,10 @@ extend self: Parser {
|
|
|
1025
1025
|
if(self.current().is(LKeyword) && (self.current().rawIs("let") || self.current().rawIs("mutable"))) {self.parseLet()} else:
|
|
1026
1026
|
if(self.current().is(LKeyword) && self.current().rawIs("function")) {self.parseFunctions()} else:
|
|
1027
1027
|
let term = self.parseTerm()
|
|
1028
|
-
if(!self.current().is(LAssign) && !self.current().
|
|
1028
|
+
if(!self.current().is(LAssign) && !self.current().is2(LAssignPlus, LAssignMinus)) {term} else:
|
|
1029
1029
|
let token = do {
|
|
1030
1030
|
if(self.current().is(LAssignPlus)) {self.skip(LAssignPlus)} else:
|
|
1031
1031
|
if(self.current().is(LAssignMinus)) {self.skip(LAssignMinus)} else:
|
|
1032
|
-
if(self.current().is(LAssignLink)) {self.skip(LAssignLink)} else:
|
|
1033
1032
|
self.skip(LAssign)
|
|
1034
1033
|
}
|
|
1035
1034
|
let operator = token.raw().dropLast(1)
|
|
@@ -1153,7 +1152,7 @@ extend self: Parser {
|
|
|
1153
1152
|
True
|
|
1154
1153
|
} else {False}
|
|
1155
1154
|
mutable result = self.parseAtom()
|
|
1156
|
-
while {self.current().
|
|
1155
|
+
while {self.current().is4(LBracketLeft, LColon, LDot, LArrowThin)} {
|
|
1157
1156
|
if(self.current().is(LDot)) {
|
|
1158
1157
|
self.skip(LDot)
|
|
1159
1158
|
if(self.current().rawIs("{")) {
|
|
@@ -1166,6 +1165,8 @@ extend self: Parser {
|
|
|
1166
1165
|
let token = self.skip(LLower)
|
|
1167
1166
|
result = EField(token.at(), False, result, token.raw())
|
|
1168
1167
|
}
|
|
1168
|
+
} elseIf {self.current().is(LArrowThin)} {
|
|
1169
|
+
result = self.parseDynamicMember(result)
|
|
1169
1170
|
} else {
|
|
1170
1171
|
let at = self.current().at()
|
|
1171
1172
|
let typeArguments = if(!self.current().rawIs("[")) {[]} else {self.parseTypeArguments()}
|
|
@@ -1181,6 +1182,46 @@ extend self: Parser {
|
|
|
1181
1182
|
}
|
|
1182
1183
|
result
|
|
1183
1184
|
}
|
|
1185
|
+
|
|
1186
|
+
parseDynamicMember(record: Term): Term {
|
|
1187
|
+
self.skip(LArrowThin)
|
|
1188
|
+
let token = self.skip(LLower)
|
|
1189
|
+
let member = EString(token.at(), "\"" + token.raw() + "\"")
|
|
1190
|
+
if(self.current().rawIs("(")) {
|
|
1191
|
+
let arguments = self.parseFunctionArguments(record.at, False)
|
|
1192
|
+
let effect = self.freshUnificationVariable(record.at)
|
|
1193
|
+
let target = DynamicCall(EField(token.at(), False, record, "call" + arguments.first.size()), False)
|
|
1194
|
+
ECall(record.at, target, effect, [], [
|
|
1195
|
+
Argument(member.at, None, member)
|
|
1196
|
+
...arguments.first
|
|
1197
|
+
], [])
|
|
1198
|
+
} elseIf {self.current().is3(LAssign, LAssignPlus, LAssignMinus)} {
|
|
1199
|
+
let method =
|
|
1200
|
+
if(self.current().is(LAssign)) {
|
|
1201
|
+
self.skip(LAssign)
|
|
1202
|
+
"set"
|
|
1203
|
+
} elseIf {self.current().is(LAssignPlus)} {
|
|
1204
|
+
self.skip(LAssignPlus)
|
|
1205
|
+
"increment"
|
|
1206
|
+
} else {
|
|
1207
|
+
self.skip(LAssignMinus)
|
|
1208
|
+
"decrement"
|
|
1209
|
+
}
|
|
1210
|
+
let value = self.parseTerm()
|
|
1211
|
+
let effect = self.freshUnificationVariable(record.at)
|
|
1212
|
+
let target = DynamicCall(EField(token.at(), False, record, "set"), False)
|
|
1213
|
+
ECall(record.at, target, effect, [], [
|
|
1214
|
+
Argument(member.at, None, member)
|
|
1215
|
+
Argument(value.at, None, value)
|
|
1216
|
+
], [])
|
|
1217
|
+
} else {
|
|
1218
|
+
let effect = self.freshUnificationVariable(record.at)
|
|
1219
|
+
let target = DynamicCall(EField(token.at(), False, record, "get"), False)
|
|
1220
|
+
ECall(record.at, target, effect, [], [
|
|
1221
|
+
Argument(member.at, None, member)
|
|
1222
|
+
], [])
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1184
1225
|
|
|
1185
1226
|
parseAtom(): Term {
|
|
1186
1227
|
if(self.current().is(LString)) {
|
package/compiler/Token.ff
CHANGED
|
@@ -38,6 +38,10 @@ extend token: Token {
|
|
|
38
38
|
token.kind == kind1 || token.kind == kind2 || token.kind == kind3
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
is4(kind1: TokenKind, kind2: TokenKind, kind3: TokenKind, kind4: TokenKind): Bool {
|
|
42
|
+
token.kind == kind1 || token.kind == kind2 || token.kind == kind3 || token.kind == kind4
|
|
43
|
+
}
|
|
44
|
+
|
|
41
45
|
rawIs(value: String): Bool {
|
|
42
46
|
token.stopOffset - token.startOffset == value.size() &&
|
|
43
47
|
token.code.startsWith(value, token.startOffset)
|
|
@@ -78,11 +82,11 @@ data TokenKind {
|
|
|
78
82
|
LPipe
|
|
79
83
|
LColon
|
|
80
84
|
LDotDotDot
|
|
85
|
+
LArrowThin
|
|
81
86
|
LArrowThick
|
|
82
87
|
LAssign
|
|
83
88
|
LAssignPlus
|
|
84
89
|
LAssignMinus
|
|
85
|
-
LAssignLink
|
|
86
90
|
}
|
|
87
91
|
|
|
88
92
|
extend self: TokenKind {
|
|
@@ -109,11 +113,11 @@ extend self: TokenKind {
|
|
|
109
113
|
| LPipe => False
|
|
110
114
|
| LColon => False
|
|
111
115
|
| LDotDotDot => False
|
|
116
|
+
| LArrowThin => False
|
|
112
117
|
| LArrowThick => False
|
|
113
118
|
| LAssign => False
|
|
114
119
|
| LAssignPlus => False
|
|
115
120
|
| LAssignMinus => False
|
|
116
|
-
| LAssignLink => False
|
|
117
121
|
}
|
|
118
122
|
}
|
|
119
123
|
|
|
@@ -139,11 +143,11 @@ extend self: TokenKind {
|
|
|
139
143
|
| LPipe => False
|
|
140
144
|
| LColon => False
|
|
141
145
|
| LDotDotDot => True
|
|
146
|
+
| LArrowThin => False
|
|
142
147
|
| LArrowThick => False
|
|
143
148
|
| LAssign => False
|
|
144
149
|
| LAssignPlus => False
|
|
145
150
|
| LAssignMinus => False
|
|
146
|
-
| LAssignLink => False
|
|
147
151
|
}
|
|
148
152
|
}
|
|
149
153
|
|
|
@@ -169,11 +173,11 @@ extend self: TokenKind {
|
|
|
169
173
|
| LPipe => False
|
|
170
174
|
| LColon => False
|
|
171
175
|
| LDotDotDot => False
|
|
176
|
+
| LArrowThin => False
|
|
172
177
|
| LArrowThick => False
|
|
173
178
|
| LAssign => False
|
|
174
179
|
| LAssignPlus => False
|
|
175
180
|
| LAssignMinus => False
|
|
176
|
-
| LAssignLink => False
|
|
177
181
|
}
|
|
178
182
|
}
|
|
179
183
|
|
package/compiler/Tokenizer.ff
CHANGED
|
@@ -226,6 +226,8 @@ tokenize(file: String, code: String, completionAt: Option[Location], attemptFixe
|
|
|
226
226
|
LColon
|
|
227
227
|
} elseIf {i - start == 3 && code.grab(i - 3) == '.' && code.grab(i - 2) == '.' && code.grab(i - 1) == '.'} {
|
|
228
228
|
LDotDotDot
|
|
229
|
+
} elseIf {i - start == 2 && code.grab(i - 2) == '-' && code.grab(i - 1) == '>'} {
|
|
230
|
+
LArrowThin
|
|
229
231
|
} elseIf {i - start == 2 && code.grab(i - 2) == '=' && code.grab(i - 1) == '>'} {
|
|
230
232
|
LArrowThick
|
|
231
233
|
} elseIf {i - start == 1 && code.grab(i - 1) == '='} {
|
|
@@ -234,8 +236,6 @@ tokenize(file: String, code: String, completionAt: Option[Location], attemptFixe
|
|
|
234
236
|
LAssignPlus
|
|
235
237
|
} elseIf {i - start == 2 && code.grab(i - 2) == '-' && code.grab(i - 1) == '='} {
|
|
236
238
|
LAssignMinus
|
|
237
|
-
} elseIf {i - start == 3 && code.grab(i - 3) == ':' && code.grab(i - 2) == ':' && code.grab(i - 1) == '='} {
|
|
238
|
-
LAssignLink
|
|
239
239
|
} else {
|
|
240
240
|
LOperator
|
|
241
241
|
}
|
package/core/JsSystem.ff
CHANGED
|
@@ -5,6 +5,18 @@ extend self: JsSystem {
|
|
|
5
5
|
global(): JsValue
|
|
6
6
|
target js sync "return self_"
|
|
7
7
|
|
|
8
|
+
get(key: String): JsValue
|
|
9
|
+
target js sync "return self_[key_]"
|
|
10
|
+
|
|
11
|
+
set[V: IsJsValue](key: String, value: V): Unit
|
|
12
|
+
target js sync "self_[key_] = value_"
|
|
13
|
+
|
|
14
|
+
increment[V: IsJsValue](key: String, value: V): Unit
|
|
15
|
+
target js sync "self_[key_] += value_"
|
|
16
|
+
|
|
17
|
+
decrement[V: IsJsValue](key: String, value: V): Unit
|
|
18
|
+
target js sync "self_[key_] -= value_"
|
|
19
|
+
|
|
8
20
|
parseJson(json: String): JsValue
|
|
9
21
|
target js sync "return JSON.parse(json_)"
|
|
10
22
|
|
package/core/JsValue.ff
CHANGED
|
@@ -88,6 +88,12 @@ extend self: JsValue {
|
|
|
88
88
|
set[K: IsJsValue, V: IsJsValue](key: K, value: V): Unit
|
|
89
89
|
target js sync "self_[key_] = value_"
|
|
90
90
|
|
|
91
|
+
increment[K: IsJsValue, V: IsJsValue](key: K, value: V): Unit
|
|
92
|
+
target js sync "self_[key_] += value_"
|
|
93
|
+
|
|
94
|
+
decrement[K: IsJsValue, V: IsJsValue](key: K, value: V): Unit
|
|
95
|
+
target js sync "self_[key_] -= value_"
|
|
96
|
+
|
|
91
97
|
delete[K: IsJsValue](key: K): Unit
|
|
92
98
|
target js sync "delete self_[key_]"
|
|
93
99
|
|
package/lux/Lux.ff
CHANGED
|
@@ -15,6 +15,7 @@ capability Lux(
|
|
|
15
15
|
mutable keys: Option[StringMap[JsValue]]
|
|
16
16
|
mutable key: String
|
|
17
17
|
mutable attributes: Option[StringMap[String]]
|
|
18
|
+
mutable texts: Array[String]
|
|
18
19
|
)
|
|
19
20
|
|
|
20
21
|
capability RenderQueueItem(
|
|
@@ -71,16 +72,16 @@ extend self: DryNode {
|
|
|
71
72
|
|
|
72
73
|
extend self: LuxElement {
|
|
73
74
|
childAt(index: Int): JsValue {
|
|
74
|
-
self.element
|
|
75
|
+
self.element->childNodes.get(index)
|
|
75
76
|
}
|
|
76
77
|
insertBefore(newNode: JsValue, referenceNode: JsValue): JsValue {
|
|
77
|
-
self.element
|
|
78
|
+
self.element->insertBefore(newNode, referenceNode)
|
|
78
79
|
}
|
|
79
80
|
removeAt(index: Int): Bool {
|
|
80
81
|
let node = self.childAt(index)
|
|
81
82
|
let remove = !node.isNullOrUndefined()
|
|
82
83
|
if(remove) {
|
|
83
|
-
self.element
|
|
84
|
+
self.element->removeChild(node)
|
|
84
85
|
}
|
|
85
86
|
remove
|
|
86
87
|
}
|
|
@@ -88,15 +89,15 @@ extend self: LuxElement {
|
|
|
88
89
|
|
|
89
90
|
extend self: LuxDocument {
|
|
90
91
|
createTextNode(value: String): JsValue {
|
|
91
|
-
self.document
|
|
92
|
+
self.document->createTextNode(value)
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
createElement(tagName: String): JsValue {
|
|
95
|
-
self.document
|
|
96
|
+
self.document->createElement(tagName)
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
createFragment(): JsValue {
|
|
99
|
-
self.document
|
|
100
|
+
self.document->createDocumentFragment()
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
103
|
|
|
@@ -113,27 +114,28 @@ extend self: Lux {
|
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
text(value: String) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
let oldValue = if(!oldNode.isNullOrUndefined()) {oldNode.get("data")} else {oldNode}
|
|
119
|
-
if(oldValue.isNullOrUndefined() || oldValue.grabString() != value) {
|
|
120
|
-
let node = self.document.createTextNode(value)
|
|
121
|
-
self.element.insertBefore(node, oldNode)
|
|
117
|
+
if(value.size() != 0) {
|
|
118
|
+
self.texts.push(value)
|
|
122
119
|
}
|
|
123
|
-
self.element.child += 1
|
|
124
120
|
}
|
|
125
121
|
|
|
126
122
|
add(tagName: String, body: () => Unit = {}) {
|
|
123
|
+
patchText(self)
|
|
127
124
|
self.dry.map {dry =>
|
|
128
125
|
self.dry = Some([].toArray())
|
|
129
126
|
let savedAttributes = self.attributes
|
|
130
127
|
let savedKeys = self.keys
|
|
131
|
-
self.attributes =
|
|
128
|
+
self.attributes = if(self.key != "") {
|
|
129
|
+
let attributes = StringMap.new()
|
|
130
|
+
attributes.set("data-lux-key", tagName.upper() + ">" + self.key)
|
|
131
|
+
attributes
|
|
132
|
+
}
|
|
132
133
|
self.key = ""
|
|
133
134
|
self.depth += 1
|
|
134
135
|
try {
|
|
135
136
|
body()
|
|
136
137
|
} finally {
|
|
138
|
+
patchText(self)
|
|
137
139
|
dry.push(DryElement(tagName, self.attributes.else {StringMap.new()}, self.dry.grab()))
|
|
138
140
|
self.depth -= 1
|
|
139
141
|
self.attributes = savedAttributes
|
|
@@ -143,23 +145,24 @@ extend self: Lux {
|
|
|
143
145
|
}
|
|
144
146
|
}.else:
|
|
145
147
|
let node = patchElement(self, tagName)
|
|
146
|
-
if(!node
|
|
147
|
-
node
|
|
148
|
-
node
|
|
148
|
+
if(!node->luxHandlers.isNullOrUndefined()) {
|
|
149
|
+
node->luxHandlers.grabArray().each {pair =>
|
|
150
|
+
node->removeEventListener(pair->event, pair->handler)
|
|
149
151
|
}
|
|
150
|
-
node
|
|
152
|
+
node->luxHandlers = self.jsSystem.array([])
|
|
151
153
|
}
|
|
152
154
|
let savedAttributes = self.attributes
|
|
153
155
|
let savedKeys = self.keys
|
|
154
156
|
let savedElement = self.element
|
|
155
157
|
self.attributes = None
|
|
156
158
|
self.element = LuxElement(node, 0, keepChildren = False)
|
|
157
|
-
self.element.element
|
|
159
|
+
self.element.element->classList->value = ""
|
|
158
160
|
self.key = ""
|
|
159
161
|
self.depth += 1
|
|
160
162
|
try {
|
|
161
163
|
body()
|
|
162
164
|
} finally {
|
|
165
|
+
patchText(self)
|
|
163
166
|
if(!self.element.keepChildren) {
|
|
164
167
|
doWhile {removeCurrentChild(self)}
|
|
165
168
|
}
|
|
@@ -212,7 +215,7 @@ extend self: Lux {
|
|
|
212
215
|
|
|
213
216
|
setValue(value: String) { // TODO: Not an attribute
|
|
214
217
|
self.dry.map {_ => self.set("value", value)}.else:
|
|
215
|
-
self.element.element
|
|
218
|
+
self.element.element->value = value
|
|
216
219
|
}
|
|
217
220
|
|
|
218
221
|
css(style: Css) {
|
|
@@ -233,15 +236,15 @@ extend self: Lux {
|
|
|
233
236
|
self.cssClasses.set(class.name(), class)
|
|
234
237
|
if(self.dry.isEmpty()):
|
|
235
238
|
let styleSheet = self.document.createElement("style")
|
|
236
|
-
styleSheet
|
|
237
|
-
self.document.document
|
|
239
|
+
styleSheet->textContent = class.show()
|
|
240
|
+
self.document.document->head->appendChild(styleSheet)
|
|
238
241
|
}
|
|
239
242
|
if(!self.dry.isEmpty()) {
|
|
240
243
|
let classNames = self.attributes.flatMap {_.get("class")}.else {""}
|
|
241
244
|
self.set("class", (classNames + " " + class.name()).trim())
|
|
242
245
|
} else {
|
|
243
|
-
self.element.element
|
|
244
|
-
self.set("class", self.element.element
|
|
246
|
+
self.element.element->classList->add(class.name())
|
|
247
|
+
self.set("class", self.element.element->className.grabString())
|
|
245
248
|
}
|
|
246
249
|
}
|
|
247
250
|
|
|
@@ -253,11 +256,11 @@ extend self: Lux {
|
|
|
253
256
|
processRenderQueue(self)
|
|
254
257
|
}
|
|
255
258
|
}
|
|
256
|
-
self.element.element
|
|
257
|
-
if(self.element.element
|
|
258
|
-
self.element.element
|
|
259
|
+
self.element.element->addEventListener(event, jsHandler)
|
|
260
|
+
if(self.element.element->luxHandlers.isNullOrUndefined()) {
|
|
261
|
+
self.element.element->luxHandlers = self.jsSystem.array([])
|
|
259
262
|
}
|
|
260
|
-
self.element.element
|
|
263
|
+
self.element.element->luxHandlers->push(
|
|
261
264
|
self.jsSystem.object().with("event", event).with("handler", jsHandler)
|
|
262
265
|
)
|
|
263
266
|
}
|
|
@@ -410,7 +413,7 @@ processRenderQueue(self: Lux) {
|
|
|
410
413
|
|
|
411
414
|
removeCurrentChild(self: Lux): Bool {
|
|
412
415
|
let child = self.element.childAt(self.element.child)
|
|
413
|
-
if(!child.isNullOrUndefined() && !child
|
|
416
|
+
if(!child.isNullOrUndefined() && !child->children.isNullOrUndefined()) {
|
|
414
417
|
abortTasksOnElement(self, child, False)
|
|
415
418
|
}
|
|
416
419
|
self.element.removeAt(self.element.child)
|
|
@@ -429,21 +432,21 @@ setStateOnElement[T /*: HasAnyTag*/](element: JsValue, depth: Int, value: T): Un
|
|
|
429
432
|
|
|
430
433
|
|
|
431
434
|
getTaskOnElement(element: JsValue): Option[Task] {
|
|
432
|
-
let value = element
|
|
435
|
+
let value = element->luxTask
|
|
433
436
|
if(value.isNullOrUndefined()) {None} else {
|
|
434
437
|
unsafeJsToValue(value)
|
|
435
438
|
}
|
|
436
439
|
}
|
|
437
440
|
|
|
438
441
|
setTaskOnElement(element: JsValue, task: Option[Task]): Unit {
|
|
439
|
-
element
|
|
442
|
+
element->luxTask = unsafeJsFromValue(task)
|
|
440
443
|
}
|
|
441
444
|
|
|
442
445
|
abortTasksOnElement(lux: Lux, element: JsValue, onlyChildren: Bool): Unit {
|
|
443
446
|
if(!onlyChildren) {
|
|
444
447
|
getTaskOnElement(element).each {task => forceAsyncAbort(lux, task)}
|
|
445
448
|
}
|
|
446
|
-
element
|
|
449
|
+
element->children.each {child =>
|
|
447
450
|
abortTasksOnElement(lux, child, False)
|
|
448
451
|
}
|
|
449
452
|
}
|
|
@@ -460,19 +463,34 @@ unsafeAsyncFunction1ToJs[R](self: Lux, body: JsValue => R): JsValue
|
|
|
460
463
|
forceAsyncAbort(self: Lux, task: Task): Unit {
|
|
461
464
|
task.abort()
|
|
462
465
|
}
|
|
463
|
-
|
|
466
|
+
|
|
467
|
+
patchText(self: Lux) {
|
|
468
|
+
if(!self.texts.isEmpty()):
|
|
469
|
+
let value = self.texts.drain().join()
|
|
470
|
+
self.dry.map {_.push(DryText(value))}.else:
|
|
471
|
+
let oldNode = self.element.childAt(self.element.child)
|
|
472
|
+
let oldValue = if(!oldNode.isNullOrUndefined()) {oldNode->data} else {oldNode}
|
|
473
|
+
if(oldValue.isNullOrUndefined() || oldValue.grabString() != value) {
|
|
474
|
+
let node = self.document.createTextNode(value)
|
|
475
|
+
self.element.insertBefore(node, oldNode)
|
|
476
|
+
}
|
|
477
|
+
self.element.child += 1
|
|
478
|
+
}
|
|
479
|
+
|
|
464
480
|
patchElement(self: Lux, tagName: String): JsValue {
|
|
465
481
|
let newKey = if(self.key != "") {tagName.upper() + ">" + self.key} else {""}
|
|
466
482
|
let oldNode = self.element.childAt(self.element.child)
|
|
467
|
-
let oldKey = if(!oldNode.isNullOrUndefined()
|
|
483
|
+
let oldKey = if(!oldNode.isNullOrUndefined() && !oldNode->getAttribute.isNullOrUndefined()) {
|
|
484
|
+
oldNode->getAttribute("data-lux-key")
|
|
485
|
+
} else {oldNode}
|
|
468
486
|
let match = if(newKey != "") {
|
|
469
487
|
!oldKey.isNullOrUndefined() &&
|
|
470
488
|
oldKey.grabString() == newKey
|
|
471
489
|
} else {
|
|
472
490
|
oldKey.isNullOrUndefined() &&
|
|
473
491
|
!oldNode.isNullOrUndefined() &&
|
|
474
|
-
!oldNode
|
|
475
|
-
oldNode
|
|
492
|
+
!oldNode->tagName.isNullOrUndefined() &&
|
|
493
|
+
oldNode->tagName.grabString() == tagName.upper()
|
|
476
494
|
}
|
|
477
495
|
if(match) {
|
|
478
496
|
oldNode
|
|
@@ -483,8 +501,10 @@ patchElement(self: Lux, tagName: String): JsValue {
|
|
|
483
501
|
mutable i = self.element.child
|
|
484
502
|
mutable c = self.element.childAt(i)
|
|
485
503
|
while {!c.isNullOrUndefined()} {
|
|
486
|
-
|
|
487
|
-
|
|
504
|
+
if(!c->getAttribute.isNullOrUndefined()) {
|
|
505
|
+
let k = c->getAttribute("data-lux-key")
|
|
506
|
+
if(!k.isNullOrUndefined()) {map.set(k.grabString(), c)}
|
|
507
|
+
}
|
|
488
508
|
c = self.element.childAt(i)
|
|
489
509
|
i += 1
|
|
490
510
|
}
|
|
@@ -497,7 +517,7 @@ patchElement(self: Lux, tagName: String): JsValue {
|
|
|
497
517
|
foundNode
|
|
498
518
|
} else {
|
|
499
519
|
let createdNode = self.document.createElement(tagName)
|
|
500
|
-
createdNode
|
|
520
|
+
createdNode->setAttribute("data-lux-key", newKey)
|
|
501
521
|
createdNode
|
|
502
522
|
}
|
|
503
523
|
}
|
|
@@ -507,28 +527,28 @@ patchElement(self: Lux, tagName: String): JsValue {
|
|
|
507
527
|
}
|
|
508
528
|
|
|
509
529
|
patchAttributes(self: Lux) {
|
|
510
|
-
let attributes = self.element.element
|
|
530
|
+
let attributes = self.element.element->attributes
|
|
511
531
|
self.attributes.{
|
|
512
532
|
| None =>
|
|
513
|
-
mutable i = attributes
|
|
533
|
+
mutable i = attributes->length.grabInt() - 1
|
|
514
534
|
while {i >= 0} {
|
|
515
535
|
let attribute = attributes.get(i)
|
|
516
|
-
self.element.element
|
|
536
|
+
self.element.element->removeAttribute(attribute->name)
|
|
517
537
|
i -= 1
|
|
518
538
|
}
|
|
519
539
|
| Some(map) =>
|
|
520
|
-
mutable i = attributes
|
|
540
|
+
mutable i = attributes->length.grabInt() - 1
|
|
521
541
|
while {i >= 0} {
|
|
522
542
|
let attribute = attributes.get(i)
|
|
523
|
-
if(!map.has(attribute
|
|
524
|
-
self.element.element
|
|
543
|
+
if(!map.has(attribute->name.grabString())) {
|
|
544
|
+
self.element.element->removeAttribute(attribute->name)
|
|
525
545
|
}
|
|
526
546
|
i -= 1
|
|
527
547
|
}
|
|
528
548
|
map.each {name, value =>
|
|
529
|
-
let oldValue = self.element.element
|
|
549
|
+
let oldValue = self.element.element->getAttribute(name)
|
|
530
550
|
if(oldValue.isNullOrUndefined() || !oldValue.equals(value)) {
|
|
531
|
-
self.element.element
|
|
551
|
+
self.element.element->setAttribute(name, value)
|
|
532
552
|
}
|
|
533
553
|
}
|
|
534
554
|
}
|
|
@@ -536,14 +556,14 @@ patchAttributes(self: Lux) {
|
|
|
536
556
|
|
|
537
557
|
render(browserSystem: BrowserSystem, element: JsValue, body: Lux => Unit) {
|
|
538
558
|
mutable document = element
|
|
539
|
-
while {!document
|
|
540
|
-
document = document
|
|
559
|
+
while {!document->parentNode.isNullOrUndefined()} {
|
|
560
|
+
document = document->parentNode
|
|
541
561
|
}
|
|
542
562
|
// [...document.querySelectorAll("[lux-class]")].map(x => x.getAttribute("lux-class"))
|
|
543
563
|
let staticCssClasses = StringMap.new()
|
|
544
564
|
let dummyCssClass = CssClass([], [], [])
|
|
545
|
-
document
|
|
546
|
-
staticCssClasses.set(e
|
|
565
|
+
document->querySelectorAll("[lux-class]").each {e =>
|
|
566
|
+
staticCssClasses.set(e->getAttribute("lux-class").grabString(), dummyCssClass)
|
|
547
567
|
}
|
|
548
568
|
let lux = Lux(
|
|
549
569
|
jsSystem = browserSystem.js()
|
|
@@ -557,15 +577,17 @@ render(browserSystem: BrowserSystem, element: JsValue, body: Lux => Unit) {
|
|
|
557
577
|
keys = None
|
|
558
578
|
key = ""
|
|
559
579
|
attributes = None
|
|
580
|
+
texts = Array.new()
|
|
560
581
|
renderQueue = Array.new()
|
|
561
582
|
)
|
|
562
583
|
lux.renderLock.do(reentrant = False) {
|
|
563
584
|
body(lux)
|
|
585
|
+
patchText(lux)
|
|
564
586
|
}
|
|
565
587
|
}
|
|
566
588
|
|
|
567
589
|
renderById(browserSystem: BrowserSystem, id: String, body: Lux => Unit) {
|
|
568
|
-
let element = browserSystem.js()
|
|
590
|
+
let element = browserSystem.js()->document->getElementById(id)
|
|
569
591
|
render(browserSystem, element, body)
|
|
570
592
|
}
|
|
571
593
|
|
|
@@ -583,9 +605,11 @@ renderToString(nodeSystem: NodeSystem, body: Lux => Unit): Pair[String, String]
|
|
|
583
605
|
keys = None
|
|
584
606
|
key = ""
|
|
585
607
|
attributes = None
|
|
608
|
+
texts = Array.new()
|
|
586
609
|
renderQueue = Array.new()
|
|
587
610
|
)
|
|
588
611
|
body(lux)
|
|
612
|
+
patchText(lux)
|
|
589
613
|
let styleTags = lux.cssClasses.values().map {c =>
|
|
590
614
|
"<style lux-class=\"" + c.name() + "\">" + c.show() + "</style>"
|
|
591
615
|
}.join()
|
package/lux/TestDry.ff
CHANGED
|
@@ -5,7 +5,7 @@ nodeMain(system: NodeSystem) {
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
let html = Lux.renderToString(system, render)
|
|
8
|
-
Log.trace(html)
|
|
8
|
+
Log.trace(html.first)
|
|
9
9
|
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -14,6 +14,7 @@ render(lux: Lux): Unit {
|
|
|
14
14
|
lux.set("id", "its-me")
|
|
15
15
|
lux.span {
|
|
16
16
|
lux.text("Hello")
|
|
17
|
+
lux.keyed("noegle"):
|
|
17
18
|
lux.div {
|
|
18
19
|
lux.set("id", "it's \"a-me\"")
|
|
19
20
|
lux.span {
|