phoenix_live_view 0.20.7 → 0.20.9

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.
@@ -331,14 +331,15 @@ export default class DOMPatch {
331
331
  }
332
332
 
333
333
  removeStreamChildElement(child){
334
- if(!this.maybePendingRemove(child)){
335
- if(this.streamInserts[child.id]){
336
- // we need to store children so we can morph them later
337
- this.streamComponentRestore[child.id] = child
338
- child.remove()
339
- } else {
334
+ // we need to store the node if it is actually re-added in the same patch
335
+ // we do NOT want to execute phx-remove, we do NOT want to call onNodeDiscarded
336
+ if(this.streamInserts[child.id]){
337
+ this.streamComponentRestore[child.id] = child
338
+ child.remove()
339
+ } else {
340
+ // only remove the element now if it has no phx-remove binding
341
+ if(!this.maybePendingRemove(child)){
340
342
  child.remove()
341
- // TODO: check if we really don't want to call discarded for re-added stream items
342
343
  this.onNodeDiscarded(child)
343
344
  }
344
345
  }
@@ -365,6 +366,12 @@ export default class DOMPatch {
365
366
  return
366
367
  }
367
368
 
369
+ // check if the element has a parent element;
370
+ // it doesn't if we are currently recursively morphing (restoring a saved stream child)
371
+ // because the element is not yet added to the real dom;
372
+ // reordering does not make sense in that case anyway
373
+ if(!el.parentElement){ return }
374
+
368
375
  if(streamAt === 0){
369
376
  el.parentElement.insertBefore(el, el.parentElement.firstElementChild)
370
377
  } else if(streamAt > 0){
@@ -167,13 +167,6 @@ export default class Rendered {
167
167
  let newc = diff[COMPONENTS]
168
168
  let cache = {}
169
169
  delete diff[COMPONENTS]
170
- // we must consider all newly added components as reset for proper change tracking
171
- if(newc){
172
- let prevComponents = this.rendered[COMPONENTS] || {}
173
- for(let cid in newc){
174
- if(prevComponents[cid] === undefined){ newc[cid].reset = true }
175
- }
176
- }
177
170
  this.rendered = this.mutableMerge(this.rendered, diff)
178
171
  this.rendered[COMPONENTS] = this.rendered[COMPONENTS] || {}
179
172
 
@@ -257,6 +250,8 @@ export default class Rendered {
257
250
  let targetVal = target[key]
258
251
  if(isObject(val) && val[STATIC] === undefined && isObject(targetVal)){
259
252
  merged[key] = this.cloneMerge(targetVal, val, pruneMagicId)
253
+ } else if(val === undefined && isObject(targetVal)){
254
+ merged[key] = this.cloneMerge(targetVal, {}, pruneMagicId)
260
255
  }
261
256
  }
262
257
  if(pruneMagicId){
@@ -294,7 +289,7 @@ export default class Rendered {
294
289
 
295
290
  nextMagicID(){
296
291
  this.magicId++
297
- return `${this.parentViewId()}-${this.magicId}`
292
+ return `m${this.magicId}-${this.parentViewId()}`
298
293
  }
299
294
 
300
295
  // Converts rendered tree to output buffer.
@@ -330,7 +325,7 @@ export default class Rendered {
330
325
  if(isRoot){
331
326
  let skip = false
332
327
  let attrs
333
- // when a LC is added on the page, we need to re-render the entire LC tree,
328
+ // When a LC is re-added to the page, we need to re-render the entire LC tree,
334
329
  // therefore changeTracking is false; however, we need to keep all the magicIds
335
330
  // from any function component so the next time the LC is updated, we can apply
336
331
  // the skip optimization
@@ -403,12 +398,15 @@ export default class Rendered {
403
398
  // Both optimization flows apply here. newRender is set based on the onlyCids optimization, and
404
399
  // we track a deterministic magicId based on the cid.
405
400
  //
401
+ // changeTracking is about the entire tree
402
+ // newRender is about the current root in the tree
403
+ //
406
404
  // By default changeTracking is enabled, but we special case the flow where the client is pruning
407
405
  // cids and the server adds the component back. In such cases, we explicitly disable changeTracking
408
406
  // with resetRender for this cid, then re-enable it after the recursive call to skip the optimization
409
407
  // for the entire component tree.
410
408
  component.newRender = !skip
411
- component.magicId = `${this.parentViewId()}-c-${cid}`
409
+ component.magicId = `c${cid}-${this.parentViewId()}`
412
410
  // enable change tracking as long as the component hasn't been reset
413
411
  let changeTracking = !component.reset
414
412
  let [html, streams] = this.recursiveToString(component, components, onlyCids, changeTracking, attrs)
@@ -120,7 +120,6 @@ export default class View {
120
120
  this.childJoins = 0
121
121
  this.loaderTimer = null
122
122
  this.pendingDiffs = []
123
- this.pruningCIDs = []
124
123
  this.redirect = false
125
124
  this.href = null
126
125
  this.joinCount = this.parent ? this.parent.joinCount - 1 : 0
@@ -130,7 +129,6 @@ export default class View {
130
129
  this.stopCallback = function(){ }
131
130
  this.pendingJoinOps = this.parent ? null : []
132
131
  this.viewHooks = {}
133
- this.uploaders = {}
134
132
  this.formSubmits = []
135
133
  this.children = this.parent ? null : {}
136
134
  this.root.children[this.id] = {}
@@ -560,7 +558,7 @@ export default class View {
560
558
  let tag = this.el.tagName
561
559
  // Don't skip any component in the diff nor any marked as pruned
562
560
  // (as they may have been added back)
563
- let cids = diff ? this.rendered.componentCIDs(diff).concat(this.pruningCIDs) : null
561
+ let cids = diff ? this.rendered.componentCIDs(diff) : null
564
562
  let [html, streams] = this.rendered.toString(cids)
565
563
  return [`<${tag}>${html}</${tag}>`, streams]
566
564
  })
@@ -1065,9 +1063,13 @@ export default class View {
1065
1063
  if(numFileInputsInProgress === 0){ onComplete() }
1066
1064
  });
1067
1065
 
1068
- this.uploaders[inputEl] = uploader
1069
1066
  let entries = uploader.entries().map(entry => entry.toPreflightPayload())
1070
1067
 
1068
+ if (entries.length === 0) {
1069
+ numFileInputsInProgress--
1070
+ return
1071
+ }
1072
+
1071
1073
  let payload = {
1072
1074
  ref: inputEl.getAttribute(PHX_UPLOAD_REF),
1073
1075
  entries: entries,
@@ -1183,11 +1185,9 @@ export default class View {
1183
1185
  }
1184
1186
 
1185
1187
  maybePushComponentsDestroyed(destroyedCIDs){
1186
- let willDestroyCIDs = destroyedCIDs.concat(this.pruningCIDs).filter(cid => {
1188
+ let willDestroyCIDs = destroyedCIDs.filter(cid => {
1187
1189
  return DOM.findComponentNodeList(this.el, cid).length === 0
1188
1190
  })
1189
- // make sure this is a copy and not a reference
1190
- this.pruningCIDs = willDestroyCIDs.concat([])
1191
1191
 
1192
1192
  if(willDestroyCIDs.length > 0){
1193
1193
  // we must reset the render change tracking for cids that
@@ -1203,7 +1203,6 @@ export default class View {
1203
1203
 
1204
1204
  if(completelyDestroyCIDs.length > 0){
1205
1205
  this.pushWithReply(null, "cids_destroyed", {cids: completelyDestroyCIDs}, (resp) => {
1206
- this.pruningCIDs = this.pruningCIDs.filter(cid => resp.cids.indexOf(cid) === -1)
1207
1206
  this.rendered.pruneCIDs(resp.cids)
1208
1207
  })
1209
1208
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phoenix_live_view",
3
- "version": "0.20.7",
3
+ "version": "0.20.9",
4
4
  "description": "The Phoenix LiveView JavaScript client.",
5
5
  "license": "MIT",
6
6
  "repository": {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phoenix_live_view",
3
- "version": "0.20.7",
3
+ "version": "0.20.9",
4
4
  "description": "The Phoenix LiveView JavaScript client.",
5
5
  "license": "MIT",
6
6
  "module": "./priv/static/phoenix_live_view.esm.js",
@@ -2363,11 +2363,11 @@ var DOMPatch = class {
2363
2363
  }
2364
2364
  }
2365
2365
  removeStreamChildElement(child) {
2366
- if (!this.maybePendingRemove(child)) {
2367
- if (this.streamInserts[child.id]) {
2368
- this.streamComponentRestore[child.id] = child;
2369
- child.remove();
2370
- } else {
2366
+ if (this.streamInserts[child.id]) {
2367
+ this.streamComponentRestore[child.id] = child;
2368
+ child.remove();
2369
+ } else {
2370
+ if (!this.maybePendingRemove(child)) {
2371
2371
  child.remove();
2372
2372
  this.onNodeDiscarded(child);
2373
2373
  }
@@ -2389,6 +2389,9 @@ var DOMPatch = class {
2389
2389
  if (!reset && !isNew) {
2390
2390
  return;
2391
2391
  }
2392
+ if (!el.parentElement) {
2393
+ return;
2394
+ }
2392
2395
  if (streamAt === 0) {
2393
2396
  el.parentElement.insertBefore(el, el.parentElement.firstElementChild);
2394
2397
  } else if (streamAt > 0) {
@@ -2606,14 +2609,6 @@ var Rendered = class {
2606
2609
  let newc = diff[COMPONENTS];
2607
2610
  let cache = {};
2608
2611
  delete diff[COMPONENTS];
2609
- if (newc) {
2610
- let prevComponents = this.rendered[COMPONENTS] || {};
2611
- for (let cid in newc) {
2612
- if (prevComponents[cid] === void 0) {
2613
- newc[cid].reset = true;
2614
- }
2615
- }
2616
- }
2617
2612
  this.rendered = this.mutableMerge(this.rendered, diff);
2618
2613
  this.rendered[COMPONENTS] = this.rendered[COMPONENTS] || {};
2619
2614
  if (newc) {
@@ -2679,6 +2674,8 @@ var Rendered = class {
2679
2674
  let targetVal = target[key];
2680
2675
  if (isObject(val) && val[STATIC] === void 0 && isObject(targetVal)) {
2681
2676
  merged[key] = this.cloneMerge(targetVal, val, pruneMagicId);
2677
+ } else if (val === void 0 && isObject(targetVal)) {
2678
+ merged[key] = this.cloneMerge(targetVal, {}, pruneMagicId);
2682
2679
  }
2683
2680
  }
2684
2681
  if (pruneMagicId) {
@@ -2712,7 +2709,7 @@ var Rendered = class {
2712
2709
  }
2713
2710
  nextMagicID() {
2714
2711
  this.magicId++;
2715
- return `${this.parentViewId()}-${this.magicId}`;
2712
+ return `m${this.magicId}-${this.parentViewId()}`;
2716
2713
  }
2717
2714
  toOutputBuffer(rendered, templates, output, changeTracking, rootAttrs = {}) {
2718
2715
  if (rendered[DYNAMICS]) {
@@ -2787,7 +2784,7 @@ var Rendered = class {
2787
2784
  let attrs = { [PHX_COMPONENT]: cid };
2788
2785
  let skip = onlyCids && !onlyCids.has(cid);
2789
2786
  component.newRender = !skip;
2790
- component.magicId = `${this.parentViewId()}-c-${cid}`;
2787
+ component.magicId = `c${cid}-${this.parentViewId()}`;
2791
2788
  let changeTracking = !component.reset;
2792
2789
  let [html, streams] = this.recursiveToString(component, components, onlyCids, changeTracking, attrs);
2793
2790
  delete component.reset;
@@ -2923,7 +2920,6 @@ var View = class {
2923
2920
  this.childJoins = 0;
2924
2921
  this.loaderTimer = null;
2925
2922
  this.pendingDiffs = [];
2926
- this.pruningCIDs = [];
2927
2923
  this.redirect = false;
2928
2924
  this.href = null;
2929
2925
  this.joinCount = this.parent ? this.parent.joinCount - 1 : 0;
@@ -2936,7 +2932,6 @@ var View = class {
2936
2932
  };
2937
2933
  this.pendingJoinOps = this.parent ? null : [];
2938
2934
  this.viewHooks = {};
2939
- this.uploaders = {};
2940
2935
  this.formSubmits = [];
2941
2936
  this.children = this.parent ? null : {};
2942
2937
  this.root.children[this.id] = {};
@@ -3331,7 +3326,7 @@ var View = class {
3331
3326
  renderContainer(diff, kind) {
3332
3327
  return this.liveSocket.time(`toString diff (${kind})`, () => {
3333
3328
  let tag = this.el.tagName;
3334
- let cids = diff ? this.rendered.componentCIDs(diff).concat(this.pruningCIDs) : null;
3329
+ let cids = diff ? this.rendered.componentCIDs(diff) : null;
3335
3330
  let [html, streams] = this.rendered.toString(cids);
3336
3331
  return [`<${tag}>${html}</${tag}>`, streams];
3337
3332
  });
@@ -3850,8 +3845,11 @@ var View = class {
3850
3845
  onComplete();
3851
3846
  }
3852
3847
  });
3853
- this.uploaders[inputEl] = uploader;
3854
3848
  let entries = uploader.entries().map((entry) => entry.toPreflightPayload());
3849
+ if (entries.length === 0) {
3850
+ numFileInputsInProgress--;
3851
+ return;
3852
+ }
3855
3853
  let payload = {
3856
3854
  ref: inputEl.getAttribute(PHX_UPLOAD_REF),
3857
3855
  entries,
@@ -3953,10 +3951,9 @@ var View = class {
3953
3951
  }).filter(([form, newForm, newCid]) => newForm);
3954
3952
  }
3955
3953
  maybePushComponentsDestroyed(destroyedCIDs) {
3956
- let willDestroyCIDs = destroyedCIDs.concat(this.pruningCIDs).filter((cid) => {
3954
+ let willDestroyCIDs = destroyedCIDs.filter((cid) => {
3957
3955
  return dom_default.findComponentNodeList(this.el, cid).length === 0;
3958
3956
  });
3959
- this.pruningCIDs = willDestroyCIDs.concat([]);
3960
3957
  if (willDestroyCIDs.length > 0) {
3961
3958
  willDestroyCIDs.forEach((cid) => this.rendered.resetRender(cid));
3962
3959
  this.pushWithReply(null, "cids_will_destroy", { cids: willDestroyCIDs }, () => {
@@ -3965,7 +3962,6 @@ var View = class {
3965
3962
  });
3966
3963
  if (completelyDestroyCIDs.length > 0) {
3967
3964
  this.pushWithReply(null, "cids_destroyed", { cids: completelyDestroyCIDs }, (resp) => {
3968
- this.pruningCIDs = this.pruningCIDs.filter((cid) => resp.cids.indexOf(cid) === -1);
3969
3965
  this.rendered.pruneCIDs(resp.cids);
3970
3966
  });
3971
3967
  }