@gemx-dev/heatmap-react 3.5.92-dev.0 → 3.5.92-dev.10
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/dist/esm/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
- package/dist/esm/hooks/view-context/index.d.ts +1 -0
- package/dist/esm/hooks/view-context/index.d.ts.map +1 -1
- package/dist/esm/hooks/view-context/useHeatmapCopyView.d.ts.map +1 -1
- package/dist/esm/hooks/view-context/useHeatmapDataContext.d.ts +2 -16
- package/dist/esm/hooks/view-context/useHeatmapDataContext.d.ts.map +1 -1
- package/dist/esm/hooks/view-context/useHeatmapLiveContext.d.ts +34 -0
- package/dist/esm/hooks/view-context/useHeatmapLiveContext.d.ts.map +1 -0
- package/dist/esm/hooks/view-context/useHeatmapSettingContext.d.ts +3 -1
- package/dist/esm/hooks/view-context/useHeatmapSettingContext.d.ts.map +1 -1
- package/dist/esm/hooks/view-context/useHeatmapVizContext.d.ts +2 -2
- package/dist/esm/hooks/view-context/useHeatmapVizContext.d.ts.map +1 -1
- package/dist/esm/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +1 -1
- package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts.map +1 -1
- package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1144 -611
- package/dist/esm/index.mjs +1144 -611
- package/dist/esm/libs/iframe-processor/index.d.ts +2 -5
- package/dist/esm/libs/iframe-processor/index.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/lifecycle.d.ts +15 -7
- package/dist/esm/libs/iframe-processor/lifecycle.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/orchestrator.d.ts +13 -45
- package/dist/esm/libs/iframe-processor/orchestrator.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/height-observer/index.d.ts +3 -14
- package/dist/esm/libs/iframe-processor/processors/height-observer/index.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/height-observer/types.d.ts +9 -1
- package/dist/esm/libs/iframe-processor/processors/height-observer/types.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/navigation/index.d.ts +3 -14
- package/dist/esm/libs/iframe-processor/processors/navigation/index.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/navigation/listeners.d.ts +3 -4
- package/dist/esm/libs/iframe-processor/processors/navigation/listeners.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/navigation/types.d.ts +13 -0
- package/dist/esm/libs/iframe-processor/processors/navigation/types.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/fixes.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/gem-slider-item/fixes.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/types.d.ts +2 -2
- package/dist/esm/libs/iframe-processor/processors/viewport/index.d.ts +3 -9
- package/dist/esm/libs/iframe-processor/processors/viewport/index.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/viewport/listeners.d.ts +3 -2
- package/dist/esm/libs/iframe-processor/processors/viewport/listeners.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/viewport/pipeline.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/viewport/shop-overrides/types.d.ts +2 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/shop-overrides/types.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/constants.d.ts +5 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/constants.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts +11 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/index.d.ts +9 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/index.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts +13 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/types.d.ts +16 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/types.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/types.d.ts +8 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/types.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/shared/factory-types.d.ts +24 -0
- package/dist/esm/libs/iframe-processor/shared/factory-types.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/shared/iframe-types.d.ts +20 -0
- package/dist/esm/libs/iframe-processor/shared/iframe-types.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/shared/perf.d.ts +58 -0
- package/dist/esm/libs/iframe-processor/shared/perf.d.ts.map +1 -0
- package/dist/esm/stores/config.d.ts +0 -2
- package/dist/esm/stores/config.d.ts.map +1 -1
- package/dist/esm/stores/data.d.ts +2 -0
- package/dist/esm/stores/data.d.ts.map +1 -1
- package/dist/esm/stores/mode-live.d.ts +30 -16
- package/dist/esm/stores/mode-live.d.ts.map +1 -1
- package/dist/esm/stores/setting.d.ts +3 -1
- package/dist/esm/stores/setting.d.ts.map +1 -1
- package/dist/esm/stores/viz.d.ts +2 -2
- package/dist/esm/stores/viz.d.ts.map +1 -1
- package/dist/esm/types/heatmap.d.ts +4 -0
- package/dist/esm/types/heatmap.d.ts.map +1 -1
- package/dist/esm/types/iframe-helper.d.ts +0 -19
- package/dist/esm/types/iframe-helper.d.ts.map +1 -1
- package/dist/umd/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
- package/dist/umd/hooks/view-context/index.d.ts +1 -0
- package/dist/umd/hooks/view-context/index.d.ts.map +1 -1
- package/dist/umd/hooks/view-context/useHeatmapCopyView.d.ts.map +1 -1
- package/dist/umd/hooks/view-context/useHeatmapDataContext.d.ts +2 -16
- package/dist/umd/hooks/view-context/useHeatmapDataContext.d.ts.map +1 -1
- package/dist/umd/hooks/view-context/useHeatmapLiveContext.d.ts +34 -0
- package/dist/umd/hooks/view-context/useHeatmapLiveContext.d.ts.map +1 -0
- package/dist/umd/hooks/view-context/useHeatmapSettingContext.d.ts +3 -1
- package/dist/umd/hooks/view-context/useHeatmapSettingContext.d.ts.map +1 -1
- package/dist/umd/hooks/view-context/useHeatmapVizContext.d.ts +2 -2
- package/dist/umd/hooks/view-context/useHeatmapVizContext.d.ts.map +1 -1
- package/dist/umd/hooks/viz-live/useVizLiveIframeMsg.d.ts.map +1 -1
- package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts.map +1 -1
- package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
- package/dist/umd/index.d.ts +1 -1
- package/dist/umd/index.d.ts.map +1 -1
- package/dist/umd/index.js +2 -2
- package/dist/umd/libs/iframe-processor/index.d.ts +2 -5
- package/dist/umd/libs/iframe-processor/index.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/lifecycle.d.ts +15 -7
- package/dist/umd/libs/iframe-processor/lifecycle.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/orchestrator.d.ts +13 -45
- package/dist/umd/libs/iframe-processor/orchestrator.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/height-observer/index.d.ts +3 -14
- package/dist/umd/libs/iframe-processor/processors/height-observer/index.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/height-observer/types.d.ts +9 -1
- package/dist/umd/libs/iframe-processor/processors/height-observer/types.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/navigation/index.d.ts +3 -14
- package/dist/umd/libs/iframe-processor/processors/navigation/index.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/navigation/listeners.d.ts +3 -4
- package/dist/umd/libs/iframe-processor/processors/navigation/listeners.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/navigation/types.d.ts +13 -0
- package/dist/umd/libs/iframe-processor/processors/navigation/types.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/fixes.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/gem-slider-item/fixes.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/types.d.ts +2 -2
- package/dist/umd/libs/iframe-processor/processors/viewport/index.d.ts +3 -9
- package/dist/umd/libs/iframe-processor/processors/viewport/index.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/viewport/listeners.d.ts +3 -2
- package/dist/umd/libs/iframe-processor/processors/viewport/listeners.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/viewport/pipeline.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/viewport/shop-overrides/types.d.ts +2 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/shop-overrides/types.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/constants.d.ts +5 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/constants.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts +11 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/index.d.ts +9 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/index.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts +13 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/types.d.ts +16 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/types.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/types.d.ts +8 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/types.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/shared/factory-types.d.ts +24 -0
- package/dist/umd/libs/iframe-processor/shared/factory-types.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/shared/iframe-types.d.ts +20 -0
- package/dist/umd/libs/iframe-processor/shared/iframe-types.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/shared/perf.d.ts +58 -0
- package/dist/umd/libs/iframe-processor/shared/perf.d.ts.map +1 -0
- package/dist/umd/stores/config.d.ts +0 -2
- package/dist/umd/stores/config.d.ts.map +1 -1
- package/dist/umd/stores/data.d.ts +2 -0
- package/dist/umd/stores/data.d.ts.map +1 -1
- package/dist/umd/stores/mode-live.d.ts +30 -16
- package/dist/umd/stores/mode-live.d.ts.map +1 -1
- package/dist/umd/stores/setting.d.ts +3 -1
- package/dist/umd/stores/setting.d.ts.map +1 -1
- package/dist/umd/stores/viz.d.ts +2 -2
- package/dist/umd/stores/viz.d.ts.map +1 -1
- package/dist/umd/types/heatmap.d.ts +4 -0
- package/dist/umd/types/heatmap.d.ts.map +1 -1
- package/dist/umd/types/iframe-helper.d.ts +0 -19
- package/dist/umd/types/iframe-helper.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer.d.ts +0 -54
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer.d.ts.map +0 -1
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer.d.ts +0 -54
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer.d.ts.map +0 -1
package/dist/esm/index.mjs
CHANGED
|
@@ -203,6 +203,11 @@ var EHeatmapMode;
|
|
|
203
203
|
EHeatmapMode["Live"] = "live";
|
|
204
204
|
EHeatmapMode["Compare"] = "compare";
|
|
205
205
|
})(EHeatmapMode || (EHeatmapMode = {}));
|
|
206
|
+
var EHeatmapDataSource;
|
|
207
|
+
(function (EHeatmapDataSource) {
|
|
208
|
+
EHeatmapDataSource["Snapshot"] = "snapshot";
|
|
209
|
+
EHeatmapDataSource["Live"] = "live";
|
|
210
|
+
})(EHeatmapDataSource || (EHeatmapDataSource = {}));
|
|
206
211
|
|
|
207
212
|
const ViewIdContext = createContext(undefined);
|
|
208
213
|
const useViewIdContext = () => {
|
|
@@ -314,18 +319,16 @@ const useHeatmapConfigStore = create()((set) => {
|
|
|
314
319
|
return {
|
|
315
320
|
mode: EHeatmapMode.Single,
|
|
316
321
|
sidebarWidth: DEFAULT_SIDEBAR_WIDTH,
|
|
317
|
-
clickMode: EClickMode.Default,
|
|
318
|
-
isRendering: true,
|
|
319
322
|
setMode: (mode) => set({ mode }),
|
|
320
323
|
resetMode: () => set({ mode: EHeatmapMode.Single }),
|
|
321
324
|
setSidebarWidth: (sidebarWidth) => set({ sidebarWidth }),
|
|
322
|
-
setIsRendering: (isRendering) => set({ isRendering }),
|
|
323
325
|
};
|
|
324
326
|
});
|
|
325
327
|
|
|
326
328
|
const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
|
|
327
329
|
return {
|
|
328
330
|
data: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
331
|
+
dataSnapshot: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
329
332
|
clickmap: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
330
333
|
clickAreas: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
331
334
|
dataInfo: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
@@ -358,6 +361,11 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
|
|
|
358
361
|
newData.set(viewId, data);
|
|
359
362
|
return { data: newData };
|
|
360
363
|
}),
|
|
364
|
+
setDataSnapshot: (data, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
365
|
+
const newDataSnapshot = new Map(prev.dataSnapshot);
|
|
366
|
+
newDataSnapshot.set(viewId, data);
|
|
367
|
+
return { dataSnapshot: newDataSnapshot };
|
|
368
|
+
}),
|
|
361
369
|
setClickmap: (clickmap, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
362
370
|
const newClickmap = new Map(prev.clickmap);
|
|
363
371
|
newClickmap.set(viewId, clickmap);
|
|
@@ -380,12 +388,14 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
|
|
|
380
388
|
}),
|
|
381
389
|
copyView: (fromViewId, toViewId) => set((prev) => {
|
|
382
390
|
const newData = new Map(prev.data);
|
|
391
|
+
const newDataSnapshot = new Map(prev.dataSnapshot);
|
|
383
392
|
const newClickmap = new Map(prev.clickmap);
|
|
384
393
|
const newClickAreas = new Map(prev.clickAreas);
|
|
385
394
|
const newDataInfo = new Map(prev.dataInfo);
|
|
386
395
|
const newScrollmap = new Map(prev.scrollmap);
|
|
387
396
|
const newAttentionMap = new Map(prev.attentionMap);
|
|
388
397
|
newData.set(toViewId, prev.data.get(fromViewId));
|
|
398
|
+
newDataSnapshot.set(toViewId, prev.dataSnapshot.get(fromViewId));
|
|
389
399
|
newClickmap.set(toViewId, prev.clickmap.get(fromViewId));
|
|
390
400
|
newClickAreas.set(toViewId, prev.clickAreas.get(fromViewId));
|
|
391
401
|
newDataInfo.set(toViewId, prev.dataInfo.get(fromViewId));
|
|
@@ -393,6 +403,7 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
|
|
|
393
403
|
newAttentionMap.set(toViewId, prev.attentionMap.get(fromViewId));
|
|
394
404
|
return {
|
|
395
405
|
data: newData,
|
|
406
|
+
dataSnapshot: newDataSnapshot,
|
|
396
407
|
clickmap: newClickmap,
|
|
397
408
|
clickAreas: newClickAreas,
|
|
398
409
|
dataInfo: newDataInfo,
|
|
@@ -402,12 +413,14 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
|
|
|
402
413
|
}),
|
|
403
414
|
clearView: (viewId) => set((prev) => {
|
|
404
415
|
const newData = new Map(prev.data);
|
|
416
|
+
const newDataSnapshot = new Map(prev.dataSnapshot);
|
|
405
417
|
const newClickmap = new Map(prev.clickmap);
|
|
406
418
|
const newClickAreas = new Map(prev.clickAreas);
|
|
407
419
|
const newDataInfo = new Map(prev.dataInfo);
|
|
408
420
|
const newScrollmap = new Map(prev.scrollmap);
|
|
409
421
|
const newAttentionMap = new Map(prev.attentionMap);
|
|
410
422
|
newData.delete(viewId);
|
|
423
|
+
newDataSnapshot.delete(viewId);
|
|
411
424
|
newClickmap.delete(viewId);
|
|
412
425
|
newClickAreas.delete(viewId);
|
|
413
426
|
newDataInfo.delete(viewId);
|
|
@@ -415,6 +428,7 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
|
|
|
415
428
|
newAttentionMap.delete(viewId);
|
|
416
429
|
return {
|
|
417
430
|
data: newData,
|
|
431
|
+
dataSnapshot: newDataSnapshot,
|
|
418
432
|
clickmap: newClickmap,
|
|
419
433
|
clickAreas: newClickAreas,
|
|
420
434
|
dataInfo: newDataInfo,
|
|
@@ -424,6 +438,7 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
|
|
|
424
438
|
}),
|
|
425
439
|
resetAll: () => set({
|
|
426
440
|
data: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
441
|
+
dataSnapshot: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
427
442
|
clickmap: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
428
443
|
clickAreas: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
429
444
|
dataInfo: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
@@ -445,6 +460,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
445
460
|
clickMode: new Map([[DEFAULT_VIEW_ID, EClickMode.Default]]),
|
|
446
461
|
scrollType: new Map([[DEFAULT_VIEW_ID, EScrollType.Depth]]),
|
|
447
462
|
heatmapType: new Map([[DEFAULT_VIEW_ID, EHeatmapType.Click]]),
|
|
463
|
+
dataSource: new Map([[DEFAULT_VIEW_ID, EHeatmapDataSource.Snapshot]]),
|
|
448
464
|
setIsRendering: (isRendering, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
449
465
|
const newIsRendering = new Map(prev.isRendering);
|
|
450
466
|
newIsRendering.set(viewId, isRendering);
|
|
@@ -495,6 +511,11 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
495
511
|
newHeatmapType.set(viewId, heatmapType);
|
|
496
512
|
return { heatmapType: newHeatmapType };
|
|
497
513
|
}),
|
|
514
|
+
setDataSource: (dataSource, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
515
|
+
const newDataSource = new Map(prev.dataSource);
|
|
516
|
+
newDataSource.set(viewId, dataSource);
|
|
517
|
+
return { dataSource: newDataSource };
|
|
518
|
+
}),
|
|
498
519
|
copyView: (fromViewId, toViewId) => set((prev) => {
|
|
499
520
|
const newIsLoadingDom = new Map(prev.isLoadingDom);
|
|
500
521
|
const newIsLoadingCanvas = new Map(prev.isLoadingCanvas);
|
|
@@ -505,6 +526,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
505
526
|
const newClickMode = new Map(prev.clickMode);
|
|
506
527
|
const newScrollType = new Map(prev.scrollType);
|
|
507
528
|
const newHeatmapType = new Map(prev.heatmapType);
|
|
529
|
+
const newDataSource = new Map(prev.dataSource);
|
|
508
530
|
newIsShowSidebar.set(toViewId, prev.isShowSidebar.get(fromViewId) ?? false);
|
|
509
531
|
newRankedBy.set(toViewId, prev.rankedBy.get(fromViewId));
|
|
510
532
|
newDeviceType.set(toViewId, prev.deviceType.get(fromViewId));
|
|
@@ -514,6 +536,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
514
536
|
newHeatmapType.set(toViewId, prev.heatmapType.get(fromViewId));
|
|
515
537
|
newIsLoadingDom.set(toViewId, prev.isLoadingDom.get(fromViewId) ?? false);
|
|
516
538
|
newIsLoadingCanvas.set(toViewId, prev.isLoadingCanvas.get(fromViewId) ?? false);
|
|
539
|
+
newDataSource.set(toViewId, prev.dataSource.get(fromViewId) ?? EHeatmapDataSource.Snapshot);
|
|
517
540
|
return {
|
|
518
541
|
isShowSidebar: newIsShowSidebar,
|
|
519
542
|
rankedBy: newRankedBy,
|
|
@@ -524,6 +547,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
524
547
|
clickMode: newClickMode,
|
|
525
548
|
scrollType: newScrollType,
|
|
526
549
|
heatmapType: newHeatmapType,
|
|
550
|
+
dataSource: newDataSource,
|
|
527
551
|
};
|
|
528
552
|
}),
|
|
529
553
|
clearView: (viewId) => set((prev) => {
|
|
@@ -536,6 +560,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
536
560
|
const newClickMode = new Map(prev.clickMode);
|
|
537
561
|
const newScrollType = new Map(prev.scrollType);
|
|
538
562
|
const newHeatmapType = new Map(prev.heatmapType);
|
|
563
|
+
const newDataSource = new Map(prev.dataSource);
|
|
539
564
|
newIsShowSidebar.delete(viewId);
|
|
540
565
|
newRankedBy.delete(viewId);
|
|
541
566
|
newIsLoadingDom.delete(viewId);
|
|
@@ -545,6 +570,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
545
570
|
newClickMode.delete(viewId);
|
|
546
571
|
newScrollType.delete(viewId);
|
|
547
572
|
newHeatmapType.delete(viewId);
|
|
573
|
+
newDataSource.delete(viewId);
|
|
548
574
|
return {
|
|
549
575
|
isShowSidebar: newIsShowSidebar,
|
|
550
576
|
rankedBy: newRankedBy,
|
|
@@ -555,6 +581,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
555
581
|
clickMode: newClickMode,
|
|
556
582
|
scrollType: newScrollType,
|
|
557
583
|
heatmapType: newHeatmapType,
|
|
584
|
+
dataSource: newDataSource,
|
|
558
585
|
};
|
|
559
586
|
}),
|
|
560
587
|
resetAll: () => set({
|
|
@@ -568,22 +595,23 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
568
595
|
clickMode: new Map([[DEFAULT_VIEW_ID, EClickMode.Default]]),
|
|
569
596
|
scrollType: new Map([[DEFAULT_VIEW_ID, EScrollType.Depth]]),
|
|
570
597
|
heatmapType: new Map([[DEFAULT_VIEW_ID, EHeatmapType.Click]]),
|
|
598
|
+
dataSource: new Map([[DEFAULT_VIEW_ID, EHeatmapDataSource.Snapshot]]),
|
|
571
599
|
}),
|
|
572
600
|
};
|
|
573
601
|
}));
|
|
574
602
|
|
|
575
603
|
const useHeatmapVizStore = create()(subscribeWithSelector((set) => {
|
|
576
604
|
return {
|
|
577
|
-
|
|
605
|
+
isRenderedViz: new Map([[DEFAULT_VIEW_ID, false]]),
|
|
578
606
|
zoomRatio: new Map([[DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO.DEFAULT]]),
|
|
579
607
|
minZoomRatio: new Map([[DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO.MIN]]),
|
|
580
608
|
maxZoomRatio: new Map([[DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO.MAX]]),
|
|
581
609
|
scale: new Map([[DEFAULT_VIEW_ID, 1]]),
|
|
582
610
|
isScaledToFit: new Map([[DEFAULT_VIEW_ID, false]]),
|
|
583
|
-
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
return {
|
|
611
|
+
setIsRenderedViz: (isRenderedViz, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
612
|
+
const newIsRenderedViz = new Map(prev.isRenderedViz);
|
|
613
|
+
newIsRenderedViz.set(viewId, isRenderedViz);
|
|
614
|
+
return { isRenderedViz: newIsRenderedViz };
|
|
587
615
|
}),
|
|
588
616
|
setZoomRatio: (zoomRatio, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
589
617
|
const newZoomRatio = new Map(prev.zoomRatio);
|
|
@@ -611,18 +639,18 @@ const useHeatmapVizStore = create()(subscribeWithSelector((set) => {
|
|
|
611
639
|
return { isScaledToFit: newIsScaledToFit };
|
|
612
640
|
}),
|
|
613
641
|
copyView: (fromViewId, toViewId) => set((prev) => {
|
|
614
|
-
const
|
|
642
|
+
const newIsRenderedViz = new Map(prev.isRenderedViz);
|
|
615
643
|
const newZoomRatio = new Map(prev.zoomRatio);
|
|
616
644
|
const newMinZoomRatio = new Map(prev.minZoomRatio);
|
|
617
645
|
const newScale = new Map(prev.scale);
|
|
618
646
|
const newIsScaledToFit = new Map(prev.isScaledToFit);
|
|
619
|
-
|
|
647
|
+
newIsRenderedViz.set(toViewId, prev.isRenderedViz.get(fromViewId) ?? false);
|
|
620
648
|
newZoomRatio.set(toViewId, prev.zoomRatio.get(fromViewId) ?? 100);
|
|
621
649
|
newMinZoomRatio.set(toViewId, prev.minZoomRatio.get(fromViewId) ?? 10);
|
|
622
650
|
newScale.set(toViewId, prev.scale.get(fromViewId) ?? 1);
|
|
623
651
|
newIsScaledToFit.set(toViewId, prev.isScaledToFit.get(fromViewId) ?? false);
|
|
624
652
|
return {
|
|
625
|
-
|
|
653
|
+
isRenderedViz: newIsRenderedViz,
|
|
626
654
|
zoomRatio: newZoomRatio,
|
|
627
655
|
minZoomRatio: newMinZoomRatio,
|
|
628
656
|
scale: newScale,
|
|
@@ -630,18 +658,18 @@ const useHeatmapVizStore = create()(subscribeWithSelector((set) => {
|
|
|
630
658
|
};
|
|
631
659
|
}),
|
|
632
660
|
clearView: (viewId) => set((prev) => {
|
|
633
|
-
const
|
|
661
|
+
const newIsRenderedViz = new Map(prev.isRenderedViz);
|
|
634
662
|
const newZoomRatio = new Map(prev.zoomRatio);
|
|
635
663
|
const newMinZoomRatio = new Map(prev.minZoomRatio);
|
|
636
664
|
const newScale = new Map(prev.scale);
|
|
637
665
|
const newIsScaledToFit = new Map(prev.isScaledToFit);
|
|
638
|
-
|
|
666
|
+
newIsRenderedViz.delete(viewId);
|
|
639
667
|
newZoomRatio.delete(viewId);
|
|
640
668
|
newMinZoomRatio.delete(viewId);
|
|
641
669
|
newScale.delete(viewId);
|
|
642
670
|
newIsScaledToFit.delete(viewId);
|
|
643
671
|
return {
|
|
644
|
-
|
|
672
|
+
isRenderedViz: newIsRenderedViz,
|
|
645
673
|
zoomRatio: newZoomRatio,
|
|
646
674
|
minZoomRatio: newMinZoomRatio,
|
|
647
675
|
scale: newScale,
|
|
@@ -649,7 +677,7 @@ const useHeatmapVizStore = create()(subscribeWithSelector((set) => {
|
|
|
649
677
|
};
|
|
650
678
|
}),
|
|
651
679
|
resetAll: () => set({
|
|
652
|
-
|
|
680
|
+
isRenderedViz: new Map([[DEFAULT_VIEW_ID, false]]),
|
|
653
681
|
zoomRatio: new Map([[DEFAULT_VIEW_ID, 100]]),
|
|
654
682
|
minZoomRatio: new Map([[DEFAULT_VIEW_ID, 10]]),
|
|
655
683
|
scale: new Map([[DEFAULT_VIEW_ID, 1]]),
|
|
@@ -1047,24 +1075,108 @@ const useHeatmapCompareStore = create()((set, get) => {
|
|
|
1047
1075
|
});
|
|
1048
1076
|
|
|
1049
1077
|
const initialState = {
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1078
|
+
decodedPayloads: new Map([[DEFAULT_VIEW_ID, []]]),
|
|
1079
|
+
encodedPayloads: new Map([[DEFAULT_VIEW_ID, []]]),
|
|
1080
|
+
htmlContent: new Map([[DEFAULT_VIEW_ID, '']]),
|
|
1081
|
+
targetUrl: new Map([[DEFAULT_VIEW_ID, '']]),
|
|
1082
|
+
renderMode: new Map([[DEFAULT_VIEW_ID, 'portal']]),
|
|
1083
|
+
storefrontPassword: new Map([[DEFAULT_VIEW_ID, '']]),
|
|
1084
|
+
};
|
|
1085
|
+
const useHeatmapLiveStore = create()(subscribeWithSelector((set) => ({
|
|
1086
|
+
...initialState,
|
|
1087
|
+
addPayload: (payload, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1088
|
+
const newDecoded = new Map(prev.decodedPayloads);
|
|
1089
|
+
newDecoded.set(viewId, [...(newDecoded.get(viewId) ?? []), payload]);
|
|
1090
|
+
const newEncoded = new Map(prev.encodedPayloads);
|
|
1091
|
+
newEncoded.set(viewId, [...(newEncoded.get(viewId) ?? []), JSON.stringify(payload)]);
|
|
1092
|
+
return { decodedPayloads: newDecoded, encodedPayloads: newEncoded };
|
|
1093
|
+
}),
|
|
1094
|
+
setPayloads: (payloads, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1095
|
+
const newDecoded = new Map(prev.decodedPayloads);
|
|
1096
|
+
newDecoded.set(viewId, payloads);
|
|
1097
|
+
const newEncoded = new Map(prev.encodedPayloads);
|
|
1098
|
+
newEncoded.set(viewId, payloads.map((p) => JSON.stringify(p)));
|
|
1099
|
+
return { decodedPayloads: newDecoded, encodedPayloads: newEncoded };
|
|
1100
|
+
}),
|
|
1101
|
+
setEncodedPayloads: (payloads, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1102
|
+
const newEncoded = new Map(prev.encodedPayloads);
|
|
1103
|
+
newEncoded.set(viewId, payloads);
|
|
1104
|
+
return { encodedPayloads: newEncoded };
|
|
1105
|
+
}),
|
|
1106
|
+
setHtmlContent: (htmlContent, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1107
|
+
const newHtmlContent = new Map(prev.htmlContent);
|
|
1108
|
+
newHtmlContent.set(viewId, htmlContent);
|
|
1109
|
+
return { htmlContent: newHtmlContent };
|
|
1110
|
+
}),
|
|
1111
|
+
setTargetUrl: (targetUrl, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1112
|
+
const newTargetUrl = new Map(prev.targetUrl);
|
|
1113
|
+
newTargetUrl.set(viewId, targetUrl);
|
|
1114
|
+
return { targetUrl: newTargetUrl };
|
|
1115
|
+
}),
|
|
1116
|
+
setRenderMode: (renderMode, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1117
|
+
const newRenderMode = new Map(prev.renderMode);
|
|
1118
|
+
newRenderMode.set(viewId, renderMode);
|
|
1119
|
+
return { renderMode: newRenderMode };
|
|
1120
|
+
}),
|
|
1121
|
+
setStorefrontPassword: (storefrontPassword, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1122
|
+
const newStorefrontPassword = new Map(prev.storefrontPassword);
|
|
1123
|
+
newStorefrontPassword.set(viewId, storefrontPassword);
|
|
1124
|
+
return { storefrontPassword: newStorefrontPassword };
|
|
1125
|
+
}),
|
|
1126
|
+
resetView: (viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1127
|
+
const newDecoded = new Map(prev.decodedPayloads);
|
|
1128
|
+
newDecoded.set(viewId, []);
|
|
1129
|
+
const newEncoded = new Map(prev.encodedPayloads);
|
|
1130
|
+
newEncoded.set(viewId, []);
|
|
1131
|
+
return { decodedPayloads: newDecoded, encodedPayloads: newEncoded };
|
|
1132
|
+
}),
|
|
1133
|
+
copyView: (fromViewId, toViewId) => set((prev) => {
|
|
1134
|
+
const newDecoded = new Map(prev.decodedPayloads);
|
|
1135
|
+
const newEncoded = new Map(prev.encodedPayloads);
|
|
1136
|
+
const newHtmlContent = new Map(prev.htmlContent);
|
|
1137
|
+
const newTargetUrl = new Map(prev.targetUrl);
|
|
1138
|
+
const newRenderMode = new Map(prev.renderMode);
|
|
1139
|
+
const newStorefrontPassword = new Map(prev.storefrontPassword);
|
|
1140
|
+
newDecoded.set(toViewId, prev.decodedPayloads.get(fromViewId) ?? []);
|
|
1141
|
+
newEncoded.set(toViewId, prev.encodedPayloads.get(fromViewId) ?? []);
|
|
1142
|
+
newHtmlContent.set(toViewId, prev.htmlContent.get(fromViewId) ?? '');
|
|
1143
|
+
newTargetUrl.set(toViewId, prev.targetUrl.get(fromViewId) ?? '');
|
|
1144
|
+
newRenderMode.set(toViewId, prev.renderMode.get(fromViewId) ?? 'portal');
|
|
1145
|
+
newStorefrontPassword.set(toViewId, prev.storefrontPassword.get(fromViewId) ?? '');
|
|
1146
|
+
return {
|
|
1147
|
+
decodedPayloads: newDecoded,
|
|
1148
|
+
encodedPayloads: newEncoded,
|
|
1149
|
+
htmlContent: newHtmlContent,
|
|
1150
|
+
targetUrl: newTargetUrl,
|
|
1151
|
+
renderMode: newRenderMode,
|
|
1152
|
+
storefrontPassword: newStorefrontPassword,
|
|
1153
|
+
};
|
|
1154
|
+
}),
|
|
1155
|
+
clearView: (viewId) => set((prev) => {
|
|
1156
|
+
const newDecoded = new Map(prev.decodedPayloads);
|
|
1157
|
+
const newEncoded = new Map(prev.encodedPayloads);
|
|
1158
|
+
const newHtmlContent = new Map(prev.htmlContent);
|
|
1159
|
+
const newTargetUrl = new Map(prev.targetUrl);
|
|
1160
|
+
const newRenderMode = new Map(prev.renderMode);
|
|
1161
|
+
const newStorefrontPassword = new Map(prev.storefrontPassword);
|
|
1162
|
+
newDecoded.delete(viewId);
|
|
1163
|
+
newEncoded.delete(viewId);
|
|
1164
|
+
newHtmlContent.delete(viewId);
|
|
1165
|
+
newTargetUrl.delete(viewId);
|
|
1166
|
+
newRenderMode.delete(viewId);
|
|
1167
|
+
newStorefrontPassword.delete(viewId);
|
|
1168
|
+
return {
|
|
1169
|
+
decodedPayloads: newDecoded,
|
|
1170
|
+
encodedPayloads: newEncoded,
|
|
1171
|
+
htmlContent: newHtmlContent,
|
|
1172
|
+
targetUrl: newTargetUrl,
|
|
1173
|
+
renderMode: newRenderMode,
|
|
1174
|
+
storefrontPassword: newStorefrontPassword,
|
|
1175
|
+
};
|
|
1176
|
+
}),
|
|
1177
|
+
resetAll: () => set(initialState),
|
|
1178
|
+
reset: () => set(initialState),
|
|
1179
|
+
})));
|
|
1068
1180
|
|
|
1069
1181
|
const useHeatmapVizRectStore = create()(subscribeWithSelector((set) => {
|
|
1070
1182
|
return {
|
|
@@ -1170,26 +1282,11 @@ const useHeatmapClickContext = createViewContextHook({
|
|
|
1170
1282
|
}),
|
|
1171
1283
|
});
|
|
1172
1284
|
|
|
1173
|
-
/**
|
|
1174
|
-
* Hook to access heatmap data state and actions with optional selector
|
|
1175
|
-
*
|
|
1176
|
-
* @example
|
|
1177
|
-
* ```tsx
|
|
1178
|
-
* // Get everything
|
|
1179
|
-
* const { data, clickmap, setData } = useHeatmapDataContext();
|
|
1180
|
-
*
|
|
1181
|
-
* // Get only what you need (no unnecessary re-renders)
|
|
1182
|
-
* const data = useHeatmapDataContext(s => s.data);
|
|
1183
|
-
* const { setData, setClickmap } = useHeatmapDataContext(s => ({
|
|
1184
|
-
* setData: s.setData,
|
|
1185
|
-
* setClickmap: s.setClickmap,
|
|
1186
|
-
* }));
|
|
1187
|
-
* ```
|
|
1188
|
-
*/
|
|
1189
1285
|
const useHeatmapDataContext = createViewContextHook({
|
|
1190
1286
|
useStore: useHeatmapDataStore,
|
|
1191
1287
|
getState: (store, viewId) => ({
|
|
1192
1288
|
data: store.data.get(viewId),
|
|
1289
|
+
dataSnapshot: store.dataSnapshot.get(viewId),
|
|
1193
1290
|
clickmap: store.clickmap.get(viewId),
|
|
1194
1291
|
clickAreas: store.clickAreas.get(viewId),
|
|
1195
1292
|
scrollmap: store.scrollmap.get(viewId),
|
|
@@ -1199,6 +1296,7 @@ const useHeatmapDataContext = createViewContextHook({
|
|
|
1199
1296
|
}),
|
|
1200
1297
|
getActions: (store, viewId) => ({
|
|
1201
1298
|
setData: (newData) => store.setData(newData, viewId),
|
|
1299
|
+
setDataSnapshot: (newData) => store.setDataSnapshot(newData, viewId),
|
|
1202
1300
|
setClickmap: (newClickmap) => store.setClickmap(newClickmap, viewId),
|
|
1203
1301
|
setClickAreas: (newClickAreas) => store.setClickAreas(newClickAreas, viewId),
|
|
1204
1302
|
setDataInfoByKey: (key, value) => store.setDataInfoByKey(key, value, viewId),
|
|
@@ -1221,6 +1319,32 @@ const useHeatmapHoverContext = createViewContextHook({
|
|
|
1221
1319
|
}),
|
|
1222
1320
|
});
|
|
1223
1321
|
|
|
1322
|
+
const useHeatmapLiveContext = createViewContextHook({
|
|
1323
|
+
useStore: useHeatmapLiveStore,
|
|
1324
|
+
getState: (store, viewId) => ({
|
|
1325
|
+
decodedPayloads: store.decodedPayloads.get(viewId) ?? [],
|
|
1326
|
+
encodedPayloads: store.encodedPayloads.get(viewId) ?? [],
|
|
1327
|
+
htmlContent: store.htmlContent.get(viewId) ?? '',
|
|
1328
|
+
targetUrl: store.targetUrl.get(viewId) ?? '',
|
|
1329
|
+
renderMode: store.renderMode.get(viewId) ?? 'portal',
|
|
1330
|
+
storefrontPassword: store.storefrontPassword.get(viewId) ?? '',
|
|
1331
|
+
}),
|
|
1332
|
+
getActions: (store, viewId) => ({
|
|
1333
|
+
addPayload: (payload) => store.addPayload(payload, viewId),
|
|
1334
|
+
setPayloads: (payloads) => store.setPayloads(payloads, viewId),
|
|
1335
|
+
setEncodedPayloads: (payloads) => store.setEncodedPayloads(payloads, viewId),
|
|
1336
|
+
setHtmlContent: (htmlContent) => store.setHtmlContent(htmlContent, viewId),
|
|
1337
|
+
setTargetUrl: (targetUrl) => store.setTargetUrl(targetUrl, viewId),
|
|
1338
|
+
setRenderMode: (mode) => store.setRenderMode(mode, viewId),
|
|
1339
|
+
setStorefrontPassword: (password) => store.setStorefrontPassword(password, viewId),
|
|
1340
|
+
resetView: () => store.resetView(viewId),
|
|
1341
|
+
copyView: (fromViewId, toViewId) => store.copyView(fromViewId, toViewId),
|
|
1342
|
+
clearView: (viewId) => store.clearView(viewId),
|
|
1343
|
+
resetAll: () => store.resetAll(),
|
|
1344
|
+
reset: () => store.reset(),
|
|
1345
|
+
}),
|
|
1346
|
+
});
|
|
1347
|
+
|
|
1224
1348
|
const useHeatmapScrollContext = createViewContextHook({
|
|
1225
1349
|
useStore: useHeatmapVizScrollStore,
|
|
1226
1350
|
getState: (store, viewId) => ({
|
|
@@ -1250,6 +1374,7 @@ const useHeatmapSettingContext = createViewContextHook({
|
|
|
1250
1374
|
clickMode: store.clickMode.get(viewId),
|
|
1251
1375
|
scrollType: store.scrollType.get(viewId),
|
|
1252
1376
|
heatmapType: store.heatmapType.get(viewId),
|
|
1377
|
+
dataSource: store.dataSource.get(viewId) ?? EHeatmapDataSource.Snapshot,
|
|
1253
1378
|
}),
|
|
1254
1379
|
getActions: (store, viewId) => ({
|
|
1255
1380
|
setIsShowSidebar: (isShowSidebar) => store.setIsShowSidebar(isShowSidebar, viewId),
|
|
@@ -1262,6 +1387,7 @@ const useHeatmapSettingContext = createViewContextHook({
|
|
|
1262
1387
|
setIsRendering: (isRendering) => store.setIsRendering(isRendering, viewId),
|
|
1263
1388
|
setIsLoadingDom: (isLoadingDom) => store.setIsLoadingDom(isLoadingDom, viewId),
|
|
1264
1389
|
setIsLoadingCanvas: (isLoadingCanvas) => store.setIsLoadingCanvas(isLoadingCanvas, viewId),
|
|
1390
|
+
setDataSource: (dataSource) => store.setDataSource(dataSource, viewId),
|
|
1265
1391
|
clearView: (viewId) => store.clearView(viewId),
|
|
1266
1392
|
}),
|
|
1267
1393
|
});
|
|
@@ -1269,7 +1395,7 @@ const useHeatmapSettingContext = createViewContextHook({
|
|
|
1269
1395
|
const useHeatmapVizContext = createViewContextHook({
|
|
1270
1396
|
useStore: useHeatmapVizStore,
|
|
1271
1397
|
getState: (store, viewId) => ({
|
|
1272
|
-
|
|
1398
|
+
isRenderedViz: store.isRenderedViz.get(viewId) ?? false,
|
|
1273
1399
|
zoomRatio: store.zoomRatio.get(viewId) ?? DEFAULT_ZOOM_RATIO.DEFAULT,
|
|
1274
1400
|
minZoomRatio: store.minZoomRatio.get(viewId) ?? DEFAULT_ZOOM_RATIO.MIN,
|
|
1275
1401
|
maxZoomRatio: store.maxZoomRatio.get(viewId) ?? DEFAULT_ZOOM_RATIO.MAX,
|
|
@@ -1277,7 +1403,7 @@ const useHeatmapVizContext = createViewContextHook({
|
|
|
1277
1403
|
isScaledToFit: store.isScaledToFit.get(viewId) ?? false,
|
|
1278
1404
|
}),
|
|
1279
1405
|
getActions: (store, viewId) => ({
|
|
1280
|
-
|
|
1406
|
+
setIsRenderedViz: (value) => store.setIsRenderedViz(value, viewId),
|
|
1281
1407
|
setZoomRatio: (value) => store.setZoomRatio(value, viewId),
|
|
1282
1408
|
setMinZoomRatio: (value) => store.setMinZoomRatio(value, viewId),
|
|
1283
1409
|
setMaxZoomRatio: (value) => store.setMaxZoomRatio(value, viewId),
|
|
@@ -1311,9 +1437,7 @@ const useHeatmapCopyView = () => {
|
|
|
1311
1437
|
const copyVizView = useHeatmapVizStore((state) => state.copyView);
|
|
1312
1438
|
const copyVizClickView = useHeatmapVizClickStore((state) => state.copyView);
|
|
1313
1439
|
const copyVizAreaClickView = useHeatmapVizClickAreaStore((state) => state.copyView);
|
|
1314
|
-
|
|
1315
|
-
// const copyVizHoverView = useHeatmapVizHoverStore((state) => state.copyView);
|
|
1316
|
-
// const copyVizScrollView = useHeatmapVizScrollStore((state) => state.copyView);
|
|
1440
|
+
const copyLiveView = useHeatmapLiveStore((state) => state.copyView);
|
|
1317
1441
|
const clearDataView = useHeatmapDataStore((state) => state.clearView);
|
|
1318
1442
|
const clearSettingView = useHeatmapSettingStore((state) => state.clearView);
|
|
1319
1443
|
const clearVizView = useHeatmapVizStore((state) => state.clearView);
|
|
@@ -1322,6 +1446,7 @@ const useHeatmapCopyView = () => {
|
|
|
1322
1446
|
const clearVizHoverView = useHeatmapVizHoverStore((state) => state.clearView);
|
|
1323
1447
|
const clearVizScrollView = useHeatmapVizScrollStore((state) => state.clearView);
|
|
1324
1448
|
const clearVizAreaClickView = useHeatmapVizClickAreaStore((state) => state.clearView);
|
|
1449
|
+
const clearLiveView = useHeatmapLiveStore((state) => state.clearView);
|
|
1325
1450
|
const resetDataAll = useHeatmapDataStore((state) => state.resetAll);
|
|
1326
1451
|
const resetSettingAll = useHeatmapSettingStore((state) => state.resetAll);
|
|
1327
1452
|
const resetVizAll = useHeatmapVizStore((state) => state.resetAll);
|
|
@@ -1330,15 +1455,14 @@ const useHeatmapCopyView = () => {
|
|
|
1330
1455
|
const resetVizHoverAll = useHeatmapVizHoverStore((state) => state.resetAll);
|
|
1331
1456
|
const resetVizScrollViewAll = useHeatmapVizScrollStore((state) => state.resetAll);
|
|
1332
1457
|
const resetVizClickAreaAll = useHeatmapVizClickAreaStore((state) => state.resetAll);
|
|
1458
|
+
const resetLiveAll = useHeatmapLiveStore((state) => state.resetAll);
|
|
1333
1459
|
const copyView = (fromViewId, toViewId) => {
|
|
1334
1460
|
copyDataView(fromViewId, toViewId);
|
|
1335
1461
|
copySettingView(fromViewId, toViewId);
|
|
1336
1462
|
copyVizView(fromViewId, toViewId);
|
|
1337
|
-
// copyVizRectView(fromViewId, toViewId);
|
|
1338
1463
|
copyVizClickView(fromViewId, toViewId);
|
|
1339
|
-
// copyVizHoverView(fromViewId, toViewId);
|
|
1340
|
-
// copyVizScrollView(fromViewId, toViewId);
|
|
1341
1464
|
copyVizAreaClickView(fromViewId, toViewId);
|
|
1465
|
+
copyLiveView(fromViewId, toViewId);
|
|
1342
1466
|
};
|
|
1343
1467
|
const copyViewToMultiple = (fromViewId, toViewIds) => {
|
|
1344
1468
|
toViewIds.forEach((toViewId) => {
|
|
@@ -1354,6 +1478,7 @@ const useHeatmapCopyView = () => {
|
|
|
1354
1478
|
clearVizHoverView(viewId);
|
|
1355
1479
|
clearVizScrollView(viewId);
|
|
1356
1480
|
clearVizAreaClickView(viewId);
|
|
1481
|
+
clearLiveView(viewId);
|
|
1357
1482
|
};
|
|
1358
1483
|
const clearMultipleViews = (viewIds) => {
|
|
1359
1484
|
viewIds.forEach((viewId) => {
|
|
@@ -1369,6 +1494,7 @@ const useHeatmapCopyView = () => {
|
|
|
1369
1494
|
resetVizHoverAll();
|
|
1370
1495
|
resetVizScrollViewAll();
|
|
1371
1496
|
resetVizClickAreaAll();
|
|
1497
|
+
resetLiveAll();
|
|
1372
1498
|
};
|
|
1373
1499
|
return {
|
|
1374
1500
|
copyView,
|
|
@@ -1770,7 +1896,7 @@ class Logger {
|
|
|
1770
1896
|
}
|
|
1771
1897
|
}
|
|
1772
1898
|
// Export singleton instance
|
|
1773
|
-
const logger$
|
|
1899
|
+
const logger$4 = new Logger();
|
|
1774
1900
|
// Export factory function để tạo logger với config riêng
|
|
1775
1901
|
function createLogger(config = {}) {
|
|
1776
1902
|
const instance = new Logger();
|
|
@@ -2159,7 +2285,7 @@ function findElementByHash(props) {
|
|
|
2159
2285
|
}
|
|
2160
2286
|
}
|
|
2161
2287
|
catch (error) {
|
|
2162
|
-
logger$
|
|
2288
|
+
logger$4.warn(`Invalid selector "${selector}":`, error);
|
|
2163
2289
|
}
|
|
2164
2290
|
const elementByHash = iframeDocument.querySelector(`[data-clarity-hashalpha="${hash}"], [data-clarity-hash="${hash}"], [data-clarity-hashbeta="${hash}"]`);
|
|
2165
2291
|
return elementByHash;
|
|
@@ -2181,7 +2307,7 @@ function hydrateAreaNode(props) {
|
|
|
2181
2307
|
const { id, hash, selector } = persistedData;
|
|
2182
2308
|
const element = findElementByHash({ hash, selector, iframeDocument, vizRef });
|
|
2183
2309
|
if (!element) {
|
|
2184
|
-
logger$
|
|
2310
|
+
logger$4.warn(`Cannot hydrate area ${id}: element not found for hash ${hash} or selector ${selector}`);
|
|
2185
2311
|
return null;
|
|
2186
2312
|
}
|
|
2187
2313
|
const areaNode = buildAreaNode(element, hash, heatmapInfo, shadowRoot, persistedData);
|
|
@@ -2198,7 +2324,7 @@ function hydrateAreas(props) {
|
|
|
2198
2324
|
hydratedAreas.push(area);
|
|
2199
2325
|
}
|
|
2200
2326
|
}
|
|
2201
|
-
logger$
|
|
2327
|
+
logger$4.info(`Hydrated ${hydratedAreas.length} of ${clickAreas.length} persisted areas`);
|
|
2202
2328
|
return hydratedAreas;
|
|
2203
2329
|
}
|
|
2204
2330
|
/**
|
|
@@ -2902,16 +3028,16 @@ const calcCalloutPositionAbsolute = (props) => {
|
|
|
2902
3028
|
|
|
2903
3029
|
function validateAreaCreation(dataInfo, hash, areas) {
|
|
2904
3030
|
if (!dataInfo?.clickMapMetrics || !dataInfo?.totalClicks) {
|
|
2905
|
-
logger$
|
|
3031
|
+
logger$4.warn('Cannot create area: missing heatmap data');
|
|
2906
3032
|
return false;
|
|
2907
3033
|
}
|
|
2908
3034
|
if (!hash) {
|
|
2909
|
-
logger$
|
|
3035
|
+
logger$4.warn('Cannot create area: missing hash');
|
|
2910
3036
|
return false;
|
|
2911
3037
|
}
|
|
2912
3038
|
const alreadyExists = areas.some((area) => area.hash === hash);
|
|
2913
3039
|
if (alreadyExists) {
|
|
2914
|
-
logger$
|
|
3040
|
+
logger$4.warn(`Area already exists for element: ${hash}`);
|
|
2915
3041
|
return false;
|
|
2916
3042
|
}
|
|
2917
3043
|
return true;
|
|
@@ -2924,14 +3050,14 @@ function identifyConflictingAreas(area) {
|
|
|
2924
3050
|
// Case 1: New area is a child of an existing area
|
|
2925
3051
|
if (area.parentNode) {
|
|
2926
3052
|
conflicts.parentId = area.parentNode.id;
|
|
2927
|
-
logger$
|
|
3053
|
+
logger$4.info(`New area "${area.selector}" is a child of existing area "${area.parentNode.selector}". Will remove parent.`);
|
|
2928
3054
|
}
|
|
2929
3055
|
// Case 2: New area is a parent of existing area(s)
|
|
2930
3056
|
if (area.childNodes.size > 0) {
|
|
2931
3057
|
area.childNodes.forEach((childArea) => {
|
|
2932
3058
|
conflicts.childrenIds.push(childArea.id);
|
|
2933
3059
|
});
|
|
2934
|
-
logger$
|
|
3060
|
+
logger$4.info(`New area "${area.selector}" is a parent of ${area.childNodes.size} existing area(s). Will remove children.`);
|
|
2935
3061
|
}
|
|
2936
3062
|
return conflicts;
|
|
2937
3063
|
}
|
|
@@ -2982,7 +3108,7 @@ function useAreaCreation(options = {}) {
|
|
|
2982
3108
|
}
|
|
2983
3109
|
}
|
|
2984
3110
|
catch (error) {
|
|
2985
|
-
logger$
|
|
3111
|
+
logger$4.error('Failed to create area:', error);
|
|
2986
3112
|
}
|
|
2987
3113
|
}, [dataInfo, areas, addArea, removeArea, removeClickArea, customShadowRoot, onAreaCreated]);
|
|
2988
3114
|
return {
|
|
@@ -3097,16 +3223,16 @@ function useAreaHydration(options) {
|
|
|
3097
3223
|
return;
|
|
3098
3224
|
if (!dataInfo)
|
|
3099
3225
|
return;
|
|
3100
|
-
logger$
|
|
3226
|
+
logger$4.info(`Hydrating ${clickAreas.length} persisted areas...`);
|
|
3101
3227
|
const hydratedAreas = hydrateAreas({ clickAreas, heatmapInfo: dataInfo, vizRef, shadowRoot });
|
|
3102
3228
|
if (!hydratedAreas?.length) {
|
|
3103
|
-
logger$
|
|
3229
|
+
logger$4.warn('No areas could be hydrated - all elements may have been removed from DOM');
|
|
3104
3230
|
return;
|
|
3105
3231
|
}
|
|
3106
3232
|
setIsInitializing(true);
|
|
3107
3233
|
buildAreaGraph(hydratedAreas);
|
|
3108
3234
|
setAreas(hydratedAreas);
|
|
3109
|
-
logger$
|
|
3235
|
+
logger$4.info(`Successfully hydrated ${hydratedAreas.length} areas`);
|
|
3110
3236
|
}, [dataInfo, vizRef, isInitializing, clickAreas]);
|
|
3111
3237
|
useEffect(() => {
|
|
3112
3238
|
if (!enabled)
|
|
@@ -3240,7 +3366,7 @@ function useAreaRectSync(options) {
|
|
|
3240
3366
|
area.rect.update(newRect);
|
|
3241
3367
|
}
|
|
3242
3368
|
catch (error) {
|
|
3243
|
-
logger$
|
|
3369
|
+
logger$4.error(`Failed to update rect for area ${area.id}:`, error);
|
|
3244
3370
|
}
|
|
3245
3371
|
});
|
|
3246
3372
|
buildAreaGraph(areas);
|
|
@@ -3345,9 +3471,9 @@ const useAreaClickmap = () => {
|
|
|
3345
3471
|
const useClickmap = () => {
|
|
3346
3472
|
const vizRef = useHeatmapVizRectContext((s) => s.vizRef);
|
|
3347
3473
|
const clickmap = useHeatmapDataContext((s) => s.clickmap);
|
|
3348
|
-
const
|
|
3474
|
+
const isRenderedViz = useHeatmapVizContext((s) => s.isRenderedViz);
|
|
3349
3475
|
const start = useCallback(() => {
|
|
3350
|
-
if (!vizRef || !clickmap || clickmap.length === 0 || !
|
|
3476
|
+
if (!vizRef || !clickmap || clickmap.length === 0 || !isRenderedViz)
|
|
3351
3477
|
return;
|
|
3352
3478
|
try {
|
|
3353
3479
|
vizRef?.clearmap?.();
|
|
@@ -3356,7 +3482,7 @@ const useClickmap = () => {
|
|
|
3356
3482
|
catch (error) {
|
|
3357
3483
|
console.error(`🚀 🐥 ~ useClickmap ~ error:`, error);
|
|
3358
3484
|
}
|
|
3359
|
-
}, [vizRef, clickmap,
|
|
3485
|
+
}, [vizRef, clickmap, isRenderedViz]);
|
|
3360
3486
|
return { start };
|
|
3361
3487
|
};
|
|
3362
3488
|
|
|
@@ -3384,7 +3510,7 @@ const useScrollmap = () => {
|
|
|
3384
3510
|
vizRef?.scrollmap?.(scrollmap);
|
|
3385
3511
|
}
|
|
3386
3512
|
catch (error) {
|
|
3387
|
-
logger$
|
|
3513
|
+
logger$4.error(`🚀 🐥 ~ useScrollmap ~ error:`, error);
|
|
3388
3514
|
}
|
|
3389
3515
|
}, [vizRef, scrollmap]);
|
|
3390
3516
|
return { start };
|
|
@@ -3855,7 +3981,7 @@ var MessageType;
|
|
|
3855
3981
|
})(MessageType || (MessageType = {}));
|
|
3856
3982
|
function useVizLiveIframeMsg(options = {}) {
|
|
3857
3983
|
const { trustedOrigins = [], onMessage } = options;
|
|
3858
|
-
const addPayload =
|
|
3984
|
+
const addPayload = useHeatmapLiveContext((s) => s.addPayload);
|
|
3859
3985
|
const [isReady, setIsReady] = useState(false);
|
|
3860
3986
|
const iframeRef = useRef(null);
|
|
3861
3987
|
const isValidOrigin = useCallback((origin) => {
|
|
@@ -3881,7 +4007,7 @@ function useVizLiveIframeMsg(options = {}) {
|
|
|
3881
4007
|
switch (message.type) {
|
|
3882
4008
|
case MessageType.GX_DOM_TRACKING_PAYLOAD:
|
|
3883
4009
|
if (message.payload) {
|
|
3884
|
-
const data =
|
|
4010
|
+
const data = JSON.parse(message.payload);
|
|
3885
4011
|
if (data) {
|
|
3886
4012
|
addPayload(data);
|
|
3887
4013
|
}
|
|
@@ -3904,21 +4030,324 @@ function useVizLiveIframeMsg(options = {}) {
|
|
|
3904
4030
|
};
|
|
3905
4031
|
}
|
|
3906
4032
|
|
|
4033
|
+
/**
|
|
4034
|
+
* Performance tracker — measures render pipeline timings and stores results
|
|
4035
|
+
* in `window.__gemxPerf` for inspection in DevTools.
|
|
4036
|
+
*
|
|
4037
|
+
* Usage:
|
|
4038
|
+
* perf.startSession('render-1');
|
|
4039
|
+
* const t = perf.mark('viewport.run');
|
|
4040
|
+
* perf.measure('viewport.run', t);
|
|
4041
|
+
* perf.endSession();
|
|
4042
|
+
*
|
|
4043
|
+
* // In DevTools:
|
|
4044
|
+
* window.__gemxPerf.latest
|
|
4045
|
+
* window.__gemxPerf.sessions
|
|
4046
|
+
*/
|
|
4047
|
+
const s = {
|
|
4048
|
+
enabled: true,
|
|
4049
|
+
current: null,
|
|
4050
|
+
sessions: [],
|
|
4051
|
+
maxSessions: 20,
|
|
4052
|
+
};
|
|
4053
|
+
// ── Functions ─────────────────────────────────────────────────────────────────
|
|
4054
|
+
function startSession(id) {
|
|
4055
|
+
if (!s.enabled)
|
|
4056
|
+
return;
|
|
4057
|
+
s.current = { id, startedAt: performance.now(), entries: [] };
|
|
4058
|
+
}
|
|
4059
|
+
function endSession() {
|
|
4060
|
+
if (!s.enabled || !s.current)
|
|
4061
|
+
return null;
|
|
4062
|
+
const session = s.current;
|
|
4063
|
+
session.total = performance.now() - session.startedAt;
|
|
4064
|
+
s.sessions = [session, ...s.sessions].slice(0, s.maxSessions);
|
|
4065
|
+
s.current = null;
|
|
4066
|
+
flush();
|
|
4067
|
+
return session;
|
|
4068
|
+
}
|
|
4069
|
+
/** Record a point-in-time mark. Returns `performance.now()` for use with measure(). */
|
|
4070
|
+
function mark$1(label) {
|
|
4071
|
+
const now = performance.now();
|
|
4072
|
+
if (s.enabled && s.current) {
|
|
4073
|
+
s.current.entries.push({ label, t: now - s.current.startedAt });
|
|
4074
|
+
}
|
|
4075
|
+
return now;
|
|
4076
|
+
}
|
|
4077
|
+
/** Record a duration from a previous mark() timestamp. */
|
|
4078
|
+
function measure$1(label, t0) {
|
|
4079
|
+
const duration = performance.now() - t0;
|
|
4080
|
+
if (s.enabled && s.current) {
|
|
4081
|
+
s.current.entries.push({ label, t: t0 - s.current.startedAt, duration });
|
|
4082
|
+
}
|
|
4083
|
+
return duration;
|
|
4084
|
+
}
|
|
4085
|
+
function getReport() {
|
|
4086
|
+
return {
|
|
4087
|
+
sessions: s.sessions,
|
|
4088
|
+
latest: s.sessions[0] ?? null,
|
|
4089
|
+
};
|
|
4090
|
+
}
|
|
4091
|
+
function clear$1() {
|
|
4092
|
+
s.current = null;
|
|
4093
|
+
s.sessions = [];
|
|
4094
|
+
if (typeof window !== 'undefined')
|
|
4095
|
+
delete window.__gemxPerf;
|
|
4096
|
+
}
|
|
4097
|
+
function enable$1() {
|
|
4098
|
+
s.enabled = true;
|
|
4099
|
+
}
|
|
4100
|
+
function disable$1() {
|
|
4101
|
+
s.enabled = false;
|
|
4102
|
+
}
|
|
4103
|
+
// ── Internal ──────────────────────────────────────────────────────────────────
|
|
4104
|
+
function flush() {
|
|
4105
|
+
if (typeof window === 'undefined')
|
|
4106
|
+
return;
|
|
4107
|
+
window.__gemxPerf = getReport();
|
|
4108
|
+
}
|
|
4109
|
+
// ── Singleton export ──────────────────────────────────────────────────────────
|
|
4110
|
+
const perf = { startSession, endSession, mark: mark$1, measure: measure$1, getReport, clear: clear$1, enable: enable$1, disable: disable$1 };
|
|
4111
|
+
|
|
3907
4112
|
/**
|
|
3908
4113
|
* DOM observation setup — ResizeObserver + MutationObserver.
|
|
3909
4114
|
* Returns a cleanup function that disconnects both observers.
|
|
3910
4115
|
*/
|
|
3911
|
-
createLogger({ enabled: false, prefix: 'IframeHeightObserver' });
|
|
4116
|
+
const logger$3 = createLogger({ enabled: false, prefix: 'IframeHeightObserver' });
|
|
4117
|
+
function setup(doc, onChange) {
|
|
4118
|
+
const resizeObserver = new ResizeObserver(onChange);
|
|
4119
|
+
resizeObserver.observe(doc.documentElement);
|
|
4120
|
+
resizeObserver.observe(doc.body);
|
|
4121
|
+
const mutationObserver = new MutationObserver(onChange);
|
|
4122
|
+
mutationObserver.observe(doc.body, {
|
|
4123
|
+
childList: true,
|
|
4124
|
+
subtree: true,
|
|
4125
|
+
attributes: true,
|
|
4126
|
+
attributeFilter: ['style', 'class', 'hidden', 'data-v'],
|
|
4127
|
+
});
|
|
4128
|
+
logger$3.log('DOM observers started (ResizeObserver + MutationObserver)');
|
|
4129
|
+
return () => {
|
|
4130
|
+
resizeObserver.disconnect();
|
|
4131
|
+
mutationObserver.disconnect();
|
|
4132
|
+
logger$3.log('DOM observers disconnected');
|
|
4133
|
+
};
|
|
4134
|
+
}
|
|
3912
4135
|
|
|
3913
4136
|
/**
|
|
3914
4137
|
* Height Observer Processor
|
|
3915
4138
|
* Background observer — watches for iframe content height changes.
|
|
3916
4139
|
*/
|
|
3917
|
-
|
|
4140
|
+
// ── Module-level functions ────────────────────────────────────────────────────
|
|
4141
|
+
function clearTimers(s) {
|
|
4142
|
+
if (s.throttleTimeout) {
|
|
4143
|
+
clearTimeout(s.throttleTimeout);
|
|
4144
|
+
s.throttleTimeout = null;
|
|
4145
|
+
}
|
|
4146
|
+
if (s.debounceTimeout) {
|
|
4147
|
+
clearTimeout(s.debounceTimeout);
|
|
4148
|
+
s.debounceTimeout = null;
|
|
4149
|
+
}
|
|
4150
|
+
}
|
|
4151
|
+
function getActualHeight(s) {
|
|
4152
|
+
if (!s.iframe?.contentDocument)
|
|
4153
|
+
return 0;
|
|
4154
|
+
const { documentElement: docEl, body } = s.iframe.contentDocument;
|
|
4155
|
+
const heights = [docEl.scrollHeight, docEl.offsetHeight, body.scrollHeight, body.offsetHeight];
|
|
4156
|
+
const maxHeight = Math.max(...heights.filter((h) => h > 0));
|
|
4157
|
+
s.logger.log('Height sources:', {
|
|
4158
|
+
'documentElement.scrollHeight': docEl.scrollHeight,
|
|
4159
|
+
'documentElement.offsetHeight': docEl.offsetHeight,
|
|
4160
|
+
'body.scrollHeight': body.scrollHeight,
|
|
4161
|
+
'body.offsetHeight': body.offsetHeight,
|
|
4162
|
+
maxHeight,
|
|
4163
|
+
});
|
|
4164
|
+
return maxHeight;
|
|
4165
|
+
}
|
|
4166
|
+
async function processHeightChange(s, newHeight) {
|
|
4167
|
+
if (!s.iframe || !s.config)
|
|
4168
|
+
return;
|
|
4169
|
+
s.isProcessing = true;
|
|
4170
|
+
s.logger.log(`Processing height change: ${newHeight}px`);
|
|
4171
|
+
try {
|
|
4172
|
+
const result = {
|
|
4173
|
+
height: newHeight,
|
|
4174
|
+
width: s.iframe.contentWindow?.innerWidth ?? 0,
|
|
4175
|
+
};
|
|
4176
|
+
s.lastHeight = newHeight;
|
|
4177
|
+
s.logger.log('Height change processed:', result);
|
|
4178
|
+
s.config.onHeightChange?.(result);
|
|
4179
|
+
window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', { detail: result }));
|
|
4180
|
+
}
|
|
4181
|
+
catch (error) {
|
|
4182
|
+
s.logger.error('Failed to process height change:', error);
|
|
4183
|
+
s.config.onError?.(error);
|
|
4184
|
+
}
|
|
4185
|
+
finally {
|
|
4186
|
+
s.isProcessing = false;
|
|
4187
|
+
}
|
|
4188
|
+
}
|
|
4189
|
+
function handleHeightChange(s) {
|
|
4190
|
+
if (s.isProcessing || s.throttleTimeout)
|
|
4191
|
+
return;
|
|
4192
|
+
s.throttleTimeout = setTimeout(() => {
|
|
4193
|
+
s.throttleTimeout = null;
|
|
4194
|
+
const currentHeight = getActualHeight(s);
|
|
4195
|
+
if (currentHeight === s.lastHeight)
|
|
4196
|
+
return;
|
|
4197
|
+
s.logger.log(`Height changed: ${s.lastHeight}px -> ${currentHeight}px`);
|
|
4198
|
+
if (s.debounceTimeout)
|
|
4199
|
+
clearTimeout(s.debounceTimeout);
|
|
4200
|
+
s.debounceTimeout = setTimeout(() => {
|
|
4201
|
+
s.debounceTimeout = null;
|
|
4202
|
+
processHeightChange(s, currentHeight);
|
|
4203
|
+
}, s.debounceMs);
|
|
4204
|
+
}, s.throttleMs);
|
|
4205
|
+
}
|
|
4206
|
+
function observe(s) {
|
|
4207
|
+
if (!s.iframe?.contentDocument?.body) {
|
|
4208
|
+
s.logger.warn('Cannot observe height changes: iframe body not found');
|
|
4209
|
+
return;
|
|
4210
|
+
}
|
|
4211
|
+
s.observerCleanup?.();
|
|
4212
|
+
s.lastHeight = s.iframe.contentDocument.documentElement.scrollHeight;
|
|
4213
|
+
s.logger.log('Initial height:', s.lastHeight);
|
|
4214
|
+
s.observerCleanup = setup(s.iframe.contentDocument, () => handleHeightChange(s));
|
|
4215
|
+
}
|
|
4216
|
+
function start$5(s, cfg) {
|
|
4217
|
+
if (s.running) {
|
|
4218
|
+
s.logger.warn('Observer is already running. Call stop() first.');
|
|
4219
|
+
return;
|
|
4220
|
+
}
|
|
4221
|
+
s.iframe = cfg.iframe;
|
|
4222
|
+
s.config = cfg;
|
|
4223
|
+
s.throttleMs = cfg.throttleMs ?? 25;
|
|
4224
|
+
s.debounceMs = cfg.debounceMs ?? 500;
|
|
4225
|
+
s.running = true;
|
|
4226
|
+
observe(s);
|
|
4227
|
+
s.logger.log('Height observer started');
|
|
4228
|
+
}
|
|
4229
|
+
function stop$5(s) {
|
|
4230
|
+
if (!s.running)
|
|
4231
|
+
return;
|
|
4232
|
+
s.observerCleanup?.();
|
|
4233
|
+
s.observerCleanup = null;
|
|
4234
|
+
clearTimers(s);
|
|
4235
|
+
s.iframe = null;
|
|
4236
|
+
s.config = null;
|
|
4237
|
+
s.lastHeight = 0;
|
|
4238
|
+
s.isProcessing = false;
|
|
4239
|
+
s.running = false;
|
|
4240
|
+
s.logger.log('Height observer stopped');
|
|
4241
|
+
}
|
|
4242
|
+
function clear(s) {
|
|
4243
|
+
s.observerCleanup?.();
|
|
4244
|
+
s.observerCleanup = null;
|
|
4245
|
+
clearTimers(s);
|
|
4246
|
+
s.lastHeight = 0;
|
|
4247
|
+
s.isProcessing = false;
|
|
4248
|
+
}
|
|
4249
|
+
function updateConfig$3(s, cfg) {
|
|
4250
|
+
if (!s.running || !s.config) {
|
|
4251
|
+
s.logger.warn('Observer is not running.');
|
|
4252
|
+
return;
|
|
4253
|
+
}
|
|
4254
|
+
s.config = { ...s.config, ...cfg };
|
|
4255
|
+
if (cfg.throttleMs !== undefined)
|
|
4256
|
+
s.throttleMs = cfg.throttleMs;
|
|
4257
|
+
if (cfg.debounceMs !== undefined)
|
|
4258
|
+
s.debounceMs = cfg.debounceMs;
|
|
4259
|
+
s.logger.configure({ enabled: !!s.config.debug });
|
|
4260
|
+
s.logger.log('Config updated');
|
|
4261
|
+
}
|
|
4262
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
4263
|
+
function createHeightObserver() {
|
|
4264
|
+
const s = {
|
|
4265
|
+
logger: createLogger({ enabled: true, prefix: 'IframeHeightObserver' }),
|
|
4266
|
+
iframe: null,
|
|
4267
|
+
config: null,
|
|
4268
|
+
observerCleanup: null,
|
|
4269
|
+
lastHeight: 0,
|
|
4270
|
+
throttleTimeout: null,
|
|
4271
|
+
debounceTimeout: null,
|
|
4272
|
+
isProcessing: false,
|
|
4273
|
+
throttleMs: 25,
|
|
4274
|
+
debounceMs: 500,
|
|
4275
|
+
running: false,
|
|
4276
|
+
};
|
|
4277
|
+
return {
|
|
4278
|
+
start: (cfg) => start$5(s, cfg),
|
|
4279
|
+
stop: () => stop$5(s),
|
|
4280
|
+
observe: () => observe(s),
|
|
4281
|
+
clear: () => clear(s),
|
|
4282
|
+
updateConfig: (cfg) => updateConfig$3(s, cfg),
|
|
4283
|
+
getCurrentHeight: () => s.lastHeight,
|
|
4284
|
+
isRunning: () => s.running,
|
|
4285
|
+
getStateInfo: () => ({
|
|
4286
|
+
isRunning: s.running,
|
|
4287
|
+
lastHeight: s.lastHeight,
|
|
4288
|
+
isProcessing: s.isProcessing,
|
|
4289
|
+
hasObservers: !!s.observerCleanup,
|
|
4290
|
+
}),
|
|
4291
|
+
};
|
|
4292
|
+
}
|
|
3918
4293
|
|
|
3919
|
-
|
|
4294
|
+
/**
|
|
4295
|
+
* Window-level event management for the navigation processor.
|
|
4296
|
+
*
|
|
4297
|
+
* Responsibilities:
|
|
4298
|
+
* - Subscribe to events dispatched by this processor (for logging/hooks)
|
|
4299
|
+
* - Dispatch navigation events to the parent window
|
|
4300
|
+
*/
|
|
4301
|
+
// ── Module-level functions ────────────────────────────────────────────────────
|
|
4302
|
+
function attach$1(s, debug) {
|
|
4303
|
+
s.logger.configure({ enabled: !!debug });
|
|
4304
|
+
s.navigationBlockedListener = (e) => {
|
|
4305
|
+
const ev = e;
|
|
4306
|
+
s.logger.log('Navigation blocked:', ev.detail.url);
|
|
4307
|
+
};
|
|
4308
|
+
s.formSubmitWindowListener = (e) => {
|
|
4309
|
+
const ev = e;
|
|
4310
|
+
s.logger.log('Form submitted:', ev.detail.data);
|
|
4311
|
+
};
|
|
4312
|
+
window.addEventListener('iframe-navigation-blocked', s.navigationBlockedListener);
|
|
4313
|
+
window.addEventListener('iframe-form-submit', s.formSubmitWindowListener);
|
|
4314
|
+
}
|
|
4315
|
+
function detach$1(s) {
|
|
4316
|
+
if (s.navigationBlockedListener) {
|
|
4317
|
+
window.removeEventListener('iframe-navigation-blocked', s.navigationBlockedListener);
|
|
4318
|
+
s.navigationBlockedListener = null;
|
|
4319
|
+
}
|
|
4320
|
+
if (s.formSubmitWindowListener) {
|
|
4321
|
+
window.removeEventListener('iframe-form-submit', s.formSubmitWindowListener);
|
|
4322
|
+
s.formSubmitWindowListener = null;
|
|
4323
|
+
}
|
|
4324
|
+
}
|
|
4325
|
+
function dispatchBlocked(url, showMessage) {
|
|
4326
|
+
if (showMessage)
|
|
4327
|
+
alert(`Navigation blocked: ${url}`);
|
|
4328
|
+
window.dispatchEvent(new CustomEvent('iframe-navigation-blocked', { detail: { url } }));
|
|
4329
|
+
}
|
|
4330
|
+
function dispatchFormSubmit(form, data) {
|
|
4331
|
+
window.dispatchEvent(new CustomEvent('iframe-form-submit', { detail: { form, data } }));
|
|
4332
|
+
}
|
|
4333
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
4334
|
+
function createNavigationListeners() {
|
|
4335
|
+
const s = {
|
|
4336
|
+
logger: createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' }),
|
|
4337
|
+
navigationBlockedListener: null,
|
|
4338
|
+
formSubmitWindowListener: null,
|
|
4339
|
+
};
|
|
4340
|
+
return {
|
|
4341
|
+
attach: (debug) => attach$1(s, debug),
|
|
4342
|
+
detach: () => detach$1(s),
|
|
4343
|
+
dispatchBlocked,
|
|
4344
|
+
dispatchFormSubmit,
|
|
4345
|
+
};
|
|
4346
|
+
}
|
|
4347
|
+
|
|
4348
|
+
const logger$2 = createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' });
|
|
3920
4349
|
function configure$1(debug) {
|
|
3921
|
-
logger$
|
|
4350
|
+
logger$2.configure({ enabled: debug });
|
|
3922
4351
|
}
|
|
3923
4352
|
// ─── DOM Utilities ────────────────────────────────────────────────────────────
|
|
3924
4353
|
function disableAllLinks(doc) {
|
|
@@ -3942,10 +4371,10 @@ function setupLinkBlocker(doc, isEnabled, onBlocked) {
|
|
|
3942
4371
|
return;
|
|
3943
4372
|
const href = link.getAttribute('href');
|
|
3944
4373
|
if (!href || href === '' || href === '#' || href.startsWith('#')) {
|
|
3945
|
-
logger$
|
|
4374
|
+
logger$2.log('Allowed hash navigation:', href);
|
|
3946
4375
|
return;
|
|
3947
4376
|
}
|
|
3948
|
-
logger$
|
|
4377
|
+
logger$2.log('Blocked link navigation to:', href);
|
|
3949
4378
|
e.preventDefault();
|
|
3950
4379
|
e.stopPropagation();
|
|
3951
4380
|
e.stopImmediatePropagation();
|
|
@@ -3959,7 +4388,7 @@ function setupLinkBlocker(doc, isEnabled, onBlocked) {
|
|
|
3959
4388
|
return;
|
|
3960
4389
|
const href = link.getAttribute('href');
|
|
3961
4390
|
if (href && !href.startsWith('#')) {
|
|
3962
|
-
logger$
|
|
4391
|
+
logger$2.log('Blocked auxclick navigation');
|
|
3963
4392
|
e.preventDefault();
|
|
3964
4393
|
e.stopPropagation();
|
|
3965
4394
|
e.stopImmediatePropagation();
|
|
@@ -3980,7 +4409,7 @@ function setupFormBlocker(doc, isEnabled, onBlocked, onFormSubmit) {
|
|
|
3980
4409
|
const form = e.target;
|
|
3981
4410
|
const action = form.getAttribute('action');
|
|
3982
4411
|
if (!action || action === '' || action === '#') {
|
|
3983
|
-
logger$
|
|
4412
|
+
logger$2.log('Allowed same-page form');
|
|
3984
4413
|
e.preventDefault();
|
|
3985
4414
|
const data = {};
|
|
3986
4415
|
new FormData(form).forEach((value, key) => {
|
|
@@ -3989,7 +4418,7 @@ function setupFormBlocker(doc, isEnabled, onBlocked, onFormSubmit) {
|
|
|
3989
4418
|
onFormSubmit(form, data);
|
|
3990
4419
|
return;
|
|
3991
4420
|
}
|
|
3992
|
-
logger$
|
|
4421
|
+
logger$2.log('Blocked form submission to:', action);
|
|
3993
4422
|
e.preventDefault();
|
|
3994
4423
|
e.stopPropagation();
|
|
3995
4424
|
e.stopImmediatePropagation();
|
|
@@ -4003,7 +4432,7 @@ function setupWindowOpenBlocker(win, originalOpen, isEnabled, onBlocked) {
|
|
|
4003
4432
|
if (!isEnabled())
|
|
4004
4433
|
return originalOpen(...args);
|
|
4005
4434
|
const url = args[0]?.toString() || 'popup';
|
|
4006
|
-
logger$
|
|
4435
|
+
logger$2.log('Blocked window.open:', url);
|
|
4007
4436
|
onBlocked(url);
|
|
4008
4437
|
return null;
|
|
4009
4438
|
});
|
|
@@ -4015,14 +4444,14 @@ function setupUnloadBlocker(win, isEnabled) {
|
|
|
4015
4444
|
const beforeUnloadListener = (e) => {
|
|
4016
4445
|
if (!isEnabled())
|
|
4017
4446
|
return;
|
|
4018
|
-
logger$
|
|
4447
|
+
logger$2.log('Blocked beforeunload');
|
|
4019
4448
|
e.preventDefault();
|
|
4020
4449
|
e.returnValue = '';
|
|
4021
4450
|
};
|
|
4022
4451
|
const unloadListener = (e) => {
|
|
4023
4452
|
if (!isEnabled())
|
|
4024
4453
|
return;
|
|
4025
|
-
logger$
|
|
4454
|
+
logger$2.log('Blocked unload');
|
|
4026
4455
|
e.preventDefault();
|
|
4027
4456
|
e.stopPropagation();
|
|
4028
4457
|
};
|
|
@@ -4039,65 +4468,14 @@ function setupDOMMonitor(doc) {
|
|
|
4039
4468
|
return () => observer.disconnect();
|
|
4040
4469
|
}
|
|
4041
4470
|
|
|
4042
|
-
/**
|
|
4043
|
-
* Window-level event management for the navigation processor.
|
|
4044
|
-
*
|
|
4045
|
-
* Responsibilities:
|
|
4046
|
-
* - Subscribe to events dispatched by this processor (for logging/hooks)
|
|
4047
|
-
* - Dispatch navigation events to the parent window
|
|
4048
|
-
*/
|
|
4049
|
-
const logger$7 = createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' });
|
|
4050
|
-
// ─── State ────────────────────────────────────────────────────────────────────
|
|
4051
|
-
let navigationBlockedListener = null;
|
|
4052
|
-
let formSubmitWindowListener = null;
|
|
4053
|
-
// ─── Subscriptions ────────────────────────────────────────────────────────────
|
|
4054
|
-
function attach$1(debug) {
|
|
4055
|
-
logger$7.configure({ enabled: !!debug });
|
|
4056
|
-
navigationBlockedListener = (e) => {
|
|
4057
|
-
const ev = e;
|
|
4058
|
-
logger$7.log('Navigation blocked:', ev.detail.url);
|
|
4059
|
-
};
|
|
4060
|
-
formSubmitWindowListener = (e) => {
|
|
4061
|
-
const ev = e;
|
|
4062
|
-
logger$7.log('Form submitted:', ev.detail.data);
|
|
4063
|
-
};
|
|
4064
|
-
window.addEventListener('iframe-navigation-blocked', navigationBlockedListener);
|
|
4065
|
-
window.addEventListener('iframe-form-submit', formSubmitWindowListener);
|
|
4066
|
-
}
|
|
4067
|
-
function detach$1() {
|
|
4068
|
-
if (navigationBlockedListener) {
|
|
4069
|
-
window.removeEventListener('iframe-navigation-blocked', navigationBlockedListener);
|
|
4070
|
-
navigationBlockedListener = null;
|
|
4071
|
-
}
|
|
4072
|
-
if (formSubmitWindowListener) {
|
|
4073
|
-
window.removeEventListener('iframe-form-submit', formSubmitWindowListener);
|
|
4074
|
-
formSubmitWindowListener = null;
|
|
4075
|
-
}
|
|
4076
|
-
}
|
|
4077
|
-
// ─── Dispatchers ─────────────────────────────────────────────────────────────
|
|
4078
|
-
function dispatchBlocked(url, showMessage) {
|
|
4079
|
-
if (showMessage)
|
|
4080
|
-
alert(`Navigation blocked: ${url}`);
|
|
4081
|
-
window.dispatchEvent(new CustomEvent('iframe-navigation-blocked', { detail: { url } }));
|
|
4082
|
-
}
|
|
4083
|
-
function dispatchFormSubmit(form, data) {
|
|
4084
|
-
window.dispatchEvent(new CustomEvent('iframe-form-submit', { detail: { form, data } }));
|
|
4085
|
-
}
|
|
4086
|
-
|
|
4087
4471
|
/**
|
|
4088
4472
|
* Navigation Processor
|
|
4089
4473
|
* Continuous guard — blocks all navigation attempts within the iframe.
|
|
4090
4474
|
*/
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
let running$4 = false;
|
|
4096
|
-
let cleanups = [];
|
|
4097
|
-
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
4098
|
-
function start$5(iframe, cfg) {
|
|
4099
|
-
if (running$4) {
|
|
4100
|
-
logger$6.warn('Blocker is already running. Call stop() first.');
|
|
4475
|
+
// ── Module-level functions ────────────────────────────────────────────────────
|
|
4476
|
+
function start$4(s, iframe, cfg) {
|
|
4477
|
+
if (s.running) {
|
|
4478
|
+
s.logger.warn('Blocker is already running. Call stop() first.');
|
|
4101
4479
|
return;
|
|
4102
4480
|
}
|
|
4103
4481
|
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
@@ -4106,76 +4484,114 @@ function start$5(iframe, cfg) {
|
|
|
4106
4484
|
const doc = iframe.contentDocument;
|
|
4107
4485
|
const win = iframe.contentWindow;
|
|
4108
4486
|
const originalOpen = win.open.bind(win);
|
|
4109
|
-
logger
|
|
4487
|
+
s.logger.configure({ enabled: !!cfg?.debug });
|
|
4110
4488
|
configure$1(!!cfg?.debug);
|
|
4111
|
-
cleanups = [
|
|
4112
|
-
setupLinkBlocker(doc, () => isEnabled, (url) => dispatchBlocked(url, showMessage)),
|
|
4113
|
-
setupFormBlocker(doc, () => isEnabled, (url) => dispatchBlocked(url, showMessage), dispatchFormSubmit),
|
|
4114
|
-
setupWindowOpenBlocker(win, originalOpen, () => isEnabled, (url) => dispatchBlocked(url, showMessage)),
|
|
4115
|
-
setupUnloadBlocker(win, () => isEnabled),
|
|
4489
|
+
s.cleanups = [
|
|
4490
|
+
setupLinkBlocker(doc, () => s.isEnabled, (url) => s.listeners.dispatchBlocked(url, s.showMessage)),
|
|
4491
|
+
setupFormBlocker(doc, () => s.isEnabled, (url) => s.listeners.dispatchBlocked(url, s.showMessage), s.listeners.dispatchFormSubmit),
|
|
4492
|
+
setupWindowOpenBlocker(win, originalOpen, () => s.isEnabled, (url) => s.listeners.dispatchBlocked(url, s.showMessage)),
|
|
4493
|
+
setupUnloadBlocker(win, () => s.isEnabled),
|
|
4116
4494
|
setupDOMMonitor(doc),
|
|
4117
4495
|
];
|
|
4118
|
-
attach
|
|
4119
|
-
running
|
|
4120
|
-
logger
|
|
4496
|
+
s.listeners.attach(cfg?.debug);
|
|
4497
|
+
s.running = true;
|
|
4498
|
+
s.logger.log('Navigation blocker started');
|
|
4499
|
+
}
|
|
4500
|
+
function stop$4(s) {
|
|
4501
|
+
if (!s.running)
|
|
4502
|
+
return;
|
|
4503
|
+
s.cleanups.forEach((fn) => fn());
|
|
4504
|
+
s.cleanups = [];
|
|
4505
|
+
s.listeners.detach();
|
|
4506
|
+
s.isEnabled = false;
|
|
4507
|
+
s.showMessage = false;
|
|
4508
|
+
s.running = false;
|
|
4509
|
+
s.logger.log('Navigation blocker stopped');
|
|
4510
|
+
}
|
|
4511
|
+
function enable(s) {
|
|
4512
|
+
if (!s.running) {
|
|
4513
|
+
s.logger.warn('Blocker is not running.');
|
|
4514
|
+
return;
|
|
4515
|
+
}
|
|
4516
|
+
s.isEnabled = true;
|
|
4517
|
+
s.logger.log('Navigation blocking enabled');
|
|
4518
|
+
}
|
|
4519
|
+
function disable(s) {
|
|
4520
|
+
if (!s.running) {
|
|
4521
|
+
s.logger.warn('Blocker is not running.');
|
|
4522
|
+
return;
|
|
4523
|
+
}
|
|
4524
|
+
s.isEnabled = false;
|
|
4525
|
+
s.logger.log('Navigation blocking disabled');
|
|
4121
4526
|
}
|
|
4122
|
-
function
|
|
4123
|
-
if (!running
|
|
4527
|
+
function enableMessage(s) {
|
|
4528
|
+
if (!s.running) {
|
|
4529
|
+
s.logger.warn('Blocker is not running.');
|
|
4124
4530
|
return;
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
running
|
|
4131
|
-
|
|
4132
|
-
}
|
|
4133
|
-
function enable() {
|
|
4134
|
-
if (!running$4) {
|
|
4135
|
-
logger$6.warn('Blocker is not running. Call start() first.');
|
|
4531
|
+
}
|
|
4532
|
+
s.showMessage = true;
|
|
4533
|
+
s.logger.log('Navigation blocking message enabled');
|
|
4534
|
+
}
|
|
4535
|
+
function disableMessage(s) {
|
|
4536
|
+
if (!s.running) {
|
|
4537
|
+
s.logger.warn('Blocker is not running.');
|
|
4136
4538
|
return;
|
|
4137
4539
|
}
|
|
4138
|
-
|
|
4139
|
-
logger
|
|
4540
|
+
s.showMessage = false;
|
|
4541
|
+
s.logger.log('Navigation blocking message disabled');
|
|
4542
|
+
}
|
|
4543
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
4544
|
+
function createNavigationBlocker() {
|
|
4545
|
+
const s = {
|
|
4546
|
+
logger: createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' }),
|
|
4547
|
+
listeners: createNavigationListeners(),
|
|
4548
|
+
isEnabled: false,
|
|
4549
|
+
showMessage: false,
|
|
4550
|
+
running: false,
|
|
4551
|
+
cleanups: [],
|
|
4552
|
+
};
|
|
4553
|
+
return {
|
|
4554
|
+
start: (iframe, cfg) => start$4(s, iframe, cfg),
|
|
4555
|
+
stop: () => stop$4(s),
|
|
4556
|
+
enable: () => enable(s),
|
|
4557
|
+
disable: () => disable(s),
|
|
4558
|
+
enableMessage: () => enableMessage(s),
|
|
4559
|
+
disableMessage: () => disableMessage(s),
|
|
4560
|
+
isRunning: () => s.running,
|
|
4561
|
+
isBlockingEnabled: () => s.isEnabled,
|
|
4562
|
+
getStateInfo: () => ({ isRunning: s.running, isEnabled: s.isEnabled, showMessage: s.showMessage }),
|
|
4563
|
+
};
|
|
4140
4564
|
}
|
|
4141
4565
|
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4566
|
+
// ── Module-level functions ────────────────────────────────────────────────────
|
|
4567
|
+
function attach(s, debug) {
|
|
4568
|
+
s.logger.configure({ enabled: !!debug });
|
|
4569
|
+
s.dimensionsListener = (e) => {
|
|
4570
|
+
const ev = e;
|
|
4571
|
+
s.logger.log('Dimensions applied:', ev.detail);
|
|
4572
|
+
};
|
|
4573
|
+
window.addEventListener('iframe-dimensions-applied', s.dimensionsListener);
|
|
4149
4574
|
}
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4575
|
+
function detach(s) {
|
|
4576
|
+
if (s.dimensionsListener) {
|
|
4577
|
+
window.removeEventListener('iframe-dimensions-applied', s.dimensionsListener);
|
|
4578
|
+
s.dimensionsListener = null;
|
|
4579
|
+
}
|
|
4580
|
+
}
|
|
4581
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
4582
|
+
function createViewportListeners() {
|
|
4583
|
+
const s = {
|
|
4584
|
+
logger: createLogger({ enabled: false, prefix: 'ViewportReplacer' }),
|
|
4585
|
+
dimensionsListener: null,
|
|
4586
|
+
};
|
|
4587
|
+
return {
|
|
4588
|
+
attach: (debug) => attach(s, debug),
|
|
4589
|
+
detach: () => detach(s),
|
|
4590
|
+
};
|
|
4163
4591
|
}
|
|
4164
4592
|
|
|
4165
|
-
/**
|
|
4166
|
-
* Computed Style Enforcer Module
|
|
4167
|
-
* Enforces computed CSS styles with viewport unit verification
|
|
4168
|
-
* @module computed-style-enforcer
|
|
4169
|
-
*/
|
|
4170
|
-
const logger$5 = createLogger({
|
|
4171
|
-
enabled: false,
|
|
4172
|
-
prefix: 'ComputedStyleEnforcer',
|
|
4173
|
-
});
|
|
4174
|
-
// ============================================================================
|
|
4175
|
-
// Constants
|
|
4176
|
-
// ============================================================================
|
|
4177
4593
|
const DEFAULT_TOLERANCE_PX = 5;
|
|
4178
|
-
const VIEWPORT_UNIT_REGEX = /([
|
|
4594
|
+
const VIEWPORT_UNIT_REGEX = /([-.\\d]+)(vh|svh|lvh|dvh|%)/gi;
|
|
4179
4595
|
const DEFAULT_CSS_VALUES = ['none', 'auto', 'normal', '0px'];
|
|
4180
4596
|
const CRITICAL_PROPERTIES = [
|
|
4181
4597
|
'display',
|
|
@@ -4212,235 +4628,241 @@ const CRITICAL_PROPERTIES = [
|
|
|
4212
4628
|
'grid-template-rows',
|
|
4213
4629
|
'gap',
|
|
4214
4630
|
];
|
|
4215
|
-
|
|
4216
|
-
//
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
let win$1 = null;
|
|
4220
|
-
let config$2 = null;
|
|
4221
|
-
const elementsWithViewportUnits$1 = new Set();
|
|
4222
|
-
let originalValues$1 = new WeakMap();
|
|
4223
|
-
let running$3 = false;
|
|
4224
|
-
// ============================================================================
|
|
4225
|
-
// Helper Functions
|
|
4226
|
-
// ============================================================================
|
|
4227
|
-
/**
|
|
4228
|
-
* Get viewport unit map for conversion from current state
|
|
4229
|
-
*/
|
|
4230
|
-
function getViewportUnitMap() {
|
|
4231
|
-
if (!config$2) {
|
|
4631
|
+
|
|
4632
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
4633
|
+
function getViewportUnitMap(s) {
|
|
4634
|
+
if (!s.config)
|
|
4232
4635
|
throw new Error('Config is not initialized');
|
|
4233
|
-
}
|
|
4234
4636
|
return {
|
|
4235
|
-
vh: config
|
|
4236
|
-
svh: config
|
|
4237
|
-
lvh: config
|
|
4238
|
-
dvh: config
|
|
4239
|
-
vw: config
|
|
4240
|
-
svw: config
|
|
4241
|
-
lvw: config
|
|
4242
|
-
dvw: config
|
|
4637
|
+
vh: s.config.targetHeight,
|
|
4638
|
+
svh: s.config.targetHeight,
|
|
4639
|
+
lvh: s.config.targetHeight,
|
|
4640
|
+
dvh: s.config.targetHeight,
|
|
4641
|
+
vw: s.config.targetWidth,
|
|
4642
|
+
svw: s.config.targetWidth,
|
|
4643
|
+
lvw: s.config.targetWidth,
|
|
4644
|
+
dvw: s.config.targetWidth,
|
|
4243
4645
|
};
|
|
4244
4646
|
}
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
*/
|
|
4248
|
-
function calculateExpectedPx(value, unit) {
|
|
4249
|
-
if (!config$2) {
|
|
4647
|
+
function calculateExpectedPx(s, value, unit) {
|
|
4648
|
+
if (!s.config)
|
|
4250
4649
|
throw new Error('Config is not initialized');
|
|
4251
|
-
}
|
|
4252
4650
|
const unitLower = unit.toLowerCase();
|
|
4253
|
-
if (unitLower === '%')
|
|
4254
|
-
return (value / 100) * config
|
|
4255
|
-
|
|
4256
|
-
const unitMap = getViewportUnitMap();
|
|
4257
|
-
return (value / 100) * (unitMap[unitLower] || 0);
|
|
4651
|
+
if (unitLower === '%')
|
|
4652
|
+
return (value / 100) * s.config.targetHeight;
|
|
4653
|
+
return (value / 100) * (getViewportUnitMap(s)[unitLower] || 0);
|
|
4258
4654
|
}
|
|
4259
|
-
/**
|
|
4260
|
-
* Check if a CSS value is a default/initial value that should be skipped
|
|
4261
|
-
*/
|
|
4262
4655
|
function isDefaultCssValue(value) {
|
|
4263
4656
|
return DEFAULT_CSS_VALUES.includes(value);
|
|
4264
4657
|
}
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
* Return true ONLY if computed value matches target config (within tolerance)
|
|
4268
|
-
* Return false if computed value is different - don't override correct values
|
|
4269
|
-
*/
|
|
4270
|
-
function shouldReplaceValue(computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
|
|
4271
|
-
if (!config$2) {
|
|
4658
|
+
function shouldReplaceValue(s, computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
|
|
4659
|
+
if (!s.config)
|
|
4272
4660
|
return false;
|
|
4273
|
-
}
|
|
4274
|
-
// Parse computed value (should be in px)
|
|
4275
4661
|
const computedPx = parseFloat(computedValue);
|
|
4276
|
-
if (isNaN(computedPx))
|
|
4277
|
-
return false;
|
|
4278
|
-
}
|
|
4279
|
-
// Parse original value to check what it should be
|
|
4662
|
+
if (isNaN(computedPx))
|
|
4663
|
+
return false;
|
|
4280
4664
|
const regex = new RegExp(VIEWPORT_UNIT_REGEX.source, VIEWPORT_UNIT_REGEX.flags);
|
|
4281
4665
|
const match = originalValue.match(regex);
|
|
4282
|
-
if (!match)
|
|
4283
|
-
return false;
|
|
4284
|
-
}
|
|
4666
|
+
if (!match)
|
|
4667
|
+
return false;
|
|
4285
4668
|
const [, value, unit] = match;
|
|
4286
4669
|
const num = parseFloat(value);
|
|
4287
|
-
if (isNaN(num))
|
|
4670
|
+
if (isNaN(num))
|
|
4288
4671
|
return false;
|
|
4289
|
-
|
|
4290
|
-
// Calculate expected value based on unit and target config
|
|
4291
|
-
const expectedPx = calculateExpectedPx(num, unit);
|
|
4292
|
-
// Check if computed value matches expected value (within tolerance)
|
|
4672
|
+
const expectedPx = calculateExpectedPx(s, num, unit);
|
|
4293
4673
|
const diff = Math.abs(computedPx - expectedPx);
|
|
4294
4674
|
if (diff <= tolerance) {
|
|
4295
|
-
|
|
4296
|
-
logger$5.log(`OK to replace: computed=${computedValue} matches expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
|
|
4675
|
+
s.logger.log(`OK to replace: computed=${computedValue} matches expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
|
|
4297
4676
|
return true;
|
|
4298
4677
|
}
|
|
4299
|
-
|
|
4300
|
-
logger$5.log(`Skip replace: computed=${computedValue} differs from expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px) - keeping current value`);
|
|
4678
|
+
s.logger.log(`Skip replace: computed=${computedValue} differs from expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
|
|
4301
4679
|
return false;
|
|
4302
4680
|
}
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
*/
|
|
4306
|
-
function applyPropertyWithVerification(element, prop, computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
|
|
4307
|
-
// Verify before replacing - only replace if computed value matches target config
|
|
4308
|
-
if (originalValue && shouldReplaceValue(computedValue, originalValue, tolerance)) {
|
|
4681
|
+
function applyPropertyWithVerification(s, element, prop, computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
|
|
4682
|
+
if (originalValue && shouldReplaceValue(s, computedValue, originalValue, tolerance)) {
|
|
4309
4683
|
element.style.setProperty(prop, computedValue, 'important');
|
|
4310
4684
|
return true;
|
|
4311
4685
|
}
|
|
4312
4686
|
else if (!originalValue) {
|
|
4313
|
-
// No original value tracked, use old behavior
|
|
4314
4687
|
element.style.setProperty(prop, computedValue, 'important');
|
|
4315
4688
|
return true;
|
|
4316
4689
|
}
|
|
4317
4690
|
return false;
|
|
4318
4691
|
}
|
|
4319
|
-
//
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
* Start the computed style enforcer
|
|
4324
|
-
* Initialize with iframe document and config
|
|
4325
|
-
*/
|
|
4326
|
-
function start$4(d, w, cfg, options = {}) {
|
|
4327
|
-
if (running$3) {
|
|
4328
|
-
logger$5.warn('Enforcer is already running. Call stop() first.');
|
|
4692
|
+
// ── Exported module-level functions ───────────────────────────────────────────
|
|
4693
|
+
function start$3(s, d, w, cfg, options = {}) {
|
|
4694
|
+
if (s.running) {
|
|
4695
|
+
s.logger.warn('Enforcer is already running. Call stop() first.');
|
|
4329
4696
|
return;
|
|
4330
4697
|
}
|
|
4331
|
-
doc
|
|
4332
|
-
win
|
|
4333
|
-
config
|
|
4334
|
-
running
|
|
4335
|
-
logger
|
|
4336
|
-
logger
|
|
4698
|
+
s.doc = d;
|
|
4699
|
+
s.win = w;
|
|
4700
|
+
s.config = cfg;
|
|
4701
|
+
s.running = true;
|
|
4702
|
+
s.logger.configure({ enabled: !!options.debug });
|
|
4703
|
+
s.logger.log('Computed style enforcer started');
|
|
4337
4704
|
}
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4705
|
+
function stop$3(s) {
|
|
4706
|
+
if (!s.running)
|
|
4707
|
+
return;
|
|
4708
|
+
s.doc = null;
|
|
4709
|
+
s.win = null;
|
|
4710
|
+
s.config = null;
|
|
4711
|
+
s.elementsWithViewportUnits.clear();
|
|
4712
|
+
s.originalValues = new WeakMap();
|
|
4713
|
+
s.running = false;
|
|
4714
|
+
s.logger.log('Computed style enforcer stopped');
|
|
4715
|
+
}
|
|
4716
|
+
function reset(s) {
|
|
4717
|
+
if (!s.running) {
|
|
4718
|
+
s.logger.warn('Enforcer is not running. Call start() first.');
|
|
4343
4719
|
return;
|
|
4344
4720
|
}
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
elementsWithViewportUnits$1.clear();
|
|
4349
|
-
originalValues$1 = new WeakMap();
|
|
4350
|
-
running$3 = false;
|
|
4351
|
-
logger$5.log('Computed style enforcer stopped');
|
|
4721
|
+
s.elementsWithViewportUnits.clear();
|
|
4722
|
+
s.originalValues = new WeakMap();
|
|
4723
|
+
s.logger.log('Computed style enforcer reset');
|
|
4352
4724
|
}
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
*/
|
|
4357
|
-
function trackElement(element, propertyOriginalValues) {
|
|
4358
|
-
if (!running$3) {
|
|
4359
|
-
logger$5.warn('Enforcer is not running. Call start() first.');
|
|
4725
|
+
function trackElement(s, element, propertyOriginalValues) {
|
|
4726
|
+
if (!s.running) {
|
|
4727
|
+
s.logger.warn('Enforcer is not running. Call start() first.');
|
|
4360
4728
|
return;
|
|
4361
4729
|
}
|
|
4362
|
-
elementsWithViewportUnits
|
|
4363
|
-
|
|
4364
|
-
let elementOriginals = originalValues$1.get(element);
|
|
4730
|
+
s.elementsWithViewportUnits.add(element);
|
|
4731
|
+
let elementOriginals = s.originalValues.get(element);
|
|
4365
4732
|
if (!elementOriginals) {
|
|
4366
4733
|
elementOriginals = new Map();
|
|
4367
|
-
originalValues
|
|
4734
|
+
s.originalValues.set(element, elementOriginals);
|
|
4368
4735
|
}
|
|
4369
|
-
// Merge property original values (don't override existing)
|
|
4370
4736
|
propertyOriginalValues.forEach((value, prop) => {
|
|
4371
|
-
if (!elementOriginals.has(prop))
|
|
4737
|
+
if (!elementOriginals.has(prop))
|
|
4372
4738
|
elementOriginals.set(prop, value);
|
|
4373
|
-
}
|
|
4374
4739
|
});
|
|
4375
4740
|
}
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
function processElement(element, options = {}) {
|
|
4380
|
-
if (!running$3 || !doc$1 || !win$1 || !config$2) {
|
|
4381
|
-
logger$5.warn('Enforcer is not running. Call start() first.');
|
|
4741
|
+
function processElement(s, element, options = {}) {
|
|
4742
|
+
if (!s.running || !s.doc || !s.win || !s.config) {
|
|
4743
|
+
s.logger.warn('Enforcer is not running.');
|
|
4382
4744
|
return 0;
|
|
4383
4745
|
}
|
|
4384
|
-
if (!elementsWithViewportUnits
|
|
4746
|
+
if (!s.elementsWithViewportUnits.has(element))
|
|
4385
4747
|
return 0;
|
|
4386
|
-
}
|
|
4387
4748
|
const htmlElement = element;
|
|
4388
|
-
const computed = win
|
|
4749
|
+
const computed = s.win.getComputedStyle(htmlElement);
|
|
4389
4750
|
const inlineStyle = htmlElement.style;
|
|
4390
|
-
const elementOriginals = originalValues
|
|
4751
|
+
const elementOriginals = s.originalValues.get(element);
|
|
4391
4752
|
const tolerance = options.tolerance ?? DEFAULT_TOLERANCE_PX;
|
|
4392
4753
|
let count = 0;
|
|
4393
4754
|
CRITICAL_PROPERTIES.forEach((prop) => {
|
|
4394
4755
|
const computedValue = computed.getPropertyValue(prop);
|
|
4395
4756
|
const inlineValue = inlineStyle.getPropertyValue(prop);
|
|
4396
|
-
if (computedValue && (!inlineValue || inlineValue !== computedValue)) {
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
count++;
|
|
4401
|
-
}
|
|
4402
|
-
}
|
|
4757
|
+
if (computedValue && (!inlineValue || inlineValue !== computedValue) && !isDefaultCssValue(computedValue)) {
|
|
4758
|
+
const originalValue = elementOriginals?.get(prop) || '';
|
|
4759
|
+
if (applyPropertyWithVerification(s, htmlElement, prop, computedValue, originalValue, tolerance))
|
|
4760
|
+
count++;
|
|
4403
4761
|
}
|
|
4404
4762
|
});
|
|
4405
4763
|
return count;
|
|
4406
4764
|
}
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
*/
|
|
4411
|
-
function processAll(options = {}) {
|
|
4412
|
-
if (!running$3 || !doc$1 || !win$1 || !config$2) {
|
|
4413
|
-
logger$5.warn('Enforcer is not running. Call start() first.');
|
|
4765
|
+
function processAll(s, options = {}) {
|
|
4766
|
+
if (!s.running || !s.doc || !s.win || !s.config) {
|
|
4767
|
+
s.logger.warn('Enforcer is not running.');
|
|
4414
4768
|
return 0;
|
|
4415
4769
|
}
|
|
4416
4770
|
let totalCount = 0;
|
|
4417
|
-
elementsWithViewportUnits
|
|
4418
|
-
totalCount += processElement(element, options);
|
|
4771
|
+
s.elementsWithViewportUnits.forEach((element) => {
|
|
4772
|
+
totalCount += processElement(s, element, options);
|
|
4419
4773
|
});
|
|
4420
|
-
logger
|
|
4774
|
+
s.logger.log(`Enforced ${totalCount} computed styles for ${s.elementsWithViewportUnits.size} elements`);
|
|
4421
4775
|
return totalCount;
|
|
4422
4776
|
}
|
|
4777
|
+
function updateConfig$2(s, cfg) {
|
|
4778
|
+
if (!s.running || !s.config) {
|
|
4779
|
+
s.logger.warn('Enforcer is not running.');
|
|
4780
|
+
return;
|
|
4781
|
+
}
|
|
4782
|
+
s.config = { ...s.config, ...cfg };
|
|
4783
|
+
s.logger.log('Config updated:', cfg);
|
|
4784
|
+
}
|
|
4785
|
+
|
|
4786
|
+
/**
|
|
4787
|
+
* Computed Style Enforcer
|
|
4788
|
+
* Enforces computed CSS styles with viewport unit verification.
|
|
4789
|
+
*/
|
|
4790
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
4791
|
+
function createEnforcer() {
|
|
4792
|
+
const s = {
|
|
4793
|
+
logger: createLogger({ enabled: false, prefix: 'ComputedStyleEnforcer' }),
|
|
4794
|
+
doc: null,
|
|
4795
|
+
win: null,
|
|
4796
|
+
config: null,
|
|
4797
|
+
elementsWithViewportUnits: new Set(),
|
|
4798
|
+
originalValues: new WeakMap(),
|
|
4799
|
+
running: false,
|
|
4800
|
+
};
|
|
4801
|
+
return {
|
|
4802
|
+
start: (d, w, cfg, options) => start$3(s, d, w, cfg, options),
|
|
4803
|
+
stop: () => stop$3(s),
|
|
4804
|
+
reset: () => reset(s),
|
|
4805
|
+
trackElement: (element, propertyOriginalValues) => trackElement(s, element, propertyOriginalValues),
|
|
4806
|
+
processElement: (element, options) => processElement(s, element, options),
|
|
4807
|
+
processAll: (options) => processAll(s, options),
|
|
4808
|
+
updateConfig: (cfg) => updateConfig$2(s, cfg),
|
|
4809
|
+
getStateInfo: () => ({
|
|
4810
|
+
isRunning: s.running,
|
|
4811
|
+
trackedElementsCount: s.elementsWithViewportUnits.size,
|
|
4812
|
+
hasConfig: !!s.config,
|
|
4813
|
+
}),
|
|
4814
|
+
isRunning: () => s.running,
|
|
4815
|
+
};
|
|
4816
|
+
}
|
|
4817
|
+
|
|
4818
|
+
const registry$1 = [];
|
|
4819
|
+
/**
|
|
4820
|
+
* Register a global fix.
|
|
4821
|
+
* Fixes are run in registration order.
|
|
4822
|
+
*/
|
|
4823
|
+
function register$1(fix) {
|
|
4824
|
+
registry$1.push(fix);
|
|
4825
|
+
}
|
|
4826
|
+
/**
|
|
4827
|
+
* Returns all fixes that are active for the given context.
|
|
4828
|
+
* A fix is active if it has no `shouldApply`, or `shouldApply` returns true.
|
|
4829
|
+
*/
|
|
4830
|
+
function getActiveFixes(ctx) {
|
|
4831
|
+
return registry$1.filter((fix) => {
|
|
4832
|
+
try {
|
|
4833
|
+
return !fix.shouldApply || fix.shouldApply(ctx);
|
|
4834
|
+
}
|
|
4835
|
+
catch {
|
|
4836
|
+
return false;
|
|
4837
|
+
}
|
|
4838
|
+
});
|
|
4839
|
+
}
|
|
4423
4840
|
|
|
4424
4841
|
/**
|
|
4425
4842
|
* Core viewport unit replacement logic.
|
|
4426
4843
|
* Converts vh/vw/svh/dvh/% to pixel values across all CSS in the iframe.
|
|
4427
4844
|
*/
|
|
4428
|
-
const logger$
|
|
4845
|
+
const logger$1 = createLogger({ enabled: false, prefix: 'ViewportUnitReplacer' });
|
|
4429
4846
|
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
4430
4847
|
const HEIGHT_RELATED_PROPERTIES = ['height', 'min-height', 'max-height', 'top', 'bottom'];
|
|
4431
4848
|
// ─── Per-run tracking state (reset on each process() call) ───────────────────
|
|
4432
4849
|
let elementsWithViewportUnits = new Set();
|
|
4433
4850
|
let originalValues = new WeakMap();
|
|
4434
4851
|
// ─── Regex ────────────────────────────────────────────────────────────────────
|
|
4435
|
-
/**
|
|
4852
|
+
/**
|
|
4853
|
+
* Stateless test-only regex (no `g` flag) — safe to share across calls.
|
|
4854
|
+
* Used exclusively for `.test()` checks before doing a full replacement.
|
|
4855
|
+
*/
|
|
4856
|
+
const VIEWPORT_RE_TEST = /([-.?\d]+)(vh|svh|lvh|dvh|vw|svw|lvw|dvw)/i;
|
|
4857
|
+
/** Fresh `g`-flagged instance for String.replace() callbacks. */
|
|
4436
4858
|
function createRegex() {
|
|
4437
|
-
return /([
|
|
4859
|
+
return /([-.?\d]+)(vh|svh|lvh|dvh|vw|svw|lvw|dvw)/gi;
|
|
4438
4860
|
}
|
|
4439
4861
|
// ─── Unit conversion ─────────────────────────────────────────────────────────
|
|
4440
4862
|
function px(value) {
|
|
4441
4863
|
return `${value.toFixed(2)}px`;
|
|
4442
4864
|
}
|
|
4443
|
-
function
|
|
4865
|
+
function buildUnitMap(ctx) {
|
|
4444
4866
|
return {
|
|
4445
4867
|
vh: ctx.targetHeight,
|
|
4446
4868
|
svh: ctx.targetHeight,
|
|
@@ -4452,15 +4874,15 @@ function getUnitMap(ctx) {
|
|
|
4452
4874
|
dvw: ctx.targetWidth,
|
|
4453
4875
|
};
|
|
4454
4876
|
}
|
|
4455
|
-
function toPx(value, unit,
|
|
4877
|
+
function toPx(value, unit, unitMap, targetHeight) {
|
|
4456
4878
|
const u = unit.toLowerCase();
|
|
4457
4879
|
if (u === '%')
|
|
4458
|
-
return (value / 100) *
|
|
4459
|
-
return (value / 100) * (
|
|
4880
|
+
return (value / 100) * targetHeight;
|
|
4881
|
+
return (value / 100) * (unitMap[u] ?? 0);
|
|
4460
4882
|
}
|
|
4461
|
-
function convert(value, unit,
|
|
4883
|
+
function convert(value, unit, unitMap, targetHeight) {
|
|
4462
4884
|
const num = parseFloat(value);
|
|
4463
|
-
return isNaN(num) ? value : px(toPx(num, unit,
|
|
4885
|
+
return isNaN(num) ? value : px(toPx(num, unit, unitMap, targetHeight));
|
|
4464
4886
|
}
|
|
4465
4887
|
function isHeightRelated(prop) {
|
|
4466
4888
|
return HEIGHT_RELATED_PROPERTIES.includes(prop);
|
|
@@ -4475,11 +4897,13 @@ function extractProperty(cssText, matchOffset) {
|
|
|
4475
4897
|
return m ? m[1].toLowerCase() : '';
|
|
4476
4898
|
}
|
|
4477
4899
|
function replaceInText(cssText, ctx) {
|
|
4900
|
+
const unitMap = buildUnitMap(ctx);
|
|
4901
|
+
const { targetHeight } = ctx;
|
|
4478
4902
|
return cssText.replace(createRegex(), (match, value, unit, offset) => {
|
|
4479
4903
|
if (unit === '%') {
|
|
4480
|
-
return isHeightRelated(extractProperty(cssText, offset)) ? convert(value, unit,
|
|
4904
|
+
return isHeightRelated(extractProperty(cssText, offset)) ? convert(value, unit, unitMap, targetHeight) : match;
|
|
4481
4905
|
}
|
|
4482
|
-
return convert(value, unit,
|
|
4906
|
+
return convert(value, unit, unitMap, targetHeight);
|
|
4483
4907
|
});
|
|
4484
4908
|
}
|
|
4485
4909
|
// ─── Element tracking ─────────────────────────────────────────────────────────
|
|
@@ -4496,11 +4920,11 @@ function trackSelector(selector, propOriginals, ctx) {
|
|
|
4496
4920
|
if (!originals.has(k))
|
|
4497
4921
|
originals.set(k, v);
|
|
4498
4922
|
});
|
|
4499
|
-
trackElement(el, propOriginals);
|
|
4923
|
+
ctx.enforcer?.trackElement(el, propOriginals);
|
|
4500
4924
|
});
|
|
4501
4925
|
}
|
|
4502
4926
|
catch {
|
|
4503
|
-
logger$
|
|
4927
|
+
logger$1.warn('Invalid selector, skipping:', selector);
|
|
4504
4928
|
}
|
|
4505
4929
|
}
|
|
4506
4930
|
// ─── CSS processing ───────────────────────────────────────────────────────────
|
|
@@ -4508,25 +4932,25 @@ function processInlineStyles(ctx) {
|
|
|
4508
4932
|
let count = 0;
|
|
4509
4933
|
ctx.doc.querySelectorAll('[style]').forEach((el) => {
|
|
4510
4934
|
const style = el.getAttribute('style');
|
|
4511
|
-
if (style &&
|
|
4935
|
+
if (style && VIEWPORT_RE_TEST.test(style)) {
|
|
4512
4936
|
elementsWithViewportUnits.add(el);
|
|
4513
4937
|
el.setAttribute('style', replaceInText(style, ctx));
|
|
4514
4938
|
count++;
|
|
4515
4939
|
}
|
|
4516
4940
|
});
|
|
4517
|
-
logger$
|
|
4941
|
+
logger$1.log(`Replaced ${count} inline style elements`);
|
|
4518
4942
|
return count;
|
|
4519
4943
|
}
|
|
4520
4944
|
function processStyleTags(ctx) {
|
|
4521
4945
|
let count = 0;
|
|
4522
4946
|
ctx.doc.querySelectorAll('style').forEach((tag) => {
|
|
4523
4947
|
const css = tag.textContent || '';
|
|
4524
|
-
if (
|
|
4948
|
+
if (VIEWPORT_RE_TEST.test(css)) {
|
|
4525
4949
|
tag.textContent = replaceInText(css, ctx);
|
|
4526
4950
|
count++;
|
|
4527
4951
|
}
|
|
4528
4952
|
});
|
|
4529
|
-
logger$
|
|
4953
|
+
logger$1.log(`Replaced ${count} <style> tags`);
|
|
4530
4954
|
return count;
|
|
4531
4955
|
}
|
|
4532
4956
|
function processRule(rule, ctx) {
|
|
@@ -4539,7 +4963,7 @@ function processRule(rule, ctx) {
|
|
|
4539
4963
|
for (let i = 0; i < style.length; i++) {
|
|
4540
4964
|
const prop = style[i];
|
|
4541
4965
|
const value = style.getPropertyValue(prop);
|
|
4542
|
-
if (value &&
|
|
4966
|
+
if (value && VIEWPORT_RE_TEST.test(value)) {
|
|
4543
4967
|
hasVp = true;
|
|
4544
4968
|
propOriginals.set(prop, value);
|
|
4545
4969
|
style.setProperty(prop, replaceInText(value, ctx), style.getPropertyPriority(prop));
|
|
@@ -4550,8 +4974,11 @@ function processRule(rule, ctx) {
|
|
|
4550
4974
|
trackSelector(cssRule.selectorText, propOriginals, ctx);
|
|
4551
4975
|
}
|
|
4552
4976
|
if ('cssRules' in rule) {
|
|
4553
|
-
|
|
4554
|
-
|
|
4977
|
+
const nested = rule.cssRules;
|
|
4978
|
+
if (nested) {
|
|
4979
|
+
for (let i = 0; i < nested.length; i++) {
|
|
4980
|
+
count += processRule(nested[i], ctx);
|
|
4981
|
+
}
|
|
4555
4982
|
}
|
|
4556
4983
|
}
|
|
4557
4984
|
return count;
|
|
@@ -4559,34 +4986,38 @@ function processRule(rule, ctx) {
|
|
|
4559
4986
|
/** Processes only inline <style> sheets. Linked sheets are handled by processLinkedStylesheets. */
|
|
4560
4987
|
function processStylesheets(ctx) {
|
|
4561
4988
|
let total = 0;
|
|
4562
|
-
|
|
4989
|
+
const sheets = ctx.doc.styleSheets;
|
|
4990
|
+
for (let i = 0; i < sheets.length; i++) {
|
|
4991
|
+
const sheet = sheets[i];
|
|
4563
4992
|
if (sheet.href)
|
|
4564
|
-
|
|
4993
|
+
continue; // deferred to processLinkedStylesheets
|
|
4565
4994
|
try {
|
|
4566
|
-
|
|
4567
|
-
|
|
4995
|
+
const rules = sheet.cssRules;
|
|
4996
|
+
for (let j = 0; j < rules.length; j++) {
|
|
4997
|
+
total += processRule(rules[j], ctx);
|
|
4568
4998
|
}
|
|
4569
4999
|
}
|
|
4570
5000
|
catch (e) {
|
|
4571
|
-
logger$
|
|
5001
|
+
logger$1.warn('Cannot read stylesheet (CORS?):', e.message);
|
|
4572
5002
|
}
|
|
4573
|
-
}
|
|
4574
|
-
logger$
|
|
5003
|
+
}
|
|
5004
|
+
logger$1.log(`Replaced ${total} rules in inline stylesheets`);
|
|
4575
5005
|
return total;
|
|
4576
5006
|
}
|
|
4577
5007
|
async function processLinkedStylesheets(ctx) {
|
|
4578
5008
|
const links = ctx.doc.querySelectorAll('link[rel="stylesheet"]');
|
|
4579
5009
|
let count = 0;
|
|
4580
|
-
for (
|
|
5010
|
+
for (let i = 0; i < links.length; i++) {
|
|
5011
|
+
const link = links[i];
|
|
4581
5012
|
// Skip cross-origin — already in browser CSSOM, handled via processStylesheets
|
|
4582
5013
|
if (link.href && !link.href.startsWith(ctx.win.location.origin)) {
|
|
4583
|
-
logger$
|
|
5014
|
+
logger$1.log('Skipping cross-origin CSS:', link.href);
|
|
4584
5015
|
continue;
|
|
4585
5016
|
}
|
|
4586
5017
|
try {
|
|
4587
5018
|
const res = await fetch(link.href);
|
|
4588
5019
|
let css = await res.text();
|
|
4589
|
-
if (
|
|
5020
|
+
if (VIEWPORT_RE_TEST.test(css)) {
|
|
4590
5021
|
css = replaceInText(css, ctx);
|
|
4591
5022
|
const style = ctx.doc.createElement('style');
|
|
4592
5023
|
style.textContent = css;
|
|
@@ -4597,15 +5028,15 @@ async function processLinkedStylesheets(ctx) {
|
|
|
4597
5028
|
}
|
|
4598
5029
|
}
|
|
4599
5030
|
catch (e) {
|
|
4600
|
-
logger$
|
|
5031
|
+
logger$1.warn('Cannot load CSS:', link.href, e);
|
|
4601
5032
|
}
|
|
4602
5033
|
}
|
|
4603
|
-
logger$
|
|
5034
|
+
logger$1.log(`Replaced ${count} linked CSS files`);
|
|
4604
5035
|
return count;
|
|
4605
5036
|
}
|
|
4606
5037
|
// ─── Public entry point ───────────────────────────────────────────────────────
|
|
4607
5038
|
async function process$1(ctx) {
|
|
4608
|
-
logger$
|
|
5039
|
+
logger$1.configure({ enabled: !!ctx.debug });
|
|
4609
5040
|
// Reset tracking state from any previous run
|
|
4610
5041
|
elementsWithViewportUnits = new Set();
|
|
4611
5042
|
originalValues = new WeakMap();
|
|
@@ -4616,8 +5047,8 @@ async function process$1(ctx) {
|
|
|
4616
5047
|
// Wait for browser to apply the replaced styles
|
|
4617
5048
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
4618
5049
|
// Enforce final computed styles to inline with !important
|
|
4619
|
-
const count = processAll({ debug: !!ctx.debug });
|
|
4620
|
-
logger$
|
|
5050
|
+
const count = ctx.enforcer?.processAll({ debug: !!ctx.debug }) ?? 0;
|
|
5051
|
+
logger$1.log(`Enforced ${count} computed styles for ${elementsWithViewportUnits.size} tracked elements`);
|
|
4621
5052
|
}
|
|
4622
5053
|
|
|
4623
5054
|
/**
|
|
@@ -4713,6 +5144,9 @@ function getMaxWByDeviceType(deviceType) {
|
|
|
4713
5144
|
// ─── Main fix ─────────────────────────────────────────────────────────────────
|
|
4714
5145
|
function afterProcess$1({ doc, targetWidth, deviceType }) {
|
|
4715
5146
|
doc.querySelectorAll(SLIDER_ITEM_SELECTOR).forEach((item) => {
|
|
5147
|
+
// When !gp-min-w-full is set, the item fills 100% width via Tailwind — skip manual width override
|
|
5148
|
+
if (item.classList.contains('!gp-min-w-full'))
|
|
5149
|
+
return;
|
|
4716
5150
|
const originalWidth = parseFloat(item.style.minWidth) || parseFloat(item.style.maxWidth) || 0;
|
|
4717
5151
|
if (!originalWidth)
|
|
4718
5152
|
return;
|
|
@@ -4813,23 +5247,6 @@ register$1({
|
|
|
4813
5247
|
afterProcess,
|
|
4814
5248
|
});
|
|
4815
5249
|
|
|
4816
|
-
const logger$3 = createLogger({ enabled: false, prefix: 'ViewportReplacer' });
|
|
4817
|
-
let dimensionsListener = null;
|
|
4818
|
-
function attach(debug) {
|
|
4819
|
-
logger$3.configure({ enabled: !!debug });
|
|
4820
|
-
dimensionsListener = (e) => {
|
|
4821
|
-
const ev = e;
|
|
4822
|
-
logger$3.log('Dimensions applied:', ev.detail);
|
|
4823
|
-
};
|
|
4824
|
-
window.addEventListener('iframe-dimensions-applied', dimensionsListener);
|
|
4825
|
-
}
|
|
4826
|
-
function detach() {
|
|
4827
|
-
if (dimensionsListener) {
|
|
4828
|
-
window.removeEventListener('iframe-dimensions-applied', dimensionsListener);
|
|
4829
|
-
dimensionsListener = null;
|
|
4830
|
-
}
|
|
4831
|
-
}
|
|
4832
|
-
|
|
4833
5250
|
/**
|
|
4834
5251
|
* Default iframe dimension calculation.
|
|
4835
5252
|
* Used as fallback when no fix overrides getDimensions().
|
|
@@ -4853,41 +5270,58 @@ function getFinalWidth(doc) {
|
|
|
4853
5270
|
* Phase 3: afterProcess (shop → global)
|
|
4854
5271
|
* Phase 4: getDimensions (shop → global → default)
|
|
4855
5272
|
*/
|
|
4856
|
-
const logger
|
|
5273
|
+
const logger = createLogger({ enabled: false, prefix: 'ViewportReplacer' });
|
|
4857
5274
|
function configure(debug) {
|
|
4858
|
-
logger
|
|
5275
|
+
logger.configure({ enabled: debug });
|
|
4859
5276
|
}
|
|
4860
5277
|
async function run$1(ctx, activeGlobal, shopFix) {
|
|
4861
5278
|
// ── Phase 1: beforeProcess ────────────────────────────────────────────────
|
|
5279
|
+
const t1 = perf.mark('phase1.beforeProcess');
|
|
4862
5280
|
for (const fix of activeGlobal) {
|
|
4863
5281
|
if (fix.beforeProcess) {
|
|
4864
|
-
logger
|
|
5282
|
+
logger.log(`[beforeProcess] ${fix.name}`);
|
|
5283
|
+
const t = perf.mark(`phase1.${fix.name}.beforeProcess`);
|
|
4865
5284
|
await fix.beforeProcess(ctx);
|
|
5285
|
+
perf.measure(`phase1.${fix.name}.beforeProcess`, t);
|
|
4866
5286
|
}
|
|
4867
5287
|
}
|
|
4868
5288
|
if (shopFix?.beforeProcess) {
|
|
4869
|
-
logger
|
|
5289
|
+
logger.log('[beforeProcess] shop');
|
|
5290
|
+
const t = perf.mark('phase1.shop.beforeProcess');
|
|
4870
5291
|
await shopFix.beforeProcess(ctx);
|
|
5292
|
+
perf.measure('phase1.shop.beforeProcess', t);
|
|
4871
5293
|
}
|
|
5294
|
+
perf.measure('phase1.beforeProcess', t1);
|
|
4872
5295
|
// ── Phase 2: process ──────────────────────────────────────────────────────
|
|
5296
|
+
const t2 = perf.mark('phase2.process');
|
|
4873
5297
|
for (const fix of activeGlobal) {
|
|
4874
5298
|
if (fix.process) {
|
|
4875
|
-
logger
|
|
5299
|
+
logger.log(`[process] ${fix.name}`);
|
|
5300
|
+
const t = perf.mark(`phase2.${fix.name}.process`);
|
|
4876
5301
|
await fix.process(ctx);
|
|
5302
|
+
perf.measure(`phase2.${fix.name}.process`, t);
|
|
4877
5303
|
}
|
|
4878
5304
|
}
|
|
5305
|
+
perf.measure('phase2.process', t2);
|
|
4879
5306
|
// ── Phase 3: afterProcess ─────────────────────────────────────────────────
|
|
5307
|
+
const t3 = perf.mark('phase3.afterProcess');
|
|
4880
5308
|
if (shopFix?.afterProcess) {
|
|
4881
|
-
logger
|
|
5309
|
+
logger.log('[afterProcess] shop');
|
|
5310
|
+
const t = perf.mark('phase3.shop.afterProcess');
|
|
4882
5311
|
await shopFix.afterProcess(ctx);
|
|
5312
|
+
perf.measure('phase3.shop.afterProcess', t);
|
|
4883
5313
|
}
|
|
4884
5314
|
for (const fix of activeGlobal) {
|
|
4885
5315
|
if (fix.afterProcess) {
|
|
4886
|
-
logger
|
|
5316
|
+
logger.log(`[afterProcess] ${fix.name}`);
|
|
5317
|
+
const t = perf.mark(`phase3.${fix.name}.afterProcess`);
|
|
4887
5318
|
await fix.afterProcess(ctx);
|
|
5319
|
+
perf.measure(`phase3.${fix.name}.afterProcess`, t);
|
|
4888
5320
|
}
|
|
4889
5321
|
}
|
|
5322
|
+
perf.measure('phase3.afterProcess', t3);
|
|
4890
5323
|
// ── Phase 4: getDimensions ────────────────────────────────────────────────
|
|
5324
|
+
const t4 = perf.mark('phase4.getDimensions');
|
|
4891
5325
|
return new Promise((resolve) => {
|
|
4892
5326
|
requestAnimationFrame(() => {
|
|
4893
5327
|
let dimensions = null;
|
|
@@ -4895,14 +5329,14 @@ async function run$1(ctx, activeGlobal, shopFix) {
|
|
|
4895
5329
|
if (shopFix?.getDimensions) {
|
|
4896
5330
|
dimensions = shopFix.getDimensions(ctx);
|
|
4897
5331
|
if (dimensions)
|
|
4898
|
-
logger
|
|
5332
|
+
logger.log('Dimensions from shop fix:', dimensions);
|
|
4899
5333
|
}
|
|
4900
5334
|
if (!dimensions) {
|
|
4901
5335
|
for (const fix of activeGlobal) {
|
|
4902
5336
|
if (fix.getDimensions) {
|
|
4903
5337
|
dimensions = fix.getDimensions(ctx);
|
|
4904
5338
|
if (dimensions) {
|
|
4905
|
-
logger
|
|
5339
|
+
logger.log(`Dimensions from global fix [${fix.name}]:`, dimensions);
|
|
4906
5340
|
break;
|
|
4907
5341
|
}
|
|
4908
5342
|
}
|
|
@@ -4911,7 +5345,8 @@ async function run$1(ctx, activeGlobal, shopFix) {
|
|
|
4911
5345
|
if (!dimensions) {
|
|
4912
5346
|
dimensions = { height: getFinalHeight(ctx.doc, ctx.win), width: getFinalWidth(ctx.doc) };
|
|
4913
5347
|
}
|
|
4914
|
-
logger
|
|
5348
|
+
logger.log('Final dimensions:', dimensions);
|
|
5349
|
+
perf.measure('phase4.getDimensions', t4);
|
|
4915
5350
|
resolve(dimensions);
|
|
4916
5351
|
});
|
|
4917
5352
|
});
|
|
@@ -4988,232 +5423,286 @@ register(`566240210141053597`, {
|
|
|
4988
5423
|
afterProcess: restoreAndFixLayout,
|
|
4989
5424
|
});
|
|
4990
5425
|
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
let config$1 = null;
|
|
4996
|
-
let shopFix = null;
|
|
4997
|
-
let running$2 = false;
|
|
4998
|
-
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
4999
|
-
function start$3(iframe, cfg) {
|
|
5000
|
-
if (running$2) {
|
|
5001
|
-
logger$1.warn('Already running. Call stop() first.');
|
|
5426
|
+
// ── Module-level functions ────────────────────────────────────────────────────
|
|
5427
|
+
function start$2(s, iframe, cfg) {
|
|
5428
|
+
if (s.running) {
|
|
5429
|
+
s.logger.warn('Already running. Call stop() first.');
|
|
5002
5430
|
return;
|
|
5003
5431
|
}
|
|
5004
5432
|
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
5005
5433
|
throw new Error('Iframe document or window not accessible');
|
|
5006
5434
|
}
|
|
5007
|
-
doc = iframe.contentDocument;
|
|
5008
|
-
win = iframe.contentWindow;
|
|
5009
|
-
config
|
|
5010
|
-
running
|
|
5011
|
-
shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
|
|
5012
|
-
if (shopFix)
|
|
5013
|
-
logger
|
|
5014
|
-
}
|
|
5015
|
-
logger$1.configure({ enabled: !!cfg.debug });
|
|
5435
|
+
s.doc = iframe.contentDocument;
|
|
5436
|
+
s.win = iframe.contentWindow;
|
|
5437
|
+
s.config = cfg;
|
|
5438
|
+
s.running = true;
|
|
5439
|
+
s.shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
|
|
5440
|
+
if (s.shopFix)
|
|
5441
|
+
s.logger.log(`Shop fix loaded for "${cfg.shopId}":`, s.shopFix.description ?? '(no description)');
|
|
5442
|
+
s.logger.configure({ enabled: !!cfg.debug });
|
|
5016
5443
|
configure(!!cfg.debug);
|
|
5017
|
-
start
|
|
5018
|
-
attach(cfg.debug);
|
|
5019
|
-
logger
|
|
5444
|
+
s.enforcer.start(s.doc, s.win, cfg, { debug: !!cfg.debug });
|
|
5445
|
+
s.listeners.attach(cfg.debug);
|
|
5446
|
+
s.logger.log('Started');
|
|
5020
5447
|
}
|
|
5021
|
-
function stop$
|
|
5022
|
-
if (!running
|
|
5448
|
+
function stop$2(s) {
|
|
5449
|
+
if (!s.running)
|
|
5023
5450
|
return;
|
|
5024
|
-
stop
|
|
5025
|
-
detach();
|
|
5026
|
-
doc = null;
|
|
5027
|
-
win = null;
|
|
5028
|
-
config
|
|
5029
|
-
shopFix = null;
|
|
5030
|
-
running
|
|
5031
|
-
logger
|
|
5032
|
-
}
|
|
5033
|
-
async function run() {
|
|
5034
|
-
if (!running
|
|
5035
|
-
logger
|
|
5451
|
+
s.enforcer.stop();
|
|
5452
|
+
s.listeners.detach();
|
|
5453
|
+
s.doc = null;
|
|
5454
|
+
s.win = null;
|
|
5455
|
+
s.config = null;
|
|
5456
|
+
s.shopFix = null;
|
|
5457
|
+
s.running = false;
|
|
5458
|
+
s.logger.log('Stopped');
|
|
5459
|
+
}
|
|
5460
|
+
async function run(s) {
|
|
5461
|
+
if (!s.running || !s.doc || !s.win || !s.config) {
|
|
5462
|
+
s.logger.warn('Not running. Call start() first.');
|
|
5036
5463
|
return { height: 1000, width: 1000 };
|
|
5037
5464
|
}
|
|
5038
5465
|
const ctx = {
|
|
5039
|
-
doc,
|
|
5040
|
-
win,
|
|
5041
|
-
deviceType: config
|
|
5042
|
-
targetWidth: config
|
|
5043
|
-
targetHeight: config
|
|
5044
|
-
debug: config
|
|
5466
|
+
doc: s.doc,
|
|
5467
|
+
win: s.win,
|
|
5468
|
+
deviceType: s.config.deviceType,
|
|
5469
|
+
targetWidth: s.config.targetWidth,
|
|
5470
|
+
targetHeight: s.config.targetHeight,
|
|
5471
|
+
debug: s.config.debug,
|
|
5472
|
+
enforcer: s.enforcer,
|
|
5045
5473
|
};
|
|
5046
5474
|
const activeGlobal = getActiveFixes(ctx);
|
|
5047
|
-
if (activeGlobal.length > 0)
|
|
5048
|
-
logger
|
|
5049
|
-
|
|
5475
|
+
if (activeGlobal.length > 0)
|
|
5476
|
+
s.logger.log(`Active global fixes: ${activeGlobal.map((f) => f.name).join(', ')}`);
|
|
5477
|
+
const tRun = perf.mark('viewport.run');
|
|
5050
5478
|
try {
|
|
5051
|
-
|
|
5479
|
+
const result = await run$1(ctx, activeGlobal, s.shopFix);
|
|
5480
|
+
perf.measure('viewport.run', tRun);
|
|
5481
|
+
return result;
|
|
5052
5482
|
}
|
|
5053
5483
|
catch (err) {
|
|
5054
|
-
|
|
5055
|
-
|
|
5484
|
+
perf.measure('viewport.run', tRun);
|
|
5485
|
+
s.logger.error('Critical error:', err);
|
|
5486
|
+
return { height: s.doc.body?.scrollHeight || 1000, width: s.doc.body?.scrollWidth || 1000 };
|
|
5056
5487
|
}
|
|
5057
5488
|
}
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
prefix: 'IframeFixer',
|
|
5062
|
-
});
|
|
5063
|
-
// ============================================================================
|
|
5064
|
-
// State
|
|
5065
|
-
// ============================================================================
|
|
5066
|
-
let iframe = null;
|
|
5067
|
-
let config = null;
|
|
5068
|
-
let running$1 = false;
|
|
5069
|
-
let loadListener = null;
|
|
5070
|
-
// ============================================================================
|
|
5071
|
-
// Core API Functions
|
|
5072
|
-
// ============================================================================
|
|
5073
|
-
function start$2(cfg) {
|
|
5074
|
-
if (running$1) {
|
|
5075
|
-
logger.warn('Fixer is already running. Call stop() first.');
|
|
5489
|
+
function updateConfig$1(s, cfg) {
|
|
5490
|
+
if (!s.running || !s.config) {
|
|
5491
|
+
s.logger.warn('Not running. Call start() first.');
|
|
5076
5492
|
return;
|
|
5077
5493
|
}
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
logger.log('
|
|
5083
|
-
|
|
5494
|
+
s.config = { ...s.config, ...cfg };
|
|
5495
|
+
if (cfg.shopId !== undefined)
|
|
5496
|
+
s.shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
|
|
5497
|
+
s.enforcer.updateConfig(cfg);
|
|
5498
|
+
s.logger.log('Config updated');
|
|
5499
|
+
}
|
|
5500
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
5501
|
+
function createViewportProcessor() {
|
|
5502
|
+
const s = {
|
|
5503
|
+
logger: createLogger({ enabled: false, prefix: 'ViewportReplacer' }),
|
|
5504
|
+
enforcer: createEnforcer(),
|
|
5505
|
+
listeners: createViewportListeners(),
|
|
5506
|
+
doc: null,
|
|
5507
|
+
win: null,
|
|
5508
|
+
config: null,
|
|
5509
|
+
shopFix: null,
|
|
5510
|
+
running: false,
|
|
5511
|
+
};
|
|
5512
|
+
return {
|
|
5513
|
+
start: (iframe, cfg) => start$2(s, iframe, cfg),
|
|
5514
|
+
stop: () => stop$2(s),
|
|
5515
|
+
run: () => run(s),
|
|
5516
|
+
updateConfig: (cfg) => updateConfig$1(s, cfg),
|
|
5517
|
+
isRunning: () => s.running,
|
|
5518
|
+
};
|
|
5084
5519
|
}
|
|
5085
|
-
|
|
5086
|
-
|
|
5520
|
+
|
|
5521
|
+
// ── Module-level functions ────────────────────────────────────────────────────
|
|
5522
|
+
function dispatchDimensionsEvent(dimensions) {
|
|
5523
|
+
window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', { detail: dimensions }));
|
|
5524
|
+
}
|
|
5525
|
+
async function process(s) {
|
|
5526
|
+
if (!s.iframe || !s.config)
|
|
5087
5527
|
return;
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
stop$5();
|
|
5092
|
-
// Remove load listener
|
|
5093
|
-
if (iframe && loadListener) {
|
|
5094
|
-
iframe.removeEventListener('load', loadListener);
|
|
5095
|
-
loadListener = null;
|
|
5096
|
-
}
|
|
5097
|
-
iframe = null;
|
|
5098
|
-
config = null;
|
|
5099
|
-
running$1 = false;
|
|
5100
|
-
logger.log('Iframe fixer stopped');
|
|
5101
|
-
}
|
|
5102
|
-
async function initialize() {
|
|
5103
|
-
if (!iframe || !config) {
|
|
5104
|
-
logger.error('iframe not found');
|
|
5105
|
-
config?.onError?.(new Error('iframe not found'));
|
|
5528
|
+
if (!s.iframe.contentDocument || !s.iframe.contentWindow) {
|
|
5529
|
+
s.logger.error('Cannot access iframe document');
|
|
5530
|
+
s.config.onError?.(new Error('Cannot access iframe document'));
|
|
5106
5531
|
return;
|
|
5107
5532
|
}
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5533
|
+
const sessionId = `render-${Date.now()}`;
|
|
5534
|
+
perf.startSession(sessionId);
|
|
5535
|
+
const t0 = perf.mark('orchestrator.process');
|
|
5536
|
+
try {
|
|
5537
|
+
s.logger.log('Processing viewport units...');
|
|
5538
|
+
s.viewportReplacer.start(s.iframe, s.config);
|
|
5539
|
+
s.navigationBlocker.start(s.iframe, { debug: s.config.debug });
|
|
5540
|
+
const result = await s.viewportReplacer.run();
|
|
5541
|
+
perf.measure('orchestrator.process', t0);
|
|
5542
|
+
perf.endSession();
|
|
5543
|
+
s.logger.log('Process completed:', result);
|
|
5544
|
+
s.config.onSuccess?.(result);
|
|
5545
|
+
dispatchDimensionsEvent(result);
|
|
5111
5546
|
}
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5547
|
+
catch (error) {
|
|
5548
|
+
perf.measure('orchestrator.process', t0);
|
|
5549
|
+
perf.endSession();
|
|
5550
|
+
s.logger.error('Failed to process:', error);
|
|
5551
|
+
s.config.onError?.(error);
|
|
5115
5552
|
}
|
|
5116
5553
|
}
|
|
5117
|
-
async function
|
|
5118
|
-
if (!iframe || !config)
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
logger.error('Cannot access iframe document');
|
|
5122
|
-
config.onError?.(new Error('Cannot access iframe document'));
|
|
5554
|
+
async function initialize(s) {
|
|
5555
|
+
if (!s.iframe || !s.config) {
|
|
5556
|
+
s.logger.error('iframe not found');
|
|
5557
|
+
s.config?.onError?.(new Error('iframe not found'));
|
|
5123
5558
|
return;
|
|
5124
5559
|
}
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
start$3(iframe, config);
|
|
5128
|
-
start$5(iframe, { debug: config.debug });
|
|
5129
|
-
const result = await run();
|
|
5130
|
-
logger.log('Process completed:', result);
|
|
5131
|
-
config.onSuccess?.(result);
|
|
5132
|
-
dispatchDimensionsEvent(result);
|
|
5133
|
-
// Optionally setup height observer
|
|
5134
|
-
// setupHeightObserver();
|
|
5560
|
+
if (s.iframe.contentDocument?.readyState === 'complete') {
|
|
5561
|
+
await process(s);
|
|
5135
5562
|
}
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5563
|
+
else {
|
|
5564
|
+
s.loadListener = () => process(s);
|
|
5565
|
+
s.iframe.addEventListener('load', s.loadListener);
|
|
5139
5566
|
}
|
|
5140
5567
|
}
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5568
|
+
function start$1(s, cfg) {
|
|
5569
|
+
if (s.running) {
|
|
5570
|
+
s.logger.warn('Fixer is already running. Call stop() first.');
|
|
5571
|
+
return;
|
|
5572
|
+
}
|
|
5573
|
+
s.iframe = cfg.iframe;
|
|
5574
|
+
s.config = cfg;
|
|
5575
|
+
s.running = true;
|
|
5576
|
+
s.logger.configure({ enabled: !!cfg.debug });
|
|
5577
|
+
s.logger.log('Iframe fixer started');
|
|
5578
|
+
initialize(s);
|
|
5148
5579
|
}
|
|
5149
|
-
function
|
|
5150
|
-
|
|
5580
|
+
function stop$1(s) {
|
|
5581
|
+
if (!s.running)
|
|
5582
|
+
return;
|
|
5583
|
+
s.viewportReplacer.stop();
|
|
5584
|
+
s.heightObserver.stop();
|
|
5585
|
+
s.navigationBlocker.stop();
|
|
5586
|
+
if (s.iframe && s.loadListener) {
|
|
5587
|
+
s.iframe.removeEventListener('load', s.loadListener);
|
|
5588
|
+
s.loadListener = null;
|
|
5589
|
+
}
|
|
5590
|
+
s.iframe = null;
|
|
5591
|
+
s.config = null;
|
|
5592
|
+
s.running = false;
|
|
5593
|
+
s.logger.log('Iframe fixer stopped');
|
|
5594
|
+
}
|
|
5595
|
+
async function recalculate$1(s) {
|
|
5596
|
+
if (!s.running) {
|
|
5597
|
+
s.logger.warn('Fixer is not running.');
|
|
5598
|
+
return;
|
|
5599
|
+
}
|
|
5600
|
+
s.logger.log('Recalculating...');
|
|
5601
|
+
await process(s);
|
|
5151
5602
|
}
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
function enableNavigationBlocking$2() {
|
|
5156
|
-
if (!running$1) {
|
|
5157
|
-
logger.warn('Fixer is not running. Call start() first.');
|
|
5603
|
+
function updateConfig(s, cfg) {
|
|
5604
|
+
if (!s.running || !s.config) {
|
|
5605
|
+
s.logger.warn('Fixer is not running.');
|
|
5158
5606
|
return;
|
|
5159
5607
|
}
|
|
5160
|
-
|
|
5608
|
+
s.config = { ...s.config, ...cfg };
|
|
5609
|
+
s.viewportReplacer.updateConfig(cfg);
|
|
5610
|
+
s.logger.log('Config updated');
|
|
5611
|
+
}
|
|
5612
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
5613
|
+
function createOrchestrator() {
|
|
5614
|
+
const s = {
|
|
5615
|
+
logger: createLogger({ enabled: false, prefix: 'IframeFixer' }),
|
|
5616
|
+
viewportReplacer: createViewportProcessor(),
|
|
5617
|
+
navigationBlocker: createNavigationBlocker(),
|
|
5618
|
+
heightObserver: createHeightObserver(),
|
|
5619
|
+
iframe: null,
|
|
5620
|
+
config: null,
|
|
5621
|
+
running: false,
|
|
5622
|
+
loadListener: null,
|
|
5623
|
+
};
|
|
5624
|
+
return {
|
|
5625
|
+
start: (cfg) => start$1(s, cfg),
|
|
5626
|
+
stop: () => stop$1(s),
|
|
5627
|
+
recalculate: () => recalculate$1(s),
|
|
5628
|
+
updateConfig: (cfg) => updateConfig(s, cfg),
|
|
5629
|
+
enableNavigationBlocking: () => s.navigationBlocker.enable(),
|
|
5630
|
+
enableNavigationBlockingMessage: () => s.navigationBlocker.enableMessage(),
|
|
5631
|
+
disableNavigationBlocking: () => s.navigationBlocker.disable(),
|
|
5632
|
+
disableNavigationBlockingMessage: () => s.navigationBlocker.disableMessage(),
|
|
5633
|
+
isRunning: () => s.running,
|
|
5634
|
+
getStateInfo: () => ({
|
|
5635
|
+
isRunning: s.running,
|
|
5636
|
+
hasIframe: !!s.iframe,
|
|
5637
|
+
hasConfig: !!s.config,
|
|
5638
|
+
hasNavigationBlocker: s.navigationBlocker.isRunning(),
|
|
5639
|
+
hasHeightObserver: s.heightObserver.isRunning(),
|
|
5640
|
+
viewportReplacerRunning: s.viewportReplacer.isRunning(),
|
|
5641
|
+
}),
|
|
5642
|
+
};
|
|
5161
5643
|
}
|
|
5162
5644
|
|
|
5163
5645
|
/**
|
|
5164
|
-
* Iframe Helper
|
|
5165
|
-
*
|
|
5646
|
+
* Iframe Helper — factory entry point.
|
|
5647
|
+
*
|
|
5648
|
+
* Each call to `createIframeHelper()` returns a fully isolated instance
|
|
5649
|
+
* with its own processor state. Use one instance per iframe.
|
|
5166
5650
|
*/
|
|
5167
|
-
//
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
// ============================================================================
|
|
5172
|
-
// Public API
|
|
5173
|
-
// ============================================================================
|
|
5174
|
-
function start$1(config) {
|
|
5175
|
-
if (running) {
|
|
5176
|
-
console.warn('[IframeHelperStarter] Already running. Call stop() first.');
|
|
5651
|
+
// ── Module-level functions ────────────────────────────────────────────────────
|
|
5652
|
+
function start(s, config) {
|
|
5653
|
+
if (s.running) {
|
|
5654
|
+
console.warn('[IframeHelper] Already running. Call stop() first.');
|
|
5177
5655
|
return;
|
|
5178
5656
|
}
|
|
5179
|
-
start
|
|
5180
|
-
running = true;
|
|
5657
|
+
s.fixer.start(config);
|
|
5658
|
+
s.running = true;
|
|
5181
5659
|
}
|
|
5182
|
-
function stop
|
|
5183
|
-
if (!running)
|
|
5660
|
+
function stop(s) {
|
|
5661
|
+
if (!s.running)
|
|
5184
5662
|
return;
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
running = false;
|
|
5663
|
+
s.fixer.stop();
|
|
5664
|
+
s.running = false;
|
|
5188
5665
|
}
|
|
5189
|
-
function
|
|
5190
|
-
if (!running) {
|
|
5191
|
-
console.warn('[
|
|
5666
|
+
async function recalculate(s) {
|
|
5667
|
+
if (!s.running) {
|
|
5668
|
+
console.warn('[IframeHelper] Not running. Call start() first.');
|
|
5192
5669
|
return;
|
|
5193
5670
|
}
|
|
5194
|
-
|
|
5195
|
-
}
|
|
5196
|
-
|
|
5197
|
-
function start(config) {
|
|
5198
|
-
start$1(config);
|
|
5671
|
+
await s.fixer.recalculate();
|
|
5199
5672
|
}
|
|
5200
|
-
function
|
|
5201
|
-
|
|
5673
|
+
function enableNavigationBlocking(s) {
|
|
5674
|
+
if (!s.running) {
|
|
5675
|
+
console.warn('[IframeHelper] Not running. Call start() first.');
|
|
5676
|
+
return;
|
|
5677
|
+
}
|
|
5678
|
+
s.fixer.enableNavigationBlocking();
|
|
5202
5679
|
}
|
|
5203
|
-
|
|
5204
|
-
|
|
5680
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
5681
|
+
function createIframeHelper() {
|
|
5682
|
+
const s = {
|
|
5683
|
+
fixer: createOrchestrator(),
|
|
5684
|
+
running: false,
|
|
5685
|
+
};
|
|
5686
|
+
return {
|
|
5687
|
+
start: (config) => start(s, config),
|
|
5688
|
+
stop: () => stop(s),
|
|
5689
|
+
recalculate: () => recalculate(s),
|
|
5690
|
+
enableNavigationBlocking: () => enableNavigationBlocking(s),
|
|
5691
|
+
isRunning: () => s.running,
|
|
5692
|
+
};
|
|
5205
5693
|
}
|
|
5206
5694
|
|
|
5695
|
+
const iframeHelper = createIframeHelper();
|
|
5207
5696
|
function useVizLiveRender() {
|
|
5208
5697
|
const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
|
|
5209
5698
|
const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
|
|
5210
5699
|
const wrapperWidth = useHeatmapVizRectContext((s) => s.wrapperWidth);
|
|
5211
|
-
const
|
|
5212
|
-
const htmlContent =
|
|
5213
|
-
const targetUrl =
|
|
5700
|
+
const setIsRenderedViz = useHeatmapVizContext((s) => s.setIsRenderedViz);
|
|
5701
|
+
const htmlContent = useHeatmapLiveContext((s) => s.htmlContent);
|
|
5702
|
+
const targetUrl = useHeatmapLiveContext((s) => s.targetUrl);
|
|
5214
5703
|
const deviceType = useHeatmapSettingContext((s) => s.deviceType);
|
|
5215
|
-
const renderMode =
|
|
5216
|
-
const storefrontPassword =
|
|
5704
|
+
const renderMode = useHeatmapLiveContext((s) => s.renderMode);
|
|
5705
|
+
const storefrontPassword = useHeatmapLiveContext((s) => s.storefrontPassword);
|
|
5217
5706
|
useHeatmapWidthByDevice();
|
|
5218
5707
|
const { iframeRef, isReady } = useVizLiveIframeMsg();
|
|
5219
5708
|
// Handle iframe rendering based on mode
|
|
@@ -5254,10 +5743,10 @@ function useVizLiveRender() {
|
|
|
5254
5743
|
const hasContent = (renderMode === 'portal' && targetUrl) || (renderMode === 'inline' && htmlContent);
|
|
5255
5744
|
if (!iframe || !hasContent)
|
|
5256
5745
|
return;
|
|
5257
|
-
|
|
5258
|
-
|
|
5746
|
+
setIsRenderedViz(true);
|
|
5747
|
+
startIframe$1(iframe, deviceType, { width: wrapperWidth, height: wrapperHeight }, (height) => {
|
|
5259
5748
|
height && setIframeHeight(height);
|
|
5260
|
-
|
|
5749
|
+
setIsRenderedViz(true);
|
|
5261
5750
|
});
|
|
5262
5751
|
return () => { };
|
|
5263
5752
|
}, [
|
|
@@ -5269,7 +5758,7 @@ function useVizLiveRender() {
|
|
|
5269
5758
|
targetUrl,
|
|
5270
5759
|
htmlContent,
|
|
5271
5760
|
iframeRef,
|
|
5272
|
-
|
|
5761
|
+
setIsRenderedViz,
|
|
5273
5762
|
setIframeHeight,
|
|
5274
5763
|
]);
|
|
5275
5764
|
return {
|
|
@@ -5288,9 +5777,9 @@ function buildPortalUrl(targetUrl, storefrontPassword) {
|
|
|
5288
5777
|
const portalServiceUrl = getPortalServiceUrl();
|
|
5289
5778
|
return `${portalServiceUrl}/?${params.toString()}`;
|
|
5290
5779
|
}
|
|
5291
|
-
function
|
|
5292
|
-
stop();
|
|
5293
|
-
start({
|
|
5780
|
+
function startIframe$1(iframe, deviceType = EDeviceType.Desktop, rect, onSuccess) {
|
|
5781
|
+
iframeHelper.stop();
|
|
5782
|
+
iframeHelper.start({
|
|
5294
5783
|
deviceType: deviceType,
|
|
5295
5784
|
targetWidth: rect.width,
|
|
5296
5785
|
targetHeight: rect.height,
|
|
@@ -5301,7 +5790,7 @@ function initIframeHelper$1(iframe, deviceType = EDeviceType.Desktop, rect, onSu
|
|
|
5301
5790
|
},
|
|
5302
5791
|
});
|
|
5303
5792
|
// fixer.recalculate();
|
|
5304
|
-
enableNavigationBlocking();
|
|
5793
|
+
iframeHelper.enableNavigationBlocking();
|
|
5305
5794
|
}
|
|
5306
5795
|
|
|
5307
5796
|
const CANVAS_ID = 'clarity-heatmap-canvas';
|
|
@@ -5551,36 +6040,67 @@ class GXVisualizer extends Visualizer {
|
|
|
5551
6040
|
};
|
|
5552
6041
|
}
|
|
5553
6042
|
|
|
6043
|
+
// ── Performance timing ────────────────────────────────────────────────────────
|
|
6044
|
+
function mark(label) {
|
|
6045
|
+
const t = performance.now();
|
|
6046
|
+
console.log(`[Render] ⏱ ${label}`);
|
|
6047
|
+
return t;
|
|
6048
|
+
}
|
|
6049
|
+
function measure(label, startMs) {
|
|
6050
|
+
const ms = (performance.now() - startMs).toFixed(1);
|
|
6051
|
+
console.log(`[Render] ✅ ${label} — ${ms}ms`);
|
|
6052
|
+
}
|
|
6053
|
+
// ── Hook ──────────────────────────────────────────────────────────────────────
|
|
5554
6054
|
const useHeatmapRender = () => {
|
|
5555
6055
|
const viewId = useViewIdContext();
|
|
5556
6056
|
const data = useHeatmapDataContext((s) => s.data);
|
|
5557
6057
|
const vizRef = useHeatmapVizRectContext((s) => s.vizRef);
|
|
5558
6058
|
const setVizRef = useHeatmapVizRectContext((s) => s.setVizRef);
|
|
5559
6059
|
const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
|
|
5560
|
-
const
|
|
6060
|
+
const setIsRenderedViz = useHeatmapVizContext((s) => s.setIsRenderedViz);
|
|
5561
6061
|
const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
|
|
5562
6062
|
const contentWidth = useHeatmapWidthByDevice();
|
|
5563
6063
|
const deviceType = useHeatmapSettingContext((s) => s.deviceType);
|
|
5564
6064
|
const iframeRef = useRef(null);
|
|
6065
|
+
const helperRef = useRef(null);
|
|
6066
|
+
const abortRef = useRef(null);
|
|
5565
6067
|
const renderHeatmap = useCallback(async (payloads) => {
|
|
5566
6068
|
if (contentWidth === 0 || wrapperHeight === 0)
|
|
5567
6069
|
return;
|
|
5568
6070
|
if (!payloads || payloads.length === 0)
|
|
5569
6071
|
return;
|
|
6072
|
+
// Cancel any in-flight render before starting a new one
|
|
6073
|
+
abortRef.current?.abort();
|
|
6074
|
+
const abort = new AbortController();
|
|
6075
|
+
abortRef.current = abort;
|
|
6076
|
+
const t0 = mark('renderHeatmap start');
|
|
5570
6077
|
const visualizer = vizRef ?? new GXVisualizer();
|
|
5571
6078
|
if (!vizRef)
|
|
5572
6079
|
setVizRef(visualizer);
|
|
5573
|
-
|
|
6080
|
+
setIsRenderedViz(false);
|
|
5574
6081
|
const iframe = iframeRef.current;
|
|
5575
6082
|
if (!iframe?.contentWindow)
|
|
5576
6083
|
return;
|
|
6084
|
+
const tHtml = mark('visualizer.html start');
|
|
5577
6085
|
await visualizer.html(payloads, iframe.contentWindow, viewId);
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
6086
|
+
measure('visualizer.html', tHtml);
|
|
6087
|
+
// Bail out if data changed or component unmounted while we were awaiting
|
|
6088
|
+
if (abort.signal.aborted)
|
|
6089
|
+
return;
|
|
6090
|
+
startIframe({
|
|
6091
|
+
helperRef,
|
|
6092
|
+
iframe,
|
|
6093
|
+
deviceType,
|
|
6094
|
+
size: { width: contentWidth, height: wrapperHeight },
|
|
6095
|
+
t0,
|
|
6096
|
+
onSuccess: (height) => {
|
|
6097
|
+
if (abort.signal.aborted)
|
|
6098
|
+
return;
|
|
6099
|
+
if (height)
|
|
6100
|
+
setIframeHeight(height);
|
|
6101
|
+
setIsRenderedViz(true);
|
|
6102
|
+
},
|
|
5582
6103
|
});
|
|
5583
|
-
// setIsRenderViz(true);
|
|
5584
6104
|
}, [wrapperHeight, contentWidth, deviceType]);
|
|
5585
6105
|
useEffect(() => {
|
|
5586
6106
|
if (!data || data.length === 0)
|
|
@@ -5591,33 +6111,46 @@ const useHeatmapRender = () => {
|
|
|
5591
6111
|
setVizRef(null);
|
|
5592
6112
|
};
|
|
5593
6113
|
}, [data, renderHeatmap, setVizRef]);
|
|
6114
|
+
// Abort render + stop helper when the component unmounts
|
|
6115
|
+
useEffect(() => {
|
|
6116
|
+
return () => {
|
|
6117
|
+
abortRef.current?.abort();
|
|
6118
|
+
helperRef.current?.stop();
|
|
6119
|
+
helperRef.current = null;
|
|
6120
|
+
};
|
|
6121
|
+
}, []);
|
|
5594
6122
|
return {
|
|
5595
6123
|
iframeRef,
|
|
5596
6124
|
};
|
|
5597
6125
|
};
|
|
5598
|
-
|
|
6126
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
6127
|
+
function startIframe({ helperRef, iframe, deviceType = EDeviceType.Desktop, size, t0, onSuccess }) {
|
|
5599
6128
|
const docWidth = size.width ?? 0;
|
|
5600
6129
|
const docHeight = size.height ?? 0;
|
|
5601
6130
|
if (docHeight === 0)
|
|
5602
6131
|
return;
|
|
5603
|
-
stop();
|
|
5604
|
-
start
|
|
5605
|
-
|
|
6132
|
+
helperRef.current?.stop();
|
|
6133
|
+
const tHelper = mark('IframeHelper.start');
|
|
6134
|
+
const helper = createIframeHelper();
|
|
6135
|
+
helperRef.current = helper;
|
|
6136
|
+
helper.start({
|
|
6137
|
+
deviceType,
|
|
5606
6138
|
targetWidth: docWidth,
|
|
5607
6139
|
targetHeight: docHeight,
|
|
5608
|
-
iframe
|
|
6140
|
+
iframe,
|
|
5609
6141
|
debug: true,
|
|
5610
6142
|
onSuccess: (data) => {
|
|
6143
|
+
measure('IframeHelper processing', tHelper);
|
|
6144
|
+
measure('Total render', t0);
|
|
5611
6145
|
iframe.style.height = `${data.height}px`;
|
|
5612
6146
|
onSuccess(data.height);
|
|
5613
6147
|
},
|
|
5614
6148
|
});
|
|
5615
|
-
// fixer.recalculate();
|
|
5616
6149
|
}
|
|
5617
6150
|
|
|
5618
6151
|
const useReplayRender = () => {
|
|
5619
6152
|
const data = useHeatmapDataContext((s) => s.data);
|
|
5620
|
-
const
|
|
6153
|
+
const setIsRenderedViz = useHeatmapVizContext((s) => s.setIsRenderedViz);
|
|
5621
6154
|
const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
|
|
5622
6155
|
const visualizerRef = useRef(null);
|
|
5623
6156
|
const iframeRef = useRef(null);
|
|
@@ -5637,7 +6170,7 @@ const useReplayRender = () => {
|
|
|
5637
6170
|
version: envelope.version,
|
|
5638
6171
|
onresize: (height) => {
|
|
5639
6172
|
height && setIframeHeight(height);
|
|
5640
|
-
|
|
6173
|
+
setIsRenderedViz(true);
|
|
5641
6174
|
},
|
|
5642
6175
|
mobile,
|
|
5643
6176
|
vNext: true,
|
|
@@ -5793,7 +6326,7 @@ const useContentDimensions = ({ iframeRef }) => {
|
|
|
5793
6326
|
const useObserveIframeHeight = (props) => {
|
|
5794
6327
|
const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
|
|
5795
6328
|
const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
|
|
5796
|
-
const
|
|
6329
|
+
const isRenderedViz = useHeatmapVizContext((s) => s.isRenderedViz);
|
|
5797
6330
|
const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
|
|
5798
6331
|
const { iframeRef } = props;
|
|
5799
6332
|
const resizeObserverRef = useRef(null);
|
|
@@ -5854,7 +6387,7 @@ const useObserveIframeHeight = (props) => {
|
|
|
5854
6387
|
}, [updateIframeHeight]);
|
|
5855
6388
|
useEffect(() => {
|
|
5856
6389
|
const iframe = iframeRef.current;
|
|
5857
|
-
if (!iframe || !iframeHeight || !
|
|
6390
|
+
if (!iframe || !iframeHeight || !isRenderedViz)
|
|
5858
6391
|
return;
|
|
5859
6392
|
const setupObservers = () => {
|
|
5860
6393
|
try {
|
|
@@ -5916,7 +6449,7 @@ const useObserveIframeHeight = (props) => {
|
|
|
5916
6449
|
}
|
|
5917
6450
|
iframe.removeEventListener('load', setupObservers);
|
|
5918
6451
|
};
|
|
5919
|
-
}, [iframeRef, iframeHeight,
|
|
6452
|
+
}, [iframeRef, iframeHeight, isRenderedViz]);
|
|
5920
6453
|
return {};
|
|
5921
6454
|
};
|
|
5922
6455
|
|
|
@@ -6215,10 +6748,10 @@ const useScrollmapZones = (options) => {
|
|
|
6215
6748
|
const newZones = createZones(scrollmap);
|
|
6216
6749
|
setZones(newZones);
|
|
6217
6750
|
setIsReady(true);
|
|
6218
|
-
logger$
|
|
6751
|
+
logger$4.log(`[useScrollmap] Created ${newZones.length} zones in ${mode} mode`);
|
|
6219
6752
|
}
|
|
6220
6753
|
catch (error) {
|
|
6221
|
-
logger$
|
|
6754
|
+
logger$4.error('[useScrollmap] Error:', error);
|
|
6222
6755
|
setIsReady(false);
|
|
6223
6756
|
}
|
|
6224
6757
|
}, [enabled, scrollmap, mode, createZones]);
|
|
@@ -7048,11 +7581,11 @@ const AutoScrollHandler = ({ visualRef }) => {
|
|
|
7048
7581
|
};
|
|
7049
7582
|
|
|
7050
7583
|
const PortalAreaRenderer = ({ iframeRef, visualRef, shadowRoot, onAreaCreated, onAreaClick, }) => {
|
|
7051
|
-
const
|
|
7584
|
+
const isRenderedViz = useHeatmapVizContext((s) => s.isRenderedViz);
|
|
7052
7585
|
const iframeDocument = iframeRef.current?.contentDocument || undefined;
|
|
7053
7586
|
const { shadowContainer, isReady } = useAreaRendererContainer(iframeDocument, shadowRoot);
|
|
7054
|
-
useAreaRectSync({ iframeDocument, shadowRoot, enabled: isReady &&
|
|
7055
|
-
useAreaPositionsUpdater({ iframeRef, visualRef, enabled: isReady &&
|
|
7587
|
+
useAreaRectSync({ iframeDocument, shadowRoot, enabled: isReady && isRenderedViz });
|
|
7588
|
+
useAreaPositionsUpdater({ iframeRef, visualRef, enabled: isReady && isRenderedViz });
|
|
7056
7589
|
if (!shadowContainer || !isReady)
|
|
7057
7590
|
return null;
|
|
7058
7591
|
return (jsxs(Fragment$1, { children: [jsx(AutoScrollHandler, { visualRef: visualRef }), jsx(AreasPortal, { shadowContainer: shadowContainer, onAreaClick: onAreaClick }), jsx(AreaEditHighlightPortal, { shadowContainer: shadowContainer, iframeRef: iframeRef, customShadowRoot: shadowRoot, onAreaCreated: onAreaCreated })] }));
|
|
@@ -7061,7 +7594,7 @@ const PortalAreaRenderer = ({ iframeRef, visualRef, shadowRoot, onAreaCreated, o
|
|
|
7061
7594
|
const VizAreaClick = ({ iframeRef, visualRef, shadowRoot, autoCreateTopN = 10, enableOverlapResolution = true, onAreaClick, }) => {
|
|
7062
7595
|
const clickAreas = useHeatmapDataContext((s) => s.clickAreas);
|
|
7063
7596
|
const resetView = useHeatmapAreaClickContext((s) => s.resetView);
|
|
7064
|
-
const
|
|
7597
|
+
const isRenderedViz = useHeatmapVizContext((s) => s.isRenderedViz);
|
|
7065
7598
|
useAreaTopAutoDetect({ autoCreateTopN, shadowRoot, disabled: !!clickAreas?.length });
|
|
7066
7599
|
useAreaFilterVisible({ iframeRef, enableOverlapResolution });
|
|
7067
7600
|
useAreaHydration({ shadowRoot });
|
|
@@ -7070,7 +7603,7 @@ const VizAreaClick = ({ iframeRef, visualRef, shadowRoot, autoCreateTopN = 10, e
|
|
|
7070
7603
|
resetView();
|
|
7071
7604
|
};
|
|
7072
7605
|
}, []);
|
|
7073
|
-
if (!iframeRef.current || !
|
|
7606
|
+
if (!iframeRef.current || !isRenderedViz)
|
|
7074
7607
|
return null;
|
|
7075
7608
|
return (jsx(Fragment, { children: jsx(PortalAreaRenderer, { iframeRef: iframeRef, visualRef: visualRef, shadowRoot: shadowRoot, onAreaClick: onAreaClick }) }));
|
|
7076
7609
|
};
|
|
@@ -7784,7 +8317,7 @@ const VizDomHeatmap = () => {
|
|
|
7784
8317
|
const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
|
|
7785
8318
|
const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
|
|
7786
8319
|
const setVizRef = useHeatmapVizRectContext((s) => s.setVizRef);
|
|
7787
|
-
const
|
|
8320
|
+
const setIsRenderedViz = useHeatmapVizContext((s) => s.setIsRenderedViz);
|
|
7788
8321
|
const setSelectedElement = useHeatmapClickContext((s) => s.setSelectedElement);
|
|
7789
8322
|
const setHoveredElement = useHeatmapHoverContext((s) => s.setHoveredElement);
|
|
7790
8323
|
// const setSelectedArea = useHeatmapAreaClickContext((s) => s.setSelectedArea);
|
|
@@ -7794,7 +8327,7 @@ const VizDomHeatmap = () => {
|
|
|
7794
8327
|
const cleanUp = () => {
|
|
7795
8328
|
setVizRef(null);
|
|
7796
8329
|
setIframeHeight(0);
|
|
7797
|
-
|
|
8330
|
+
setIsRenderedViz(false);
|
|
7798
8331
|
setSelectedElement(null);
|
|
7799
8332
|
setHoveredElement(null);
|
|
7800
8333
|
// setSelectedArea(null);
|
|
@@ -7826,7 +8359,7 @@ const VizLiveRenderer = () => {
|
|
|
7826
8359
|
const VizLiveHeatmap = () => {
|
|
7827
8360
|
const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
|
|
7828
8361
|
const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
|
|
7829
|
-
|
|
8362
|
+
useHeatmapLiveContext((s) => s.reset);
|
|
7830
8363
|
const CompVizLoading = useHeatmapControlStore((state) => state.controls.VizLoading);
|
|
7831
8364
|
// TODO: Remove this after testing
|
|
7832
8365
|
useEffect(() => {
|
|
@@ -7911,4 +8444,4 @@ const HeatmapLayout = ({ data, clickmap, clickAreas, scrollmap, attentionMap, co
|
|
|
7911
8444
|
}
|
|
7912
8445
|
};
|
|
7913
8446
|
|
|
7914
|
-
export { BACKDROP_CONFIG, DEFAULT_SIDEBAR_WIDTH, DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO, EClickMode, EClickRankType, EClickType, EDeviceType, EHeatmapMode, EHeatmapType, ELM_CALLOUT_CONFIG, EScrollType, GraphView, HEATMAP_CONFIG, HEATMAP_IFRAME, HEATMAP_STYLE, HeatmapLayout, ViewIdContext, Z_INDEX$1 as Z_INDEX, compareViewPerformance, convertViewportToIframeCoords, createStorePerformanceTracker, createViewContextHook, decodeArrayClarity, decodeClarity, downloadPerformanceReport, getCompareViewId, getMetricsByViewId, getPerformanceReportJSON, getScrollGradientColor, performanceLogger, printPerformanceSummary, scrollToElementIfNeeded, sendPerformanceReport, serializeAreas, trackStoreAction, useAreaCreation, useAreaEditMode, useAreaFilterVisible, useAreaHydration, useAreaInteraction, useAreaPositionsUpdater, useAreaRectSync, useAreaRendererContainer, useAreaTopAutoDetect, useClickedElement, useDebounceCallback, useElementCalloutVisible, useHeatmapAreaClickContext, useHeatmapCanvas, useHeatmapClickContext, useHeatmapCompareStore, useHeatmapConfigStore, useHeatmapCopyView, useHeatmapDataContext, useHeatmapEffects, useHeatmapElementPosition, useHeatmapHoverContext,
|
|
8447
|
+
export { BACKDROP_CONFIG, DEFAULT_SIDEBAR_WIDTH, DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO, EClickMode, EClickRankType, EClickType, EDeviceType, EHeatmapDataSource, EHeatmapMode, EHeatmapType, ELM_CALLOUT_CONFIG, EScrollType, GraphView, HEATMAP_CONFIG, HEATMAP_IFRAME, HEATMAP_STYLE, HeatmapLayout, ViewIdContext, Z_INDEX$1 as Z_INDEX, compareViewPerformance, convertViewportToIframeCoords, createStorePerformanceTracker, createViewContextHook, decodeArrayClarity, decodeClarity, downloadPerformanceReport, getCompareViewId, getMetricsByViewId, getPerformanceReportJSON, getScrollGradientColor, performanceLogger, printPerformanceSummary, scrollToElementIfNeeded, sendPerformanceReport, serializeAreas, trackStoreAction, useAreaCreation, useAreaEditMode, useAreaFilterVisible, useAreaHydration, useAreaInteraction, useAreaPositionsUpdater, useAreaRectSync, useAreaRendererContainer, useAreaTopAutoDetect, useClickedElement, useDebounceCallback, useElementCalloutVisible, useHeatmapAreaClickContext, useHeatmapCanvas, useHeatmapClickContext, useHeatmapCompareStore, useHeatmapConfigStore, useHeatmapCopyView, useHeatmapDataContext, useHeatmapEffects, useHeatmapElementPosition, useHeatmapHoverContext, useHeatmapLiveContext, useHeatmapRenderByMode, useHeatmapScale, useHeatmapScroll, useHeatmapScrollContext, useHeatmapSettingContext, useHeatmapVizContext, useHeatmapVizRectContext, useHeatmapWidthByDevice, useHoveredElement, useMeasureFunction, useRegisterConfig, useRegisterControl, useRegisterData, useRegisterHeatmap, useRenderCount, useScrollmapZones, useTrackHookCall, useViewIdContext, useVizLiveRender, useWhyDidYouUpdate, useWrapperRefHeight, useZonePositions, withPerformanceTracking };
|