phoenix_live_view 0.20.2 → 0.20.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/js/phoenix_live_view/constants.js +3 -1
- package/assets/js/phoenix_live_view/dom.js +78 -12
- package/assets/js/phoenix_live_view/dom_patch.js +96 -58
- package/assets/js/phoenix_live_view/hooks.js +71 -17
- package/assets/js/phoenix_live_view/js.js +39 -8
- package/assets/js/phoenix_live_view/live_socket.js +22 -12
- package/assets/js/phoenix_live_view/live_uploader.js +8 -1
- package/assets/js/phoenix_live_view/rendered.js +52 -49
- package/assets/js/phoenix_live_view/upload_entry.js +10 -1
- package/assets/js/phoenix_live_view/view.js +52 -21
- package/assets/package.json +11 -9
- package/package.json +9 -2
- package/priv/static/phoenix_live_view.cjs.js +333 -167
- package/priv/static/phoenix_live_view.cjs.js.map +2 -2
- package/priv/static/phoenix_live_view.esm.js +333 -167
- package/priv/static/phoenix_live_view.esm.js.map +2 -2
- package/priv/static/phoenix_live_view.js +333 -167
- package/priv/static/phoenix_live_view.min.js +4 -5
|
@@ -24,7 +24,8 @@ var PHX_EVENT_CLASSES = [
|
|
|
24
24
|
"phx-keydown-loading",
|
|
25
25
|
"phx-keyup-loading",
|
|
26
26
|
"phx-blur-loading",
|
|
27
|
-
"phx-focus-loading"
|
|
27
|
+
"phx-focus-loading",
|
|
28
|
+
"phx-hook-loading"
|
|
28
29
|
];
|
|
29
30
|
var PHX_COMPONENT = "data-phx-component";
|
|
30
31
|
var PHX_LIVE_LINK = "data-phx-link";
|
|
@@ -56,6 +57,7 @@ var PHX_VIEWPORT_TOP = "viewport-top";
|
|
|
56
57
|
var PHX_VIEWPORT_BOTTOM = "viewport-bottom";
|
|
57
58
|
var PHX_TRIGGER_ACTION = "trigger-action";
|
|
58
59
|
var PHX_FEEDBACK_FOR = "feedback-for";
|
|
60
|
+
var PHX_FEEDBACK_GROUP = "feedback-group";
|
|
59
61
|
var PHX_HAS_FOCUSED = "phx-has-focused";
|
|
60
62
|
var FOCUSABLE_INPUTS = ["text", "textarea", "number", "email", "password", "search", "tel", "url", "date", "time", "datetime-local", "color", "range"];
|
|
61
63
|
var CHECKABLE_INPUTS = ["checkbox", "radio"];
|
|
@@ -311,7 +313,9 @@ var DOM = {
|
|
|
311
313
|
return inputEl.hasAttribute("data-phx-auto-upload");
|
|
312
314
|
},
|
|
313
315
|
findUploadInputs(node) {
|
|
314
|
-
|
|
316
|
+
const formId = node.id;
|
|
317
|
+
const inputsOutsideForm = this.all(document, `input[type="file"][${PHX_UPLOAD_REF}][form="${formId}"]`);
|
|
318
|
+
return this.all(node, `input[type="file"][${PHX_UPLOAD_REF}]`).concat(inputsOutsideForm);
|
|
315
319
|
},
|
|
316
320
|
findComponentNodeList(node, cid) {
|
|
317
321
|
return this.filterWithinSameLiveView(this.all(node, `[${PHX_COMPONENT}="${cid}"]`), node);
|
|
@@ -505,7 +509,9 @@ var DOM = {
|
|
|
505
509
|
});
|
|
506
510
|
}
|
|
507
511
|
if (this.once(el, "bind-debounce")) {
|
|
508
|
-
el.addEventListener("blur", () =>
|
|
512
|
+
el.addEventListener("blur", () => {
|
|
513
|
+
callback();
|
|
514
|
+
});
|
|
509
515
|
}
|
|
510
516
|
}
|
|
511
517
|
},
|
|
@@ -538,16 +544,39 @@ var DOM = {
|
|
|
538
544
|
el.setAttribute("data-phx-hook", "Phoenix.InfiniteScroll");
|
|
539
545
|
}
|
|
540
546
|
},
|
|
541
|
-
maybeHideFeedback(container,
|
|
547
|
+
maybeHideFeedback(container, forms, phxFeedbackFor, phxFeedbackGroup) {
|
|
542
548
|
let feedbacks = [];
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
549
|
+
let inputNamesFocused = {};
|
|
550
|
+
let feedbackGroups = {};
|
|
551
|
+
forms.forEach((form) => {
|
|
552
|
+
Array.from(form.elements).forEach((input) => {
|
|
553
|
+
const group = input.getAttribute(phxFeedbackGroup);
|
|
554
|
+
if (group && !(group in feedbackGroups)) {
|
|
555
|
+
feedbackGroups[group] = true;
|
|
548
556
|
}
|
|
549
|
-
|
|
557
|
+
if (!(input.name in inputNamesFocused)) {
|
|
558
|
+
inputNamesFocused[input.name] = false;
|
|
559
|
+
}
|
|
560
|
+
if (this.private(input, PHX_HAS_FOCUSED) || this.private(input, PHX_HAS_SUBMITTED)) {
|
|
561
|
+
inputNamesFocused[input.name] = true;
|
|
562
|
+
if (group) {
|
|
563
|
+
feedbackGroups[group] = false;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
});
|
|
550
567
|
});
|
|
568
|
+
for (const [name, focused] of Object.entries(inputNamesFocused)) {
|
|
569
|
+
if (!focused) {
|
|
570
|
+
feedbacks.push(name);
|
|
571
|
+
if (name.endsWith("[]")) {
|
|
572
|
+
feedbacks.push(name.slice(0, -2));
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
for (const [group, noFeedback] of Object.entries(feedbackGroups)) {
|
|
577
|
+
if (noFeedback)
|
|
578
|
+
feedbacks.push(group);
|
|
579
|
+
}
|
|
551
580
|
if (feedbacks.length > 0) {
|
|
552
581
|
let selector = feedbacks.map((f) => `[${phxFeedbackFor}="${f}"]`).join(", ");
|
|
553
582
|
DOM.all(container, selector, (el) => el.classList.add(PHX_NO_FEEDBACK_CLASS));
|
|
@@ -578,11 +607,19 @@ var DOM = {
|
|
|
578
607
|
isPhxSticky(node) {
|
|
579
608
|
return node.getAttribute && node.getAttribute(PHX_STICKY) !== null;
|
|
580
609
|
},
|
|
610
|
+
isChildOfAny(el, parents) {
|
|
611
|
+
return !!parents.find((parent) => parent.contains(el));
|
|
612
|
+
},
|
|
581
613
|
firstPhxChild(el) {
|
|
582
614
|
return this.isPhxChild(el) ? el : this.all(el, `[${PHX_PARENT_ID}]`)[0];
|
|
583
615
|
},
|
|
584
616
|
dispatchEvent(target, name, opts = {}) {
|
|
585
|
-
let
|
|
617
|
+
let defaultBubble = true;
|
|
618
|
+
let isUploadTarget = target.nodeName === "INPUT" && target.type === "file";
|
|
619
|
+
if (isUploadTarget && name === "click") {
|
|
620
|
+
defaultBubble = false;
|
|
621
|
+
}
|
|
622
|
+
let bubbles = opts.bubbles === void 0 ? defaultBubble : !!opts.bubbles;
|
|
586
623
|
let eventOpts = { bubbles, cancelable: true, detail: opts.detail || {} };
|
|
587
624
|
let event = name === "click" ? new MouseEvent("click", eventOpts) : new CustomEvent(name, eventOpts);
|
|
588
625
|
target.dispatchEvent(event);
|
|
@@ -597,20 +634,27 @@ var DOM = {
|
|
|
597
634
|
}
|
|
598
635
|
},
|
|
599
636
|
mergeAttrs(target, source, opts = {}) {
|
|
600
|
-
let exclude = opts.exclude || [];
|
|
637
|
+
let exclude = new Set(opts.exclude || []);
|
|
601
638
|
let isIgnored = opts.isIgnored;
|
|
602
639
|
let sourceAttrs = source.attributes;
|
|
603
640
|
for (let i = sourceAttrs.length - 1; i >= 0; i--) {
|
|
604
641
|
let name = sourceAttrs[i].name;
|
|
605
|
-
if (exclude.
|
|
606
|
-
|
|
642
|
+
if (!exclude.has(name)) {
|
|
643
|
+
const sourceValue = source.getAttribute(name);
|
|
644
|
+
if (target.getAttribute(name) !== sourceValue && (!isIgnored || isIgnored && name.startsWith("data-"))) {
|
|
645
|
+
target.setAttribute(name, sourceValue);
|
|
646
|
+
}
|
|
647
|
+
} else {
|
|
648
|
+
if (name === "value" && target.value === source.value) {
|
|
649
|
+
target.setAttribute("value", source.getAttribute(name));
|
|
650
|
+
}
|
|
607
651
|
}
|
|
608
652
|
}
|
|
609
653
|
let targetAttrs = target.attributes;
|
|
610
654
|
for (let i = targetAttrs.length - 1; i >= 0; i--) {
|
|
611
655
|
let name = targetAttrs[i].name;
|
|
612
656
|
if (isIgnored) {
|
|
613
|
-
if (name.startsWith("data-") && !source.hasAttribute(name)) {
|
|
657
|
+
if (name.startsWith("data-") && !source.hasAttribute(name) && ![PHX_REF, PHX_REF_SRC].includes(name)) {
|
|
614
658
|
target.removeAttribute(name);
|
|
615
659
|
}
|
|
616
660
|
} else {
|
|
@@ -634,6 +678,9 @@ var DOM = {
|
|
|
634
678
|
return el.setSelectionRange && (el.type === "text" || el.type === "textarea");
|
|
635
679
|
},
|
|
636
680
|
restoreFocus(focused, selectionStart, selectionEnd) {
|
|
681
|
+
if (focused instanceof HTMLSelectElement) {
|
|
682
|
+
focused.focus();
|
|
683
|
+
}
|
|
637
684
|
if (!DOM.isTextualInput(focused)) {
|
|
638
685
|
return;
|
|
639
686
|
}
|
|
@@ -757,15 +804,22 @@ var dom_default = DOM;
|
|
|
757
804
|
var UploadEntry = class {
|
|
758
805
|
static isActive(fileEl, file) {
|
|
759
806
|
let isNew = file._phxRef === void 0;
|
|
807
|
+
let isPreflightInProgress = UploadEntry.isPreflightInProgress(file);
|
|
760
808
|
let activeRefs = fileEl.getAttribute(PHX_ACTIVE_ENTRY_REFS).split(",");
|
|
761
809
|
let isActive = activeRefs.indexOf(LiveUploader.genFileRef(file)) >= 0;
|
|
762
|
-
return file.size > 0 && (isNew || isActive);
|
|
810
|
+
return file.size > 0 && (isNew || isActive || !isPreflightInProgress);
|
|
763
811
|
}
|
|
764
812
|
static isPreflighted(fileEl, file) {
|
|
765
813
|
let preflightedRefs = fileEl.getAttribute(PHX_PREFLIGHTED_REFS).split(",");
|
|
766
814
|
let isPreflighted = preflightedRefs.indexOf(LiveUploader.genFileRef(file)) >= 0;
|
|
767
815
|
return isPreflighted && this.isActive(fileEl, file);
|
|
768
816
|
}
|
|
817
|
+
static isPreflightInProgress(file) {
|
|
818
|
+
return file._preflightInProgress === true;
|
|
819
|
+
}
|
|
820
|
+
static markPreflightInProgress(file) {
|
|
821
|
+
file._preflightInProgress = true;
|
|
822
|
+
}
|
|
769
823
|
constructor(fileEl, file, view) {
|
|
770
824
|
this.ref = LiveUploader.genFileRef(file);
|
|
771
825
|
this.fileEl = fileEl;
|
|
@@ -932,12 +986,16 @@ var LiveUploader = class {
|
|
|
932
986
|
return Array.from(fileInputs).filter((input) => this.filesAwaitingPreflight(input).length > 0);
|
|
933
987
|
}
|
|
934
988
|
static filesAwaitingPreflight(input) {
|
|
935
|
-
return this.activeFiles(input).filter((f) => !UploadEntry.isPreflighted(input, f));
|
|
989
|
+
return this.activeFiles(input).filter((f) => !UploadEntry.isPreflighted(input, f) && !UploadEntry.isPreflightInProgress(f));
|
|
990
|
+
}
|
|
991
|
+
static markPreflightInProgress(entries) {
|
|
992
|
+
entries.forEach((entry) => UploadEntry.markPreflightInProgress(entry.file));
|
|
936
993
|
}
|
|
937
994
|
constructor(inputEl, view, onComplete) {
|
|
938
995
|
this.view = view;
|
|
939
996
|
this.onComplete = onComplete;
|
|
940
997
|
this._entries = Array.from(LiveUploader.filesAwaitingPreflight(inputEl) || []).map((file) => new UploadEntry(inputEl, file, view));
|
|
998
|
+
LiveUploader.markPreflightInProgress(this._entries);
|
|
941
999
|
this.numEntriesInProgress = this._entries.length;
|
|
942
1000
|
}
|
|
943
1001
|
entries() {
|
|
@@ -1078,23 +1136,50 @@ var Hooks = {
|
|
|
1078
1136
|
}
|
|
1079
1137
|
}
|
|
1080
1138
|
};
|
|
1081
|
-
var
|
|
1082
|
-
|
|
1083
|
-
|
|
1139
|
+
var findScrollContainer = (el) => {
|
|
1140
|
+
if (["scroll", "auto"].indexOf(getComputedStyle(el).overflowY) >= 0)
|
|
1141
|
+
return el;
|
|
1142
|
+
if (document.documentElement === el)
|
|
1143
|
+
return null;
|
|
1144
|
+
return findScrollContainer(el.parentElement);
|
|
1145
|
+
};
|
|
1146
|
+
var scrollTop = (scrollContainer) => {
|
|
1147
|
+
if (scrollContainer) {
|
|
1148
|
+
return scrollContainer.scrollTop;
|
|
1149
|
+
} else {
|
|
1150
|
+
return document.documentElement.scrollTop || document.body.scrollTop;
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
1153
|
+
var bottom = (scrollContainer) => {
|
|
1154
|
+
if (scrollContainer) {
|
|
1155
|
+
return scrollContainer.getBoundingClientRect().bottom;
|
|
1156
|
+
} else {
|
|
1157
|
+
return window.innerHeight || document.documentElement.clientHeight;
|
|
1158
|
+
}
|
|
1159
|
+
};
|
|
1160
|
+
var top = (scrollContainer) => {
|
|
1161
|
+
if (scrollContainer) {
|
|
1162
|
+
return scrollContainer.getBoundingClientRect().top;
|
|
1163
|
+
} else {
|
|
1164
|
+
return 0;
|
|
1165
|
+
}
|
|
1166
|
+
};
|
|
1167
|
+
var isAtViewportTop = (el, scrollContainer) => {
|
|
1084
1168
|
let rect = el.getBoundingClientRect();
|
|
1085
|
-
return rect.top >=
|
|
1169
|
+
return rect.top >= top(scrollContainer) && rect.left >= 0 && rect.top <= bottom(scrollContainer);
|
|
1086
1170
|
};
|
|
1087
|
-
var isAtViewportBottom = (el) => {
|
|
1171
|
+
var isAtViewportBottom = (el, scrollContainer) => {
|
|
1088
1172
|
let rect = el.getBoundingClientRect();
|
|
1089
|
-
return rect.right >=
|
|
1173
|
+
return rect.right >= top(scrollContainer) && rect.left >= 0 && rect.bottom <= bottom(scrollContainer);
|
|
1090
1174
|
};
|
|
1091
|
-
var isWithinViewport = (el) => {
|
|
1175
|
+
var isWithinViewport = (el, scrollContainer) => {
|
|
1092
1176
|
let rect = el.getBoundingClientRect();
|
|
1093
|
-
return rect.top >=
|
|
1177
|
+
return rect.top >= top(scrollContainer) && rect.left >= 0 && rect.top <= bottom(scrollContainer);
|
|
1094
1178
|
};
|
|
1095
1179
|
Hooks.InfiniteScroll = {
|
|
1096
1180
|
mounted() {
|
|
1097
|
-
|
|
1181
|
+
this.scrollContainer = findScrollContainer(this.el);
|
|
1182
|
+
let scrollBefore = scrollTop(this.scrollContainer);
|
|
1098
1183
|
let topOverran = false;
|
|
1099
1184
|
let throttleInterval = 500;
|
|
1100
1185
|
let pendingOp = null;
|
|
@@ -1108,22 +1193,26 @@ Hooks.InfiniteScroll = {
|
|
|
1108
1193
|
pendingOp = () => firstChild.scrollIntoView({ block: "start" });
|
|
1109
1194
|
this.liveSocket.execJSHookPush(this.el, topEvent, { id: firstChild.id }, () => {
|
|
1110
1195
|
pendingOp = null;
|
|
1111
|
-
|
|
1112
|
-
firstChild.
|
|
1113
|
-
|
|
1196
|
+
window.requestAnimationFrame(() => {
|
|
1197
|
+
if (!isWithinViewport(firstChild, this.scrollContainer)) {
|
|
1198
|
+
firstChild.scrollIntoView({ block: "start" });
|
|
1199
|
+
}
|
|
1200
|
+
});
|
|
1114
1201
|
});
|
|
1115
1202
|
});
|
|
1116
1203
|
let onLastChildAtBottom = this.throttle(throttleInterval, (bottomEvent, lastChild) => {
|
|
1117
1204
|
pendingOp = () => lastChild.scrollIntoView({ block: "end" });
|
|
1118
1205
|
this.liveSocket.execJSHookPush(this.el, bottomEvent, { id: lastChild.id }, () => {
|
|
1119
1206
|
pendingOp = null;
|
|
1120
|
-
|
|
1121
|
-
lastChild.
|
|
1122
|
-
|
|
1207
|
+
window.requestAnimationFrame(() => {
|
|
1208
|
+
if (!isWithinViewport(lastChild, this.scrollContainer)) {
|
|
1209
|
+
lastChild.scrollIntoView({ block: "end" });
|
|
1210
|
+
}
|
|
1211
|
+
});
|
|
1123
1212
|
});
|
|
1124
1213
|
});
|
|
1125
|
-
this.onScroll = (
|
|
1126
|
-
let scrollNow = scrollTop();
|
|
1214
|
+
this.onScroll = (_e) => {
|
|
1215
|
+
let scrollNow = scrollTop(this.scrollContainer);
|
|
1127
1216
|
if (pendingOp) {
|
|
1128
1217
|
scrollBefore = scrollNow;
|
|
1129
1218
|
return pendingOp();
|
|
@@ -1141,17 +1230,25 @@ Hooks.InfiniteScroll = {
|
|
|
1141
1230
|
} else if (isScrollingDown && topOverran && rect.top <= 0) {
|
|
1142
1231
|
topOverran = false;
|
|
1143
1232
|
}
|
|
1144
|
-
if (topEvent && isScrollingUp && isAtViewportTop(firstChild)) {
|
|
1233
|
+
if (topEvent && isScrollingUp && isAtViewportTop(firstChild, this.scrollContainer)) {
|
|
1145
1234
|
onFirstChildAtTop(topEvent, firstChild);
|
|
1146
|
-
} else if (bottomEvent && isScrollingDown && isAtViewportBottom(lastChild)) {
|
|
1235
|
+
} else if (bottomEvent && isScrollingDown && isAtViewportBottom(lastChild, this.scrollContainer)) {
|
|
1147
1236
|
onLastChildAtBottom(bottomEvent, lastChild);
|
|
1148
1237
|
}
|
|
1149
1238
|
scrollBefore = scrollNow;
|
|
1150
1239
|
};
|
|
1151
|
-
|
|
1240
|
+
if (this.scrollContainer) {
|
|
1241
|
+
this.scrollContainer.addEventListener("scroll", this.onScroll);
|
|
1242
|
+
} else {
|
|
1243
|
+
window.addEventListener("scroll", this.onScroll);
|
|
1244
|
+
}
|
|
1152
1245
|
},
|
|
1153
1246
|
destroyed() {
|
|
1154
|
-
|
|
1247
|
+
if (this.scrollContainer) {
|
|
1248
|
+
this.scrollContainer.removeEventListener("scroll", this.onScroll);
|
|
1249
|
+
} else {
|
|
1250
|
+
window.removeEventListener("scroll", this.onScroll);
|
|
1251
|
+
}
|
|
1155
1252
|
},
|
|
1156
1253
|
throttle(interval, callback) {
|
|
1157
1254
|
let lastCallAt = 0;
|
|
@@ -1598,6 +1695,7 @@ function morphdomFactory(morphAttrs2) {
|
|
|
1598
1695
|
removeNode(curFromNodeChild, fromEl, true);
|
|
1599
1696
|
}
|
|
1600
1697
|
curFromNodeChild = matchingFromEl;
|
|
1698
|
+
curFromNodeKey = getNodeKey(curFromNodeChild);
|
|
1601
1699
|
}
|
|
1602
1700
|
} else {
|
|
1603
1701
|
isCompatible = false;
|
|
@@ -1730,6 +1828,7 @@ var DOMPatch = class {
|
|
|
1730
1828
|
this.html = html;
|
|
1731
1829
|
this.streams = streams;
|
|
1732
1830
|
this.streamInserts = {};
|
|
1831
|
+
this.streamComponentRestore = {};
|
|
1733
1832
|
this.targetCID = targetCID;
|
|
1734
1833
|
this.cidPatch = isCid(this.targetCID);
|
|
1735
1834
|
this.pendingRemoves = [];
|
|
@@ -1759,7 +1858,6 @@ var DOMPatch = class {
|
|
|
1759
1858
|
}
|
|
1760
1859
|
markPrunableContentForRemoval() {
|
|
1761
1860
|
let phxUpdate = this.liveSocket.binding(PHX_UPDATE);
|
|
1762
|
-
dom_default.all(this.container, `[${phxUpdate}=${PHX_STREAM}]`, (el) => el.innerHTML = "");
|
|
1763
1861
|
dom_default.all(this.container, `[${phxUpdate}=append] > *, [${phxUpdate}=prepend] > *`, (el) => {
|
|
1764
1862
|
el.setAttribute(PHX_PRUNE, "");
|
|
1765
1863
|
});
|
|
@@ -1774,12 +1872,13 @@ var DOMPatch = class {
|
|
|
1774
1872
|
let { selectionStart, selectionEnd } = focused && dom_default.hasSelectionRange(focused) ? focused : {};
|
|
1775
1873
|
let phxUpdate = liveSocket.binding(PHX_UPDATE);
|
|
1776
1874
|
let phxFeedbackFor = liveSocket.binding(PHX_FEEDBACK_FOR);
|
|
1875
|
+
let phxFeedbackGroup = liveSocket.binding(PHX_FEEDBACK_GROUP);
|
|
1777
1876
|
let disableWith = liveSocket.binding(PHX_DISABLE_WITH);
|
|
1778
1877
|
let phxViewportTop = liveSocket.binding(PHX_VIEWPORT_TOP);
|
|
1779
1878
|
let phxViewportBottom = liveSocket.binding(PHX_VIEWPORT_BOTTOM);
|
|
1780
1879
|
let phxTriggerExternal = liveSocket.binding(PHX_TRIGGER_ACTION);
|
|
1781
1880
|
let added = [];
|
|
1782
|
-
let
|
|
1881
|
+
let trackedForms = new Set();
|
|
1783
1882
|
let updates = [];
|
|
1784
1883
|
let appendPrependUpdates = [];
|
|
1785
1884
|
let externalFormTriggered = null;
|
|
@@ -1787,16 +1886,12 @@ var DOMPatch = class {
|
|
|
1787
1886
|
this.trackBefore("updated", container, container);
|
|
1788
1887
|
liveSocket.time("morphdom", () => {
|
|
1789
1888
|
this.streams.forEach(([ref, inserts, deleteIds, reset]) => {
|
|
1790
|
-
|
|
1791
|
-
this.streamInserts[key] = { ref, streamAt, limit,
|
|
1889
|
+
inserts.forEach(([key, streamAt, limit]) => {
|
|
1890
|
+
this.streamInserts[key] = { ref, streamAt, limit, reset };
|
|
1792
1891
|
});
|
|
1793
1892
|
if (reset !== void 0) {
|
|
1794
1893
|
dom_default.all(container, `[${PHX_STREAM_REF}="${ref}"]`, (child) => {
|
|
1795
|
-
|
|
1796
|
-
this.streamInserts[child.id].resetKept = true;
|
|
1797
|
-
} else {
|
|
1798
|
-
this.removeStreamChildElement(child);
|
|
1799
|
-
}
|
|
1894
|
+
this.removeStreamChildElement(child);
|
|
1800
1895
|
});
|
|
1801
1896
|
}
|
|
1802
1897
|
deleteIds.forEach((id) => {
|
|
@@ -1806,6 +1901,17 @@ var DOMPatch = class {
|
|
|
1806
1901
|
}
|
|
1807
1902
|
});
|
|
1808
1903
|
});
|
|
1904
|
+
if (isJoinPatch) {
|
|
1905
|
+
dom_default.all(this.container, `[${phxUpdate}=${PHX_STREAM}]`, (el) => {
|
|
1906
|
+
this.liveSocket.owner(el, (view2) => {
|
|
1907
|
+
if (view2 === this.view) {
|
|
1908
|
+
Array.from(el.children).forEach((child) => {
|
|
1909
|
+
this.removeStreamChildElement(child);
|
|
1910
|
+
});
|
|
1911
|
+
}
|
|
1912
|
+
});
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1809
1915
|
morphdom_esm_default(targetContainer, html, {
|
|
1810
1916
|
childrenOnly: targetContainer.getAttribute(PHX_COMPONENT) === null,
|
|
1811
1917
|
getNodeKey: (node) => {
|
|
@@ -1821,11 +1927,17 @@ var DOMPatch = class {
|
|
|
1821
1927
|
return from.getAttribute(phxUpdate) === PHX_STREAM;
|
|
1822
1928
|
},
|
|
1823
1929
|
addChild: (parent, child) => {
|
|
1824
|
-
let { ref, streamAt
|
|
1930
|
+
let { ref, streamAt } = this.getStreamInsert(child);
|
|
1825
1931
|
if (ref === void 0) {
|
|
1826
1932
|
return parent.appendChild(child);
|
|
1827
1933
|
}
|
|
1828
|
-
|
|
1934
|
+
this.setStreamRef(child, ref);
|
|
1935
|
+
child.querySelectorAll(`[${PHX_MAGIC_ID}][${PHX_SKIP}]`).forEach((el) => {
|
|
1936
|
+
const component = this.streamComponentRestore[el.getAttribute(PHX_MAGIC_ID)];
|
|
1937
|
+
if (component) {
|
|
1938
|
+
el.replaceWith(component);
|
|
1939
|
+
}
|
|
1940
|
+
});
|
|
1829
1941
|
if (streamAt === 0) {
|
|
1830
1942
|
parent.insertAdjacentElement("afterbegin", child);
|
|
1831
1943
|
} else if (streamAt === -1) {
|
|
@@ -1834,18 +1946,6 @@ var DOMPatch = class {
|
|
|
1834
1946
|
let sibling = Array.from(parent.children)[streamAt];
|
|
1835
1947
|
parent.insertBefore(child, sibling);
|
|
1836
1948
|
}
|
|
1837
|
-
let children = limit !== null && Array.from(parent.children);
|
|
1838
|
-
let childrenToRemove = [];
|
|
1839
|
-
if (limit && limit < 0 && children.length > limit * -1) {
|
|
1840
|
-
childrenToRemove = children.slice(0, children.length + limit);
|
|
1841
|
-
} else if (limit && limit >= 0 && children.length > limit) {
|
|
1842
|
-
childrenToRemove = children.slice(limit);
|
|
1843
|
-
}
|
|
1844
|
-
childrenToRemove.forEach((removeChild) => {
|
|
1845
|
-
if (!this.streamInserts[removeChild.id]) {
|
|
1846
|
-
this.removeStreamChildElement(removeChild);
|
|
1847
|
-
}
|
|
1848
|
-
});
|
|
1849
1949
|
},
|
|
1850
1950
|
onBeforeNodeAdded: (el) => {
|
|
1851
1951
|
dom_default.maybeAddPrivateHooks(el, phxViewportTop, phxViewportBottom);
|
|
@@ -1854,7 +1954,7 @@ var DOMPatch = class {
|
|
|
1854
1954
|
},
|
|
1855
1955
|
onNodeAdded: (el) => {
|
|
1856
1956
|
if (el.getAttribute) {
|
|
1857
|
-
this.maybeReOrderStream(el);
|
|
1957
|
+
this.maybeReOrderStream(el, true);
|
|
1858
1958
|
}
|
|
1859
1959
|
if (el instanceof HTMLImageElement && el.srcset) {
|
|
1860
1960
|
el.srcset = el.srcset;
|
|
@@ -1865,32 +1965,13 @@ var DOMPatch = class {
|
|
|
1865
1965
|
externalFormTriggered = el;
|
|
1866
1966
|
}
|
|
1867
1967
|
if (el.getAttribute && el.getAttribute("name") && dom_default.isFormInput(el)) {
|
|
1868
|
-
|
|
1968
|
+
trackedForms.add(el.form);
|
|
1869
1969
|
}
|
|
1870
1970
|
if (dom_default.isPhxChild(el) && view.ownsElement(el) || dom_default.isPhxSticky(el) && view.ownsElement(el.parentNode)) {
|
|
1871
1971
|
this.trackAfter("phxChildAdded", el);
|
|
1872
1972
|
}
|
|
1873
1973
|
added.push(el);
|
|
1874
1974
|
},
|
|
1875
|
-
onBeforeElChildrenUpdated: (fromEl, toEl) => {
|
|
1876
|
-
if (fromEl.getAttribute(phxUpdate) === PHX_STREAM) {
|
|
1877
|
-
let toIds = Array.from(toEl.children).map((child) => child.id);
|
|
1878
|
-
Array.from(fromEl.children).filter((child) => {
|
|
1879
|
-
let { resetKept } = this.getStreamInsert(child);
|
|
1880
|
-
return resetKept;
|
|
1881
|
-
}).sort((a, b) => {
|
|
1882
|
-
let aIdx = toIds.indexOf(a.id);
|
|
1883
|
-
let bIdx = toIds.indexOf(b.id);
|
|
1884
|
-
if (aIdx === bIdx) {
|
|
1885
|
-
return 0;
|
|
1886
|
-
} else if (aIdx < bIdx) {
|
|
1887
|
-
return -1;
|
|
1888
|
-
} else {
|
|
1889
|
-
return 1;
|
|
1890
|
-
}
|
|
1891
|
-
}).forEach((child) => fromEl.appendChild(child));
|
|
1892
|
-
}
|
|
1893
|
-
},
|
|
1894
1975
|
onNodeDiscarded: (el) => this.onNodeDiscarded(el),
|
|
1895
1976
|
onBeforeNodeDiscarded: (el) => {
|
|
1896
1977
|
if (el.getAttribute && el.getAttribute(PHX_PRUNE) !== null) {
|
|
@@ -1912,12 +1993,13 @@ var DOMPatch = class {
|
|
|
1912
1993
|
externalFormTriggered = el;
|
|
1913
1994
|
}
|
|
1914
1995
|
updates.push(el);
|
|
1915
|
-
this.maybeReOrderStream(el);
|
|
1996
|
+
this.maybeReOrderStream(el, false);
|
|
1916
1997
|
},
|
|
1917
1998
|
onBeforeElUpdated: (fromEl, toEl) => {
|
|
1918
1999
|
dom_default.maybeAddPrivateHooks(toEl, phxViewportTop, phxViewportBottom);
|
|
1919
2000
|
dom_default.cleanChildNodes(toEl, phxUpdate);
|
|
1920
2001
|
if (this.skipCIDSibling(toEl)) {
|
|
2002
|
+
this.maybeReOrderStream(fromEl);
|
|
1921
2003
|
return false;
|
|
1922
2004
|
}
|
|
1923
2005
|
if (dom_default.isPhxSticky(fromEl)) {
|
|
@@ -1953,22 +2035,26 @@ var DOMPatch = class {
|
|
|
1953
2035
|
}
|
|
1954
2036
|
dom_default.copyPrivates(toEl, fromEl);
|
|
1955
2037
|
let isFocusedFormEl = focused && fromEl.isSameNode(focused) && dom_default.isFormInput(fromEl);
|
|
1956
|
-
|
|
2038
|
+
let focusedSelectChanged = isFocusedFormEl && this.isChangedSelect(fromEl, toEl);
|
|
2039
|
+
if (isFocusedFormEl && fromEl.type !== "hidden" && !focusedSelectChanged) {
|
|
1957
2040
|
this.trackBefore("updated", fromEl, toEl);
|
|
1958
2041
|
dom_default.mergeFocusedInput(fromEl, toEl);
|
|
1959
2042
|
dom_default.syncAttrsToProps(fromEl);
|
|
1960
2043
|
updates.push(fromEl);
|
|
1961
2044
|
dom_default.applyStickyOperations(fromEl);
|
|
1962
|
-
|
|
2045
|
+
trackedForms.add(fromEl.form);
|
|
1963
2046
|
return false;
|
|
1964
2047
|
} else {
|
|
2048
|
+
if (focusedSelectChanged) {
|
|
2049
|
+
fromEl.blur();
|
|
2050
|
+
}
|
|
1965
2051
|
if (dom_default.isPhxUpdate(toEl, phxUpdate, ["append", "prepend"])) {
|
|
1966
2052
|
appendPrependUpdates.push(new DOMPostMorphRestorer(fromEl, toEl, toEl.getAttribute(phxUpdate)));
|
|
1967
2053
|
}
|
|
1968
2054
|
dom_default.syncAttrsToProps(toEl);
|
|
1969
2055
|
dom_default.applyStickyOperations(toEl);
|
|
1970
2056
|
if (toEl.getAttribute("name") && dom_default.isFormInput(toEl)) {
|
|
1971
|
-
|
|
2057
|
+
trackedForms.add(toEl.form);
|
|
1972
2058
|
}
|
|
1973
2059
|
this.trackBefore("updated", fromEl, toEl);
|
|
1974
2060
|
return true;
|
|
@@ -1984,7 +2070,7 @@ var DOMPatch = class {
|
|
|
1984
2070
|
appendPrependUpdates.forEach((update) => update.perform());
|
|
1985
2071
|
});
|
|
1986
2072
|
}
|
|
1987
|
-
dom_default.maybeHideFeedback(targetContainer,
|
|
2073
|
+
dom_default.maybeHideFeedback(targetContainer, trackedForms, phxFeedbackFor, phxFeedbackGroup);
|
|
1988
2074
|
liveSocket.silenceEvents(() => dom_default.restoreFocus(focused, selectionStart, selectionEnd));
|
|
1989
2075
|
dom_default.dispatchEvent(document, "phx:update");
|
|
1990
2076
|
added.forEach((el) => this.trackAfter("added", el));
|
|
@@ -2012,6 +2098,11 @@ var DOMPatch = class {
|
|
|
2012
2098
|
}
|
|
2013
2099
|
removeStreamChildElement(child) {
|
|
2014
2100
|
if (!this.maybePendingRemove(child)) {
|
|
2101
|
+
if (this.streamInserts[child.id]) {
|
|
2102
|
+
child.querySelectorAll(`[${PHX_MAGIC_ID}]`).forEach((el) => {
|
|
2103
|
+
this.streamComponentRestore[el.getAttribute(PHX_MAGIC_ID)] = el;
|
|
2104
|
+
});
|
|
2105
|
+
}
|
|
2015
2106
|
child.remove();
|
|
2016
2107
|
this.onNodeDiscarded(child);
|
|
2017
2108
|
}
|
|
@@ -2020,12 +2111,18 @@ var DOMPatch = class {
|
|
|
2020
2111
|
let insert = el.id ? this.streamInserts[el.id] : {};
|
|
2021
2112
|
return insert || {};
|
|
2022
2113
|
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2114
|
+
setStreamRef(el, ref) {
|
|
2115
|
+
dom_default.putSticky(el, PHX_STREAM_REF, (el2) => el2.setAttribute(PHX_STREAM_REF, ref));
|
|
2116
|
+
}
|
|
2117
|
+
maybeReOrderStream(el, isNew) {
|
|
2118
|
+
let { ref, streamAt, reset } = this.getStreamInsert(el);
|
|
2025
2119
|
if (streamAt === void 0) {
|
|
2026
2120
|
return;
|
|
2027
2121
|
}
|
|
2028
|
-
|
|
2122
|
+
this.setStreamRef(el, ref);
|
|
2123
|
+
if (!reset && !isNew) {
|
|
2124
|
+
return;
|
|
2125
|
+
}
|
|
2029
2126
|
if (streamAt === 0) {
|
|
2030
2127
|
el.parentElement.insertBefore(el, el.parentElement.firstElementChild);
|
|
2031
2128
|
} else if (streamAt > 0) {
|
|
@@ -2042,6 +2139,16 @@ var DOMPatch = class {
|
|
|
2042
2139
|
}
|
|
2043
2140
|
}
|
|
2044
2141
|
}
|
|
2142
|
+
this.maybeLimitStream(el);
|
|
2143
|
+
}
|
|
2144
|
+
maybeLimitStream(el) {
|
|
2145
|
+
let { limit } = this.getStreamInsert(el);
|
|
2146
|
+
let children = limit !== null && Array.from(el.parentElement.children);
|
|
2147
|
+
if (limit && limit < 0 && children.length > limit * -1) {
|
|
2148
|
+
children.slice(0, children.length + limit).forEach((child) => this.removeStreamChildElement(child));
|
|
2149
|
+
} else if (limit && limit >= 0 && children.length > limit) {
|
|
2150
|
+
children.slice(limit).forEach((child) => this.removeStreamChildElement(child));
|
|
2151
|
+
}
|
|
2045
2152
|
}
|
|
2046
2153
|
transitionPendingRemoves() {
|
|
2047
2154
|
let { pendingRemoves, liveSocket } = this;
|
|
@@ -2059,6 +2166,20 @@ var DOMPatch = class {
|
|
|
2059
2166
|
});
|
|
2060
2167
|
}
|
|
2061
2168
|
}
|
|
2169
|
+
isChangedSelect(fromEl, toEl) {
|
|
2170
|
+
if (!(fromEl instanceof HTMLSelectElement) || fromEl.multiple) {
|
|
2171
|
+
return false;
|
|
2172
|
+
}
|
|
2173
|
+
if (fromEl.options.length !== toEl.options.length) {
|
|
2174
|
+
return true;
|
|
2175
|
+
}
|
|
2176
|
+
let fromSelected = fromEl.selectedOptions[0];
|
|
2177
|
+
let toSelected = toEl.selectedOptions[0];
|
|
2178
|
+
if (fromSelected && fromSelected.hasAttribute("selected")) {
|
|
2179
|
+
toSelected.setAttribute("selected", fromSelected.getAttribute("selected"));
|
|
2180
|
+
}
|
|
2181
|
+
return !fromEl.isEqualNode(toEl);
|
|
2182
|
+
}
|
|
2062
2183
|
isCIDPatch() {
|
|
2063
2184
|
return this.cidPatch;
|
|
2064
2185
|
}
|
|
@@ -2100,66 +2221,42 @@ var VOID_TAGS = new Set([
|
|
|
2100
2221
|
"track",
|
|
2101
2222
|
"wbr"
|
|
2102
2223
|
]);
|
|
2103
|
-
var endingTagNameChars = new Set([">", "/", " ", "\n", " ", "\r"]);
|
|
2104
2224
|
var quoteChars = new Set(["'", '"']);
|
|
2105
2225
|
var modifyRoot = (html, attrs, clearInnerHTML) => {
|
|
2106
2226
|
let i = 0;
|
|
2107
2227
|
let insideComment = false;
|
|
2108
2228
|
let beforeTag, afterTag, tag, tagNameEndsAt, id, newHTML;
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
let iAtOpen = i;
|
|
2229
|
+
let lookahead = html.match(/^(\s*(?:<!--.*?-->\s*)*)<([^\s\/>]+)/);
|
|
2230
|
+
if (lookahead === null) {
|
|
2231
|
+
throw new Error(`malformed html ${html}`);
|
|
2232
|
+
}
|
|
2233
|
+
i = lookahead[0].length;
|
|
2234
|
+
beforeTag = lookahead[1];
|
|
2235
|
+
tag = lookahead[2];
|
|
2236
|
+
tagNameEndsAt = i;
|
|
2237
|
+
for (i; i < html.length; i++) {
|
|
2238
|
+
if (html.charAt(i) === ">") {
|
|
2239
|
+
break;
|
|
2240
|
+
}
|
|
2241
|
+
if (html.charAt(i) === "=") {
|
|
2242
|
+
let isId = html.slice(i - 3, i) === " id";
|
|
2124
2243
|
i++;
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2244
|
+
let char = html.charAt(i);
|
|
2245
|
+
if (quoteChars.has(char)) {
|
|
2246
|
+
let attrStartsAt = i;
|
|
2247
|
+
i++;
|
|
2248
|
+
for (i; i < html.length; i++) {
|
|
2249
|
+
if (html.charAt(i) === char) {
|
|
2250
|
+
break;
|
|
2251
|
+
}
|
|
2128
2252
|
}
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
tag = html.slice(iAtOpen + 1, tagNameEndsAt);
|
|
2132
|
-
for (i; i < html.length; i++) {
|
|
2133
|
-
if (html.charAt(i) === ">") {
|
|
2253
|
+
if (isId) {
|
|
2254
|
+
id = html.slice(attrStartsAt + 1, i);
|
|
2134
2255
|
break;
|
|
2135
2256
|
}
|
|
2136
|
-
if (html.charAt(i) === "=") {
|
|
2137
|
-
let isId = html.slice(i - 3, i) === " id";
|
|
2138
|
-
i++;
|
|
2139
|
-
let char2 = html.charAt(i);
|
|
2140
|
-
if (quoteChars.has(char2)) {
|
|
2141
|
-
let attrStartsAt = i;
|
|
2142
|
-
i++;
|
|
2143
|
-
for (i; i < html.length; i++) {
|
|
2144
|
-
if (html.charAt(i) === char2) {
|
|
2145
|
-
break;
|
|
2146
|
-
}
|
|
2147
|
-
}
|
|
2148
|
-
if (isId) {
|
|
2149
|
-
id = html.slice(attrStartsAt + 1, i);
|
|
2150
|
-
break;
|
|
2151
|
-
}
|
|
2152
|
-
}
|
|
2153
|
-
}
|
|
2154
2257
|
}
|
|
2155
|
-
break;
|
|
2156
|
-
} else {
|
|
2157
|
-
i++;
|
|
2158
2258
|
}
|
|
2159
2259
|
}
|
|
2160
|
-
if (!tag) {
|
|
2161
|
-
throw new Error(`malformed html ${html}`);
|
|
2162
|
-
}
|
|
2163
2260
|
let closeAt = html.length - 1;
|
|
2164
2261
|
insideComment = false;
|
|
2165
2262
|
while (closeAt >= beforeTag.length + tag.length) {
|
|
@@ -2234,6 +2331,11 @@ var Rendered = class {
|
|
|
2234
2331
|
getComponent(diff, cid) {
|
|
2235
2332
|
return diff[COMPONENTS][cid];
|
|
2236
2333
|
}
|
|
2334
|
+
resetRender(cid) {
|
|
2335
|
+
if (this.rendered[COMPONENTS][cid]) {
|
|
2336
|
+
this.rendered[COMPONENTS][cid].reset = true;
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2237
2339
|
mergeDiff(diff) {
|
|
2238
2340
|
let newc = diff[COMPONENTS];
|
|
2239
2341
|
let cache = {};
|
|
@@ -2361,8 +2463,8 @@ var Rendered = class {
|
|
|
2361
2463
|
if (isRoot) {
|
|
2362
2464
|
let skip = false;
|
|
2363
2465
|
let attrs;
|
|
2364
|
-
if (changeTracking ||
|
|
2365
|
-
skip = !rendered.newRender;
|
|
2466
|
+
if (changeTracking || rendered.magicId) {
|
|
2467
|
+
skip = changeTracking && !rendered.newRender;
|
|
2366
2468
|
attrs = { [PHX_MAGIC_ID]: rendered.magicId, ...rootAttrs };
|
|
2367
2469
|
} else {
|
|
2368
2470
|
attrs = rootAttrs;
|
|
@@ -2412,8 +2514,9 @@ var Rendered = class {
|
|
|
2412
2514
|
let skip = onlyCids && !onlyCids.has(cid);
|
|
2413
2515
|
component.newRender = !skip;
|
|
2414
2516
|
component.magicId = `${this.parentViewId()}-c-${cid}`;
|
|
2415
|
-
let changeTracking =
|
|
2517
|
+
let changeTracking = !component.reset;
|
|
2416
2518
|
let [html, streams] = this.recursiveToString(component, components, onlyCids, changeTracking, attrs);
|
|
2519
|
+
delete component.reset;
|
|
2417
2520
|
return [html, streams];
|
|
2418
2521
|
}
|
|
2419
2522
|
};
|
|
@@ -2497,6 +2600,7 @@ var ViewHook = class {
|
|
|
2497
2600
|
|
|
2498
2601
|
// js/phoenix_live_view/js.js
|
|
2499
2602
|
var focusStack = null;
|
|
2603
|
+
var default_transition_time = 200;
|
|
2500
2604
|
var JS = {
|
|
2501
2605
|
exec(eventType, phxEvent, view, sourceEl, defaults) {
|
|
2502
2606
|
let [defaultKind, defaultArgs] = defaults || [null, { callback: defaults && defaults.callback }];
|
|
@@ -2518,7 +2622,7 @@ var JS = {
|
|
|
2518
2622
|
const rect = el.getBoundingClientRect();
|
|
2519
2623
|
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
|
|
2520
2624
|
},
|
|
2521
|
-
exec_exec(eventType, phxEvent, view, sourceEl, el,
|
|
2625
|
+
exec_exec(eventType, phxEvent, view, sourceEl, el, { attr, to }) {
|
|
2522
2626
|
let nodes = to ? dom_default.all(document, to) : [sourceEl];
|
|
2523
2627
|
nodes.forEach((node) => {
|
|
2524
2628
|
let encodedJS = node.getAttribute(attr);
|
|
@@ -2534,14 +2638,14 @@ var JS = {
|
|
|
2534
2638
|
dom_default.dispatchEvent(el, event, { detail, bubbles });
|
|
2535
2639
|
},
|
|
2536
2640
|
exec_push(eventType, phxEvent, view, sourceEl, el, args) {
|
|
2537
|
-
if (!view.isConnected()) {
|
|
2538
|
-
return;
|
|
2539
|
-
}
|
|
2540
2641
|
let { event, data, target, page_loading, loading, value, dispatcher, callback } = args;
|
|
2541
2642
|
let pushOpts = { loading, value, target, page_loading: !!page_loading };
|
|
2542
2643
|
let targetSrc = eventType === "change" && dispatcher ? dispatcher : sourceEl;
|
|
2543
2644
|
let phxTarget = target || targetSrc.getAttribute(view.binding("target")) || targetSrc;
|
|
2544
2645
|
view.withinTargets(phxTarget, (targetView, targetCtx) => {
|
|
2646
|
+
if (!targetView.isConnected()) {
|
|
2647
|
+
return;
|
|
2648
|
+
}
|
|
2545
2649
|
if (eventType === "change") {
|
|
2546
2650
|
let { newCid, _target } = args;
|
|
2547
2651
|
_target = _target || (dom_default.isFormInput(sourceEl) ? sourceEl.name : void 0);
|
|
@@ -2586,6 +2690,24 @@ var JS = {
|
|
|
2586
2690
|
exec_remove_class(eventType, phxEvent, view, sourceEl, el, { names, transition, time }) {
|
|
2587
2691
|
this.addOrRemoveClasses(el, [], names, transition, time, view);
|
|
2588
2692
|
},
|
|
2693
|
+
exec_toggle_class(eventType, phxEvent, view, sourceEl, el, { to, names, transition, time }) {
|
|
2694
|
+
this.toggleClasses(el, names, transition, view);
|
|
2695
|
+
},
|
|
2696
|
+
exec_toggle_attr(eventType, phxEvent, view, sourceEl, el, { attr: [attr, val1, val2] }) {
|
|
2697
|
+
if (el.hasAttribute(attr)) {
|
|
2698
|
+
if (val2 !== void 0) {
|
|
2699
|
+
if (el.getAttribute(attr) === val1) {
|
|
2700
|
+
this.setOrRemoveAttrs(el, [[attr, val2]], []);
|
|
2701
|
+
} else {
|
|
2702
|
+
this.setOrRemoveAttrs(el, [[attr, val1]], []);
|
|
2703
|
+
}
|
|
2704
|
+
} else {
|
|
2705
|
+
this.setOrRemoveAttrs(el, [], [attr]);
|
|
2706
|
+
}
|
|
2707
|
+
} else {
|
|
2708
|
+
this.setOrRemoveAttrs(el, [[attr, val1]], []);
|
|
2709
|
+
}
|
|
2710
|
+
},
|
|
2589
2711
|
exec_transition(eventType, phxEvent, view, sourceEl, el, { time, transition }) {
|
|
2590
2712
|
this.addOrRemoveClasses(el, [], [], transition, time, view);
|
|
2591
2713
|
},
|
|
@@ -2615,6 +2737,7 @@ var JS = {
|
|
|
2615
2737
|
}
|
|
2616
2738
|
},
|
|
2617
2739
|
toggle(eventType, view, el, display, ins, outs, time) {
|
|
2740
|
+
time = time || default_transition_time;
|
|
2618
2741
|
let [inClasses, inStartClasses, inEndClasses] = ins || [[], [], []];
|
|
2619
2742
|
let [outClasses, outStartClasses, outEndClasses] = outs || [[], [], []];
|
|
2620
2743
|
if (inClasses.length > 0 || outClasses.length > 0) {
|
|
@@ -2668,7 +2791,16 @@ var JS = {
|
|
|
2668
2791
|
}
|
|
2669
2792
|
}
|
|
2670
2793
|
},
|
|
2794
|
+
toggleClasses(el, classes, transition, time, view) {
|
|
2795
|
+
window.requestAnimationFrame(() => {
|
|
2796
|
+
let [prevAdds, prevRemoves] = dom_default.getSticky(el, "classes", [[], []]);
|
|
2797
|
+
let newAdds = classes.filter((name) => prevAdds.indexOf(name) < 0 && !el.classList.contains(name));
|
|
2798
|
+
let newRemoves = classes.filter((name) => prevRemoves.indexOf(name) < 0 && el.classList.contains(name));
|
|
2799
|
+
this.addOrRemoveClasses(el, newAdds, newRemoves, transition, time, view);
|
|
2800
|
+
});
|
|
2801
|
+
},
|
|
2671
2802
|
addOrRemoveClasses(el, adds, removes, transition, time, view) {
|
|
2803
|
+
time = time || default_transition_time;
|
|
2672
2804
|
let [transitionRun, transitionStart, transitionEnd] = transition || [[], [], []];
|
|
2673
2805
|
if (transitionRun.length > 0) {
|
|
2674
2806
|
let onStart = () => {
|
|
@@ -2722,24 +2854,37 @@ var js_default = JS;
|
|
|
2722
2854
|
|
|
2723
2855
|
// js/phoenix_live_view/view.js
|
|
2724
2856
|
var serializeForm = (form, metadata, onlyNames = []) => {
|
|
2725
|
-
|
|
2726
|
-
let
|
|
2727
|
-
if (submitter && submitter.
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2857
|
+
const { submitter, ...meta } = metadata;
|
|
2858
|
+
let injectedElement;
|
|
2859
|
+
if (submitter && submitter.name) {
|
|
2860
|
+
const input = document.createElement("input");
|
|
2861
|
+
input.type = "hidden";
|
|
2862
|
+
const formId = submitter.getAttribute("form");
|
|
2863
|
+
if (formId) {
|
|
2864
|
+
input.setAttribute("form", form);
|
|
2865
|
+
}
|
|
2866
|
+
input.name = submitter.name;
|
|
2867
|
+
input.value = submitter.value;
|
|
2868
|
+
submitter.parentElement.insertBefore(input, submitter);
|
|
2869
|
+
injectedElement = input;
|
|
2870
|
+
}
|
|
2871
|
+
const formData = new FormData(form);
|
|
2872
|
+
const toRemove = [];
|
|
2731
2873
|
formData.forEach((val, key, _index) => {
|
|
2732
2874
|
if (val instanceof File) {
|
|
2733
2875
|
toRemove.push(key);
|
|
2734
2876
|
}
|
|
2735
2877
|
});
|
|
2736
2878
|
toRemove.forEach((key) => formData.delete(key));
|
|
2737
|
-
|
|
2879
|
+
const params = new URLSearchParams();
|
|
2738
2880
|
for (let [key, val] of formData.entries()) {
|
|
2739
2881
|
if (onlyNames.length === 0 || onlyNames.indexOf(key) >= 0) {
|
|
2740
2882
|
params.append(key, val);
|
|
2741
2883
|
}
|
|
2742
2884
|
}
|
|
2885
|
+
if (submitter && injectedElement) {
|
|
2886
|
+
submitter.parentElement.removeChild(injectedElement);
|
|
2887
|
+
}
|
|
2743
2888
|
for (let metaKey in meta) {
|
|
2744
2889
|
params.append(metaKey, meta[metaKey]);
|
|
2745
2890
|
}
|
|
@@ -2943,6 +3088,9 @@ var View = class {
|
|
|
2943
3088
|
if (phxStatic) {
|
|
2944
3089
|
toEl.setAttribute(PHX_STATIC, phxStatic);
|
|
2945
3090
|
}
|
|
3091
|
+
if (fromEl) {
|
|
3092
|
+
fromEl.setAttribute(PHX_ROOT_ID, this.root.id);
|
|
3093
|
+
}
|
|
2946
3094
|
return this.joinChild(toEl);
|
|
2947
3095
|
});
|
|
2948
3096
|
if (newChildren.length === 0) {
|
|
@@ -3022,6 +3170,9 @@ var View = class {
|
|
|
3022
3170
|
let updatedHookIds = new Set();
|
|
3023
3171
|
patch.after("added", (el) => {
|
|
3024
3172
|
this.liveSocket.triggerDOM("onNodeAdded", [el]);
|
|
3173
|
+
let phxViewportTop = this.binding(PHX_VIEWPORT_TOP);
|
|
3174
|
+
let phxViewportBottom = this.binding(PHX_VIEWPORT_BOTTOM);
|
|
3175
|
+
dom_default.maybeAddPrivateHooks(el, phxViewportTop, phxViewportBottom);
|
|
3025
3176
|
this.maybeAddNewHook(el);
|
|
3026
3177
|
if (el.getAttribute) {
|
|
3027
3178
|
this.maybeMounted(el);
|
|
@@ -3398,10 +3549,11 @@ var View = class {
|
|
|
3398
3549
|
}
|
|
3399
3550
|
dom_default.all(document, `[${PHX_REF_SRC}="${this.id}"][${PHX_REF}="${ref}"]`, (el) => {
|
|
3400
3551
|
let disabledVal = el.getAttribute(PHX_DISABLED);
|
|
3552
|
+
let readOnlyVal = el.getAttribute(PHX_READONLY);
|
|
3401
3553
|
el.removeAttribute(PHX_REF);
|
|
3402
3554
|
el.removeAttribute(PHX_REF_SRC);
|
|
3403
|
-
if (
|
|
3404
|
-
el.readOnly = false;
|
|
3555
|
+
if (readOnlyVal !== null) {
|
|
3556
|
+
el.readOnly = readOnlyVal === "true" ? true : false;
|
|
3405
3557
|
el.removeAttribute(PHX_READONLY);
|
|
3406
3558
|
}
|
|
3407
3559
|
if (disabledVal !== null) {
|
|
@@ -3443,6 +3595,7 @@ var View = class {
|
|
|
3443
3595
|
if (disableText !== "") {
|
|
3444
3596
|
el.innerText = disableText;
|
|
3445
3597
|
}
|
|
3598
|
+
el.setAttribute(PHX_DISABLED, el.getAttribute(PHX_DISABLED) || el.disabled);
|
|
3446
3599
|
el.setAttribute("disabled", "");
|
|
3447
3600
|
}
|
|
3448
3601
|
});
|
|
@@ -3544,6 +3697,9 @@ var View = class {
|
|
|
3544
3697
|
let refGenerator = () => this.putRef([inputEl, inputEl.form], "change", opts);
|
|
3545
3698
|
let formData;
|
|
3546
3699
|
let meta = this.extractMeta(inputEl.form);
|
|
3700
|
+
if (inputEl instanceof HTMLButtonElement) {
|
|
3701
|
+
meta.submitter = inputEl;
|
|
3702
|
+
}
|
|
3547
3703
|
if (inputEl.getAttribute(this.binding("change"))) {
|
|
3548
3704
|
formData = serializeForm(inputEl.form, { _target: opts._target, ...meta }, [inputEl.name]);
|
|
3549
3705
|
} else {
|
|
@@ -3568,6 +3724,7 @@ var View = class {
|
|
|
3568
3724
|
this.uploadFiles(inputEl.form, targetCtx, ref, cid, (_uploads) => {
|
|
3569
3725
|
callback && callback(resp);
|
|
3570
3726
|
this.triggerAwaitingSubmit(inputEl.form);
|
|
3727
|
+
this.undoRefs(ref);
|
|
3571
3728
|
});
|
|
3572
3729
|
}
|
|
3573
3730
|
} else {
|
|
@@ -3766,7 +3923,7 @@ var View = class {
|
|
|
3766
3923
|
let template = document.createElement("template");
|
|
3767
3924
|
template.innerHTML = html;
|
|
3768
3925
|
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) => {
|
|
3769
|
-
const phxChangeValue = form.getAttribute(phxChange)
|
|
3926
|
+
const phxChangeValue = CSS.escape(form.getAttribute(phxChange));
|
|
3770
3927
|
let newForm = template.content.querySelector(`form[id="${form.id}"][${phxChange}="${phxChangeValue}"]`);
|
|
3771
3928
|
if (newForm) {
|
|
3772
3929
|
return [form, newForm, this.targetComponentID(newForm)];
|
|
@@ -3776,18 +3933,19 @@ var View = class {
|
|
|
3776
3933
|
}).filter(([form, newForm, newCid]) => newForm);
|
|
3777
3934
|
}
|
|
3778
3935
|
maybePushComponentsDestroyed(destroyedCIDs) {
|
|
3779
|
-
let willDestroyCIDs = destroyedCIDs.filter((cid) => {
|
|
3936
|
+
let willDestroyCIDs = destroyedCIDs.concat(this.pruningCIDs).filter((cid) => {
|
|
3780
3937
|
return dom_default.findComponentNodeList(this.el, cid).length === 0;
|
|
3781
3938
|
});
|
|
3939
|
+
this.pruningCIDs = willDestroyCIDs.concat([]);
|
|
3782
3940
|
if (willDestroyCIDs.length > 0) {
|
|
3783
|
-
this.
|
|
3941
|
+
willDestroyCIDs.forEach((cid) => this.rendered.resetRender(cid));
|
|
3784
3942
|
this.pushWithReply(null, "cids_will_destroy", { cids: willDestroyCIDs }, () => {
|
|
3785
|
-
this.pruningCIDs = this.pruningCIDs.filter((cid) => willDestroyCIDs.indexOf(cid) !== -1);
|
|
3786
3943
|
let completelyDestroyCIDs = willDestroyCIDs.filter((cid) => {
|
|
3787
3944
|
return dom_default.findComponentNodeList(this.el, cid).length === 0;
|
|
3788
3945
|
});
|
|
3789
3946
|
if (completelyDestroyCIDs.length > 0) {
|
|
3790
3947
|
this.pushWithReply(null, "cids_destroyed", { cids: completelyDestroyCIDs }, (resp) => {
|
|
3948
|
+
this.pruningCIDs = this.pruningCIDs.filter((cid) => resp.cids.indexOf(cid) === -1);
|
|
3791
3949
|
this.rendered.pruneCIDs(resp.cids);
|
|
3792
3950
|
});
|
|
3793
3951
|
}
|
|
@@ -4103,22 +4261,26 @@ var LiveSocket = class {
|
|
|
4103
4261
|
this.main.destroy();
|
|
4104
4262
|
this.main = this.newRootView(newMainEl, flash, liveReferer);
|
|
4105
4263
|
this.main.setRedirect(href);
|
|
4106
|
-
this.transitionRemoves();
|
|
4264
|
+
this.transitionRemoves(null, true);
|
|
4107
4265
|
this.main.join((joinCount, onDone) => {
|
|
4108
4266
|
if (joinCount === 1 && this.commitPendingLink(linkRef)) {
|
|
4109
4267
|
this.requestDOMUpdate(() => {
|
|
4110
4268
|
dom_default.findPhxSticky(document).forEach((el) => newMainEl.appendChild(el));
|
|
4111
4269
|
this.outgoingMainEl.replaceWith(newMainEl);
|
|
4112
4270
|
this.outgoingMainEl = null;
|
|
4113
|
-
callback &&
|
|
4271
|
+
callback && callback(linkRef);
|
|
4114
4272
|
onDone();
|
|
4115
4273
|
});
|
|
4116
4274
|
}
|
|
4117
4275
|
});
|
|
4118
4276
|
}
|
|
4119
|
-
transitionRemoves(elements) {
|
|
4277
|
+
transitionRemoves(elements, skipSticky) {
|
|
4120
4278
|
let removeAttr = this.binding("remove");
|
|
4121
4279
|
elements = elements || dom_default.all(document, `[${removeAttr}]`);
|
|
4280
|
+
if (skipSticky) {
|
|
4281
|
+
const stickies = dom_default.findPhxSticky(document) || [];
|
|
4282
|
+
elements = elements.filter((el) => !dom_default.isChildOfAny(el, stickies));
|
|
4283
|
+
}
|
|
4122
4284
|
elements.forEach((el) => {
|
|
4123
4285
|
this.execJS(el, el.getAttribute(removeAttr), "remove");
|
|
4124
4286
|
});
|
|
@@ -4334,6 +4496,8 @@ var LiveSocket = class {
|
|
|
4334
4496
|
if (capture) {
|
|
4335
4497
|
target = e.target.matches(`[${click}]`) ? e.target : e.target.querySelector(`[${click}]`);
|
|
4336
4498
|
} else {
|
|
4499
|
+
if (e.detail === 0)
|
|
4500
|
+
this.clickStartedAtTarget = e.target;
|
|
4337
4501
|
let clickStartedAtTarget = this.clickStartedAtTarget || e.target;
|
|
4338
4502
|
target = closestPhxBinding(clickStartedAtTarget, click);
|
|
4339
4503
|
this.dispatchClickAway(e, clickStartedAtTarget);
|
|
@@ -4363,7 +4527,7 @@ var LiveSocket = class {
|
|
|
4363
4527
|
let phxClickAway = this.binding("click-away");
|
|
4364
4528
|
dom_default.all(document, `[${phxClickAway}]`, (el) => {
|
|
4365
4529
|
if (!(el.isSameNode(clickStartedAt) || el.contains(clickStartedAt))) {
|
|
4366
|
-
this.withinOwners(
|
|
4530
|
+
this.withinOwners(el, (view) => {
|
|
4367
4531
|
let phxEvent = el.getAttribute(phxClickAway);
|
|
4368
4532
|
if (js_default.isVisible(el) && js_default.isInViewport(el)) {
|
|
4369
4533
|
js_default.exec("click", phxEvent, view, el, ["push", { data: this.eventMeta("click", e, e.target) }]);
|
|
@@ -4455,7 +4619,7 @@ var LiveSocket = class {
|
|
|
4455
4619
|
return callback ? callback(done) : done;
|
|
4456
4620
|
}
|
|
4457
4621
|
pushHistoryPatch(href, linkState, targetEl) {
|
|
4458
|
-
if (!this.isConnected()) {
|
|
4622
|
+
if (!this.isConnected() || !this.main.isMain()) {
|
|
4459
4623
|
return browser_default.redirect(href);
|
|
4460
4624
|
}
|
|
4461
4625
|
this.withPageLoading({ to: href, kind: "patch" }, (done) => {
|
|
@@ -4474,7 +4638,7 @@ var LiveSocket = class {
|
|
|
4474
4638
|
this.registerNewLocation(window.location);
|
|
4475
4639
|
}
|
|
4476
4640
|
historyRedirect(href, linkState, flash) {
|
|
4477
|
-
if (!this.isConnected()) {
|
|
4641
|
+
if (!this.isConnected() || !this.main.isMain()) {
|
|
4478
4642
|
return browser_default.redirect(href, flash);
|
|
4479
4643
|
}
|
|
4480
4644
|
if (/^\/$|^\/[^\/]+.*$/.test(href)) {
|
|
@@ -4575,9 +4739,11 @@ var LiveSocket = class {
|
|
|
4575
4739
|
let form = e.target;
|
|
4576
4740
|
dom_default.resetForm(form, this.binding(PHX_FEEDBACK_FOR));
|
|
4577
4741
|
let input = Array.from(form.elements).find((el) => el.type === "reset");
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4742
|
+
if (input) {
|
|
4743
|
+
window.requestAnimationFrame(() => {
|
|
4744
|
+
input.dispatchEvent(new Event("input", { bubbles: true, cancelable: false }));
|
|
4745
|
+
});
|
|
4746
|
+
}
|
|
4581
4747
|
});
|
|
4582
4748
|
}
|
|
4583
4749
|
debounce(el, event, eventType, callback) {
|