mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
Changes related to #492 - Added support for body-slot and putting functions in state
This commit is contained in:
parent
58ca13be22
commit
306e19b88e
@ -403,6 +403,10 @@ class CustomTag extends HtmlElement {
|
||||
Object.assign(this._additionalProps, additionalProps);
|
||||
}
|
||||
|
||||
hasProp(name) {
|
||||
return this._additionalProps && this._additionalProps.hasOwnProperty(name);
|
||||
}
|
||||
|
||||
addProp(name, value) {
|
||||
if (!this._additionalProps) {
|
||||
this._additionalProps = {};
|
||||
|
||||
@ -137,6 +137,7 @@
|
||||
},
|
||||
"minprops": {
|
||||
"exclude": [
|
||||
"b",
|
||||
"c",
|
||||
"ca",
|
||||
"e",
|
||||
|
||||
11
taglibs/core/body-slot-tag.js
Normal file
11
taglibs/core/body-slot-tag.js
Normal file
@ -0,0 +1,11 @@
|
||||
module.exports = function codeGenerator(elNode, generator) {
|
||||
var context = generator.context;
|
||||
var builder = generator.builder;
|
||||
var includeNode = context.createNodeForEl('include');
|
||||
includeNode.addProp(
|
||||
'_target',
|
||||
builder.memberExpression(
|
||||
builder.identifier('data'),
|
||||
builder.identifier('renderBody')));
|
||||
return includeNode;
|
||||
};
|
||||
@ -163,8 +163,30 @@ var coreAttrHandlers = [
|
||||
'include', function(attr, node, el) {
|
||||
var context = this.context;
|
||||
|
||||
var includeNode = context.createNodeForEl('include', null, attr.argument);
|
||||
node.appendChild(includeNode);
|
||||
if (attr.argument) {
|
||||
var includeNode = context.createNodeForEl('include', null, attr.argument);
|
||||
node.appendChild(includeNode);
|
||||
} else {
|
||||
context.addError(el, 'The include attribute must have an argument. For example: include("./target.marko") or include(data.renderBody)');
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'body-slot', function(attr, node, el) {
|
||||
var context = this.context;
|
||||
|
||||
if (attr.argument) {
|
||||
context.addError(el, 'The body-slot attribute should not have an argument.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (attr.value) {
|
||||
context.addError(el, 'The body-slot attribute should not have a value.');
|
||||
return;
|
||||
}
|
||||
|
||||
var bodySlot = context.createNodeForEl('body-slot');
|
||||
node.appendChild(bodySlot);
|
||||
}
|
||||
]
|
||||
];
|
||||
|
||||
@ -1,34 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function codeGenerator(el, context) {
|
||||
module.exports = function(el, context) {
|
||||
let builder = context.builder;
|
||||
|
||||
let target;
|
||||
let arg;
|
||||
|
||||
if (el.argument) {
|
||||
let args = el.argument && builder.parseJavaScriptArgs(el.argument);
|
||||
el.argument = null;
|
||||
|
||||
target = args[0];
|
||||
arg = args[1];
|
||||
} else {
|
||||
return;
|
||||
let target = args[0];
|
||||
let arg = args[1];
|
||||
|
||||
if (target.type === 'Literal') {
|
||||
target = context.importTemplate(target.value);
|
||||
}
|
||||
|
||||
var includeProps = {
|
||||
_target: target
|
||||
};
|
||||
|
||||
if (arg) {
|
||||
includeProps._arg = arg;
|
||||
}
|
||||
|
||||
el.addProps(includeProps);
|
||||
} else if (!el.hasProp('_target')) {
|
||||
context.addError(el, 'The <include(...)> tag must have an argument: <include("./target.marko")/> or <include(data.renderBody)/>');
|
||||
}
|
||||
|
||||
if (target.type === 'Literal') {
|
||||
target = context.importTemplate(target.value);
|
||||
}
|
||||
|
||||
var includeProps = {
|
||||
_target: target
|
||||
};
|
||||
|
||||
if (arg) {
|
||||
includeProps._arg = arg;
|
||||
}
|
||||
|
||||
el.data.includeTarget = target;
|
||||
|
||||
el.addProps(includeProps);
|
||||
};
|
||||
@ -9,6 +9,17 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"<body-slot>": {
|
||||
"code-generator": "./body-slot-tag",
|
||||
"attributes": {},
|
||||
"autocomplete": [
|
||||
{
|
||||
"displayText": "body-slot",
|
||||
"snippet": "body-slot",
|
||||
"openTagOnly": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"<else>": {
|
||||
"node-factory": "./else-tag",
|
||||
"attributes": {},
|
||||
@ -299,8 +310,8 @@
|
||||
"descriptionMoreURL": "http://markojs.com/docs/marko/language-guide/#includes"
|
||||
},
|
||||
{
|
||||
"displayText": "include()",
|
||||
"snippet": "include()",
|
||||
"displayText": "include(data.renderBody)",
|
||||
"snippet": "include(data.renderBody)",
|
||||
"descriptionMoreURL": "http://markojs.com/docs/marko/language-guide/#includes"
|
||||
},
|
||||
{
|
||||
|
||||
@ -0,0 +1 @@
|
||||
<div><h1>Test</h1><div class="body"><strong>This is the body</strong></div></div>
|
||||
@ -0,0 +1,3 @@
|
||||
<div body-slot(invalid)>
|
||||
|
||||
</div>
|
||||
@ -0,0 +1,8 @@
|
||||
var expect = require('chai').expect;
|
||||
|
||||
exports.templateData = {};
|
||||
|
||||
exports.checkError = function(e) {
|
||||
var message = e.toString();
|
||||
expect(message).to.contain('The body-slot attribute should not have an argument');
|
||||
};
|
||||
@ -0,0 +1 @@
|
||||
<div><h1>Test</h1><div class="body"><strong>This is the body</strong></div></div>
|
||||
@ -0,0 +1,3 @@
|
||||
<div body-slot='invalid'>
|
||||
|
||||
</div>
|
||||
8
test/autotests/render/body-slot-attr-error-value/test.js
Normal file
8
test/autotests/render/body-slot-attr-error-value/test.js
Normal file
@ -0,0 +1,8 @@
|
||||
var expect = require('chai').expect;
|
||||
|
||||
exports.templateData = {};
|
||||
|
||||
exports.checkError = function(e) {
|
||||
var message = e.toString();
|
||||
expect(message).to.contain('The body-slot attribute should not have a value');
|
||||
};
|
||||
1
test/autotests/render/body-slot-attr/expected.html
Normal file
1
test/autotests/render/body-slot-attr/expected.html
Normal file
@ -0,0 +1 @@
|
||||
<div><h1>Test</h1><div class="body"><strong>This is the body</strong></div></div>
|
||||
@ -0,0 +1,4 @@
|
||||
<div>
|
||||
<h1>Test</h1>
|
||||
<div.body body-slot/>
|
||||
</div>
|
||||
3
test/autotests/render/body-slot-attr/template.marko
Normal file
3
test/autotests/render/body-slot-attr/template.marko
Normal file
@ -0,0 +1,3 @@
|
||||
<include('./include-target.marko')>
|
||||
<strong>This is the body</strong>
|
||||
</include>
|
||||
1
test/autotests/render/body-slot-attr/test.js
Normal file
1
test/autotests/render/body-slot-attr/test.js
Normal file
@ -0,0 +1 @@
|
||||
exports.templateData = {};
|
||||
1
test/autotests/render/body-slot/expected.html
Normal file
1
test/autotests/render/body-slot/expected.html
Normal file
@ -0,0 +1 @@
|
||||
<div><h1>Test</h1><div class="body"><strong>This is the body</strong></div></div>
|
||||
6
test/autotests/render/body-slot/include-target.marko
Normal file
6
test/autotests/render/body-slot/include-target.marko
Normal file
@ -0,0 +1,6 @@
|
||||
<div>
|
||||
<h1>Test</h1>
|
||||
<div.body>
|
||||
<body-slot/>
|
||||
</div>
|
||||
</div>
|
||||
3
test/autotests/render/body-slot/template.marko
Normal file
3
test/autotests/render/body-slot/template.marko
Normal file
@ -0,0 +1,3 @@
|
||||
<include('./include-target.marko')>
|
||||
<strong>This is the body</strong>
|
||||
</include>
|
||||
1
test/autotests/render/body-slot/test.js
Normal file
1
test/autotests/render/body-slot/test.js
Normal file
@ -0,0 +1 @@
|
||||
exports.templateData = {};
|
||||
@ -0,0 +1 @@
|
||||
<div><h1>Test</h1><div class="body"><strong>This is the body</strong></div></div>
|
||||
@ -0,0 +1,2 @@
|
||||
<div include()>
|
||||
</div>
|
||||
@ -0,0 +1,9 @@
|
||||
var expect = require('chai').expect;
|
||||
|
||||
exports.templateData = {};
|
||||
|
||||
exports.checkError = function(e) {
|
||||
var message = e.toString();
|
||||
expect(message).to.contain('template.marko:1:0');
|
||||
expect(message).to.contain('The include attribute must have an argument');
|
||||
};
|
||||
@ -0,0 +1 @@
|
||||
<div><h1>Test</h1><div class="body"><strong>This is the body</strong></div></div>
|
||||
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<include()/>
|
||||
</div>
|
||||
@ -0,0 +1,8 @@
|
||||
var expect = require('chai').expect;
|
||||
|
||||
exports.templateData = {};
|
||||
|
||||
exports.checkError = function(e) {
|
||||
var message = e.toString();
|
||||
expect(message).to.contain('The <include(...)> tag must have an argument');
|
||||
};
|
||||
@ -18,6 +18,7 @@
|
||||
"ref",
|
||||
"w-for",
|
||||
"w-id",
|
||||
"body-slot",
|
||||
"w-body",
|
||||
"w-preserve",
|
||||
"w-preserve-body",
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
"lasso-resource",
|
||||
"browser-refresh",
|
||||
"assign",
|
||||
"body-slot",
|
||||
"else",
|
||||
"else-if",
|
||||
"for",
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
"await-timeout",
|
||||
"bar",
|
||||
"body",
|
||||
"body-slot",
|
||||
"browser-refresh",
|
||||
"cached-fragment",
|
||||
"else",
|
||||
|
||||
@ -4,5 +4,5 @@
|
||||
'app-button-' + state.variant,
|
||||
'app-button-' + state.size
|
||||
] onClick("handleClick")>
|
||||
<span include()/>
|
||||
<span body-slot/>
|
||||
</button>
|
||||
@ -1,4 +1,6 @@
|
||||
<app-button ref="button" class=state.className onClick('handleClick')>
|
||||
<span class="app-checkbox-icon"/>
|
||||
<span ref="checkboxLabel" include()/>
|
||||
<span ref="checkboxLabel">
|
||||
<body-slot/>
|
||||
</span>
|
||||
</app-button>
|
||||
@ -10,5 +10,5 @@
|
||||
|
||||
<div.foo>
|
||||
<span>Hello ${state.name}!</span>
|
||||
<div.body><include()/></div>
|
||||
<div.body><body-slot/></div>
|
||||
</div>
|
||||
@ -0,0 +1,31 @@
|
||||
<script>
|
||||
module.exports = {
|
||||
onInput: function(input) {
|
||||
this.state = {
|
||||
size: input.size || 'normal',
|
||||
variant: input.variant || 'primary'
|
||||
};
|
||||
this.body = input.renderBody;
|
||||
},
|
||||
|
||||
// Add any other methods here
|
||||
setVariant: function(variant) {
|
||||
this.state.variant = variant;
|
||||
},
|
||||
|
||||
setSize: function(size) {
|
||||
this.state.size = size;
|
||||
},
|
||||
|
||||
setLabel: function(label) {
|
||||
this.state.label = label;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
var variantClassName=(state.variant !== 'primary' && 'app-button-' + state.variant)
|
||||
var sizeClassName=(state.size !== 'normal' && 'app-button-' + state.size)
|
||||
|
||||
<button class=['app-button', variantClassName, sizeClassName]>
|
||||
<span body-slot/>
|
||||
</button>
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
module.exports = {
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<app-button size="small" variant="primary" ref="button">
|
||||
<b>${data.name}</b>
|
||||
</app-button>
|
||||
</div>
|
||||
@ -0,0 +1,23 @@
|
||||
var expect = require('chai').expect;
|
||||
|
||||
module.exports = function(helpers) {
|
||||
var widget = helpers.mount(require('./index'), {
|
||||
name: 'Frank'
|
||||
});
|
||||
|
||||
var buttonWidget = widget.getWidget('button');
|
||||
expect(buttonWidget.el.innerHTML).to.contain('Frank');
|
||||
expect(buttonWidget.el.className).to.equal('app-button app-button-small');
|
||||
|
||||
// Button widget will not rerender since it's state did not change and that means that the
|
||||
// button content will remain as 'John' instead of 'Frank'
|
||||
widget.setProps({ name: 'John '});
|
||||
widget.update();
|
||||
|
||||
expect(buttonWidget.el.innerHTML).to.contain('John');
|
||||
|
||||
buttonWidget.setSize('large');
|
||||
buttonWidget.update();
|
||||
expect(buttonWidget.el.innerHTML).to.contain('John');
|
||||
expect(buttonWidget.el.className).to.equal('app-button app-button-large');
|
||||
};
|
||||
@ -0,0 +1,32 @@
|
||||
<script>
|
||||
module.exports = {
|
||||
onInput: function(input) {
|
||||
this.state = {
|
||||
size: input.size || 'normal',
|
||||
variant: input.variant || 'primary'
|
||||
};
|
||||
},
|
||||
|
||||
// Add any other methods here
|
||||
setVariant: function(variant) {
|
||||
this.state.variant = variant;
|
||||
},
|
||||
|
||||
setSize: function(size) {
|
||||
this.state.size = size;
|
||||
},
|
||||
|
||||
setLabel: function(label) {
|
||||
this.state.label = label;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
var variantClassName=(state.variant !== 'primary' && 'app-button-' + state.variant)
|
||||
var sizeClassName=(state.size !== 'normal' && 'app-button-' + state.size)
|
||||
|
||||
<button class=['app-button', variantClassName, sizeClassName]>
|
||||
<span>
|
||||
<body-slot/>
|
||||
</span>
|
||||
</button>
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
module.exports = {
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<app-button size="small" variant="primary" ref="button">
|
||||
<b>${data.name}</b>
|
||||
</app-button>
|
||||
</div>
|
||||
@ -0,0 +1,21 @@
|
||||
var expect = require('chai').expect;
|
||||
|
||||
module.exports = function(helpers) {
|
||||
var widget = helpers.mount(require('./index'), {
|
||||
name: 'Frank'
|
||||
});
|
||||
|
||||
var buttonWidget = widget.getWidget('button');
|
||||
expect(buttonWidget.el.innerHTML).to.contain('Frank');
|
||||
expect(buttonWidget.el.className).to.equal('app-button app-button-small');
|
||||
|
||||
widget.setProps({ name: 'John '});
|
||||
widget.update();
|
||||
|
||||
expect(buttonWidget.el.innerHTML).to.contain('John');
|
||||
|
||||
buttonWidget.setSize('large');
|
||||
buttonWidget.update();
|
||||
expect(buttonWidget.el.innerHTML).to.contain('John');
|
||||
expect(buttonWidget.el.className).to.equal('app-button app-button-large');
|
||||
};
|
||||
@ -0,0 +1,33 @@
|
||||
<script>
|
||||
module.exports = {
|
||||
onInput: function(input) {
|
||||
this.state = {
|
||||
size: input.size || 'normal',
|
||||
variant: input.variant || 'primary'
|
||||
};
|
||||
this.body = input.renderBody;
|
||||
},
|
||||
|
||||
// Add any other methods here
|
||||
setVariant: function(variant) {
|
||||
this.state.variant = variant;
|
||||
},
|
||||
|
||||
setSize: function(size) {
|
||||
this.state.size = size;
|
||||
},
|
||||
|
||||
setLabel: function(label) {
|
||||
this.state.label = label;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
var variantClassName=(state.variant !== 'primary' && 'app-button-' + state.variant)
|
||||
var sizeClassName=(state.size !== 'normal' && 'app-button-' + state.size)
|
||||
|
||||
<button class=['app-button', variantClassName, sizeClassName]>
|
||||
<span>
|
||||
<body-slot/>
|
||||
</span>
|
||||
</button>
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
module.exports = {
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<app-button size="small" variant="primary" ref="button">
|
||||
<b>${data.name}</b>
|
||||
</app-button>
|
||||
</div>
|
||||
@ -0,0 +1,21 @@
|
||||
var expect = require('chai').expect;
|
||||
|
||||
module.exports = function(helpers) {
|
||||
var widget = helpers.mount(require('./index'), {
|
||||
name: 'Frank'
|
||||
});
|
||||
|
||||
var buttonWidget = widget.getWidget('button');
|
||||
expect(buttonWidget.el.innerHTML).to.contain('Frank');
|
||||
expect(buttonWidget.el.className).to.equal('app-button app-button-small');
|
||||
|
||||
widget.setProps({ name: 'John '});
|
||||
widget.update();
|
||||
|
||||
expect(buttonWidget.el.innerHTML).to.contain('John');
|
||||
|
||||
buttonWidget.setSize('large');
|
||||
buttonWidget.update();
|
||||
expect(buttonWidget.el.innerHTML).to.contain('John');
|
||||
expect(buttonWidget.el.className).to.equal('app-button app-button-large');
|
||||
};
|
||||
@ -0,0 +1,31 @@
|
||||
<script>
|
||||
module.exports = {
|
||||
onInput: function(input) {
|
||||
this.state = {
|
||||
size: input.size || 'normal',
|
||||
variant: input.variant || 'primary',
|
||||
body: input.label || input.renderBody
|
||||
};
|
||||
},
|
||||
|
||||
// Add any other methods here
|
||||
setVariant: function(variant) {
|
||||
this.state.variant = variant;
|
||||
},
|
||||
|
||||
setSize: function(size) {
|
||||
this.state.size = size;
|
||||
},
|
||||
|
||||
setLabel: function(label) {
|
||||
this.state.label = label;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
var variantClassName=(state.variant !== 'primary' && 'app-button-' + state.variant)
|
||||
var sizeClassName=(state.size !== 'normal' && 'app-button-' + state.size)
|
||||
|
||||
<button class=['app-button', variantClassName, sizeClassName]>
|
||||
<span include(state.body)/>
|
||||
</button>
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
module.exports = {
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<app-button size="small" variant="primary" ref="button">
|
||||
<b>${data.name}</b>
|
||||
</app-button>
|
||||
</div>
|
||||
@ -0,0 +1,29 @@
|
||||
var expect = require('chai').expect;
|
||||
|
||||
module.exports = function(helpers) {
|
||||
var widget = helpers.mount(require('./index'), {
|
||||
name: 'Frank'
|
||||
});
|
||||
|
||||
var buttonWidget = widget.getWidget('button');
|
||||
expect(buttonWidget.el.innerHTML).to.contain('Frank');
|
||||
expect(buttonWidget.el.className).to.equal('app-button app-button-small');
|
||||
|
||||
widget.rerender({ name: 'John '});
|
||||
|
||||
expect(buttonWidget.el.innerHTML).to.contain('John');
|
||||
|
||||
buttonWidget.setSize('large');
|
||||
buttonWidget.update();
|
||||
expect(buttonWidget.el.innerHTML).to.contain('John');
|
||||
expect(buttonWidget.el.className).to.equal('app-button app-button-large');
|
||||
|
||||
buttonWidget.rerender({
|
||||
size: 'small',
|
||||
variant: 'secondary'
|
||||
// NOTE: We aren't including renderBody() but we expect that content to be preserved
|
||||
});
|
||||
|
||||
expect(buttonWidget.el.innerHTML).to.contain('John');
|
||||
expect(buttonWidget.el.className).to.equal('app-button app-button-secondary app-button-small');
|
||||
};
|
||||
@ -0,0 +1,30 @@
|
||||
<script>
|
||||
module.exports = {
|
||||
onInput: function(input) {
|
||||
this.state = {
|
||||
size: input.size || 'normal',
|
||||
variant: input.variant || 'primary'
|
||||
};
|
||||
},
|
||||
|
||||
// Add any other methods here
|
||||
setVariant: function(variant) {
|
||||
this.state.variant = variant;
|
||||
},
|
||||
|
||||
setSize: function(size) {
|
||||
this.state.size = size;
|
||||
},
|
||||
|
||||
setLabel: function(label) {
|
||||
this.state.label = label;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
var variantClassName=(state.variant !== 'primary' && 'app-button-' + state.variant)
|
||||
var sizeClassName=(state.size !== 'normal' && 'app-button-' + state.size)
|
||||
|
||||
<button class=['app-button', variantClassName, sizeClassName]>
|
||||
<span include(data.renderBody)/>
|
||||
</button>
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
module.exports = {
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<app-button size="small" variant="primary" ref="button">
|
||||
<b>${data.name}</b>
|
||||
</app-button>
|
||||
</div>
|
||||
@ -0,0 +1,23 @@
|
||||
var expect = require('chai').expect;
|
||||
|
||||
module.exports = function(helpers) {
|
||||
var widget = helpers.mount(require('./index'), {
|
||||
name: 'Frank'
|
||||
});
|
||||
|
||||
var buttonWidget = widget.getWidget('button');
|
||||
expect(buttonWidget.el.innerHTML).to.contain('Frank');
|
||||
expect(buttonWidget.el.className).to.equal('app-button app-button-small');
|
||||
|
||||
// Button widget will not rerender since it's state did not change and that means that the
|
||||
// button content will remain as 'John' instead of 'Frank'
|
||||
widget.setProps({ name: 'John '});
|
||||
widget.update();
|
||||
|
||||
expect(buttonWidget.el.innerHTML).to.contain('Frank');
|
||||
|
||||
buttonWidget.setSize('large');
|
||||
buttonWidget.update();
|
||||
expect(buttonWidget.el.innerHTML).to.contain('Frank');
|
||||
expect(buttonWidget.el.className).to.equal('app-button app-button-large');
|
||||
};
|
||||
@ -6,10 +6,7 @@ module.exports = {
|
||||
className: input['class'],
|
||||
attrs: input['*']
|
||||
};
|
||||
},
|
||||
|
||||
getInitialBody: function(input) {
|
||||
return input.label || input.renderBody;
|
||||
this.body = input.label || input.renderBody;
|
||||
},
|
||||
getTemplateData: function(state, input) {
|
||||
var rootAttrs = {};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<button ${data.rootAttrs}
|
||||
onClick("handleClick")
|
||||
w-bind
|
||||
include()></button>
|
||||
onClick("handleClick")>
|
||||
<body-slot/>
|
||||
</button>
|
||||
@ -1,4 +1,3 @@
|
||||
<button ${data.rootAttrs}
|
||||
onClick("handleClick")
|
||||
w-bind
|
||||
include()></button>
|
||||
<button ${data.rootAttrs} onClick("handleClick")>
|
||||
<body-slot/>
|
||||
</button>
|
||||
@ -1,3 +1,4 @@
|
||||
<button ${data.rootAttrs}
|
||||
onClick("handleClick")
|
||||
include()></button>
|
||||
onClick("handleClick")>
|
||||
<body-slot/>
|
||||
</button>
|
||||
@ -1,4 +1,4 @@
|
||||
<button ${data.rootAttrs}
|
||||
onClick("handleClick")
|
||||
w-bind
|
||||
include()></button>
|
||||
onClick("handleClick")>
|
||||
<body-slot/>
|
||||
</button>
|
||||
@ -4,6 +4,8 @@ var className=('alert alert-'+type)
|
||||
<div class=className role="alert">
|
||||
<div>
|
||||
<h1>ALERT! ${type} ${Date.now()}</h1>
|
||||
<div include/>
|
||||
<div>
|
||||
<body-slot/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -17,7 +17,7 @@ function render(data, out, widget, state) {
|
||||
">");
|
||||
|
||||
include_tag({
|
||||
_target: widget.body,
|
||||
_target: widget.b,
|
||||
_elId: widget.elId(0),
|
||||
_arg: widget
|
||||
}, out);
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
<button ${data.rootAttrs}
|
||||
onClick("handleClick")
|
||||
include()></button>
|
||||
onClick("handleClick")>
|
||||
<body-slot/>
|
||||
</button>
|
||||
@ -69,10 +69,6 @@ State.prototype = {
|
||||
ensure(self, name);
|
||||
}
|
||||
|
||||
if (typeof value === 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value === null) {
|
||||
// Treat null as undefined to simplify our comparison logic
|
||||
value = undefined;
|
||||
|
||||
@ -21,7 +21,7 @@ function WidgetDef(id, out, widgetStack, widgetStackLen) {
|
||||
this.$__customEvents = // An array containing information about custom events
|
||||
this.$__bodyElId = // The ID for the default body element (if any any)
|
||||
this.$__roots = // IDs of root elements if there are multiple root elements
|
||||
this.body =
|
||||
this.b =
|
||||
this.$__existingWidget =
|
||||
this.$__children = // An array of nested WidgetDef instances
|
||||
this.$__domEvents = // An array of DOM events that need to be added (in sets of three)
|
||||
|
||||
@ -125,17 +125,6 @@ function initWidget(widgetDef, doc) {
|
||||
|
||||
widgetLookup[id] = widget;
|
||||
|
||||
if (state) {
|
||||
for (var k in state) {
|
||||
if (state.hasOwnProperty(k)) {
|
||||
var v = state[k];
|
||||
if (typeof v === 'function' || v == null) {
|
||||
delete state[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
widget.state = state || {}; // First time rendering so use the provided state or an empty state object
|
||||
|
||||
if (!config) {
|
||||
|
||||
@ -159,8 +159,10 @@ module.exports = function createRendererFunc(templateRenderFunc, widgetProps, re
|
||||
var lightweightWidget = Object.create(renderingLogic);
|
||||
lightweightWidget.onInput(input);
|
||||
widgetState = lightweightWidget.state;
|
||||
widgetBody = lightweightWidget.body;
|
||||
widgetConfig = lightweightWidget;
|
||||
delete widgetConfig.state;
|
||||
delete widgetConfig.body;
|
||||
} else {
|
||||
if (getWidgetConfig) {
|
||||
// If getWidgetConfig() was implemented then use that to
|
||||
@ -172,16 +174,17 @@ module.exports = function createRendererFunc(templateRenderFunc, widgetProps, re
|
||||
} else {
|
||||
widgetConfig = input.widgetConfig;
|
||||
}
|
||||
|
||||
if (getInitialBody) {
|
||||
// If we have widget a widget body then pass it to the template
|
||||
// so that it is available to the widget tag and can be inserted
|
||||
// at the w-body marker
|
||||
widgetBody = getInitialBody(input, out);
|
||||
}
|
||||
}
|
||||
|
||||
if (getInitialBody) {
|
||||
// If we have widget a widget body then pass it to the template
|
||||
// so that it is available to the widget tag and can be inserted
|
||||
// at the w-body marker
|
||||
widgetBody = getInitialBody(input, out);
|
||||
} else {
|
||||
if (!widgetBody) {
|
||||
// Default to using the nested content as the widget body
|
||||
// getInitialBody was not implemented
|
||||
widgetBody = input.renderBody;
|
||||
}
|
||||
|
||||
@ -292,7 +295,7 @@ module.exports = function createRendererFunc(templateRenderFunc, widgetProps, re
|
||||
widgetDef.$__existingWidget = existingWidget;
|
||||
widgetDef.$__bodyElId = bodyElId;
|
||||
widgetDef.$__roots = roots;
|
||||
widgetDef.body = widgetBody;
|
||||
widgetDef.b = widgetBody;
|
||||
|
||||
// Render the template associated with the component using the final template
|
||||
// data that we constructed
|
||||
|
||||
41
widgets/taglib/TransformHelper/handleBodySlotNode.js
Normal file
41
widgets/taglib/TransformHelper/handleBodySlotNode.js
Normal file
@ -0,0 +1,41 @@
|
||||
'use strict';
|
||||
|
||||
var includeTagForWidgets = require.resolve('../include-tag');
|
||||
|
||||
module.exports = function(bodySlotNode) {
|
||||
if (!this.hasBoundWidgetForTemplate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var context = this.context;
|
||||
var builder = this.builder;
|
||||
|
||||
var parentNode = bodySlotNode.parentNode;
|
||||
|
||||
parentNode._normalizeChildTextNodes(context);
|
||||
|
||||
if (parentNode.childCount !== 1) {
|
||||
throw new Error('TBD');
|
||||
}
|
||||
|
||||
let parentTransformHelper = this.getTransformHelper(parentNode);
|
||||
|
||||
let includeNode = context.createNodeForEl('include');
|
||||
includeNode.data.bodySlot = true;
|
||||
includeNode.addProp('_target', builder.memberExpression(builder.identifier('widget'), builder.identifier('b')));
|
||||
includeNode.addProp('_elId', parentTransformHelper.getIdExpression());
|
||||
includeNode.addProp('_arg', builder.identifier('widget'));
|
||||
|
||||
parentTransformHelper.assignWidgetId(false /* not repeated */);
|
||||
var widgetProps = this.getWidgetProps();
|
||||
widgetProps.body = parentTransformHelper.getNestedIdExpression();
|
||||
|
||||
includeNode.setRendererPath(includeTagForWidgets);
|
||||
|
||||
// includeNode.onBeforeGenerateCode(function() {
|
||||
// includeNode.addProp('_elId', parentTransformHelper.getIdExpression());
|
||||
// includeNode.addProp('_arg', builder.identifier('widget'));
|
||||
// });
|
||||
|
||||
bodySlotNode.replaceWith(includeNode);
|
||||
};
|
||||
@ -21,7 +21,11 @@ module.exports = function(includeNode) {
|
||||
|
||||
let parentTransformHelper = this.getTransformHelper(parentNode);
|
||||
|
||||
if (includeNode.argument) {
|
||||
if (includeNode.data.bodySlot) {
|
||||
parentTransformHelper.assignWidgetId(false /* not repeated */);
|
||||
var widgetProps = this.getWidgetProps();
|
||||
widgetProps.body = parentTransformHelper.getNestedIdExpression();
|
||||
} else {
|
||||
let widgetIdInfo = parentTransformHelper.assignWidgetId(true /* repeated */);
|
||||
if (!widgetIdInfo.idVarNode) {
|
||||
let idVarNode = widgetIdInfo.createIdVarNode();
|
||||
@ -29,19 +33,11 @@ module.exports = function(includeNode) {
|
||||
event.insertCode(idVarNode);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
parentTransformHelper.assignWidgetId(false /* not repeated */);
|
||||
var widgetProps = this.getWidgetProps();
|
||||
widgetProps.body = parentTransformHelper.getNestedIdExpression();
|
||||
}
|
||||
|
||||
includeNode.setRendererPath(includeTagForWidgets);
|
||||
|
||||
includeNode.onBeforeGenerateCode(function() {
|
||||
if (!includeNode.data.includeTarget) {
|
||||
includeNode.addProp('_target', builder.memberExpression(builder.identifier('widget'), builder.identifier('body')));
|
||||
}
|
||||
|
||||
includeNode.addProp('_elId', parentTransformHelper.getIdExpression());
|
||||
includeNode.addProp('_arg', builder.identifier('widget'));
|
||||
});
|
||||
|
||||
@ -142,6 +142,7 @@ class TransformHelper {
|
||||
}
|
||||
|
||||
TransformHelper.prototype.assignWidgetId = require('./assignWidgetId');
|
||||
TransformHelper.prototype.handleBodySlotNode = require('./handleBodySlotNode');
|
||||
TransformHelper.prototype.handleRootNodes = require('./handleRootNodes');
|
||||
TransformHelper.prototype.handleIncludeNode = require('./handleIncludeNode');
|
||||
TransformHelper.prototype.handleWidgetEvents = require('./handleWidgetEvents');
|
||||
|
||||
@ -96,14 +96,12 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"@body-slot": {
|
||||
"preserve-name": true
|
||||
},
|
||||
"@w-body": {
|
||||
"preserve-name": true,
|
||||
"autocomplete": [
|
||||
{
|
||||
"openTagOnly": true,
|
||||
"descriptionMoreURL": "http://markojs.com/docs/marko-widgets/get-started/#adding-dom-event-listeners"
|
||||
}
|
||||
]
|
||||
"autocomplete": []
|
||||
},
|
||||
"@w-preserve": {
|
||||
"type": "flag",
|
||||
|
||||
@ -10,11 +10,23 @@ module.exports = function transform(el, context) {
|
||||
}
|
||||
|
||||
if (el.hasAttribute('w-body')) {
|
||||
var bodyAttr = el.getAttributeValue('w-body');
|
||||
let bodyValue = el.getAttributeValue('w-body');
|
||||
el.removeAttribute('w-body');
|
||||
|
||||
let includeNode = context.createNodeForEl('include', null, bodyAttr && bodyAttr.toString());
|
||||
el.appendChild(includeNode);
|
||||
if (bodyValue) {
|
||||
let includeNode = context.createNodeForEl('include');
|
||||
includeNode.addProp('_target', bodyValue);
|
||||
el.appendChild(includeNode);
|
||||
} else {
|
||||
el.setAttributeValue('body-slot', null);
|
||||
}
|
||||
}
|
||||
|
||||
if (el.hasAttribute('body-slot')) {
|
||||
el.removeAttribute('body-slot');
|
||||
|
||||
let bodySlotNode = context.createNodeForEl('body-slot');
|
||||
el.appendChild(bodySlotNode);
|
||||
}
|
||||
|
||||
if (el.tagName === 'widget-types') {
|
||||
@ -23,6 +35,9 @@ module.exports = function transform(el, context) {
|
||||
transformHelper.handleIncludeNode(el);
|
||||
transformHelper.getWidgetArgs().compile(transformHelper);
|
||||
return;
|
||||
} else if (el.tagName === 'body-slot') {
|
||||
transformHelper.handleBodySlotNode(el);
|
||||
return;
|
||||
}
|
||||
|
||||
if (el.hasAttribute('w-el-id')) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user