Skip to content

Commit 6a838b2

Browse files
committed
Add/use some utility functions.
1 parent 1867cae commit 6a838b2

File tree

6 files changed

+63
-61
lines changed

6 files changed

+63
-61
lines changed

django_unicorn/static/js/component.js

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { $, contains, isEmpty, walk } from "./utils.js";
1+
import { $, contains, hasValue, isEmpty, walk } from "./utils.js";
22
import { debounce } from "./delayers.js";
33
import { Element } from "./element.js";
44
import { send } from "./messageSender.js";
@@ -80,30 +80,28 @@ export class Component {
8080

8181
if (element.isUnicorn) {
8282
if (
83-
!isEmpty(element.field) &&
84-
!(isEmpty(element.db) && isEmpty(element.model))
83+
hasValue(element.field) &&
84+
(hasValue(element.db) || hasValue(element.model))
8585
) {
86-
if (!this.attachedDbEvents.some((e) => e.el.isSameNode(element.el))) {
86+
if (!this.attachedDbEvents.some((e) => e.isSame(element))) {
8787
this.attachedDbEvents.push(element);
8888
addDbEventListener(this, element.el, element.field.eventType);
8989
}
9090

91-
if (!this.dbEls.some((e) => e.el.isSameNode(element.el))) {
91+
if (!this.dbEls.some((e) => e.isSame(element))) {
9292
this.dbEls.push(element);
9393
}
9494
} else if (
95-
!isEmpty(element.model) &&
95+
hasValue(element.model) &&
9696
isEmpty(element.db) &&
9797
isEmpty(element.field)
9898
) {
99-
if (
100-
!this.attachedModelEvents.some((e) => e.el.isSameNode(element.el))
101-
) {
99+
if (!this.attachedModelEvents.some((e) => e.isSame(element))) {
102100
this.attachedModelEvents.push(element);
103101
addModelEventListener(this, element.el, element.model.eventType);
104102
}
105103

106-
if (!this.modelEls.some((e) => e.el.isSameNode(element.el))) {
104+
if (!this.modelEls.some((e) => e.isSame(element))) {
107105
this.modelEls.push(element);
108106
}
109107
}
@@ -154,7 +152,7 @@ export class Component {
154152
initPolling() {
155153
const rootElement = new Element(this.root);
156154

157-
if (rootElement.isUnicorn && !isEmpty(rootElement.poll)) {
155+
if (rootElement.isUnicorn && hasValue(rootElement.poll)) {
158156
this.poll = rootElement.poll;
159157
this.poll.timer = null;
160158

@@ -250,7 +248,7 @@ export class Component {
250248
// Empty string for the PK implies that the model is not associated to an actual model instance
251249
element.setValue("");
252250
} else {
253-
if (typeof element.model.name === "undefined") {
251+
if (isEmpty(element.model.name)) {
254252
throw Error("Setting a field value requires a model to be set");
255253
}
256254

@@ -285,8 +283,8 @@ export class Component {
285283
const lastTriggeringElement = triggeringElements.slice(-1)[0];
286284

287285
if (
288-
typeof lastTriggeringElement !== "undefined" &&
289-
!isEmpty(lastTriggeringElement.model) &&
286+
hasValue(lastTriggeringElement) &&
287+
hasValue(lastTriggeringElement.model) &&
290288
!lastTriggeringElement.model.isLazy
291289
) {
292290
["id", "key"].forEach((attr) => {
@@ -309,7 +307,7 @@ export class Component {
309307
let shouldSetValue = false;
310308

311309
triggeringElements.forEach((triggeringElement) => {
312-
if (!element.el.isSameNode(triggeringElement.el)) {
310+
if (!element.isSame(triggeringElement)) {
313311
shouldSetValue = true;
314312
}
315313
});

django_unicorn/static/js/element.js

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Attribute } from "./attribute.js";
2-
import { isEmpty, hasValue } from "./utils.js";
2+
import { isEmpty, generateDbKey, hasValue } from "./utils.js";
33

44
/**
55
* Encapsulate DOM element for Unicorn-related information.
@@ -30,7 +30,7 @@ export class Element {
3030
this.db = {};
3131
this.field = {};
3232

33-
this.key = undefined;
33+
this.key = null;
3434
this.errors = [];
3535

3636
if (!this.el.attributes) {
@@ -112,41 +112,34 @@ export class Element {
112112
const dbAttrs = ["pk", "name"];
113113
let elToCheck = this;
114114

115+
// Look for `db.pk` and `db.name`
115116
dbAttrs.forEach((attr) => {
116117
elToCheck = this;
117118

118-
while (typeof this.db[attr] === "undefined" || this.db[attr] == null) {
119+
while (isEmpty(this.db[attr])) {
119120
if (elToCheck.el.getAttribute("unicorn:checksum")) {
120121
// A litte hacky, but stop looking after you hit the beginning of the component
121122
break;
122123
}
123124

124-
if (
125-
elToCheck.isUnicorn &&
126-
typeof elToCheck.db[attr] !== "undefined"
127-
) {
125+
if (elToCheck.isUnicorn && hasValue(elToCheck.db[attr])) {
128126
this.db[attr] = elToCheck.db[attr];
129127
}
130128

131129
elToCheck = elToCheck.parent;
132130
}
133131
});
134132

133+
// Look for model.name
135134
elToCheck = this;
136135

137-
while (
138-
typeof this.model.name === "undefined" ||
139-
this.model.name == null
140-
) {
136+
while (isEmpty(this.model.name)) {
141137
if (elToCheck.el.getAttribute("unicorn:checksum")) {
142138
// A litte hacky, but stop looking after you hit the beginning of the component
143139
break;
144140
}
145141

146-
if (
147-
elToCheck.isUnicorn &&
148-
typeof elToCheck.model.name !== "undefined"
149-
) {
142+
if (elToCheck.isUnicorn && hasValue(elToCheck.model.name)) {
150143
this.model.name = elToCheck.model.name;
151144
}
152145

@@ -166,11 +159,16 @@ export class Element {
166159
* A key that takes into consideration the db name and pk.
167160
*/
168161
dbKey() {
169-
if (hasValue(this.db) && hasValue(this.db.pk) && hasValue(this.db.name)) {
170-
return `${this.db.name}:${this.db.pk}`;
171-
}
162+
return generateDbKey(this);
163+
}
172164

173-
return null;
165+
/**
166+
* Check if another `Element` is the same as this `Element`.
167+
* @param {Element} other
168+
*/
169+
isSame(other) {
170+
// Use isSameNode (not isEqualNode) because we want to check the nodes reference the same object
171+
return this.el.isSameNode(other.el);
174172
}
175173

176174
/**

django_unicorn/static/js/eventListeners.js

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isEmpty, toKebabCase, walk } from "./utils.js";
1+
import { generateDbKey, isEmpty, toKebabCase, walk } from "./utils.js";
22
import { Element } from "./element.js";
33

44
/**
@@ -21,8 +21,7 @@ export function addActionEventListener(component, eventType) {
2121
const { action } = actionEvent;
2222
const { element } = actionEvent;
2323

24-
// Use isSameNode (not isEqualNode) because we want to check the nodes reference the same object
25-
if (targetElement.el.isSameNode(element.el)) {
24+
if (targetElement.isSame(element)) {
2625
// Add the value of any child element of the target that is a lazy model to the action queue
2726
// Handles situations similar to https://github.com/livewire/livewire/issues/528
2827
walk(element.el, (childEl) => {
@@ -106,9 +105,7 @@ export function addModelEventListener(component, el, eventType) {
106105
},
107106
};
108107

109-
if (
110-
!component.lastTriggeringElements.some((e) => e.el.isSameNode(element.el))
111-
) {
108+
if (!component.lastTriggeringElements.some((e) => e.isSame(element))) {
112109
component.lastTriggeringElements.push(element);
113110
}
114111

@@ -158,27 +155,21 @@ export function addDbEventListener(component, el, eventType) {
158155
const element = new Element(event.target);
159156

160157
if (
161-
((typeof element.db.name === "undefined" || element.db.name == null) &&
162-
(typeof element.model.name === "undefined" ||
163-
element.model.name == null)) ||
164-
typeof element.db.pk === "undefined" ||
165-
element.db.pk == null
158+
(isEmpty(element.db.name) && isEmpty(element.model.name)) ||
159+
isEmpty(element.db.pk)
166160
) {
167161
return;
168162
}
169163

170-
if (
171-
!component.lastTriggeringElements.some((e) => e.el.isSameNode(element.el))
172-
) {
164+
if (!component.lastTriggeringElements.some((e) => e.isSame(element))) {
173165
component.lastTriggeringElements.push(element);
174166
}
175167

176168
const action = {
177169
type: "dbInput",
178170
payload: {
179171
model: element.model.name,
180-
db: element.db.name,
181-
pk: element.db.pk,
172+
db: element.db,
182173
fields: {},
183174
},
184175
};
@@ -190,10 +181,7 @@ export function addDbEventListener(component, el, eventType) {
190181

191182
// Update the existing action with the current value
192183
component.actionQueue.forEach((a) => {
193-
if (
194-
a.payload.db === element.db.name &&
195-
a.payload.pk === element.db.pk
196-
) {
184+
if (generateDbKey(a.payload) === element.dbKey()) {
197185
a.payload.fields[element.field.name] = element.getValue();
198186
foundAction = true;
199187
}

django_unicorn/static/js/messageSender.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getCsrfToken } from "./utils.js";
1+
import { getCsrfToken, isFunction } from "./utils.js";
22
import morphdom from "./morphdom/2.6.1/morphdom.js";
33
import { MORPHDOM_OPTIONS } from "./morphdom/2.6.1/options.js";
44

@@ -93,7 +93,7 @@ export function send(component, callback) {
9393
// Clear the current action queue
9494
component.currentActionQueue = null;
9595

96-
if (callback && typeof callback === "function") {
96+
if (isFunction(callback)) {
9797
callback(triggeringElements, null);
9898
}
9999
})
@@ -103,7 +103,7 @@ export function send(component, callback) {
103103
component.currentActionQueue = null;
104104
component.lastTriggeringElements = [];
105105

106-
if (callback && typeof callback === "function") {
106+
if (isFunction(callback)) {
107107
callback(null, null, err);
108108
}
109109
});

django_unicorn/static/js/utils.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,25 @@ export function hasValue(obj) {
1616
return !isEmpty(obj);
1717
}
1818

19+
/**
20+
* Checks if an object is a function.
21+
*/
22+
export function isFunction(obj) {
23+
return obj && typeof obj === "function";
24+
}
25+
26+
/**
27+
* Makes a dbKey based on the passed-in object.
28+
* @param {*} obj
29+
*/
30+
export function generateDbKey(obj) {
31+
if (hasValue(obj.db) && hasValue(obj.db.pk) && hasValue(obj.db.name)) {
32+
return `${obj.db.name}:${obj.db.pk}`;
33+
}
34+
35+
return null;
36+
}
37+
1938
/**
2039
* Checks if a string has the search text.
2140
*/

django_unicorn/views.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,10 @@ def message(request: HttpRequest, component_name: str = None) -> JsonResponse:
238238
if action_type == "syncInput":
239239
_set_property_from_payload(component, payload, component_request.data)
240240
elif action_type == "dbInput":
241-
pk = payload.get("pk")
242-
243-
# Find model
244241
model = payload.get("model")
245-
db_model_name = payload.get("db")
242+
db = payload.get("db", {})
243+
db_model_name = db.get("name")
244+
pk = db.get("pk")
246245

247246
DbModel = None
248247
db_defaults = {}

0 commit comments

Comments
 (0)