Skip to content

Commit

Permalink
Updating/Insetring of wrong nodes fixed. Closes astoilkov#104.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Joscha Rohmann committed Oct 24, 2015
1 parent c552b7d commit 1ebe48e
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 22 deletions.
67 changes: 57 additions & 10 deletions src/query/Expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ define([
var Expression = {
Html: 0,
ValueOnly: 2,
NodeWise: 4,

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

character = text.substring(endIndex, startIndex - 2);
if (character) {
result.push(character);
result.push({
value: character,
nodePositions: []
});
}

result.push({
expression: match,
attributeName: attributeName
attributeName: attributeName,
nodePositions: []
});

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

character = text.substring(endIndex);
if (character) {
result.push(character);
result.push({
value: character,
nodePositions: []
});
}

result.text = text;
result.attributeName = attributeName;
result.element = element;
result.isExpression = true;
result.nodeLength = 0;
return match ? result : null;
},

GetValue: function (context, elementData, expression, type) {
var value = '';
var nodeWise = type == Expression.NodeWise;
var value = nodeWise ? [] : '';
var length = expression.length;
var index = -1;
var chunk;
var nodeIndex;
type = type||Expression.Html;

if (!context) {
return expression.text;
}


if (type == Expression.Html) {
expression.nodeLength = 0;
}

if (length == 1) {
value = Expression.Execute(context, elementData, expression[0], expression, type);
if (nodeWise) {
value[0] = Expression.Execute(context, elementData, expression[0], expression, nodeWise ? Expression.ValueOnly : type);
} else {
value = Expression.Execute(context, elementData, expression[0], expression, nodeWise ? Expression.ValueOnly : type);
}
} else {
while (++index < length) {
chunk = expression[index];
if (typeof chunk == 'string') {
value += chunk;
if (chunk.value) {
if (nodeWise) {
// static text can only have one node
nodeIndex = chunk.nodePositions[0];
value[nodeIndex] = (value[nodeIndex]||'') + chunk.value;
} else {
value += chunk.value;
}

if (type == Expression.Html) {
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
chunk.nodePositions.push(expression.nodeLength === 0 ? expression.nodeLength++ : expression.nodeLength - 1);
}
} else {
value += Expression.Execute(context, elementData, chunk, expression, type);
if (nodeWise) {
// If more then one node (observable) update value node
nodeIndex = chunk.nodePositions[chunk.nodePositions.length - 1];
if (chunk.nodePositions.length == 2) {
value[nodeIndex - 1] = null; // the comment node should be skipped
}
value[nodeIndex] = (value[nodeIndex]||'') + Expression.Execute(context, elementData, chunk, expression, Expression.ValueOnly);
} else {
value += Expression.Execute(context, elementData, chunk, expression, type);
}
}
}
}
Expand Down Expand Up @@ -150,10 +190,17 @@ define([
});
}
if (!attributeName) {
if (type == Expression.Html) {
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
expressionData.nodePositions.push(entireExpression.nodeLength++, entireExpression.nodeLength++); // two new nodes
}
result = '<!-- ' + elementData.id + ':blocks -->' + result;
}
} else if (!attributeName && type == Expression.Html) {
expressionData.nodePositions = [];
expressionData.nodePositions.push(entireExpression.nodeLength === 0 ? entireExpression.nodeLength++ : entireExpression.nodeLength - 1);
}

return result;
}
};
Expand Down
40 changes: 28 additions & 12 deletions src/query/VirtualElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -451,35 +451,47 @@ define([
var children = this._template || this._children;
var length = children.length;
var state = this._state;
var element = this._el.nodeType == 8 ? this._el.nextSibling : this._el.childNodes[offset || 0];
var element = this._el.nodeType == 8 ? this._el : this._el.childNodes[offset || 0];
var index = -1;
var elementForDeletion;
var deletionCount;
var fragment;
var expression;
var child;
var lastExpression;

while (++index < length) {
child = children[index];
if (child.isExpression) {
if (domQuery) {
expression = Expression.GetValue(domQuery._context, null, child, state ? Expression.ValueOnly : Expression.Html);
expression = Expression.GetValue(domQuery._context, null, child, state ? Expression.NodeWise : Expression.Html);

if (!state || (state && state.expressions[index] !== expression)) {
if (state) {
lastExpression = state.expressions[index];
state.expressions[index] = expression;
if (element) {
if (element.nodeType == 8) {
blocks.each(expression, function (value, key) {
// skipp comment (= null values) & unchanged nodes
if (value == null || element.nodeType == 8 || (blocks.isArray(lastExpression) && lastExpression[key] == value)) {
element = element.nextSibling;
return;
}
element.nodeValue = value;
element = element.nextSibling;
}
element.nodeValue = expression;
element = element.nextSibling;
});
} else {
this._el.textContent = expression;
this._el.textContent = expression.join();
}
} else {
this._el.insertBefore(createFragment(expression), element);
elementForDeletion = element;
element = element.nextSibling;
this._el.removeChild(elementForDeletion);
fragment = createFragment(expression);
deletionCount = syncIndex ? child.nodeLength : 1;
this._el.insertBefore(fragment, element);
while (deletionCount-- > 0) {
elementForDeletion = element;
element = element.nextSibling;
this._el.removeChild(elementForDeletion);
}
}
}
}
Expand Down Expand Up @@ -528,7 +540,11 @@ define([

while (++index < template.length) {
if (template[index]._renderMode !== VirtualElement.RenderMode.None) {
length += 1;
if (template[index].isExpression && template[index].nodeLength) {
length += template[index].nodeLength;
} else {
length += 1;
}
}
}

Expand Down

0 comments on commit 1ebe48e

Please sign in to comment.