Deprecated w-on* attributes (#434)

Added support for on*() attributes.
This commit is contained in:
Charlie Duong 2016-11-16 13:53:51 -05:00 committed by Michael Rawlings
parent 3eb3c286e8
commit fc82ef0cf0
38 changed files with 122 additions and 81 deletions

View File

@ -264,7 +264,7 @@ And, here is the corresponding Marko template for the UI component:
<div>
You clicked the button ${data.clickCount} ${data.timesMessage}.
</div>
<button type="button" w-onclick="handleButtonClick">
<button type="button" onClick("handleButtonClick")>
Click Me
</button>
</div>

View File

@ -51,6 +51,7 @@ var SequenceExpression = require('./ast/SequenceExpression');
var parseExpression = require('./util/parseExpression');
var parseStatement = require('./util/parseStatement');
var parseJavaScriptArgs = require('./util/parseJavaScriptArgs');
var replacePlaceholderEscapeFuncs = require('./util/replacePlaceholderEscapeFuncs');
var isValidJavaScriptIdentifier = require('./util/isValidJavaScriptIdentifier');
var DEFAULT_BUILDER;
@ -420,6 +421,10 @@ class Builder {
return parsed;
}
replacePlaceholderEscapeFuncs(node, context) {
return replacePlaceholderEscapeFuncs(node, context);
}
program(body) {
return new Program({body});
}

View File

@ -1,6 +1,6 @@
'use strict';
var ok = require('assert').ok;
var AttributePlaceholder = require('./ast/AttributePlaceholder');
var replacePlaceholderEscapeFuncs = require('./util/replacePlaceholderEscapeFuncs');
var COMPILER_ATTRIBUTE_HANDLERS = {
'preserve-whitespace': function(attr, context) {
@ -17,24 +17,6 @@ function isIEConditionalComment(comment) {
return ieConditionalCommentRegExp.test(comment);
}
function replacePlaceholderEscapeFuncs(node, context) {
var walker = context.createWalker({
exit: function(node, parent) {
if (node.type === 'FunctionCall' &&
node.callee.type === 'Identifier') {
if (node.callee.name === '$noEscapeXml') {
return new AttributePlaceholder({escape: false, value: node.args[0]});
} else if (node.callee.name === '$escapeXml') {
return new AttributePlaceholder({escape: true, value: node.args[0]});
}
}
}
});
return walker.walk(node);
}
function mergeShorthandClassNames(el, shorthandClassNames, context) {
var builder = context.builder;
let classNames = shorthandClassNames.map((className) => {

View File

@ -0,0 +1,19 @@
var AttributePlaceholder = require('../ast/AttributePlaceholder');
module.exports = function replacePlaceholderEscapeFuncs(node, context) {
var walker = context.createWalker({
exit: function(node, parent) {
if (node.type === 'FunctionCall' &&
node.callee.type === 'Identifier') {
if (node.callee.name === '$noEscapeXml') {
return new AttributePlaceholder({escape: false, value: node.args[0]});
} else if (node.callee.name === '$escapeXml') {
return new AttributePlaceholder({escape: true, value: node.args[0]});
}
}
}
});
return walker.walk(node);
};

View File

@ -308,8 +308,8 @@ Listeners can be attached declaratively as shown in the following sample code:
```xml
<div w-bind>
<form w-onsubmit="handleFormSubmit">
<input type="text" value="email" w-onchange="handleEmailChange">
<form onsubmit("handleFormSubmit")>
<input type="text" value="email" onchange("handleEmailChange")>
<button>Submit</button>
</form>
</div>
@ -406,7 +406,7 @@ Listeners can be attached declaratively as shown in the following sample code:
```xml
<div w-bind="./widget">
<app-overlay title="My Overlay"
w-onBeforeHide="handleOverlayBeforeHide">
onBeforeHide("handleOverlayBeforeHide")>
Content for overlay
@ -699,7 +699,7 @@ ___src/components/app-hello/template.marko:___
```xml
<div w-bind
w-on-click="handleClick">
on-click("handleClick")>
Hello ${data.name}!
</div>
```
@ -736,7 +736,7 @@ ___src/components/app-hello/template.marko:___
```xml
<div w-bind="./widget"
w-on-click="handleClick">
on-click("handleClick")>
Hello ${data.name}!
</div>
```

View File

@ -113,7 +113,7 @@ __src/components/app-hello/template.marko__
```xml
<div w-bind
w-onClick="handleClick">
onClick("handleClick")>
Hello ${data.name}!
@ -154,7 +154,7 @@ __src/components/app-hello/template.marko__
```xml
<div w-bind
w-onClick="handleClick"
onClick("handleClick")
style="background-color: ${data.color}">
Hello ${data.name}!
@ -202,7 +202,7 @@ __src/components/app-hello/template.marko__
```xml
<div w-bind
w-onClick="handleClick"
onClick("handleClick")
style="background-color: ${data.color}">
Hello ${data.name}!
@ -258,17 +258,17 @@ module.exports = require('marko-widgets').defineComponent({
<div w-bind>
<app-overlay title="My Overlay"
ref="overlay"
w-onBeforeHide="handleOverlayBeforeHide">
onBeforeHide("handleOverlayBeforeHide")>
Body content for overlay.
</app-overlay>
<button type="button"
w-onClick="handleShowButtonClick">
onClick("handleShowButtonClick")>
Show Overlay
</button>
<button type="button"
w-onClick="handleHideButtonClick">
onClick("handleHideButtonClick")>
Hide Overlay
</button>
</div>

View File

@ -85,7 +85,7 @@ NOTE: For DOM events that bubble, efficient DOM event delegation will automatica
```xml
<div w-bind="./widget">
<button w-onclick="handleMyButtonClick" type="button">My Button</button>
<button onClick("handleMyButtonClick") type="button">My Button</button>
</div>
```
@ -113,7 +113,7 @@ var myButton = this.getEl('myButton');
```xml
<div w-bind="./widget">
<app-button w-onSomeCustomEvent="handleSomeCustomEvent" label="My Button" />
<app-button onSomeCustomEvent("handleSomeCustomEvent") label="My Button" />
</div>
```

View File

@ -28,5 +28,6 @@
"no-update-if",
"no-update-body-if",
"w-preserve-attrs",
"on*",
"w-on*"
]

View File

@ -1,4 +1,4 @@
<button ${data.rootAttrs}
w-onclick="handleClick"
onClick("handleClick")
w-bind
include()></button>

View File

@ -1,4 +1,4 @@
<button ${data.rootAttrs}
w-onclick="handleClick"
onClick("handleClick")
w-bind
include()></button>

View File

@ -5,8 +5,8 @@
<app-bar ref="barArray[]" label="1"/>
<app-bar ref="barArray[]" label="2"/>
<app-custom-events w-onTestEvent="handleTestEvent1" ref="customEvents" />
<app-custom-events w-onTestEvent="handleTestEvent2" channel="customEvents-${widget.id}" />
<app-custom-events onTestEvent("handleTestEvent1") ref="customEvents" />
<app-custom-events onTestEvent("handleTestEvent2") channel="customEvents-${widget.id}" />
<ul>
<li for(color in ['red', 'green', 'blue']) ref="colorListItems[]">${color}</li>

View File

@ -5,8 +5,8 @@
<app-bar ref="barArray[]" label="1"/>
<app-bar ref="barArray[]" label="2"/>
<app-custom-events w-onTestEvent="handleTestEvent1" ref="customEvents" />
<app-custom-events w-onTestEvent="handleTestEvent2" channel="customEvents-${widget.id}" />
<app-custom-events onTestEvent("handleTestEvent1") ref="customEvents" />
<app-custom-events onTestEvent("handleTestEvent2") channel="customEvents-${widget.id}" />
<ul>
<li for(color in ['red', 'green', 'blue']) ref="colorListItems[]">${color}</li>

View File

@ -5,8 +5,8 @@
<app-bar ref="barArray[]" label="1"/>
<app-bar ref="barArray[]" label="2"/>
<app-custom-events w-onTestEvent="handleTestEvent1" ref="customEvents" />
<app-custom-events w-onTestEvent="handleTestEvent2" channel="customEvents-${widget.id}" />
<app-custom-events onTestEvent("handleTestEvent1") ref="customEvents" />
<app-custom-events onTestEvent("handleTestEvent2") channel="customEvents-${widget.id}" />
<ul>
<li for(color in ['red', 'green', 'blue']) ref="colorListItems[]">${color}</li>

View File

@ -1,5 +1,5 @@
<button type="button" class="app-legacy-button"
w-bind="./widget"
w-onmousedown="handleRootMouseDown">
onMousedown("handleRootMouseDown")>
<invoke data.renderBody(out)/>
</button>

View File

@ -1,6 +1,6 @@
<div w-bind>
<a href="#foo" ref="fooLink"
w-ondblclick="handleFooLinkDblClick"
w-onmouseout="handleFooLinkMouseOut">
onDblclick("handleFooLinkDblClick")
onMouseout("handleFooLinkMouseOut")>
</a>
</div>

View File

@ -1,6 +1,6 @@
<div w-bind>
<ul>
<li w-onMouseMove="handleMouseMove" ref="foo-${loop.getIndex()}"
<li onMouseMove("handleMouseMove") ref="foo-${loop.getIndex()}"
for(color in ['red', 'green', 'blue'] | status-var=loop)>${color}</li>
</ul>
</div>

View File

@ -1,5 +1,5 @@
<button type="button" class="app-legacy-button"
w-bind="./widget"
w-onmousedown="handleRootMouseDown">
onMousedown("handleRootMouseDown")>
<invoke data.renderBody(out)/>
</button>

View File

@ -1,20 +1,20 @@
<div class="app-dom-events"
w-bind="./widget"
w-onmousemove="handleRootMouseMove"
w-onClick="handleRootClick">
onMousemove("handleRootMouseMove")
onClick("handleRootClick")>
<button type="button" ref="button"
w-onclick="handleButtonClick">
<span w-onmousemove="handleButtonSpanMouseMove">
onClick("handleButtonClick")>
<span onMousemove("handleButtonSpanMouseMove")>
Button
</span>
</button>
<a href="#foo" id="fooLink"
w-ondblclick="handleFooLinkDblClick"
w-onmouseout="handleFooLinkMouseOut">
onDblclick("handleFooLinkDblClick")
onMouseout("handleFooLinkMouseOut")>
</a>
<app-legacy-button ref="appButton">
<span ref="helloWorld" w-onmousedown="handleHelloWorldMouseDown">Hello World</span>
<span ref="helloWorld" onMousedown("handleHelloWorldMouseDown")>Hello World</span>
</app-legacy-button>
</div>

View File

@ -1,5 +1,5 @@
<div w-bind>
<input w-onclick=(false && 'handleButtonClick') ref="inputWithoutHandler" type="button">
<input w-onclick=(true && 'handleButtonClick') ref="inputWithHandler" type="button">
<input w-onclick='handleButtonClick' ref="inputWithLiteralHandler" type="button">
<input onClick(false && 'handleButtonClick') ref="inputWithoutHandler" type="button">
<input onClick(true && 'handleButtonClick') ref="inputWithHandler" type="button">
<input onClick('handleButtonClick') ref="inputWithLiteralHandler" type="button">
</div>

View File

@ -1,5 +1,5 @@
<div w-bind>
<input w-onMouseMove=(false && "handleMouseMove") ref="inputWithoutHandler" type="button">
<input w-onMouseMove=(true && 'handleMouseMove') ref="inputWithHandler" type="button">
<input w-onMouseMove='handleMouseMove' ref="inputWithLiteralHandler" type="button">
<input onMouseMove(false && "handleMouseMove") ref="inputWithoutHandler" type="button">
<input onMouseMove(true && 'handleMouseMove') ref="inputWithHandler" type="button">
<input onMouseMove('handleMouseMove') ref="inputWithLiteralHandler" type="button">
</div>

View File

@ -1,7 +1,7 @@
<div w-bind>
<h1>app-macro-events</h1>
<macro renderButton(id, label, handler)>
<button ref="${id}" type="button" w-onClick="${handler}">
<button ref="${id}" type="button" onClick("${handler}")>
$label
</button>
</macro>

View File

@ -1,5 +1,5 @@
<button ${data.rootAttrs}
w-onclick="handleClick"
onClick("handleClick")
w-bind="./widget">
<if(data.label)>

View File

@ -1,4 +1,4 @@
<button ${data.rootAttrs}
w-onclick="handleClick"
onClick("handleClick")
w-bind
include()></button>

View File

@ -1,4 +1,4 @@
<button ${data.rootAttrs}
w-onclick="handleClick"
onClick("handleClick")
w-bind
include()></button>

View File

@ -1,4 +1,4 @@
<button ${data.rootAttrs}
w-onclick="handleClick"
onClick("handleClick")
w-bind
include></button>

View File

@ -1,4 +1,4 @@
<button ${data.rootAttrs}
w-onclick="handleClick"
onClick("handleClick")
w-bind
include()></button>

View File

@ -1,4 +1,4 @@
<button ${data.rootAttrs}
w-onclick="handleClick"
onClick("handleClick")
w-bind
include()></button>

View File

@ -1,4 +1,4 @@
<button ${data.rootAttrs}
w-onclick="handleClick"
onClick("handleClick")
w-bind
include()></button>

View File

@ -1,4 +1,4 @@
<button ${data.rootAttrs}
w-onclick="handleClick"
onClick("handleClick")
w-bind
include()></button>

View File

@ -1,4 +1,4 @@
<button ${data.rootAttrs}
w-onclick="handleClick"
onClick("handleClick")
w-bind
include()></button>

View File

@ -1,4 +1,4 @@
<button ${data.rootAttrs}
w-onclick="handleClick"
onClick("handleClick")
w-bind
include()></button>

View File

@ -1,4 +1,4 @@
<button ${data.rootAttrs}
w-onclick="handleClick"
onClick("handleClick")
w-bind
include()></button>

View File

@ -1,7 +1,7 @@
<div w-bind>
<div w-onclick="handleDivClick">
<div onClick("handleDivClick")>
Hello
<button ref="button" type="button" w-onclick="handleButtonClick">
<button ref="button" type="button" onClick("handleButtonClick")>
Button
</button>
</div>

View File

@ -1,2 +1,2 @@
div w-bind
button ref="button" w-onMouseMove='handleButtonMouseMove' w-onClick="handleButtonClick"
button ref="button" onMouseMove('handleButtonMouseMove') onClick("handleButtonClick")

View File

@ -1,4 +1,4 @@
<button ${data.rootAttrs}
w-onclick="handleClick"
onClick("handleClick")
w-bind
w-body></button>

View File

@ -48,7 +48,7 @@ var attachBubbleEventListeners = function() {
var target;
// Attributes will have the following form:
// w-on<event_type>="<target_method>|<widget_id>"
// on<event_type>("<target_method>|<widget_id>")
do {
if ((target = getEventAttribute(curNode, attrName))) {

View File

@ -89,6 +89,7 @@ function addCustomEventListener(transformHelper, eventType, targetMethod) {
module.exports = function handleWidgetEvents() {
var el = this.el;
var builder = this.builder;
var context = this.context;
var isCustomTag = el.type !== 'HtmlElement';
// We configured the Marko compiler to attach a flag to nodes that
// have one or more attributes that match the "w-on*" pattern.
@ -100,16 +101,35 @@ module.exports = function handleWidgetEvents() {
var attrs = el.getAttributes().concat([]);
attrs.forEach((attr) => {
var eventType;
var targetMethod;
var attrName = attr.name;
if (!attrName || !attrName.startsWith('w-on')) {
var args = attr.argument;
if (!attrName) {
return;
}
if (attrName.startsWith('on') && args) {
eventType = attrName.substring(2); // Chop off "on"
try {
var parsedArgs = builder.parseExpression(args);
targetMethod = builder.replacePlaceholderEscapeFuncs(parsedArgs, context);
} catch (err) {
this.addError('Invalid Javascript Expression for "' + attrName + '": ' + err);
}
} else if (attrName.startsWith('w-on')) {
console.warn('"w-on*" attributes are deprecated. Please use "on*()" instead. (' + (el.pos ? context.getPosInfo(el.pos) : context.filename) + ')');
eventType = attrName.substring(4); // Chop off "w-on"
targetMethod = attr.value;
}
if (!eventType || !targetMethod) {
return;
}
el.removeAttribute(attrName);
var eventType = attrName.substring(4); // Chop off "w-on"
var targetMethod = attr.value;
if (isCustomTag) {
var widgetArgs = this.getWidgetArgs();
if (widgetArgs.getId() == null) {
@ -165,4 +185,4 @@ module.exports = function handleWidgetEvents() {
});
}
};
};

View File

@ -64,6 +64,20 @@
}
]
},
"@on*": {
"pattern": true,
"type": "statement",
"allow-expressions": true,
"preserve-name": true,
"set-flag": "hasWidgetEvents",
"autocomplete": [
{
"displayText": "on<event>(\"<method>\")",
"snippet": "on${1:Click}(\"handle${2:Button}${1:Click}\")",
"descriptionMoreURL": "http://markojs.com/docs/marko-widgets/get-started/#adding-dom-event-listeners"
}
]
},
"@w-on*": {
"pattern": true,
"type": "string",