Skip to content

Commit 4985fea

Browse files
committed
Add support for multiple actions. #50
1 parent dc5b33b commit 4985fea

File tree

7 files changed

+69
-44
lines changed

7 files changed

+69
-44
lines changed

django_unicorn/static/js/component.js

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export class Component {
8282
document.addEventListener(eventType, (event) => {
8383
const targetElement = new Element(event.target);
8484

85-
if (targetElement && targetElement.isUnicorn && !isEmpty(targetElement.action)) {
85+
if (targetElement && targetElement.isUnicorn && targetElement.actions.length > 0) {
8686
this.actionEvents[eventType].forEach((element) => {
8787
// Use isSameNode (not isEqualNode) because we want to check the nodes reference the same object
8888
if (targetElement.el.isSameNode(element.el)) {
@@ -91,21 +91,23 @@ export class Component {
9191
this.actionQueue.push(action);
9292
}
9393

94-
if (element.action.isPrevent) {
95-
event.preventDefault();
96-
}
94+
element.actions.forEach((action) => {
95+
if (action.isPrevent) {
96+
event.preventDefault();
97+
}
9798

98-
if (element.action.isStop) {
99-
event.stopPropagation();
100-
}
99+
if (action.isStop) {
100+
event.stopPropagation();
101+
}
101102

102-
if (element.action.key) {
103-
if (element.action.key === toKebabCase(event.key)) {
104-
this.callMethod(element.action.name);
103+
if (action.key) {
104+
if (action.key === toKebabCase(event.key)) {
105+
this.callMethod(action.name);
106+
}
107+
} else {
108+
this.callMethod(action.name);
105109
}
106-
} else {
107-
this.callMethod(element.action.name);
108-
}
110+
});
109111
}
110112
});
111113
}
@@ -174,18 +176,18 @@ export class Component {
174176
}
175177
}
176178

177-
if (!isEmpty(element.action)) {
178-
if (this.actionEvents[element.action.eventType]) {
179-
this.actionEvents[element.action.eventType].push(element);
179+
element.actions.forEach((action) => {
180+
if (this.actionEvents[action.eventType]) {
181+
this.actionEvents[action.eventType].push(element);
180182
} else {
181-
this.actionEvents[element.action.eventType] = [element];
183+
this.actionEvents[action.eventType] = [element];
182184

183-
if (this.attachedEventTypes.filter((et) => et === element.action.eventType).length === 0) {
184-
this.attachedEventTypes.push(element.action.eventType);
185-
this.addActionEventListener(element.action.eventType);
185+
if (this.attachedEventTypes.filter((et) => et === action.eventType).length === 0) {
186+
this.attachedEventTypes.push(action.eventType);
187+
this.addActionEventListener(action.eventType);
186188
}
187189
}
188-
}
190+
});
189191
}
190192
});
191193
}

django_unicorn/static/js/element.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export class Element {
2020

2121
this.model = {};
2222
this.poll = {};
23-
this.action = {};
23+
this.actions = [];
2424

2525
this.key = undefined;
2626
this.errors = [];
@@ -47,23 +47,26 @@ export class Element {
4747
this.poll.method = attribute.value ? attribute.value : "refresh";
4848
this.poll.timing = parseInt(Object.keys(attribute.modifiers)[0], 10) || 2000;
4949
} else if (attribute.eventType) {
50-
this.action.name = attribute.value;
51-
this.action.eventType = attribute.eventType;
52-
this.action.isPrevent = false;
53-
this.action.isStop = false;
50+
const action = {};
51+
action.name = attribute.value;
52+
action.eventType = attribute.eventType;
53+
action.isPrevent = false;
54+
action.isStop = false;
5455

5556
if (attribute.modifiers) {
5657
Object.keys(attribute.modifiers).forEach((modifier) => {
5758
if (modifier === "prevent") {
58-
this.action.isPrevent = true;
59+
action.isPrevent = true;
5960
} else if (modifier === "stop") {
60-
this.action.isStop = true;
61+
action.isStop = true;
6162
} else {
6263
// Assume the modifier is a keycode
63-
this.action.key = modifier;
64+
action.key = modifier;
6465
}
6566
});
6667
}
68+
69+
this.actions.push(action);
6770
}
6871

6972
if (attribute.isKey) {

example/unicorn/templates/unicorn/text-inputs.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
<label>Chained lazy and debounce-500</label>
3131
<input unicorn:model.lazy.debounce-500="name" type="text" id="lazyDebounceName">
3232

33+
<label>Multiple actions</label>
34+
<input unicorn:model="name" type="text" unicorn:keyup.enter="name='enter'" unicorn:keydown.escape="name=''"></input>
35+
3336
<br />
3437
<button unicorn:click="set_name">set_name</button>
3538
<button unicorn:click="set_name()">set_name()</button>

tests/js/element/action.test.js

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,46 @@ test("click", (t) => {
55
const html = "<button unicorn:click='test()'></button>";
66
const element = getElement(html);
77

8-
t.is(element.action.name, "test()");
9-
t.is(element.action.eventType, "click");
8+
const action = element.actions[0];
9+
t.is(action.name, "test()");
10+
t.is(action.eventType, "click");
1011
});
1112

1213
test("keydown.enter", (t) => {
1314
const html = "<input unicorn:keydown.enter='test()'></input>";
1415
const element = getElement(html);
1516

16-
t.is(element.action.name, "test()");
17-
t.is(element.action.eventType, "keydown");
18-
t.is(element.action.key, "enter");
17+
const action = element.actions[0];
18+
t.is(action.name, "test()");
19+
t.is(action.eventType, "keydown");
20+
t.is(action.key, "enter");
1921
});
2022

2123
test("click.prevent", (t) => {
2224
const html = "<a href='#' unicorn:click.prevent='test()'>Test()</a>";
2325
const element = getElement(html);
2426

25-
t.true(element.action.isPrevent);
26-
t.is(element.action.eventType, "click");
27-
t.is(element.action.key, undefined);
27+
const action = element.actions[0];
28+
t.true(action.isPrevent);
29+
t.is(action.eventType, "click");
30+
t.is(action.key, undefined);
2831
});
2932

3033
test("click.stop", (t) => {
3134
const html = "<a href='#' unicorn:click.stop='test()'>Test()</a>";
3235
const element = getElement(html);
3336

34-
t.true(element.action.isStop);
35-
t.is(element.action.eventType, "click");
36-
t.is(element.action.key, undefined);
37+
const action = element.actions[0];
38+
t.true(action.isStop);
39+
t.is(action.eventType, "click");
40+
t.is(action.key, undefined);
41+
});
42+
43+
test("multiple actions", (t) => {
44+
const html = "<input unicorn:keyup.enter='add' unicorn:keydown.escape='clear'></input>";
45+
const element = getElement(html);
46+
47+
t.true(element.actions.length === 2);
48+
t.true(element.actions[0].eventType === "keyup");
49+
t.true(element.actions[1].eventType === "keydown");
3750
});

tests/js/element/init.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,21 @@ test("unicorn:id is not an action", (t) => {
2727
const element = getElement(html);
2828

2929
t.true(element.isUnicorn);
30-
t.deepEqual(element.action, {});
30+
t.is(element.actions.length, 0);
3131
});
3232

3333
test("unicorn:key is not an action", (t) => {
3434
const html = "<div unicorn:key='hjkl'></div>";
3535
const element = getElement(html);
3636

3737
t.true(element.isUnicorn);
38-
t.deepEqual(element.action, {});
38+
t.is(element.actions.length, 0);
3939
});
4040

4141
test("unicorn:checksum is not an action", (t) => {
4242
const html = "<div unicorn:checksum='fghj'></div>";
4343
const element = getElement(html);
4444

4545
t.true(element.isUnicorn);
46-
t.deepEqual(element.action, {});
46+
t.is(element.actions.length, 0);
4747
});

tests/js/utils/morphdom.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ test("contains", (t) => {
1010
Name:
1111
</div>
1212
`;
13-
let componentRoot = getEl(componentRootHtml);
13+
const componentRoot = getEl(componentRootHtml);
1414

1515
const rerenderedComponentHtml = `
1616
<div unicorn:id="5jypjiyb" unicorn:name="text-inputs" unicorn:checksum="GXzew3Km">

tests/js/utils/toKebobCase.test.js renamed to tests/js/utils/toKebabCase.test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ test("Escape to kebab case", (t) => {
1212
test("Null to empty string", (t) => {
1313
t.is(toKebabCase(null), "");
1414
});
15+
16+
test("Empty string to empty string", (t) => {
17+
t.is(toKebabCase(""), "");
18+
});

0 commit comments

Comments
 (0)