Skip to content

Commit 484c3c6

Browse files
Merge pull request #2440 from NullVoxPopuli/nvp/template-lint-extract-rule-template-no-inline-event-handlers
Extract rule: template-no-inline-event-handlers
2 parents 1430c61 + 591d810 commit 484c3c6

File tree

4 files changed

+202
-0
lines changed

4 files changed

+202
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ rules in templates can be disabled with eslint directives with mustache or html
203203
| [template-no-chained-this](docs/rules/template-no-chained-this.md) | disallow redundant `this.this` in templates | | 🔧 | |
204204
| [template-no-debugger](docs/rules/template-no-debugger.md) | disallow {{debugger}} in templates | | | |
205205
| [template-no-element-event-actions](docs/rules/template-no-element-event-actions.md) | disallow element event actions (use {{on}} modifier instead) | | | |
206+
| [template-no-inline-event-handlers](docs/rules/template-no-inline-event-handlers.md) | disallow DOM event handler attributes | | | |
206207
| [template-no-inline-styles](docs/rules/template-no-inline-styles.md) | disallow inline styles | | | |
207208
| [template-no-input-placeholder](docs/rules/template-no-input-placeholder.md) | disallow placeholder attribute on input elements | | | |
208209
| [template-no-input-tagname](docs/rules/template-no-input-tagname.md) | disallow tagName attribute on {{input}} helper | | | |
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# ember/template-no-inline-event-handlers
2+
3+
<!-- end auto-generated rule header -->
4+
5+
Disallows DOM event handler attributes in templates.
6+
7+
Inline event handlers like `onclick="..."` are an older pattern that should be replaced with the `{{on}}` modifier for better Ember integration and testability.
8+
9+
## Rule Details
10+
11+
This rule disallows the use of inline DOM event handler attributes like `onclick`, `onsubmit`, etc.
12+
13+
## Examples
14+
15+
Examples of **incorrect** code for this rule:
16+
17+
```gjs
18+
<template>
19+
<button onclick="alert('test')">Click</button>
20+
</template>
21+
```
22+
23+
```gjs
24+
<template>
25+
<div onmousedown="handleEvent()">Content</div>
26+
</template>
27+
```
28+
29+
```gjs
30+
<template>
31+
<form onsubmit="return false;">Form</form>
32+
</template>
33+
```
34+
35+
Examples of **correct** code for this rule:
36+
37+
```gjs
38+
<template>
39+
<button {{on "click" this.handleClick}}>Click</button>
40+
</template>
41+
```
42+
43+
```gjs
44+
<template>
45+
<input {{on "input" this.handleInput}} />
46+
</template>
47+
```
48+
49+
```gjs
50+
<template>
51+
<form {{on "submit" this.handleSubmit}}>Form</form>
52+
</template>
53+
```
54+
55+
## Migration
56+
57+
Replace:
58+
59+
```gjs
60+
<button onclick="alert('clicked')">
61+
```
62+
63+
With:
64+
65+
```gjs
66+
<button {{on "click" this.handleClick}}>
67+
```
68+
69+
## References
70+
71+
- [Ember.js Guides - Event Handling](https://guides.emberjs.com/release/components/component-state-and-actions/)
72+
- [eslint-plugin-ember template-no-inline-styles](https://github.com/ember-cli/eslint-plugin-ember/blob/master/docs/rules/template-no-inline-styles.md)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/** @type {import('eslint').Rule.RuleModule} */
2+
module.exports = {
3+
meta: {
4+
type: 'problem',
5+
docs: {
6+
description: 'disallow DOM event handler attributes',
7+
category: 'Best Practices',
8+
strictGjs: true,
9+
strictGts: true,
10+
url: 'https://github.com/ember-cli/eslint-plugin-ember/tree/master/docs/rules/template-no-inline-event-handlers.md',
11+
},
12+
fixable: null,
13+
schema: [],
14+
messages: {
15+
unexpected:
16+
'Do not use inline event handlers like "{{name}}". Use the (on) modifier instead.',
17+
},
18+
},
19+
20+
create(context) {
21+
const EVENT_HANDLER_ATTRS = new Set([
22+
'onclick',
23+
'ondblclick',
24+
'onmousedown',
25+
'onmouseup',
26+
'onmousemove',
27+
'onmouseout',
28+
'onmouseover',
29+
'onkeydown',
30+
'onkeyup',
31+
'onkeypress',
32+
'onchange',
33+
'oninput',
34+
'onsubmit',
35+
'onfocus',
36+
'onblur',
37+
'onload',
38+
'onerror',
39+
'onscroll',
40+
]);
41+
42+
return {
43+
GlimmerElementNode(node) {
44+
if (node.attributes) {
45+
for (const attr of node.attributes) {
46+
if (attr.name && EVENT_HANDLER_ATTRS.has(attr.name.toLowerCase())) {
47+
context.report({
48+
node: attr,
49+
messageId: 'unexpected',
50+
data: { name: attr.name },
51+
});
52+
}
53+
}
54+
}
55+
},
56+
};
57+
},
58+
};
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//------------------------------------------------------------------------------
2+
// Requirements
3+
//------------------------------------------------------------------------------
4+
5+
const rule = require('../../../lib/rules/template-no-inline-event-handlers');
6+
const RuleTester = require('eslint').RuleTester;
7+
8+
//------------------------------------------------------------------------------
9+
// Tests
10+
//------------------------------------------------------------------------------
11+
12+
const ruleTester = new RuleTester({
13+
parser: require.resolve('ember-eslint-parser'),
14+
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
15+
});
16+
17+
ruleTester.run('template-no-inline-event-handlers', rule, {
18+
valid: [
19+
`<template>
20+
<button {{on "click" this.handleClick}}>Click</button>
21+
</template>`,
22+
`<template>
23+
<input {{on "input" this.handleInput}} />
24+
</template>`,
25+
`<template>
26+
<div>No handlers</div>
27+
</template>`,
28+
],
29+
30+
invalid: [
31+
{
32+
code: `<template>
33+
<button onclick="alert('test')">Click</button>
34+
</template>`,
35+
output: null,
36+
errors: [
37+
{
38+
message:
39+
'Do not use inline event handlers like "onclick". Use the (on) modifier instead.',
40+
type: 'GlimmerAttrNode',
41+
},
42+
],
43+
},
44+
{
45+
code: `<template>
46+
<div onmousedown="handleEvent()">Content</div>
47+
</template>`,
48+
output: null,
49+
errors: [
50+
{
51+
message:
52+
'Do not use inline event handlers like "onmousedown". Use the (on) modifier instead.',
53+
type: 'GlimmerAttrNode',
54+
},
55+
],
56+
},
57+
{
58+
code: `<template>
59+
<form onsubmit="return false;">Form</form>
60+
</template>`,
61+
output: null,
62+
errors: [
63+
{
64+
message:
65+
'Do not use inline event handlers like "onsubmit". Use the (on) modifier instead.',
66+
type: 'GlimmerAttrNode',
67+
},
68+
],
69+
},
70+
],
71+
});

0 commit comments

Comments
 (0)