phoenix_live_view 0.20.0 → 0.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -9
- package/assets/js/phoenix_live_view/aria.js +1 -1
- package/assets/js/phoenix_live_view/constants.js +3 -1
- package/assets/js/phoenix_live_view/dom.js +9 -4
- package/assets/js/phoenix_live_view/dom_patch.js +35 -45
- package/assets/js/phoenix_live_view/entry_uploader.js +1 -0
- package/assets/js/phoenix_live_view/js.js +10 -0
- package/assets/js/phoenix_live_view/live_socket.js +9 -7
- package/assets/js/phoenix_live_view/live_uploader.js +1 -0
- package/assets/js/phoenix_live_view/rendered.js +216 -71
- package/assets/js/phoenix_live_view/upload_entry.js +2 -1
- package/assets/js/phoenix_live_view/view.js +23 -10
- package/assets/js/phoenix_live_view/view_hook.js +4 -2
- package/assets/package.json +2 -2
- package/package.json +1 -1
- package/priv/static/phoenix_live_view.cjs.js +266 -131
- package/priv/static/phoenix_live_view.cjs.js.map +2 -2
- package/priv/static/phoenix_live_view.esm.js +266 -131
- package/priv/static/phoenix_live_view.esm.js.map +2 -2
- package/priv/static/phoenix_live_view.js +266 -131
- package/priv/static/phoenix_live_view.min.js +5 -10
|
@@ -27,6 +27,7 @@ var PHX_DROP_TARGET = "drop-target";
|
|
|
27
27
|
var PHX_ACTIVE_ENTRY_REFS = "data-phx-active-refs";
|
|
28
28
|
var PHX_LIVE_FILE_UPDATED = "phx:live-file:updated";
|
|
29
29
|
var PHX_SKIP = "data-phx-skip";
|
|
30
|
+
var PHX_MAGIC_ID = "data-phx-id";
|
|
30
31
|
var PHX_PRUNE = "data-phx-prune";
|
|
31
32
|
var PHX_PAGE_LOADING = "page-loading";
|
|
32
33
|
var PHX_CONNECTED_CLASS = "phx-connected";
|
|
@@ -81,6 +82,7 @@ var DEFAULTS = {
|
|
|
81
82
|
};
|
|
82
83
|
var DYNAMICS = "d";
|
|
83
84
|
var STATIC = "s";
|
|
85
|
+
var ROOT = "r";
|
|
84
86
|
var COMPONENTS = "c";
|
|
85
87
|
var EVENTS = "e";
|
|
86
88
|
var REPLY = "r";
|
|
@@ -103,6 +105,7 @@ var EntryUploader = class {
|
|
|
103
105
|
if (this.errored) {
|
|
104
106
|
return;
|
|
105
107
|
}
|
|
108
|
+
this.uploadChannel.leave();
|
|
106
109
|
this.errored = true;
|
|
107
110
|
clearTimeout(this.chunkTimer);
|
|
108
111
|
this.entry.error(reason);
|
|
@@ -522,12 +525,17 @@ var DOM = {
|
|
|
522
525
|
el.setAttribute("data-phx-hook", "Phoenix.InfiniteScroll");
|
|
523
526
|
}
|
|
524
527
|
},
|
|
525
|
-
maybeHideFeedback(container,
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
if (input.
|
|
529
|
-
feedbacks.push(input.name
|
|
528
|
+
maybeHideFeedback(container, inputs, phxFeedbackFor) {
|
|
529
|
+
let feedbacks = [];
|
|
530
|
+
inputs.forEach((input) => {
|
|
531
|
+
if (!(this.private(input, PHX_HAS_FOCUSED) || this.private(input, PHX_HAS_SUBMITTED))) {
|
|
532
|
+
feedbacks.push(input.name);
|
|
533
|
+
if (input.name.endsWith("[]")) {
|
|
534
|
+
feedbacks.push(input.name.slice(0, -2));
|
|
535
|
+
}
|
|
530
536
|
}
|
|
537
|
+
});
|
|
538
|
+
if (feedbacks.length > 0) {
|
|
531
539
|
let selector = feedbacks.map((f) => `[${phxFeedbackFor}="${f}"]`).join(", ");
|
|
532
540
|
DOM.all(container, selector, (el) => el.classList.add(PHX_NO_FEEDBACK_CLASS));
|
|
533
541
|
}
|
|
@@ -814,7 +822,8 @@ var UploadEntry = class {
|
|
|
814
822
|
relative_path: this.file.webkitRelativePath,
|
|
815
823
|
size: this.file.size,
|
|
816
824
|
type: this.file.type,
|
|
817
|
-
ref: this.ref
|
|
825
|
+
ref: this.ref,
|
|
826
|
+
meta: typeof this.file.meta === "function" ? this.file.meta() : void 0
|
|
818
827
|
};
|
|
819
828
|
}
|
|
820
829
|
uploader(uploaders) {
|
|
@@ -871,6 +880,9 @@ var LiveUploader = class {
|
|
|
871
880
|
entry.relative_path = file.webkitRelativePath;
|
|
872
881
|
entry.type = file.type;
|
|
873
882
|
entry.size = file.size;
|
|
883
|
+
if (typeof file.meta === "function") {
|
|
884
|
+
entry.meta = file.meta();
|
|
885
|
+
}
|
|
874
886
|
fileData[uploadRef].push(entry);
|
|
875
887
|
});
|
|
876
888
|
return fileData;
|
|
@@ -960,7 +972,7 @@ var ARIA = {
|
|
|
960
972
|
return classes.find((name) => instance instanceof name);
|
|
961
973
|
},
|
|
962
974
|
isFocusable(el, interactiveOnly) {
|
|
963
|
-
return el instanceof HTMLAnchorElement && el.rel !== "ignore" || el instanceof HTMLAreaElement && el.href !== void 0 || !el.disabled && this.anyOf(el, [HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement, HTMLButtonElement]) || el instanceof HTMLIFrameElement || (el.tabIndex > 0 || !interactiveOnly && el.
|
|
975
|
+
return el instanceof HTMLAnchorElement && el.rel !== "ignore" || el instanceof HTMLAreaElement && el.href !== void 0 || !el.disabled && this.anyOf(el, [HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement, HTMLButtonElement]) || el instanceof HTMLIFrameElement || (el.tabIndex > 0 || !interactiveOnly && el.getAttribute("tabindex") !== null && el.getAttribute("aria-hidden") !== "true");
|
|
964
976
|
},
|
|
965
977
|
attemptFocus(el, interactiveOnly) {
|
|
966
978
|
if (this.isFocusable(el, interactiveOnly)) {
|
|
@@ -1536,7 +1548,7 @@ function morphdomFactory(morphAttrs2) {
|
|
|
1536
1548
|
}
|
|
1537
1549
|
}
|
|
1538
1550
|
function morphChildren(fromEl, toEl) {
|
|
1539
|
-
var skipFrom = skipFromChildren(fromEl);
|
|
1551
|
+
var skipFrom = skipFromChildren(fromEl, toEl);
|
|
1540
1552
|
var curToNodeChild = toEl.firstChild;
|
|
1541
1553
|
var curFromNodeChild = fromEl.firstChild;
|
|
1542
1554
|
var curToNodeKey;
|
|
@@ -1739,7 +1751,7 @@ var DOMPatch = class {
|
|
|
1739
1751
|
el.setAttribute(PHX_PRUNE, "");
|
|
1740
1752
|
});
|
|
1741
1753
|
}
|
|
1742
|
-
perform() {
|
|
1754
|
+
perform(isJoinPatch) {
|
|
1743
1755
|
let { view, liveSocket, container, html } = this;
|
|
1744
1756
|
let targetContainer = this.isCIDPatch() ? this.targetCIDContainer(html) : container;
|
|
1745
1757
|
if (this.isCIDPatch() && !targetContainer) {
|
|
@@ -1758,19 +1770,18 @@ var DOMPatch = class {
|
|
|
1758
1770
|
let updates = [];
|
|
1759
1771
|
let appendPrependUpdates = [];
|
|
1760
1772
|
let externalFormTriggered = null;
|
|
1761
|
-
let diffHTML = liveSocket.time("premorph container prep", () => {
|
|
1762
|
-
return this.buildDiffHTML(container, html, phxUpdate, targetContainer);
|
|
1763
|
-
});
|
|
1764
1773
|
this.trackBefore("added", container);
|
|
1765
1774
|
this.trackBefore("updated", container, container);
|
|
1766
1775
|
liveSocket.time("morphdom", () => {
|
|
1767
1776
|
this.streams.forEach(([ref, inserts, deleteIds, reset]) => {
|
|
1768
1777
|
Object.entries(inserts).forEach(([key, [streamAt, limit]]) => {
|
|
1769
|
-
this.streamInserts[key] = { ref, streamAt, limit };
|
|
1778
|
+
this.streamInserts[key] = { ref, streamAt, limit, resetKept: false };
|
|
1770
1779
|
});
|
|
1771
1780
|
if (reset !== void 0) {
|
|
1772
1781
|
dom_default.all(container, `[${PHX_STREAM_REF}="${ref}"]`, (child) => {
|
|
1773
|
-
if (
|
|
1782
|
+
if (inserts[child.id]) {
|
|
1783
|
+
this.streamInserts[child.id].resetKept = true;
|
|
1784
|
+
} else {
|
|
1774
1785
|
this.removeStreamChildElement(child);
|
|
1775
1786
|
}
|
|
1776
1787
|
});
|
|
@@ -1782,10 +1793,16 @@ var DOMPatch = class {
|
|
|
1782
1793
|
}
|
|
1783
1794
|
});
|
|
1784
1795
|
});
|
|
1785
|
-
morphdom_esm_default(targetContainer,
|
|
1796
|
+
morphdom_esm_default(targetContainer, html, {
|
|
1786
1797
|
childrenOnly: targetContainer.getAttribute(PHX_COMPONENT) === null,
|
|
1787
1798
|
getNodeKey: (node) => {
|
|
1788
|
-
|
|
1799
|
+
if (dom_default.isPhxDestroyed(node)) {
|
|
1800
|
+
return null;
|
|
1801
|
+
}
|
|
1802
|
+
if (isJoinPatch) {
|
|
1803
|
+
return node.id;
|
|
1804
|
+
}
|
|
1805
|
+
return node.id || node.getAttribute && node.getAttribute(PHX_MAGIC_ID);
|
|
1789
1806
|
},
|
|
1790
1807
|
skipFromChildren: (from) => {
|
|
1791
1808
|
return from.getAttribute(phxUpdate) === PHX_STREAM;
|
|
@@ -1842,6 +1859,25 @@ var DOMPatch = class {
|
|
|
1842
1859
|
}
|
|
1843
1860
|
added.push(el);
|
|
1844
1861
|
},
|
|
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
|
+
},
|
|
1845
1881
|
onNodeDiscarded: (el) => this.onNodeDiscarded(el),
|
|
1846
1882
|
onBeforeNodeDiscarded: (el) => {
|
|
1847
1883
|
if (el.getAttribute && el.getAttribute(PHX_PRUNE) !== null) {
|
|
@@ -1935,9 +1971,7 @@ var DOMPatch = class {
|
|
|
1935
1971
|
appendPrependUpdates.forEach((update) => update.perform());
|
|
1936
1972
|
});
|
|
1937
1973
|
}
|
|
1938
|
-
|
|
1939
|
-
dom_default.maybeHideFeedback(targetContainer, input, phxFeedbackFor);
|
|
1940
|
-
});
|
|
1974
|
+
dom_default.maybeHideFeedback(targetContainer, trackedInputs, phxFeedbackFor);
|
|
1941
1975
|
liveSocket.silenceEvents(() => dom_default.restoreFocus(focused, selectionStart, selectionEnd));
|
|
1942
1976
|
dom_default.dispatchEvent(document, "phx:update");
|
|
1943
1977
|
added.forEach((el) => this.trackAfter("added", el));
|
|
@@ -2016,7 +2050,7 @@ var DOMPatch = class {
|
|
|
2016
2050
|
return this.cidPatch;
|
|
2017
2051
|
}
|
|
2018
2052
|
skipCIDSibling(el) {
|
|
2019
|
-
return el.nodeType === Node.ELEMENT_NODE && el.
|
|
2053
|
+
return el.nodeType === Node.ELEMENT_NODE && el.hasAttribute(PHX_SKIP);
|
|
2020
2054
|
}
|
|
2021
2055
|
targetCIDContainer(html) {
|
|
2022
2056
|
if (!this.isCIDPatch()) {
|
|
@@ -2029,35 +2063,125 @@ var DOMPatch = class {
|
|
|
2029
2063
|
return first && first.parentNode;
|
|
2030
2064
|
}
|
|
2031
2065
|
}
|
|
2032
|
-
buildDiffHTML(container, html, phxUpdate, targetContainer) {
|
|
2033
|
-
let isCIDPatch = this.isCIDPatch();
|
|
2034
|
-
let isCIDWithSingleRoot = isCIDPatch && targetContainer.getAttribute(PHX_COMPONENT) === this.targetCID.toString();
|
|
2035
|
-
if (!isCIDPatch || isCIDWithSingleRoot) {
|
|
2036
|
-
return html;
|
|
2037
|
-
} else {
|
|
2038
|
-
let diffContainer = null;
|
|
2039
|
-
let template = document.createElement("template");
|
|
2040
|
-
diffContainer = dom_default.cloneNode(targetContainer);
|
|
2041
|
-
let [firstComponent, ...rest] = dom_default.findComponentNodeList(diffContainer, this.targetCID);
|
|
2042
|
-
template.innerHTML = html;
|
|
2043
|
-
rest.forEach((el) => el.remove());
|
|
2044
|
-
Array.from(diffContainer.childNodes).forEach((child) => {
|
|
2045
|
-
if (child.id && child.nodeType === Node.ELEMENT_NODE && child.getAttribute(PHX_COMPONENT) !== this.targetCID.toString()) {
|
|
2046
|
-
child.setAttribute(PHX_SKIP, "");
|
|
2047
|
-
child.innerHTML = "";
|
|
2048
|
-
}
|
|
2049
|
-
});
|
|
2050
|
-
Array.from(template.content.childNodes).forEach((el) => diffContainer.insertBefore(el, firstComponent));
|
|
2051
|
-
firstComponent.remove();
|
|
2052
|
-
return diffContainer.outerHTML;
|
|
2053
|
-
}
|
|
2054
|
-
}
|
|
2055
2066
|
indexOf(parent, child) {
|
|
2056
2067
|
return Array.from(parent.children).indexOf(child);
|
|
2057
2068
|
}
|
|
2058
2069
|
};
|
|
2059
2070
|
|
|
2060
2071
|
// js/phoenix_live_view/rendered.js
|
|
2072
|
+
var VOID_TAGS = new Set([
|
|
2073
|
+
"area",
|
|
2074
|
+
"base",
|
|
2075
|
+
"br",
|
|
2076
|
+
"col",
|
|
2077
|
+
"command",
|
|
2078
|
+
"embed",
|
|
2079
|
+
"hr",
|
|
2080
|
+
"img",
|
|
2081
|
+
"input",
|
|
2082
|
+
"keygen",
|
|
2083
|
+
"link",
|
|
2084
|
+
"meta",
|
|
2085
|
+
"param",
|
|
2086
|
+
"source",
|
|
2087
|
+
"track",
|
|
2088
|
+
"wbr"
|
|
2089
|
+
]);
|
|
2090
|
+
var endingTagNameChars = new Set([">", "/", " ", "\n", " ", "\r"]);
|
|
2091
|
+
var quoteChars = new Set(["'", '"']);
|
|
2092
|
+
var modifyRoot = (html, attrs, clearInnerHTML) => {
|
|
2093
|
+
let i = 0;
|
|
2094
|
+
let insideComment = false;
|
|
2095
|
+
let beforeTag, afterTag, tag, tagNameEndsAt, id, newHTML;
|
|
2096
|
+
while (i < html.length) {
|
|
2097
|
+
let char = html.charAt(i);
|
|
2098
|
+
if (insideComment) {
|
|
2099
|
+
if (char === "-" && html.slice(i, i + 3) === "-->") {
|
|
2100
|
+
insideComment = false;
|
|
2101
|
+
i += 3;
|
|
2102
|
+
} else {
|
|
2103
|
+
i++;
|
|
2104
|
+
}
|
|
2105
|
+
} else if (char === "<" && html.slice(i, i + 4) === "<!--") {
|
|
2106
|
+
insideComment = true;
|
|
2107
|
+
i += 4;
|
|
2108
|
+
} else if (char === "<") {
|
|
2109
|
+
beforeTag = html.slice(0, i);
|
|
2110
|
+
let iAtOpen = i;
|
|
2111
|
+
i++;
|
|
2112
|
+
for (i; i < html.length; i++) {
|
|
2113
|
+
if (endingTagNameChars.has(html.charAt(i))) {
|
|
2114
|
+
break;
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
tagNameEndsAt = i;
|
|
2118
|
+
tag = html.slice(iAtOpen + 1, tagNameEndsAt);
|
|
2119
|
+
for (i; i < html.length; i++) {
|
|
2120
|
+
if (html.charAt(i) === ">") {
|
|
2121
|
+
break;
|
|
2122
|
+
}
|
|
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
|
+
}
|
|
2142
|
+
break;
|
|
2143
|
+
} else {
|
|
2144
|
+
i++;
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
if (!tag) {
|
|
2148
|
+
throw new Error(`malformed html ${html}`);
|
|
2149
|
+
}
|
|
2150
|
+
let closeAt = html.length - 1;
|
|
2151
|
+
insideComment = false;
|
|
2152
|
+
while (closeAt >= beforeTag.length + tag.length) {
|
|
2153
|
+
let char = html.charAt(closeAt);
|
|
2154
|
+
if (insideComment) {
|
|
2155
|
+
if (char === "-" && html.slice(closeAt - 3, closeAt) === "<!-") {
|
|
2156
|
+
insideComment = false;
|
|
2157
|
+
closeAt -= 4;
|
|
2158
|
+
} else {
|
|
2159
|
+
closeAt -= 1;
|
|
2160
|
+
}
|
|
2161
|
+
} else if (char === ">" && html.slice(closeAt - 2, closeAt) === "--") {
|
|
2162
|
+
insideComment = true;
|
|
2163
|
+
closeAt -= 3;
|
|
2164
|
+
} else if (char === ">") {
|
|
2165
|
+
break;
|
|
2166
|
+
} else {
|
|
2167
|
+
closeAt -= 1;
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
afterTag = html.slice(closeAt + 1, html.length);
|
|
2171
|
+
let attrsStr = Object.keys(attrs).map((attr) => attrs[attr] === true ? attr : `${attr}="${attrs[attr]}"`).join(" ");
|
|
2172
|
+
if (clearInnerHTML) {
|
|
2173
|
+
let idAttrStr = id ? ` id="${id}"` : "";
|
|
2174
|
+
if (VOID_TAGS.has(tag)) {
|
|
2175
|
+
newHTML = `<${tag}${idAttrStr}${attrsStr === "" ? "" : " "}${attrsStr}/>`;
|
|
2176
|
+
} else {
|
|
2177
|
+
newHTML = `<${tag}${idAttrStr}${attrsStr === "" ? "" : " "}${attrsStr}></${tag}>`;
|
|
2178
|
+
}
|
|
2179
|
+
} else {
|
|
2180
|
+
let rest = html.slice(tagNameEndsAt, closeAt + 1);
|
|
2181
|
+
newHTML = `<${tag}${attrsStr === "" ? "" : " "}${attrsStr}${rest}`;
|
|
2182
|
+
}
|
|
2183
|
+
return [newHTML, beforeTag, afterTag];
|
|
2184
|
+
};
|
|
2061
2185
|
var Rendered = class {
|
|
2062
2186
|
static extract(diff) {
|
|
2063
2187
|
let { [REPLY]: reply, [EVENTS]: events, [TITLE]: title } = diff;
|
|
@@ -2069,19 +2193,20 @@ var Rendered = class {
|
|
|
2069
2193
|
constructor(viewId, rendered) {
|
|
2070
2194
|
this.viewId = viewId;
|
|
2071
2195
|
this.rendered = {};
|
|
2196
|
+
this.magicId = 0;
|
|
2072
2197
|
this.mergeDiff(rendered);
|
|
2073
2198
|
}
|
|
2074
2199
|
parentViewId() {
|
|
2075
2200
|
return this.viewId;
|
|
2076
2201
|
}
|
|
2077
2202
|
toString(onlyCids) {
|
|
2078
|
-
let [str, streams] = this.recursiveToString(this.rendered, this.rendered[COMPONENTS], onlyCids);
|
|
2203
|
+
let [str, streams] = this.recursiveToString(this.rendered, this.rendered[COMPONENTS], onlyCids, true, {});
|
|
2079
2204
|
return [str, streams];
|
|
2080
2205
|
}
|
|
2081
|
-
recursiveToString(rendered, components = rendered[COMPONENTS], onlyCids) {
|
|
2206
|
+
recursiveToString(rendered, components = rendered[COMPONENTS], onlyCids, changeTracking, rootAttrs) {
|
|
2082
2207
|
onlyCids = onlyCids ? new Set(onlyCids) : null;
|
|
2083
2208
|
let output = { buffer: "", components, onlyCids, streams: new Set() };
|
|
2084
|
-
this.toOutputBuffer(rendered, null, output);
|
|
2209
|
+
this.toOutputBuffer(rendered, null, output, changeTracking, rootAttrs);
|
|
2085
2210
|
return [output.buffer, output.streams];
|
|
2086
2211
|
}
|
|
2087
2212
|
componentCIDs(diff) {
|
|
@@ -2126,10 +2251,10 @@ var Rendered = class {
|
|
|
2126
2251
|
tdiff = oldc[-scid];
|
|
2127
2252
|
}
|
|
2128
2253
|
stat = tdiff[STATIC];
|
|
2129
|
-
ndiff = this.cloneMerge(tdiff, cdiff);
|
|
2254
|
+
ndiff = this.cloneMerge(tdiff, cdiff, true);
|
|
2130
2255
|
ndiff[STATIC] = stat;
|
|
2131
2256
|
} else {
|
|
2132
|
-
ndiff = cdiff[STATIC] !== void 0 ? cdiff : this.cloneMerge(oldc[cid]
|
|
2257
|
+
ndiff = cdiff[STATIC] !== void 0 || oldc[cid] === void 0 ? cdiff : this.cloneMerge(oldc[cid], cdiff, false);
|
|
2133
2258
|
}
|
|
2134
2259
|
cache[cid] = ndiff;
|
|
2135
2260
|
return ndiff;
|
|
@@ -2154,21 +2279,31 @@ var Rendered = class {
|
|
|
2154
2279
|
target[key] = val;
|
|
2155
2280
|
}
|
|
2156
2281
|
}
|
|
2282
|
+
if (target[ROOT]) {
|
|
2283
|
+
target.newRender = true;
|
|
2284
|
+
}
|
|
2157
2285
|
}
|
|
2158
|
-
cloneMerge(target, source) {
|
|
2286
|
+
cloneMerge(target, source, pruneMagicId) {
|
|
2159
2287
|
let merged = { ...target, ...source };
|
|
2160
2288
|
for (let key in merged) {
|
|
2161
2289
|
let val = source[key];
|
|
2162
2290
|
let targetVal = target[key];
|
|
2163
2291
|
if (isObject(val) && val[STATIC] === void 0 && isObject(targetVal)) {
|
|
2164
|
-
merged[key] = this.cloneMerge(targetVal, val);
|
|
2292
|
+
merged[key] = this.cloneMerge(targetVal, val, pruneMagicId);
|
|
2165
2293
|
}
|
|
2166
2294
|
}
|
|
2295
|
+
if (pruneMagicId) {
|
|
2296
|
+
delete merged.magicId;
|
|
2297
|
+
delete merged.newRender;
|
|
2298
|
+
} else if (target[ROOT]) {
|
|
2299
|
+
merged.newRender = true;
|
|
2300
|
+
}
|
|
2167
2301
|
return merged;
|
|
2168
2302
|
}
|
|
2169
2303
|
componentToString(cid) {
|
|
2170
|
-
let [str, streams] = this.recursiveCIDToString(this.rendered[COMPONENTS], cid, null
|
|
2171
|
-
|
|
2304
|
+
let [str, streams] = this.recursiveCIDToString(this.rendered[COMPONENTS], cid, null);
|
|
2305
|
+
let [strippedHTML, _before, _after] = modifyRoot(str, {});
|
|
2306
|
+
return [strippedHTML, streams];
|
|
2172
2307
|
}
|
|
2173
2308
|
pruneCIDs(cids) {
|
|
2174
2309
|
cids.forEach((cid) => delete this.rendered[COMPONENTS][cid]);
|
|
@@ -2186,17 +2321,46 @@ var Rendered = class {
|
|
|
2186
2321
|
return part;
|
|
2187
2322
|
}
|
|
2188
2323
|
}
|
|
2189
|
-
|
|
2324
|
+
nextMagicID() {
|
|
2325
|
+
this.magicId++;
|
|
2326
|
+
return `${this.parentViewId()}-${this.magicId}`;
|
|
2327
|
+
}
|
|
2328
|
+
toOutputBuffer(rendered, templates, output, changeTracking, rootAttrs = {}) {
|
|
2190
2329
|
if (rendered[DYNAMICS]) {
|
|
2191
2330
|
return this.comprehensionToBuffer(rendered, templates, output);
|
|
2192
2331
|
}
|
|
2193
2332
|
let { [STATIC]: statics } = rendered;
|
|
2194
2333
|
statics = this.templateStatic(statics, templates);
|
|
2334
|
+
let isRoot = rendered[ROOT];
|
|
2335
|
+
let prevBuffer = output.buffer;
|
|
2336
|
+
if (isRoot) {
|
|
2337
|
+
output.buffer = "";
|
|
2338
|
+
}
|
|
2339
|
+
if (changeTracking && isRoot && !rendered.magicId) {
|
|
2340
|
+
rendered.newRender = true;
|
|
2341
|
+
rendered.magicId = this.nextMagicID();
|
|
2342
|
+
}
|
|
2195
2343
|
output.buffer += statics[0];
|
|
2196
2344
|
for (let i = 1; i < statics.length; i++) {
|
|
2197
|
-
this.dynamicToBuffer(rendered[i - 1], templates, output);
|
|
2345
|
+
this.dynamicToBuffer(rendered[i - 1], templates, output, changeTracking);
|
|
2198
2346
|
output.buffer += statics[i];
|
|
2199
2347
|
}
|
|
2348
|
+
if (isRoot) {
|
|
2349
|
+
let skip = false;
|
|
2350
|
+
let attrs;
|
|
2351
|
+
if (changeTracking || Object.keys(rootAttrs).length > 0) {
|
|
2352
|
+
skip = !rendered.newRender;
|
|
2353
|
+
attrs = { [PHX_MAGIC_ID]: rendered.magicId, ...rootAttrs };
|
|
2354
|
+
} else {
|
|
2355
|
+
attrs = rootAttrs;
|
|
2356
|
+
}
|
|
2357
|
+
if (skip) {
|
|
2358
|
+
attrs[PHX_SKIP] = true;
|
|
2359
|
+
}
|
|
2360
|
+
let [newRoot, commentBefore, commentAfter] = modifyRoot(output.buffer, attrs, skip);
|
|
2361
|
+
rendered.newRender = false;
|
|
2362
|
+
output.buffer = prevBuffer + commentBefore + newRoot + commentAfter;
|
|
2363
|
+
}
|
|
2200
2364
|
}
|
|
2201
2365
|
comprehensionToBuffer(rendered, templates, output) {
|
|
2202
2366
|
let { [DYNAMICS]: dynamics, [STATIC]: statics, [STREAM]: stream } = rendered;
|
|
@@ -2207,7 +2371,8 @@ var Rendered = class {
|
|
|
2207
2371
|
let dynamic = dynamics[d];
|
|
2208
2372
|
output.buffer += statics[0];
|
|
2209
2373
|
for (let i = 1; i < statics.length; i++) {
|
|
2210
|
-
|
|
2374
|
+
let changeTracking = false;
|
|
2375
|
+
this.dynamicToBuffer(dynamic[i - 1], compTemplates, output, changeTracking);
|
|
2211
2376
|
output.buffer += statics[i];
|
|
2212
2377
|
}
|
|
2213
2378
|
}
|
|
@@ -2217,74 +2382,26 @@ var Rendered = class {
|
|
|
2217
2382
|
output.streams.add(stream);
|
|
2218
2383
|
}
|
|
2219
2384
|
}
|
|
2220
|
-
dynamicToBuffer(rendered, templates, output) {
|
|
2385
|
+
dynamicToBuffer(rendered, templates, output, changeTracking) {
|
|
2221
2386
|
if (typeof rendered === "number") {
|
|
2222
2387
|
let [str, streams] = this.recursiveCIDToString(output.components, rendered, output.onlyCids);
|
|
2223
2388
|
output.buffer += str;
|
|
2224
2389
|
output.streams = new Set([...output.streams, ...streams]);
|
|
2225
2390
|
} else if (isObject(rendered)) {
|
|
2226
|
-
this.toOutputBuffer(rendered, templates, output);
|
|
2391
|
+
this.toOutputBuffer(rendered, templates, output, changeTracking, {});
|
|
2227
2392
|
} else {
|
|
2228
2393
|
output.buffer += rendered;
|
|
2229
2394
|
}
|
|
2230
2395
|
}
|
|
2231
|
-
recursiveCIDToString(components, cid, onlyCids
|
|
2396
|
+
recursiveCIDToString(components, cid, onlyCids) {
|
|
2232
2397
|
let component = components[cid] || logError(`no component for CID ${cid}`, components);
|
|
2233
|
-
let
|
|
2234
|
-
let [html, streams] = this.recursiveToString(component, components, onlyCids);
|
|
2235
|
-
template.innerHTML = html;
|
|
2236
|
-
let container = template.content;
|
|
2398
|
+
let attrs = { [PHX_COMPONENT]: cid };
|
|
2237
2399
|
let skip = onlyCids && !onlyCids.has(cid);
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
child.setAttribute(PHX_COMPONENT, cid);
|
|
2244
|
-
if (!child.id) {
|
|
2245
|
-
child.id = `${this.parentViewId()}-${cid}-${i}`;
|
|
2246
|
-
}
|
|
2247
|
-
if (skip) {
|
|
2248
|
-
child.setAttribute(PHX_SKIP, "");
|
|
2249
|
-
child.innerHTML = "";
|
|
2250
|
-
}
|
|
2251
|
-
return [true, hasComponents];
|
|
2252
|
-
} else if (child.nodeType === Node.COMMENT_NODE) {
|
|
2253
|
-
if (!allowRootComments) {
|
|
2254
|
-
child.remove();
|
|
2255
|
-
}
|
|
2256
|
-
return [hasNodes, hasComponents];
|
|
2257
|
-
} else {
|
|
2258
|
-
if (child.nodeValue.trim() !== "") {
|
|
2259
|
-
logError(`only HTML element tags are allowed at the root of components.
|
|
2260
|
-
|
|
2261
|
-
got: "${child.nodeValue.trim()}"
|
|
2262
|
-
|
|
2263
|
-
within:
|
|
2264
|
-
`, template.innerHTML.trim());
|
|
2265
|
-
child.replaceWith(this.createSpan(child.nodeValue, cid));
|
|
2266
|
-
return [true, hasComponents];
|
|
2267
|
-
} else {
|
|
2268
|
-
child.remove();
|
|
2269
|
-
return [hasNodes, hasComponents];
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
|
-
}, [false, false]);
|
|
2273
|
-
if (!hasChildNodes && !hasChildComponents) {
|
|
2274
|
-
logError("expected at least one HTML element tag inside a component, but the component is empty:\n", template.innerHTML.trim());
|
|
2275
|
-
return [this.createSpan("", cid).outerHTML, streams];
|
|
2276
|
-
} else if (!hasChildNodes && hasChildComponents) {
|
|
2277
|
-
logError("expected at least one HTML element tag directly inside a component, but only subcomponents were found. A component must render at least one HTML tag directly inside itself.", template.innerHTML.trim());
|
|
2278
|
-
return [template.innerHTML, streams];
|
|
2279
|
-
} else {
|
|
2280
|
-
return [template.innerHTML, streams];
|
|
2281
|
-
}
|
|
2282
|
-
}
|
|
2283
|
-
createSpan(text, cid) {
|
|
2284
|
-
let span = document.createElement("span");
|
|
2285
|
-
span.innerText = text;
|
|
2286
|
-
span.setAttribute(PHX_COMPONENT, cid);
|
|
2287
|
-
return span;
|
|
2400
|
+
component.newRender = !skip;
|
|
2401
|
+
component.magicId = `${this.parentViewId()}-c-${cid}`;
|
|
2402
|
+
let changeTracking = true;
|
|
2403
|
+
let [html, streams] = this.recursiveToString(component, components, onlyCids, changeTracking, attrs);
|
|
2404
|
+
return [html, streams];
|
|
2288
2405
|
}
|
|
2289
2406
|
};
|
|
2290
2407
|
|
|
@@ -2353,10 +2470,12 @@ var ViewHook = class {
|
|
|
2353
2470
|
this.__listeners.delete(callbackRef);
|
|
2354
2471
|
}
|
|
2355
2472
|
upload(name, files) {
|
|
2356
|
-
return this.__view.dispatchUploads(name, files);
|
|
2473
|
+
return this.__view.dispatchUploads(null, name, files);
|
|
2357
2474
|
}
|
|
2358
2475
|
uploadTo(phxTarget, name, files) {
|
|
2359
|
-
return this.__view.withinTargets(phxTarget, (view) =>
|
|
2476
|
+
return this.__view.withinTargets(phxTarget, (view, targetCtx) => {
|
|
2477
|
+
view.dispatchUploads(targetCtx, name, files);
|
|
2478
|
+
});
|
|
2360
2479
|
}
|
|
2361
2480
|
__cleanup__() {
|
|
2362
2481
|
this.__listeners.forEach((callbackRef) => this.removeHandleEvent(callbackRef));
|
|
@@ -2382,6 +2501,10 @@ var JS = {
|
|
|
2382
2501
|
isVisible(el) {
|
|
2383
2502
|
return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length > 0);
|
|
2384
2503
|
},
|
|
2504
|
+
isInViewport(el) {
|
|
2505
|
+
const rect = el.getBoundingClientRect();
|
|
2506
|
+
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
|
|
2507
|
+
},
|
|
2385
2508
|
exec_exec(eventType, phxEvent, view, sourceEl, el, [attr, to]) {
|
|
2386
2509
|
let nodes = to ? dom_default.all(document, to) : [sourceEl];
|
|
2387
2510
|
nodes.forEach((node) => {
|
|
@@ -2640,9 +2763,10 @@ var View = class {
|
|
|
2640
2763
|
this.children = this.parent ? null : {};
|
|
2641
2764
|
this.root.children[this.id] = {};
|
|
2642
2765
|
this.channel = this.liveSocket.channel(`lv:${this.id}`, () => {
|
|
2766
|
+
let url = this.href && this.expandURL(this.href);
|
|
2643
2767
|
return {
|
|
2644
|
-
redirect: this.redirect ?
|
|
2645
|
-
url: this.redirect ? void 0 :
|
|
2768
|
+
redirect: this.redirect ? url : void 0,
|
|
2769
|
+
url: this.redirect ? void 0 : url || void 0,
|
|
2646
2770
|
params: this.connectParams(liveReferer),
|
|
2647
2771
|
session: this.getSession(),
|
|
2648
2772
|
static: this.getStatic(),
|
|
@@ -2840,7 +2964,7 @@ var View = class {
|
|
|
2840
2964
|
this.attachTrueDocEl();
|
|
2841
2965
|
let patch = new DOMPatch(this, this.el, this.id, html, streams, null);
|
|
2842
2966
|
patch.markPrunableContentForRemoval();
|
|
2843
|
-
this.performPatch(patch, false);
|
|
2967
|
+
this.performPatch(patch, false, true);
|
|
2844
2968
|
this.joinNewChildren();
|
|
2845
2969
|
this.execNewMounted();
|
|
2846
2970
|
this.joinPending = false;
|
|
@@ -2879,7 +3003,7 @@ var View = class {
|
|
|
2879
3003
|
newHook.__mounted();
|
|
2880
3004
|
}
|
|
2881
3005
|
}
|
|
2882
|
-
performPatch(patch, pruneCids) {
|
|
3006
|
+
performPatch(patch, pruneCids, isJoinPatch = false) {
|
|
2883
3007
|
let removedEls = [];
|
|
2884
3008
|
let phxChildrenAdded = false;
|
|
2885
3009
|
let updatedHookIds = new Set();
|
|
@@ -2914,7 +3038,7 @@ var View = class {
|
|
|
2914
3038
|
}
|
|
2915
3039
|
});
|
|
2916
3040
|
patch.after("transitionsDiscarded", (els) => this.afterElementsRemoved(els, pruneCids));
|
|
2917
|
-
patch.perform();
|
|
3041
|
+
patch.perform(isJoinPatch);
|
|
2918
3042
|
this.afterElementsRemoved(removedEls, pruneCids);
|
|
2919
3043
|
return phxChildrenAdded;
|
|
2920
3044
|
}
|
|
@@ -3319,7 +3443,7 @@ var View = class {
|
|
|
3319
3443
|
if (isCid(targetCtx)) {
|
|
3320
3444
|
return targetCtx;
|
|
3321
3445
|
}
|
|
3322
|
-
let cidOrSelector = target.getAttribute(this.binding("target"));
|
|
3446
|
+
let cidOrSelector = opts.target || target.getAttribute(this.binding("target"));
|
|
3323
3447
|
if (isCid(cidOrSelector)) {
|
|
3324
3448
|
return parseInt(cidOrSelector);
|
|
3325
3449
|
} else if (targetCtx && (cidOrSelector !== null || opts.target)) {
|
|
@@ -3403,7 +3527,7 @@ var View = class {
|
|
|
3403
3527
|
}
|
|
3404
3528
|
pushInput(inputEl, targetCtx, forceCid, phxEvent, opts, callback) {
|
|
3405
3529
|
let uploads;
|
|
3406
|
-
let cid = isCid(forceCid) ? forceCid : this.targetComponentID(inputEl.form, targetCtx);
|
|
3530
|
+
let cid = isCid(forceCid) ? forceCid : this.targetComponentID(inputEl.form, targetCtx, opts);
|
|
3407
3531
|
let refGenerator = () => this.putRef([inputEl, inputEl.form], "change", opts);
|
|
3408
3532
|
let formData;
|
|
3409
3533
|
let meta = this.extractMeta(inputEl.form);
|
|
@@ -3499,7 +3623,7 @@ var View = class {
|
|
|
3499
3623
|
let cid = this.targetComponentID(formEl, targetCtx);
|
|
3500
3624
|
if (LiveUploader.hasUploadsInProgress(formEl)) {
|
|
3501
3625
|
let [ref, _els] = refGenerator();
|
|
3502
|
-
let push = () => this.pushFormSubmit(formEl,
|
|
3626
|
+
let push = () => this.pushFormSubmit(formEl, targetCtx, phxEvent, submitter, opts, onReply);
|
|
3503
3627
|
return this.scheduleSubmit(formEl, ref, opts, push);
|
|
3504
3628
|
} else if (LiveUploader.inputsAwaitingPreflight(formEl).length > 0) {
|
|
3505
3629
|
let [ref, els] = refGenerator();
|
|
@@ -3563,8 +3687,9 @@ var View = class {
|
|
|
3563
3687
|
});
|
|
3564
3688
|
});
|
|
3565
3689
|
}
|
|
3566
|
-
dispatchUploads(name, filesOrBlobs) {
|
|
3567
|
-
let
|
|
3690
|
+
dispatchUploads(targetCtx, name, filesOrBlobs) {
|
|
3691
|
+
let targetElement = this.targetCtxElement(targetCtx) || this.el;
|
|
3692
|
+
let inputs = dom_default.findUploadInputs(targetElement).filter((el) => el.name === name);
|
|
3568
3693
|
if (inputs.length === 0) {
|
|
3569
3694
|
logError(`no live file inputs found matching the name "${name}"`);
|
|
3570
3695
|
} else if (inputs.length > 1) {
|
|
@@ -3573,6 +3698,16 @@ var View = class {
|
|
|
3573
3698
|
dom_default.dispatchEvent(inputs[0], PHX_TRACK_UPLOADS, { detail: { files: filesOrBlobs } });
|
|
3574
3699
|
}
|
|
3575
3700
|
}
|
|
3701
|
+
targetCtxElement(targetCtx) {
|
|
3702
|
+
if (isCid(targetCtx)) {
|
|
3703
|
+
let [target] = dom_default.findComponentNodeList(this.el, targetCtx);
|
|
3704
|
+
return target;
|
|
3705
|
+
} else if (targetCtx) {
|
|
3706
|
+
return targetCtx;
|
|
3707
|
+
} else {
|
|
3708
|
+
return null;
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3576
3711
|
pushFormRecovery(form, newCid, callback) {
|
|
3577
3712
|
this.liveSocket.withinOwners(form, (view, targetCtx) => {
|
|
3578
3713
|
let phxChange = this.binding("change");
|
|
@@ -4079,7 +4214,7 @@ var LiveSocket = class {
|
|
|
4079
4214
|
if (!dead) {
|
|
4080
4215
|
this.bindForms();
|
|
4081
4216
|
}
|
|
4082
|
-
this.bind({ keyup: "keyup", keydown: "keydown" }, (e, type, view, targetEl, phxEvent,
|
|
4217
|
+
this.bind({ keyup: "keyup", keydown: "keydown" }, (e, type, view, targetEl, phxEvent, phxTarget) => {
|
|
4083
4218
|
let matchKey = targetEl.getAttribute(this.binding(PHX_KEY));
|
|
4084
4219
|
let pressedKey = e.key && e.key.toLowerCase();
|
|
4085
4220
|
if (matchKey && matchKey.toLowerCase() !== pressedKey) {
|
|
@@ -4088,13 +4223,13 @@ var LiveSocket = class {
|
|
|
4088
4223
|
let data = { key: e.key, ...this.eventMeta(type, e, targetEl) };
|
|
4089
4224
|
js_default.exec(type, phxEvent, view, targetEl, ["push", { data }]);
|
|
4090
4225
|
});
|
|
4091
|
-
this.bind({ blur: "focusout", focus: "focusin" }, (e, type, view, targetEl, phxEvent,
|
|
4092
|
-
if (!
|
|
4226
|
+
this.bind({ blur: "focusout", focus: "focusin" }, (e, type, view, targetEl, phxEvent, phxTarget) => {
|
|
4227
|
+
if (!phxTarget) {
|
|
4093
4228
|
let data = { key: e.key, ...this.eventMeta(type, e, targetEl) };
|
|
4094
4229
|
js_default.exec(type, phxEvent, view, targetEl, ["push", { data }]);
|
|
4095
4230
|
}
|
|
4096
4231
|
});
|
|
4097
|
-
this.bind({ blur: "blur", focus: "focus" }, (e, type, view, targetEl,
|
|
4232
|
+
this.bind({ blur: "blur", focus: "focus" }, (e, type, view, targetEl, phxEvent, phxTarget) => {
|
|
4098
4233
|
if (phxTarget === "window") {
|
|
4099
4234
|
let data = this.eventMeta(type, e, targetEl);
|
|
4100
4235
|
js_default.exec(type, phxEvent, view, targetEl, ["push", { data }]);
|
|
@@ -4175,7 +4310,7 @@ var LiveSocket = class {
|
|
|
4175
4310
|
}
|
|
4176
4311
|
}
|
|
4177
4312
|
bindClicks() {
|
|
4178
|
-
window.addEventListener("
|
|
4313
|
+
window.addEventListener("mousedown", (e) => this.clickStartedAtTarget = e.target);
|
|
4179
4314
|
this.bindClick("click", "click", false);
|
|
4180
4315
|
this.bindClick("mousedown", "capture-click", true);
|
|
4181
4316
|
}
|
|
@@ -4217,7 +4352,7 @@ var LiveSocket = class {
|
|
|
4217
4352
|
if (!(el.isSameNode(clickStartedAt) || el.contains(clickStartedAt))) {
|
|
4218
4353
|
this.withinOwners(e.target, (view) => {
|
|
4219
4354
|
let phxEvent = el.getAttribute(phxClickAway);
|
|
4220
|
-
if (js_default.isVisible(el)) {
|
|
4355
|
+
if (js_default.isVisible(el) && js_default.isInViewport(el)) {
|
|
4221
4356
|
js_default.exec("click", phxEvent, view, el, ["push", { data: this.eventMeta("click", e, e.target) }]);
|
|
4222
4357
|
}
|
|
4223
4358
|
});
|
|
@@ -4266,7 +4401,7 @@ var LiveSocket = class {
|
|
|
4266
4401
|
if (!type || !this.isConnected() || !this.main || dom_default.wantsNewTab(e)) {
|
|
4267
4402
|
return;
|
|
4268
4403
|
}
|
|
4269
|
-
let href = target.href;
|
|
4404
|
+
let href = target.href instanceof SVGAnimatedString ? target.href.baseVal : target.href;
|
|
4270
4405
|
let linkState = target.getAttribute(PHX_LINK_STATE);
|
|
4271
4406
|
e.preventDefault();
|
|
4272
4407
|
e.stopImmediatePropagation();
|