phoenix_live_view 1.0.2 → 1.0.3
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 +2 -10
- package/assets/js/phoenix_live_view/dom.js +6 -1
- package/assets/js/phoenix_live_view/dom_patch.js +8 -36
- package/assets/js/phoenix_live_view/element_ref.js +9 -0
- package/assets/js/phoenix_live_view/hooks.js +20 -2
- package/assets/js/phoenix_live_view/live_socket.js +7 -18
- package/assets/js/phoenix_live_view/utils.js +11 -0
- package/assets/js/phoenix_live_view/view.js +32 -17
- package/package.json +24 -6
- package/priv/static/phoenix_live_view.cjs.js +81 -76
- package/priv/static/phoenix_live_view.cjs.js.map +2 -2
- package/priv/static/phoenix_live_view.esm.js +81 -76
- package/priv/static/phoenix_live_view.esm.js.map +2 -2
- package/priv/static/phoenix_live_view.js +81 -76
- package/priv/static/phoenix_live_view.min.js +6 -6
- package/assets/package.json +0 -29
|
@@ -221,6 +221,16 @@ var LiveView = (() => {
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
|
+
function detectInvalidStreamInserts(inserts) {
|
|
225
|
+
const errors = /* @__PURE__ */ new Set();
|
|
226
|
+
Object.keys(inserts).forEach((id) => {
|
|
227
|
+
const streamEl = document.getElementById(id);
|
|
228
|
+
if (streamEl && streamEl.parentElement && streamEl.parentElement.getAttribute("phx-update") !== "stream") {
|
|
229
|
+
errors.add(`The stream container with id "${streamEl.parentElement.id}" is missing the phx-update="stream" attribute. Ensure it is set for streams to work properly.`);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
errors.forEach((error) => console.error(error));
|
|
233
|
+
}
|
|
224
234
|
var debug = (view, kind, msg, obj) => {
|
|
225
235
|
if (view.liveSocket.isDebugEnabled()) {
|
|
226
236
|
console.log(`${view.id} ${kind}: ${msg} - `, obj);
|
|
@@ -447,7 +457,7 @@ var LiveView = (() => {
|
|
|
447
457
|
cids.forEach((cid) => {
|
|
448
458
|
this.filterWithinSameLiveView(this.all(node, `[${PHX_COMPONENT}="${cid}"]`), node).forEach((parent) => {
|
|
449
459
|
parentCids.add(cid);
|
|
450
|
-
this.all(parent, `[${PHX_COMPONENT}]`).map((el) => parseInt(el.getAttribute(PHX_COMPONENT))).forEach((childCID) => childrenCids.add(childCID));
|
|
460
|
+
this.filterWithinSameLiveView(this.all(parent, `[${PHX_COMPONENT}]`), parent).map((el) => parseInt(el.getAttribute(PHX_COMPONENT))).forEach((childCID) => childrenCids.add(childCID));
|
|
451
461
|
});
|
|
452
462
|
});
|
|
453
463
|
childrenCids.forEach((childCid) => parentCids.delete(childCid));
|
|
@@ -824,6 +834,9 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
824
834
|
return;
|
|
825
835
|
}
|
|
826
836
|
ops.forEach(([name, op, _stashed]) => this.putSticky(el, name, op));
|
|
837
|
+
},
|
|
838
|
+
isLocked(el) {
|
|
839
|
+
return el.hasAttribute && el.hasAttribute(PHX_REF_LOCK);
|
|
827
840
|
}
|
|
828
841
|
};
|
|
829
842
|
var dom_default = DOM;
|
|
@@ -1166,8 +1179,22 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
1166
1179
|
mounted() {
|
|
1167
1180
|
this.focusStart = this.el.firstElementChild;
|
|
1168
1181
|
this.focusEnd = this.el.lastElementChild;
|
|
1169
|
-
this.focusStart.addEventListener("focus", () =>
|
|
1170
|
-
|
|
1182
|
+
this.focusStart.addEventListener("focus", (e) => {
|
|
1183
|
+
if (!e.relatedTarget || !this.el.contains(e.relatedTarget)) {
|
|
1184
|
+
const nextFocus = e.target.nextElementSibling;
|
|
1185
|
+
aria_default.attemptFocus(nextFocus) || aria_default.focusFirst(nextFocus);
|
|
1186
|
+
} else {
|
|
1187
|
+
aria_default.focusLast(this.el);
|
|
1188
|
+
}
|
|
1189
|
+
});
|
|
1190
|
+
this.focusEnd.addEventListener("focus", (e) => {
|
|
1191
|
+
if (!e.relatedTarget || !this.el.contains(e.relatedTarget)) {
|
|
1192
|
+
const nextFocus = e.target.previousElementSibling;
|
|
1193
|
+
aria_default.attemptFocus(nextFocus) || aria_default.focusLast(nextFocus);
|
|
1194
|
+
} else {
|
|
1195
|
+
aria_default.focusFirst(this.el);
|
|
1196
|
+
}
|
|
1197
|
+
});
|
|
1171
1198
|
this.el.addEventListener("phx:show-end", () => this.el.focus());
|
|
1172
1199
|
if (window.getComputedStyle(this.el).display !== "none") {
|
|
1173
1200
|
aria_default.focusFirst(this.el);
|
|
@@ -1316,6 +1343,16 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
1316
1343
|
|
|
1317
1344
|
// js/phoenix_live_view/element_ref.js
|
|
1318
1345
|
var ElementRef = class {
|
|
1346
|
+
static onUnlock(el, callback) {
|
|
1347
|
+
if (!dom_default.isLocked(el) && !el.closest(`[${PHX_REF_LOCK}]`)) {
|
|
1348
|
+
return callback();
|
|
1349
|
+
}
|
|
1350
|
+
const closestLock = el.closest(`[${PHX_REF_LOCK}]`);
|
|
1351
|
+
const ref = closestLock.closest(`[${PHX_REF_LOCK}]`).getAttribute(PHX_REF_LOCK);
|
|
1352
|
+
closestLock.addEventListener(`phx:undo-lock:${ref}`, () => {
|
|
1353
|
+
callback();
|
|
1354
|
+
}, { once: true });
|
|
1355
|
+
}
|
|
1319
1356
|
constructor(el) {
|
|
1320
1357
|
this.el = el;
|
|
1321
1358
|
this.loadingRef = el.hasAttribute(PHX_REF_LOADING) ? parseInt(el.getAttribute(PHX_REF_LOADING), 10) : null;
|
|
@@ -1967,37 +2004,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
1967
2004
|
|
|
1968
2005
|
// js/phoenix_live_view/dom_patch.js
|
|
1969
2006
|
var DOMPatch = class {
|
|
1970
|
-
|
|
1971
|
-
let focused = liveSocket.getActiveElement();
|
|
1972
|
-
let { selectionStart, selectionEnd } = focused && dom_default.hasSelectionRange(focused) ? focused : {};
|
|
1973
|
-
let phxUpdate = liveSocket.binding(PHX_UPDATE);
|
|
1974
|
-
let externalFormTriggered = null;
|
|
1975
|
-
morphdom_esm_default(container, clonedTree, {
|
|
1976
|
-
childrenOnly: false,
|
|
1977
|
-
onBeforeElUpdated: (fromEl, toEl) => {
|
|
1978
|
-
dom_default.syncPendingAttrs(fromEl, toEl);
|
|
1979
|
-
if (!container.isSameNode(fromEl) && fromEl.hasAttribute(PHX_REF_LOCK)) {
|
|
1980
|
-
return false;
|
|
1981
|
-
}
|
|
1982
|
-
if (dom_default.isIgnored(fromEl, phxUpdate)) {
|
|
1983
|
-
return false;
|
|
1984
|
-
}
|
|
1985
|
-
if (focused && focused.isSameNode(fromEl) && dom_default.isFormInput(fromEl)) {
|
|
1986
|
-
dom_default.mergeFocusedInput(fromEl, toEl);
|
|
1987
|
-
return false;
|
|
1988
|
-
}
|
|
1989
|
-
if (dom_default.isNowTriggerFormExternal(toEl, liveSocket.binding(PHX_TRIGGER_ACTION))) {
|
|
1990
|
-
externalFormTriggered = toEl;
|
|
1991
|
-
}
|
|
1992
|
-
}
|
|
1993
|
-
});
|
|
1994
|
-
if (externalFormTriggered) {
|
|
1995
|
-
liveSocket.unload();
|
|
1996
|
-
Object.getPrototypeOf(externalFormTriggered).submit.call(externalFormTriggered);
|
|
1997
|
-
}
|
|
1998
|
-
liveSocket.silenceEvents(() => dom_default.restoreFocus(focused, selectionStart, selectionEnd));
|
|
1999
|
-
}
|
|
2000
|
-
constructor(view, container, id, html, streams, targetCID) {
|
|
2007
|
+
constructor(view, container, id, html, streams, targetCID, opts = {}) {
|
|
2001
2008
|
this.view = view;
|
|
2002
2009
|
this.liveSocket = view.liveSocket;
|
|
2003
2010
|
this.container = container;
|
|
@@ -2022,6 +2029,8 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
2022
2029
|
afterphxChildAdded: [],
|
|
2023
2030
|
aftertransitionsDiscarded: []
|
|
2024
2031
|
};
|
|
2032
|
+
this.withChildren = opts.withChildren || opts.undoRef || false;
|
|
2033
|
+
this.undoRef = opts.undoRef;
|
|
2025
2034
|
}
|
|
2026
2035
|
before(kind, callback) {
|
|
2027
2036
|
this.callbacks[`before${kind}`].push(callback);
|
|
@@ -2056,7 +2065,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
2056
2065
|
let updates = [];
|
|
2057
2066
|
let appendPrependUpdates = [];
|
|
2058
2067
|
let externalFormTriggered = null;
|
|
2059
|
-
function morph(targetContainer2, source, withChildren =
|
|
2068
|
+
function morph(targetContainer2, source, withChildren = this.withChildren) {
|
|
2060
2069
|
let morphCallbacks = {
|
|
2061
2070
|
// normally, we are running with childrenOnly, as the patch HTML for a LV
|
|
2062
2071
|
// does not include the LV attrs (data-phx-session, etc.)
|
|
@@ -2182,7 +2191,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
2182
2191
|
}
|
|
2183
2192
|
let isFocusedFormEl = focused && fromEl.isSameNode(focused) && dom_default.isFormInput(fromEl);
|
|
2184
2193
|
let focusedSelectChanged = isFocusedFormEl && this.isChangedSelect(fromEl, toEl);
|
|
2185
|
-
if (fromEl.hasAttribute(PHX_REF_SRC)) {
|
|
2194
|
+
if (fromEl.hasAttribute(PHX_REF_SRC) && fromEl.getAttribute(PHX_REF_LOCK) != this.undoRef) {
|
|
2186
2195
|
if (dom_default.isUploadInput(fromEl)) {
|
|
2187
2196
|
dom_default.mergeAttrs(fromEl, toEl, { isIgnored: true });
|
|
2188
2197
|
this.trackBefore("updated", fromEl, toEl);
|
|
@@ -2266,6 +2275,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
2266
2275
|
});
|
|
2267
2276
|
if (liveSocket.isDebugEnabled()) {
|
|
2268
2277
|
detectDuplicateIds();
|
|
2278
|
+
detectInvalidStreamInserts(this.streamInserts);
|
|
2269
2279
|
Array.from(document.querySelectorAll("input[name=id]")).forEach((node) => {
|
|
2270
2280
|
if (node.form) {
|
|
2271
2281
|
console.error('Detected an input with name="id" inside a form! This will cause problems when patching the DOM.\n', node);
|
|
@@ -3600,7 +3610,11 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
3600
3610
|
this.formsForRecovery = this.getFormsForRecovery();
|
|
3601
3611
|
}
|
|
3602
3612
|
if (this.isMain() && window.history.state === null) {
|
|
3603
|
-
|
|
3613
|
+
browser_default.pushState("replace", {
|
|
3614
|
+
type: "patch",
|
|
3615
|
+
id: this.id,
|
|
3616
|
+
position: this.liveSocket.currentHistoryPosition
|
|
3617
|
+
});
|
|
3604
3618
|
}
|
|
3605
3619
|
if (liveview_version !== this.liveSocket.version()) {
|
|
3606
3620
|
console.error(`LiveView asset version mismatch. JavaScript version ${this.liveSocket.version()} vs. server ${liveview_version}. To avoid issues, please ensure that your assets use the same version as the server.`);
|
|
@@ -3923,6 +3937,9 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
3923
3937
|
}
|
|
3924
3938
|
addHook(el) {
|
|
3925
3939
|
let hookElId = ViewHook.elementID(el);
|
|
3940
|
+
if (el.getAttribute && !this.ownsElement(el)) {
|
|
3941
|
+
return;
|
|
3942
|
+
}
|
|
3926
3943
|
if (hookElId && !this.viewHooks[hookElId]) {
|
|
3927
3944
|
let hook = dom_default.getCustomElHook(el) || logError(`no hook found for custom element: ${el.id}`);
|
|
3928
3945
|
this.viewHooks[hookElId] = hook;
|
|
@@ -3932,9 +3949,6 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
3932
3949
|
return;
|
|
3933
3950
|
} else {
|
|
3934
3951
|
let hookName = el.getAttribute(`data-phx-${PHX_HOOK}`) || el.getAttribute(this.binding(PHX_HOOK));
|
|
3935
|
-
if (hookName && !this.ownsElement(el)) {
|
|
3936
|
-
return;
|
|
3937
|
-
}
|
|
3938
3952
|
let callbacks = this.liveSocket.getHookCallbacks(hookName);
|
|
3939
3953
|
if (callbacks) {
|
|
3940
3954
|
if (!el.id) {
|
|
@@ -3949,9 +3963,10 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
3949
3963
|
}
|
|
3950
3964
|
}
|
|
3951
3965
|
destroyHook(hook) {
|
|
3966
|
+
const hookId = ViewHook.elementID(hook.el);
|
|
3952
3967
|
hook.__destroyed();
|
|
3953
3968
|
hook.__cleanup__();
|
|
3954
|
-
delete this.viewHooks[
|
|
3969
|
+
delete this.viewHooks[hookId];
|
|
3955
3970
|
}
|
|
3956
3971
|
applyPendingUpdates() {
|
|
3957
3972
|
this.pendingDiffs.forEach(({ diff, events }) => this.update(diff, events));
|
|
@@ -4201,12 +4216,11 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
4201
4216
|
undoElRef(el, ref, phxEvent) {
|
|
4202
4217
|
let elRef = new ElementRef(el);
|
|
4203
4218
|
elRef.maybeUndo(ref, phxEvent, (clonedTree) => {
|
|
4204
|
-
let
|
|
4205
|
-
|
|
4219
|
+
let patch = new DOMPatch(this, el, this.id, clonedTree, [], null, { undoRef: ref });
|
|
4220
|
+
const phxChildrenAdded = this.performPatch(patch, true);
|
|
4206
4221
|
dom_default.all(el, `[${PHX_REF_SRC}="${this.refSrc()}"]`, (child) => this.undoElRef(child, ref, phxEvent));
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
hook.__updated();
|
|
4222
|
+
if (phxChildrenAdded) {
|
|
4223
|
+
this.joinNewChildren();
|
|
4210
4224
|
}
|
|
4211
4225
|
});
|
|
4212
4226
|
}
|
|
@@ -4422,15 +4436,17 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
4422
4436
|
};
|
|
4423
4437
|
this.pushWithReply(refGenerator, "event", event).then(({ resp }) => {
|
|
4424
4438
|
if (dom_default.isUploadInput(inputEl) && dom_default.isAutoUpload(inputEl)) {
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4439
|
+
ElementRef.onUnlock(inputEl, () => {
|
|
4440
|
+
if (LiveUploader.filesAwaitingPreflight(inputEl).length > 0) {
|
|
4441
|
+
let [ref, _els] = refGenerator();
|
|
4442
|
+
this.undoRefs(ref, phxEvent, [inputEl.form]);
|
|
4443
|
+
this.uploadFiles(inputEl.form, phxEvent, targetCtx, ref, cid, (_uploads) => {
|
|
4444
|
+
callback && callback(resp);
|
|
4445
|
+
this.triggerAwaitingSubmit(inputEl.form, phxEvent);
|
|
4446
|
+
this.undoRefs(ref, phxEvent);
|
|
4447
|
+
});
|
|
4448
|
+
}
|
|
4449
|
+
});
|
|
4434
4450
|
} else {
|
|
4435
4451
|
callback && callback(resp);
|
|
4436
4452
|
}
|
|
@@ -4780,7 +4796,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
4780
4796
|
}
|
|
4781
4797
|
// public
|
|
4782
4798
|
version() {
|
|
4783
|
-
return "1.0.
|
|
4799
|
+
return "1.0.3";
|
|
4784
4800
|
}
|
|
4785
4801
|
isProfileEnabled() {
|
|
4786
4802
|
return this.sessionStorage.getItem(PHX_LV_PROFILE) === "true";
|
|
@@ -4978,7 +4994,9 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
4978
4994
|
dom_default.all(document, `${PHX_VIEW_SELECTOR}:not([${PHX_PARENT_ID}])`, (rootEl) => {
|
|
4979
4995
|
if (!this.getRootById(rootEl.id)) {
|
|
4980
4996
|
let view = this.newRootView(rootEl);
|
|
4981
|
-
|
|
4997
|
+
if (!dom_default.isPhxSticky(rootEl)) {
|
|
4998
|
+
view.setHref(this.getHref());
|
|
4999
|
+
}
|
|
4982
5000
|
view.join();
|
|
4983
5001
|
if (rootEl.hasAttribute(PHX_MAIN)) {
|
|
4984
5002
|
this.main = view;
|
|
@@ -5292,7 +5310,7 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
5292
5310
|
if (!this.registerNewLocation(window.location)) {
|
|
5293
5311
|
return;
|
|
5294
5312
|
}
|
|
5295
|
-
let { type, backType, id,
|
|
5313
|
+
let { type, backType, id, scroll, position } = event.state || {};
|
|
5296
5314
|
let href = window.location.href;
|
|
5297
5315
|
let isForward = position > this.currentHistoryPosition;
|
|
5298
5316
|
type = isForward ? type : backType || type;
|
|
@@ -5300,17 +5318,13 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
5300
5318
|
this.sessionStorage.setItem(PHX_LV_HISTORY_POSITION, this.currentHistoryPosition.toString());
|
|
5301
5319
|
dom_default.dispatchEvent(window, "phx:navigate", { detail: { href, patch: type === "patch", pop: true, direction: isForward ? "forward" : "backward" } });
|
|
5302
5320
|
this.requestDOMUpdate(() => {
|
|
5321
|
+
const callback = () => {
|
|
5322
|
+
this.maybeScroll(scroll);
|
|
5323
|
+
};
|
|
5303
5324
|
if (this.main.isConnected() && (type === "patch" && id === this.main.id)) {
|
|
5304
|
-
this.main.pushLinkPatch(event, href, null,
|
|
5305
|
-
this.maybeScroll(scroll);
|
|
5306
|
-
});
|
|
5325
|
+
this.main.pushLinkPatch(event, href, null, callback);
|
|
5307
5326
|
} else {
|
|
5308
|
-
this.replaceMain(href, null,
|
|
5309
|
-
if (root) {
|
|
5310
|
-
this.replaceRootHistory();
|
|
5311
|
-
}
|
|
5312
|
-
this.maybeScroll(scroll);
|
|
5313
|
-
});
|
|
5327
|
+
this.replaceMain(href, null, callback);
|
|
5314
5328
|
}
|
|
5315
5329
|
});
|
|
5316
5330
|
}, false);
|
|
@@ -5417,15 +5431,6 @@ removing illegal node: "${(childNode.outerHTML || childNode.nodeValue).trim()}"
|
|
|
5417
5431
|
});
|
|
5418
5432
|
});
|
|
5419
5433
|
}
|
|
5420
|
-
replaceRootHistory() {
|
|
5421
|
-
browser_default.pushState("replace", {
|
|
5422
|
-
root: true,
|
|
5423
|
-
type: "patch",
|
|
5424
|
-
id: this.main.id,
|
|
5425
|
-
position: this.currentHistoryPosition
|
|
5426
|
-
// Preserve current position
|
|
5427
|
-
});
|
|
5428
|
-
}
|
|
5429
5434
|
registerNewLocation(newLocation) {
|
|
5430
5435
|
let { pathname, search } = this.currentLocation;
|
|
5431
5436
|
if (pathname + search === newLocation.pathname + newLocation.search) {
|