Skip to content

Commit 1ebe48e

Browse files
author
Joscha Rohmann
committed
Updating/Insetring of wrong nodes fixed. Closes #104.
Added an rendering type Expression.NodeWise that will return an array with the values positioned in the order of the node when passed to Expression.GetValue. Expressios objects now have a property nodeLength and chunks of expressions now have an array nodePositions containing the the position of the nodes the expression updates. Updated VirtualElement.syncChildren to delete all nodes related to an expression and to update all nodes of an expression with a changed value.
1 parent c552b7d commit 1ebe48e

File tree

2 files changed

+85
-22
lines changed

2 files changed

+85
-22
lines changed

src/query/Expression.js

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ define([
88
var Expression = {
99
Html: 0,
1010
ValueOnly: 2,
11+
NodeWise: 4,
1112

1213
Create: function (text, attributeName, element) {
1314
var index = -1;
@@ -36,12 +37,16 @@ define([
3637

3738
character = text.substring(endIndex, startIndex - 2);
3839
if (character) {
39-
result.push(character);
40+
result.push({
41+
value: character,
42+
nodePositions: []
43+
});
4044
}
4145

4246
result.push({
4347
expression: match,
44-
attributeName: attributeName
48+
attributeName: attributeName,
49+
nodePositions: []
4550
});
4651

4752
endIndex = index + 2;
@@ -52,35 +57,70 @@ define([
5257

5358
character = text.substring(endIndex);
5459
if (character) {
55-
result.push(character);
60+
result.push({
61+
value: character,
62+
nodePositions: []
63+
});
5664
}
5765

5866
result.text = text;
5967
result.attributeName = attributeName;
6068
result.element = element;
6169
result.isExpression = true;
70+
result.nodeLength = 0;
6271
return match ? result : null;
6372
},
6473

6574
GetValue: function (context, elementData, expression, type) {
66-
var value = '';
75+
var nodeWise = type == Expression.NodeWise;
76+
var value = nodeWise ? [] : '';
6777
var length = expression.length;
6878
var index = -1;
6979
var chunk;
80+
var nodeIndex;
81+
type = type||Expression.Html;
7082

7183
if (!context) {
7284
return expression.text;
7385
}
74-
86+
87+
if (type == Expression.Html) {
88+
expression.nodeLength = 0;
89+
}
90+
7591
if (length == 1) {
76-
value = Expression.Execute(context, elementData, expression[0], expression, type);
92+
if (nodeWise) {
93+
value[0] = Expression.Execute(context, elementData, expression[0], expression, nodeWise ? Expression.ValueOnly : type);
94+
} else {
95+
value = Expression.Execute(context, elementData, expression[0], expression, nodeWise ? Expression.ValueOnly : type);
96+
}
7797
} else {
7898
while (++index < length) {
7999
chunk = expression[index];
80-
if (typeof chunk == 'string') {
81-
value += chunk;
100+
if (chunk.value) {
101+
if (nodeWise) {
102+
// static text can only have one node
103+
nodeIndex = chunk.nodePositions[0];
104+
value[nodeIndex] = (value[nodeIndex]||'') + chunk.value;
105+
} else {
106+
value += chunk.value;
107+
}
108+
109+
if (type == Expression.Html) {
110+
chunk.nodePositions = []; // resetting nodeIndecies. Seeing currently no other way for resettings for the edge case descriped in https://github.com/astoilkov/jsblocks/issues/104#issuecomment-150715660
111+
chunk.nodePositions.push(expression.nodeLength === 0 ? expression.nodeLength++ : expression.nodeLength - 1);
112+
}
82113
} else {
83-
value += Expression.Execute(context, elementData, chunk, expression, type);
114+
if (nodeWise) {
115+
// If more then one node (observable) update value node
116+
nodeIndex = chunk.nodePositions[chunk.nodePositions.length - 1];
117+
if (chunk.nodePositions.length == 2) {
118+
value[nodeIndex - 1] = null; // the comment node should be skipped
119+
}
120+
value[nodeIndex] = (value[nodeIndex]||'') + Expression.Execute(context, elementData, chunk, expression, Expression.ValueOnly);
121+
} else {
122+
value += Expression.Execute(context, elementData, chunk, expression, type);
123+
}
84124
}
85125
}
86126
}
@@ -150,10 +190,17 @@ define([
150190
});
151191
}
152192
if (!attributeName) {
193+
if (type == Expression.Html) {
194+
expressionData.nodePositions = []; //resetting nodeIndecies. Seeing currently no other way for resettings for the edge case descriped in https://github.com/astoilkov/jsblocks/issues/104#issuecomment-150715660
195+
expressionData.nodePositions.push(entireExpression.nodeLength++, entireExpression.nodeLength++); // two new nodes
196+
}
153197
result = '<!-- ' + elementData.id + ':blocks -->' + result;
154198
}
199+
} else if (!attributeName && type == Expression.Html) {
200+
expressionData.nodePositions = [];
201+
expressionData.nodePositions.push(entireExpression.nodeLength === 0 ? entireExpression.nodeLength++ : entireExpression.nodeLength - 1);
155202
}
156-
203+
157204
return result;
158205
}
159206
};

src/query/VirtualElement.js

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -451,35 +451,47 @@ define([
451451
var children = this._template || this._children;
452452
var length = children.length;
453453
var state = this._state;
454-
var element = this._el.nodeType == 8 ? this._el.nextSibling : this._el.childNodes[offset || 0];
454+
var element = this._el.nodeType == 8 ? this._el : this._el.childNodes[offset || 0];
455455
var index = -1;
456456
var elementForDeletion;
457+
var deletionCount;
458+
var fragment;
457459
var expression;
458460
var child;
461+
var lastExpression;
459462

460463
while (++index < length) {
461464
child = children[index];
462465
if (child.isExpression) {
463466
if (domQuery) {
464-
expression = Expression.GetValue(domQuery._context, null, child, state ? Expression.ValueOnly : Expression.Html);
467+
expression = Expression.GetValue(domQuery._context, null, child, state ? Expression.NodeWise : Expression.Html);
465468

466469
if (!state || (state && state.expressions[index] !== expression)) {
467470
if (state) {
471+
lastExpression = state.expressions[index];
468472
state.expressions[index] = expression;
469473
if (element) {
470-
if (element.nodeType == 8) {
474+
blocks.each(expression, function (value, key) {
475+
// skipp comment (= null values) & unchanged nodes
476+
if (value == null || element.nodeType == 8 || (blocks.isArray(lastExpression) && lastExpression[key] == value)) {
477+
element = element.nextSibling;
478+
return;
479+
}
480+
element.nodeValue = value;
471481
element = element.nextSibling;
472-
}
473-
element.nodeValue = expression;
474-
element = element.nextSibling;
482+
});
475483
} else {
476-
this._el.textContent = expression;
484+
this._el.textContent = expression.join();
477485
}
478486
} else {
479-
this._el.insertBefore(createFragment(expression), element);
480-
elementForDeletion = element;
481-
element = element.nextSibling;
482-
this._el.removeChild(elementForDeletion);
487+
fragment = createFragment(expression);
488+
deletionCount = syncIndex ? child.nodeLength : 1;
489+
this._el.insertBefore(fragment, element);
490+
while (deletionCount-- > 0) {
491+
elementForDeletion = element;
492+
element = element.nextSibling;
493+
this._el.removeChild(elementForDeletion);
494+
}
483495
}
484496
}
485497
}
@@ -528,7 +540,11 @@ define([
528540

529541
while (++index < template.length) {
530542
if (template[index]._renderMode !== VirtualElement.RenderMode.None) {
531-
length += 1;
543+
if (template[index].isExpression && template[index].nodeLength) {
544+
length += template[index].nodeLength;
545+
} else {
546+
length += 1;
547+
}
532548
}
533549
}
534550

0 commit comments

Comments
 (0)