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
|
@@ -11,7 +11,8 @@ var PHX_EVENT_CLASSES = [
|
|
|
11
11
|
"phx-keydown-loading",
|
|
12
12
|
"phx-keyup-loading",
|
|
13
13
|
"phx-blur-loading",
|
|
14
|
-
"phx-focus-loading"
|
|
14
|
+
"phx-focus-loading",
|
|
15
|
+
"phx-hook-loading"
|
|
15
16
|
];
|
|
16
17
|
var PHX_COMPONENT = "data-phx-component";
|
|
17
18
|
var PHX_LIVE_LINK = "data-phx-link";
|
|
@@ -43,6 +44,7 @@ var PHX_VIEWPORT_TOP = "viewport-top";
|
|
|
43
44
|
var PHX_VIEWPORT_BOTTOM = "viewport-bottom";
|
|
44
45
|
var PHX_TRIGGER_ACTION = "trigger-action";
|
|
45
46
|
var PHX_FEEDBACK_FOR = "feedback-for";
|
|
47
|
+
var PHX_FEEDBACK_GROUP = "feedback-group";
|
|
46
48
|
var PHX_HAS_FOCUSED = "phx-has-focused";
|
|
47
49
|
var FOCUSABLE_INPUTS = ["text", "textarea", "number", "email", "password", "search", "tel", "url", "date", "time", "datetime-local", "color", "range"];
|
|
48
50
|
var CHECKABLE_INPUTS = ["checkbox", "radio"];
|
|
@@ -298,7 +300,9 @@ var DOM = {
|
|
|
298
300
|
return inputEl.hasAttribute("data-phx-auto-upload");
|
|
299
301
|
},
|
|
300
302
|
findUploadInputs(node) {
|
|
301
|
-
|
|
303
|
+
const formId = node.id;
|
|
304
|
+
const inputsOutsideForm = this.all(document, `input[type="file"][${PHX_UPLOAD_REF}][form="${formId}"]`);
|
|
305
|
+
return this.all(node, `input[type="file"][${PHX_UPLOAD_REF}]`).concat(inputsOutsideForm);
|
|
302
306
|
},
|
|
303
307
|
findComponentNodeList(node, cid) {
|
|
304
308
|
return this.filterWithinSameLiveView(this.all(node, `[${PHX_COMPONENT}="${cid}"]`), node);
|
|
@@ -492,7 +496,9 @@ var DOM = {
|
|
|
492
496
|
});
|
|
493
497
|
}
|
|
494
498
|
if (this.once(el, "bind-debounce")) {
|
|
495
|
-
el.addEventListener("blur", () =>
|
|
499
|
+
el.addEventListener("blur", () => {
|
|
500
|
+
callback();
|
|
501
|
+
});
|
|
496
502
|
}
|
|
497
503
|
}
|
|
498
504
|
},
|
|
@@ -525,16 +531,39 @@ var DOM = {
|
|
|
525
531
|
el.setAttribute("data-phx-hook", "Phoenix.InfiniteScroll");
|
|
526
532
|
}
|
|
527
533
|
},
|
|
528
|
-
maybeHideFeedback(container,
|
|
534
|
+
maybeHideFeedback(container, forms, phxFeedbackFor, phxFeedbackGroup) {
|
|
529
535
|
let feedbacks = [];
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
536
|
+
let inputNamesFocused = {};
|
|
537
|
+
let feedbackGroups = {};
|
|
538
|
+
forms.forEach((form) => {
|
|
539
|
+
Array.from(form.elements).forEach((input) => {
|
|
540
|
+
const group = input.getAttribute(phxFeedbackGroup);
|
|
541
|
+
if (group && !(group in feedbackGroups)) {
|
|
542
|
+
feedbackGroups[group] = true;
|
|
535
543
|
}
|
|
536
|
-
|
|
544
|
+
if (!(input.name in inputNamesFocused)) {
|
|
545
|
+
inputNamesFocused[input.name] = false;
|
|
546
|
+
}
|
|
547
|
+
if (this.private(input, PHX_HAS_FOCUSED) || this.private(input, PHX_HAS_SUBMITTED)) {
|
|
548
|
+
inputNamesFocused[input.name] = true;
|
|
549
|
+
if (group) {
|
|
550
|
+
feedbackGroups[group] = false;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
});
|
|
537
554
|
});
|
|
555
|
+
for (const [name, focused] of Object.entries(inputNamesFocused)) {
|
|
556
|
+
if (!focused) {
|
|
557
|
+
feedbacks.push(name);
|
|
558
|
+
if (name.endsWith("[]")) {
|
|
559
|
+
feedbacks.push(name.slice(0, -2));
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
for (const [group, noFeedback] of Object.entries(feedbackGroups)) {
|
|
564
|
+
if (noFeedback)
|
|
565
|
+
feedbacks.push(group);
|
|
566
|
+
}
|
|
538
567
|
if (feedbacks.length > 0) {
|
|
539
568
|
let selector = feedbacks.map((f) => `[${phxFeedbackFor}="${f}"]`).join(", ");
|
|
540
569
|
DOM.all(container, selector, (el) => el.classList.add(PHX_NO_FEEDBACK_CLASS));
|
|
@@ -565,11 +594,19 @@ var DOM = {
|
|
|
565
594
|
isPhxSticky(node) {
|
|
566
595
|
return node.getAttribute && node.getAttribute(PHX_STICKY) !== null;
|
|
567
596
|
},
|
|
597
|
+
isChildOfAny(el, parents) {
|
|
598
|
+
return !!parents.find((parent) => parent.contains(el));
|
|
599
|
+
},
|
|
568
600
|
firstPhxChild(el) {
|
|
569
601
|
return this.isPhxChild(el) ? el : this.all(el, `[${PHX_PARENT_ID}]`)[0];
|
|
570
602
|
},
|
|
571
603
|
dispatchEvent(target, name, opts = {}) {
|
|
572
|
-
let
|
|
604
|
+
let defaultBubble = true;
|
|
605
|
+
let isUploadTarget = target.nodeName === "INPUT" && target.type === "file";
|
|
606
|
+
if (isUploadTarget && name === "click") {
|
|
607
|
+
defaultBubble = false;
|
|
608
|
+
}
|
|
609
|
+
let bubbles = opts.bubbles === void 0 ? defaultBubble : !!opts.bubbles;
|
|
573
610
|
let eventOpts = { bubbles, cancelable: true, detail: opts.detail || {} };
|
|
574
611
|
let event = name === "click" ? new MouseEvent("click", eventOpts) : new CustomEvent(name, eventOpts);
|
|
575
612
|
target.dispatchEvent(event);
|
|
@@ -584,20 +621,27 @@ var DOM = {
|
|
|
584
621
|
}
|
|
585
622
|
},
|
|
586
623
|
mergeAttrs(target, source, opts = {}) {
|
|
587
|
-
let exclude = opts.exclude || [];
|
|
624
|
+
let exclude = new Set(opts.exclude || []);
|
|
588
625
|
let isIgnored = opts.isIgnored;
|
|
589
626
|
let sourceAttrs = source.attributes;
|
|
590
627
|
for (let i = sourceAttrs.length - 1; i >= 0; i--) {
|
|
591
628
|
let name = sourceAttrs[i].name;
|
|
592
|
-
if (exclude.
|
|
593
|
-
|
|
629
|
+
if (!exclude.has(name)) {
|
|
630
|
+
const sourceValue = source.getAttribute(name);
|
|
631
|
+
if (target.getAttribute(name) !== sourceValue && (!isIgnored || isIgnored && name.startsWith("data-"))) {
|
|
632
|
+
target.setAttribute(name, sourceValue);
|
|
633
|
+
}
|
|
634
|
+
} else {
|
|
635
|
+
if (name === "value" && target.value === source.value) {
|
|
636
|
+
target.setAttribute("value", source.getAttribute(name));
|
|
637
|
+
}
|
|
594
638
|
}
|
|
595
639
|
}
|
|
596
640
|
let targetAttrs = target.attributes;
|
|
597
641
|
for (let i = targetAttrs.length - 1; i >= 0; i--) {
|
|
598
642
|
let name = targetAttrs[i].name;
|
|
599
643
|
if (isIgnored) {
|
|
600
|
-
if (name.startsWith("data-") && !source.hasAttribute(name)) {
|
|
644
|
+
if (name.startsWith("data-") && !source.hasAttribute(name) && ![PHX_REF, PHX_REF_SRC].includes(name)) {
|
|
601
645
|
target.removeAttribute(name);
|
|
602
646
|
}
|
|
603
647
|
} else {
|
|
@@ -621,6 +665,9 @@ var DOM = {
|
|
|
621
665
|
return el.setSelectionRange && (el.type === "text" || el.type === "textarea");
|
|
622
666
|
},
|
|
623
667
|
restoreFocus(focused, selectionStart, selectionEnd) {
|
|
668
|
+
if (focused instanceof HTMLSelectElement) {
|
|
669
|
+
focused.focus();
|
|
670
|
+
}
|
|
624
671
|
if (!DOM.isTextualInput(focused)) {
|
|
625
672
|
return;
|
|
626
673
|
}
|
|
@@ -744,15 +791,22 @@ var dom_default = DOM;
|
|
|
744
791
|
var UploadEntry = class {
|
|
745
792
|
static isActive(fileEl, file) {
|
|
746
793
|
let isNew = file._phxRef === void 0;
|
|
794
|
+
let isPreflightInProgress = UploadEntry.isPreflightInProgress(file);
|
|
747
795
|
let activeRefs = fileEl.getAttribute(PHX_ACTIVE_ENTRY_REFS).split(",");
|
|
748
796
|
let isActive = activeRefs.indexOf(LiveUploader.genFileRef(file)) >= 0;
|
|
749
|
-
return file.size > 0 && (isNew || isActive);
|
|
797
|
+
return file.size > 0 && (isNew || isActive || !isPreflightInProgress);
|
|
750
798
|
}
|
|
751
799
|
static isPreflighted(fileEl, file) {
|
|
752
800
|
let preflightedRefs = fileEl.getAttribute(PHX_PREFLIGHTED_REFS).split(",");
|
|
753
801
|
let isPreflighted = preflightedRefs.indexOf(LiveUploader.genFileRef(file)) >= 0;
|
|
754
802
|
return isPreflighted && this.isActive(fileEl, file);
|
|
755
803
|
}
|
|
804
|
+
static isPreflightInProgress(file) {
|
|
805
|
+
return file._preflightInProgress === true;
|
|
806
|
+
}
|
|
807
|
+
static markPreflightInProgress(file) {
|
|
808
|
+
file._preflightInProgress = true;
|
|
809
|
+
}
|
|
756
810
|
constructor(fileEl, file, view) {
|
|
757
811
|
this.ref = LiveUploader.genFileRef(file);
|
|
758
812
|
this.fileEl = fileEl;
|
|
@@ -919,12 +973,16 @@ var LiveUploader = class {
|
|
|
919
973
|
return Array.from(fileInputs).filter((input) => this.filesAwaitingPreflight(input).length > 0);
|
|
920
974
|
}
|
|
921
975
|
static filesAwaitingPreflight(input) {
|
|
922
|
-
return this.activeFiles(input).filter((f) => !UploadEntry.isPreflighted(input, f));
|
|
976
|
+
return this.activeFiles(input).filter((f) => !UploadEntry.isPreflighted(input, f) && !UploadEntry.isPreflightInProgress(f));
|
|
977
|
+
}
|
|
978
|
+
static markPreflightInProgress(entries) {
|
|
979
|
+
entries.forEach((entry) => UploadEntry.markPreflightInProgress(entry.file));
|
|
923
980
|
}
|
|
924
981
|
constructor(inputEl, view, onComplete) {
|
|
925
982
|
this.view = view;
|
|
926
983
|
this.onComplete = onComplete;
|
|
927
984
|
this._entries = Array.from(LiveUploader.filesAwaitingPreflight(inputEl) || []).map((file) => new UploadEntry(inputEl, file, view));
|
|
985
|
+
LiveUploader.markPreflightInProgress(this._entries);
|
|
928
986
|
this.numEntriesInProgress = this._entries.length;
|
|
929
987
|
}
|
|
930
988
|
entries() {
|
|
@@ -1065,23 +1123,50 @@ var Hooks = {
|
|
|
1065
1123
|
}
|
|
1066
1124
|
}
|
|
1067
1125
|
};
|
|
1068
|
-
var
|
|
1069
|
-
|
|
1070
|
-
|
|
1126
|
+
var findScrollContainer = (el) => {
|
|
1127
|
+
if (["scroll", "auto"].indexOf(getComputedStyle(el).overflowY) >= 0)
|
|
1128
|
+
return el;
|
|
1129
|
+
if (document.documentElement === el)
|
|
1130
|
+
return null;
|
|
1131
|
+
return findScrollContainer(el.parentElement);
|
|
1132
|
+
};
|
|
1133
|
+
var scrollTop = (scrollContainer) => {
|
|
1134
|
+
if (scrollContainer) {
|
|
1135
|
+
return scrollContainer.scrollTop;
|
|
1136
|
+
} else {
|
|
1137
|
+
return document.documentElement.scrollTop || document.body.scrollTop;
|
|
1138
|
+
}
|
|
1139
|
+
};
|
|
1140
|
+
var bottom = (scrollContainer) => {
|
|
1141
|
+
if (scrollContainer) {
|
|
1142
|
+
return scrollContainer.getBoundingClientRect().bottom;
|
|
1143
|
+
} else {
|
|
1144
|
+
return window.innerHeight || document.documentElement.clientHeight;
|
|
1145
|
+
}
|
|
1146
|
+
};
|
|
1147
|
+
var top = (scrollContainer) => {
|
|
1148
|
+
if (scrollContainer) {
|
|
1149
|
+
return scrollContainer.getBoundingClientRect().top;
|
|
1150
|
+
} else {
|
|
1151
|
+
return 0;
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
1154
|
+
var isAtViewportTop = (el, scrollContainer) => {
|
|
1071
1155
|
let rect = el.getBoundingClientRect();
|
|
1072
|
-
return rect.top >=
|
|
1156
|
+
return rect.top >= top(scrollContainer) && rect.left >= 0 && rect.top <= bottom(scrollContainer);
|
|
1073
1157
|
};
|
|
1074
|
-
var isAtViewportBottom = (el) => {
|
|
1158
|
+
var isAtViewportBottom = (el, scrollContainer) => {
|
|
1075
1159
|
let rect = el.getBoundingClientRect();
|
|
1076
|
-
return rect.right >=
|
|
1160
|
+
return rect.right >= top(scrollContainer) && rect.left >= 0 && rect.bottom <= bottom(scrollContainer);
|
|
1077
1161
|
};
|
|
1078
|
-
var isWithinViewport = (el) => {
|
|
1162
|
+
var isWithinViewport = (el, scrollContainer) => {
|
|
1079
1163
|
let rect = el.getBoundingClientRect();
|
|
1080
|
-
return rect.top >=
|
|
1164
|
+
return rect.top >= top(scrollContainer) && rect.left >= 0 && rect.top <= bottom(scrollContainer);
|
|
1081
1165
|
};
|
|
1082
1166
|
Hooks.InfiniteScroll = {
|
|
1083
1167
|
mounted() {
|
|
1084
|
-
|
|
1168
|
+
this.scrollContainer = findScrollContainer(this.el);
|
|
1169
|
+
let scrollBefore = scrollTop(this.scrollContainer);
|
|
1085
1170
|
let topOverran = false;
|
|
1086
1171
|
let throttleInterval = 500;
|
|
1087
1172
|
let pendingOp = null;
|
|
@@ -1095,22 +1180,26 @@ Hooks.InfiniteScroll = {
|
|
|
1095
1180
|
pendingOp = () => firstChild.scrollIntoView({ block: "start" });
|
|
1096
1181
|
this.liveSocket.execJSHookPush(this.el, topEvent, { id: firstChild.id }, () => {
|
|
1097
1182
|
pendingOp = null;
|
|
1098
|
-
|
|
1099
|
-
firstChild.
|
|
1100
|
-
|
|
1183
|
+
window.requestAnimationFrame(() => {
|
|
1184
|
+
if (!isWithinViewport(firstChild, this.scrollContainer)) {
|
|
1185
|
+
firstChild.scrollIntoView({ block: "start" });
|
|
1186
|
+
}
|
|
1187
|
+
});
|
|
1101
1188
|
});
|
|
1102
1189
|
});
|
|
1103
1190
|
let onLastChildAtBottom = this.throttle(throttleInterval, (bottomEvent, lastChild) => {
|
|
1104
1191
|
pendingOp = () => lastChild.scrollIntoView({ block: "end" });
|
|
1105
1192
|
this.liveSocket.execJSHookPush(this.el, bottomEvent, { id: lastChild.id }, () => {
|
|
1106
1193
|
pendingOp = null;
|
|
1107
|
-
|
|
1108
|
-
lastChild.
|
|
1109
|
-
|
|
1194
|
+
window.requestAnimationFrame(() => {
|
|
1195
|
+
if (!isWithinViewport(lastChild, this.scrollContainer)) {
|
|
1196
|
+
lastChild.scrollIntoView({ block: "end" });
|
|
1197
|
+
}
|
|
1198
|
+
});
|
|
1110
1199
|
});
|
|
1111
1200
|
});
|
|
1112
|
-
this.onScroll = (
|
|
1113
|
-
let scrollNow = scrollTop();
|
|
1201
|
+
this.onScroll = (_e) => {
|
|
1202
|
+
let scrollNow = scrollTop(this.scrollContainer);
|
|
1114
1203
|
if (pendingOp) {
|
|
1115
1204
|
scrollBefore = scrollNow;
|
|
1116
1205
|
return pendingOp();
|
|
@@ -1128,17 +1217,25 @@ Hooks.InfiniteScroll = {
|
|
|
1128
1217
|
} else if (isScrollingDown && topOverran && rect.top <= 0) {
|
|
1129
1218
|
topOverran = false;
|
|
1130
1219
|
}
|
|
1131
|
-
if (topEvent && isScrollingUp && isAtViewportTop(firstChild)) {
|
|
1220
|
+
if (topEvent && isScrollingUp && isAtViewportTop(firstChild, this.scrollContainer)) {
|
|
1132
1221
|
onFirstChildAtTop(topEvent, firstChild);
|
|
1133
|
-
} else if (bottomEvent && isScrollingDown && isAtViewportBottom(lastChild)) {
|
|
1222
|
+
} else if (bottomEvent && isScrollingDown && isAtViewportBottom(lastChild, this.scrollContainer)) {
|
|
1134
1223
|
onLastChildAtBottom(bottomEvent, lastChild);
|
|
1135
1224
|
}
|
|
1136
1225
|
scrollBefore = scrollNow;
|
|
1137
1226
|
};
|
|
1138
|
-
|
|
1227
|
+
if (this.scrollContainer) {
|
|
1228
|
+
this.scrollContainer.addEventListener("scroll", this.onScroll);
|
|
1229
|
+
} else {
|
|
1230
|
+
window.addEventListener("scroll", this.onScroll);
|
|
1231
|
+
}
|
|
1139
1232
|
},
|
|
1140
1233
|
destroyed() {
|
|
1141
|
-
|
|
1234
|
+
if (this.scrollContainer) {
|
|
1235
|
+
this.scrollContainer.removeEventListener("scroll", this.onScroll);
|
|
1236
|
+
} else {
|
|
1237
|
+
window.removeEventListener("scroll", this.onScroll);
|
|
1238
|
+
}
|
|
1142
1239
|
},
|
|
1143
1240
|
throttle(interval, callback) {
|
|
1144
1241
|
let lastCallAt = 0;
|
|
@@ -1585,6 +1682,7 @@ function morphdomFactory(morphAttrs2) {
|
|
|
1585
1682
|
removeNode(curFromNodeChild, fromEl, true);
|
|
1586
1683
|
}
|
|
1587
1684
|
curFromNodeChild = matchingFromEl;
|
|
1685
|
+
curFromNodeKey = getNodeKey(curFromNodeChild);
|
|
1588
1686
|
}
|
|
1589
1687
|
} else {
|
|
1590
1688
|
isCompatible = false;
|
|
@@ -1717,6 +1815,7 @@ var DOMPatch = class {
|
|
|
1717
1815
|
this.html = html;
|
|
1718
1816
|
this.streams = streams;
|
|
1719
1817
|
this.streamInserts = {};
|
|
1818
|
+
this.streamComponentRestore = {};
|
|
1720
1819
|
this.targetCID = targetCID;
|
|
1721
1820
|
this.cidPatch = isCid(this.targetCID);
|
|
1722
1821
|
this.pendingRemoves = [];
|
|
@@ -1746,7 +1845,6 @@ var DOMPatch = class {
|
|
|
1746
1845
|
}
|
|
1747
1846
|
markPrunableContentForRemoval() {
|
|
1748
1847
|
let phxUpdate = this.liveSocket.binding(PHX_UPDATE);
|
|
1749
|
-
dom_default.all(this.container, `[${phxUpdate}=${PHX_STREAM}]`, (el) => el.innerHTML = "");
|
|
1750
1848
|
dom_default.all(this.container, `[${phxUpdate}=append] > *, [${phxUpdate}=prepend] > *`, (el) => {
|
|
1751
1849
|
el.setAttribute(PHX_PRUNE, "");
|
|
1752
1850
|
});
|
|
@@ -1761,12 +1859,13 @@ var DOMPatch = class {
|
|
|
1761
1859
|
let { selectionStart, selectionEnd } = focused && dom_default.hasSelectionRange(focused) ? focused : {};
|
|
1762
1860
|
let phxUpdate = liveSocket.binding(PHX_UPDATE);
|
|
1763
1861
|
let phxFeedbackFor = liveSocket.binding(PHX_FEEDBACK_FOR);
|
|
1862
|
+
let phxFeedbackGroup = liveSocket.binding(PHX_FEEDBACK_GROUP);
|
|
1764
1863
|
let disableWith = liveSocket.binding(PHX_DISABLE_WITH);
|
|
1765
1864
|
let phxViewportTop = liveSocket.binding(PHX_VIEWPORT_TOP);
|
|
1766
1865
|
let phxViewportBottom = liveSocket.binding(PHX_VIEWPORT_BOTTOM);
|
|
1767
1866
|
let phxTriggerExternal = liveSocket.binding(PHX_TRIGGER_ACTION);
|
|
1768
1867
|
let added = [];
|
|
1769
|
-
let
|
|
1868
|
+
let trackedForms = new Set();
|
|
1770
1869
|
let updates = [];
|
|
1771
1870
|
let appendPrependUpdates = [];
|
|
1772
1871
|
let externalFormTriggered = null;
|
|
@@ -1774,16 +1873,12 @@ var DOMPatch = class {
|
|
|
1774
1873
|
this.trackBefore("updated", container, container);
|
|
1775
1874
|
liveSocket.time("morphdom", () => {
|
|
1776
1875
|
this.streams.forEach(([ref, inserts, deleteIds, reset]) => {
|
|
1777
|
-
|
|
1778
|
-
this.streamInserts[key] = { ref, streamAt, limit,
|
|
1876
|
+
inserts.forEach(([key, streamAt, limit]) => {
|
|
1877
|
+
this.streamInserts[key] = { ref, streamAt, limit, reset };
|
|
1779
1878
|
});
|
|
1780
1879
|
if (reset !== void 0) {
|
|
1781
1880
|
dom_default.all(container, `[${PHX_STREAM_REF}="${ref}"]`, (child) => {
|
|
1782
|
-
|
|
1783
|
-
this.streamInserts[child.id].resetKept = true;
|
|
1784
|
-
} else {
|
|
1785
|
-
this.removeStreamChildElement(child);
|
|
1786
|
-
}
|
|
1881
|
+
this.removeStreamChildElement(child);
|
|
1787
1882
|
});
|
|
1788
1883
|
}
|
|
1789
1884
|
deleteIds.forEach((id) => {
|
|
@@ -1793,6 +1888,17 @@ var DOMPatch = class {
|
|
|
1793
1888
|
}
|
|
1794
1889
|
});
|
|
1795
1890
|
});
|
|
1891
|
+
if (isJoinPatch) {
|
|
1892
|
+
dom_default.all(this.container, `[${phxUpdate}=${PHX_STREAM}]`, (el) => {
|
|
1893
|
+
this.liveSocket.owner(el, (view2) => {
|
|
1894
|
+
if (view2 === this.view) {
|
|
1895
|
+
Array.from(el.children).forEach((child) => {
|
|
1896
|
+
this.removeStreamChildElement(child);
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
});
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1796
1902
|
morphdom_esm_default(targetContainer, html, {
|
|
1797
1903
|
childrenOnly: targetContainer.getAttribute(PHX_COMPONENT) === null,
|
|
1798
1904
|
getNodeKey: (node) => {
|
|
@@ -1808,11 +1914,17 @@ var DOMPatch = class {
|
|
|
1808
1914
|
return from.getAttribute(phxUpdate) === PHX_STREAM;
|
|
1809
1915
|
},
|
|
1810
1916
|
addChild: (parent, child) => {
|
|
1811
|
-
let { ref, streamAt
|
|
1917
|
+
let { ref, streamAt } = this.getStreamInsert(child);
|
|
1812
1918
|
if (ref === void 0) {
|
|
1813
1919
|
return parent.appendChild(child);
|
|
1814
1920
|
}
|
|
1815
|
-
|
|
1921
|
+
this.setStreamRef(child, ref);
|
|
1922
|
+
child.querySelectorAll(`[${PHX_MAGIC_ID}][${PHX_SKIP}]`).forEach((el) => {
|
|
1923
|
+
const component = this.streamComponentRestore[el.getAttribute(PHX_MAGIC_ID)];
|
|
1924
|
+
if (component) {
|
|
1925
|
+
el.replaceWith(component);
|
|
1926
|
+
}
|
|
1927
|
+
});
|
|
1816
1928
|
if (streamAt === 0) {
|
|
1817
1929
|
parent.insertAdjacentElement("afterbegin", child);
|
|
1818
1930
|
} else if (streamAt === -1) {
|
|
@@ -1821,18 +1933,6 @@ var DOMPatch = class {
|
|
|
1821
1933
|
let sibling = Array.from(parent.children)[streamAt];
|
|
1822
1934
|
parent.insertBefore(child, sibling);
|
|
1823
1935
|
}
|
|
1824
|
-
let children = limit !== null && Array.from(parent.children);
|
|
1825
|
-
let childrenToRemove = [];
|
|
1826
|
-
if (limit && limit < 0 && children.length > limit * -1) {
|
|
1827
|
-
childrenToRemove = children.slice(0, children.length + limit);
|
|
1828
|
-
} else if (limit && limit >= 0 && children.length > limit) {
|
|
1829
|
-
childrenToRemove = children.slice(limit);
|
|
1830
|
-
}
|
|
1831
|
-
childrenToRemove.forEach((removeChild) => {
|
|
1832
|
-
if (!this.streamInserts[removeChild.id]) {
|
|
1833
|
-
this.removeStreamChildElement(removeChild);
|
|
1834
|
-
}
|
|
1835
|
-
});
|
|
1836
1936
|
},
|
|
1837
1937
|
onBeforeNodeAdded: (el) => {
|
|
1838
1938
|
dom_default.maybeAddPrivateHooks(el, phxViewportTop, phxViewportBottom);
|
|
@@ -1841,7 +1941,7 @@ var DOMPatch = class {
|
|
|
1841
1941
|
},
|
|
1842
1942
|
onNodeAdded: (el) => {
|
|
1843
1943
|
if (el.getAttribute) {
|
|
1844
|
-
this.maybeReOrderStream(el);
|
|
1944
|
+
this.maybeReOrderStream(el, true);
|
|
1845
1945
|
}
|
|
1846
1946
|
if (el instanceof HTMLImageElement && el.srcset) {
|
|
1847
1947
|
el.srcset = el.srcset;
|
|
@@ -1852,32 +1952,13 @@ var DOMPatch = class {
|
|
|
1852
1952
|
externalFormTriggered = el;
|
|
1853
1953
|
}
|
|
1854
1954
|
if (el.getAttribute && el.getAttribute("name") && dom_default.isFormInput(el)) {
|
|
1855
|
-
|
|
1955
|
+
trackedForms.add(el.form);
|
|
1856
1956
|
}
|
|
1857
1957
|
if (dom_default.isPhxChild(el) && view.ownsElement(el) || dom_default.isPhxSticky(el) && view.ownsElement(el.parentNode)) {
|
|
1858
1958
|
this.trackAfter("phxChildAdded", el);
|
|
1859
1959
|
}
|
|
1860
1960
|
added.push(el);
|
|
1861
1961
|
},
|
|
1862
|
-
onBeforeElChildrenUpdated: (fromEl, toEl) => {
|
|
1863
|
-
if (fromEl.getAttribute(phxUpdate) === PHX_STREAM) {
|
|
1864
|
-
let toIds = Array.from(toEl.children).map((child) => child.id);
|
|
1865
|
-
Array.from(fromEl.children).filter((child) => {
|
|
1866
|
-
let { resetKept } = this.getStreamInsert(child);
|
|
1867
|
-
return resetKept;
|
|
1868
|
-
}).sort((a, b) => {
|
|
1869
|
-
let aIdx = toIds.indexOf(a.id);
|
|
1870
|
-
let bIdx = toIds.indexOf(b.id);
|
|
1871
|
-
if (aIdx === bIdx) {
|
|
1872
|
-
return 0;
|
|
1873
|
-
} else if (aIdx < bIdx) {
|
|
1874
|
-
return -1;
|
|
1875
|
-
} else {
|
|
1876
|
-
return 1;
|
|
1877
|
-
}
|
|
1878
|
-
}).forEach((child) => fromEl.appendChild(child));
|
|
1879
|
-
}
|
|
1880
|
-
},
|
|
1881
1962
|
onNodeDiscarded: (el) => this.onNodeDiscarded(el),
|
|
1882
1963
|
onBeforeNodeDiscarded: (el) => {
|
|
1883
1964
|
if (el.getAttribute && el.getAttribute(PHX_PRUNE) !== null) {
|
|
@@ -1899,12 +1980,13 @@ var DOMPatch = class {
|
|
|
1899
1980
|
externalFormTriggered = el;
|
|
1900
1981
|
}
|
|
1901
1982
|
updates.push(el);
|
|
1902
|
-
this.maybeReOrderStream(el);
|
|
1983
|
+
this.maybeReOrderStream(el, false);
|
|
1903
1984
|
},
|
|
1904
1985
|
onBeforeElUpdated: (fromEl, toEl) => {
|
|
1905
1986
|
dom_default.maybeAddPrivateHooks(toEl, phxViewportTop, phxViewportBottom);
|
|
1906
1987
|
dom_default.cleanChildNodes(toEl, phxUpdate);
|
|
1907
1988
|
if (this.skipCIDSibling(toEl)) {
|
|
1989
|
+
this.maybeReOrderStream(fromEl);
|
|
1908
1990
|
return false;
|
|
1909
1991
|
}
|
|
1910
1992
|
if (dom_default.isPhxSticky(fromEl)) {
|
|
@@ -1940,22 +2022,26 @@ var DOMPatch = class {
|
|
|
1940
2022
|
}
|
|
1941
2023
|
dom_default.copyPrivates(toEl, fromEl);
|
|
1942
2024
|
let isFocusedFormEl = focused && fromEl.isSameNode(focused) && dom_default.isFormInput(fromEl);
|
|
1943
|
-
|
|
2025
|
+
let focusedSelectChanged = isFocusedFormEl && this.isChangedSelect(fromEl, toEl);
|
|
2026
|
+
if (isFocusedFormEl && fromEl.type !== "hidden" && !focusedSelectChanged) {
|
|
1944
2027
|
this.trackBefore("updated", fromEl, toEl);
|
|
1945
2028
|
dom_default.mergeFocusedInput(fromEl, toEl);
|
|
1946
2029
|
dom_default.syncAttrsToProps(fromEl);
|
|
1947
2030
|
updates.push(fromEl);
|
|
1948
2031
|
dom_default.applyStickyOperations(fromEl);
|
|
1949
|
-
|
|
2032
|
+
trackedForms.add(fromEl.form);
|
|
1950
2033
|
return false;
|
|
1951
2034
|
} else {
|
|
2035
|
+
if (focusedSelectChanged) {
|
|
2036
|
+
fromEl.blur();
|
|
2037
|
+
}
|
|
1952
2038
|
if (dom_default.isPhxUpdate(toEl, phxUpdate, ["append", "prepend"])) {
|
|
1953
2039
|
appendPrependUpdates.push(new DOMPostMorphRestorer(fromEl, toEl, toEl.getAttribute(phxUpdate)));
|
|
1954
2040
|
}
|
|
1955
2041
|
dom_default.syncAttrsToProps(toEl);
|
|
1956
2042
|
dom_default.applyStickyOperations(toEl);
|
|
1957
2043
|
if (toEl.getAttribute("name") && dom_default.isFormInput(toEl)) {
|
|
1958
|
-
|
|
2044
|
+
trackedForms.add(toEl.form);
|
|
1959
2045
|
}
|
|
1960
2046
|
this.trackBefore("updated", fromEl, toEl);
|
|
1961
2047
|
return true;
|
|
@@ -1971,7 +2057,7 @@ var DOMPatch = class {
|
|
|
1971
2057
|
appendPrependUpdates.forEach((update) => update.perform());
|
|
1972
2058
|
});
|
|
1973
2059
|
}
|
|
1974
|
-
dom_default.maybeHideFeedback(targetContainer,
|
|
2060
|
+
dom_default.maybeHideFeedback(targetContainer, trackedForms, phxFeedbackFor, phxFeedbackGroup);
|
|
1975
2061
|
liveSocket.silenceEvents(() => dom_default.restoreFocus(focused, selectionStart, selectionEnd));
|
|
1976
2062
|
dom_default.dispatchEvent(document, "phx:update");
|
|
1977
2063
|
added.forEach((el) => this.trackAfter("added", el));
|
|
@@ -1999,6 +2085,11 @@ var DOMPatch = class {
|
|
|
1999
2085
|
}
|
|
2000
2086
|
removeStreamChildElement(child) {
|
|
2001
2087
|
if (!this.maybePendingRemove(child)) {
|
|
2088
|
+
if (this.streamInserts[child.id]) {
|
|
2089
|
+
child.querySelectorAll(`[${PHX_MAGIC_ID}]`).forEach((el) => {
|
|
2090
|
+
this.streamComponentRestore[el.getAttribute(PHX_MAGIC_ID)] = el;
|
|
2091
|
+
});
|
|
2092
|
+
}
|
|
2002
2093
|
child.remove();
|
|
2003
2094
|
this.onNodeDiscarded(child);
|
|
2004
2095
|
}
|
|
@@ -2007,12 +2098,18 @@ var DOMPatch = class {
|
|
|
2007
2098
|
let insert = el.id ? this.streamInserts[el.id] : {};
|
|
2008
2099
|
return insert || {};
|
|
2009
2100
|
}
|
|
2010
|
-
|
|
2011
|
-
|
|
2101
|
+
setStreamRef(el, ref) {
|
|
2102
|
+
dom_default.putSticky(el, PHX_STREAM_REF, (el2) => el2.setAttribute(PHX_STREAM_REF, ref));
|
|
2103
|
+
}
|
|
2104
|
+
maybeReOrderStream(el, isNew) {
|
|
2105
|
+
let { ref, streamAt, reset } = this.getStreamInsert(el);
|
|
2012
2106
|
if (streamAt === void 0) {
|
|
2013
2107
|
return;
|
|
2014
2108
|
}
|
|
2015
|
-
|
|
2109
|
+
this.setStreamRef(el, ref);
|
|
2110
|
+
if (!reset && !isNew) {
|
|
2111
|
+
return;
|
|
2112
|
+
}
|
|
2016
2113
|
if (streamAt === 0) {
|
|
2017
2114
|
el.parentElement.insertBefore(el, el.parentElement.firstElementChild);
|
|
2018
2115
|
} else if (streamAt > 0) {
|
|
@@ -2029,6 +2126,16 @@ var DOMPatch = class {
|
|
|
2029
2126
|
}
|
|
2030
2127
|
}
|
|
2031
2128
|
}
|
|
2129
|
+
this.maybeLimitStream(el);
|
|
2130
|
+
}
|
|
2131
|
+
maybeLimitStream(el) {
|
|
2132
|
+
let { limit } = this.getStreamInsert(el);
|
|
2133
|
+
let children = limit !== null && Array.from(el.parentElement.children);
|
|
2134
|
+
if (limit && limit < 0 && children.length > limit * -1) {
|
|
2135
|
+
children.slice(0, children.length + limit).forEach((child) => this.removeStreamChildElement(child));
|
|
2136
|
+
} else if (limit && limit >= 0 && children.length > limit) {
|
|
2137
|
+
children.slice(limit).forEach((child) => this.removeStreamChildElement(child));
|
|
2138
|
+
}
|
|
2032
2139
|
}
|
|
2033
2140
|
transitionPendingRemoves() {
|
|
2034
2141
|
let { pendingRemoves, liveSocket } = this;
|
|
@@ -2046,6 +2153,20 @@ var DOMPatch = class {
|
|
|
2046
2153
|
});
|
|
2047
2154
|
}
|
|
2048
2155
|
}
|
|
2156
|
+
isChangedSelect(fromEl, toEl) {
|
|
2157
|
+
if (!(fromEl instanceof HTMLSelectElement) || fromEl.multiple) {
|
|
2158
|
+
return false;
|
|
2159
|
+
}
|
|
2160
|
+
if (fromEl.options.length !== toEl.options.length) {
|
|
2161
|
+
return true;
|
|
2162
|
+
}
|
|
2163
|
+
let fromSelected = fromEl.selectedOptions[0];
|
|
2164
|
+
let toSelected = toEl.selectedOptions[0];
|
|
2165
|
+
if (fromSelected && fromSelected.hasAttribute("selected")) {
|
|
2166
|
+
toSelected.setAttribute("selected", fromSelected.getAttribute("selected"));
|
|
2167
|
+
}
|
|
2168
|
+
return !fromEl.isEqualNode(toEl);
|
|
2169
|
+
}
|
|
2049
2170
|
isCIDPatch() {
|
|
2050
2171
|
return this.cidPatch;
|
|
2051
2172
|
}
|
|
@@ -2087,66 +2208,42 @@ var VOID_TAGS = new Set([
|
|
|
2087
2208
|
"track",
|
|
2088
2209
|
"wbr"
|
|
2089
2210
|
]);
|
|
2090
|
-
var endingTagNameChars = new Set([">", "/", " ", "\n", " ", "\r"]);
|
|
2091
2211
|
var quoteChars = new Set(["'", '"']);
|
|
2092
2212
|
var modifyRoot = (html, attrs, clearInnerHTML) => {
|
|
2093
2213
|
let i = 0;
|
|
2094
2214
|
let insideComment = false;
|
|
2095
2215
|
let beforeTag, afterTag, tag, tagNameEndsAt, id, newHTML;
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
let iAtOpen = i;
|
|
2216
|
+
let lookahead = html.match(/^(\s*(?:<!--.*?-->\s*)*)<([^\s\/>]+)/);
|
|
2217
|
+
if (lookahead === null) {
|
|
2218
|
+
throw new Error(`malformed html ${html}`);
|
|
2219
|
+
}
|
|
2220
|
+
i = lookahead[0].length;
|
|
2221
|
+
beforeTag = lookahead[1];
|
|
2222
|
+
tag = lookahead[2];
|
|
2223
|
+
tagNameEndsAt = i;
|
|
2224
|
+
for (i; i < html.length; i++) {
|
|
2225
|
+
if (html.charAt(i) === ">") {
|
|
2226
|
+
break;
|
|
2227
|
+
}
|
|
2228
|
+
if (html.charAt(i) === "=") {
|
|
2229
|
+
let isId = html.slice(i - 3, i) === " id";
|
|
2111
2230
|
i++;
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2231
|
+
let char = html.charAt(i);
|
|
2232
|
+
if (quoteChars.has(char)) {
|
|
2233
|
+
let attrStartsAt = i;
|
|
2234
|
+
i++;
|
|
2235
|
+
for (i; i < html.length; i++) {
|
|
2236
|
+
if (html.charAt(i) === char) {
|
|
2237
|
+
break;
|
|
2238
|
+
}
|
|
2115
2239
|
}
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
tag = html.slice(iAtOpen + 1, tagNameEndsAt);
|
|
2119
|
-
for (i; i < html.length; i++) {
|
|
2120
|
-
if (html.charAt(i) === ">") {
|
|
2240
|
+
if (isId) {
|
|
2241
|
+
id = html.slice(attrStartsAt + 1, i);
|
|
2121
2242
|
break;
|
|
2122
2243
|
}
|
|
2123
|
-
if (html.charAt(i) === "=") {
|
|
2124
|
-
let isId = html.slice(i - 3, i) === " id";
|
|
2125
|
-
i++;
|
|
2126
|
-
let char2 = html.charAt(i);
|
|
2127
|
-
if (quoteChars.has(char2)) {
|
|
2128
|
-
let attrStartsAt = i;
|
|
2129
|
-
i++;
|
|
2130
|
-
for (i; i < html.length; i++) {
|
|
2131
|
-
if (html.charAt(i) === char2) {
|
|
2132
|
-
break;
|
|
2133
|
-
}
|
|
2134
|
-
}
|
|
2135
|
-
if (isId) {
|
|
2136
|
-
id = html.slice(attrStartsAt + 1, i);
|
|
2137
|
-
break;
|
|
2138
|
-
}
|
|
2139
|
-
}
|
|
2140
|
-
}
|
|
2141
2244
|
}
|
|
2142
|
-
break;
|
|
2143
|
-
} else {
|
|
2144
|
-
i++;
|
|
2145
2245
|
}
|
|
2146
2246
|
}
|
|
2147
|
-
if (!tag) {
|
|
2148
|
-
throw new Error(`malformed html ${html}`);
|
|
2149
|
-
}
|
|
2150
2247
|
let closeAt = html.length - 1;
|
|
2151
2248
|
insideComment = false;
|
|
2152
2249
|
while (closeAt >= beforeTag.length + tag.length) {
|
|
@@ -2221,6 +2318,11 @@ var Rendered = class {
|
|
|
2221
2318
|
getComponent(diff, cid) {
|
|
2222
2319
|
return diff[COMPONENTS][cid];
|
|
2223
2320
|
}
|
|
2321
|
+
resetRender(cid) {
|
|
2322
|
+
if (this.rendered[COMPONENTS][cid]) {
|
|
2323
|
+
this.rendered[COMPONENTS][cid].reset = true;
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2224
2326
|
mergeDiff(diff) {
|
|
2225
2327
|
let newc = diff[COMPONENTS];
|
|
2226
2328
|
let cache = {};
|
|
@@ -2348,8 +2450,8 @@ var Rendered = class {
|
|
|
2348
2450
|
if (isRoot) {
|
|
2349
2451
|
let skip = false;
|
|
2350
2452
|
let attrs;
|
|
2351
|
-
if (changeTracking ||
|
|
2352
|
-
skip = !rendered.newRender;
|
|
2453
|
+
if (changeTracking || rendered.magicId) {
|
|
2454
|
+
skip = changeTracking && !rendered.newRender;
|
|
2353
2455
|
attrs = { [PHX_MAGIC_ID]: rendered.magicId, ...rootAttrs };
|
|
2354
2456
|
} else {
|
|
2355
2457
|
attrs = rootAttrs;
|
|
@@ -2399,8 +2501,9 @@ var Rendered = class {
|
|
|
2399
2501
|
let skip = onlyCids && !onlyCids.has(cid);
|
|
2400
2502
|
component.newRender = !skip;
|
|
2401
2503
|
component.magicId = `${this.parentViewId()}-c-${cid}`;
|
|
2402
|
-
let changeTracking =
|
|
2504
|
+
let changeTracking = !component.reset;
|
|
2403
2505
|
let [html, streams] = this.recursiveToString(component, components, onlyCids, changeTracking, attrs);
|
|
2506
|
+
delete component.reset;
|
|
2404
2507
|
return [html, streams];
|
|
2405
2508
|
}
|
|
2406
2509
|
};
|
|
@@ -2484,6 +2587,7 @@ var ViewHook = class {
|
|
|
2484
2587
|
|
|
2485
2588
|
// js/phoenix_live_view/js.js
|
|
2486
2589
|
var focusStack = null;
|
|
2590
|
+
var default_transition_time = 200;
|
|
2487
2591
|
var JS = {
|
|
2488
2592
|
exec(eventType, phxEvent, view, sourceEl, defaults) {
|
|
2489
2593
|
let [defaultKind, defaultArgs] = defaults || [null, { callback: defaults && defaults.callback }];
|
|
@@ -2505,7 +2609,7 @@ var JS = {
|
|
|
2505
2609
|
const rect = el.getBoundingClientRect();
|
|
2506
2610
|
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
|
|
2507
2611
|
},
|
|
2508
|
-
exec_exec(eventType, phxEvent, view, sourceEl, el,
|
|
2612
|
+
exec_exec(eventType, phxEvent, view, sourceEl, el, { attr, to }) {
|
|
2509
2613
|
let nodes = to ? dom_default.all(document, to) : [sourceEl];
|
|
2510
2614
|
nodes.forEach((node) => {
|
|
2511
2615
|
let encodedJS = node.getAttribute(attr);
|
|
@@ -2521,14 +2625,14 @@ var JS = {
|
|
|
2521
2625
|
dom_default.dispatchEvent(el, event, { detail, bubbles });
|
|
2522
2626
|
},
|
|
2523
2627
|
exec_push(eventType, phxEvent, view, sourceEl, el, args) {
|
|
2524
|
-
if (!view.isConnected()) {
|
|
2525
|
-
return;
|
|
2526
|
-
}
|
|
2527
2628
|
let { event, data, target, page_loading, loading, value, dispatcher, callback } = args;
|
|
2528
2629
|
let pushOpts = { loading, value, target, page_loading: !!page_loading };
|
|
2529
2630
|
let targetSrc = eventType === "change" && dispatcher ? dispatcher : sourceEl;
|
|
2530
2631
|
let phxTarget = target || targetSrc.getAttribute(view.binding("target")) || targetSrc;
|
|
2531
2632
|
view.withinTargets(phxTarget, (targetView, targetCtx) => {
|
|
2633
|
+
if (!targetView.isConnected()) {
|
|
2634
|
+
return;
|
|
2635
|
+
}
|
|
2532
2636
|
if (eventType === "change") {
|
|
2533
2637
|
let { newCid, _target } = args;
|
|
2534
2638
|
_target = _target || (dom_default.isFormInput(sourceEl) ? sourceEl.name : void 0);
|
|
@@ -2573,6 +2677,24 @@ var JS = {
|
|
|
2573
2677
|
exec_remove_class(eventType, phxEvent, view, sourceEl, el, { names, transition, time }) {
|
|
2574
2678
|
this.addOrRemoveClasses(el, [], names, transition, time, view);
|
|
2575
2679
|
},
|
|
2680
|
+
exec_toggle_class(eventType, phxEvent, view, sourceEl, el, { to, names, transition, time }) {
|
|
2681
|
+
this.toggleClasses(el, names, transition, view);
|
|
2682
|
+
},
|
|
2683
|
+
exec_toggle_attr(eventType, phxEvent, view, sourceEl, el, { attr: [attr, val1, val2] }) {
|
|
2684
|
+
if (el.hasAttribute(attr)) {
|
|
2685
|
+
if (val2 !== void 0) {
|
|
2686
|
+
if (el.getAttribute(attr) === val1) {
|
|
2687
|
+
this.setOrRemoveAttrs(el, [[attr, val2]], []);
|
|
2688
|
+
} else {
|
|
2689
|
+
this.setOrRemoveAttrs(el, [[attr, val1]], []);
|
|
2690
|
+
}
|
|
2691
|
+
} else {
|
|
2692
|
+
this.setOrRemoveAttrs(el, [], [attr]);
|
|
2693
|
+
}
|
|
2694
|
+
} else {
|
|
2695
|
+
this.setOrRemoveAttrs(el, [[attr, val1]], []);
|
|
2696
|
+
}
|
|
2697
|
+
},
|
|
2576
2698
|
exec_transition(eventType, phxEvent, view, sourceEl, el, { time, transition }) {
|
|
2577
2699
|
this.addOrRemoveClasses(el, [], [], transition, time, view);
|
|
2578
2700
|
},
|
|
@@ -2602,6 +2724,7 @@ var JS = {
|
|
|
2602
2724
|
}
|
|
2603
2725
|
},
|
|
2604
2726
|
toggle(eventType, view, el, display, ins, outs, time) {
|
|
2727
|
+
time = time || default_transition_time;
|
|
2605
2728
|
let [inClasses, inStartClasses, inEndClasses] = ins || [[], [], []];
|
|
2606
2729
|
let [outClasses, outStartClasses, outEndClasses] = outs || [[], [], []];
|
|
2607
2730
|
if (inClasses.length > 0 || outClasses.length > 0) {
|
|
@@ -2655,7 +2778,16 @@ var JS = {
|
|
|
2655
2778
|
}
|
|
2656
2779
|
}
|
|
2657
2780
|
},
|
|
2781
|
+
toggleClasses(el, classes, transition, time, view) {
|
|
2782
|
+
window.requestAnimationFrame(() => {
|
|
2783
|
+
let [prevAdds, prevRemoves] = dom_default.getSticky(el, "classes", [[], []]);
|
|
2784
|
+
let newAdds = classes.filter((name) => prevAdds.indexOf(name) < 0 && !el.classList.contains(name));
|
|
2785
|
+
let newRemoves = classes.filter((name) => prevRemoves.indexOf(name) < 0 && el.classList.contains(name));
|
|
2786
|
+
this.addOrRemoveClasses(el, newAdds, newRemoves, transition, time, view);
|
|
2787
|
+
});
|
|
2788
|
+
},
|
|
2658
2789
|
addOrRemoveClasses(el, adds, removes, transition, time, view) {
|
|
2790
|
+
time = time || default_transition_time;
|
|
2659
2791
|
let [transitionRun, transitionStart, transitionEnd] = transition || [[], [], []];
|
|
2660
2792
|
if (transitionRun.length > 0) {
|
|
2661
2793
|
let onStart = () => {
|
|
@@ -2709,24 +2841,37 @@ var js_default = JS;
|
|
|
2709
2841
|
|
|
2710
2842
|
// js/phoenix_live_view/view.js
|
|
2711
2843
|
var serializeForm = (form, metadata, onlyNames = []) => {
|
|
2712
|
-
|
|
2713
|
-
let
|
|
2714
|
-
if (submitter && submitter.
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2844
|
+
const { submitter, ...meta } = metadata;
|
|
2845
|
+
let injectedElement;
|
|
2846
|
+
if (submitter && submitter.name) {
|
|
2847
|
+
const input = document.createElement("input");
|
|
2848
|
+
input.type = "hidden";
|
|
2849
|
+
const formId = submitter.getAttribute("form");
|
|
2850
|
+
if (formId) {
|
|
2851
|
+
input.setAttribute("form", form);
|
|
2852
|
+
}
|
|
2853
|
+
input.name = submitter.name;
|
|
2854
|
+
input.value = submitter.value;
|
|
2855
|
+
submitter.parentElement.insertBefore(input, submitter);
|
|
2856
|
+
injectedElement = input;
|
|
2857
|
+
}
|
|
2858
|
+
const formData = new FormData(form);
|
|
2859
|
+
const toRemove = [];
|
|
2718
2860
|
formData.forEach((val, key, _index) => {
|
|
2719
2861
|
if (val instanceof File) {
|
|
2720
2862
|
toRemove.push(key);
|
|
2721
2863
|
}
|
|
2722
2864
|
});
|
|
2723
2865
|
toRemove.forEach((key) => formData.delete(key));
|
|
2724
|
-
|
|
2866
|
+
const params = new URLSearchParams();
|
|
2725
2867
|
for (let [key, val] of formData.entries()) {
|
|
2726
2868
|
if (onlyNames.length === 0 || onlyNames.indexOf(key) >= 0) {
|
|
2727
2869
|
params.append(key, val);
|
|
2728
2870
|
}
|
|
2729
2871
|
}
|
|
2872
|
+
if (submitter && injectedElement) {
|
|
2873
|
+
submitter.parentElement.removeChild(injectedElement);
|
|
2874
|
+
}
|
|
2730
2875
|
for (let metaKey in meta) {
|
|
2731
2876
|
params.append(metaKey, meta[metaKey]);
|
|
2732
2877
|
}
|
|
@@ -2930,6 +3075,9 @@ var View = class {
|
|
|
2930
3075
|
if (phxStatic) {
|
|
2931
3076
|
toEl.setAttribute(PHX_STATIC, phxStatic);
|
|
2932
3077
|
}
|
|
3078
|
+
if (fromEl) {
|
|
3079
|
+
fromEl.setAttribute(PHX_ROOT_ID, this.root.id);
|
|
3080
|
+
}
|
|
2933
3081
|
return this.joinChild(toEl);
|
|
2934
3082
|
});
|
|
2935
3083
|
if (newChildren.length === 0) {
|
|
@@ -3009,6 +3157,9 @@ var View = class {
|
|
|
3009
3157
|
let updatedHookIds = new Set();
|
|
3010
3158
|
patch.after("added", (el) => {
|
|
3011
3159
|
this.liveSocket.triggerDOM("onNodeAdded", [el]);
|
|
3160
|
+
let phxViewportTop = this.binding(PHX_VIEWPORT_TOP);
|
|
3161
|
+
let phxViewportBottom = this.binding(PHX_VIEWPORT_BOTTOM);
|
|
3162
|
+
dom_default.maybeAddPrivateHooks(el, phxViewportTop, phxViewportBottom);
|
|
3012
3163
|
this.maybeAddNewHook(el);
|
|
3013
3164
|
if (el.getAttribute) {
|
|
3014
3165
|
this.maybeMounted(el);
|
|
@@ -3385,10 +3536,11 @@ var View = class {
|
|
|
3385
3536
|
}
|
|
3386
3537
|
dom_default.all(document, `[${PHX_REF_SRC}="${this.id}"][${PHX_REF}="${ref}"]`, (el) => {
|
|
3387
3538
|
let disabledVal = el.getAttribute(PHX_DISABLED);
|
|
3539
|
+
let readOnlyVal = el.getAttribute(PHX_READONLY);
|
|
3388
3540
|
el.removeAttribute(PHX_REF);
|
|
3389
3541
|
el.removeAttribute(PHX_REF_SRC);
|
|
3390
|
-
if (
|
|
3391
|
-
el.readOnly = false;
|
|
3542
|
+
if (readOnlyVal !== null) {
|
|
3543
|
+
el.readOnly = readOnlyVal === "true" ? true : false;
|
|
3392
3544
|
el.removeAttribute(PHX_READONLY);
|
|
3393
3545
|
}
|
|
3394
3546
|
if (disabledVal !== null) {
|
|
@@ -3430,6 +3582,7 @@ var View = class {
|
|
|
3430
3582
|
if (disableText !== "") {
|
|
3431
3583
|
el.innerText = disableText;
|
|
3432
3584
|
}
|
|
3585
|
+
el.setAttribute(PHX_DISABLED, el.getAttribute(PHX_DISABLED) || el.disabled);
|
|
3433
3586
|
el.setAttribute("disabled", "");
|
|
3434
3587
|
}
|
|
3435
3588
|
});
|
|
@@ -3531,6 +3684,9 @@ var View = class {
|
|
|
3531
3684
|
let refGenerator = () => this.putRef([inputEl, inputEl.form], "change", opts);
|
|
3532
3685
|
let formData;
|
|
3533
3686
|
let meta = this.extractMeta(inputEl.form);
|
|
3687
|
+
if (inputEl instanceof HTMLButtonElement) {
|
|
3688
|
+
meta.submitter = inputEl;
|
|
3689
|
+
}
|
|
3534
3690
|
if (inputEl.getAttribute(this.binding("change"))) {
|
|
3535
3691
|
formData = serializeForm(inputEl.form, { _target: opts._target, ...meta }, [inputEl.name]);
|
|
3536
3692
|
} else {
|
|
@@ -3555,6 +3711,7 @@ var View = class {
|
|
|
3555
3711
|
this.uploadFiles(inputEl.form, targetCtx, ref, cid, (_uploads) => {
|
|
3556
3712
|
callback && callback(resp);
|
|
3557
3713
|
this.triggerAwaitingSubmit(inputEl.form);
|
|
3714
|
+
this.undoRefs(ref);
|
|
3558
3715
|
});
|
|
3559
3716
|
}
|
|
3560
3717
|
} else {
|
|
@@ -3753,7 +3910,7 @@ var View = class {
|
|
|
3753
3910
|
let template = document.createElement("template");
|
|
3754
3911
|
template.innerHTML = html;
|
|
3755
3912
|
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) => {
|
|
3756
|
-
const phxChangeValue = form.getAttribute(phxChange)
|
|
3913
|
+
const phxChangeValue = CSS.escape(form.getAttribute(phxChange));
|
|
3757
3914
|
let newForm = template.content.querySelector(`form[id="${form.id}"][${phxChange}="${phxChangeValue}"]`);
|
|
3758
3915
|
if (newForm) {
|
|
3759
3916
|
return [form, newForm, this.targetComponentID(newForm)];
|
|
@@ -3763,18 +3920,19 @@ var View = class {
|
|
|
3763
3920
|
}).filter(([form, newForm, newCid]) => newForm);
|
|
3764
3921
|
}
|
|
3765
3922
|
maybePushComponentsDestroyed(destroyedCIDs) {
|
|
3766
|
-
let willDestroyCIDs = destroyedCIDs.filter((cid) => {
|
|
3923
|
+
let willDestroyCIDs = destroyedCIDs.concat(this.pruningCIDs).filter((cid) => {
|
|
3767
3924
|
return dom_default.findComponentNodeList(this.el, cid).length === 0;
|
|
3768
3925
|
});
|
|
3926
|
+
this.pruningCIDs = willDestroyCIDs.concat([]);
|
|
3769
3927
|
if (willDestroyCIDs.length > 0) {
|
|
3770
|
-
this.
|
|
3928
|
+
willDestroyCIDs.forEach((cid) => this.rendered.resetRender(cid));
|
|
3771
3929
|
this.pushWithReply(null, "cids_will_destroy", { cids: willDestroyCIDs }, () => {
|
|
3772
|
-
this.pruningCIDs = this.pruningCIDs.filter((cid) => willDestroyCIDs.indexOf(cid) !== -1);
|
|
3773
3930
|
let completelyDestroyCIDs = willDestroyCIDs.filter((cid) => {
|
|
3774
3931
|
return dom_default.findComponentNodeList(this.el, cid).length === 0;
|
|
3775
3932
|
});
|
|
3776
3933
|
if (completelyDestroyCIDs.length > 0) {
|
|
3777
3934
|
this.pushWithReply(null, "cids_destroyed", { cids: completelyDestroyCIDs }, (resp) => {
|
|
3935
|
+
this.pruningCIDs = this.pruningCIDs.filter((cid) => resp.cids.indexOf(cid) === -1);
|
|
3778
3936
|
this.rendered.pruneCIDs(resp.cids);
|
|
3779
3937
|
});
|
|
3780
3938
|
}
|
|
@@ -4090,22 +4248,26 @@ var LiveSocket = class {
|
|
|
4090
4248
|
this.main.destroy();
|
|
4091
4249
|
this.main = this.newRootView(newMainEl, flash, liveReferer);
|
|
4092
4250
|
this.main.setRedirect(href);
|
|
4093
|
-
this.transitionRemoves();
|
|
4251
|
+
this.transitionRemoves(null, true);
|
|
4094
4252
|
this.main.join((joinCount, onDone) => {
|
|
4095
4253
|
if (joinCount === 1 && this.commitPendingLink(linkRef)) {
|
|
4096
4254
|
this.requestDOMUpdate(() => {
|
|
4097
4255
|
dom_default.findPhxSticky(document).forEach((el) => newMainEl.appendChild(el));
|
|
4098
4256
|
this.outgoingMainEl.replaceWith(newMainEl);
|
|
4099
4257
|
this.outgoingMainEl = null;
|
|
4100
|
-
callback &&
|
|
4258
|
+
callback && callback(linkRef);
|
|
4101
4259
|
onDone();
|
|
4102
4260
|
});
|
|
4103
4261
|
}
|
|
4104
4262
|
});
|
|
4105
4263
|
}
|
|
4106
|
-
transitionRemoves(elements) {
|
|
4264
|
+
transitionRemoves(elements, skipSticky) {
|
|
4107
4265
|
let removeAttr = this.binding("remove");
|
|
4108
4266
|
elements = elements || dom_default.all(document, `[${removeAttr}]`);
|
|
4267
|
+
if (skipSticky) {
|
|
4268
|
+
const stickies = dom_default.findPhxSticky(document) || [];
|
|
4269
|
+
elements = elements.filter((el) => !dom_default.isChildOfAny(el, stickies));
|
|
4270
|
+
}
|
|
4109
4271
|
elements.forEach((el) => {
|
|
4110
4272
|
this.execJS(el, el.getAttribute(removeAttr), "remove");
|
|
4111
4273
|
});
|
|
@@ -4321,6 +4483,8 @@ var LiveSocket = class {
|
|
|
4321
4483
|
if (capture) {
|
|
4322
4484
|
target = e.target.matches(`[${click}]`) ? e.target : e.target.querySelector(`[${click}]`);
|
|
4323
4485
|
} else {
|
|
4486
|
+
if (e.detail === 0)
|
|
4487
|
+
this.clickStartedAtTarget = e.target;
|
|
4324
4488
|
let clickStartedAtTarget = this.clickStartedAtTarget || e.target;
|
|
4325
4489
|
target = closestPhxBinding(clickStartedAtTarget, click);
|
|
4326
4490
|
this.dispatchClickAway(e, clickStartedAtTarget);
|
|
@@ -4350,7 +4514,7 @@ var LiveSocket = class {
|
|
|
4350
4514
|
let phxClickAway = this.binding("click-away");
|
|
4351
4515
|
dom_default.all(document, `[${phxClickAway}]`, (el) => {
|
|
4352
4516
|
if (!(el.isSameNode(clickStartedAt) || el.contains(clickStartedAt))) {
|
|
4353
|
-
this.withinOwners(
|
|
4517
|
+
this.withinOwners(el, (view) => {
|
|
4354
4518
|
let phxEvent = el.getAttribute(phxClickAway);
|
|
4355
4519
|
if (js_default.isVisible(el) && js_default.isInViewport(el)) {
|
|
4356
4520
|
js_default.exec("click", phxEvent, view, el, ["push", { data: this.eventMeta("click", e, e.target) }]);
|
|
@@ -4442,7 +4606,7 @@ var LiveSocket = class {
|
|
|
4442
4606
|
return callback ? callback(done) : done;
|
|
4443
4607
|
}
|
|
4444
4608
|
pushHistoryPatch(href, linkState, targetEl) {
|
|
4445
|
-
if (!this.isConnected()) {
|
|
4609
|
+
if (!this.isConnected() || !this.main.isMain()) {
|
|
4446
4610
|
return browser_default.redirect(href);
|
|
4447
4611
|
}
|
|
4448
4612
|
this.withPageLoading({ to: href, kind: "patch" }, (done) => {
|
|
@@ -4461,7 +4625,7 @@ var LiveSocket = class {
|
|
|
4461
4625
|
this.registerNewLocation(window.location);
|
|
4462
4626
|
}
|
|
4463
4627
|
historyRedirect(href, linkState, flash) {
|
|
4464
|
-
if (!this.isConnected()) {
|
|
4628
|
+
if (!this.isConnected() || !this.main.isMain()) {
|
|
4465
4629
|
return browser_default.redirect(href, flash);
|
|
4466
4630
|
}
|
|
4467
4631
|
if (/^\/$|^\/[^\/]+.*$/.test(href)) {
|
|
@@ -4562,9 +4726,11 @@ var LiveSocket = class {
|
|
|
4562
4726
|
let form = e.target;
|
|
4563
4727
|
dom_default.resetForm(form, this.binding(PHX_FEEDBACK_FOR));
|
|
4564
4728
|
let input = Array.from(form.elements).find((el) => el.type === "reset");
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4729
|
+
if (input) {
|
|
4730
|
+
window.requestAnimationFrame(() => {
|
|
4731
|
+
input.dispatchEvent(new Event("input", { bubbles: true, cancelable: false }));
|
|
4732
|
+
});
|
|
4733
|
+
}
|
|
4568
4734
|
});
|
|
4569
4735
|
}
|
|
4570
4736
|
debounce(el, event, eventType, callback) {
|