@adobe/helix-rum-enhancer 2.19.2 → 2.20.0

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/.husky/pre-commit CHANGED
@@ -1,2 +1 @@
1
1
  npx lint-staged
2
- npm test
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [2.20.0](https://github.com/adobe/helix-rum-enhancer/compare/v2.19.2...v2.20.0) (2024-08-19)
2
+
3
+
4
+ ### Features
5
+
6
+ * observe all mutations to capture late added medias ([#261](https://github.com/adobe/helix-rum-enhancer/issues/261)) ([56844b2](https://github.com/adobe/helix-rum-enhancer/commit/56844b2aa61fe5cc837cd5a887f0c8669a335e0f))
7
+
1
8
  ## [2.19.2](https://github.com/adobe/helix-rum-enhancer/compare/v2.19.1...v2.19.2) (2024-08-15)
2
9
 
3
10
 
package/modules/index.js CHANGED
@@ -26,9 +26,14 @@ const { sampleRUM, queue, isSelected } = (window.hlx && window.hlx.rum) ? window
26
26
  /* c8 ignore next */ : {};
27
27
 
28
28
  const formSubmitListener = (e) => sampleRUM('formsubmit', { target: targetSelector(e.target), source: sourceSelector(e.target) });
29
- // eslint-disable-next-line no-use-before-define
30
- const mutationObserver = window.MutationObserver ? new MutationObserver(mutationsCallback)
31
- /* c8 ignore next */ : null;
29
+
30
+ // eslint-disable-next-line no-use-before-define, max-len
31
+ const blocksMutationObserver = window.MutationObserver ? new MutationObserver(blocksMutationsCallback)
32
+ /* c8 ignore next */ : {};
33
+
34
+ // eslint-disable-next-line no-use-before-define, max-len
35
+ const mediaMutationObserver = window.MutationObserver ? new MutationObserver(mediaMutationsCallback)
36
+ /* c8 ignore next */ : {};
32
37
 
33
38
  function trackCheckpoint(checkpoint, data, t) {
34
39
  const { weight, id } = window.hlx.rum;
@@ -52,7 +57,7 @@ function trackCheckpoint(checkpoint, data, t) {
52
57
  }
53
58
 
54
59
  function processQueue() {
55
- while (queue.length) {
60
+ while (queue && queue.length) {
56
61
  const ck = queue.shift();
57
62
  trackCheckpoint(...ck);
58
63
  }
@@ -148,21 +153,36 @@ function addLoadResourceTracking() {
148
153
  }
149
154
 
150
155
  function activateBlocksMutationObserver() {
151
- if (!mutationObserver || mutationObserver.active) {
156
+ if (!blocksMutationObserver || blocksMutationObserver.active) {
152
157
  return;
153
158
  }
154
- mutationObserver.active = true;
155
- mutationObserver.observe(
159
+ blocksMutationObserver.active = true;
160
+ blocksMutationObserver.observe(
156
161
  document.body,
157
162
  // eslint-disable-next-line object-curly-newline
158
163
  { subtree: true, attributes: true, attributeFilter: ['data-block-status'] },
159
164
  );
160
165
  }
161
166
 
167
+ function activateMediaMutationObserver() {
168
+ if (!mediaMutationObserver || mediaMutationObserver.active) {
169
+ return;
170
+ }
171
+ mediaMutationObserver.active = true;
172
+ mediaMutationObserver.observe(
173
+ document.body,
174
+ // eslint-disable-next-line object-curly-newline
175
+ { subtree: true, attributes: false, childList: true },
176
+ );
177
+ }
178
+
162
179
  function getIntersectionObsever(checkpoint) {
163
- /* c8 ignore next */
164
- if (!window.IntersectionObserver) return null;
180
+ /* c8 ignore next 3 */
181
+ if (!window.IntersectionObserver) {
182
+ return null;
183
+ }
165
184
  activateBlocksMutationObserver();
185
+ activateMediaMutationObserver();
166
186
  const observer = new IntersectionObserver((entries) => {
167
187
  try {
168
188
  entries
@@ -188,11 +208,13 @@ function addViewBlockTracking(element) {
188
208
  }
189
209
  }
190
210
 
211
+ const observedMedia = new Set();
191
212
  function addViewMediaTracking(parent) {
192
213
  const mediaobserver = getIntersectionObsever('viewmedia');
193
214
  if (mediaobserver) {
194
215
  parent.querySelectorAll('img, video, audio, iframe').forEach((m) => {
195
- if (!m.closest('div .block') || m.closest('div[data-block-status="loaded"]')) {
216
+ if (!observedMedia.has(m)) {
217
+ observedMedia.add(m);
196
218
  mediaobserver.observe(m);
197
219
  }
198
220
  });
@@ -201,19 +223,32 @@ function addViewMediaTracking(parent) {
201
223
 
202
224
  function addFormTracking(parent) {
203
225
  activateBlocksMutationObserver();
226
+ activateMediaMutationObserver();
204
227
  parent.querySelectorAll('form').forEach((form) => {
205
228
  form.removeEventListener('submit', formSubmitListener); // listen only once
206
229
  form.addEventListener('submit', formSubmitListener);
207
230
  });
208
231
  }
209
232
 
210
- const addObserver = (ck, fn, block) => DEFAULT_TRACKING_EVENTS.includes(ck) && fn(block);
211
- function mutationsCallback(mutations) {
212
- mutations.filter((m) => m.type === 'attributes' && m.attributeName === 'data-block-status')
233
+ function addObserver(ck, fn, block) {
234
+ return DEFAULT_TRACKING_EVENTS.includes(ck) && fn(block);
235
+ }
236
+
237
+ function blocksMutationsCallback(mutations) {
238
+ // block specific mutations
239
+ mutations
240
+ .filter((m) => m.type === 'attributes' && m.attributeName === 'data-block-status')
213
241
  .filter((m) => m.target.dataset.blockStatus === 'loaded')
214
242
  .forEach((m) => {
215
243
  addObserver('form', addFormTracking, m.target);
216
244
  addObserver('viewblock', addViewBlockTracking, m.target);
245
+ });
246
+ }
247
+
248
+ function mediaMutationsCallback(mutations) {
249
+ // media mutations
250
+ mutations
251
+ .forEach((m) => {
217
252
  addObserver('viewmedia', addViewMediaTracking, m.target);
218
253
  });
219
254
  }
@@ -241,6 +276,7 @@ function initEnhancer() {
241
276
  window.hlx.rum.collector = trackCheckpoint;
242
277
  processQueue();
243
278
  }
279
+ /* c8 ignore next 3 */
244
280
  } catch (error) {
245
281
  // something went wrong
246
282
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/helix-rum-enhancer",
3
- "version": "2.19.2",
3
+ "version": "2.20.0",
4
4
  "description": "Helix RUM Enhancer",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -51,13 +51,13 @@
51
51
  "husky": "9.1.4",
52
52
  "jsdoc-to-markdown": "8.0.3",
53
53
  "junit-report-builder": "5.0.0",
54
- "lint-staged": "15.2.8",
54
+ "lint-staged": "15.2.9",
55
55
  "mocha": "10.7.3",
56
56
  "mocha-multi-reporters": "1.5.1",
57
57
  "rollup": "4.20.0",
58
58
  "rollup-plugin-cleanup": "3.2.1",
59
59
  "rollup-plugin-eslint-bundle": "9.0.0",
60
- "semantic-release": "24.0.0",
60
+ "semantic-release": "24.1.0",
61
61
  "web-vitals": "4.2.3"
62
62
  },
63
63
  "lint-staged": {
package/src/index.js CHANGED
@@ -203,9 +203,14 @@
203
203
  : {};
204
204
 
205
205
  const formSubmitListener = (e) => sampleRUM('formsubmit', { target: targetSelector(e.target), source: sourceSelector(e.target) });
206
- // eslint-disable-next-line no-use-before-define
207
- const mutationObserver = window.MutationObserver ? new MutationObserver(mutationsCallback)
208
- : null;
206
+
207
+ // eslint-disable-next-line no-use-before-define, max-len
208
+ const blocksMutationObserver = window.MutationObserver ? new MutationObserver(blocksMutationsCallback)
209
+ : {};
210
+
211
+ // eslint-disable-next-line no-use-before-define, max-len
212
+ const mediaMutationObserver = window.MutationObserver ? new MutationObserver(mediaMutationsCallback)
213
+ : {};
209
214
 
210
215
  function trackCheckpoint(checkpoint, data, t) {
211
216
  const { weight, id } = window.hlx.rum;
@@ -228,7 +233,7 @@
228
233
  }
229
234
 
230
235
  function processQueue() {
231
- while (queue.length) {
236
+ while (queue && queue.length) {
232
237
  const ck = queue.shift();
233
238
  trackCheckpoint(...ck);
234
239
  }
@@ -322,20 +327,35 @@
322
327
  }
323
328
 
324
329
  function activateBlocksMutationObserver() {
325
- if (!mutationObserver || mutationObserver.active) {
330
+ if (!blocksMutationObserver || blocksMutationObserver.active) {
326
331
  return;
327
332
  }
328
- mutationObserver.active = true;
329
- mutationObserver.observe(
333
+ blocksMutationObserver.active = true;
334
+ blocksMutationObserver.observe(
330
335
  document.body,
331
336
  // eslint-disable-next-line object-curly-newline
332
337
  { subtree: true, attributes: true, attributeFilter: ['data-block-status'] },
333
338
  );
334
339
  }
335
340
 
341
+ function activateMediaMutationObserver() {
342
+ if (!mediaMutationObserver || mediaMutationObserver.active) {
343
+ return;
344
+ }
345
+ mediaMutationObserver.active = true;
346
+ mediaMutationObserver.observe(
347
+ document.body,
348
+ // eslint-disable-next-line object-curly-newline
349
+ { subtree: true, attributes: false, childList: true },
350
+ );
351
+ }
352
+
336
353
  function getIntersectionObsever(checkpoint) {
337
- if (!window.IntersectionObserver) return null;
354
+ if (!window.IntersectionObserver) {
355
+ return null;
356
+ }
338
357
  activateBlocksMutationObserver();
358
+ activateMediaMutationObserver();
339
359
  const observer = new IntersectionObserver((entries) => {
340
360
  try {
341
361
  entries
@@ -360,11 +380,13 @@
360
380
  }
361
381
  }
362
382
 
383
+ const observedMedia = new Set();
363
384
  function addViewMediaTracking(parent) {
364
385
  const mediaobserver = getIntersectionObsever('viewmedia');
365
386
  if (mediaobserver) {
366
387
  parent.querySelectorAll('img, video, audio, iframe').forEach((m) => {
367
- if (!m.closest('div .block') || m.closest('div[data-block-status="loaded"]')) {
388
+ if (!observedMedia.has(m)) {
389
+ observedMedia.add(m);
368
390
  mediaobserver.observe(m);
369
391
  }
370
392
  });
@@ -373,19 +395,32 @@
373
395
 
374
396
  function addFormTracking(parent) {
375
397
  activateBlocksMutationObserver();
398
+ activateMediaMutationObserver();
376
399
  parent.querySelectorAll('form').forEach((form) => {
377
400
  form.removeEventListener('submit', formSubmitListener); // listen only once
378
401
  form.addEventListener('submit', formSubmitListener);
379
402
  });
380
403
  }
381
404
 
382
- const addObserver = (ck, fn, block) => DEFAULT_TRACKING_EVENTS.includes(ck) && fn(block);
383
- function mutationsCallback(mutations) {
384
- mutations.filter((m) => m.type === 'attributes' && m.attributeName === 'data-block-status')
405
+ function addObserver(ck, fn, block) {
406
+ return DEFAULT_TRACKING_EVENTS.includes(ck) && fn(block);
407
+ }
408
+
409
+ function blocksMutationsCallback(mutations) {
410
+ // block specific mutations
411
+ mutations
412
+ .filter((m) => m.type === 'attributes' && m.attributeName === 'data-block-status')
385
413
  .filter((m) => m.target.dataset.blockStatus === 'loaded')
386
414
  .forEach((m) => {
387
415
  addObserver('form', addFormTracking, m.target);
388
416
  addObserver('viewblock', addViewBlockTracking, m.target);
417
+ });
418
+ }
419
+
420
+ function mediaMutationsCallback(mutations) {
421
+ // media mutations
422
+ mutations
423
+ .forEach((m) => {
389
424
  addObserver('viewmedia', addViewMediaTracking, m.target);
390
425
  });
391
426
  }