mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
Fixes #419 - Deprecate w-preserve/w-preserve-if/w-preserve-body/w-preserve-body-if in favor of no-update-*. (#433)
This commit is contained in:
parent
c35bbf0b9d
commit
3eb3c286e8
@ -373,12 +373,12 @@ Sometimes it is important to _not_ re-render a DOM subtree. This may due to eith
|
||||
- DOM nodes contains externally provided content
|
||||
- DOM nodes have internal state that needs to be maintained
|
||||
|
||||
Marko Widgets allows DOM nodes to be preserved by putting a special `w-preserve`, `w-preserve-if(<condition>)`, `w-preserve-body` or `w-preserve-body-if(<condition>)` attribute on the HTML tags that should be preserved. Preserved DOM nodes will be reused and re-inserted into a widget's newly rendered DOM automatically.
|
||||
Marko Widgets allows DOM nodes to be preserved by putting a special `no-update`, `no-update-if(<condition>)`, `no-update-body` or `no-update-body-if(<condition>)` attribute on the HTML tags that should be preserved. Preserved DOM nodes will be reused and re-inserted into a widget's newly rendered DOM automatically.
|
||||
|
||||
```xml
|
||||
<div w-bind>
|
||||
|
||||
<span w-preserve>
|
||||
<span no-update>
|
||||
<p>
|
||||
The root span and all its children will never
|
||||
be re-rendered.
|
||||
@ -387,7 +387,7 @@ Marko Widgets allows DOM nodes to be preserved by putting a special `w-preserve`
|
||||
Rendered at ${Date.now()}.
|
||||
</p>
|
||||
</span>
|
||||
<div w-preserve-body>
|
||||
<div no-update-body>
|
||||
Only the children of the div will preserved and
|
||||
the outer HTML div tag will be re-rendered.
|
||||
</div>
|
||||
@ -395,7 +395,7 @@ Marko Widgets allows DOM nodes to be preserved by putting a special `w-preserve`
|
||||
Don't rerender the search results if no search results
|
||||
are provided.
|
||||
<app-search-results items="data.searchResults"
|
||||
w-preserve-if(data.searchResults == null)/>
|
||||
no-update-if(data.searchResults == null)/>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
@ -123,9 +123,9 @@ For the example above it is assumed that the nested widget will emit the custom
|
||||
this.emit('handleSomeCustomEvent', { foo: bar });
|
||||
```
|
||||
|
||||
<a name="w-preserve"></a>
|
||||
<a name="no-update"></a>
|
||||
|
||||
## w-preserve
|
||||
## no-update
|
||||
|
||||
Preserves the DOM subtree associated with the DOM element or widget such that it won't be modified or rerendered when rerendering the UI component.
|
||||
|
||||
@ -133,7 +133,7 @@ Example:
|
||||
|
||||
```xml
|
||||
<div>
|
||||
<table w-preserve> <!-- Don't ever rerender this table -->
|
||||
<table no-update> <!-- Don't ever rerender this table -->
|
||||
...
|
||||
</table>
|
||||
</div>
|
||||
@ -141,39 +141,39 @@ Example:
|
||||
|
||||
```xml
|
||||
<div>
|
||||
<app-map w-preserve/> <!-- Don't ever rerender this UI component -->
|
||||
<app-map no-update/> <!-- Don't ever rerender this UI component -->
|
||||
</div>
|
||||
```
|
||||
|
||||
## w-preserve-if
|
||||
## no-update-if
|
||||
|
||||
Similar to [w-preserve](#w-preserve) except that the DOM subtree is conditionally preserved:
|
||||
Similar to [no-update](#no-update) except that the DOM subtree is conditionally preserved:
|
||||
|
||||
```xml
|
||||
<div>
|
||||
<table w-preserve-if(data.tableData == null)>
|
||||
<table no-update-if(data.tableData == null)>
|
||||
...
|
||||
</table>
|
||||
</div>
|
||||
```
|
||||
|
||||
## w-preserve-body
|
||||
## no-update-body
|
||||
|
||||
Similar to [w-preserve](#w-preserve) except that only the child DOM nodes are preserved:
|
||||
Similar to [no-update](#no-update) except that only the child DOM nodes are preserved:
|
||||
|
||||
```xml
|
||||
<div w-preserve-body> <!-- Don't ever rerender any nested DOM elements -->
|
||||
<div no-update-body> <!-- Don't ever rerender any nested DOM elements -->
|
||||
...
|
||||
</div>
|
||||
```
|
||||
|
||||
## w-preserve-body-if
|
||||
## no-update-body-if
|
||||
|
||||
Similar to [w-preserve-if](#w-preserve) except that only the child DOM nodes are preserved:
|
||||
Similar to [no-update-if](#no-update) except that only the child DOM nodes are preserved:
|
||||
|
||||
```xml
|
||||
<div>
|
||||
<table w-preserve-if(data.tableData == null)>
|
||||
<table no-update-if(data.tableData == null)>
|
||||
...
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@ -23,6 +23,10 @@
|
||||
"w-preserve-body",
|
||||
"w-preserve-if",
|
||||
"w-preserve-body-if",
|
||||
"no-update",
|
||||
"no-update-body",
|
||||
"no-update-if",
|
||||
"no-update-body-if",
|
||||
"w-preserve-attrs",
|
||||
"w-on*"
|
||||
]
|
||||
|
||||
@ -47,6 +47,7 @@
|
||||
"w-widget",
|
||||
"init-widgets",
|
||||
"w-preserve",
|
||||
"no-update",
|
||||
"widget-types",
|
||||
"body"
|
||||
]
|
||||
@ -40,6 +40,7 @@
|
||||
"macro",
|
||||
"macro-body",
|
||||
"marko-preserve-whitespace",
|
||||
"no-update",
|
||||
"pre",
|
||||
"script",
|
||||
"style",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div w-bind>
|
||||
<div.unpreserved-counter>${data.counter}</div>
|
||||
<span class="preserve" data-counter=data.counter w-preserve-body>
|
||||
<span class="preserve" data-counter=data.counter no-update-body>
|
||||
<div.preserved-counter>${data.counter}</div>
|
||||
</span>
|
||||
</div>
|
||||
@ -1,6 +1,6 @@
|
||||
<div w-bind>
|
||||
<div.unpreserved-counter>${data.counter}</div>
|
||||
<span ref="preserve" data-counter=data.counter w-preserve-body>
|
||||
<span ref="preserve" data-counter=data.counter no-update-body>
|
||||
<div.preserved-counter>${data.counter}</div>
|
||||
</span>
|
||||
</div>
|
||||
@ -1,6 +1,6 @@
|
||||
<div w-bind>
|
||||
<div.unpreserved-counter>${data.counter}</div>
|
||||
<span class="preserve" data-counter=data.counter w-preserve>
|
||||
<span class="preserve" data-counter=data.counter no-update>
|
||||
<div.preserved-counter>${data.counter}</div>
|
||||
</span>
|
||||
</div>
|
||||
@ -1,6 +1,6 @@
|
||||
<div w-bind>
|
||||
<div.unpreserved-counter>${data.counter}</div>
|
||||
<span ref="preserve" data-counter=data.counter w-preserve>
|
||||
<span ref="preserve" data-counter=data.counter no-update>
|
||||
<div.preserved-counter>${data.counter}</div>
|
||||
</span>
|
||||
</div>
|
||||
@ -1,18 +1,18 @@
|
||||
<div w-bind>
|
||||
<h1>Preserve Begin</h1>
|
||||
<span ref="preserve" w-preserve-if(data.preserveCondition) data-renderId=data.renderId>${data.renderId}</span>
|
||||
<span ref="preserve" no-update-if(data.preserveCondition) data-renderId=data.renderId>${data.renderId}</span>
|
||||
|
||||
<span ref="preserveBody" w-preserve-body-if(data.preserveCondition) data-renderId=data.renderId>${data.renderId}</span>
|
||||
<span ref="preserveBody" no-update-body-if(data.preserveCondition) data-renderId=data.renderId>${data.renderId}</span>
|
||||
|
||||
<app-stateful-rerender ref="widget" name=(data.renderId.toString()) w-preserve-if(data.preserveCondition) />
|
||||
<app-stateful-rerender ref="widget" name=(data.renderId.toString()) no-update-if(data.preserveCondition) />
|
||||
|
||||
<!-- Test without an ID -->
|
||||
|
||||
<span class="preserve" w-preserve-if(data.preserveCondition) data-renderId=data.renderId>${data.renderId}</span>
|
||||
<span class="preserve" no-update-if(data.preserveCondition) data-renderId=data.renderId>${data.renderId}</span>
|
||||
|
||||
<span class="preserve-body" w-preserve-body-if(data.preserveCondition) data-renderId=data.renderId>${data.renderId}</span>
|
||||
<span class="preserve-body" no-update-body-if(data.preserveCondition) data-renderId=data.renderId>${data.renderId}</span>
|
||||
|
||||
<app-stateful-rerender class="widget-no-id" name=(data.renderId.toString()) w-preserve-if(data.preserveCondition) data-renderId=data.renderId/>
|
||||
<app-stateful-rerender class="widget-no-id" name=(data.renderId.toString()) no-update-if(data.preserveCondition) data-renderId=data.renderId/>
|
||||
|
||||
<h1>Preserve End</h1>
|
||||
</div>
|
||||
@ -1 +1 @@
|
||||
<div w-bind><div w-preserve for(color in ['red', 'green', 'blue'])>${color}</div></div>
|
||||
<div w-bind><div no-update for(color in ['red', 'green', 'blue'])>${color}</div></div>
|
||||
@ -1,3 +1,3 @@
|
||||
<div w-bind w-preserve>
|
||||
<div w-bind no-update>
|
||||
Hello ${data.name}! You have ${data.messageCount} new messages.
|
||||
</div>
|
||||
@ -16,12 +16,11 @@
|
||||
'use strict';
|
||||
|
||||
function addPreserve(transformHelper, bodyOnly, condition) {
|
||||
let el = transformHelper.el;
|
||||
let context = transformHelper.context;
|
||||
let builder = transformHelper.builder;
|
||||
|
||||
var el = transformHelper.el;
|
||||
var context = transformHelper.context;
|
||||
var builder = transformHelper.builder;
|
||||
|
||||
var preserveAttrs = {};
|
||||
let preserveAttrs = {};
|
||||
|
||||
if (bodyOnly) {
|
||||
preserveAttrs['body-only'] = builder.literal(bodyOnly);
|
||||
@ -31,13 +30,13 @@ function addPreserve(transformHelper, bodyOnly, condition) {
|
||||
preserveAttrs['if'] = condition;
|
||||
}
|
||||
|
||||
var widgetIdInfo = transformHelper.assignWidgetId(true /* repeated */);
|
||||
var idVarNode = widgetIdInfo.idVarNode ? null : widgetIdInfo.createIdVarNode();
|
||||
let widgetIdInfo = transformHelper.assignWidgetId(true /* repeated */);
|
||||
let idVarNode = widgetIdInfo.idVarNode ? null : widgetIdInfo.createIdVarNode();
|
||||
|
||||
preserveAttrs.id = transformHelper.getIdExpression();
|
||||
|
||||
var preserveNode = context.createNodeForEl('w-preserve', preserveAttrs);
|
||||
var idVarNodeTarget;
|
||||
let preserveNode = context.createNodeForEl('w-preserve', preserveAttrs);
|
||||
let idVarNodeTarget;
|
||||
|
||||
if (bodyOnly) {
|
||||
el.moveChildrenTo(preserveNode);
|
||||
@ -57,33 +56,127 @@ function addPreserve(transformHelper, bodyOnly, condition) {
|
||||
return preserveNode;
|
||||
}
|
||||
|
||||
function deprecatedWarning(preserveType, transformHelper, el) {
|
||||
let attribute = preserveType.attribute;
|
||||
let suffix = preserveType.suffix;
|
||||
let context = transformHelper.getCompileContext();
|
||||
|
||||
let newAttributeName = 'no-update';
|
||||
if (suffix) {
|
||||
newAttributeName += suffix;
|
||||
}
|
||||
|
||||
console.warn(`The '${attribute}' attribute is deprecated. Please use '${newAttributeName}' instead. (${el.pos ? context.getPosInfo(el.pos) : context.filename})`);
|
||||
}
|
||||
|
||||
function preserveHandler(transformHelper, preserveType, el) {
|
||||
if (preserveType.deprecated) {
|
||||
deprecatedWarning(preserveType, transformHelper, el);
|
||||
}
|
||||
|
||||
el.removeAttribute(preserveType.attribute);
|
||||
addPreserve(transformHelper, false);
|
||||
}
|
||||
|
||||
function preserveIfHandler(transformHelper, preserveType, el) {
|
||||
if (preserveType.deprecated) {
|
||||
deprecatedWarning(preserveType, transformHelper, el);
|
||||
}
|
||||
|
||||
let attribute = preserveType.attribute;
|
||||
let preserveIfAttr = el.getAttribute(attribute);
|
||||
let preserveIfCondition = preserveIfAttr.argument;
|
||||
|
||||
if (!preserveIfCondition) {
|
||||
transformHelper.addError(`The '${attribute}' attribute should have an argument. For example: <div ${attribute}(someCondition)>`);
|
||||
return;
|
||||
}
|
||||
|
||||
addPreserve(transformHelper, false, transformHelper.builder.expression(preserveIfCondition));
|
||||
el.removeAttribute(attribute);
|
||||
}
|
||||
|
||||
function preserveBodyHandler(transformHelper, preserveType, el) {
|
||||
if (preserveType.deprecated) {
|
||||
deprecatedWarning(preserveType, transformHelper, el);
|
||||
}
|
||||
|
||||
el.removeAttribute(preserveType.attribute);
|
||||
addPreserve(transformHelper, true);
|
||||
}
|
||||
|
||||
function preserveBodyIfHandler(transformHelper, preserveType, el) {
|
||||
if (preserveType.deprecated) {
|
||||
deprecatedWarning(preserveType, transformHelper, el);
|
||||
}
|
||||
|
||||
let attribute = preserveType.attribute;
|
||||
let preserveBodyIfAttr = el.getAttribute(attribute);
|
||||
let preserveBodyIfCondition = preserveBodyIfAttr.argument;
|
||||
|
||||
if (!preserveBodyIfCondition) {
|
||||
transformHelper.addError(`The '${attribute}' attribute should have an argument. For example: <div ${attribute}(someCondition)>`);
|
||||
return;
|
||||
}
|
||||
|
||||
addPreserve(transformHelper, true, transformHelper.builder.expression(preserveBodyIfCondition));
|
||||
el.removeAttribute('w-preserve-body-if');
|
||||
}
|
||||
|
||||
const preserveTypes = [
|
||||
// The new preserve types
|
||||
{
|
||||
attribute: 'no-update',
|
||||
handler: preserveHandler
|
||||
},
|
||||
{
|
||||
attribute: 'no-update-if',
|
||||
handler: preserveIfHandler
|
||||
},
|
||||
{
|
||||
attribute: 'no-update-body',
|
||||
handler: preserveBodyHandler
|
||||
},
|
||||
{
|
||||
attribute: 'no-update-body-if',
|
||||
handler: preserveBodyIfHandler
|
||||
},
|
||||
|
||||
// The deprecated preserve types
|
||||
{
|
||||
attribute: 'w-preserve',
|
||||
handler: preserveHandler,
|
||||
deprecated: true
|
||||
},
|
||||
{
|
||||
attribute: 'w-preserve-if',
|
||||
suffix: '-if',
|
||||
handler: preserveIfHandler,
|
||||
deprecated: true
|
||||
},
|
||||
{
|
||||
attribute: 'w-preserve-body',
|
||||
suffix: '-body',
|
||||
handler: preserveBodyHandler,
|
||||
deprecated: true
|
||||
},
|
||||
{
|
||||
attribute: 'w-preserve-body-if',
|
||||
suffix: '-body-if',
|
||||
handler: preserveBodyIfHandler,
|
||||
deprecated: true
|
||||
}
|
||||
];
|
||||
|
||||
module.exports = function handleWidgetPreserve() {
|
||||
var el = this.el;
|
||||
let el = this.el;
|
||||
|
||||
if (el.hasAttribute('w-preserve')) {
|
||||
el.removeAttribute('w-preserve');
|
||||
addPreserve(this, false);
|
||||
} else if (el.hasAttribute('w-preserve-if')) {
|
||||
let preserveIfAttr = el.getAttribute('w-preserve-if');
|
||||
var preserveIfCondition = preserveIfAttr.argument;
|
||||
if (!preserveIfCondition) {
|
||||
this.addError('The `w-preserve-if` attribute should have an argument. For example: <div w-preserve-if(someCondition)>');
|
||||
for (let i = 0; i < preserveTypes.length; i++) {
|
||||
let preserveType = preserveTypes[i];
|
||||
|
||||
if (el.hasAttribute(preserveType.attribute)) {
|
||||
preserveType.handler(this, preserveType, el);
|
||||
return;
|
||||
}
|
||||
addPreserve(this, false, this.builder.expression(preserveIfCondition));
|
||||
el.removeAttribute('w-preserve-if');
|
||||
} else if (el.hasAttribute('w-preserve-body')) {
|
||||
el.removeAttribute('w-preserve-body');
|
||||
addPreserve(this, true);
|
||||
} else if (el.hasAttribute('w-preserve-body-if')) {
|
||||
let preserveBodyIfAttr = el.getAttribute('w-preserve-body-if');
|
||||
var preserveBodyIfCondition = preserveBodyIfAttr.argument;
|
||||
if (!preserveBodyIfCondition) {
|
||||
this.addError('The `w-preserve-body-if` attribute should have an argument. For example: <div w-preserve-body-if(someCondition)>');
|
||||
return;
|
||||
}
|
||||
|
||||
addPreserve(this, true, this.builder.expression(preserveBodyIfCondition));
|
||||
el.removeAttribute('w-preserve-body-if');
|
||||
}
|
||||
};
|
||||
@ -57,6 +57,10 @@ class TransformHelper {
|
||||
return this.widgetIdInfo;
|
||||
}
|
||||
|
||||
getCompileContext() {
|
||||
return this.context;
|
||||
}
|
||||
|
||||
getDefaultWidgetModule() {
|
||||
var dirname = this.dirname;
|
||||
if (resolveFrom(dirname, './component')) {
|
||||
|
||||
@ -97,6 +97,7 @@
|
||||
"preserve-name": true,
|
||||
"autocomplete": [
|
||||
{
|
||||
"displayText": "w-preserve (Deprecated)",
|
||||
"descriptionMoreURL": "http://markojs.com/docs/marko-widgets/#preserving-dom-nodes-during-re-render"
|
||||
}
|
||||
]
|
||||
@ -106,6 +107,7 @@
|
||||
"preserve-name": true,
|
||||
"autocomplete": [
|
||||
{
|
||||
"displayText": "w-preserve-body (Deprecated)",
|
||||
"descriptionMoreURL": "http://markojs.com/docs/marko-widgets/#preserving-dom-nodes-during-re-render"
|
||||
}
|
||||
]
|
||||
@ -114,6 +116,7 @@
|
||||
"preserve-name": true,
|
||||
"autocomplete": [
|
||||
{
|
||||
"displayText": "w-preserve-if (Deprecated)",
|
||||
"snippet": "w-preserve-if(${1:condition})",
|
||||
"descriptionMoreURL": "http://markojs.com/docs/marko-widgets/#preserving-dom-nodes-during-re-render"
|
||||
}
|
||||
@ -123,11 +126,48 @@
|
||||
"preserve-name": true,
|
||||
"autocomplete": [
|
||||
{
|
||||
"displayText": "w-preserve-body-if (Deprecated)",
|
||||
"snippet": "w-preserve-body-if(${1:condition})",
|
||||
"descriptionMoreURL": "http://markojs.com/docs/marko-widgets/#preserving-dom-nodes-during-re-render"
|
||||
}
|
||||
]
|
||||
},
|
||||
"@no-update": {
|
||||
"type": "flag",
|
||||
"preserve-name": true,
|
||||
"autocomplete": [
|
||||
{
|
||||
"descriptionMoreURL": "http://markojs.com/docs/marko-widgets/#preserving-dom-nodes-during-re-render"
|
||||
}
|
||||
]
|
||||
},
|
||||
"@no-update-body": {
|
||||
"type": "flag",
|
||||
"preserve-name": true,
|
||||
"autocomplete": [
|
||||
{
|
||||
"descriptionMoreURL": "http://markojs.com/docs/marko-widgets/#preserving-dom-nodes-during-re-render"
|
||||
}
|
||||
]
|
||||
},
|
||||
"@no-update-if": {
|
||||
"preserve-name": true,
|
||||
"autocomplete": [
|
||||
{
|
||||
"snippet": "no-update-if(${1:condition})",
|
||||
"descriptionMoreURL": "http://markojs.com/docs/marko-widgets/#preserving-dom-nodes-during-re-render"
|
||||
}
|
||||
]
|
||||
},
|
||||
"@no-update-body-if": {
|
||||
"preserve-name": true,
|
||||
"autocomplete": [
|
||||
{
|
||||
"snippet": "no-update-body-if(${1:condition})",
|
||||
"descriptionMoreURL": "http://markojs.com/docs/marko-widgets/#preserving-dom-nodes-during-re-render"
|
||||
}
|
||||
]
|
||||
},
|
||||
"@w-preserve-attrs": {
|
||||
"type": "string",
|
||||
"preserve-name": true,
|
||||
@ -168,6 +208,13 @@
|
||||
"@body-only": "expression",
|
||||
"autocomplete": []
|
||||
},
|
||||
"<no-update>": {
|
||||
"renderer": "./preserve-tag.js",
|
||||
"@id": "string",
|
||||
"@if": "expression",
|
||||
"@body-only": "expression",
|
||||
"autocomplete": []
|
||||
},
|
||||
"<widget-types>": {
|
||||
"code-generator": "./widget-types-tag.js",
|
||||
"@*": "string",
|
||||
|
||||
@ -53,7 +53,13 @@ module.exports = function transform(el, context) {
|
||||
transformHelper.handleWidgetExtend();
|
||||
}
|
||||
|
||||
if (el.hasAttribute('w-preserve') ||
|
||||
if (/* New preserve attributes */
|
||||
el.hasAttribute('no-update') ||
|
||||
el.hasAttribute('no-update-body') ||
|
||||
el.hasAttribute('no-update-if') ||
|
||||
el.hasAttribute('no-update-body-if') ||
|
||||
/* Old preserve attributes */
|
||||
el.hasAttribute('w-preserve') ||
|
||||
el.hasAttribute('w-preserve-body') ||
|
||||
el.hasAttribute('w-preserve-if') ||
|
||||
el.hasAttribute('w-preserve-body-if')) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user