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.
@@ -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