phoenix_live_view 0.16.3 → 0.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +128 -7
- package/assets/js/phoenix_live_view/constants.js +2 -2
- package/assets/js/phoenix_live_view/dom.js +49 -13
- package/assets/js/phoenix_live_view/dom_patch.js +31 -11
- package/assets/js/phoenix_live_view/js.js +169 -0
- package/assets/js/phoenix_live_view/live_socket.js +143 -50
- package/assets/js/phoenix_live_view/view.js +113 -87
- package/assets/js/phoenix_live_view/view_hook.js +2 -2
- package/package.json +5 -3
- package/priv/static/phoenix_live_view.cjs.js +3737 -0
- package/priv/static/phoenix_live_view.cjs.js.map +7 -0
- package/priv/static/phoenix_live_view.esm.js +495 -167
- package/priv/static/phoenix_live_view.esm.js.map +3 -3
- package/priv/static/phoenix_live_view.js +495 -167
- package/priv/static/phoenix_live_view.min.js +6 -6
|
@@ -0,0 +1,3737 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
|
|
3
|
+
var __export = (target, all) => {
|
|
4
|
+
__markAsModule(target);
|
|
5
|
+
for (var name in all)
|
|
6
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
// js/phoenix_live_view/index.js
|
|
10
|
+
__export(exports, {
|
|
11
|
+
LiveSocket: () => LiveSocket
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// js/phoenix_live_view/constants.js
|
|
15
|
+
var CONSECUTIVE_RELOADS = "consecutive-reloads";
|
|
16
|
+
var MAX_RELOADS = 10;
|
|
17
|
+
var RELOAD_JITTER = [1e3, 3e3];
|
|
18
|
+
var FAILSAFE_JITTER = 3e4;
|
|
19
|
+
var PHX_EVENT_CLASSES = [
|
|
20
|
+
"phx-click-loading",
|
|
21
|
+
"phx-change-loading",
|
|
22
|
+
"phx-submit-loading",
|
|
23
|
+
"phx-keydown-loading",
|
|
24
|
+
"phx-keyup-loading",
|
|
25
|
+
"phx-blur-loading",
|
|
26
|
+
"phx-focus-loading"
|
|
27
|
+
];
|
|
28
|
+
var PHX_COMPONENT = "data-phx-component";
|
|
29
|
+
var PHX_LIVE_LINK = "data-phx-link";
|
|
30
|
+
var PHX_TRACK_STATIC = "track-static";
|
|
31
|
+
var PHX_LINK_STATE = "data-phx-link-state";
|
|
32
|
+
var PHX_REF = "data-phx-ref";
|
|
33
|
+
var PHX_TRACK_UPLOADS = "track-uploads";
|
|
34
|
+
var PHX_UPLOAD_REF = "data-phx-upload-ref";
|
|
35
|
+
var PHX_PREFLIGHTED_REFS = "data-phx-preflighted-refs";
|
|
36
|
+
var PHX_DONE_REFS = "data-phx-done-refs";
|
|
37
|
+
var PHX_DROP_TARGET = "drop-target";
|
|
38
|
+
var PHX_ACTIVE_ENTRY_REFS = "data-phx-active-refs";
|
|
39
|
+
var PHX_LIVE_FILE_UPDATED = "phx:live-file:updated";
|
|
40
|
+
var PHX_SKIP = "data-phx-skip";
|
|
41
|
+
var PHX_PRUNE = "data-phx-prune";
|
|
42
|
+
var PHX_PAGE_LOADING = "page-loading";
|
|
43
|
+
var PHX_CONNECTED_CLASS = "phx-connected";
|
|
44
|
+
var PHX_DISCONNECTED_CLASS = "phx-loading";
|
|
45
|
+
var PHX_NO_FEEDBACK_CLASS = "phx-no-feedback";
|
|
46
|
+
var PHX_ERROR_CLASS = "phx-error";
|
|
47
|
+
var PHX_PARENT_ID = "data-phx-parent-id";
|
|
48
|
+
var PHX_MAIN = "data-phx-main";
|
|
49
|
+
var PHX_ROOT_ID = "data-phx-root-id";
|
|
50
|
+
var PHX_TRIGGER_ACTION = "trigger-action";
|
|
51
|
+
var PHX_FEEDBACK_FOR = "feedback-for";
|
|
52
|
+
var PHX_HAS_FOCUSED = "phx-has-focused";
|
|
53
|
+
var FOCUSABLE_INPUTS = ["text", "textarea", "number", "email", "password", "search", "tel", "url", "date", "time"];
|
|
54
|
+
var CHECKABLE_INPUTS = ["checkbox", "radio"];
|
|
55
|
+
var PHX_HAS_SUBMITTED = "phx-has-submitted";
|
|
56
|
+
var PHX_SESSION = "data-phx-session";
|
|
57
|
+
var PHX_VIEW_SELECTOR = `[${PHX_SESSION}]`;
|
|
58
|
+
var PHX_STATIC = "data-phx-static";
|
|
59
|
+
var PHX_READONLY = "data-phx-readonly";
|
|
60
|
+
var PHX_DISABLED = "data-phx-disabled";
|
|
61
|
+
var PHX_DISABLE_WITH = "disable-with";
|
|
62
|
+
var PHX_DISABLE_WITH_RESTORE = "data-phx-disable-with-restore";
|
|
63
|
+
var PHX_HOOK = "hook";
|
|
64
|
+
var PHX_DEBOUNCE = "debounce";
|
|
65
|
+
var PHX_THROTTLE = "throttle";
|
|
66
|
+
var PHX_UPDATE = "update";
|
|
67
|
+
var PHX_KEY = "key";
|
|
68
|
+
var PHX_PRIVATE = "phxPrivate";
|
|
69
|
+
var PHX_AUTO_RECOVER = "auto-recover";
|
|
70
|
+
var PHX_LV_DEBUG = "phx:live-socket:debug";
|
|
71
|
+
var PHX_LV_PROFILE = "phx:live-socket:profiling";
|
|
72
|
+
var PHX_LV_LATENCY_SIM = "phx:live-socket:latency-sim";
|
|
73
|
+
var PHX_PROGRESS = "progress";
|
|
74
|
+
var LOADER_TIMEOUT = 1;
|
|
75
|
+
var BEFORE_UNLOAD_LOADER_TIMEOUT = 200;
|
|
76
|
+
var BINDING_PREFIX = "phx-";
|
|
77
|
+
var PUSH_TIMEOUT = 3e4;
|
|
78
|
+
var DEBOUNCE_TRIGGER = "debounce-trigger";
|
|
79
|
+
var THROTTLED = "throttled";
|
|
80
|
+
var DEBOUNCE_PREV_KEY = "debounce-prev-key";
|
|
81
|
+
var DEFAULTS = {
|
|
82
|
+
debounce: 300,
|
|
83
|
+
throttle: 300
|
|
84
|
+
};
|
|
85
|
+
var DYNAMICS = "d";
|
|
86
|
+
var STATIC = "s";
|
|
87
|
+
var COMPONENTS = "c";
|
|
88
|
+
var EVENTS = "e";
|
|
89
|
+
var REPLY = "r";
|
|
90
|
+
var TITLE = "t";
|
|
91
|
+
|
|
92
|
+
// js/phoenix_live_view/entry_uploader.js
|
|
93
|
+
var EntryUploader = class {
|
|
94
|
+
constructor(entry, chunkSize, liveSocket) {
|
|
95
|
+
this.liveSocket = liveSocket;
|
|
96
|
+
this.entry = entry;
|
|
97
|
+
this.offset = 0;
|
|
98
|
+
this.chunkSize = chunkSize;
|
|
99
|
+
this.chunkTimer = null;
|
|
100
|
+
this.uploadChannel = liveSocket.channel(`lvu:${entry.ref}`, { token: entry.metadata() });
|
|
101
|
+
}
|
|
102
|
+
error(reason) {
|
|
103
|
+
clearTimeout(this.chunkTimer);
|
|
104
|
+
this.uploadChannel.leave();
|
|
105
|
+
this.entry.error(reason);
|
|
106
|
+
}
|
|
107
|
+
upload() {
|
|
108
|
+
this.uploadChannel.onError((reason) => this.error(reason));
|
|
109
|
+
this.uploadChannel.join().receive("ok", (_data) => this.readNextChunk()).receive("error", (reason) => this.error(reason));
|
|
110
|
+
}
|
|
111
|
+
isDone() {
|
|
112
|
+
return this.offset >= this.entry.file.size;
|
|
113
|
+
}
|
|
114
|
+
readNextChunk() {
|
|
115
|
+
let reader = new window.FileReader();
|
|
116
|
+
let blob = this.entry.file.slice(this.offset, this.chunkSize + this.offset);
|
|
117
|
+
reader.onload = (e) => {
|
|
118
|
+
if (e.target.error === null) {
|
|
119
|
+
this.offset += e.target.result.byteLength;
|
|
120
|
+
this.pushChunk(e.target.result);
|
|
121
|
+
} else {
|
|
122
|
+
return logError("Read error: " + e.target.error);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
reader.readAsArrayBuffer(blob);
|
|
126
|
+
}
|
|
127
|
+
pushChunk(chunk) {
|
|
128
|
+
if (!this.uploadChannel.isJoined()) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
this.uploadChannel.push("chunk", chunk).receive("ok", () => {
|
|
132
|
+
this.entry.progress(this.offset / this.entry.file.size * 100);
|
|
133
|
+
if (!this.isDone()) {
|
|
134
|
+
this.chunkTimer = setTimeout(() => this.readNextChunk(), this.liveSocket.getLatencySim() || 0);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// js/phoenix_live_view/utils.js
|
|
141
|
+
var logError = (msg, obj) => console.error && console.error(msg, obj);
|
|
142
|
+
var isCid = (cid) => typeof cid === "number";
|
|
143
|
+
function detectDuplicateIds() {
|
|
144
|
+
let ids = new Set();
|
|
145
|
+
let elems = document.querySelectorAll("*[id]");
|
|
146
|
+
for (let i = 0, len = elems.length; i < len; i++) {
|
|
147
|
+
if (ids.has(elems[i].id)) {
|
|
148
|
+
console.error(`Multiple IDs detected: ${elems[i].id}. Ensure unique element ids.`);
|
|
149
|
+
} else {
|
|
150
|
+
ids.add(elems[i].id);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
var debug = (view, kind, msg, obj) => {
|
|
155
|
+
if (view.liveSocket.isDebugEnabled()) {
|
|
156
|
+
console.log(`${view.id} ${kind}: ${msg} - `, obj);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
var closure = (val) => typeof val === "function" ? val : function() {
|
|
160
|
+
return val;
|
|
161
|
+
};
|
|
162
|
+
var clone = (obj) => {
|
|
163
|
+
return JSON.parse(JSON.stringify(obj));
|
|
164
|
+
};
|
|
165
|
+
var closestPhxBinding = (el, binding, borderEl) => {
|
|
166
|
+
do {
|
|
167
|
+
if (el.matches(`[${binding}]`)) {
|
|
168
|
+
return el;
|
|
169
|
+
}
|
|
170
|
+
el = el.parentElement || el.parentNode;
|
|
171
|
+
} while (el !== null && el.nodeType === 1 && !(borderEl && borderEl.isSameNode(el) || el.matches(PHX_VIEW_SELECTOR)));
|
|
172
|
+
return null;
|
|
173
|
+
};
|
|
174
|
+
var isObject = (obj) => {
|
|
175
|
+
return obj !== null && typeof obj === "object" && !(obj instanceof Array);
|
|
176
|
+
};
|
|
177
|
+
var isEqualObj = (obj1, obj2) => JSON.stringify(obj1) === JSON.stringify(obj2);
|
|
178
|
+
var isEmpty = (obj) => {
|
|
179
|
+
for (let x in obj) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
return true;
|
|
183
|
+
};
|
|
184
|
+
var maybe = (el, callback) => el && callback(el);
|
|
185
|
+
var channelUploader = function(entries, onError, resp, liveSocket) {
|
|
186
|
+
entries.forEach((entry) => {
|
|
187
|
+
let entryUploader = new EntryUploader(entry, resp.config.chunk_size, liveSocket);
|
|
188
|
+
entryUploader.upload();
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// js/phoenix_live_view/browser.js
|
|
193
|
+
var Browser = {
|
|
194
|
+
canPushState() {
|
|
195
|
+
return typeof history.pushState !== "undefined";
|
|
196
|
+
},
|
|
197
|
+
dropLocal(localStorage, namespace, subkey) {
|
|
198
|
+
return localStorage.removeItem(this.localKey(namespace, subkey));
|
|
199
|
+
},
|
|
200
|
+
updateLocal(localStorage, namespace, subkey, initial, func) {
|
|
201
|
+
let current = this.getLocal(localStorage, namespace, subkey);
|
|
202
|
+
let key = this.localKey(namespace, subkey);
|
|
203
|
+
let newVal = current === null ? initial : func(current);
|
|
204
|
+
localStorage.setItem(key, JSON.stringify(newVal));
|
|
205
|
+
return newVal;
|
|
206
|
+
},
|
|
207
|
+
getLocal(localStorage, namespace, subkey) {
|
|
208
|
+
return JSON.parse(localStorage.getItem(this.localKey(namespace, subkey)));
|
|
209
|
+
},
|
|
210
|
+
updateCurrentState(callback) {
|
|
211
|
+
if (!this.canPushState()) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
history.replaceState(callback(history.state || {}), "", window.location.href);
|
|
215
|
+
},
|
|
216
|
+
pushState(kind, meta, to) {
|
|
217
|
+
if (this.canPushState()) {
|
|
218
|
+
if (to !== window.location.href) {
|
|
219
|
+
if (meta.type == "redirect" && meta.scroll) {
|
|
220
|
+
let currentState = history.state || {};
|
|
221
|
+
currentState.scroll = meta.scroll;
|
|
222
|
+
history.replaceState(currentState, "", window.location.href);
|
|
223
|
+
}
|
|
224
|
+
delete meta.scroll;
|
|
225
|
+
history[kind + "State"](meta, "", to || null);
|
|
226
|
+
let hashEl = this.getHashTargetEl(window.location.hash);
|
|
227
|
+
if (hashEl) {
|
|
228
|
+
hashEl.scrollIntoView();
|
|
229
|
+
} else if (meta.type === "redirect") {
|
|
230
|
+
window.scroll(0, 0);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
this.redirect(to);
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
setCookie(name, value) {
|
|
238
|
+
document.cookie = `${name}=${value}`;
|
|
239
|
+
},
|
|
240
|
+
getCookie(name) {
|
|
241
|
+
return document.cookie.replace(new RegExp(`(?:(?:^|.*;s*)${name}s*=s*([^;]*).*$)|^.*$`), "$1");
|
|
242
|
+
},
|
|
243
|
+
redirect(toURL, flash) {
|
|
244
|
+
if (flash) {
|
|
245
|
+
Browser.setCookie("__phoenix_flash__", flash + "; max-age=60000; path=/");
|
|
246
|
+
}
|
|
247
|
+
window.location = toURL;
|
|
248
|
+
},
|
|
249
|
+
localKey(namespace, subkey) {
|
|
250
|
+
return `${namespace}-${subkey}`;
|
|
251
|
+
},
|
|
252
|
+
getHashTargetEl(maybeHash) {
|
|
253
|
+
let hash = maybeHash.toString().substring(1);
|
|
254
|
+
if (hash === "") {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
return document.getElementById(hash) || document.querySelector(`a[name="${hash}"]`);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
var browser_default = Browser;
|
|
261
|
+
|
|
262
|
+
// js/phoenix_live_view/dom.js
|
|
263
|
+
var DOM = {
|
|
264
|
+
byId(id) {
|
|
265
|
+
return document.getElementById(id) || logError(`no id found for ${id}`);
|
|
266
|
+
},
|
|
267
|
+
removeClass(el, className) {
|
|
268
|
+
el.classList.remove(className);
|
|
269
|
+
if (el.classList.length === 0) {
|
|
270
|
+
el.removeAttribute("class");
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
all(node, query, callback) {
|
|
274
|
+
if (!node) {
|
|
275
|
+
return [];
|
|
276
|
+
}
|
|
277
|
+
let array = Array.from(node.querySelectorAll(query));
|
|
278
|
+
return callback ? array.forEach(callback) : array;
|
|
279
|
+
},
|
|
280
|
+
childNodeLength(html) {
|
|
281
|
+
let template = document.createElement("template");
|
|
282
|
+
template.innerHTML = html;
|
|
283
|
+
return template.content.childElementCount;
|
|
284
|
+
},
|
|
285
|
+
isUploadInput(el) {
|
|
286
|
+
return el.type === "file" && el.getAttribute(PHX_UPLOAD_REF) !== null;
|
|
287
|
+
},
|
|
288
|
+
findUploadInputs(node) {
|
|
289
|
+
return this.all(node, `input[type="file"][${PHX_UPLOAD_REF}]`);
|
|
290
|
+
},
|
|
291
|
+
findComponentNodeList(node, cid) {
|
|
292
|
+
return this.filterWithinSameLiveView(this.all(node, `[${PHX_COMPONENT}="${cid}"]`), node);
|
|
293
|
+
},
|
|
294
|
+
isPhxDestroyed(node) {
|
|
295
|
+
return node.id && DOM.private(node, "destroyed") ? true : false;
|
|
296
|
+
},
|
|
297
|
+
markPhxChildDestroyed(el) {
|
|
298
|
+
if (this.isPhxChild(el)) {
|
|
299
|
+
el.setAttribute(PHX_SESSION, "");
|
|
300
|
+
}
|
|
301
|
+
this.putPrivate(el, "destroyed", true);
|
|
302
|
+
},
|
|
303
|
+
findPhxChildrenInFragment(html, parentId) {
|
|
304
|
+
let template = document.createElement("template");
|
|
305
|
+
template.innerHTML = html;
|
|
306
|
+
return this.findPhxChildren(template.content, parentId);
|
|
307
|
+
},
|
|
308
|
+
isIgnored(el, phxUpdate) {
|
|
309
|
+
return (el.getAttribute(phxUpdate) || el.getAttribute("data-phx-update")) === "ignore";
|
|
310
|
+
},
|
|
311
|
+
isPhxUpdate(el, phxUpdate, updateTypes) {
|
|
312
|
+
return el.getAttribute && updateTypes.indexOf(el.getAttribute(phxUpdate)) >= 0;
|
|
313
|
+
},
|
|
314
|
+
findPhxChildren(el, parentId) {
|
|
315
|
+
return this.all(el, `${PHX_VIEW_SELECTOR}[${PHX_PARENT_ID}="${parentId}"]`);
|
|
316
|
+
},
|
|
317
|
+
findParentCIDs(node, cids) {
|
|
318
|
+
let initial = new Set(cids);
|
|
319
|
+
return cids.reduce((acc, cid) => {
|
|
320
|
+
let selector = `[${PHX_COMPONENT}="${cid}"] [${PHX_COMPONENT}]`;
|
|
321
|
+
this.filterWithinSameLiveView(this.all(node, selector), node).map((el) => parseInt(el.getAttribute(PHX_COMPONENT))).forEach((childCID) => acc.delete(childCID));
|
|
322
|
+
return acc;
|
|
323
|
+
}, initial);
|
|
324
|
+
},
|
|
325
|
+
filterWithinSameLiveView(nodes, parent) {
|
|
326
|
+
if (parent.querySelector(PHX_VIEW_SELECTOR)) {
|
|
327
|
+
return nodes.filter((el) => this.withinSameLiveView(el, parent));
|
|
328
|
+
} else {
|
|
329
|
+
return nodes;
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
withinSameLiveView(node, parent) {
|
|
333
|
+
while (node = node.parentNode) {
|
|
334
|
+
if (node.isSameNode(parent)) {
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
if (node.getAttribute(PHX_SESSION) !== null) {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
private(el, key) {
|
|
343
|
+
return el[PHX_PRIVATE] && el[PHX_PRIVATE][key];
|
|
344
|
+
},
|
|
345
|
+
deletePrivate(el, key) {
|
|
346
|
+
el[PHX_PRIVATE] && delete el[PHX_PRIVATE][key];
|
|
347
|
+
},
|
|
348
|
+
putPrivate(el, key, value) {
|
|
349
|
+
if (!el[PHX_PRIVATE]) {
|
|
350
|
+
el[PHX_PRIVATE] = {};
|
|
351
|
+
}
|
|
352
|
+
el[PHX_PRIVATE][key] = value;
|
|
353
|
+
},
|
|
354
|
+
updatePrivate(el, key, defaultVal, updateFunc) {
|
|
355
|
+
let existing = this.private(el, key);
|
|
356
|
+
if (existing === void 0) {
|
|
357
|
+
this.putPrivate(el, key, updateFunc(defaultVal));
|
|
358
|
+
} else {
|
|
359
|
+
this.putPrivate(el, key, updateFunc(existing));
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
copyPrivates(target, source) {
|
|
363
|
+
if (source[PHX_PRIVATE]) {
|
|
364
|
+
target[PHX_PRIVATE] = source[PHX_PRIVATE];
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
putTitle(str) {
|
|
368
|
+
let titleEl = document.querySelector("title");
|
|
369
|
+
let { prefix, suffix } = titleEl.dataset;
|
|
370
|
+
document.title = `${prefix || ""}${str}${suffix || ""}`;
|
|
371
|
+
},
|
|
372
|
+
debounce(el, event, phxDebounce, defaultDebounce, phxThrottle, defaultThrottle, callback) {
|
|
373
|
+
let debounce = el.getAttribute(phxDebounce);
|
|
374
|
+
let throttle = el.getAttribute(phxThrottle);
|
|
375
|
+
if (debounce === "") {
|
|
376
|
+
debounce = defaultDebounce;
|
|
377
|
+
}
|
|
378
|
+
if (throttle === "") {
|
|
379
|
+
throttle = defaultThrottle;
|
|
380
|
+
}
|
|
381
|
+
let value = debounce || throttle;
|
|
382
|
+
switch (value) {
|
|
383
|
+
case null:
|
|
384
|
+
return callback();
|
|
385
|
+
case "blur":
|
|
386
|
+
if (this.once(el, "debounce-blur")) {
|
|
387
|
+
el.addEventListener("blur", () => callback());
|
|
388
|
+
}
|
|
389
|
+
return;
|
|
390
|
+
default:
|
|
391
|
+
let timeout = parseInt(value);
|
|
392
|
+
let trigger = () => throttle ? this.deletePrivate(el, THROTTLED) : callback();
|
|
393
|
+
let currentCycle = this.incCycle(el, DEBOUNCE_TRIGGER, trigger);
|
|
394
|
+
if (isNaN(timeout)) {
|
|
395
|
+
return logError(`invalid throttle/debounce value: ${value}`);
|
|
396
|
+
}
|
|
397
|
+
if (throttle) {
|
|
398
|
+
let newKeyDown = false;
|
|
399
|
+
if (event.type === "keydown") {
|
|
400
|
+
let prevKey = this.private(el, DEBOUNCE_PREV_KEY);
|
|
401
|
+
this.putPrivate(el, DEBOUNCE_PREV_KEY, event.key);
|
|
402
|
+
newKeyDown = prevKey !== event.key;
|
|
403
|
+
}
|
|
404
|
+
if (!newKeyDown && this.private(el, THROTTLED)) {
|
|
405
|
+
return false;
|
|
406
|
+
} else {
|
|
407
|
+
callback();
|
|
408
|
+
this.putPrivate(el, THROTTLED, true);
|
|
409
|
+
setTimeout(() => this.triggerCycle(el, DEBOUNCE_TRIGGER), timeout);
|
|
410
|
+
}
|
|
411
|
+
} else {
|
|
412
|
+
setTimeout(() => this.triggerCycle(el, DEBOUNCE_TRIGGER, currentCycle), timeout);
|
|
413
|
+
}
|
|
414
|
+
let form = el.form;
|
|
415
|
+
if (form && this.once(form, "bind-debounce")) {
|
|
416
|
+
form.addEventListener("submit", () => {
|
|
417
|
+
Array.from(new FormData(form).entries(), ([name]) => {
|
|
418
|
+
let input = form.querySelector(`[name="${name}"]`);
|
|
419
|
+
this.incCycle(input, DEBOUNCE_TRIGGER);
|
|
420
|
+
this.deletePrivate(input, THROTTLED);
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
if (this.once(el, "bind-debounce")) {
|
|
425
|
+
el.addEventListener("blur", () => this.triggerCycle(el, DEBOUNCE_TRIGGER));
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
triggerCycle(el, key, currentCycle) {
|
|
430
|
+
let [cycle, trigger] = this.private(el, key);
|
|
431
|
+
if (!currentCycle) {
|
|
432
|
+
currentCycle = cycle;
|
|
433
|
+
}
|
|
434
|
+
if (currentCycle === cycle) {
|
|
435
|
+
this.incCycle(el, key);
|
|
436
|
+
trigger();
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
once(el, key) {
|
|
440
|
+
if (this.private(el, key) === true) {
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
this.putPrivate(el, key, true);
|
|
444
|
+
return true;
|
|
445
|
+
},
|
|
446
|
+
incCycle(el, key, trigger = function() {
|
|
447
|
+
}) {
|
|
448
|
+
let [currentCycle] = this.private(el, key) || [0, trigger];
|
|
449
|
+
currentCycle++;
|
|
450
|
+
this.putPrivate(el, key, [currentCycle, trigger]);
|
|
451
|
+
return currentCycle;
|
|
452
|
+
},
|
|
453
|
+
discardError(container, el, phxFeedbackFor) {
|
|
454
|
+
let field = el.getAttribute && el.getAttribute(phxFeedbackFor);
|
|
455
|
+
let input = field && container.querySelector(`[id="${field}"], [name="${field}"]`);
|
|
456
|
+
if (!input) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
if (!(this.private(input, PHX_HAS_FOCUSED) || this.private(input.form, PHX_HAS_SUBMITTED))) {
|
|
460
|
+
el.classList.add(PHX_NO_FEEDBACK_CLASS);
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
showError(inputEl, phxFeedbackFor) {
|
|
464
|
+
if (inputEl.id || inputEl.name) {
|
|
465
|
+
this.all(inputEl.form, `[${phxFeedbackFor}="${inputEl.id}"], [${phxFeedbackFor}="${inputEl.name}"]`, (el) => {
|
|
466
|
+
this.removeClass(el, PHX_NO_FEEDBACK_CLASS);
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
isPhxChild(node) {
|
|
471
|
+
return node.getAttribute && node.getAttribute(PHX_PARENT_ID);
|
|
472
|
+
},
|
|
473
|
+
dispatchEvent(target, eventString, detail = {}) {
|
|
474
|
+
let event = new CustomEvent(eventString, { bubbles: true, cancelable: true, detail });
|
|
475
|
+
target.dispatchEvent(event);
|
|
476
|
+
},
|
|
477
|
+
cloneNode(node, html) {
|
|
478
|
+
if (typeof html === "undefined") {
|
|
479
|
+
return node.cloneNode(true);
|
|
480
|
+
} else {
|
|
481
|
+
let cloned = node.cloneNode(false);
|
|
482
|
+
cloned.innerHTML = html;
|
|
483
|
+
return cloned;
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
mergeAttrs(target, source, opts = {}) {
|
|
487
|
+
let exclude = opts.exclude || [];
|
|
488
|
+
let isIgnored = opts.isIgnored;
|
|
489
|
+
let sourceAttrs = source.attributes;
|
|
490
|
+
for (let i = sourceAttrs.length - 1; i >= 0; i--) {
|
|
491
|
+
let name = sourceAttrs[i].name;
|
|
492
|
+
if (exclude.indexOf(name) < 0) {
|
|
493
|
+
target.setAttribute(name, source.getAttribute(name));
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
let targetAttrs = target.attributes;
|
|
497
|
+
for (let i = targetAttrs.length - 1; i >= 0; i--) {
|
|
498
|
+
let name = targetAttrs[i].name;
|
|
499
|
+
if (isIgnored) {
|
|
500
|
+
if (name.startsWith("data-") && !source.hasAttribute(name)) {
|
|
501
|
+
target.removeAttribute(name);
|
|
502
|
+
}
|
|
503
|
+
} else {
|
|
504
|
+
if (!source.hasAttribute(name)) {
|
|
505
|
+
target.removeAttribute(name);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
},
|
|
510
|
+
mergeFocusedInput(target, source) {
|
|
511
|
+
if (!(target instanceof HTMLSelectElement)) {
|
|
512
|
+
DOM.mergeAttrs(target, source, { except: ["value"] });
|
|
513
|
+
}
|
|
514
|
+
if (source.readOnly) {
|
|
515
|
+
target.setAttribute("readonly", true);
|
|
516
|
+
} else {
|
|
517
|
+
target.removeAttribute("readonly");
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
hasSelectionRange(el) {
|
|
521
|
+
return el.setSelectionRange && (el.type === "text" || el.type === "textarea");
|
|
522
|
+
},
|
|
523
|
+
restoreFocus(focused, selectionStart, selectionEnd) {
|
|
524
|
+
if (!DOM.isTextualInput(focused)) {
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
let wasFocused = focused.matches(":focus");
|
|
528
|
+
if (focused.readOnly) {
|
|
529
|
+
focused.blur();
|
|
530
|
+
}
|
|
531
|
+
if (!wasFocused) {
|
|
532
|
+
focused.focus();
|
|
533
|
+
}
|
|
534
|
+
if (this.hasSelectionRange(focused)) {
|
|
535
|
+
focused.setSelectionRange(selectionStart, selectionEnd);
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
isFormInput(el) {
|
|
539
|
+
return /^(?:input|select|textarea)$/i.test(el.tagName) && el.type !== "button";
|
|
540
|
+
},
|
|
541
|
+
syncAttrsToProps(el) {
|
|
542
|
+
if (el instanceof HTMLInputElement && CHECKABLE_INPUTS.indexOf(el.type.toLocaleLowerCase()) >= 0) {
|
|
543
|
+
el.checked = el.getAttribute("checked") !== null;
|
|
544
|
+
}
|
|
545
|
+
},
|
|
546
|
+
isTextualInput(el) {
|
|
547
|
+
return FOCUSABLE_INPUTS.indexOf(el.type) >= 0;
|
|
548
|
+
},
|
|
549
|
+
isNowTriggerFormExternal(el, phxTriggerExternal) {
|
|
550
|
+
return el.getAttribute && el.getAttribute(phxTriggerExternal) !== null;
|
|
551
|
+
},
|
|
552
|
+
syncPendingRef(fromEl, toEl, disableWith) {
|
|
553
|
+
let ref = fromEl.getAttribute(PHX_REF);
|
|
554
|
+
if (ref === null) {
|
|
555
|
+
return true;
|
|
556
|
+
}
|
|
557
|
+
if (DOM.isFormInput(fromEl) || fromEl.getAttribute(disableWith) !== null) {
|
|
558
|
+
if (DOM.isUploadInput(fromEl)) {
|
|
559
|
+
DOM.mergeAttrs(fromEl, toEl, { isIgnored: true });
|
|
560
|
+
}
|
|
561
|
+
DOM.putPrivate(fromEl, PHX_REF, toEl);
|
|
562
|
+
return false;
|
|
563
|
+
} else {
|
|
564
|
+
PHX_EVENT_CLASSES.forEach((className) => {
|
|
565
|
+
fromEl.classList.contains(className) && toEl.classList.add(className);
|
|
566
|
+
});
|
|
567
|
+
toEl.setAttribute(PHX_REF, ref);
|
|
568
|
+
return true;
|
|
569
|
+
}
|
|
570
|
+
},
|
|
571
|
+
cleanChildNodes(container, phxUpdate) {
|
|
572
|
+
if (DOM.isPhxUpdate(container, phxUpdate, ["append", "prepend"])) {
|
|
573
|
+
let toRemove = [];
|
|
574
|
+
container.childNodes.forEach((childNode) => {
|
|
575
|
+
if (!childNode.id) {
|
|
576
|
+
let isEmptyTextNode = childNode.nodeType === Node.TEXT_NODE && childNode.nodeValue.trim() === "";
|
|
577
|
+
if (!isEmptyTextNode) {
|
|
578
|
+
logError(`only HTML element tags with an id are allowed inside containers with phx-update.
|
|
579
|
+
|
|
580
|
+
removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
581
|
+
|
|
582
|
+
`);
|
|
583
|
+
}
|
|
584
|
+
toRemove.push(childNode);
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
toRemove.forEach((childNode) => childNode.remove());
|
|
588
|
+
}
|
|
589
|
+
},
|
|
590
|
+
replaceRootContainer(container, tagName, attrs) {
|
|
591
|
+
let retainedAttrs = new Set(["id", PHX_SESSION, PHX_STATIC, PHX_MAIN, PHX_ROOT_ID]);
|
|
592
|
+
if (container.tagName.toLowerCase() === tagName.toLowerCase()) {
|
|
593
|
+
Array.from(container.attributes).filter((attr) => !retainedAttrs.has(attr.name.toLowerCase())).forEach((attr) => container.removeAttribute(attr.name));
|
|
594
|
+
Object.keys(attrs).filter((name) => !retainedAttrs.has(name.toLowerCase())).forEach((attr) => container.setAttribute(attr, attrs[attr]));
|
|
595
|
+
return container;
|
|
596
|
+
} else {
|
|
597
|
+
let newContainer = document.createElement(tagName);
|
|
598
|
+
Object.keys(attrs).forEach((attr) => newContainer.setAttribute(attr, attrs[attr]));
|
|
599
|
+
retainedAttrs.forEach((attr) => newContainer.setAttribute(attr, container.getAttribute(attr)));
|
|
600
|
+
newContainer.innerHTML = container.innerHTML;
|
|
601
|
+
container.replaceWith(newContainer);
|
|
602
|
+
return newContainer;
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
getSticky(el, name, defaultVal) {
|
|
606
|
+
let op = (DOM.private(el, "sticky") || []).find(([existingName]) => name === existingName);
|
|
607
|
+
if (op) {
|
|
608
|
+
let [_name, _op, stashedResult] = op;
|
|
609
|
+
return stashedResult;
|
|
610
|
+
} else {
|
|
611
|
+
return typeof defaultVal === "function" ? defaultVal() : defaultVal;
|
|
612
|
+
}
|
|
613
|
+
},
|
|
614
|
+
deleteSticky(el, name) {
|
|
615
|
+
this.updatePrivate(el, "sticky", [], (ops) => {
|
|
616
|
+
return ops.filter(([existingName, _]) => existingName !== name);
|
|
617
|
+
});
|
|
618
|
+
},
|
|
619
|
+
putSticky(el, name, op) {
|
|
620
|
+
let stashedResult = op(el);
|
|
621
|
+
this.updatePrivate(el, "sticky", [], (ops) => {
|
|
622
|
+
let existingIndex = ops.findIndex(([existingName]) => name === existingName);
|
|
623
|
+
if (existingIndex >= 0) {
|
|
624
|
+
ops[existingIndex] = [name, op, stashedResult];
|
|
625
|
+
} else {
|
|
626
|
+
ops.push([name, op, stashedResult]);
|
|
627
|
+
}
|
|
628
|
+
return ops;
|
|
629
|
+
});
|
|
630
|
+
},
|
|
631
|
+
applyStickyOperations(el) {
|
|
632
|
+
let ops = DOM.private(el, "sticky");
|
|
633
|
+
if (!ops) {
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
ops.forEach(([name, op, _stashed]) => this.putSticky(el, name, op));
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
var dom_default = DOM;
|
|
640
|
+
|
|
641
|
+
// js/phoenix_live_view/upload_entry.js
|
|
642
|
+
var UploadEntry = class {
|
|
643
|
+
static isActive(fileEl, file) {
|
|
644
|
+
let isNew = file._phxRef === void 0;
|
|
645
|
+
let activeRefs = fileEl.getAttribute(PHX_ACTIVE_ENTRY_REFS).split(",");
|
|
646
|
+
let isActive = activeRefs.indexOf(LiveUploader.genFileRef(file)) >= 0;
|
|
647
|
+
return file.size > 0 && (isNew || isActive);
|
|
648
|
+
}
|
|
649
|
+
static isPreflighted(fileEl, file) {
|
|
650
|
+
let preflightedRefs = fileEl.getAttribute(PHX_PREFLIGHTED_REFS).split(",");
|
|
651
|
+
let isPreflighted = preflightedRefs.indexOf(LiveUploader.genFileRef(file)) >= 0;
|
|
652
|
+
return isPreflighted && this.isActive(fileEl, file);
|
|
653
|
+
}
|
|
654
|
+
constructor(fileEl, file, view) {
|
|
655
|
+
this.ref = LiveUploader.genFileRef(file);
|
|
656
|
+
this.fileEl = fileEl;
|
|
657
|
+
this.file = file;
|
|
658
|
+
this.view = view;
|
|
659
|
+
this.meta = null;
|
|
660
|
+
this._isCancelled = false;
|
|
661
|
+
this._isDone = false;
|
|
662
|
+
this._progress = 0;
|
|
663
|
+
this._lastProgressSent = -1;
|
|
664
|
+
this._onDone = function() {
|
|
665
|
+
};
|
|
666
|
+
this._onElUpdated = this.onElUpdated.bind(this);
|
|
667
|
+
this.fileEl.addEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated);
|
|
668
|
+
}
|
|
669
|
+
metadata() {
|
|
670
|
+
return this.meta;
|
|
671
|
+
}
|
|
672
|
+
progress(progress) {
|
|
673
|
+
this._progress = Math.floor(progress);
|
|
674
|
+
if (this._progress > this._lastProgressSent) {
|
|
675
|
+
if (this._progress >= 100) {
|
|
676
|
+
this._progress = 100;
|
|
677
|
+
this._lastProgressSent = 100;
|
|
678
|
+
this._isDone = true;
|
|
679
|
+
this.view.pushFileProgress(this.fileEl, this.ref, 100, () => {
|
|
680
|
+
LiveUploader.untrackFile(this.fileEl, this.file);
|
|
681
|
+
this._onDone();
|
|
682
|
+
});
|
|
683
|
+
} else {
|
|
684
|
+
this._lastProgressSent = this._progress;
|
|
685
|
+
this.view.pushFileProgress(this.fileEl, this.ref, this._progress);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
cancel() {
|
|
690
|
+
this._isCancelled = true;
|
|
691
|
+
this._isDone = true;
|
|
692
|
+
this._onDone();
|
|
693
|
+
}
|
|
694
|
+
isDone() {
|
|
695
|
+
return this._isDone;
|
|
696
|
+
}
|
|
697
|
+
error(reason = "failed") {
|
|
698
|
+
this.view.pushFileProgress(this.fileEl, this.ref, { error: reason });
|
|
699
|
+
LiveUploader.clearFiles(this.fileEl);
|
|
700
|
+
}
|
|
701
|
+
onDone(callback) {
|
|
702
|
+
this._onDone = () => {
|
|
703
|
+
this.fileEl.removeEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated);
|
|
704
|
+
callback();
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
onElUpdated() {
|
|
708
|
+
let activeRefs = this.fileEl.getAttribute(PHX_ACTIVE_ENTRY_REFS).split(",");
|
|
709
|
+
if (activeRefs.indexOf(this.ref) === -1) {
|
|
710
|
+
this.cancel();
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
toPreflightPayload() {
|
|
714
|
+
return {
|
|
715
|
+
last_modified: this.file.lastModified,
|
|
716
|
+
name: this.file.name,
|
|
717
|
+
size: this.file.size,
|
|
718
|
+
type: this.file.type,
|
|
719
|
+
ref: this.ref
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
uploader(uploaders) {
|
|
723
|
+
if (this.meta.uploader) {
|
|
724
|
+
let callback = uploaders[this.meta.uploader] || logError(`no uploader configured for ${this.meta.uploader}`);
|
|
725
|
+
return { name: this.meta.uploader, callback };
|
|
726
|
+
} else {
|
|
727
|
+
return { name: "channel", callback: channelUploader };
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
zipPostFlight(resp) {
|
|
731
|
+
this.meta = resp.entries[this.ref];
|
|
732
|
+
if (!this.meta) {
|
|
733
|
+
logError(`no preflight upload response returned with ref ${this.ref}`, { input: this.fileEl, response: resp });
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
|
|
738
|
+
// js/phoenix_live_view/live_uploader.js
|
|
739
|
+
var liveUploaderFileRef = 0;
|
|
740
|
+
var LiveUploader = class {
|
|
741
|
+
static genFileRef(file) {
|
|
742
|
+
let ref = file._phxRef;
|
|
743
|
+
if (ref !== void 0) {
|
|
744
|
+
return ref;
|
|
745
|
+
} else {
|
|
746
|
+
file._phxRef = (liveUploaderFileRef++).toString();
|
|
747
|
+
return file._phxRef;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
static getEntryDataURL(inputEl, ref, callback) {
|
|
751
|
+
let file = this.activeFiles(inputEl).find((file2) => this.genFileRef(file2) === ref);
|
|
752
|
+
callback(URL.createObjectURL(file));
|
|
753
|
+
}
|
|
754
|
+
static hasUploadsInProgress(formEl) {
|
|
755
|
+
let active = 0;
|
|
756
|
+
dom_default.findUploadInputs(formEl).forEach((input) => {
|
|
757
|
+
if (input.getAttribute(PHX_PREFLIGHTED_REFS) !== input.getAttribute(PHX_DONE_REFS)) {
|
|
758
|
+
active++;
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
return active > 0;
|
|
762
|
+
}
|
|
763
|
+
static serializeUploads(inputEl) {
|
|
764
|
+
let files = this.activeFiles(inputEl);
|
|
765
|
+
let fileData = {};
|
|
766
|
+
files.forEach((file) => {
|
|
767
|
+
let entry = { path: inputEl.name };
|
|
768
|
+
let uploadRef = inputEl.getAttribute(PHX_UPLOAD_REF);
|
|
769
|
+
fileData[uploadRef] = fileData[uploadRef] || [];
|
|
770
|
+
entry.ref = this.genFileRef(file);
|
|
771
|
+
entry.name = file.name || entry.ref;
|
|
772
|
+
entry.type = file.type;
|
|
773
|
+
entry.size = file.size;
|
|
774
|
+
fileData[uploadRef].push(entry);
|
|
775
|
+
});
|
|
776
|
+
return fileData;
|
|
777
|
+
}
|
|
778
|
+
static clearFiles(inputEl) {
|
|
779
|
+
inputEl.value = null;
|
|
780
|
+
inputEl.removeAttribute(PHX_UPLOAD_REF);
|
|
781
|
+
dom_default.putPrivate(inputEl, "files", []);
|
|
782
|
+
}
|
|
783
|
+
static untrackFile(inputEl, file) {
|
|
784
|
+
dom_default.putPrivate(inputEl, "files", dom_default.private(inputEl, "files").filter((f) => !Object.is(f, file)));
|
|
785
|
+
}
|
|
786
|
+
static trackFiles(inputEl, files) {
|
|
787
|
+
if (inputEl.getAttribute("multiple") !== null) {
|
|
788
|
+
let newFiles = files.filter((file) => !this.activeFiles(inputEl).find((f) => Object.is(f, file)));
|
|
789
|
+
dom_default.putPrivate(inputEl, "files", this.activeFiles(inputEl).concat(newFiles));
|
|
790
|
+
inputEl.value = null;
|
|
791
|
+
} else {
|
|
792
|
+
dom_default.putPrivate(inputEl, "files", files);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
static activeFileInputs(formEl) {
|
|
796
|
+
let fileInputs = dom_default.findUploadInputs(formEl);
|
|
797
|
+
return Array.from(fileInputs).filter((el) => el.files && this.activeFiles(el).length > 0);
|
|
798
|
+
}
|
|
799
|
+
static activeFiles(input) {
|
|
800
|
+
return (dom_default.private(input, "files") || []).filter((f) => UploadEntry.isActive(input, f));
|
|
801
|
+
}
|
|
802
|
+
static inputsAwaitingPreflight(formEl) {
|
|
803
|
+
let fileInputs = dom_default.findUploadInputs(formEl);
|
|
804
|
+
return Array.from(fileInputs).filter((input) => this.filesAwaitingPreflight(input).length > 0);
|
|
805
|
+
}
|
|
806
|
+
static filesAwaitingPreflight(input) {
|
|
807
|
+
return this.activeFiles(input).filter((f) => !UploadEntry.isPreflighted(input, f));
|
|
808
|
+
}
|
|
809
|
+
constructor(inputEl, view, onComplete) {
|
|
810
|
+
this.view = view;
|
|
811
|
+
this.onComplete = onComplete;
|
|
812
|
+
this._entries = Array.from(LiveUploader.filesAwaitingPreflight(inputEl) || []).map((file) => new UploadEntry(inputEl, file, view));
|
|
813
|
+
this.numEntriesInProgress = this._entries.length;
|
|
814
|
+
}
|
|
815
|
+
entries() {
|
|
816
|
+
return this._entries;
|
|
817
|
+
}
|
|
818
|
+
initAdapterUpload(resp, onError, liveSocket) {
|
|
819
|
+
this._entries = this._entries.map((entry) => {
|
|
820
|
+
entry.zipPostFlight(resp);
|
|
821
|
+
entry.onDone(() => {
|
|
822
|
+
this.numEntriesInProgress--;
|
|
823
|
+
if (this.numEntriesInProgress === 0) {
|
|
824
|
+
this.onComplete();
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
return entry;
|
|
828
|
+
});
|
|
829
|
+
let groupedEntries = this._entries.reduce((acc, entry) => {
|
|
830
|
+
let { name, callback } = entry.uploader(liveSocket.uploaders);
|
|
831
|
+
acc[name] = acc[name] || { callback, entries: [] };
|
|
832
|
+
acc[name].entries.push(entry);
|
|
833
|
+
return acc;
|
|
834
|
+
}, {});
|
|
835
|
+
for (let name in groupedEntries) {
|
|
836
|
+
let { callback, entries } = groupedEntries[name];
|
|
837
|
+
callback(entries, onError, resp, liveSocket);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
|
|
842
|
+
// js/phoenix_live_view/hooks.js
|
|
843
|
+
var Hooks = {
|
|
844
|
+
LiveFileUpload: {
|
|
845
|
+
activeRefs() {
|
|
846
|
+
return this.el.getAttribute(PHX_ACTIVE_ENTRY_REFS);
|
|
847
|
+
},
|
|
848
|
+
preflightedRefs() {
|
|
849
|
+
return this.el.getAttribute(PHX_PREFLIGHTED_REFS);
|
|
850
|
+
},
|
|
851
|
+
mounted() {
|
|
852
|
+
this.preflightedWas = this.preflightedRefs();
|
|
853
|
+
},
|
|
854
|
+
updated() {
|
|
855
|
+
let newPreflights = this.preflightedRefs();
|
|
856
|
+
if (this.preflightedWas !== newPreflights) {
|
|
857
|
+
this.preflightedWas = newPreflights;
|
|
858
|
+
if (newPreflights === "") {
|
|
859
|
+
this.__view.cancelSubmit(this.el.form);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
if (this.activeRefs() === "") {
|
|
863
|
+
this.el.value = null;
|
|
864
|
+
}
|
|
865
|
+
this.el.dispatchEvent(new CustomEvent(PHX_LIVE_FILE_UPDATED));
|
|
866
|
+
}
|
|
867
|
+
},
|
|
868
|
+
LiveImgPreview: {
|
|
869
|
+
mounted() {
|
|
870
|
+
this.ref = this.el.getAttribute("data-phx-entry-ref");
|
|
871
|
+
this.inputEl = document.getElementById(this.el.getAttribute(PHX_UPLOAD_REF));
|
|
872
|
+
LiveUploader.getEntryDataURL(this.inputEl, this.ref, (url) => {
|
|
873
|
+
this.url = url;
|
|
874
|
+
this.el.src = url;
|
|
875
|
+
});
|
|
876
|
+
},
|
|
877
|
+
destroyed() {
|
|
878
|
+
URL.revokeObjectURL(this.url);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
};
|
|
882
|
+
var hooks_default = Hooks;
|
|
883
|
+
|
|
884
|
+
// js/phoenix_live_view/dom_post_morph_restorer.js
|
|
885
|
+
var DOMPostMorphRestorer = class {
|
|
886
|
+
constructor(containerBefore, containerAfter, updateType) {
|
|
887
|
+
let idsBefore = new Set();
|
|
888
|
+
let idsAfter = new Set([...containerAfter.children].map((child) => child.id));
|
|
889
|
+
let elementsToModify = [];
|
|
890
|
+
Array.from(containerBefore.children).forEach((child) => {
|
|
891
|
+
if (child.id) {
|
|
892
|
+
idsBefore.add(child.id);
|
|
893
|
+
if (idsAfter.has(child.id)) {
|
|
894
|
+
let previousElementId = child.previousElementSibling && child.previousElementSibling.id;
|
|
895
|
+
elementsToModify.push({ elementId: child.id, previousElementId });
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
this.containerId = containerAfter.id;
|
|
900
|
+
this.updateType = updateType;
|
|
901
|
+
this.elementsToModify = elementsToModify;
|
|
902
|
+
this.elementIdsToAdd = [...idsAfter].filter((id) => !idsBefore.has(id));
|
|
903
|
+
}
|
|
904
|
+
perform() {
|
|
905
|
+
let container = dom_default.byId(this.containerId);
|
|
906
|
+
this.elementsToModify.forEach((elementToModify) => {
|
|
907
|
+
if (elementToModify.previousElementId) {
|
|
908
|
+
maybe(document.getElementById(elementToModify.previousElementId), (previousElem) => {
|
|
909
|
+
maybe(document.getElementById(elementToModify.elementId), (elem) => {
|
|
910
|
+
let isInRightPlace = elem.previousElementSibling && elem.previousElementSibling.id == previousElem.id;
|
|
911
|
+
if (!isInRightPlace) {
|
|
912
|
+
previousElem.insertAdjacentElement("afterend", elem);
|
|
913
|
+
}
|
|
914
|
+
});
|
|
915
|
+
});
|
|
916
|
+
} else {
|
|
917
|
+
maybe(document.getElementById(elementToModify.elementId), (elem) => {
|
|
918
|
+
let isInRightPlace = elem.previousElementSibling == null;
|
|
919
|
+
if (!isInRightPlace) {
|
|
920
|
+
container.insertAdjacentElement("afterbegin", elem);
|
|
921
|
+
}
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
});
|
|
925
|
+
if (this.updateType == "prepend") {
|
|
926
|
+
this.elementIdsToAdd.reverse().forEach((elemId) => {
|
|
927
|
+
maybe(document.getElementById(elemId), (elem) => container.insertAdjacentElement("afterbegin", elem));
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
// node_modules/morphdom/dist/morphdom-esm.js
|
|
934
|
+
var DOCUMENT_FRAGMENT_NODE = 11;
|
|
935
|
+
function morphAttrs(fromNode, toNode) {
|
|
936
|
+
var toNodeAttrs = toNode.attributes;
|
|
937
|
+
var attr;
|
|
938
|
+
var attrName;
|
|
939
|
+
var attrNamespaceURI;
|
|
940
|
+
var attrValue;
|
|
941
|
+
var fromValue;
|
|
942
|
+
if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE || fromNode.nodeType === DOCUMENT_FRAGMENT_NODE) {
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
for (var i = toNodeAttrs.length - 1; i >= 0; i--) {
|
|
946
|
+
attr = toNodeAttrs[i];
|
|
947
|
+
attrName = attr.name;
|
|
948
|
+
attrNamespaceURI = attr.namespaceURI;
|
|
949
|
+
attrValue = attr.value;
|
|
950
|
+
if (attrNamespaceURI) {
|
|
951
|
+
attrName = attr.localName || attrName;
|
|
952
|
+
fromValue = fromNode.getAttributeNS(attrNamespaceURI, attrName);
|
|
953
|
+
if (fromValue !== attrValue) {
|
|
954
|
+
if (attr.prefix === "xmlns") {
|
|
955
|
+
attrName = attr.name;
|
|
956
|
+
}
|
|
957
|
+
fromNode.setAttributeNS(attrNamespaceURI, attrName, attrValue);
|
|
958
|
+
}
|
|
959
|
+
} else {
|
|
960
|
+
fromValue = fromNode.getAttribute(attrName);
|
|
961
|
+
if (fromValue !== attrValue) {
|
|
962
|
+
fromNode.setAttribute(attrName, attrValue);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
var fromNodeAttrs = fromNode.attributes;
|
|
967
|
+
for (var d = fromNodeAttrs.length - 1; d >= 0; d--) {
|
|
968
|
+
attr = fromNodeAttrs[d];
|
|
969
|
+
attrName = attr.name;
|
|
970
|
+
attrNamespaceURI = attr.namespaceURI;
|
|
971
|
+
if (attrNamespaceURI) {
|
|
972
|
+
attrName = attr.localName || attrName;
|
|
973
|
+
if (!toNode.hasAttributeNS(attrNamespaceURI, attrName)) {
|
|
974
|
+
fromNode.removeAttributeNS(attrNamespaceURI, attrName);
|
|
975
|
+
}
|
|
976
|
+
} else {
|
|
977
|
+
if (!toNode.hasAttribute(attrName)) {
|
|
978
|
+
fromNode.removeAttribute(attrName);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
var range;
|
|
984
|
+
var NS_XHTML = "http://www.w3.org/1999/xhtml";
|
|
985
|
+
var doc = typeof document === "undefined" ? void 0 : document;
|
|
986
|
+
var HAS_TEMPLATE_SUPPORT = !!doc && "content" in doc.createElement("template");
|
|
987
|
+
var HAS_RANGE_SUPPORT = !!doc && doc.createRange && "createContextualFragment" in doc.createRange();
|
|
988
|
+
function createFragmentFromTemplate(str) {
|
|
989
|
+
var template = doc.createElement("template");
|
|
990
|
+
template.innerHTML = str;
|
|
991
|
+
return template.content.childNodes[0];
|
|
992
|
+
}
|
|
993
|
+
function createFragmentFromRange(str) {
|
|
994
|
+
if (!range) {
|
|
995
|
+
range = doc.createRange();
|
|
996
|
+
range.selectNode(doc.body);
|
|
997
|
+
}
|
|
998
|
+
var fragment = range.createContextualFragment(str);
|
|
999
|
+
return fragment.childNodes[0];
|
|
1000
|
+
}
|
|
1001
|
+
function createFragmentFromWrap(str) {
|
|
1002
|
+
var fragment = doc.createElement("body");
|
|
1003
|
+
fragment.innerHTML = str;
|
|
1004
|
+
return fragment.childNodes[0];
|
|
1005
|
+
}
|
|
1006
|
+
function toElement(str) {
|
|
1007
|
+
str = str.trim();
|
|
1008
|
+
if (HAS_TEMPLATE_SUPPORT) {
|
|
1009
|
+
return createFragmentFromTemplate(str);
|
|
1010
|
+
} else if (HAS_RANGE_SUPPORT) {
|
|
1011
|
+
return createFragmentFromRange(str);
|
|
1012
|
+
}
|
|
1013
|
+
return createFragmentFromWrap(str);
|
|
1014
|
+
}
|
|
1015
|
+
function compareNodeNames(fromEl, toEl) {
|
|
1016
|
+
var fromNodeName = fromEl.nodeName;
|
|
1017
|
+
var toNodeName = toEl.nodeName;
|
|
1018
|
+
var fromCodeStart, toCodeStart;
|
|
1019
|
+
if (fromNodeName === toNodeName) {
|
|
1020
|
+
return true;
|
|
1021
|
+
}
|
|
1022
|
+
fromCodeStart = fromNodeName.charCodeAt(0);
|
|
1023
|
+
toCodeStart = toNodeName.charCodeAt(0);
|
|
1024
|
+
if (fromCodeStart <= 90 && toCodeStart >= 97) {
|
|
1025
|
+
return fromNodeName === toNodeName.toUpperCase();
|
|
1026
|
+
} else if (toCodeStart <= 90 && fromCodeStart >= 97) {
|
|
1027
|
+
return toNodeName === fromNodeName.toUpperCase();
|
|
1028
|
+
} else {
|
|
1029
|
+
return false;
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
function createElementNS(name, namespaceURI) {
|
|
1033
|
+
return !namespaceURI || namespaceURI === NS_XHTML ? doc.createElement(name) : doc.createElementNS(namespaceURI, name);
|
|
1034
|
+
}
|
|
1035
|
+
function moveChildren(fromEl, toEl) {
|
|
1036
|
+
var curChild = fromEl.firstChild;
|
|
1037
|
+
while (curChild) {
|
|
1038
|
+
var nextChild = curChild.nextSibling;
|
|
1039
|
+
toEl.appendChild(curChild);
|
|
1040
|
+
curChild = nextChild;
|
|
1041
|
+
}
|
|
1042
|
+
return toEl;
|
|
1043
|
+
}
|
|
1044
|
+
function syncBooleanAttrProp(fromEl, toEl, name) {
|
|
1045
|
+
if (fromEl[name] !== toEl[name]) {
|
|
1046
|
+
fromEl[name] = toEl[name];
|
|
1047
|
+
if (fromEl[name]) {
|
|
1048
|
+
fromEl.setAttribute(name, "");
|
|
1049
|
+
} else {
|
|
1050
|
+
fromEl.removeAttribute(name);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
var specialElHandlers = {
|
|
1055
|
+
OPTION: function(fromEl, toEl) {
|
|
1056
|
+
var parentNode = fromEl.parentNode;
|
|
1057
|
+
if (parentNode) {
|
|
1058
|
+
var parentName = parentNode.nodeName.toUpperCase();
|
|
1059
|
+
if (parentName === "OPTGROUP") {
|
|
1060
|
+
parentNode = parentNode.parentNode;
|
|
1061
|
+
parentName = parentNode && parentNode.nodeName.toUpperCase();
|
|
1062
|
+
}
|
|
1063
|
+
if (parentName === "SELECT" && !parentNode.hasAttribute("multiple")) {
|
|
1064
|
+
if (fromEl.hasAttribute("selected") && !toEl.selected) {
|
|
1065
|
+
fromEl.setAttribute("selected", "selected");
|
|
1066
|
+
fromEl.removeAttribute("selected");
|
|
1067
|
+
}
|
|
1068
|
+
parentNode.selectedIndex = -1;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
syncBooleanAttrProp(fromEl, toEl, "selected");
|
|
1072
|
+
},
|
|
1073
|
+
INPUT: function(fromEl, toEl) {
|
|
1074
|
+
syncBooleanAttrProp(fromEl, toEl, "checked");
|
|
1075
|
+
syncBooleanAttrProp(fromEl, toEl, "disabled");
|
|
1076
|
+
if (fromEl.value !== toEl.value) {
|
|
1077
|
+
fromEl.value = toEl.value;
|
|
1078
|
+
}
|
|
1079
|
+
if (!toEl.hasAttribute("value")) {
|
|
1080
|
+
fromEl.removeAttribute("value");
|
|
1081
|
+
}
|
|
1082
|
+
},
|
|
1083
|
+
TEXTAREA: function(fromEl, toEl) {
|
|
1084
|
+
var newValue = toEl.value;
|
|
1085
|
+
if (fromEl.value !== newValue) {
|
|
1086
|
+
fromEl.value = newValue;
|
|
1087
|
+
}
|
|
1088
|
+
var firstChild = fromEl.firstChild;
|
|
1089
|
+
if (firstChild) {
|
|
1090
|
+
var oldValue = firstChild.nodeValue;
|
|
1091
|
+
if (oldValue == newValue || !newValue && oldValue == fromEl.placeholder) {
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
firstChild.nodeValue = newValue;
|
|
1095
|
+
}
|
|
1096
|
+
},
|
|
1097
|
+
SELECT: function(fromEl, toEl) {
|
|
1098
|
+
if (!toEl.hasAttribute("multiple")) {
|
|
1099
|
+
var selectedIndex = -1;
|
|
1100
|
+
var i = 0;
|
|
1101
|
+
var curChild = fromEl.firstChild;
|
|
1102
|
+
var optgroup;
|
|
1103
|
+
var nodeName;
|
|
1104
|
+
while (curChild) {
|
|
1105
|
+
nodeName = curChild.nodeName && curChild.nodeName.toUpperCase();
|
|
1106
|
+
if (nodeName === "OPTGROUP") {
|
|
1107
|
+
optgroup = curChild;
|
|
1108
|
+
curChild = optgroup.firstChild;
|
|
1109
|
+
} else {
|
|
1110
|
+
if (nodeName === "OPTION") {
|
|
1111
|
+
if (curChild.hasAttribute("selected")) {
|
|
1112
|
+
selectedIndex = i;
|
|
1113
|
+
break;
|
|
1114
|
+
}
|
|
1115
|
+
i++;
|
|
1116
|
+
}
|
|
1117
|
+
curChild = curChild.nextSibling;
|
|
1118
|
+
if (!curChild && optgroup) {
|
|
1119
|
+
curChild = optgroup.nextSibling;
|
|
1120
|
+
optgroup = null;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
fromEl.selectedIndex = selectedIndex;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
var ELEMENT_NODE = 1;
|
|
1129
|
+
var DOCUMENT_FRAGMENT_NODE$1 = 11;
|
|
1130
|
+
var TEXT_NODE = 3;
|
|
1131
|
+
var COMMENT_NODE = 8;
|
|
1132
|
+
function noop() {
|
|
1133
|
+
}
|
|
1134
|
+
function defaultGetNodeKey(node) {
|
|
1135
|
+
if (node) {
|
|
1136
|
+
return node.getAttribute && node.getAttribute("id") || node.id;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
function morphdomFactory(morphAttrs2) {
|
|
1140
|
+
return function morphdom2(fromNode, toNode, options) {
|
|
1141
|
+
if (!options) {
|
|
1142
|
+
options = {};
|
|
1143
|
+
}
|
|
1144
|
+
if (typeof toNode === "string") {
|
|
1145
|
+
if (fromNode.nodeName === "#document" || fromNode.nodeName === "HTML" || fromNode.nodeName === "BODY") {
|
|
1146
|
+
var toNodeHtml = toNode;
|
|
1147
|
+
toNode = doc.createElement("html");
|
|
1148
|
+
toNode.innerHTML = toNodeHtml;
|
|
1149
|
+
} else {
|
|
1150
|
+
toNode = toElement(toNode);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
var getNodeKey = options.getNodeKey || defaultGetNodeKey;
|
|
1154
|
+
var onBeforeNodeAdded = options.onBeforeNodeAdded || noop;
|
|
1155
|
+
var onNodeAdded = options.onNodeAdded || noop;
|
|
1156
|
+
var onBeforeElUpdated = options.onBeforeElUpdated || noop;
|
|
1157
|
+
var onElUpdated = options.onElUpdated || noop;
|
|
1158
|
+
var onBeforeNodeDiscarded = options.onBeforeNodeDiscarded || noop;
|
|
1159
|
+
var onNodeDiscarded = options.onNodeDiscarded || noop;
|
|
1160
|
+
var onBeforeElChildrenUpdated = options.onBeforeElChildrenUpdated || noop;
|
|
1161
|
+
var childrenOnly = options.childrenOnly === true;
|
|
1162
|
+
var fromNodesLookup = Object.create(null);
|
|
1163
|
+
var keyedRemovalList = [];
|
|
1164
|
+
function addKeyedRemoval(key) {
|
|
1165
|
+
keyedRemovalList.push(key);
|
|
1166
|
+
}
|
|
1167
|
+
function walkDiscardedChildNodes(node, skipKeyedNodes) {
|
|
1168
|
+
if (node.nodeType === ELEMENT_NODE) {
|
|
1169
|
+
var curChild = node.firstChild;
|
|
1170
|
+
while (curChild) {
|
|
1171
|
+
var key = void 0;
|
|
1172
|
+
if (skipKeyedNodes && (key = getNodeKey(curChild))) {
|
|
1173
|
+
addKeyedRemoval(key);
|
|
1174
|
+
} else {
|
|
1175
|
+
onNodeDiscarded(curChild);
|
|
1176
|
+
if (curChild.firstChild) {
|
|
1177
|
+
walkDiscardedChildNodes(curChild, skipKeyedNodes);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
curChild = curChild.nextSibling;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
function removeNode(node, parentNode, skipKeyedNodes) {
|
|
1185
|
+
if (onBeforeNodeDiscarded(node) === false) {
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
if (parentNode) {
|
|
1189
|
+
parentNode.removeChild(node);
|
|
1190
|
+
}
|
|
1191
|
+
onNodeDiscarded(node);
|
|
1192
|
+
walkDiscardedChildNodes(node, skipKeyedNodes);
|
|
1193
|
+
}
|
|
1194
|
+
function indexTree(node) {
|
|
1195
|
+
if (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE$1) {
|
|
1196
|
+
var curChild = node.firstChild;
|
|
1197
|
+
while (curChild) {
|
|
1198
|
+
var key = getNodeKey(curChild);
|
|
1199
|
+
if (key) {
|
|
1200
|
+
fromNodesLookup[key] = curChild;
|
|
1201
|
+
}
|
|
1202
|
+
indexTree(curChild);
|
|
1203
|
+
curChild = curChild.nextSibling;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
indexTree(fromNode);
|
|
1208
|
+
function handleNodeAdded(el) {
|
|
1209
|
+
onNodeAdded(el);
|
|
1210
|
+
var curChild = el.firstChild;
|
|
1211
|
+
while (curChild) {
|
|
1212
|
+
var nextSibling = curChild.nextSibling;
|
|
1213
|
+
var key = getNodeKey(curChild);
|
|
1214
|
+
if (key) {
|
|
1215
|
+
var unmatchedFromEl = fromNodesLookup[key];
|
|
1216
|
+
if (unmatchedFromEl && compareNodeNames(curChild, unmatchedFromEl)) {
|
|
1217
|
+
curChild.parentNode.replaceChild(unmatchedFromEl, curChild);
|
|
1218
|
+
morphEl(unmatchedFromEl, curChild);
|
|
1219
|
+
} else {
|
|
1220
|
+
handleNodeAdded(curChild);
|
|
1221
|
+
}
|
|
1222
|
+
} else {
|
|
1223
|
+
handleNodeAdded(curChild);
|
|
1224
|
+
}
|
|
1225
|
+
curChild = nextSibling;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
function cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey) {
|
|
1229
|
+
while (curFromNodeChild) {
|
|
1230
|
+
var fromNextSibling = curFromNodeChild.nextSibling;
|
|
1231
|
+
if (curFromNodeKey = getNodeKey(curFromNodeChild)) {
|
|
1232
|
+
addKeyedRemoval(curFromNodeKey);
|
|
1233
|
+
} else {
|
|
1234
|
+
removeNode(curFromNodeChild, fromEl, true);
|
|
1235
|
+
}
|
|
1236
|
+
curFromNodeChild = fromNextSibling;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
function morphEl(fromEl, toEl, childrenOnly2) {
|
|
1240
|
+
var toElKey = getNodeKey(toEl);
|
|
1241
|
+
if (toElKey) {
|
|
1242
|
+
delete fromNodesLookup[toElKey];
|
|
1243
|
+
}
|
|
1244
|
+
if (!childrenOnly2) {
|
|
1245
|
+
if (onBeforeElUpdated(fromEl, toEl) === false) {
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
morphAttrs2(fromEl, toEl);
|
|
1249
|
+
onElUpdated(fromEl);
|
|
1250
|
+
if (onBeforeElChildrenUpdated(fromEl, toEl) === false) {
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
if (fromEl.nodeName !== "TEXTAREA") {
|
|
1255
|
+
morphChildren(fromEl, toEl);
|
|
1256
|
+
} else {
|
|
1257
|
+
specialElHandlers.TEXTAREA(fromEl, toEl);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
function morphChildren(fromEl, toEl) {
|
|
1261
|
+
var curToNodeChild = toEl.firstChild;
|
|
1262
|
+
var curFromNodeChild = fromEl.firstChild;
|
|
1263
|
+
var curToNodeKey;
|
|
1264
|
+
var curFromNodeKey;
|
|
1265
|
+
var fromNextSibling;
|
|
1266
|
+
var toNextSibling;
|
|
1267
|
+
var matchingFromEl;
|
|
1268
|
+
outer:
|
|
1269
|
+
while (curToNodeChild) {
|
|
1270
|
+
toNextSibling = curToNodeChild.nextSibling;
|
|
1271
|
+
curToNodeKey = getNodeKey(curToNodeChild);
|
|
1272
|
+
while (curFromNodeChild) {
|
|
1273
|
+
fromNextSibling = curFromNodeChild.nextSibling;
|
|
1274
|
+
if (curToNodeChild.isSameNode && curToNodeChild.isSameNode(curFromNodeChild)) {
|
|
1275
|
+
curToNodeChild = toNextSibling;
|
|
1276
|
+
curFromNodeChild = fromNextSibling;
|
|
1277
|
+
continue outer;
|
|
1278
|
+
}
|
|
1279
|
+
curFromNodeKey = getNodeKey(curFromNodeChild);
|
|
1280
|
+
var curFromNodeType = curFromNodeChild.nodeType;
|
|
1281
|
+
var isCompatible = void 0;
|
|
1282
|
+
if (curFromNodeType === curToNodeChild.nodeType) {
|
|
1283
|
+
if (curFromNodeType === ELEMENT_NODE) {
|
|
1284
|
+
if (curToNodeKey) {
|
|
1285
|
+
if (curToNodeKey !== curFromNodeKey) {
|
|
1286
|
+
if (matchingFromEl = fromNodesLookup[curToNodeKey]) {
|
|
1287
|
+
if (fromNextSibling === matchingFromEl) {
|
|
1288
|
+
isCompatible = false;
|
|
1289
|
+
} else {
|
|
1290
|
+
fromEl.insertBefore(matchingFromEl, curFromNodeChild);
|
|
1291
|
+
if (curFromNodeKey) {
|
|
1292
|
+
addKeyedRemoval(curFromNodeKey);
|
|
1293
|
+
} else {
|
|
1294
|
+
removeNode(curFromNodeChild, fromEl, true);
|
|
1295
|
+
}
|
|
1296
|
+
curFromNodeChild = matchingFromEl;
|
|
1297
|
+
}
|
|
1298
|
+
} else {
|
|
1299
|
+
isCompatible = false;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
} else if (curFromNodeKey) {
|
|
1303
|
+
isCompatible = false;
|
|
1304
|
+
}
|
|
1305
|
+
isCompatible = isCompatible !== false && compareNodeNames(curFromNodeChild, curToNodeChild);
|
|
1306
|
+
if (isCompatible) {
|
|
1307
|
+
morphEl(curFromNodeChild, curToNodeChild);
|
|
1308
|
+
}
|
|
1309
|
+
} else if (curFromNodeType === TEXT_NODE || curFromNodeType == COMMENT_NODE) {
|
|
1310
|
+
isCompatible = true;
|
|
1311
|
+
if (curFromNodeChild.nodeValue !== curToNodeChild.nodeValue) {
|
|
1312
|
+
curFromNodeChild.nodeValue = curToNodeChild.nodeValue;
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
if (isCompatible) {
|
|
1317
|
+
curToNodeChild = toNextSibling;
|
|
1318
|
+
curFromNodeChild = fromNextSibling;
|
|
1319
|
+
continue outer;
|
|
1320
|
+
}
|
|
1321
|
+
if (curFromNodeKey) {
|
|
1322
|
+
addKeyedRemoval(curFromNodeKey);
|
|
1323
|
+
} else {
|
|
1324
|
+
removeNode(curFromNodeChild, fromEl, true);
|
|
1325
|
+
}
|
|
1326
|
+
curFromNodeChild = fromNextSibling;
|
|
1327
|
+
}
|
|
1328
|
+
if (curToNodeKey && (matchingFromEl = fromNodesLookup[curToNodeKey]) && compareNodeNames(matchingFromEl, curToNodeChild)) {
|
|
1329
|
+
fromEl.appendChild(matchingFromEl);
|
|
1330
|
+
morphEl(matchingFromEl, curToNodeChild);
|
|
1331
|
+
} else {
|
|
1332
|
+
var onBeforeNodeAddedResult = onBeforeNodeAdded(curToNodeChild);
|
|
1333
|
+
if (onBeforeNodeAddedResult !== false) {
|
|
1334
|
+
if (onBeforeNodeAddedResult) {
|
|
1335
|
+
curToNodeChild = onBeforeNodeAddedResult;
|
|
1336
|
+
}
|
|
1337
|
+
if (curToNodeChild.actualize) {
|
|
1338
|
+
curToNodeChild = curToNodeChild.actualize(fromEl.ownerDocument || doc);
|
|
1339
|
+
}
|
|
1340
|
+
fromEl.appendChild(curToNodeChild);
|
|
1341
|
+
handleNodeAdded(curToNodeChild);
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
curToNodeChild = toNextSibling;
|
|
1345
|
+
curFromNodeChild = fromNextSibling;
|
|
1346
|
+
}
|
|
1347
|
+
cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey);
|
|
1348
|
+
var specialElHandler = specialElHandlers[fromEl.nodeName];
|
|
1349
|
+
if (specialElHandler) {
|
|
1350
|
+
specialElHandler(fromEl, toEl);
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
var morphedNode = fromNode;
|
|
1354
|
+
var morphedNodeType = morphedNode.nodeType;
|
|
1355
|
+
var toNodeType = toNode.nodeType;
|
|
1356
|
+
if (!childrenOnly) {
|
|
1357
|
+
if (morphedNodeType === ELEMENT_NODE) {
|
|
1358
|
+
if (toNodeType === ELEMENT_NODE) {
|
|
1359
|
+
if (!compareNodeNames(fromNode, toNode)) {
|
|
1360
|
+
onNodeDiscarded(fromNode);
|
|
1361
|
+
morphedNode = moveChildren(fromNode, createElementNS(toNode.nodeName, toNode.namespaceURI));
|
|
1362
|
+
}
|
|
1363
|
+
} else {
|
|
1364
|
+
morphedNode = toNode;
|
|
1365
|
+
}
|
|
1366
|
+
} else if (morphedNodeType === TEXT_NODE || morphedNodeType === COMMENT_NODE) {
|
|
1367
|
+
if (toNodeType === morphedNodeType) {
|
|
1368
|
+
if (morphedNode.nodeValue !== toNode.nodeValue) {
|
|
1369
|
+
morphedNode.nodeValue = toNode.nodeValue;
|
|
1370
|
+
}
|
|
1371
|
+
return morphedNode;
|
|
1372
|
+
} else {
|
|
1373
|
+
morphedNode = toNode;
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
if (morphedNode === toNode) {
|
|
1378
|
+
onNodeDiscarded(fromNode);
|
|
1379
|
+
} else {
|
|
1380
|
+
if (toNode.isSameNode && toNode.isSameNode(morphedNode)) {
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
morphEl(morphedNode, toNode, childrenOnly);
|
|
1384
|
+
if (keyedRemovalList) {
|
|
1385
|
+
for (var i = 0, len = keyedRemovalList.length; i < len; i++) {
|
|
1386
|
+
var elToRemove = fromNodesLookup[keyedRemovalList[i]];
|
|
1387
|
+
if (elToRemove) {
|
|
1388
|
+
removeNode(elToRemove, elToRemove.parentNode, false);
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
if (!childrenOnly && morphedNode !== fromNode && fromNode.parentNode) {
|
|
1394
|
+
if (morphedNode.actualize) {
|
|
1395
|
+
morphedNode = morphedNode.actualize(fromNode.ownerDocument || doc);
|
|
1396
|
+
}
|
|
1397
|
+
fromNode.parentNode.replaceChild(morphedNode, fromNode);
|
|
1398
|
+
}
|
|
1399
|
+
return morphedNode;
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
var morphdom = morphdomFactory(morphAttrs);
|
|
1403
|
+
var morphdom_esm_default = morphdom;
|
|
1404
|
+
|
|
1405
|
+
// js/phoenix_live_view/dom_patch.js
|
|
1406
|
+
var DOMPatch = class {
|
|
1407
|
+
static patchEl(fromEl, toEl, activeElement) {
|
|
1408
|
+
morphdom_esm_default(fromEl, toEl, {
|
|
1409
|
+
childrenOnly: false,
|
|
1410
|
+
onBeforeElUpdated: (fromEl2, toEl2) => {
|
|
1411
|
+
if (activeElement && activeElement.isSameNode(fromEl2) && dom_default.isFormInput(fromEl2)) {
|
|
1412
|
+
dom_default.mergeFocusedInput(fromEl2, toEl2);
|
|
1413
|
+
return false;
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
});
|
|
1417
|
+
}
|
|
1418
|
+
constructor(view, container, id, html, targetCID) {
|
|
1419
|
+
this.view = view;
|
|
1420
|
+
this.liveSocket = view.liveSocket;
|
|
1421
|
+
this.container = container;
|
|
1422
|
+
this.id = id;
|
|
1423
|
+
this.rootID = view.root.id;
|
|
1424
|
+
this.html = html;
|
|
1425
|
+
this.targetCID = targetCID;
|
|
1426
|
+
this.cidPatch = isCid(this.targetCID);
|
|
1427
|
+
this.callbacks = {
|
|
1428
|
+
beforeadded: [],
|
|
1429
|
+
beforeupdated: [],
|
|
1430
|
+
beforephxChildAdded: [],
|
|
1431
|
+
afteradded: [],
|
|
1432
|
+
afterupdated: [],
|
|
1433
|
+
afterdiscarded: [],
|
|
1434
|
+
afterphxChildAdded: [],
|
|
1435
|
+
aftertransitionsDiscarded: []
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
before(kind, callback) {
|
|
1439
|
+
this.callbacks[`before${kind}`].push(callback);
|
|
1440
|
+
}
|
|
1441
|
+
after(kind, callback) {
|
|
1442
|
+
this.callbacks[`after${kind}`].push(callback);
|
|
1443
|
+
}
|
|
1444
|
+
trackBefore(kind, ...args) {
|
|
1445
|
+
this.callbacks[`before${kind}`].forEach((callback) => callback(...args));
|
|
1446
|
+
}
|
|
1447
|
+
trackAfter(kind, ...args) {
|
|
1448
|
+
this.callbacks[`after${kind}`].forEach((callback) => callback(...args));
|
|
1449
|
+
}
|
|
1450
|
+
markPrunableContentForRemoval() {
|
|
1451
|
+
dom_default.all(this.container, "[phx-update=append] > *, [phx-update=prepend] > *", (el) => {
|
|
1452
|
+
el.setAttribute(PHX_PRUNE, "");
|
|
1453
|
+
});
|
|
1454
|
+
}
|
|
1455
|
+
perform() {
|
|
1456
|
+
let { view, liveSocket, container, html } = this;
|
|
1457
|
+
let targetContainer = this.isCIDPatch() ? this.targetCIDContainer(html) : container;
|
|
1458
|
+
if (this.isCIDPatch() && !targetContainer) {
|
|
1459
|
+
return;
|
|
1460
|
+
}
|
|
1461
|
+
let focused = liveSocket.getActiveElement();
|
|
1462
|
+
let { selectionStart, selectionEnd } = focused && dom_default.hasSelectionRange(focused) ? focused : {};
|
|
1463
|
+
let phxUpdate = liveSocket.binding(PHX_UPDATE);
|
|
1464
|
+
let phxFeedbackFor = liveSocket.binding(PHX_FEEDBACK_FOR);
|
|
1465
|
+
let disableWith = liveSocket.binding(PHX_DISABLE_WITH);
|
|
1466
|
+
let phxTriggerExternal = liveSocket.binding(PHX_TRIGGER_ACTION);
|
|
1467
|
+
let phxRemove = liveSocket.binding("remove");
|
|
1468
|
+
let added = [];
|
|
1469
|
+
let updates = [];
|
|
1470
|
+
let appendPrependUpdates = [];
|
|
1471
|
+
let pendingRemoves = [];
|
|
1472
|
+
let externalFormTriggered = null;
|
|
1473
|
+
let diffHTML = liveSocket.time("premorph container prep", () => {
|
|
1474
|
+
return this.buildDiffHTML(container, html, phxUpdate, targetContainer);
|
|
1475
|
+
});
|
|
1476
|
+
this.trackBefore("added", container);
|
|
1477
|
+
this.trackBefore("updated", container, container);
|
|
1478
|
+
liveSocket.time("morphdom", () => {
|
|
1479
|
+
morphdom_esm_default(targetContainer, diffHTML, {
|
|
1480
|
+
childrenOnly: targetContainer.getAttribute(PHX_COMPONENT) === null,
|
|
1481
|
+
getNodeKey: (node) => {
|
|
1482
|
+
return dom_default.isPhxDestroyed(node) ? null : node.id;
|
|
1483
|
+
},
|
|
1484
|
+
onBeforeNodeAdded: (el) => {
|
|
1485
|
+
this.trackBefore("added", el);
|
|
1486
|
+
return el;
|
|
1487
|
+
},
|
|
1488
|
+
onNodeAdded: (el) => {
|
|
1489
|
+
if (el instanceof HTMLImageElement && el.srcset) {
|
|
1490
|
+
el.srcset = el.srcset;
|
|
1491
|
+
} else if (el instanceof HTMLVideoElement && el.autoplay) {
|
|
1492
|
+
el.play();
|
|
1493
|
+
}
|
|
1494
|
+
if (dom_default.isNowTriggerFormExternal(el, phxTriggerExternal)) {
|
|
1495
|
+
externalFormTriggered = el;
|
|
1496
|
+
}
|
|
1497
|
+
dom_default.discardError(targetContainer, el, phxFeedbackFor);
|
|
1498
|
+
if (dom_default.isPhxChild(el) && view.ownsElement(el)) {
|
|
1499
|
+
this.trackAfter("phxChildAdded", el);
|
|
1500
|
+
}
|
|
1501
|
+
added.push(el);
|
|
1502
|
+
},
|
|
1503
|
+
onNodeDiscarded: (el) => {
|
|
1504
|
+
if (dom_default.isPhxChild(el)) {
|
|
1505
|
+
liveSocket.destroyViewByEl(el);
|
|
1506
|
+
}
|
|
1507
|
+
this.trackAfter("discarded", el);
|
|
1508
|
+
},
|
|
1509
|
+
onBeforeNodeDiscarded: (el) => {
|
|
1510
|
+
if (el.getAttribute && el.getAttribute(PHX_PRUNE) !== null) {
|
|
1511
|
+
return true;
|
|
1512
|
+
}
|
|
1513
|
+
if (el.parentNode !== null && dom_default.isPhxUpdate(el.parentNode, phxUpdate, ["append", "prepend"]) && el.id) {
|
|
1514
|
+
return false;
|
|
1515
|
+
}
|
|
1516
|
+
if (el.getAttribute && el.getAttribute(phxRemove)) {
|
|
1517
|
+
pendingRemoves.push(el);
|
|
1518
|
+
return false;
|
|
1519
|
+
}
|
|
1520
|
+
if (this.skipCIDSibling(el)) {
|
|
1521
|
+
return false;
|
|
1522
|
+
}
|
|
1523
|
+
return true;
|
|
1524
|
+
},
|
|
1525
|
+
onElUpdated: (el) => {
|
|
1526
|
+
if (dom_default.isNowTriggerFormExternal(el, phxTriggerExternal)) {
|
|
1527
|
+
externalFormTriggered = el;
|
|
1528
|
+
}
|
|
1529
|
+
updates.push(el);
|
|
1530
|
+
},
|
|
1531
|
+
onBeforeElUpdated: (fromEl, toEl) => {
|
|
1532
|
+
dom_default.cleanChildNodes(toEl, phxUpdate);
|
|
1533
|
+
if (this.skipCIDSibling(toEl)) {
|
|
1534
|
+
return false;
|
|
1535
|
+
}
|
|
1536
|
+
if (dom_default.isIgnored(fromEl, phxUpdate)) {
|
|
1537
|
+
this.trackBefore("updated", fromEl, toEl);
|
|
1538
|
+
dom_default.mergeAttrs(fromEl, toEl, { isIgnored: true });
|
|
1539
|
+
updates.push(fromEl);
|
|
1540
|
+
dom_default.applyStickyOperations(fromEl);
|
|
1541
|
+
return false;
|
|
1542
|
+
}
|
|
1543
|
+
if (fromEl.type === "number" && (fromEl.validity && fromEl.validity.badInput)) {
|
|
1544
|
+
return false;
|
|
1545
|
+
}
|
|
1546
|
+
if (!dom_default.syncPendingRef(fromEl, toEl, disableWith)) {
|
|
1547
|
+
if (dom_default.isUploadInput(fromEl)) {
|
|
1548
|
+
this.trackBefore("updated", fromEl, toEl);
|
|
1549
|
+
updates.push(fromEl);
|
|
1550
|
+
}
|
|
1551
|
+
dom_default.applyStickyOperations(fromEl);
|
|
1552
|
+
return false;
|
|
1553
|
+
}
|
|
1554
|
+
if (dom_default.isPhxChild(toEl)) {
|
|
1555
|
+
let prevSession = fromEl.getAttribute(PHX_SESSION);
|
|
1556
|
+
dom_default.mergeAttrs(fromEl, toEl, { exclude: [PHX_STATIC] });
|
|
1557
|
+
if (prevSession !== "") {
|
|
1558
|
+
fromEl.setAttribute(PHX_SESSION, prevSession);
|
|
1559
|
+
}
|
|
1560
|
+
fromEl.setAttribute(PHX_ROOT_ID, this.rootID);
|
|
1561
|
+
dom_default.applyStickyOperations(fromEl);
|
|
1562
|
+
return false;
|
|
1563
|
+
}
|
|
1564
|
+
dom_default.copyPrivates(toEl, fromEl);
|
|
1565
|
+
dom_default.discardError(targetContainer, toEl, phxFeedbackFor);
|
|
1566
|
+
let isFocusedFormEl = focused && fromEl.isSameNode(focused) && dom_default.isFormInput(fromEl);
|
|
1567
|
+
if (isFocusedFormEl) {
|
|
1568
|
+
this.trackBefore("updated", fromEl, toEl);
|
|
1569
|
+
dom_default.mergeFocusedInput(fromEl, toEl);
|
|
1570
|
+
dom_default.syncAttrsToProps(fromEl);
|
|
1571
|
+
updates.push(fromEl);
|
|
1572
|
+
dom_default.applyStickyOperations(fromEl);
|
|
1573
|
+
return false;
|
|
1574
|
+
} else {
|
|
1575
|
+
if (dom_default.isPhxUpdate(toEl, phxUpdate, ["append", "prepend"])) {
|
|
1576
|
+
appendPrependUpdates.push(new DOMPostMorphRestorer(fromEl, toEl, toEl.getAttribute(phxUpdate)));
|
|
1577
|
+
}
|
|
1578
|
+
dom_default.syncAttrsToProps(toEl);
|
|
1579
|
+
dom_default.applyStickyOperations(toEl);
|
|
1580
|
+
this.trackBefore("updated", fromEl, toEl);
|
|
1581
|
+
return true;
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
});
|
|
1585
|
+
});
|
|
1586
|
+
if (liveSocket.isDebugEnabled()) {
|
|
1587
|
+
detectDuplicateIds();
|
|
1588
|
+
}
|
|
1589
|
+
if (appendPrependUpdates.length > 0) {
|
|
1590
|
+
liveSocket.time("post-morph append/prepend restoration", () => {
|
|
1591
|
+
appendPrependUpdates.forEach((update) => update.perform());
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
liveSocket.silenceEvents(() => dom_default.restoreFocus(focused, selectionStart, selectionEnd));
|
|
1595
|
+
dom_default.dispatchEvent(document, "phx:update");
|
|
1596
|
+
added.forEach((el) => this.trackAfter("added", el));
|
|
1597
|
+
updates.forEach((el) => this.trackAfter("updated", el));
|
|
1598
|
+
if (pendingRemoves.length > 0) {
|
|
1599
|
+
liveSocket.transitionRemoves(pendingRemoves);
|
|
1600
|
+
liveSocket.requestDOMUpdate(() => {
|
|
1601
|
+
pendingRemoves.forEach((el) => el.remove());
|
|
1602
|
+
this.trackAfter("transitionsDiscarded", pendingRemoves);
|
|
1603
|
+
});
|
|
1604
|
+
}
|
|
1605
|
+
if (externalFormTriggered) {
|
|
1606
|
+
liveSocket.disconnect();
|
|
1607
|
+
externalFormTriggered.submit();
|
|
1608
|
+
}
|
|
1609
|
+
return true;
|
|
1610
|
+
}
|
|
1611
|
+
isCIDPatch() {
|
|
1612
|
+
return this.cidPatch;
|
|
1613
|
+
}
|
|
1614
|
+
skipCIDSibling(el) {
|
|
1615
|
+
return el.nodeType === Node.ELEMENT_NODE && el.getAttribute(PHX_SKIP) !== null;
|
|
1616
|
+
}
|
|
1617
|
+
targetCIDContainer(html) {
|
|
1618
|
+
if (!this.isCIDPatch()) {
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
let [first, ...rest] = dom_default.findComponentNodeList(this.container, this.targetCID);
|
|
1622
|
+
if (rest.length === 0 && dom_default.childNodeLength(html) === 1) {
|
|
1623
|
+
return first;
|
|
1624
|
+
} else {
|
|
1625
|
+
return first && first.parentNode;
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
buildDiffHTML(container, html, phxUpdate, targetContainer) {
|
|
1629
|
+
let isCIDPatch = this.isCIDPatch();
|
|
1630
|
+
let isCIDWithSingleRoot = isCIDPatch && targetContainer.getAttribute(PHX_COMPONENT) === this.targetCID.toString();
|
|
1631
|
+
if (!isCIDPatch || isCIDWithSingleRoot) {
|
|
1632
|
+
return html;
|
|
1633
|
+
} else {
|
|
1634
|
+
let diffContainer = null;
|
|
1635
|
+
let template = document.createElement("template");
|
|
1636
|
+
diffContainer = dom_default.cloneNode(targetContainer);
|
|
1637
|
+
let [firstComponent, ...rest] = dom_default.findComponentNodeList(diffContainer, this.targetCID);
|
|
1638
|
+
template.innerHTML = html;
|
|
1639
|
+
rest.forEach((el) => el.remove());
|
|
1640
|
+
Array.from(diffContainer.childNodes).forEach((child) => {
|
|
1641
|
+
if (child.id && child.nodeType === Node.ELEMENT_NODE && child.getAttribute(PHX_COMPONENT) !== this.targetCID.toString()) {
|
|
1642
|
+
child.setAttribute(PHX_SKIP, "");
|
|
1643
|
+
child.innerHTML = "";
|
|
1644
|
+
}
|
|
1645
|
+
});
|
|
1646
|
+
Array.from(template.content.childNodes).forEach((el) => diffContainer.insertBefore(el, firstComponent));
|
|
1647
|
+
firstComponent.remove();
|
|
1648
|
+
return diffContainer.outerHTML;
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
};
|
|
1652
|
+
|
|
1653
|
+
// js/phoenix_live_view/rendered.js
|
|
1654
|
+
var Rendered = class {
|
|
1655
|
+
static extract(diff) {
|
|
1656
|
+
let { [REPLY]: reply, [EVENTS]: events, [TITLE]: title } = diff;
|
|
1657
|
+
delete diff[REPLY];
|
|
1658
|
+
delete diff[EVENTS];
|
|
1659
|
+
delete diff[TITLE];
|
|
1660
|
+
return { diff, title, reply: reply || null, events: events || [] };
|
|
1661
|
+
}
|
|
1662
|
+
constructor(viewId, rendered) {
|
|
1663
|
+
this.viewId = viewId;
|
|
1664
|
+
this.rendered = {};
|
|
1665
|
+
this.mergeDiff(rendered);
|
|
1666
|
+
}
|
|
1667
|
+
parentViewId() {
|
|
1668
|
+
return this.viewId;
|
|
1669
|
+
}
|
|
1670
|
+
toString(onlyCids) {
|
|
1671
|
+
return this.recursiveToString(this.rendered, this.rendered[COMPONENTS], onlyCids);
|
|
1672
|
+
}
|
|
1673
|
+
recursiveToString(rendered, components = rendered[COMPONENTS], onlyCids) {
|
|
1674
|
+
onlyCids = onlyCids ? new Set(onlyCids) : null;
|
|
1675
|
+
let output = { buffer: "", components, onlyCids };
|
|
1676
|
+
this.toOutputBuffer(rendered, output);
|
|
1677
|
+
return output.buffer;
|
|
1678
|
+
}
|
|
1679
|
+
componentCIDs(diff) {
|
|
1680
|
+
return Object.keys(diff[COMPONENTS] || {}).map((i) => parseInt(i));
|
|
1681
|
+
}
|
|
1682
|
+
isComponentOnlyDiff(diff) {
|
|
1683
|
+
if (!diff[COMPONENTS]) {
|
|
1684
|
+
return false;
|
|
1685
|
+
}
|
|
1686
|
+
return Object.keys(diff).length === 1;
|
|
1687
|
+
}
|
|
1688
|
+
getComponent(diff, cid) {
|
|
1689
|
+
return diff[COMPONENTS][cid];
|
|
1690
|
+
}
|
|
1691
|
+
mergeDiff(diff) {
|
|
1692
|
+
let newc = diff[COMPONENTS];
|
|
1693
|
+
let cache = {};
|
|
1694
|
+
delete diff[COMPONENTS];
|
|
1695
|
+
this.rendered = this.mutableMerge(this.rendered, diff);
|
|
1696
|
+
this.rendered[COMPONENTS] = this.rendered[COMPONENTS] || {};
|
|
1697
|
+
if (newc) {
|
|
1698
|
+
let oldc = this.rendered[COMPONENTS];
|
|
1699
|
+
for (let cid in newc) {
|
|
1700
|
+
newc[cid] = this.cachedFindComponent(cid, newc[cid], oldc, newc, cache);
|
|
1701
|
+
}
|
|
1702
|
+
for (var key in newc) {
|
|
1703
|
+
oldc[key] = newc[key];
|
|
1704
|
+
}
|
|
1705
|
+
diff[COMPONENTS] = newc;
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
cachedFindComponent(cid, cdiff, oldc, newc, cache) {
|
|
1709
|
+
if (cache[cid]) {
|
|
1710
|
+
return cache[cid];
|
|
1711
|
+
} else {
|
|
1712
|
+
let ndiff, stat, scid = cdiff[STATIC];
|
|
1713
|
+
if (isCid(scid)) {
|
|
1714
|
+
let tdiff;
|
|
1715
|
+
if (scid > 0) {
|
|
1716
|
+
tdiff = this.cachedFindComponent(scid, newc[scid], oldc, newc, cache);
|
|
1717
|
+
} else {
|
|
1718
|
+
tdiff = oldc[-scid];
|
|
1719
|
+
}
|
|
1720
|
+
stat = tdiff[STATIC];
|
|
1721
|
+
ndiff = this.cloneMerge(tdiff, cdiff);
|
|
1722
|
+
ndiff[STATIC] = stat;
|
|
1723
|
+
} else {
|
|
1724
|
+
ndiff = cdiff[STATIC] !== void 0 ? cdiff : this.cloneMerge(oldc[cid] || {}, cdiff);
|
|
1725
|
+
}
|
|
1726
|
+
cache[cid] = ndiff;
|
|
1727
|
+
return ndiff;
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
mutableMerge(target, source) {
|
|
1731
|
+
if (source[STATIC] !== void 0) {
|
|
1732
|
+
return source;
|
|
1733
|
+
} else {
|
|
1734
|
+
this.doMutableMerge(target, source);
|
|
1735
|
+
return target;
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
doMutableMerge(target, source) {
|
|
1739
|
+
for (let key in source) {
|
|
1740
|
+
let val = source[key];
|
|
1741
|
+
let targetVal = target[key];
|
|
1742
|
+
if (isObject(val) && val[STATIC] === void 0 && isObject(targetVal)) {
|
|
1743
|
+
this.doMutableMerge(targetVal, val);
|
|
1744
|
+
} else {
|
|
1745
|
+
target[key] = val;
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
cloneMerge(target, source) {
|
|
1750
|
+
let merged = { ...target, ...source };
|
|
1751
|
+
for (let key in merged) {
|
|
1752
|
+
let val = source[key];
|
|
1753
|
+
let targetVal = target[key];
|
|
1754
|
+
if (isObject(val) && val[STATIC] === void 0 && isObject(targetVal)) {
|
|
1755
|
+
merged[key] = this.cloneMerge(targetVal, val);
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
return merged;
|
|
1759
|
+
}
|
|
1760
|
+
componentToString(cid) {
|
|
1761
|
+
return this.recursiveCIDToString(this.rendered[COMPONENTS], cid);
|
|
1762
|
+
}
|
|
1763
|
+
pruneCIDs(cids) {
|
|
1764
|
+
cids.forEach((cid) => delete this.rendered[COMPONENTS][cid]);
|
|
1765
|
+
}
|
|
1766
|
+
get() {
|
|
1767
|
+
return this.rendered;
|
|
1768
|
+
}
|
|
1769
|
+
isNewFingerprint(diff = {}) {
|
|
1770
|
+
return !!diff[STATIC];
|
|
1771
|
+
}
|
|
1772
|
+
toOutputBuffer(rendered, output) {
|
|
1773
|
+
if (rendered[DYNAMICS]) {
|
|
1774
|
+
return this.comprehensionToBuffer(rendered, output);
|
|
1775
|
+
}
|
|
1776
|
+
let { [STATIC]: statics } = rendered;
|
|
1777
|
+
output.buffer += statics[0];
|
|
1778
|
+
for (let i = 1; i < statics.length; i++) {
|
|
1779
|
+
this.dynamicToBuffer(rendered[i - 1], output);
|
|
1780
|
+
output.buffer += statics[i];
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
comprehensionToBuffer(rendered, output) {
|
|
1784
|
+
let { [DYNAMICS]: dynamics, [STATIC]: statics } = rendered;
|
|
1785
|
+
for (let d = 0; d < dynamics.length; d++) {
|
|
1786
|
+
let dynamic = dynamics[d];
|
|
1787
|
+
output.buffer += statics[0];
|
|
1788
|
+
for (let i = 1; i < statics.length; i++) {
|
|
1789
|
+
this.dynamicToBuffer(dynamic[i - 1], output);
|
|
1790
|
+
output.buffer += statics[i];
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
dynamicToBuffer(rendered, output) {
|
|
1795
|
+
if (typeof rendered === "number") {
|
|
1796
|
+
output.buffer += this.recursiveCIDToString(output.components, rendered, output.onlyCids);
|
|
1797
|
+
} else if (isObject(rendered)) {
|
|
1798
|
+
this.toOutputBuffer(rendered, output);
|
|
1799
|
+
} else {
|
|
1800
|
+
output.buffer += rendered;
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
recursiveCIDToString(components, cid, onlyCids) {
|
|
1804
|
+
let component = components[cid] || logError(`no component for CID ${cid}`, components);
|
|
1805
|
+
let template = document.createElement("template");
|
|
1806
|
+
template.innerHTML = this.recursiveToString(component, components, onlyCids);
|
|
1807
|
+
let container = template.content;
|
|
1808
|
+
let skip = onlyCids && !onlyCids.has(cid);
|
|
1809
|
+
let [hasChildNodes, hasChildComponents] = Array.from(container.childNodes).reduce(([hasNodes, hasComponents], child, i) => {
|
|
1810
|
+
if (child.nodeType === Node.ELEMENT_NODE) {
|
|
1811
|
+
if (child.getAttribute(PHX_COMPONENT)) {
|
|
1812
|
+
return [hasNodes, true];
|
|
1813
|
+
}
|
|
1814
|
+
child.setAttribute(PHX_COMPONENT, cid);
|
|
1815
|
+
if (!child.id) {
|
|
1816
|
+
child.id = `${this.parentViewId()}-${cid}-${i}`;
|
|
1817
|
+
}
|
|
1818
|
+
if (skip) {
|
|
1819
|
+
child.setAttribute(PHX_SKIP, "");
|
|
1820
|
+
child.innerHTML = "";
|
|
1821
|
+
}
|
|
1822
|
+
return [true, hasComponents];
|
|
1823
|
+
} else {
|
|
1824
|
+
if (child.nodeValue.trim() !== "") {
|
|
1825
|
+
logError(`only HTML element tags are allowed at the root of components.
|
|
1826
|
+
|
|
1827
|
+
got: "${child.nodeValue.trim()}"
|
|
1828
|
+
|
|
1829
|
+
within:
|
|
1830
|
+
`, template.innerHTML.trim());
|
|
1831
|
+
child.replaceWith(this.createSpan(child.nodeValue, cid));
|
|
1832
|
+
return [true, hasComponents];
|
|
1833
|
+
} else {
|
|
1834
|
+
child.remove();
|
|
1835
|
+
return [hasNodes, hasComponents];
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
}, [false, false]);
|
|
1839
|
+
if (!hasChildNodes && !hasChildComponents) {
|
|
1840
|
+
logError("expected at least one HTML element tag inside a component, but the component is empty:\n", template.innerHTML.trim());
|
|
1841
|
+
return this.createSpan("", cid).outerHTML;
|
|
1842
|
+
} else if (!hasChildNodes && hasChildComponents) {
|
|
1843
|
+
logError("expected at least one HTML element tag directly inside a component, but only subcomponents were found. A component must render at least one HTML tag directly inside itself.", template.innerHTML.trim());
|
|
1844
|
+
return template.innerHTML;
|
|
1845
|
+
} else {
|
|
1846
|
+
return template.innerHTML;
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
createSpan(text, cid) {
|
|
1850
|
+
let span = document.createElement("span");
|
|
1851
|
+
span.innerText = text;
|
|
1852
|
+
span.setAttribute(PHX_COMPONENT, cid);
|
|
1853
|
+
return span;
|
|
1854
|
+
}
|
|
1855
|
+
};
|
|
1856
|
+
|
|
1857
|
+
// js/phoenix_live_view/view_hook.js
|
|
1858
|
+
var viewHookID = 1;
|
|
1859
|
+
var ViewHook = class {
|
|
1860
|
+
static makeID() {
|
|
1861
|
+
return viewHookID++;
|
|
1862
|
+
}
|
|
1863
|
+
static elementID(el) {
|
|
1864
|
+
return el.phxHookId;
|
|
1865
|
+
}
|
|
1866
|
+
constructor(view, el, callbacks) {
|
|
1867
|
+
this.__view = view;
|
|
1868
|
+
this.__liveSocket = view.liveSocket;
|
|
1869
|
+
this.__callbacks = callbacks;
|
|
1870
|
+
this.__listeners = new Set();
|
|
1871
|
+
this.__isDisconnected = false;
|
|
1872
|
+
this.el = el;
|
|
1873
|
+
this.el.phxHookId = this.constructor.makeID();
|
|
1874
|
+
for (let key in this.__callbacks) {
|
|
1875
|
+
this[key] = this.__callbacks[key];
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
__mounted() {
|
|
1879
|
+
this.mounted && this.mounted();
|
|
1880
|
+
}
|
|
1881
|
+
__updated() {
|
|
1882
|
+
this.updated && this.updated();
|
|
1883
|
+
}
|
|
1884
|
+
__beforeUpdate() {
|
|
1885
|
+
this.beforeUpdate && this.beforeUpdate();
|
|
1886
|
+
}
|
|
1887
|
+
__destroyed() {
|
|
1888
|
+
this.destroyed && this.destroyed();
|
|
1889
|
+
}
|
|
1890
|
+
__reconnected() {
|
|
1891
|
+
if (this.__isDisconnected) {
|
|
1892
|
+
this.__isDisconnected = false;
|
|
1893
|
+
this.reconnected && this.reconnected();
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
__disconnected() {
|
|
1897
|
+
this.__isDisconnected = true;
|
|
1898
|
+
this.disconnected && this.disconnected();
|
|
1899
|
+
}
|
|
1900
|
+
pushEvent(event, payload = {}, onReply = function() {
|
|
1901
|
+
}) {
|
|
1902
|
+
return this.__view.pushHookEvent(null, event, payload, onReply);
|
|
1903
|
+
}
|
|
1904
|
+
pushEventTo(phxTarget, event, payload = {}, onReply = function() {
|
|
1905
|
+
}) {
|
|
1906
|
+
return this.__view.withinTargets(phxTarget, (view, targetCtx) => {
|
|
1907
|
+
return view.pushHookEvent(targetCtx, event, payload, onReply);
|
|
1908
|
+
});
|
|
1909
|
+
}
|
|
1910
|
+
handleEvent(event, callback) {
|
|
1911
|
+
let callbackRef = (customEvent, bypass) => bypass ? event : callback(customEvent.detail);
|
|
1912
|
+
window.addEventListener(`phx:${event}`, callbackRef);
|
|
1913
|
+
this.__listeners.add(callbackRef);
|
|
1914
|
+
return callbackRef;
|
|
1915
|
+
}
|
|
1916
|
+
removeHandleEvent(callbackRef) {
|
|
1917
|
+
let event = callbackRef(null, true);
|
|
1918
|
+
window.removeEventListener(`phx:${event}`, callbackRef);
|
|
1919
|
+
this.__listeners.delete(callbackRef);
|
|
1920
|
+
}
|
|
1921
|
+
upload(name, files) {
|
|
1922
|
+
return this.__view.dispatchUploads(name, files);
|
|
1923
|
+
}
|
|
1924
|
+
uploadTo(phxTarget, name, files) {
|
|
1925
|
+
return this.__view.withinTargets(phxTarget, (view) => view.dispatchUploads(name, files));
|
|
1926
|
+
}
|
|
1927
|
+
__cleanup__() {
|
|
1928
|
+
this.__listeners.forEach((callbackRef) => this.removeHandleEvent(callbackRef));
|
|
1929
|
+
}
|
|
1930
|
+
};
|
|
1931
|
+
|
|
1932
|
+
// js/phoenix_live_view/js.js
|
|
1933
|
+
var JS = {
|
|
1934
|
+
exec(eventType, phxEvent, view, el, defaults) {
|
|
1935
|
+
let [defaultKind, defaultArgs] = defaults || [null, {}];
|
|
1936
|
+
let commands = phxEvent.charAt(0) === "[" ? JSON.parse(phxEvent) : [[defaultKind, defaultArgs]];
|
|
1937
|
+
commands.forEach(([kind, args]) => {
|
|
1938
|
+
if (kind === defaultKind && defaultArgs.data) {
|
|
1939
|
+
args.data = Object.assign(args.data || {}, defaultArgs.data);
|
|
1940
|
+
}
|
|
1941
|
+
this[`exec_${kind}`](eventType, phxEvent, view, el, args);
|
|
1942
|
+
});
|
|
1943
|
+
},
|
|
1944
|
+
exec_dispatch(eventType, phxEvent, view, sourceEl, { to, event, detail }) {
|
|
1945
|
+
if (to) {
|
|
1946
|
+
dom_default.all(document, to, (el) => dom_default.dispatchEvent(el, event, detail));
|
|
1947
|
+
} else {
|
|
1948
|
+
dom_default.dispatchEvent(sourceEl, event, detail);
|
|
1949
|
+
}
|
|
1950
|
+
},
|
|
1951
|
+
exec_push(eventType, phxEvent, view, sourceEl, args) {
|
|
1952
|
+
let { event, data, target, page_loading, loading, value } = args;
|
|
1953
|
+
let pushOpts = { page_loading: !!page_loading, loading, value };
|
|
1954
|
+
let targetSrc = eventType === "change" ? sourceEl.form : sourceEl;
|
|
1955
|
+
let phxTarget = target || targetSrc.getAttribute(view.binding("target")) || targetSrc;
|
|
1956
|
+
view.withinTargets(phxTarget, (targetView, targetCtx) => {
|
|
1957
|
+
if (eventType === "change") {
|
|
1958
|
+
let { newCid, _target, callback } = args;
|
|
1959
|
+
if (_target) {
|
|
1960
|
+
pushOpts._target = _target;
|
|
1961
|
+
}
|
|
1962
|
+
targetView.pushInput(sourceEl, targetCtx, newCid, event || phxEvent, pushOpts, callback);
|
|
1963
|
+
} else if (eventType === "submit") {
|
|
1964
|
+
targetView.submitForm(sourceEl, targetCtx, event || phxEvent, pushOpts);
|
|
1965
|
+
} else {
|
|
1966
|
+
targetView.pushEvent(eventType, sourceEl, targetCtx, event || phxEvent, data, pushOpts);
|
|
1967
|
+
}
|
|
1968
|
+
});
|
|
1969
|
+
},
|
|
1970
|
+
exec_add_class(eventType, phxEvent, view, sourceEl, { to, names, transition, time }) {
|
|
1971
|
+
if (to) {
|
|
1972
|
+
dom_default.all(document, to, (el) => this.addOrRemoveClasses(el, names, [], transition, time, view));
|
|
1973
|
+
} else {
|
|
1974
|
+
this.addOrRemoveClasses(sourceEl, names, [], transition, view);
|
|
1975
|
+
}
|
|
1976
|
+
},
|
|
1977
|
+
exec_remove_class(eventType, phxEvent, view, sourceEl, { to, names, transition, time }) {
|
|
1978
|
+
if (to) {
|
|
1979
|
+
dom_default.all(document, to, (el) => this.addOrRemoveClasses(el, [], names, transition, time, view));
|
|
1980
|
+
} else {
|
|
1981
|
+
this.addOrRemoveClasses(sourceEl, [], names, transition, time, view);
|
|
1982
|
+
}
|
|
1983
|
+
},
|
|
1984
|
+
exec_transition(eventType, phxEvent, view, sourceEl, { time, to, names }) {
|
|
1985
|
+
let els = to ? dom_default.all(document, to) : [sourceEl];
|
|
1986
|
+
els.forEach((el) => {
|
|
1987
|
+
this.addOrRemoveClasses(el, names, []);
|
|
1988
|
+
view.transition(time, () => this.addOrRemoveClasses(el, [], names));
|
|
1989
|
+
});
|
|
1990
|
+
},
|
|
1991
|
+
exec_toggle(eventType, phxEvent, view, sourceEl, { to, display, ins, outs, time }) {
|
|
1992
|
+
if (to) {
|
|
1993
|
+
dom_default.all(document, to, (el) => this.toggle(eventType, view, el, display, ins || [], outs || [], time));
|
|
1994
|
+
} else {
|
|
1995
|
+
this.toggle(eventType, view, sourceEl, display, ins || [], outs || [], time);
|
|
1996
|
+
}
|
|
1997
|
+
},
|
|
1998
|
+
exec_show(eventType, phxEvent, view, sourceEl, { to, display, transition, time }) {
|
|
1999
|
+
if (to) {
|
|
2000
|
+
dom_default.all(document, to, (el) => this.show(eventType, view, el, display, transition, time));
|
|
2001
|
+
} else {
|
|
2002
|
+
this.show(eventType, view, sourceEl, transition, time);
|
|
2003
|
+
}
|
|
2004
|
+
},
|
|
2005
|
+
exec_hide(eventType, phxEvent, view, sourceEl, { to, display, transition, time }) {
|
|
2006
|
+
if (to) {
|
|
2007
|
+
dom_default.all(document, to, (el) => this.hide(eventType, view, el, display, transition, time));
|
|
2008
|
+
} else {
|
|
2009
|
+
this.hide(eventType, view, sourceEl, display, transition, time);
|
|
2010
|
+
}
|
|
2011
|
+
},
|
|
2012
|
+
show(eventType, view, el, display, transition, time) {
|
|
2013
|
+
let isVisible = this.isVisible(el);
|
|
2014
|
+
if (transition.length > 0 && !isVisible) {
|
|
2015
|
+
this.toggle(eventType, view, el, display, transition, [], time);
|
|
2016
|
+
} else if (!isVisible) {
|
|
2017
|
+
this.toggle(eventType, view, el, display, [], [], null);
|
|
2018
|
+
}
|
|
2019
|
+
},
|
|
2020
|
+
hide(eventType, view, el, display, transition, time) {
|
|
2021
|
+
let isVisible = this.isVisible(el);
|
|
2022
|
+
if (transition.length > 0 && isVisible) {
|
|
2023
|
+
this.toggle(eventType, view, el, display, [], transition, time);
|
|
2024
|
+
} else if (isVisible) {
|
|
2025
|
+
this.toggle(eventType, view, el, display, [], [], time);
|
|
2026
|
+
}
|
|
2027
|
+
},
|
|
2028
|
+
toggle(eventType, view, el, display, in_classes, out_classes, time) {
|
|
2029
|
+
if (in_classes.length > 0 || out_classes.length > 0) {
|
|
2030
|
+
if (this.isVisible(el)) {
|
|
2031
|
+
this.addOrRemoveClasses(el, out_classes, in_classes);
|
|
2032
|
+
view.transition(time, () => {
|
|
2033
|
+
dom_default.putSticky(el, "toggle", (currentEl) => currentEl.style.display = "none");
|
|
2034
|
+
this.addOrRemoveClasses(el, [], out_classes);
|
|
2035
|
+
});
|
|
2036
|
+
} else {
|
|
2037
|
+
if (eventType === "remove") {
|
|
2038
|
+
return;
|
|
2039
|
+
}
|
|
2040
|
+
this.addOrRemoveClasses(el, in_classes, out_classes);
|
|
2041
|
+
dom_default.putSticky(el, "toggle", (currentEl) => currentEl.style.display = display || "block");
|
|
2042
|
+
view.transition(time, () => {
|
|
2043
|
+
this.addOrRemoveClasses(el, [], in_classes);
|
|
2044
|
+
});
|
|
2045
|
+
}
|
|
2046
|
+
} else {
|
|
2047
|
+
let newDisplay = this.isVisible(el) ? "none" : display || "block";
|
|
2048
|
+
dom_default.putSticky(el, "toggle", (currentEl) => currentEl.style.display = newDisplay);
|
|
2049
|
+
}
|
|
2050
|
+
},
|
|
2051
|
+
addOrRemoveClasses(el, adds, removes, transition, time, view) {
|
|
2052
|
+
if (transition && transition.length > 0) {
|
|
2053
|
+
this.addOrRemoveClasses(el, transition, []);
|
|
2054
|
+
return view.transition(time, () => this.addOrRemoveClasses(el, adds, removes.concat(transition)));
|
|
2055
|
+
}
|
|
2056
|
+
window.requestAnimationFrame(() => {
|
|
2057
|
+
let [prevAdds, prevRemoves] = dom_default.getSticky(el, "classes", [[], []]);
|
|
2058
|
+
let keepAdds = adds.filter((name) => prevAdds.indexOf(name) < 0 && !el.classList.contains(name));
|
|
2059
|
+
let keepRemoves = removes.filter((name) => prevRemoves.indexOf(name) < 0 && el.classList.contains(name));
|
|
2060
|
+
let newAdds = prevAdds.filter((name) => removes.indexOf(name) < 0).concat(keepAdds);
|
|
2061
|
+
let newRemoves = prevRemoves.filter((name) => adds.indexOf(name) < 0).concat(keepRemoves);
|
|
2062
|
+
dom_default.putSticky(el, "classes", (currentEl) => {
|
|
2063
|
+
currentEl.classList.remove(...newRemoves);
|
|
2064
|
+
currentEl.classList.add(...newAdds);
|
|
2065
|
+
return [newAdds, newRemoves];
|
|
2066
|
+
});
|
|
2067
|
+
});
|
|
2068
|
+
},
|
|
2069
|
+
hasAllClasses(el, classes) {
|
|
2070
|
+
return classes.every((name) => el.classList.contains(name));
|
|
2071
|
+
},
|
|
2072
|
+
isVisible(el) {
|
|
2073
|
+
let style = window.getComputedStyle(el);
|
|
2074
|
+
return !(style.opacity === 0 || style.display === "none");
|
|
2075
|
+
},
|
|
2076
|
+
isToggledOut(el, out_classes) {
|
|
2077
|
+
return !this.isVisible(el) || this.hasAllClasses(el, out_classes);
|
|
2078
|
+
}
|
|
2079
|
+
};
|
|
2080
|
+
var js_default = JS;
|
|
2081
|
+
|
|
2082
|
+
// js/phoenix_live_view/view.js
|
|
2083
|
+
var serializeForm = (form, meta = {}) => {
|
|
2084
|
+
let formData = new FormData(form);
|
|
2085
|
+
let toRemove = [];
|
|
2086
|
+
formData.forEach((val, key, _index) => {
|
|
2087
|
+
if (val instanceof File) {
|
|
2088
|
+
toRemove.push(key);
|
|
2089
|
+
}
|
|
2090
|
+
});
|
|
2091
|
+
toRemove.forEach((key) => formData.delete(key));
|
|
2092
|
+
let params = new URLSearchParams();
|
|
2093
|
+
for (let [key, val] of formData.entries()) {
|
|
2094
|
+
params.append(key, val);
|
|
2095
|
+
}
|
|
2096
|
+
for (let metaKey in meta) {
|
|
2097
|
+
params.append(metaKey, meta[metaKey]);
|
|
2098
|
+
}
|
|
2099
|
+
return params.toString();
|
|
2100
|
+
};
|
|
2101
|
+
var View = class {
|
|
2102
|
+
constructor(el, liveSocket, parentView, flash) {
|
|
2103
|
+
this.liveSocket = liveSocket;
|
|
2104
|
+
this.flash = flash;
|
|
2105
|
+
this.parent = parentView;
|
|
2106
|
+
this.root = parentView ? parentView.root : this;
|
|
2107
|
+
this.el = el;
|
|
2108
|
+
this.id = this.el.id;
|
|
2109
|
+
this.ref = 0;
|
|
2110
|
+
this.childJoins = 0;
|
|
2111
|
+
this.loaderTimer = null;
|
|
2112
|
+
this.pendingDiffs = [];
|
|
2113
|
+
this.pruningCIDs = [];
|
|
2114
|
+
this.redirect = false;
|
|
2115
|
+
this.href = null;
|
|
2116
|
+
this.joinCount = this.parent ? this.parent.joinCount - 1 : 0;
|
|
2117
|
+
this.joinPending = true;
|
|
2118
|
+
this.destroyed = false;
|
|
2119
|
+
this.joinCallback = function(onDone) {
|
|
2120
|
+
onDone && onDone();
|
|
2121
|
+
};
|
|
2122
|
+
this.stopCallback = function() {
|
|
2123
|
+
};
|
|
2124
|
+
this.pendingJoinOps = this.parent ? null : [];
|
|
2125
|
+
this.viewHooks = {};
|
|
2126
|
+
this.uploaders = {};
|
|
2127
|
+
this.formSubmits = [];
|
|
2128
|
+
this.children = this.parent ? null : {};
|
|
2129
|
+
this.root.children[this.id] = {};
|
|
2130
|
+
this.channel = this.liveSocket.channel(`lv:${this.id}`, () => {
|
|
2131
|
+
return {
|
|
2132
|
+
redirect: this.redirect ? this.href : void 0,
|
|
2133
|
+
url: this.redirect ? void 0 : this.href || void 0,
|
|
2134
|
+
params: this.connectParams(),
|
|
2135
|
+
session: this.getSession(),
|
|
2136
|
+
static: this.getStatic(),
|
|
2137
|
+
flash: this.flash
|
|
2138
|
+
};
|
|
2139
|
+
});
|
|
2140
|
+
this.showLoader(this.liveSocket.loaderTimeout);
|
|
2141
|
+
this.bindChannel();
|
|
2142
|
+
}
|
|
2143
|
+
setHref(href) {
|
|
2144
|
+
this.href = href;
|
|
2145
|
+
}
|
|
2146
|
+
setRedirect(href) {
|
|
2147
|
+
this.redirect = true;
|
|
2148
|
+
this.href = href;
|
|
2149
|
+
}
|
|
2150
|
+
isMain() {
|
|
2151
|
+
return this.liveSocket.main === this;
|
|
2152
|
+
}
|
|
2153
|
+
connectParams() {
|
|
2154
|
+
let params = this.liveSocket.params(this.el);
|
|
2155
|
+
let manifest = dom_default.all(document, `[${this.binding(PHX_TRACK_STATIC)}]`).map((node) => node.src || node.href).filter((url) => typeof url === "string");
|
|
2156
|
+
if (manifest.length > 0) {
|
|
2157
|
+
params["_track_static"] = manifest;
|
|
2158
|
+
}
|
|
2159
|
+
params["_mounts"] = this.joinCount;
|
|
2160
|
+
return params;
|
|
2161
|
+
}
|
|
2162
|
+
isConnected() {
|
|
2163
|
+
return this.channel.canPush();
|
|
2164
|
+
}
|
|
2165
|
+
getSession() {
|
|
2166
|
+
return this.el.getAttribute(PHX_SESSION);
|
|
2167
|
+
}
|
|
2168
|
+
getStatic() {
|
|
2169
|
+
let val = this.el.getAttribute(PHX_STATIC);
|
|
2170
|
+
return val === "" ? null : val;
|
|
2171
|
+
}
|
|
2172
|
+
destroy(callback = function() {
|
|
2173
|
+
}) {
|
|
2174
|
+
this.destroyAllChildren();
|
|
2175
|
+
this.destroyed = true;
|
|
2176
|
+
delete this.root.children[this.id];
|
|
2177
|
+
if (this.parent) {
|
|
2178
|
+
delete this.root.children[this.parent.id][this.id];
|
|
2179
|
+
}
|
|
2180
|
+
clearTimeout(this.loaderTimer);
|
|
2181
|
+
let onFinished = () => {
|
|
2182
|
+
callback();
|
|
2183
|
+
for (let id in this.viewHooks) {
|
|
2184
|
+
this.destroyHook(this.viewHooks[id]);
|
|
2185
|
+
}
|
|
2186
|
+
};
|
|
2187
|
+
dom_default.markPhxChildDestroyed(this.el);
|
|
2188
|
+
this.log("destroyed", () => ["the child has been removed from the parent"]);
|
|
2189
|
+
this.channel.leave().receive("ok", onFinished).receive("error", onFinished).receive("timeout", onFinished);
|
|
2190
|
+
}
|
|
2191
|
+
setContainerClasses(...classes) {
|
|
2192
|
+
this.el.classList.remove(PHX_CONNECTED_CLASS, PHX_DISCONNECTED_CLASS, PHX_ERROR_CLASS);
|
|
2193
|
+
this.el.classList.add(...classes);
|
|
2194
|
+
}
|
|
2195
|
+
showLoader(timeout) {
|
|
2196
|
+
clearTimeout(this.loaderTimer);
|
|
2197
|
+
if (timeout) {
|
|
2198
|
+
this.loaderTimer = setTimeout(() => this.showLoader(), timeout);
|
|
2199
|
+
} else {
|
|
2200
|
+
for (let id in this.viewHooks) {
|
|
2201
|
+
this.viewHooks[id].__disconnected();
|
|
2202
|
+
}
|
|
2203
|
+
this.setContainerClasses(PHX_DISCONNECTED_CLASS);
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
hideLoader() {
|
|
2207
|
+
clearTimeout(this.loaderTimer);
|
|
2208
|
+
this.setContainerClasses(PHX_CONNECTED_CLASS);
|
|
2209
|
+
}
|
|
2210
|
+
triggerReconnected() {
|
|
2211
|
+
for (let id in this.viewHooks) {
|
|
2212
|
+
this.viewHooks[id].__reconnected();
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
log(kind, msgCallback) {
|
|
2216
|
+
this.liveSocket.log(this, kind, msgCallback);
|
|
2217
|
+
}
|
|
2218
|
+
transition(time, onDone = function() {
|
|
2219
|
+
}) {
|
|
2220
|
+
this.liveSocket.transition(time, onDone);
|
|
2221
|
+
}
|
|
2222
|
+
withinTargets(phxTarget, callback) {
|
|
2223
|
+
if (phxTarget instanceof HTMLElement || phxTarget instanceof SVGElement) {
|
|
2224
|
+
return this.liveSocket.owner(phxTarget, (view) => callback(view, phxTarget));
|
|
2225
|
+
}
|
|
2226
|
+
if (typeof phxTarget === "number" || /^(0|[1-9]\d*)$/.test(phxTarget)) {
|
|
2227
|
+
let targets = dom_default.findComponentNodeList(this.el, phxTarget);
|
|
2228
|
+
if (targets.length === 0) {
|
|
2229
|
+
logError(`no component found matching phx-target of ${phxTarget}`);
|
|
2230
|
+
} else {
|
|
2231
|
+
callback(this, parseInt(phxTarget));
|
|
2232
|
+
}
|
|
2233
|
+
} else {
|
|
2234
|
+
let targets = Array.from(document.querySelectorAll(phxTarget));
|
|
2235
|
+
if (targets.length === 0) {
|
|
2236
|
+
logError(`nothing found matching the phx-target selector "${phxTarget}"`);
|
|
2237
|
+
}
|
|
2238
|
+
targets.forEach((target) => this.liveSocket.owner(target, (view) => callback(view, target)));
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
applyDiff(type, rawDiff, callback) {
|
|
2242
|
+
this.log(type, () => ["", clone(rawDiff)]);
|
|
2243
|
+
let { diff, reply, events, title } = Rendered.extract(rawDiff);
|
|
2244
|
+
if (title) {
|
|
2245
|
+
dom_default.putTitle(title);
|
|
2246
|
+
}
|
|
2247
|
+
callback({ diff, reply, events });
|
|
2248
|
+
return reply;
|
|
2249
|
+
}
|
|
2250
|
+
onJoin(resp) {
|
|
2251
|
+
let { rendered, container } = resp;
|
|
2252
|
+
if (container) {
|
|
2253
|
+
let [tag, attrs] = container;
|
|
2254
|
+
this.el = dom_default.replaceRootContainer(this.el, tag, attrs);
|
|
2255
|
+
}
|
|
2256
|
+
this.childJoins = 0;
|
|
2257
|
+
this.joinPending = true;
|
|
2258
|
+
this.flash = null;
|
|
2259
|
+
browser_default.dropLocal(this.liveSocket.localStorage, window.location.pathname, CONSECUTIVE_RELOADS);
|
|
2260
|
+
this.applyDiff("mount", rendered, ({ diff, events }) => {
|
|
2261
|
+
this.rendered = new Rendered(this.id, diff);
|
|
2262
|
+
let html = this.renderContainer(null, "join");
|
|
2263
|
+
this.dropPendingRefs();
|
|
2264
|
+
let forms = this.formsForRecovery(html);
|
|
2265
|
+
this.joinCount++;
|
|
2266
|
+
if (forms.length > 0) {
|
|
2267
|
+
forms.forEach(([form, newForm, newCid], i) => {
|
|
2268
|
+
this.pushFormRecovery(form, newCid, (resp2) => {
|
|
2269
|
+
if (i === forms.length - 1) {
|
|
2270
|
+
this.onJoinComplete(resp2, html, events);
|
|
2271
|
+
}
|
|
2272
|
+
});
|
|
2273
|
+
});
|
|
2274
|
+
} else {
|
|
2275
|
+
this.onJoinComplete(resp, html, events);
|
|
2276
|
+
}
|
|
2277
|
+
});
|
|
2278
|
+
}
|
|
2279
|
+
dropPendingRefs() {
|
|
2280
|
+
dom_default.all(this.el, `[${PHX_REF}]`, (el) => el.removeAttribute(PHX_REF));
|
|
2281
|
+
}
|
|
2282
|
+
onJoinComplete({ live_patch }, html, events) {
|
|
2283
|
+
if (this.joinCount > 1 || this.parent && !this.parent.isJoinPending()) {
|
|
2284
|
+
return this.applyJoinPatch(live_patch, html, events);
|
|
2285
|
+
}
|
|
2286
|
+
let newChildren = dom_default.findPhxChildrenInFragment(html, this.id).filter((toEl) => {
|
|
2287
|
+
let fromEl = toEl.id && this.el.querySelector(`[id="${toEl.id}"]`);
|
|
2288
|
+
let phxStatic = fromEl && fromEl.getAttribute(PHX_STATIC);
|
|
2289
|
+
if (phxStatic) {
|
|
2290
|
+
toEl.setAttribute(PHX_STATIC, phxStatic);
|
|
2291
|
+
}
|
|
2292
|
+
return this.joinChild(toEl);
|
|
2293
|
+
});
|
|
2294
|
+
if (newChildren.length === 0) {
|
|
2295
|
+
if (this.parent) {
|
|
2296
|
+
this.root.pendingJoinOps.push([this, () => this.applyJoinPatch(live_patch, html, events)]);
|
|
2297
|
+
this.parent.ackJoin(this);
|
|
2298
|
+
} else {
|
|
2299
|
+
this.onAllChildJoinsComplete();
|
|
2300
|
+
this.applyJoinPatch(live_patch, html, events);
|
|
2301
|
+
}
|
|
2302
|
+
} else {
|
|
2303
|
+
this.root.pendingJoinOps.push([this, () => this.applyJoinPatch(live_patch, html, events)]);
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
attachTrueDocEl() {
|
|
2307
|
+
this.el = dom_default.byId(this.id);
|
|
2308
|
+
this.el.setAttribute(PHX_ROOT_ID, this.root.id);
|
|
2309
|
+
}
|
|
2310
|
+
applyJoinPatch(live_patch, html, events) {
|
|
2311
|
+
this.attachTrueDocEl();
|
|
2312
|
+
let patch = new DOMPatch(this, this.el, this.id, html, null);
|
|
2313
|
+
patch.markPrunableContentForRemoval();
|
|
2314
|
+
this.performPatch(patch, false);
|
|
2315
|
+
this.joinNewChildren();
|
|
2316
|
+
dom_default.all(this.el, `[${this.binding(PHX_HOOK)}], [data-phx-${PHX_HOOK}]`, (hookEl) => {
|
|
2317
|
+
let hook = this.addHook(hookEl);
|
|
2318
|
+
if (hook) {
|
|
2319
|
+
hook.__mounted();
|
|
2320
|
+
}
|
|
2321
|
+
});
|
|
2322
|
+
this.joinPending = false;
|
|
2323
|
+
this.liveSocket.dispatchEvents(events);
|
|
2324
|
+
this.applyPendingUpdates();
|
|
2325
|
+
if (live_patch) {
|
|
2326
|
+
let { kind, to } = live_patch;
|
|
2327
|
+
this.liveSocket.historyPatch(to, kind);
|
|
2328
|
+
}
|
|
2329
|
+
this.hideLoader();
|
|
2330
|
+
if (this.joinCount > 1) {
|
|
2331
|
+
this.triggerReconnected();
|
|
2332
|
+
}
|
|
2333
|
+
this.stopCallback();
|
|
2334
|
+
}
|
|
2335
|
+
triggerBeforeUpdateHook(fromEl, toEl) {
|
|
2336
|
+
this.liveSocket.triggerDOM("onBeforeElUpdated", [fromEl, toEl]);
|
|
2337
|
+
let hook = this.getHook(fromEl);
|
|
2338
|
+
let isIgnored = hook && dom_default.isIgnored(fromEl, this.binding(PHX_UPDATE));
|
|
2339
|
+
if (hook && !fromEl.isEqualNode(toEl) && !(isIgnored && isEqualObj(fromEl.dataset, toEl.dataset))) {
|
|
2340
|
+
hook.__beforeUpdate();
|
|
2341
|
+
return hook;
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
performPatch(patch, pruneCids) {
|
|
2345
|
+
let removedEls = [];
|
|
2346
|
+
let phxChildrenAdded = false;
|
|
2347
|
+
let updatedHookIds = new Set();
|
|
2348
|
+
patch.after("added", (el) => {
|
|
2349
|
+
this.liveSocket.triggerDOM("onNodeAdded", [el]);
|
|
2350
|
+
let newHook = this.addHook(el);
|
|
2351
|
+
if (newHook) {
|
|
2352
|
+
newHook.__mounted();
|
|
2353
|
+
}
|
|
2354
|
+
});
|
|
2355
|
+
patch.after("phxChildAdded", (_el) => phxChildrenAdded = true);
|
|
2356
|
+
patch.before("updated", (fromEl, toEl) => {
|
|
2357
|
+
let hook = this.triggerBeforeUpdateHook(fromEl, toEl);
|
|
2358
|
+
if (hook) {
|
|
2359
|
+
updatedHookIds.add(fromEl.id);
|
|
2360
|
+
}
|
|
2361
|
+
});
|
|
2362
|
+
patch.after("updated", (el) => {
|
|
2363
|
+
if (updatedHookIds.has(el.id)) {
|
|
2364
|
+
this.getHook(el).__updated();
|
|
2365
|
+
}
|
|
2366
|
+
});
|
|
2367
|
+
patch.after("discarded", (el) => {
|
|
2368
|
+
if (el.nodeType === Node.ELEMENT_NODE) {
|
|
2369
|
+
removedEls.push(el);
|
|
2370
|
+
}
|
|
2371
|
+
});
|
|
2372
|
+
patch.after("transitionsDiscarded", (els) => this.afterElementsRemoved(els, pruneCids));
|
|
2373
|
+
patch.perform();
|
|
2374
|
+
this.afterElementsRemoved(removedEls, pruneCids);
|
|
2375
|
+
return phxChildrenAdded;
|
|
2376
|
+
}
|
|
2377
|
+
afterElementsRemoved(elements, pruneCids) {
|
|
2378
|
+
let destroyedCIDs = [];
|
|
2379
|
+
elements.forEach((parent) => {
|
|
2380
|
+
let components = dom_default.all(parent, `[${PHX_COMPONENT}]`);
|
|
2381
|
+
components.concat(parent).forEach((el) => {
|
|
2382
|
+
let cid = this.componentID(el);
|
|
2383
|
+
if (isCid(cid) && destroyedCIDs.indexOf(cid) === -1) {
|
|
2384
|
+
destroyedCIDs.push(cid);
|
|
2385
|
+
}
|
|
2386
|
+
let hook = this.getHook(el);
|
|
2387
|
+
hook && this.destroyHook(hook);
|
|
2388
|
+
});
|
|
2389
|
+
});
|
|
2390
|
+
if (pruneCids) {
|
|
2391
|
+
this.maybePushComponentsDestroyed(destroyedCIDs);
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
joinNewChildren() {
|
|
2395
|
+
dom_default.findPhxChildren(this.el, this.id).forEach((el) => this.joinChild(el));
|
|
2396
|
+
}
|
|
2397
|
+
getChildById(id) {
|
|
2398
|
+
return this.root.children[this.id][id];
|
|
2399
|
+
}
|
|
2400
|
+
getDescendentByEl(el) {
|
|
2401
|
+
if (el.id === this.id) {
|
|
2402
|
+
return this;
|
|
2403
|
+
} else {
|
|
2404
|
+
return this.children[el.getAttribute(PHX_PARENT_ID)][el.id];
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
destroyDescendent(id) {
|
|
2408
|
+
for (let parentId in this.root.children) {
|
|
2409
|
+
for (let childId in this.root.children[parentId]) {
|
|
2410
|
+
if (childId === id) {
|
|
2411
|
+
return this.root.children[parentId][childId].destroy();
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
joinChild(el) {
|
|
2417
|
+
let child = this.getChildById(el.id);
|
|
2418
|
+
if (!child) {
|
|
2419
|
+
let view = new View(el, this.liveSocket, this);
|
|
2420
|
+
this.root.children[this.id][view.id] = view;
|
|
2421
|
+
view.join();
|
|
2422
|
+
this.childJoins++;
|
|
2423
|
+
return true;
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
isJoinPending() {
|
|
2427
|
+
return this.joinPending;
|
|
2428
|
+
}
|
|
2429
|
+
ackJoin(_child) {
|
|
2430
|
+
this.childJoins--;
|
|
2431
|
+
if (this.childJoins === 0) {
|
|
2432
|
+
if (this.parent) {
|
|
2433
|
+
this.parent.ackJoin(this);
|
|
2434
|
+
} else {
|
|
2435
|
+
this.onAllChildJoinsComplete();
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
onAllChildJoinsComplete() {
|
|
2440
|
+
this.joinCallback(() => {
|
|
2441
|
+
this.pendingJoinOps.forEach(([view, op]) => {
|
|
2442
|
+
if (!view.isDestroyed()) {
|
|
2443
|
+
op();
|
|
2444
|
+
}
|
|
2445
|
+
});
|
|
2446
|
+
this.pendingJoinOps = [];
|
|
2447
|
+
});
|
|
2448
|
+
}
|
|
2449
|
+
update(diff, events) {
|
|
2450
|
+
if (this.isJoinPending() || this.liveSocket.hasPendingLink()) {
|
|
2451
|
+
return this.pendingDiffs.push({ diff, events });
|
|
2452
|
+
}
|
|
2453
|
+
this.rendered.mergeDiff(diff);
|
|
2454
|
+
let phxChildrenAdded = false;
|
|
2455
|
+
if (this.rendered.isComponentOnlyDiff(diff)) {
|
|
2456
|
+
this.liveSocket.time("component patch complete", () => {
|
|
2457
|
+
let parentCids = dom_default.findParentCIDs(this.el, this.rendered.componentCIDs(diff));
|
|
2458
|
+
parentCids.forEach((parentCID) => {
|
|
2459
|
+
if (this.componentPatch(this.rendered.getComponent(diff, parentCID), parentCID)) {
|
|
2460
|
+
phxChildrenAdded = true;
|
|
2461
|
+
}
|
|
2462
|
+
});
|
|
2463
|
+
});
|
|
2464
|
+
} else if (!isEmpty(diff)) {
|
|
2465
|
+
this.liveSocket.time("full patch complete", () => {
|
|
2466
|
+
let html = this.renderContainer(diff, "update");
|
|
2467
|
+
let patch = new DOMPatch(this, this.el, this.id, html, null);
|
|
2468
|
+
phxChildrenAdded = this.performPatch(patch, true);
|
|
2469
|
+
});
|
|
2470
|
+
}
|
|
2471
|
+
this.liveSocket.dispatchEvents(events);
|
|
2472
|
+
if (phxChildrenAdded) {
|
|
2473
|
+
this.joinNewChildren();
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
renderContainer(diff, kind) {
|
|
2477
|
+
return this.liveSocket.time(`toString diff (${kind})`, () => {
|
|
2478
|
+
let tag = this.el.tagName;
|
|
2479
|
+
let cids = diff ? this.rendered.componentCIDs(diff).concat(this.pruningCIDs) : null;
|
|
2480
|
+
let html = this.rendered.toString(cids);
|
|
2481
|
+
return `<${tag}>${html}</${tag}>`;
|
|
2482
|
+
});
|
|
2483
|
+
}
|
|
2484
|
+
componentPatch(diff, cid) {
|
|
2485
|
+
if (isEmpty(diff))
|
|
2486
|
+
return false;
|
|
2487
|
+
let html = this.rendered.componentToString(cid);
|
|
2488
|
+
let patch = new DOMPatch(this, this.el, this.id, html, cid);
|
|
2489
|
+
let childrenAdded = this.performPatch(patch, true);
|
|
2490
|
+
return childrenAdded;
|
|
2491
|
+
}
|
|
2492
|
+
getHook(el) {
|
|
2493
|
+
return this.viewHooks[ViewHook.elementID(el)];
|
|
2494
|
+
}
|
|
2495
|
+
addHook(el) {
|
|
2496
|
+
if (ViewHook.elementID(el) || !el.getAttribute) {
|
|
2497
|
+
return;
|
|
2498
|
+
}
|
|
2499
|
+
let hookName = el.getAttribute(`data-phx-${PHX_HOOK}`) || el.getAttribute(this.binding(PHX_HOOK));
|
|
2500
|
+
if (hookName && !this.ownsElement(el)) {
|
|
2501
|
+
return;
|
|
2502
|
+
}
|
|
2503
|
+
let callbacks = this.liveSocket.getHookCallbacks(hookName);
|
|
2504
|
+
if (callbacks) {
|
|
2505
|
+
if (!el.id) {
|
|
2506
|
+
logError(`no DOM ID for hook "${hookName}". Hooks require a unique ID on each element.`, el);
|
|
2507
|
+
}
|
|
2508
|
+
let hook = new ViewHook(this, el, callbacks);
|
|
2509
|
+
this.viewHooks[ViewHook.elementID(hook.el)] = hook;
|
|
2510
|
+
return hook;
|
|
2511
|
+
} else if (hookName !== null) {
|
|
2512
|
+
logError(`unknown hook found for "${hookName}"`, el);
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
destroyHook(hook) {
|
|
2516
|
+
hook.__destroyed();
|
|
2517
|
+
hook.__cleanup__();
|
|
2518
|
+
delete this.viewHooks[ViewHook.elementID(hook.el)];
|
|
2519
|
+
}
|
|
2520
|
+
applyPendingUpdates() {
|
|
2521
|
+
this.pendingDiffs.forEach(({ diff, events }) => this.update(diff, events));
|
|
2522
|
+
this.pendingDiffs = [];
|
|
2523
|
+
}
|
|
2524
|
+
onChannel(event, cb) {
|
|
2525
|
+
this.liveSocket.onChannel(this.channel, event, (resp) => {
|
|
2526
|
+
if (this.isJoinPending()) {
|
|
2527
|
+
this.root.pendingJoinOps.push([this, () => cb(resp)]);
|
|
2528
|
+
} else {
|
|
2529
|
+
this.liveSocket.requestDOMUpdate(() => cb(resp));
|
|
2530
|
+
}
|
|
2531
|
+
});
|
|
2532
|
+
}
|
|
2533
|
+
bindChannel() {
|
|
2534
|
+
this.liveSocket.onChannel(this.channel, "diff", (rawDiff) => {
|
|
2535
|
+
this.liveSocket.requestDOMUpdate(() => {
|
|
2536
|
+
this.applyDiff("update", rawDiff, ({ diff, events }) => this.update(diff, events));
|
|
2537
|
+
});
|
|
2538
|
+
});
|
|
2539
|
+
this.onChannel("redirect", ({ to, flash }) => this.onRedirect({ to, flash }));
|
|
2540
|
+
this.onChannel("live_patch", (redir) => this.onLivePatch(redir));
|
|
2541
|
+
this.onChannel("live_redirect", (redir) => this.onLiveRedirect(redir));
|
|
2542
|
+
this.channel.onError((reason) => this.onError(reason));
|
|
2543
|
+
this.channel.onClose((reason) => this.onClose(reason));
|
|
2544
|
+
}
|
|
2545
|
+
destroyAllChildren() {
|
|
2546
|
+
for (let id in this.root.children[this.id]) {
|
|
2547
|
+
this.getChildById(id).destroy();
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
onLiveRedirect(redir) {
|
|
2551
|
+
let { to, kind, flash } = redir;
|
|
2552
|
+
let url = this.expandURL(to);
|
|
2553
|
+
this.liveSocket.historyRedirect(url, kind, flash);
|
|
2554
|
+
}
|
|
2555
|
+
onLivePatch(redir) {
|
|
2556
|
+
let { to, kind } = redir;
|
|
2557
|
+
this.href = this.expandURL(to);
|
|
2558
|
+
this.liveSocket.historyPatch(to, kind);
|
|
2559
|
+
}
|
|
2560
|
+
expandURL(to) {
|
|
2561
|
+
return to.startsWith("/") ? `${window.location.protocol}//${window.location.host}${to}` : to;
|
|
2562
|
+
}
|
|
2563
|
+
onRedirect({ to, flash }) {
|
|
2564
|
+
this.liveSocket.redirect(to, flash);
|
|
2565
|
+
}
|
|
2566
|
+
isDestroyed() {
|
|
2567
|
+
return this.destroyed;
|
|
2568
|
+
}
|
|
2569
|
+
join(callback) {
|
|
2570
|
+
if (!this.parent) {
|
|
2571
|
+
this.stopCallback = this.liveSocket.withPageLoading({ to: this.href, kind: "initial" });
|
|
2572
|
+
}
|
|
2573
|
+
this.joinCallback = (onDone) => {
|
|
2574
|
+
onDone = onDone || function() {
|
|
2575
|
+
};
|
|
2576
|
+
callback ? callback(this.joinCount, onDone) : onDone();
|
|
2577
|
+
};
|
|
2578
|
+
this.liveSocket.wrapPush(this, { timeout: false }, () => {
|
|
2579
|
+
return this.channel.join().receive("ok", (data) => {
|
|
2580
|
+
if (!this.isDestroyed()) {
|
|
2581
|
+
this.liveSocket.requestDOMUpdate(() => this.onJoin(data));
|
|
2582
|
+
}
|
|
2583
|
+
}).receive("error", (resp) => !this.isDestroyed() && this.onJoinError(resp)).receive("timeout", () => !this.isDestroyed() && this.onJoinError({ reason: "timeout" }));
|
|
2584
|
+
});
|
|
2585
|
+
}
|
|
2586
|
+
onJoinError(resp) {
|
|
2587
|
+
if (resp.reason === "unauthorized" || resp.reason === "stale") {
|
|
2588
|
+
this.log("error", () => ["unauthorized live_redirect. Falling back to page request", resp]);
|
|
2589
|
+
return this.onRedirect({ to: this.href });
|
|
2590
|
+
}
|
|
2591
|
+
if (resp.redirect || resp.live_redirect) {
|
|
2592
|
+
this.joinPending = false;
|
|
2593
|
+
this.channel.leave();
|
|
2594
|
+
}
|
|
2595
|
+
if (resp.redirect) {
|
|
2596
|
+
return this.onRedirect(resp.redirect);
|
|
2597
|
+
}
|
|
2598
|
+
if (resp.live_redirect) {
|
|
2599
|
+
return this.onLiveRedirect(resp.live_redirect);
|
|
2600
|
+
}
|
|
2601
|
+
this.log("error", () => ["unable to join", resp]);
|
|
2602
|
+
return this.liveSocket.reloadWithJitter(this);
|
|
2603
|
+
}
|
|
2604
|
+
onClose(reason) {
|
|
2605
|
+
if (this.isDestroyed()) {
|
|
2606
|
+
return;
|
|
2607
|
+
}
|
|
2608
|
+
if (this.isJoinPending() && document.visibilityState !== "hidden" || this.liveSocket.hasPendingLink() && reason !== "leave") {
|
|
2609
|
+
return this.liveSocket.reloadWithJitter(this);
|
|
2610
|
+
}
|
|
2611
|
+
this.destroyAllChildren();
|
|
2612
|
+
this.liveSocket.dropActiveElement(this);
|
|
2613
|
+
if (document.activeElement) {
|
|
2614
|
+
document.activeElement.blur();
|
|
2615
|
+
}
|
|
2616
|
+
if (this.liveSocket.isUnloaded()) {
|
|
2617
|
+
this.showLoader(BEFORE_UNLOAD_LOADER_TIMEOUT);
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
onError(reason) {
|
|
2621
|
+
this.onClose(reason);
|
|
2622
|
+
this.log("error", () => ["view crashed", reason]);
|
|
2623
|
+
if (!this.liveSocket.isUnloaded()) {
|
|
2624
|
+
this.displayError();
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
displayError() {
|
|
2628
|
+
if (this.isMain()) {
|
|
2629
|
+
dom_default.dispatchEvent(window, "phx:page-loading-start", { to: this.href, kind: "error" });
|
|
2630
|
+
}
|
|
2631
|
+
this.showLoader();
|
|
2632
|
+
this.setContainerClasses(PHX_DISCONNECTED_CLASS, PHX_ERROR_CLASS);
|
|
2633
|
+
}
|
|
2634
|
+
pushWithReply(refGenerator, event, payload, onReply = function() {
|
|
2635
|
+
}) {
|
|
2636
|
+
if (!this.isConnected()) {
|
|
2637
|
+
return;
|
|
2638
|
+
}
|
|
2639
|
+
let [ref, [el], opts] = refGenerator ? refGenerator() : [null, [], {}];
|
|
2640
|
+
let onLoadingDone = function() {
|
|
2641
|
+
};
|
|
2642
|
+
if (opts.page_loading || el && el.getAttribute(this.binding(PHX_PAGE_LOADING)) !== null) {
|
|
2643
|
+
onLoadingDone = this.liveSocket.withPageLoading({ kind: "element", target: el });
|
|
2644
|
+
}
|
|
2645
|
+
if (typeof payload.cid !== "number") {
|
|
2646
|
+
delete payload.cid;
|
|
2647
|
+
}
|
|
2648
|
+
return this.liveSocket.wrapPush(this, { timeout: true }, () => {
|
|
2649
|
+
return this.channel.push(event, payload, PUSH_TIMEOUT).receive("ok", (resp) => {
|
|
2650
|
+
this.liveSocket.requestDOMUpdate(() => {
|
|
2651
|
+
let hookReply = null;
|
|
2652
|
+
if (ref !== null) {
|
|
2653
|
+
this.undoRefs(ref);
|
|
2654
|
+
}
|
|
2655
|
+
if (resp.diff) {
|
|
2656
|
+
hookReply = this.applyDiff("update", resp.diff, ({ diff, events }) => {
|
|
2657
|
+
this.update(diff, events);
|
|
2658
|
+
});
|
|
2659
|
+
}
|
|
2660
|
+
if (resp.redirect) {
|
|
2661
|
+
this.onRedirect(resp.redirect);
|
|
2662
|
+
}
|
|
2663
|
+
if (resp.live_patch) {
|
|
2664
|
+
this.onLivePatch(resp.live_patch);
|
|
2665
|
+
}
|
|
2666
|
+
if (resp.live_redirect) {
|
|
2667
|
+
this.onLiveRedirect(resp.live_redirect);
|
|
2668
|
+
}
|
|
2669
|
+
onLoadingDone();
|
|
2670
|
+
onReply(resp, hookReply);
|
|
2671
|
+
});
|
|
2672
|
+
});
|
|
2673
|
+
});
|
|
2674
|
+
}
|
|
2675
|
+
undoRefs(ref) {
|
|
2676
|
+
dom_default.all(this.el, `[${PHX_REF}="${ref}"]`, (el) => {
|
|
2677
|
+
let disabledVal = el.getAttribute(PHX_DISABLED);
|
|
2678
|
+
el.removeAttribute(PHX_REF);
|
|
2679
|
+
if (el.getAttribute(PHX_READONLY) !== null) {
|
|
2680
|
+
el.readOnly = false;
|
|
2681
|
+
el.removeAttribute(PHX_READONLY);
|
|
2682
|
+
}
|
|
2683
|
+
if (disabledVal !== null) {
|
|
2684
|
+
el.disabled = disabledVal === "true" ? true : false;
|
|
2685
|
+
el.removeAttribute(PHX_DISABLED);
|
|
2686
|
+
}
|
|
2687
|
+
PHX_EVENT_CLASSES.forEach((className) => dom_default.removeClass(el, className));
|
|
2688
|
+
let disableRestore = el.getAttribute(PHX_DISABLE_WITH_RESTORE);
|
|
2689
|
+
if (disableRestore !== null) {
|
|
2690
|
+
el.innerText = disableRestore;
|
|
2691
|
+
el.removeAttribute(PHX_DISABLE_WITH_RESTORE);
|
|
2692
|
+
}
|
|
2693
|
+
let toEl = dom_default.private(el, PHX_REF);
|
|
2694
|
+
if (toEl) {
|
|
2695
|
+
let hook = this.triggerBeforeUpdateHook(el, toEl);
|
|
2696
|
+
DOMPatch.patchEl(el, toEl, this.liveSocket.getActiveElement());
|
|
2697
|
+
if (hook) {
|
|
2698
|
+
hook.__updated();
|
|
2699
|
+
}
|
|
2700
|
+
dom_default.deletePrivate(el, PHX_REF);
|
|
2701
|
+
}
|
|
2702
|
+
});
|
|
2703
|
+
}
|
|
2704
|
+
putRef(elements, event, opts = {}) {
|
|
2705
|
+
let newRef = this.ref++;
|
|
2706
|
+
let disableWith = this.binding(PHX_DISABLE_WITH);
|
|
2707
|
+
if (opts.loading) {
|
|
2708
|
+
elements = elements.concat(dom_default.all(document, opts.loading));
|
|
2709
|
+
}
|
|
2710
|
+
elements.forEach((el) => {
|
|
2711
|
+
el.classList.add(`phx-${event}-loading`);
|
|
2712
|
+
el.setAttribute(PHX_REF, newRef);
|
|
2713
|
+
let disableText = el.getAttribute(disableWith);
|
|
2714
|
+
if (disableText !== null) {
|
|
2715
|
+
if (!el.getAttribute(PHX_DISABLE_WITH_RESTORE)) {
|
|
2716
|
+
el.setAttribute(PHX_DISABLE_WITH_RESTORE, el.innerText);
|
|
2717
|
+
}
|
|
2718
|
+
el.innerText = disableText;
|
|
2719
|
+
}
|
|
2720
|
+
});
|
|
2721
|
+
return [newRef, elements, opts];
|
|
2722
|
+
}
|
|
2723
|
+
componentID(el) {
|
|
2724
|
+
let cid = el.getAttribute && el.getAttribute(PHX_COMPONENT);
|
|
2725
|
+
return cid ? parseInt(cid) : null;
|
|
2726
|
+
}
|
|
2727
|
+
targetComponentID(target, targetCtx) {
|
|
2728
|
+
if (isCid(targetCtx)) {
|
|
2729
|
+
return targetCtx;
|
|
2730
|
+
} else if (target.getAttribute(this.binding("target"))) {
|
|
2731
|
+
return this.closestComponentID(targetCtx);
|
|
2732
|
+
} else {
|
|
2733
|
+
return null;
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
closestComponentID(targetCtx) {
|
|
2737
|
+
if (isCid(targetCtx)) {
|
|
2738
|
+
return targetCtx;
|
|
2739
|
+
} else if (targetCtx) {
|
|
2740
|
+
return maybe(targetCtx.closest(`[${PHX_COMPONENT}]`), (el) => this.ownsElement(el) && this.componentID(el));
|
|
2741
|
+
} else {
|
|
2742
|
+
return null;
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
pushHookEvent(targetCtx, event, payload, onReply) {
|
|
2746
|
+
if (!this.isConnected()) {
|
|
2747
|
+
this.log("hook", () => ["unable to push hook event. LiveView not connected", event, payload]);
|
|
2748
|
+
return false;
|
|
2749
|
+
}
|
|
2750
|
+
let [ref, els, opts] = this.putRef([], "hook");
|
|
2751
|
+
this.pushWithReply(() => [ref, els, opts], "event", {
|
|
2752
|
+
type: "hook",
|
|
2753
|
+
event,
|
|
2754
|
+
value: payload,
|
|
2755
|
+
cid: this.closestComponentID(targetCtx)
|
|
2756
|
+
}, (resp, reply) => onReply(reply, ref));
|
|
2757
|
+
return ref;
|
|
2758
|
+
}
|
|
2759
|
+
extractMeta(el, meta, value) {
|
|
2760
|
+
let prefix = this.binding("value-");
|
|
2761
|
+
for (let i = 0; i < el.attributes.length; i++) {
|
|
2762
|
+
if (!meta) {
|
|
2763
|
+
meta = {};
|
|
2764
|
+
}
|
|
2765
|
+
let name = el.attributes[i].name;
|
|
2766
|
+
if (name.startsWith(prefix)) {
|
|
2767
|
+
meta[name.replace(prefix, "")] = el.getAttribute(name);
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
if (el.value !== void 0) {
|
|
2771
|
+
if (!meta) {
|
|
2772
|
+
meta = {};
|
|
2773
|
+
}
|
|
2774
|
+
meta.value = el.value;
|
|
2775
|
+
if (el.tagName === "INPUT" && CHECKABLE_INPUTS.indexOf(el.type) >= 0 && !el.checked) {
|
|
2776
|
+
delete meta.value;
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
if (value) {
|
|
2780
|
+
if (!meta) {
|
|
2781
|
+
meta = {};
|
|
2782
|
+
}
|
|
2783
|
+
for (let key in value) {
|
|
2784
|
+
meta[key] = value[key];
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
return meta;
|
|
2788
|
+
}
|
|
2789
|
+
pushEvent(type, el, targetCtx, phxEvent, meta, opts = {}) {
|
|
2790
|
+
this.pushWithReply(() => this.putRef([el], type, opts), "event", {
|
|
2791
|
+
type,
|
|
2792
|
+
event: phxEvent,
|
|
2793
|
+
value: this.extractMeta(el, meta, opts.value),
|
|
2794
|
+
cid: this.targetComponentID(el, targetCtx)
|
|
2795
|
+
});
|
|
2796
|
+
}
|
|
2797
|
+
pushFileProgress(fileEl, entryRef, progress, onReply = function() {
|
|
2798
|
+
}) {
|
|
2799
|
+
this.liveSocket.withinOwners(fileEl.form, (view, targetCtx) => {
|
|
2800
|
+
view.pushWithReply(null, "progress", {
|
|
2801
|
+
event: fileEl.getAttribute(view.binding(PHX_PROGRESS)),
|
|
2802
|
+
ref: fileEl.getAttribute(PHX_UPLOAD_REF),
|
|
2803
|
+
entry_ref: entryRef,
|
|
2804
|
+
progress,
|
|
2805
|
+
cid: view.targetComponentID(fileEl.form, targetCtx)
|
|
2806
|
+
}, onReply);
|
|
2807
|
+
});
|
|
2808
|
+
}
|
|
2809
|
+
pushInput(inputEl, targetCtx, forceCid, phxEvent, opts, callback) {
|
|
2810
|
+
let uploads;
|
|
2811
|
+
let cid = isCid(forceCid) ? forceCid : this.targetComponentID(inputEl.form, targetCtx);
|
|
2812
|
+
let refGenerator = () => this.putRef([inputEl, inputEl.form], "change", opts);
|
|
2813
|
+
let formData = serializeForm(inputEl.form, { _target: opts._target });
|
|
2814
|
+
if (dom_default.isUploadInput(inputEl) && inputEl.files && inputEl.files.length > 0) {
|
|
2815
|
+
LiveUploader.trackFiles(inputEl, Array.from(inputEl.files));
|
|
2816
|
+
}
|
|
2817
|
+
uploads = LiveUploader.serializeUploads(inputEl);
|
|
2818
|
+
let event = {
|
|
2819
|
+
type: "form",
|
|
2820
|
+
event: phxEvent,
|
|
2821
|
+
value: formData,
|
|
2822
|
+
uploads,
|
|
2823
|
+
cid
|
|
2824
|
+
};
|
|
2825
|
+
this.pushWithReply(refGenerator, "event", event, (resp) => {
|
|
2826
|
+
dom_default.showError(inputEl, this.liveSocket.binding(PHX_FEEDBACK_FOR));
|
|
2827
|
+
if (dom_default.isUploadInput(inputEl) && inputEl.getAttribute("data-phx-auto-upload") !== null) {
|
|
2828
|
+
if (LiveUploader.filesAwaitingPreflight(inputEl).length > 0) {
|
|
2829
|
+
let [ref, _els] = refGenerator();
|
|
2830
|
+
this.uploadFiles(inputEl.form, targetCtx, ref, cid, (_uploads) => {
|
|
2831
|
+
callback && callback(resp);
|
|
2832
|
+
this.triggerAwaitingSubmit(inputEl.form);
|
|
2833
|
+
});
|
|
2834
|
+
}
|
|
2835
|
+
} else {
|
|
2836
|
+
callback && callback(resp);
|
|
2837
|
+
}
|
|
2838
|
+
});
|
|
2839
|
+
}
|
|
2840
|
+
triggerAwaitingSubmit(formEl) {
|
|
2841
|
+
let awaitingSubmit = this.getScheduledSubmit(formEl);
|
|
2842
|
+
if (awaitingSubmit) {
|
|
2843
|
+
let [_el, _ref, _opts, callback] = awaitingSubmit;
|
|
2844
|
+
this.cancelSubmit(formEl);
|
|
2845
|
+
callback();
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
getScheduledSubmit(formEl) {
|
|
2849
|
+
return this.formSubmits.find(([el, _ref, _opts, _callback]) => el.isSameNode(formEl));
|
|
2850
|
+
}
|
|
2851
|
+
scheduleSubmit(formEl, ref, opts, callback) {
|
|
2852
|
+
if (this.getScheduledSubmit(formEl)) {
|
|
2853
|
+
return true;
|
|
2854
|
+
}
|
|
2855
|
+
this.formSubmits.push([formEl, ref, opts, callback]);
|
|
2856
|
+
}
|
|
2857
|
+
cancelSubmit(formEl) {
|
|
2858
|
+
this.formSubmits = this.formSubmits.filter(([el, ref, _callback]) => {
|
|
2859
|
+
if (el.isSameNode(formEl)) {
|
|
2860
|
+
this.undoRefs(ref);
|
|
2861
|
+
return false;
|
|
2862
|
+
} else {
|
|
2863
|
+
return true;
|
|
2864
|
+
}
|
|
2865
|
+
});
|
|
2866
|
+
}
|
|
2867
|
+
pushFormSubmit(formEl, targetCtx, phxEvent, opts, onReply) {
|
|
2868
|
+
let filterIgnored = (el) => {
|
|
2869
|
+
let userIgnored = closestPhxBinding(el, `${this.binding(PHX_UPDATE)}=ignore`, el.form);
|
|
2870
|
+
return !(userIgnored || closestPhxBinding(el, "data-phx-update=ignore", el.form));
|
|
2871
|
+
};
|
|
2872
|
+
let filterDisables = (el) => {
|
|
2873
|
+
return el.hasAttribute(this.binding(PHX_DISABLE_WITH));
|
|
2874
|
+
};
|
|
2875
|
+
let filterButton = (el) => el.tagName == "BUTTON";
|
|
2876
|
+
let filterInput = (el) => ["INPUT", "TEXTAREA", "SELECT"].includes(el.tagName);
|
|
2877
|
+
let refGenerator = () => {
|
|
2878
|
+
let formElements = Array.from(formEl.elements);
|
|
2879
|
+
let disables = formElements.filter(filterDisables);
|
|
2880
|
+
let buttons = formElements.filter(filterButton).filter(filterIgnored);
|
|
2881
|
+
let inputs = formElements.filter(filterInput).filter(filterIgnored);
|
|
2882
|
+
buttons.forEach((button) => {
|
|
2883
|
+
button.setAttribute(PHX_DISABLED, button.disabled);
|
|
2884
|
+
button.disabled = true;
|
|
2885
|
+
});
|
|
2886
|
+
inputs.forEach((input) => {
|
|
2887
|
+
input.setAttribute(PHX_READONLY, input.readOnly);
|
|
2888
|
+
input.readOnly = true;
|
|
2889
|
+
if (input.files) {
|
|
2890
|
+
input.setAttribute(PHX_DISABLED, input.disabled);
|
|
2891
|
+
input.disabled = true;
|
|
2892
|
+
}
|
|
2893
|
+
});
|
|
2894
|
+
formEl.setAttribute(this.binding(PHX_PAGE_LOADING), "");
|
|
2895
|
+
return this.putRef([formEl].concat(disables).concat(buttons).concat(inputs), "submit", opts);
|
|
2896
|
+
};
|
|
2897
|
+
let cid = this.targetComponentID(formEl, targetCtx);
|
|
2898
|
+
if (LiveUploader.hasUploadsInProgress(formEl)) {
|
|
2899
|
+
let [ref, _els] = refGenerator();
|
|
2900
|
+
let push = () => this.pushFormSubmit(formEl, targetCtx, phxEvent, opts, onReply);
|
|
2901
|
+
return this.scheduleSubmit(formEl, ref, opts, push);
|
|
2902
|
+
} else if (LiveUploader.inputsAwaitingPreflight(formEl).length > 0) {
|
|
2903
|
+
let [ref, els] = refGenerator();
|
|
2904
|
+
let proxyRefGen = () => [ref, els, opts];
|
|
2905
|
+
this.uploadFiles(formEl, targetCtx, ref, cid, (_uploads) => {
|
|
2906
|
+
let formData = serializeForm(formEl, {});
|
|
2907
|
+
this.pushWithReply(proxyRefGen, "event", {
|
|
2908
|
+
type: "form",
|
|
2909
|
+
event: phxEvent,
|
|
2910
|
+
value: formData,
|
|
2911
|
+
cid
|
|
2912
|
+
}, onReply);
|
|
2913
|
+
});
|
|
2914
|
+
} else {
|
|
2915
|
+
let formData = serializeForm(formEl);
|
|
2916
|
+
this.pushWithReply(refGenerator, "event", {
|
|
2917
|
+
type: "form",
|
|
2918
|
+
event: phxEvent,
|
|
2919
|
+
value: formData,
|
|
2920
|
+
cid
|
|
2921
|
+
}, onReply);
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
uploadFiles(formEl, targetCtx, ref, cid, onComplete) {
|
|
2925
|
+
let joinCountAtUpload = this.joinCount;
|
|
2926
|
+
let inputEls = LiveUploader.activeFileInputs(formEl);
|
|
2927
|
+
let numFileInputsInProgress = inputEls.length;
|
|
2928
|
+
inputEls.forEach((inputEl) => {
|
|
2929
|
+
let uploader = new LiveUploader(inputEl, this, () => {
|
|
2930
|
+
numFileInputsInProgress--;
|
|
2931
|
+
if (numFileInputsInProgress === 0) {
|
|
2932
|
+
onComplete();
|
|
2933
|
+
}
|
|
2934
|
+
});
|
|
2935
|
+
this.uploaders[inputEl] = uploader;
|
|
2936
|
+
let entries = uploader.entries().map((entry) => entry.toPreflightPayload());
|
|
2937
|
+
let payload = {
|
|
2938
|
+
ref: inputEl.getAttribute(PHX_UPLOAD_REF),
|
|
2939
|
+
entries,
|
|
2940
|
+
cid: this.targetComponentID(inputEl.form, targetCtx)
|
|
2941
|
+
};
|
|
2942
|
+
this.log("upload", () => ["sending preflight request", payload]);
|
|
2943
|
+
this.pushWithReply(null, "allow_upload", payload, (resp) => {
|
|
2944
|
+
this.log("upload", () => ["got preflight response", resp]);
|
|
2945
|
+
if (resp.error) {
|
|
2946
|
+
this.undoRefs(ref);
|
|
2947
|
+
let [entry_ref, reason] = resp.error;
|
|
2948
|
+
this.log("upload", () => [`error for entry ${entry_ref}`, reason]);
|
|
2949
|
+
} else {
|
|
2950
|
+
let onError = (callback) => {
|
|
2951
|
+
this.channel.onError(() => {
|
|
2952
|
+
if (this.joinCount === joinCountAtUpload) {
|
|
2953
|
+
callback();
|
|
2954
|
+
}
|
|
2955
|
+
});
|
|
2956
|
+
};
|
|
2957
|
+
uploader.initAdapterUpload(resp, onError, this.liveSocket);
|
|
2958
|
+
}
|
|
2959
|
+
});
|
|
2960
|
+
});
|
|
2961
|
+
}
|
|
2962
|
+
dispatchUploads(name, filesOrBlobs) {
|
|
2963
|
+
let inputs = dom_default.findUploadInputs(this.el).filter((el) => el.name === name);
|
|
2964
|
+
if (inputs.length === 0) {
|
|
2965
|
+
logError(`no live file inputs found matching the name "${name}"`);
|
|
2966
|
+
} else if (inputs.length > 1) {
|
|
2967
|
+
logError(`duplicate live file inputs found matching the name "${name}"`);
|
|
2968
|
+
} else {
|
|
2969
|
+
dom_default.dispatchEvent(inputs[0], PHX_TRACK_UPLOADS, { files: filesOrBlobs });
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
pushFormRecovery(form, newCid, callback) {
|
|
2973
|
+
this.liveSocket.withinOwners(form, (view, targetCtx) => {
|
|
2974
|
+
let input = form.elements[0];
|
|
2975
|
+
let phxEvent = form.getAttribute(this.binding(PHX_AUTO_RECOVER)) || form.getAttribute(this.binding("change"));
|
|
2976
|
+
js_default.exec("change", phxEvent, view, input, ["push", { _target: input.name, newCid, callback }]);
|
|
2977
|
+
});
|
|
2978
|
+
}
|
|
2979
|
+
pushLinkPatch(href, targetEl, callback) {
|
|
2980
|
+
let linkRef = this.liveSocket.setPendingLink(href);
|
|
2981
|
+
let refGen = targetEl ? () => this.putRef([targetEl], "click") : null;
|
|
2982
|
+
this.pushWithReply(refGen, "live_patch", { url: href }, (resp) => {
|
|
2983
|
+
this.liveSocket.requestDOMUpdate(() => {
|
|
2984
|
+
if (resp.link_redirect) {
|
|
2985
|
+
this.liveSocket.replaceMain(href, null, callback, linkRef);
|
|
2986
|
+
} else {
|
|
2987
|
+
if (this.liveSocket.commitPendingLink(linkRef)) {
|
|
2988
|
+
this.href = href;
|
|
2989
|
+
}
|
|
2990
|
+
this.applyPendingUpdates();
|
|
2991
|
+
callback && callback(linkRef);
|
|
2992
|
+
}
|
|
2993
|
+
});
|
|
2994
|
+
}).receive("timeout", () => this.liveSocket.redirect(window.location.href));
|
|
2995
|
+
}
|
|
2996
|
+
formsForRecovery(html) {
|
|
2997
|
+
if (this.joinCount === 0) {
|
|
2998
|
+
return [];
|
|
2999
|
+
}
|
|
3000
|
+
let phxChange = this.binding("change");
|
|
3001
|
+
let template = document.createElement("template");
|
|
3002
|
+
template.innerHTML = html;
|
|
3003
|
+
return dom_default.all(this.el, `form[${phxChange}]`).filter((form) => form.id && this.ownsElement(form)).filter((form) => form.elements.length > 0).filter((form) => form.getAttribute(this.binding(PHX_AUTO_RECOVER)) !== "ignore").map((form) => {
|
|
3004
|
+
let newForm = template.content.querySelector(`form[id="${form.id}"][${phxChange}="${form.getAttribute(phxChange)}"]`);
|
|
3005
|
+
if (newForm) {
|
|
3006
|
+
return [form, newForm, this.componentID(newForm)];
|
|
3007
|
+
} else {
|
|
3008
|
+
return [form, null, null];
|
|
3009
|
+
}
|
|
3010
|
+
}).filter(([form, newForm, newCid]) => newForm);
|
|
3011
|
+
}
|
|
3012
|
+
maybePushComponentsDestroyed(destroyedCIDs) {
|
|
3013
|
+
let willDestroyCIDs = destroyedCIDs.filter((cid) => {
|
|
3014
|
+
return dom_default.findComponentNodeList(this.el, cid).length === 0;
|
|
3015
|
+
});
|
|
3016
|
+
if (willDestroyCIDs.length > 0) {
|
|
3017
|
+
this.pruningCIDs.push(...willDestroyCIDs);
|
|
3018
|
+
this.pushWithReply(null, "cids_will_destroy", { cids: willDestroyCIDs }, () => {
|
|
3019
|
+
this.pruningCIDs = this.pruningCIDs.filter((cid) => willDestroyCIDs.indexOf(cid) !== -1);
|
|
3020
|
+
let completelyDestroyCIDs = willDestroyCIDs.filter((cid) => {
|
|
3021
|
+
return dom_default.findComponentNodeList(this.el, cid).length === 0;
|
|
3022
|
+
});
|
|
3023
|
+
if (completelyDestroyCIDs.length > 0) {
|
|
3024
|
+
this.pushWithReply(null, "cids_destroyed", { cids: completelyDestroyCIDs }, (resp) => {
|
|
3025
|
+
this.rendered.pruneCIDs(resp.cids);
|
|
3026
|
+
});
|
|
3027
|
+
}
|
|
3028
|
+
});
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
ownsElement(el) {
|
|
3032
|
+
return el.getAttribute(PHX_PARENT_ID) === this.id || maybe(el.closest(PHX_VIEW_SELECTOR), (node) => node.id) === this.id;
|
|
3033
|
+
}
|
|
3034
|
+
submitForm(form, targetCtx, phxEvent, opts = {}) {
|
|
3035
|
+
dom_default.putPrivate(form, PHX_HAS_SUBMITTED, true);
|
|
3036
|
+
this.liveSocket.blurActiveElement(this);
|
|
3037
|
+
this.pushFormSubmit(form, targetCtx, phxEvent, opts, () => {
|
|
3038
|
+
this.liveSocket.restorePreviouslyActiveFocus();
|
|
3039
|
+
});
|
|
3040
|
+
}
|
|
3041
|
+
binding(kind) {
|
|
3042
|
+
return this.liveSocket.binding(kind);
|
|
3043
|
+
}
|
|
3044
|
+
};
|
|
3045
|
+
|
|
3046
|
+
// js/phoenix_live_view/live_socket.js
|
|
3047
|
+
var LiveSocket = class {
|
|
3048
|
+
constructor(url, phxSocket, opts = {}) {
|
|
3049
|
+
this.unloaded = false;
|
|
3050
|
+
if (!phxSocket || phxSocket.constructor.name === "Object") {
|
|
3051
|
+
throw new Error(`
|
|
3052
|
+
a phoenix Socket must be provided as the second argument to the LiveSocket constructor. For example:
|
|
3053
|
+
|
|
3054
|
+
import {Socket} from "phoenix"
|
|
3055
|
+
import LiveSocket from "phoenix_live_view"
|
|
3056
|
+
let liveSocket = new LiveSocket("/live", Socket, {...})
|
|
3057
|
+
`);
|
|
3058
|
+
}
|
|
3059
|
+
this.socket = new phxSocket(url, opts);
|
|
3060
|
+
this.bindingPrefix = opts.bindingPrefix || BINDING_PREFIX;
|
|
3061
|
+
this.opts = opts;
|
|
3062
|
+
this.params = closure(opts.params || {});
|
|
3063
|
+
this.viewLogger = opts.viewLogger;
|
|
3064
|
+
this.metadataCallbacks = opts.metadata || {};
|
|
3065
|
+
this.defaults = Object.assign(clone(DEFAULTS), opts.defaults || {});
|
|
3066
|
+
this.activeElement = null;
|
|
3067
|
+
this.prevActive = null;
|
|
3068
|
+
this.silenced = false;
|
|
3069
|
+
this.main = null;
|
|
3070
|
+
this.linkRef = 1;
|
|
3071
|
+
this.roots = {};
|
|
3072
|
+
this.href = window.location.href;
|
|
3073
|
+
this.pendingLink = null;
|
|
3074
|
+
this.currentLocation = clone(window.location);
|
|
3075
|
+
this.hooks = opts.hooks || {};
|
|
3076
|
+
this.uploaders = opts.uploaders || {};
|
|
3077
|
+
this.loaderTimeout = opts.loaderTimeout || LOADER_TIMEOUT;
|
|
3078
|
+
this.localStorage = opts.localStorage || window.localStorage;
|
|
3079
|
+
this.sessionStorage = opts.sessionStorage || window.sessionStorage;
|
|
3080
|
+
this.boundTopLevelEvents = false;
|
|
3081
|
+
this.domCallbacks = Object.assign({ onNodeAdded: closure(), onBeforeElUpdated: closure() }, opts.dom || {});
|
|
3082
|
+
this.transitions = new TransitionSet();
|
|
3083
|
+
window.addEventListener("pagehide", (_e) => {
|
|
3084
|
+
this.unloaded = true;
|
|
3085
|
+
});
|
|
3086
|
+
this.socket.onOpen(() => {
|
|
3087
|
+
if (this.isUnloaded()) {
|
|
3088
|
+
window.location.reload();
|
|
3089
|
+
}
|
|
3090
|
+
});
|
|
3091
|
+
}
|
|
3092
|
+
isProfileEnabled() {
|
|
3093
|
+
return this.sessionStorage.getItem(PHX_LV_PROFILE) === "true";
|
|
3094
|
+
}
|
|
3095
|
+
isDebugEnabled() {
|
|
3096
|
+
return this.sessionStorage.getItem(PHX_LV_DEBUG) === "true";
|
|
3097
|
+
}
|
|
3098
|
+
enableDebug() {
|
|
3099
|
+
this.sessionStorage.setItem(PHX_LV_DEBUG, "true");
|
|
3100
|
+
}
|
|
3101
|
+
enableProfiling() {
|
|
3102
|
+
this.sessionStorage.setItem(PHX_LV_PROFILE, "true");
|
|
3103
|
+
}
|
|
3104
|
+
disableDebug() {
|
|
3105
|
+
this.sessionStorage.removeItem(PHX_LV_DEBUG);
|
|
3106
|
+
}
|
|
3107
|
+
disableProfiling() {
|
|
3108
|
+
this.sessionStorage.removeItem(PHX_LV_PROFILE);
|
|
3109
|
+
}
|
|
3110
|
+
enableLatencySim(upperBoundMs) {
|
|
3111
|
+
this.enableDebug();
|
|
3112
|
+
console.log("latency simulator enabled for the duration of this browser session. Call disableLatencySim() to disable");
|
|
3113
|
+
this.sessionStorage.setItem(PHX_LV_LATENCY_SIM, upperBoundMs);
|
|
3114
|
+
}
|
|
3115
|
+
disableLatencySim() {
|
|
3116
|
+
this.sessionStorage.removeItem(PHX_LV_LATENCY_SIM);
|
|
3117
|
+
}
|
|
3118
|
+
getLatencySim() {
|
|
3119
|
+
let str = this.sessionStorage.getItem(PHX_LV_LATENCY_SIM);
|
|
3120
|
+
return str ? parseInt(str) : null;
|
|
3121
|
+
}
|
|
3122
|
+
getSocket() {
|
|
3123
|
+
return this.socket;
|
|
3124
|
+
}
|
|
3125
|
+
connect() {
|
|
3126
|
+
let doConnect = () => {
|
|
3127
|
+
if (this.joinRootViews()) {
|
|
3128
|
+
this.bindTopLevelEvents();
|
|
3129
|
+
this.socket.connect();
|
|
3130
|
+
}
|
|
3131
|
+
};
|
|
3132
|
+
if (["complete", "loaded", "interactive"].indexOf(document.readyState) >= 0) {
|
|
3133
|
+
doConnect();
|
|
3134
|
+
} else {
|
|
3135
|
+
document.addEventListener("DOMContentLoaded", () => doConnect());
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
disconnect(callback) {
|
|
3139
|
+
this.socket.disconnect(callback);
|
|
3140
|
+
}
|
|
3141
|
+
execJS(el, encodedJS, eventType = null) {
|
|
3142
|
+
this.owner(el, (view) => js_default.exec(eventType, encodedJS, view, el));
|
|
3143
|
+
}
|
|
3144
|
+
triggerDOM(kind, args) {
|
|
3145
|
+
this.domCallbacks[kind](...args);
|
|
3146
|
+
}
|
|
3147
|
+
time(name, func) {
|
|
3148
|
+
if (!this.isProfileEnabled() || !console.time) {
|
|
3149
|
+
return func();
|
|
3150
|
+
}
|
|
3151
|
+
console.time(name);
|
|
3152
|
+
let result = func();
|
|
3153
|
+
console.timeEnd(name);
|
|
3154
|
+
return result;
|
|
3155
|
+
}
|
|
3156
|
+
log(view, kind, msgCallback) {
|
|
3157
|
+
if (this.viewLogger) {
|
|
3158
|
+
let [msg, obj] = msgCallback();
|
|
3159
|
+
this.viewLogger(view, kind, msg, obj);
|
|
3160
|
+
} else if (this.isDebugEnabled()) {
|
|
3161
|
+
let [msg, obj] = msgCallback();
|
|
3162
|
+
debug(view, kind, msg, obj);
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
requestDOMUpdate(callback) {
|
|
3166
|
+
this.transitions.after(callback);
|
|
3167
|
+
}
|
|
3168
|
+
transition(time, onDone = function() {
|
|
3169
|
+
}) {
|
|
3170
|
+
this.transitions.addTransition(time, onDone);
|
|
3171
|
+
}
|
|
3172
|
+
onChannel(channel, event, cb) {
|
|
3173
|
+
channel.on(event, (data) => {
|
|
3174
|
+
let latency = this.getLatencySim();
|
|
3175
|
+
if (!latency) {
|
|
3176
|
+
cb(data);
|
|
3177
|
+
} else {
|
|
3178
|
+
console.log(`simulating ${latency}ms of latency from server to client`);
|
|
3179
|
+
setTimeout(() => cb(data), latency);
|
|
3180
|
+
}
|
|
3181
|
+
});
|
|
3182
|
+
}
|
|
3183
|
+
wrapPush(view, opts, push) {
|
|
3184
|
+
let latency = this.getLatencySim();
|
|
3185
|
+
let oldJoinCount = view.joinCount;
|
|
3186
|
+
if (!latency) {
|
|
3187
|
+
if (opts.timeout) {
|
|
3188
|
+
return push().receive("timeout", () => {
|
|
3189
|
+
if (view.joinCount === oldJoinCount && !view.isDestroyed()) {
|
|
3190
|
+
this.reloadWithJitter(view, () => {
|
|
3191
|
+
this.log(view, "timeout", () => ["received timeout while communicating with server. Falling back to hard refresh for recovery"]);
|
|
3192
|
+
});
|
|
3193
|
+
}
|
|
3194
|
+
});
|
|
3195
|
+
} else {
|
|
3196
|
+
return push();
|
|
3197
|
+
}
|
|
3198
|
+
}
|
|
3199
|
+
console.log(`simulating ${latency}ms of latency from client to server`);
|
|
3200
|
+
let fakePush = {
|
|
3201
|
+
receives: [],
|
|
3202
|
+
receive(kind, cb) {
|
|
3203
|
+
this.receives.push([kind, cb]);
|
|
3204
|
+
}
|
|
3205
|
+
};
|
|
3206
|
+
setTimeout(() => {
|
|
3207
|
+
if (view.isDestroyed()) {
|
|
3208
|
+
return;
|
|
3209
|
+
}
|
|
3210
|
+
fakePush.receives.reduce((acc, [kind, cb]) => acc.receive(kind, cb), push());
|
|
3211
|
+
}, latency);
|
|
3212
|
+
return fakePush;
|
|
3213
|
+
}
|
|
3214
|
+
reloadWithJitter(view, log) {
|
|
3215
|
+
view.destroy();
|
|
3216
|
+
this.disconnect();
|
|
3217
|
+
let [minMs, maxMs] = RELOAD_JITTER;
|
|
3218
|
+
let afterMs = Math.floor(Math.random() * (maxMs - minMs + 1)) + minMs;
|
|
3219
|
+
let tries = browser_default.updateLocal(this.localStorage, window.location.pathname, CONSECUTIVE_RELOADS, 0, (count) => count + 1);
|
|
3220
|
+
log ? log() : this.log(view, "join", () => [`encountered ${tries} consecutive reloads`]);
|
|
3221
|
+
if (tries > MAX_RELOADS) {
|
|
3222
|
+
this.log(view, "join", () => [`exceeded ${MAX_RELOADS} consecutive reloads. Entering failsafe mode`]);
|
|
3223
|
+
afterMs = FAILSAFE_JITTER;
|
|
3224
|
+
}
|
|
3225
|
+
setTimeout(() => {
|
|
3226
|
+
if (this.hasPendingLink()) {
|
|
3227
|
+
window.location = this.pendingLink;
|
|
3228
|
+
} else {
|
|
3229
|
+
window.location.reload();
|
|
3230
|
+
}
|
|
3231
|
+
}, afterMs);
|
|
3232
|
+
}
|
|
3233
|
+
getHookCallbacks(name) {
|
|
3234
|
+
return name && name.startsWith("Phoenix.") ? hooks_default[name.split(".")[1]] : this.hooks[name];
|
|
3235
|
+
}
|
|
3236
|
+
isUnloaded() {
|
|
3237
|
+
return this.unloaded;
|
|
3238
|
+
}
|
|
3239
|
+
isConnected() {
|
|
3240
|
+
return this.socket.isConnected();
|
|
3241
|
+
}
|
|
3242
|
+
getBindingPrefix() {
|
|
3243
|
+
return this.bindingPrefix;
|
|
3244
|
+
}
|
|
3245
|
+
binding(kind) {
|
|
3246
|
+
return `${this.getBindingPrefix()}${kind}`;
|
|
3247
|
+
}
|
|
3248
|
+
channel(topic, params) {
|
|
3249
|
+
return this.socket.channel(topic, params);
|
|
3250
|
+
}
|
|
3251
|
+
joinRootViews() {
|
|
3252
|
+
let rootsFound = false;
|
|
3253
|
+
dom_default.all(document, `${PHX_VIEW_SELECTOR}:not([${PHX_PARENT_ID}])`, (rootEl) => {
|
|
3254
|
+
if (!this.getRootById(rootEl.id)) {
|
|
3255
|
+
let view = this.newRootView(rootEl);
|
|
3256
|
+
view.setHref(this.getHref());
|
|
3257
|
+
view.join();
|
|
3258
|
+
if (rootEl.getAttribute(PHX_MAIN)) {
|
|
3259
|
+
this.main = view;
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
3262
|
+
rootsFound = true;
|
|
3263
|
+
});
|
|
3264
|
+
return rootsFound;
|
|
3265
|
+
}
|
|
3266
|
+
redirect(to, flash) {
|
|
3267
|
+
this.disconnect();
|
|
3268
|
+
browser_default.redirect(to, flash);
|
|
3269
|
+
}
|
|
3270
|
+
replaceMain(href, flash, callback = null, linkRef = this.setPendingLink(href)) {
|
|
3271
|
+
let oldMainEl = this.main.el;
|
|
3272
|
+
let newMainEl = dom_default.cloneNode(oldMainEl, "");
|
|
3273
|
+
this.main.showLoader(this.loaderTimeout);
|
|
3274
|
+
this.main.destroy();
|
|
3275
|
+
this.main = this.newRootView(newMainEl, flash);
|
|
3276
|
+
this.main.setRedirect(href);
|
|
3277
|
+
this.transitionRemoves();
|
|
3278
|
+
this.main.join((joinCount, onDone) => {
|
|
3279
|
+
if (joinCount === 1 && this.commitPendingLink(linkRef)) {
|
|
3280
|
+
this.requestDOMUpdate(() => {
|
|
3281
|
+
oldMainEl.replaceWith(newMainEl);
|
|
3282
|
+
callback && callback();
|
|
3283
|
+
onDone();
|
|
3284
|
+
});
|
|
3285
|
+
}
|
|
3286
|
+
});
|
|
3287
|
+
}
|
|
3288
|
+
transitionRemoves(elements) {
|
|
3289
|
+
let removeAttr = this.binding("remove");
|
|
3290
|
+
elements = elements || dom_default.all(document, `[${removeAttr}]`);
|
|
3291
|
+
elements.forEach((el) => {
|
|
3292
|
+
if (document.body.contains(el)) {
|
|
3293
|
+
this.execJS(el, el.getAttribute(removeAttr), "remove");
|
|
3294
|
+
}
|
|
3295
|
+
});
|
|
3296
|
+
}
|
|
3297
|
+
isPhxView(el) {
|
|
3298
|
+
return el.getAttribute && el.getAttribute(PHX_SESSION) !== null;
|
|
3299
|
+
}
|
|
3300
|
+
newRootView(el, flash) {
|
|
3301
|
+
let view = new View(el, this, null, flash);
|
|
3302
|
+
this.roots[view.id] = view;
|
|
3303
|
+
return view;
|
|
3304
|
+
}
|
|
3305
|
+
owner(childEl, callback) {
|
|
3306
|
+
let view = maybe(childEl.closest(PHX_VIEW_SELECTOR), (el) => this.getViewByEl(el));
|
|
3307
|
+
if (view) {
|
|
3308
|
+
callback(view);
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
withinOwners(childEl, callback) {
|
|
3312
|
+
this.owner(childEl, (view) => callback(view, childEl));
|
|
3313
|
+
}
|
|
3314
|
+
getViewByEl(el) {
|
|
3315
|
+
let rootId = el.getAttribute(PHX_ROOT_ID);
|
|
3316
|
+
return maybe(this.getRootById(rootId), (root) => root.getDescendentByEl(el));
|
|
3317
|
+
}
|
|
3318
|
+
getRootById(id) {
|
|
3319
|
+
return this.roots[id];
|
|
3320
|
+
}
|
|
3321
|
+
destroyAllViews() {
|
|
3322
|
+
for (let id in this.roots) {
|
|
3323
|
+
this.roots[id].destroy();
|
|
3324
|
+
delete this.roots[id];
|
|
3325
|
+
}
|
|
3326
|
+
}
|
|
3327
|
+
destroyViewByEl(el) {
|
|
3328
|
+
let root = this.getRootById(el.getAttribute(PHX_ROOT_ID));
|
|
3329
|
+
if (root) {
|
|
3330
|
+
root.destroyDescendent(el.id);
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
setActiveElement(target) {
|
|
3334
|
+
if (this.activeElement === target) {
|
|
3335
|
+
return;
|
|
3336
|
+
}
|
|
3337
|
+
this.activeElement = target;
|
|
3338
|
+
let cancel = () => {
|
|
3339
|
+
if (target === this.activeElement) {
|
|
3340
|
+
this.activeElement = null;
|
|
3341
|
+
}
|
|
3342
|
+
target.removeEventListener("mouseup", this);
|
|
3343
|
+
target.removeEventListener("touchend", this);
|
|
3344
|
+
};
|
|
3345
|
+
target.addEventListener("mouseup", cancel);
|
|
3346
|
+
target.addEventListener("touchend", cancel);
|
|
3347
|
+
}
|
|
3348
|
+
getActiveElement() {
|
|
3349
|
+
if (document.activeElement === document.body) {
|
|
3350
|
+
return this.activeElement || document.activeElement;
|
|
3351
|
+
} else {
|
|
3352
|
+
return document.activeElement || document.body;
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
dropActiveElement(view) {
|
|
3356
|
+
if (this.prevActive && view.ownsElement(this.prevActive)) {
|
|
3357
|
+
this.prevActive = null;
|
|
3358
|
+
}
|
|
3359
|
+
}
|
|
3360
|
+
restorePreviouslyActiveFocus() {
|
|
3361
|
+
if (this.prevActive && this.prevActive !== document.body) {
|
|
3362
|
+
this.prevActive.focus();
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
blurActiveElement() {
|
|
3366
|
+
this.prevActive = this.getActiveElement();
|
|
3367
|
+
if (this.prevActive !== document.body) {
|
|
3368
|
+
this.prevActive.blur();
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
bindTopLevelEvents() {
|
|
3372
|
+
if (this.boundTopLevelEvents) {
|
|
3373
|
+
return;
|
|
3374
|
+
}
|
|
3375
|
+
this.boundTopLevelEvents = true;
|
|
3376
|
+
document.body.addEventListener("click", function() {
|
|
3377
|
+
});
|
|
3378
|
+
window.addEventListener("pageshow", (e) => {
|
|
3379
|
+
if (e.persisted) {
|
|
3380
|
+
this.getSocket().disconnect();
|
|
3381
|
+
this.withPageLoading({ to: window.location.href, kind: "redirect" });
|
|
3382
|
+
window.location.reload();
|
|
3383
|
+
}
|
|
3384
|
+
}, true);
|
|
3385
|
+
this.bindNav();
|
|
3386
|
+
this.bindClicks();
|
|
3387
|
+
this.bindForms();
|
|
3388
|
+
this.bind({ keyup: "keyup", keydown: "keydown" }, (e, type, view, targetEl, phxEvent, eventTarget) => {
|
|
3389
|
+
let matchKey = targetEl.getAttribute(this.binding(PHX_KEY));
|
|
3390
|
+
let pressedKey = e.key && e.key.toLowerCase();
|
|
3391
|
+
if (matchKey && matchKey.toLowerCase() !== pressedKey) {
|
|
3392
|
+
return;
|
|
3393
|
+
}
|
|
3394
|
+
let data = { key: e.key, ...this.eventMeta(type, e, targetEl) };
|
|
3395
|
+
js_default.exec(type, phxEvent, view, targetEl, ["push", { data }]);
|
|
3396
|
+
});
|
|
3397
|
+
this.bind({ blur: "focusout", focus: "focusin" }, (e, type, view, targetEl, phxEvent, eventTarget) => {
|
|
3398
|
+
if (!eventTarget) {
|
|
3399
|
+
let data = { key: e.key, ...this.eventMeta(type, e, targetEl) };
|
|
3400
|
+
js_default.exec(type, phxEvent, view, targetEl, ["push", { data }]);
|
|
3401
|
+
}
|
|
3402
|
+
});
|
|
3403
|
+
this.bind({ blur: "blur", focus: "focus" }, (e, type, view, targetEl, targetCtx, phxEvent, phxTarget) => {
|
|
3404
|
+
if (phxTarget === "window") {
|
|
3405
|
+
let data = this.eventMeta(type, e, targetEl);
|
|
3406
|
+
js_default.exec(type, phxEvent, view, targetEl, ["push", { data }]);
|
|
3407
|
+
}
|
|
3408
|
+
});
|
|
3409
|
+
window.addEventListener("dragover", (e) => e.preventDefault());
|
|
3410
|
+
window.addEventListener("drop", (e) => {
|
|
3411
|
+
e.preventDefault();
|
|
3412
|
+
let dropTargetId = maybe(closestPhxBinding(e.target, this.binding(PHX_DROP_TARGET)), (trueTarget) => {
|
|
3413
|
+
return trueTarget.getAttribute(this.binding(PHX_DROP_TARGET));
|
|
3414
|
+
});
|
|
3415
|
+
let dropTarget = dropTargetId && document.getElementById(dropTargetId);
|
|
3416
|
+
let files = Array.from(e.dataTransfer.files || []);
|
|
3417
|
+
if (!dropTarget || dropTarget.disabled || files.length === 0 || !(dropTarget.files instanceof FileList)) {
|
|
3418
|
+
return;
|
|
3419
|
+
}
|
|
3420
|
+
LiveUploader.trackFiles(dropTarget, files);
|
|
3421
|
+
dropTarget.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3422
|
+
});
|
|
3423
|
+
this.on(PHX_TRACK_UPLOADS, (e) => {
|
|
3424
|
+
let uploadTarget = e.target;
|
|
3425
|
+
if (!dom_default.isUploadInput(uploadTarget)) {
|
|
3426
|
+
return;
|
|
3427
|
+
}
|
|
3428
|
+
let files = Array.from(e.detail.files || []).filter((f) => f instanceof File || f instanceof Blob);
|
|
3429
|
+
LiveUploader.trackFiles(uploadTarget, files);
|
|
3430
|
+
uploadTarget.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3431
|
+
});
|
|
3432
|
+
}
|
|
3433
|
+
eventMeta(eventName, e, targetEl) {
|
|
3434
|
+
let callback = this.metadataCallbacks[eventName];
|
|
3435
|
+
return callback ? callback(e, targetEl) : {};
|
|
3436
|
+
}
|
|
3437
|
+
setPendingLink(href) {
|
|
3438
|
+
this.linkRef++;
|
|
3439
|
+
this.pendingLink = href;
|
|
3440
|
+
return this.linkRef;
|
|
3441
|
+
}
|
|
3442
|
+
commitPendingLink(linkRef) {
|
|
3443
|
+
if (this.linkRef !== linkRef) {
|
|
3444
|
+
return false;
|
|
3445
|
+
} else {
|
|
3446
|
+
this.href = this.pendingLink;
|
|
3447
|
+
this.pendingLink = null;
|
|
3448
|
+
return true;
|
|
3449
|
+
}
|
|
3450
|
+
}
|
|
3451
|
+
getHref() {
|
|
3452
|
+
return this.href;
|
|
3453
|
+
}
|
|
3454
|
+
hasPendingLink() {
|
|
3455
|
+
return !!this.pendingLink;
|
|
3456
|
+
}
|
|
3457
|
+
bind(events, callback) {
|
|
3458
|
+
for (let event in events) {
|
|
3459
|
+
let browserEventName = events[event];
|
|
3460
|
+
this.on(browserEventName, (e) => {
|
|
3461
|
+
let binding = this.binding(event);
|
|
3462
|
+
let windowBinding = this.binding(`window-${event}`);
|
|
3463
|
+
let targetPhxEvent = e.target.getAttribute && e.target.getAttribute(binding);
|
|
3464
|
+
if (targetPhxEvent) {
|
|
3465
|
+
this.debounce(e.target, e, () => {
|
|
3466
|
+
this.withinOwners(e.target, (view) => {
|
|
3467
|
+
callback(e, event, view, e.target, targetPhxEvent, null);
|
|
3468
|
+
});
|
|
3469
|
+
});
|
|
3470
|
+
} else {
|
|
3471
|
+
dom_default.all(document, `[${windowBinding}]`, (el) => {
|
|
3472
|
+
let phxEvent = el.getAttribute(windowBinding);
|
|
3473
|
+
this.debounce(el, e, () => {
|
|
3474
|
+
this.withinOwners(el, (view) => {
|
|
3475
|
+
callback(e, event, view, el, phxEvent, "window");
|
|
3476
|
+
});
|
|
3477
|
+
});
|
|
3478
|
+
});
|
|
3479
|
+
}
|
|
3480
|
+
});
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3483
|
+
bindClicks() {
|
|
3484
|
+
this.bindClick("click", "click", false);
|
|
3485
|
+
this.bindClick("mousedown", "capture-click", true);
|
|
3486
|
+
}
|
|
3487
|
+
bindClick(eventName, bindingName, capture) {
|
|
3488
|
+
let click = this.binding(bindingName);
|
|
3489
|
+
window.addEventListener(eventName, (e) => {
|
|
3490
|
+
if (!this.isConnected()) {
|
|
3491
|
+
return;
|
|
3492
|
+
}
|
|
3493
|
+
let target = null;
|
|
3494
|
+
if (capture) {
|
|
3495
|
+
target = e.target.matches(`[${click}]`) ? e.target : e.target.querySelector(`[${click}]`);
|
|
3496
|
+
} else {
|
|
3497
|
+
target = closestPhxBinding(e.target, click);
|
|
3498
|
+
this.dispatchClickAway(e);
|
|
3499
|
+
}
|
|
3500
|
+
let phxEvent = target && target.getAttribute(click);
|
|
3501
|
+
if (!phxEvent) {
|
|
3502
|
+
return;
|
|
3503
|
+
}
|
|
3504
|
+
if (target.getAttribute("href") === "#") {
|
|
3505
|
+
e.preventDefault();
|
|
3506
|
+
}
|
|
3507
|
+
this.debounce(target, e, () => {
|
|
3508
|
+
this.withinOwners(target, (view) => {
|
|
3509
|
+
js_default.exec("click", phxEvent, view, target, ["push", { data: this.eventMeta("click", e, target) }]);
|
|
3510
|
+
});
|
|
3511
|
+
});
|
|
3512
|
+
}, capture);
|
|
3513
|
+
}
|
|
3514
|
+
dispatchClickAway(e) {
|
|
3515
|
+
let binding = this.binding("click-away");
|
|
3516
|
+
dom_default.all(document, `[${binding}]`, (el) => {
|
|
3517
|
+
if (!(el.isSameNode(e.target) || el.contains(e.target))) {
|
|
3518
|
+
this.withinOwners(e.target, (view) => {
|
|
3519
|
+
let phxEvent = el.getAttribute(binding);
|
|
3520
|
+
js_default.exec("click", phxEvent, view, e.target, ["push", { data: this.eventMeta("click", e, e.target) }]);
|
|
3521
|
+
});
|
|
3522
|
+
}
|
|
3523
|
+
});
|
|
3524
|
+
}
|
|
3525
|
+
bindNav() {
|
|
3526
|
+
if (!browser_default.canPushState()) {
|
|
3527
|
+
return;
|
|
3528
|
+
}
|
|
3529
|
+
if (history.scrollRestoration) {
|
|
3530
|
+
history.scrollRestoration = "manual";
|
|
3531
|
+
}
|
|
3532
|
+
let scrollTimer = null;
|
|
3533
|
+
window.addEventListener("scroll", (_e) => {
|
|
3534
|
+
clearTimeout(scrollTimer);
|
|
3535
|
+
scrollTimer = setTimeout(() => {
|
|
3536
|
+
browser_default.updateCurrentState((state) => Object.assign(state, { scroll: window.scrollY }));
|
|
3537
|
+
}, 100);
|
|
3538
|
+
});
|
|
3539
|
+
window.addEventListener("popstate", (event) => {
|
|
3540
|
+
if (!this.registerNewLocation(window.location)) {
|
|
3541
|
+
return;
|
|
3542
|
+
}
|
|
3543
|
+
let { type, id, root, scroll } = event.state || {};
|
|
3544
|
+
let href = window.location.href;
|
|
3545
|
+
this.requestDOMUpdate(() => {
|
|
3546
|
+
if (this.main.isConnected() && (type === "patch" && id === this.main.id)) {
|
|
3547
|
+
this.main.pushLinkPatch(href, null);
|
|
3548
|
+
} else {
|
|
3549
|
+
this.replaceMain(href, null, () => {
|
|
3550
|
+
if (root) {
|
|
3551
|
+
this.replaceRootHistory();
|
|
3552
|
+
}
|
|
3553
|
+
if (typeof scroll === "number") {
|
|
3554
|
+
setTimeout(() => {
|
|
3555
|
+
window.scrollTo(0, scroll);
|
|
3556
|
+
}, 0);
|
|
3557
|
+
}
|
|
3558
|
+
});
|
|
3559
|
+
}
|
|
3560
|
+
});
|
|
3561
|
+
}, false);
|
|
3562
|
+
window.addEventListener("click", (e) => {
|
|
3563
|
+
let target = closestPhxBinding(e.target, PHX_LIVE_LINK);
|
|
3564
|
+
let type = target && target.getAttribute(PHX_LIVE_LINK);
|
|
3565
|
+
let wantsNewTab = e.metaKey || e.ctrlKey || e.button === 1;
|
|
3566
|
+
if (!type || !this.isConnected() || !this.main || wantsNewTab) {
|
|
3567
|
+
return;
|
|
3568
|
+
}
|
|
3569
|
+
let href = target.href;
|
|
3570
|
+
let linkState = target.getAttribute(PHX_LINK_STATE);
|
|
3571
|
+
e.preventDefault();
|
|
3572
|
+
if (this.pendingLink === href) {
|
|
3573
|
+
return;
|
|
3574
|
+
}
|
|
3575
|
+
this.requestDOMUpdate(() => {
|
|
3576
|
+
if (type === "patch") {
|
|
3577
|
+
this.pushHistoryPatch(href, linkState, target);
|
|
3578
|
+
} else if (type === "redirect") {
|
|
3579
|
+
this.historyRedirect(href, linkState);
|
|
3580
|
+
} else {
|
|
3581
|
+
throw new Error(`expected ${PHX_LIVE_LINK} to be "patch" or "redirect", got: ${type}`);
|
|
3582
|
+
}
|
|
3583
|
+
});
|
|
3584
|
+
}, false);
|
|
3585
|
+
}
|
|
3586
|
+
dispatchEvent(event, payload = {}) {
|
|
3587
|
+
dom_default.dispatchEvent(window, `phx:${event}`, payload);
|
|
3588
|
+
}
|
|
3589
|
+
dispatchEvents(events) {
|
|
3590
|
+
events.forEach(([event, payload]) => this.dispatchEvent(event, payload));
|
|
3591
|
+
}
|
|
3592
|
+
withPageLoading(info, callback) {
|
|
3593
|
+
dom_default.dispatchEvent(window, "phx:page-loading-start", info);
|
|
3594
|
+
let done = () => dom_default.dispatchEvent(window, "phx:page-loading-stop", info);
|
|
3595
|
+
return callback ? callback(done) : done;
|
|
3596
|
+
}
|
|
3597
|
+
pushHistoryPatch(href, linkState, targetEl) {
|
|
3598
|
+
this.withPageLoading({ to: href, kind: "patch" }, (done) => {
|
|
3599
|
+
this.main.pushLinkPatch(href, targetEl, (linkRef) => {
|
|
3600
|
+
this.historyPatch(href, linkState, linkRef);
|
|
3601
|
+
done();
|
|
3602
|
+
});
|
|
3603
|
+
});
|
|
3604
|
+
}
|
|
3605
|
+
historyPatch(href, linkState, linkRef = this.setPendingLink(href)) {
|
|
3606
|
+
if (!this.commitPendingLink(linkRef)) {
|
|
3607
|
+
return;
|
|
3608
|
+
}
|
|
3609
|
+
browser_default.pushState(linkState, { type: "patch", id: this.main.id }, href);
|
|
3610
|
+
this.registerNewLocation(window.location);
|
|
3611
|
+
}
|
|
3612
|
+
historyRedirect(href, linkState, flash) {
|
|
3613
|
+
let scroll = window.scrollY;
|
|
3614
|
+
this.withPageLoading({ to: href, kind: "redirect" }, (done) => {
|
|
3615
|
+
this.replaceMain(href, flash, () => {
|
|
3616
|
+
browser_default.pushState(linkState, { type: "redirect", id: this.main.id, scroll }, href);
|
|
3617
|
+
this.registerNewLocation(window.location);
|
|
3618
|
+
done();
|
|
3619
|
+
});
|
|
3620
|
+
});
|
|
3621
|
+
}
|
|
3622
|
+
replaceRootHistory() {
|
|
3623
|
+
browser_default.pushState("replace", { root: true, type: "patch", id: this.main.id });
|
|
3624
|
+
}
|
|
3625
|
+
registerNewLocation(newLocation) {
|
|
3626
|
+
let { pathname, search } = this.currentLocation;
|
|
3627
|
+
if (pathname + search === newLocation.pathname + newLocation.search) {
|
|
3628
|
+
return false;
|
|
3629
|
+
} else {
|
|
3630
|
+
this.currentLocation = clone(newLocation);
|
|
3631
|
+
return true;
|
|
3632
|
+
}
|
|
3633
|
+
}
|
|
3634
|
+
bindForms() {
|
|
3635
|
+
let iterations = 0;
|
|
3636
|
+
this.on("submit", (e) => {
|
|
3637
|
+
let phxEvent = e.target.getAttribute(this.binding("submit"));
|
|
3638
|
+
if (!phxEvent) {
|
|
3639
|
+
return;
|
|
3640
|
+
}
|
|
3641
|
+
e.preventDefault();
|
|
3642
|
+
e.target.disabled = true;
|
|
3643
|
+
this.withinOwners(e.target, (view) => {
|
|
3644
|
+
js_default.exec("submit", phxEvent, view, e.target, ["push", {}]);
|
|
3645
|
+
});
|
|
3646
|
+
}, false);
|
|
3647
|
+
for (let type of ["change", "input"]) {
|
|
3648
|
+
this.on(type, (e) => {
|
|
3649
|
+
let input = e.target;
|
|
3650
|
+
let phxEvent = input.form && input.form.getAttribute(this.binding("change"));
|
|
3651
|
+
if (!phxEvent) {
|
|
3652
|
+
return;
|
|
3653
|
+
}
|
|
3654
|
+
if (input.type === "number" && input.validity && input.validity.badInput) {
|
|
3655
|
+
return;
|
|
3656
|
+
}
|
|
3657
|
+
let currentIterations = iterations;
|
|
3658
|
+
iterations++;
|
|
3659
|
+
let { at, type: lastType } = dom_default.private(input, "prev-iteration") || {};
|
|
3660
|
+
if (at === currentIterations - 1 && type !== lastType) {
|
|
3661
|
+
return;
|
|
3662
|
+
}
|
|
3663
|
+
dom_default.putPrivate(input, "prev-iteration", { at: currentIterations, type });
|
|
3664
|
+
this.debounce(input, e, () => {
|
|
3665
|
+
this.withinOwners(input.form, (view) => {
|
|
3666
|
+
dom_default.putPrivate(input, PHX_HAS_FOCUSED, true);
|
|
3667
|
+
if (!dom_default.isTextualInput(input)) {
|
|
3668
|
+
this.setActiveElement(input);
|
|
3669
|
+
}
|
|
3670
|
+
js_default.exec("change", phxEvent, view, input, ["push", { _target: e.target.name }]);
|
|
3671
|
+
});
|
|
3672
|
+
});
|
|
3673
|
+
}, false);
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
debounce(el, event, callback) {
|
|
3677
|
+
let phxDebounce = this.binding(PHX_DEBOUNCE);
|
|
3678
|
+
let phxThrottle = this.binding(PHX_THROTTLE);
|
|
3679
|
+
let defaultDebounce = this.defaults.debounce.toString();
|
|
3680
|
+
let defaultThrottle = this.defaults.throttle.toString();
|
|
3681
|
+
dom_default.debounce(el, event, phxDebounce, defaultDebounce, phxThrottle, defaultThrottle, callback);
|
|
3682
|
+
}
|
|
3683
|
+
silenceEvents(callback) {
|
|
3684
|
+
this.silenced = true;
|
|
3685
|
+
callback();
|
|
3686
|
+
this.silenced = false;
|
|
3687
|
+
}
|
|
3688
|
+
on(event, callback) {
|
|
3689
|
+
window.addEventListener(event, (e) => {
|
|
3690
|
+
if (!this.silenced) {
|
|
3691
|
+
callback(e);
|
|
3692
|
+
}
|
|
3693
|
+
});
|
|
3694
|
+
}
|
|
3695
|
+
};
|
|
3696
|
+
var TransitionSet = class {
|
|
3697
|
+
constructor() {
|
|
3698
|
+
this.transitions = new Set();
|
|
3699
|
+
this.pendingOps = [];
|
|
3700
|
+
this.reset();
|
|
3701
|
+
}
|
|
3702
|
+
reset() {
|
|
3703
|
+
this.transitions.forEach((timer) => {
|
|
3704
|
+
cancelTimeout(timer);
|
|
3705
|
+
this.transitions.delete(timer);
|
|
3706
|
+
});
|
|
3707
|
+
this.flushPendingOps();
|
|
3708
|
+
}
|
|
3709
|
+
after(callback) {
|
|
3710
|
+
if (this.size() === 0) {
|
|
3711
|
+
callback();
|
|
3712
|
+
} else {
|
|
3713
|
+
this.pushPendingOp(callback);
|
|
3714
|
+
}
|
|
3715
|
+
}
|
|
3716
|
+
addTransition(time, onDone) {
|
|
3717
|
+
let timer = setTimeout(() => {
|
|
3718
|
+
this.transitions.delete(timer);
|
|
3719
|
+
onDone();
|
|
3720
|
+
if (this.size() === 0) {
|
|
3721
|
+
this.flushPendingOps();
|
|
3722
|
+
}
|
|
3723
|
+
}, time);
|
|
3724
|
+
this.transitions.add(timer);
|
|
3725
|
+
}
|
|
3726
|
+
pushPendingOp(op) {
|
|
3727
|
+
this.pendingOps.push(op);
|
|
3728
|
+
}
|
|
3729
|
+
size() {
|
|
3730
|
+
return this.transitions.size;
|
|
3731
|
+
}
|
|
3732
|
+
flushPendingOps() {
|
|
3733
|
+
this.pendingOps.forEach((op) => op());
|
|
3734
|
+
this.pendingOps = [];
|
|
3735
|
+
}
|
|
3736
|
+
};
|
|
3737
|
+
//# sourceMappingURL=phoenix_live_view.cjs.js.map
|