@gemx-dev/heatmap-react 3.5.92-dev.2 → 3.5.92-dev.20
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/Layout/HeatmapLayout.d.ts +2 -0
- package/dist/esm/components/Layout/HeatmapLayout.d.ts.map +1 -1
- package/dist/esm/components/VizDom/VizDomHeatmap.d.ts.map +1 -1
- package/dist/esm/components/VizDom/VizDomRenderer.d.ts +2 -1
- package/dist/esm/components/VizDom/VizDomRenderer.d.ts.map +1 -1
- package/dist/esm/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
- package/dist/esm/hooks/common/index.d.ts +1 -1
- package/dist/esm/hooks/common/index.d.ts.map +1 -1
- package/dist/esm/hooks/common/useHeatmapViewportByDevice.d.ts +7 -0
- package/dist/esm/hooks/common/useHeatmapViewportByDevice.d.ts.map +1 -0
- package/dist/esm/hooks/register/useRegisterConfig.d.ts +3 -1
- package/dist/esm/hooks/register/useRegisterConfig.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 +4 -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/viz-canvas/useClickmap.d.ts.map +1 -1
- package/dist/esm/hooks/viz-canvas/useScrollmap.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/useHeatmapIframeProcessor.d.ts +6 -0
- package/dist/esm/hooks/viz-render/useHeatmapIframeProcessor.d.ts.map +1 -0
- package/dist/esm/hooks/viz-render/useHeatmapRenderByMode.d.ts +3 -2
- package/dist/esm/hooks/viz-render/useHeatmapRenderByMode.d.ts.map +1 -1
- package/dist/esm/hooks/viz-render/useHeatmapRenderDom.d.ts +5 -0
- package/dist/esm/hooks/viz-render/useHeatmapRenderDom.d.ts.map +1 -0
- package/dist/esm/hooks/viz-render/useReplayRender.d.ts +2 -2
- package/dist/esm/hooks/viz-render/useReplayRender.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useScaleCalculation.d.ts +1 -2
- package/dist/esm/hooks/viz-scale/useScaleCalculation.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 +1823 -876
- package/dist/esm/index.mjs +1823 -876
- 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/index.d.ts +0 -1
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/index.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/index.d.ts +1 -0
- package/dist/esm/libs/index.d.ts.map +1 -1
- package/dist/esm/libs/perf.d.ts +83 -0
- package/dist/esm/libs/perf.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/GXVisualizer.d.ts +12 -4
- package/dist/esm/libs/visualizer/GXVisualizer.d.ts.map +1 -1
- package/dist/esm/libs/visualizer/cache/config.d.ts +15 -0
- package/dist/esm/libs/visualizer/cache/config.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/cache/index.d.ts +16 -0
- package/dist/esm/libs/visualizer/cache/index.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/index.d.ts +1 -2
- package/dist/esm/libs/visualizer/index.d.ts.map +1 -1
- package/dist/{umd/libs/visualizer → esm/libs/visualizer/renderers}/AttentionMapRenderer.d.ts +1 -1
- package/dist/esm/libs/visualizer/renderers/AttentionMapRenderer.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/{ClickHeatmapRenderer.d.ts → renderers/ClickHeatmapRenderer.d.ts} +1 -1
- package/dist/esm/libs/visualizer/renderers/ClickHeatmapRenderer.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/renderers/index.d.ts +3 -0
- package/dist/esm/libs/visualizer/renderers/index.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/shadow-dom/extractor.d.ts +23 -0
- package/dist/esm/libs/visualizer/shadow-dom/extractor.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/types/data.d.ts +72 -0
- package/dist/esm/libs/visualizer/types/data.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/{types.d.ts → types/extend.d.ts} +7 -2
- package/dist/esm/libs/visualizer/types/extend.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/types/index.d.ts +6 -0
- package/dist/esm/libs/visualizer/types/index.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/types/layout.d.ts +69 -0
- package/dist/esm/libs/visualizer/types/layout.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/types/visualize.d.ts +26 -0
- package/dist/esm/libs/visualizer/types/visualize.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/utils/delay.d.ts +21 -0
- package/dist/esm/libs/visualizer/utils/delay.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/utils/render.d.ts +7 -0
- package/dist/esm/libs/visualizer/utils/render.d.ts.map +1 -0
- package/dist/esm/stores/config.d.ts +4 -2
- package/dist/esm/stores/config.d.ts.map +1 -1
- package/dist/esm/stores/data.d.ts +4 -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/types/heatmap-info.d.ts +1 -0
- package/dist/esm/types/heatmap-info.d.ts.map +1 -1
- package/dist/esm/types/heatmap.d.ts +9 -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/Layout/HeatmapLayout.d.ts +2 -0
- package/dist/umd/components/Layout/HeatmapLayout.d.ts.map +1 -1
- package/dist/umd/components/VizDom/VizDomHeatmap.d.ts.map +1 -1
- package/dist/umd/components/VizDom/VizDomRenderer.d.ts +2 -1
- package/dist/umd/components/VizDom/VizDomRenderer.d.ts.map +1 -1
- package/dist/umd/components/VizLive/VizLiveHeatmap.d.ts.map +1 -1
- package/dist/umd/hooks/common/index.d.ts +1 -1
- package/dist/umd/hooks/common/index.d.ts.map +1 -1
- package/dist/umd/hooks/common/useHeatmapViewportByDevice.d.ts +7 -0
- package/dist/umd/hooks/common/useHeatmapViewportByDevice.d.ts.map +1 -0
- package/dist/umd/hooks/register/useRegisterConfig.d.ts +3 -1
- package/dist/umd/hooks/register/useRegisterConfig.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 +4 -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/viz-canvas/useClickmap.d.ts.map +1 -1
- package/dist/umd/hooks/viz-canvas/useScrollmap.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/useHeatmapIframeProcessor.d.ts +6 -0
- package/dist/umd/hooks/viz-render/useHeatmapIframeProcessor.d.ts.map +1 -0
- package/dist/umd/hooks/viz-render/useHeatmapRenderByMode.d.ts +3 -2
- package/dist/umd/hooks/viz-render/useHeatmapRenderByMode.d.ts.map +1 -1
- package/dist/umd/hooks/viz-render/useHeatmapRenderDom.d.ts +5 -0
- package/dist/umd/hooks/viz-render/useHeatmapRenderDom.d.ts.map +1 -0
- package/dist/umd/hooks/viz-render/useReplayRender.d.ts +2 -2
- package/dist/umd/hooks/viz-render/useReplayRender.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useScaleCalculation.d.ts +1 -2
- package/dist/umd/hooks/viz-scale/useScaleCalculation.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/index.d.ts +0 -1
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/index.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/index.d.ts +1 -0
- package/dist/umd/libs/index.d.ts.map +1 -1
- package/dist/umd/libs/perf.d.ts +83 -0
- package/dist/umd/libs/perf.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/GXVisualizer.d.ts +12 -4
- package/dist/umd/libs/visualizer/GXVisualizer.d.ts.map +1 -1
- package/dist/umd/libs/visualizer/cache/config.d.ts +15 -0
- package/dist/umd/libs/visualizer/cache/config.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/cache/index.d.ts +16 -0
- package/dist/umd/libs/visualizer/cache/index.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/index.d.ts +1 -2
- package/dist/umd/libs/visualizer/index.d.ts.map +1 -1
- package/dist/{esm/libs/visualizer → umd/libs/visualizer/renderers}/AttentionMapRenderer.d.ts +1 -1
- package/dist/umd/libs/visualizer/renderers/AttentionMapRenderer.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/{ClickHeatmapRenderer.d.ts → renderers/ClickHeatmapRenderer.d.ts} +1 -1
- package/dist/umd/libs/visualizer/renderers/ClickHeatmapRenderer.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/renderers/index.d.ts +3 -0
- package/dist/umd/libs/visualizer/renderers/index.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/shadow-dom/extractor.d.ts +23 -0
- package/dist/umd/libs/visualizer/shadow-dom/extractor.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/types/data.d.ts +72 -0
- package/dist/umd/libs/visualizer/types/data.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/{types.d.ts → types/extend.d.ts} +7 -2
- package/dist/umd/libs/visualizer/types/extend.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/types/index.d.ts +6 -0
- package/dist/umd/libs/visualizer/types/index.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/types/layout.d.ts +69 -0
- package/dist/umd/libs/visualizer/types/layout.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/types/visualize.d.ts +26 -0
- package/dist/umd/libs/visualizer/types/visualize.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/utils/delay.d.ts +21 -0
- package/dist/umd/libs/visualizer/utils/delay.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/utils/render.d.ts +7 -0
- package/dist/umd/libs/visualizer/utils/render.d.ts.map +1 -0
- package/dist/umd/stores/config.d.ts +4 -2
- package/dist/umd/stores/config.d.ts.map +1 -1
- package/dist/umd/stores/data.d.ts +4 -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/types/heatmap-info.d.ts +1 -0
- package/dist/umd/types/heatmap-info.d.ts.map +1 -1
- package/dist/umd/types/heatmap.d.ts +9 -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 +4 -4
- package/dist/esm/hooks/common/useHeatmapWidthByDevice.d.ts +0 -2
- package/dist/esm/hooks/common/useHeatmapWidthByDevice.d.ts.map +0 -1
- package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts +0 -6
- package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts.map +0 -1
- package/dist/esm/hooks/viz-scale/useContentDimensions.d.ts +0 -9
- package/dist/esm/hooks/viz-scale/useContentDimensions.d.ts.map +0 -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/esm/libs/visualizer/AttentionMapRenderer.d.ts.map +0 -1
- package/dist/esm/libs/visualizer/ClickHeatmapRenderer.d.ts.map +0 -1
- package/dist/esm/libs/visualizer/ScrollHeatmapRenderer.d.ts +0 -17
- package/dist/esm/libs/visualizer/ScrollHeatmapRenderer.d.ts.map +0 -1
- package/dist/esm/libs/visualizer/types.d.ts.map +0 -1
- package/dist/umd/hooks/common/useHeatmapWidthByDevice.d.ts +0 -2
- package/dist/umd/hooks/common/useHeatmapWidthByDevice.d.ts.map +0 -1
- package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts +0 -6
- package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts.map +0 -1
- package/dist/umd/hooks/viz-scale/useContentDimensions.d.ts +0 -9
- package/dist/umd/hooks/viz-scale/useContentDimensions.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/umd/libs/visualizer/AttentionMapRenderer.d.ts.map +0 -1
- package/dist/umd/libs/visualizer/ClickHeatmapRenderer.d.ts.map +0 -1
- package/dist/umd/libs/visualizer/ScrollHeatmapRenderer.d.ts +0 -17
- package/dist/umd/libs/visualizer/ScrollHeatmapRenderer.d.ts.map +0 -1
- package/dist/umd/libs/visualizer/types.d.ts.map +0 -1
package/dist/esm/index.js
CHANGED
|
@@ -152,6 +152,7 @@ function useDebounceCallback(callback, delay) {
|
|
|
152
152
|
|
|
153
153
|
var EDeviceType;
|
|
154
154
|
(function (EDeviceType) {
|
|
155
|
+
EDeviceType["DesktopLarge"] = "DESKTOP_LARGE";
|
|
155
156
|
EDeviceType["Desktop"] = "DESKTOP";
|
|
156
157
|
EDeviceType["Mobile"] = "MOBILE";
|
|
157
158
|
EDeviceType["Tablet"] = "TABLET";
|
|
@@ -161,6 +162,11 @@ var EHeatmapType;
|
|
|
161
162
|
EHeatmapType["Click"] = "click";
|
|
162
163
|
EHeatmapType["Scroll"] = "scroll";
|
|
163
164
|
})(EHeatmapType || (EHeatmapType = {}));
|
|
165
|
+
var EHeatmapMode;
|
|
166
|
+
(function (EHeatmapMode) {
|
|
167
|
+
EHeatmapMode["Heatmap"] = "heatmap";
|
|
168
|
+
EHeatmapMode["Replay"] = "replay";
|
|
169
|
+
})(EHeatmapMode || (EHeatmapMode = {}));
|
|
164
170
|
var EClickType;
|
|
165
171
|
(function (EClickType) {
|
|
166
172
|
/** Return all clicks (default) */
|
|
@@ -197,12 +203,16 @@ var EScrollType;
|
|
|
197
203
|
EScrollType["Attention"] = "ATTENTION";
|
|
198
204
|
EScrollType["Revenue"] = "REVENUE";
|
|
199
205
|
})(EScrollType || (EScrollType = {}));
|
|
200
|
-
var EHeatmapMode;
|
|
201
206
|
(function (EHeatmapMode) {
|
|
202
207
|
EHeatmapMode["Single"] = "single";
|
|
203
208
|
EHeatmapMode["Live"] = "live";
|
|
204
209
|
EHeatmapMode["Compare"] = "compare";
|
|
205
210
|
})(EHeatmapMode || (EHeatmapMode = {}));
|
|
211
|
+
var EHeatmapDataSource;
|
|
212
|
+
(function (EHeatmapDataSource) {
|
|
213
|
+
EHeatmapDataSource["Snapshot"] = "snapshot";
|
|
214
|
+
EHeatmapDataSource["Live"] = "live";
|
|
215
|
+
})(EHeatmapDataSource || (EHeatmapDataSource = {}));
|
|
206
216
|
|
|
207
217
|
const ViewIdContext = createContext(undefined);
|
|
208
218
|
const useViewIdContext = () => {
|
|
@@ -314,18 +324,21 @@ const useHeatmapConfigStore = create()((set) => {
|
|
|
314
324
|
return {
|
|
315
325
|
mode: EHeatmapMode.Single,
|
|
316
326
|
sidebarWidth: DEFAULT_SIDEBAR_WIDTH,
|
|
317
|
-
|
|
318
|
-
|
|
327
|
+
shopId: undefined,
|
|
328
|
+
excludeClassNames: [],
|
|
319
329
|
setMode: (mode) => set({ mode }),
|
|
320
330
|
resetMode: () => set({ mode: EHeatmapMode.Single }),
|
|
321
331
|
setSidebarWidth: (sidebarWidth) => set({ sidebarWidth }),
|
|
322
|
-
|
|
332
|
+
setShopId: (shopId) => set({ shopId }),
|
|
333
|
+
setExcludeClassNames: (excludeClassNames) => set({ excludeClassNames }),
|
|
323
334
|
};
|
|
324
335
|
});
|
|
325
336
|
|
|
326
337
|
const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
|
|
327
338
|
return {
|
|
328
339
|
data: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
340
|
+
dataHash: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
341
|
+
dataSnapshot: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
329
342
|
clickmap: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
330
343
|
clickAreas: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
331
344
|
dataInfo: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
@@ -358,6 +371,16 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
|
|
|
358
371
|
newData.set(viewId, data);
|
|
359
372
|
return { data: newData };
|
|
360
373
|
}),
|
|
374
|
+
setDataHash: (dataHash, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
375
|
+
const newDataHash = new Map(prev.dataHash);
|
|
376
|
+
newDataHash.set(viewId, dataHash);
|
|
377
|
+
return { dataHash: newDataHash };
|
|
378
|
+
}),
|
|
379
|
+
setDataSnapshot: (data, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
380
|
+
const newDataSnapshot = new Map(prev.dataSnapshot);
|
|
381
|
+
newDataSnapshot.set(viewId, data);
|
|
382
|
+
return { dataSnapshot: newDataSnapshot };
|
|
383
|
+
}),
|
|
361
384
|
setClickmap: (clickmap, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
362
385
|
const newClickmap = new Map(prev.clickmap);
|
|
363
386
|
newClickmap.set(viewId, clickmap);
|
|
@@ -380,12 +403,16 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
|
|
|
380
403
|
}),
|
|
381
404
|
copyView: (fromViewId, toViewId) => set((prev) => {
|
|
382
405
|
const newData = new Map(prev.data);
|
|
406
|
+
const newDataSnapshot = new Map(prev.dataSnapshot);
|
|
383
407
|
const newClickmap = new Map(prev.clickmap);
|
|
384
408
|
const newClickAreas = new Map(prev.clickAreas);
|
|
385
409
|
const newDataInfo = new Map(prev.dataInfo);
|
|
386
410
|
const newScrollmap = new Map(prev.scrollmap);
|
|
387
411
|
const newAttentionMap = new Map(prev.attentionMap);
|
|
412
|
+
const newDataHash = new Map(prev.dataHash);
|
|
388
413
|
newData.set(toViewId, prev.data.get(fromViewId));
|
|
414
|
+
newDataSnapshot.set(toViewId, prev.dataSnapshot.get(fromViewId));
|
|
415
|
+
newDataHash.set(toViewId, prev.dataHash.get(fromViewId));
|
|
389
416
|
newClickmap.set(toViewId, prev.clickmap.get(fromViewId));
|
|
390
417
|
newClickAreas.set(toViewId, prev.clickAreas.get(fromViewId));
|
|
391
418
|
newDataInfo.set(toViewId, prev.dataInfo.get(fromViewId));
|
|
@@ -393,21 +420,27 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
|
|
|
393
420
|
newAttentionMap.set(toViewId, prev.attentionMap.get(fromViewId));
|
|
394
421
|
return {
|
|
395
422
|
data: newData,
|
|
423
|
+
dataSnapshot: newDataSnapshot,
|
|
396
424
|
clickmap: newClickmap,
|
|
397
425
|
clickAreas: newClickAreas,
|
|
398
426
|
dataInfo: newDataInfo,
|
|
399
427
|
scrollmap: newScrollmap,
|
|
400
428
|
attentionMap: newAttentionMap,
|
|
429
|
+
dataHash: newDataHash,
|
|
401
430
|
};
|
|
402
431
|
}),
|
|
403
432
|
clearView: (viewId) => set((prev) => {
|
|
404
433
|
const newData = new Map(prev.data);
|
|
434
|
+
const newDataSnapshot = new Map(prev.dataSnapshot);
|
|
405
435
|
const newClickmap = new Map(prev.clickmap);
|
|
406
436
|
const newClickAreas = new Map(prev.clickAreas);
|
|
407
437
|
const newDataInfo = new Map(prev.dataInfo);
|
|
408
438
|
const newScrollmap = new Map(prev.scrollmap);
|
|
409
439
|
const newAttentionMap = new Map(prev.attentionMap);
|
|
440
|
+
const newDataHash = new Map(prev.dataHash);
|
|
410
441
|
newData.delete(viewId);
|
|
442
|
+
newDataSnapshot.delete(viewId);
|
|
443
|
+
newDataHash.delete(viewId);
|
|
411
444
|
newClickmap.delete(viewId);
|
|
412
445
|
newClickAreas.delete(viewId);
|
|
413
446
|
newDataInfo.delete(viewId);
|
|
@@ -415,6 +448,8 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
|
|
|
415
448
|
newAttentionMap.delete(viewId);
|
|
416
449
|
return {
|
|
417
450
|
data: newData,
|
|
451
|
+
dataSnapshot: newDataSnapshot,
|
|
452
|
+
dataHash: newDataHash,
|
|
418
453
|
clickmap: newClickmap,
|
|
419
454
|
clickAreas: newClickAreas,
|
|
420
455
|
dataInfo: newDataInfo,
|
|
@@ -424,6 +459,8 @@ const useHeatmapDataStore = create()(subscribeWithSelector((set) => {
|
|
|
424
459
|
}),
|
|
425
460
|
resetAll: () => set({
|
|
426
461
|
data: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
462
|
+
dataSnapshot: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
463
|
+
dataHash: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
427
464
|
clickmap: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
428
465
|
clickAreas: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
429
466
|
dataInfo: new Map([[DEFAULT_VIEW_ID, undefined]]),
|
|
@@ -445,6 +482,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
445
482
|
clickMode: new Map([[DEFAULT_VIEW_ID, EClickMode.Default]]),
|
|
446
483
|
scrollType: new Map([[DEFAULT_VIEW_ID, EScrollType.Depth]]),
|
|
447
484
|
heatmapType: new Map([[DEFAULT_VIEW_ID, EHeatmapType.Click]]),
|
|
485
|
+
dataSource: new Map([[DEFAULT_VIEW_ID, EHeatmapDataSource.Snapshot]]),
|
|
448
486
|
setIsRendering: (isRendering, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
449
487
|
const newIsRendering = new Map(prev.isRendering);
|
|
450
488
|
newIsRendering.set(viewId, isRendering);
|
|
@@ -495,6 +533,11 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
495
533
|
newHeatmapType.set(viewId, heatmapType);
|
|
496
534
|
return { heatmapType: newHeatmapType };
|
|
497
535
|
}),
|
|
536
|
+
setDataSource: (dataSource, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
537
|
+
const newDataSource = new Map(prev.dataSource);
|
|
538
|
+
newDataSource.set(viewId, dataSource);
|
|
539
|
+
return { dataSource: newDataSource };
|
|
540
|
+
}),
|
|
498
541
|
copyView: (fromViewId, toViewId) => set((prev) => {
|
|
499
542
|
const newIsLoadingDom = new Map(prev.isLoadingDom);
|
|
500
543
|
const newIsLoadingCanvas = new Map(prev.isLoadingCanvas);
|
|
@@ -505,6 +548,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
505
548
|
const newClickMode = new Map(prev.clickMode);
|
|
506
549
|
const newScrollType = new Map(prev.scrollType);
|
|
507
550
|
const newHeatmapType = new Map(prev.heatmapType);
|
|
551
|
+
const newDataSource = new Map(prev.dataSource);
|
|
508
552
|
newIsShowSidebar.set(toViewId, prev.isShowSidebar.get(fromViewId) ?? false);
|
|
509
553
|
newRankedBy.set(toViewId, prev.rankedBy.get(fromViewId));
|
|
510
554
|
newDeviceType.set(toViewId, prev.deviceType.get(fromViewId));
|
|
@@ -514,6 +558,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
514
558
|
newHeatmapType.set(toViewId, prev.heatmapType.get(fromViewId));
|
|
515
559
|
newIsLoadingDom.set(toViewId, prev.isLoadingDom.get(fromViewId) ?? false);
|
|
516
560
|
newIsLoadingCanvas.set(toViewId, prev.isLoadingCanvas.get(fromViewId) ?? false);
|
|
561
|
+
newDataSource.set(toViewId, prev.dataSource.get(fromViewId) ?? EHeatmapDataSource.Snapshot);
|
|
517
562
|
return {
|
|
518
563
|
isShowSidebar: newIsShowSidebar,
|
|
519
564
|
rankedBy: newRankedBy,
|
|
@@ -524,6 +569,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
524
569
|
clickMode: newClickMode,
|
|
525
570
|
scrollType: newScrollType,
|
|
526
571
|
heatmapType: newHeatmapType,
|
|
572
|
+
dataSource: newDataSource,
|
|
527
573
|
};
|
|
528
574
|
}),
|
|
529
575
|
clearView: (viewId) => set((prev) => {
|
|
@@ -536,6 +582,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
536
582
|
const newClickMode = new Map(prev.clickMode);
|
|
537
583
|
const newScrollType = new Map(prev.scrollType);
|
|
538
584
|
const newHeatmapType = new Map(prev.heatmapType);
|
|
585
|
+
const newDataSource = new Map(prev.dataSource);
|
|
539
586
|
newIsShowSidebar.delete(viewId);
|
|
540
587
|
newRankedBy.delete(viewId);
|
|
541
588
|
newIsLoadingDom.delete(viewId);
|
|
@@ -545,6 +592,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
545
592
|
newClickMode.delete(viewId);
|
|
546
593
|
newScrollType.delete(viewId);
|
|
547
594
|
newHeatmapType.delete(viewId);
|
|
595
|
+
newDataSource.delete(viewId);
|
|
548
596
|
return {
|
|
549
597
|
isShowSidebar: newIsShowSidebar,
|
|
550
598
|
rankedBy: newRankedBy,
|
|
@@ -555,6 +603,7 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
555
603
|
clickMode: newClickMode,
|
|
556
604
|
scrollType: newScrollType,
|
|
557
605
|
heatmapType: newHeatmapType,
|
|
606
|
+
dataSource: newDataSource,
|
|
558
607
|
};
|
|
559
608
|
}),
|
|
560
609
|
resetAll: () => set({
|
|
@@ -568,22 +617,23 @@ const useHeatmapSettingStore = create()(subscribeWithSelector((set) => {
|
|
|
568
617
|
clickMode: new Map([[DEFAULT_VIEW_ID, EClickMode.Default]]),
|
|
569
618
|
scrollType: new Map([[DEFAULT_VIEW_ID, EScrollType.Depth]]),
|
|
570
619
|
heatmapType: new Map([[DEFAULT_VIEW_ID, EHeatmapType.Click]]),
|
|
620
|
+
dataSource: new Map([[DEFAULT_VIEW_ID, EHeatmapDataSource.Snapshot]]),
|
|
571
621
|
}),
|
|
572
622
|
};
|
|
573
623
|
}));
|
|
574
624
|
|
|
575
625
|
const useHeatmapVizStore = create()(subscribeWithSelector((set) => {
|
|
576
626
|
return {
|
|
577
|
-
|
|
627
|
+
isDomLoaded: new Map([[DEFAULT_VIEW_ID, false]]),
|
|
578
628
|
zoomRatio: new Map([[DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO.DEFAULT]]),
|
|
579
629
|
minZoomRatio: new Map([[DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO.MIN]]),
|
|
580
630
|
maxZoomRatio: new Map([[DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO.MAX]]),
|
|
581
631
|
scale: new Map([[DEFAULT_VIEW_ID, 1]]),
|
|
582
632
|
isScaledToFit: new Map([[DEFAULT_VIEW_ID, false]]),
|
|
583
|
-
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
return {
|
|
633
|
+
setIsDomLoaded: (isDomLoaded, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
634
|
+
const newIsDomLoaded = new Map(prev.isDomLoaded);
|
|
635
|
+
newIsDomLoaded.set(viewId, isDomLoaded);
|
|
636
|
+
return { isDomLoaded: newIsDomLoaded };
|
|
587
637
|
}),
|
|
588
638
|
setZoomRatio: (zoomRatio, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
589
639
|
const newZoomRatio = new Map(prev.zoomRatio);
|
|
@@ -611,18 +661,18 @@ const useHeatmapVizStore = create()(subscribeWithSelector((set) => {
|
|
|
611
661
|
return { isScaledToFit: newIsScaledToFit };
|
|
612
662
|
}),
|
|
613
663
|
copyView: (fromViewId, toViewId) => set((prev) => {
|
|
614
|
-
const
|
|
664
|
+
const newIsDomLoaded = new Map(prev.isDomLoaded);
|
|
615
665
|
const newZoomRatio = new Map(prev.zoomRatio);
|
|
616
666
|
const newMinZoomRatio = new Map(prev.minZoomRatio);
|
|
617
667
|
const newScale = new Map(prev.scale);
|
|
618
668
|
const newIsScaledToFit = new Map(prev.isScaledToFit);
|
|
619
|
-
|
|
669
|
+
newIsDomLoaded.set(toViewId, prev.isDomLoaded.get(fromViewId) ?? false);
|
|
620
670
|
newZoomRatio.set(toViewId, prev.zoomRatio.get(fromViewId) ?? 100);
|
|
621
671
|
newMinZoomRatio.set(toViewId, prev.minZoomRatio.get(fromViewId) ?? 10);
|
|
622
672
|
newScale.set(toViewId, prev.scale.get(fromViewId) ?? 1);
|
|
623
673
|
newIsScaledToFit.set(toViewId, prev.isScaledToFit.get(fromViewId) ?? false);
|
|
624
674
|
return {
|
|
625
|
-
|
|
675
|
+
isDomLoaded: newIsDomLoaded,
|
|
626
676
|
zoomRatio: newZoomRatio,
|
|
627
677
|
minZoomRatio: newMinZoomRatio,
|
|
628
678
|
scale: newScale,
|
|
@@ -630,18 +680,18 @@ const useHeatmapVizStore = create()(subscribeWithSelector((set) => {
|
|
|
630
680
|
};
|
|
631
681
|
}),
|
|
632
682
|
clearView: (viewId) => set((prev) => {
|
|
633
|
-
const
|
|
683
|
+
const newIsDomLoaded = new Map(prev.isDomLoaded);
|
|
634
684
|
const newZoomRatio = new Map(prev.zoomRatio);
|
|
635
685
|
const newMinZoomRatio = new Map(prev.minZoomRatio);
|
|
636
686
|
const newScale = new Map(prev.scale);
|
|
637
687
|
const newIsScaledToFit = new Map(prev.isScaledToFit);
|
|
638
|
-
|
|
688
|
+
newIsDomLoaded.delete(viewId);
|
|
639
689
|
newZoomRatio.delete(viewId);
|
|
640
690
|
newMinZoomRatio.delete(viewId);
|
|
641
691
|
newScale.delete(viewId);
|
|
642
692
|
newIsScaledToFit.delete(viewId);
|
|
643
693
|
return {
|
|
644
|
-
|
|
694
|
+
isDomLoaded: newIsDomLoaded,
|
|
645
695
|
zoomRatio: newZoomRatio,
|
|
646
696
|
minZoomRatio: newMinZoomRatio,
|
|
647
697
|
scale: newScale,
|
|
@@ -649,7 +699,7 @@ const useHeatmapVizStore = create()(subscribeWithSelector((set) => {
|
|
|
649
699
|
};
|
|
650
700
|
}),
|
|
651
701
|
resetAll: () => set({
|
|
652
|
-
|
|
702
|
+
isDomLoaded: new Map([[DEFAULT_VIEW_ID, false]]),
|
|
653
703
|
zoomRatio: new Map([[DEFAULT_VIEW_ID, 100]]),
|
|
654
704
|
minZoomRatio: new Map([[DEFAULT_VIEW_ID, 10]]),
|
|
655
705
|
scale: new Map([[DEFAULT_VIEW_ID, 1]]),
|
|
@@ -1047,24 +1097,108 @@ const useHeatmapCompareStore = create()((set, get) => {
|
|
|
1047
1097
|
});
|
|
1048
1098
|
|
|
1049
1099
|
const initialState = {
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1100
|
+
decodedPayloads: new Map([[DEFAULT_VIEW_ID, []]]),
|
|
1101
|
+
encodedPayloads: new Map([[DEFAULT_VIEW_ID, []]]),
|
|
1102
|
+
htmlContent: new Map([[DEFAULT_VIEW_ID, '']]),
|
|
1103
|
+
targetUrl: new Map([[DEFAULT_VIEW_ID, '']]),
|
|
1104
|
+
renderMode: new Map([[DEFAULT_VIEW_ID, 'portal']]),
|
|
1105
|
+
storefrontPassword: new Map([[DEFAULT_VIEW_ID, '']]),
|
|
1106
|
+
};
|
|
1107
|
+
const useHeatmapLiveStore = create()(subscribeWithSelector((set) => ({
|
|
1108
|
+
...initialState,
|
|
1109
|
+
addPayload: (payload, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1110
|
+
const newDecoded = new Map(prev.decodedPayloads);
|
|
1111
|
+
newDecoded.set(viewId, [...(newDecoded.get(viewId) ?? []), payload]);
|
|
1112
|
+
const newEncoded = new Map(prev.encodedPayloads);
|
|
1113
|
+
newEncoded.set(viewId, [...(newEncoded.get(viewId) ?? []), JSON.stringify(payload)]);
|
|
1114
|
+
return { decodedPayloads: newDecoded, encodedPayloads: newEncoded };
|
|
1115
|
+
}),
|
|
1116
|
+
setPayloads: (payloads, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1117
|
+
const newDecoded = new Map(prev.decodedPayloads);
|
|
1118
|
+
newDecoded.set(viewId, payloads);
|
|
1119
|
+
const newEncoded = new Map(prev.encodedPayloads);
|
|
1120
|
+
newEncoded.set(viewId, payloads.map((p) => JSON.stringify(p)));
|
|
1121
|
+
return { decodedPayloads: newDecoded, encodedPayloads: newEncoded };
|
|
1122
|
+
}),
|
|
1123
|
+
setEncodedPayloads: (payloads, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1124
|
+
const newEncoded = new Map(prev.encodedPayloads);
|
|
1125
|
+
newEncoded.set(viewId, payloads);
|
|
1126
|
+
return { encodedPayloads: newEncoded };
|
|
1127
|
+
}),
|
|
1128
|
+
setHtmlContent: (htmlContent, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1129
|
+
const newHtmlContent = new Map(prev.htmlContent);
|
|
1130
|
+
newHtmlContent.set(viewId, htmlContent);
|
|
1131
|
+
return { htmlContent: newHtmlContent };
|
|
1132
|
+
}),
|
|
1133
|
+
setTargetUrl: (targetUrl, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1134
|
+
const newTargetUrl = new Map(prev.targetUrl);
|
|
1135
|
+
newTargetUrl.set(viewId, targetUrl);
|
|
1136
|
+
return { targetUrl: newTargetUrl };
|
|
1137
|
+
}),
|
|
1138
|
+
setRenderMode: (renderMode, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1139
|
+
const newRenderMode = new Map(prev.renderMode);
|
|
1140
|
+
newRenderMode.set(viewId, renderMode);
|
|
1141
|
+
return { renderMode: newRenderMode };
|
|
1142
|
+
}),
|
|
1143
|
+
setStorefrontPassword: (storefrontPassword, viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1144
|
+
const newStorefrontPassword = new Map(prev.storefrontPassword);
|
|
1145
|
+
newStorefrontPassword.set(viewId, storefrontPassword);
|
|
1146
|
+
return { storefrontPassword: newStorefrontPassword };
|
|
1147
|
+
}),
|
|
1148
|
+
resetView: (viewId = DEFAULT_VIEW_ID) => set((prev) => {
|
|
1149
|
+
const newDecoded = new Map(prev.decodedPayloads);
|
|
1150
|
+
newDecoded.set(viewId, []);
|
|
1151
|
+
const newEncoded = new Map(prev.encodedPayloads);
|
|
1152
|
+
newEncoded.set(viewId, []);
|
|
1153
|
+
return { decodedPayloads: newDecoded, encodedPayloads: newEncoded };
|
|
1154
|
+
}),
|
|
1155
|
+
copyView: (fromViewId, toViewId) => 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.set(toViewId, prev.decodedPayloads.get(fromViewId) ?? []);
|
|
1163
|
+
newEncoded.set(toViewId, prev.encodedPayloads.get(fromViewId) ?? []);
|
|
1164
|
+
newHtmlContent.set(toViewId, prev.htmlContent.get(fromViewId) ?? '');
|
|
1165
|
+
newTargetUrl.set(toViewId, prev.targetUrl.get(fromViewId) ?? '');
|
|
1166
|
+
newRenderMode.set(toViewId, prev.renderMode.get(fromViewId) ?? 'portal');
|
|
1167
|
+
newStorefrontPassword.set(toViewId, prev.storefrontPassword.get(fromViewId) ?? '');
|
|
1168
|
+
return {
|
|
1169
|
+
decodedPayloads: newDecoded,
|
|
1170
|
+
encodedPayloads: newEncoded,
|
|
1171
|
+
htmlContent: newHtmlContent,
|
|
1172
|
+
targetUrl: newTargetUrl,
|
|
1173
|
+
renderMode: newRenderMode,
|
|
1174
|
+
storefrontPassword: newStorefrontPassword,
|
|
1175
|
+
};
|
|
1176
|
+
}),
|
|
1177
|
+
clearView: (viewId) => set((prev) => {
|
|
1178
|
+
const newDecoded = new Map(prev.decodedPayloads);
|
|
1179
|
+
const newEncoded = new Map(prev.encodedPayloads);
|
|
1180
|
+
const newHtmlContent = new Map(prev.htmlContent);
|
|
1181
|
+
const newTargetUrl = new Map(prev.targetUrl);
|
|
1182
|
+
const newRenderMode = new Map(prev.renderMode);
|
|
1183
|
+
const newStorefrontPassword = new Map(prev.storefrontPassword);
|
|
1184
|
+
newDecoded.delete(viewId);
|
|
1185
|
+
newEncoded.delete(viewId);
|
|
1186
|
+
newHtmlContent.delete(viewId);
|
|
1187
|
+
newTargetUrl.delete(viewId);
|
|
1188
|
+
newRenderMode.delete(viewId);
|
|
1189
|
+
newStorefrontPassword.delete(viewId);
|
|
1190
|
+
return {
|
|
1191
|
+
decodedPayloads: newDecoded,
|
|
1192
|
+
encodedPayloads: newEncoded,
|
|
1193
|
+
htmlContent: newHtmlContent,
|
|
1194
|
+
targetUrl: newTargetUrl,
|
|
1195
|
+
renderMode: newRenderMode,
|
|
1196
|
+
storefrontPassword: newStorefrontPassword,
|
|
1197
|
+
};
|
|
1198
|
+
}),
|
|
1199
|
+
resetAll: () => set(initialState),
|
|
1200
|
+
reset: () => set(initialState),
|
|
1201
|
+
})));
|
|
1068
1202
|
|
|
1069
1203
|
const useHeatmapVizRectStore = create()(subscribeWithSelector((set) => {
|
|
1070
1204
|
return {
|
|
@@ -1170,26 +1304,12 @@ const useHeatmapClickContext = createViewContextHook({
|
|
|
1170
1304
|
}),
|
|
1171
1305
|
});
|
|
1172
1306
|
|
|
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
1307
|
const useHeatmapDataContext = createViewContextHook({
|
|
1190
1308
|
useStore: useHeatmapDataStore,
|
|
1191
1309
|
getState: (store, viewId) => ({
|
|
1192
1310
|
data: store.data.get(viewId),
|
|
1311
|
+
dataHash: store.dataHash.get(viewId),
|
|
1312
|
+
dataSnapshot: store.dataSnapshot.get(viewId),
|
|
1193
1313
|
clickmap: store.clickmap.get(viewId),
|
|
1194
1314
|
clickAreas: store.clickAreas.get(viewId),
|
|
1195
1315
|
scrollmap: store.scrollmap.get(viewId),
|
|
@@ -1199,6 +1319,8 @@ const useHeatmapDataContext = createViewContextHook({
|
|
|
1199
1319
|
}),
|
|
1200
1320
|
getActions: (store, viewId) => ({
|
|
1201
1321
|
setData: (newData) => store.setData(newData, viewId),
|
|
1322
|
+
setDataSnapshot: (newData) => store.setDataSnapshot(newData, viewId),
|
|
1323
|
+
setDataHash: (newHash) => store.setDataHash(newHash, viewId),
|
|
1202
1324
|
setClickmap: (newClickmap) => store.setClickmap(newClickmap, viewId),
|
|
1203
1325
|
setClickAreas: (newClickAreas) => store.setClickAreas(newClickAreas, viewId),
|
|
1204
1326
|
setDataInfoByKey: (key, value) => store.setDataInfoByKey(key, value, viewId),
|
|
@@ -1221,6 +1343,32 @@ const useHeatmapHoverContext = createViewContextHook({
|
|
|
1221
1343
|
}),
|
|
1222
1344
|
});
|
|
1223
1345
|
|
|
1346
|
+
const useHeatmapLiveContext = createViewContextHook({
|
|
1347
|
+
useStore: useHeatmapLiveStore,
|
|
1348
|
+
getState: (store, viewId) => ({
|
|
1349
|
+
decodedPayloads: store.decodedPayloads.get(viewId) ?? [],
|
|
1350
|
+
encodedPayloads: store.encodedPayloads.get(viewId) ?? [],
|
|
1351
|
+
htmlContent: store.htmlContent.get(viewId) ?? '',
|
|
1352
|
+
targetUrl: store.targetUrl.get(viewId) ?? '',
|
|
1353
|
+
renderMode: store.renderMode.get(viewId) ?? 'portal',
|
|
1354
|
+
storefrontPassword: store.storefrontPassword.get(viewId) ?? '',
|
|
1355
|
+
}),
|
|
1356
|
+
getActions: (store, viewId) => ({
|
|
1357
|
+
addPayload: (payload) => store.addPayload(payload, viewId),
|
|
1358
|
+
setPayloads: (payloads) => store.setPayloads(payloads, viewId),
|
|
1359
|
+
setEncodedPayloads: (payloads) => store.setEncodedPayloads(payloads, viewId),
|
|
1360
|
+
setHtmlContent: (htmlContent) => store.setHtmlContent(htmlContent, viewId),
|
|
1361
|
+
setTargetUrl: (targetUrl) => store.setTargetUrl(targetUrl, viewId),
|
|
1362
|
+
setRenderMode: (mode) => store.setRenderMode(mode, viewId),
|
|
1363
|
+
setStorefrontPassword: (password) => store.setStorefrontPassword(password, viewId),
|
|
1364
|
+
resetView: () => store.resetView(viewId),
|
|
1365
|
+
copyView: (fromViewId, toViewId) => store.copyView(fromViewId, toViewId),
|
|
1366
|
+
clearView: (viewId) => store.clearView(viewId),
|
|
1367
|
+
resetAll: () => store.resetAll(),
|
|
1368
|
+
reset: () => store.reset(),
|
|
1369
|
+
}),
|
|
1370
|
+
});
|
|
1371
|
+
|
|
1224
1372
|
const useHeatmapScrollContext = createViewContextHook({
|
|
1225
1373
|
useStore: useHeatmapVizScrollStore,
|
|
1226
1374
|
getState: (store, viewId) => ({
|
|
@@ -1250,6 +1398,7 @@ const useHeatmapSettingContext = createViewContextHook({
|
|
|
1250
1398
|
clickMode: store.clickMode.get(viewId),
|
|
1251
1399
|
scrollType: store.scrollType.get(viewId),
|
|
1252
1400
|
heatmapType: store.heatmapType.get(viewId),
|
|
1401
|
+
dataSource: store.dataSource.get(viewId) ?? EHeatmapDataSource.Snapshot,
|
|
1253
1402
|
}),
|
|
1254
1403
|
getActions: (store, viewId) => ({
|
|
1255
1404
|
setIsShowSidebar: (isShowSidebar) => store.setIsShowSidebar(isShowSidebar, viewId),
|
|
@@ -1262,6 +1411,7 @@ const useHeatmapSettingContext = createViewContextHook({
|
|
|
1262
1411
|
setIsRendering: (isRendering) => store.setIsRendering(isRendering, viewId),
|
|
1263
1412
|
setIsLoadingDom: (isLoadingDom) => store.setIsLoadingDom(isLoadingDom, viewId),
|
|
1264
1413
|
setIsLoadingCanvas: (isLoadingCanvas) => store.setIsLoadingCanvas(isLoadingCanvas, viewId),
|
|
1414
|
+
setDataSource: (dataSource) => store.setDataSource(dataSource, viewId),
|
|
1265
1415
|
clearView: (viewId) => store.clearView(viewId),
|
|
1266
1416
|
}),
|
|
1267
1417
|
});
|
|
@@ -1269,7 +1419,7 @@ const useHeatmapSettingContext = createViewContextHook({
|
|
|
1269
1419
|
const useHeatmapVizContext = createViewContextHook({
|
|
1270
1420
|
useStore: useHeatmapVizStore,
|
|
1271
1421
|
getState: (store, viewId) => ({
|
|
1272
|
-
|
|
1422
|
+
isDomLoaded: store.isDomLoaded.get(viewId) ?? false,
|
|
1273
1423
|
zoomRatio: store.zoomRatio.get(viewId) ?? DEFAULT_ZOOM_RATIO.DEFAULT,
|
|
1274
1424
|
minZoomRatio: store.minZoomRatio.get(viewId) ?? DEFAULT_ZOOM_RATIO.MIN,
|
|
1275
1425
|
maxZoomRatio: store.maxZoomRatio.get(viewId) ?? DEFAULT_ZOOM_RATIO.MAX,
|
|
@@ -1277,7 +1427,7 @@ const useHeatmapVizContext = createViewContextHook({
|
|
|
1277
1427
|
isScaledToFit: store.isScaledToFit.get(viewId) ?? false,
|
|
1278
1428
|
}),
|
|
1279
1429
|
getActions: (store, viewId) => ({
|
|
1280
|
-
|
|
1430
|
+
setIsDomLoaded: (value) => store.setIsDomLoaded(value, viewId),
|
|
1281
1431
|
setZoomRatio: (value) => store.setZoomRatio(value, viewId),
|
|
1282
1432
|
setMinZoomRatio: (value) => store.setMinZoomRatio(value, viewId),
|
|
1283
1433
|
setMaxZoomRatio: (value) => store.setMaxZoomRatio(value, viewId),
|
|
@@ -1311,9 +1461,7 @@ const useHeatmapCopyView = () => {
|
|
|
1311
1461
|
const copyVizView = useHeatmapVizStore((state) => state.copyView);
|
|
1312
1462
|
const copyVizClickView = useHeatmapVizClickStore((state) => state.copyView);
|
|
1313
1463
|
const copyVizAreaClickView = useHeatmapVizClickAreaStore((state) => state.copyView);
|
|
1314
|
-
|
|
1315
|
-
// const copyVizHoverView = useHeatmapVizHoverStore((state) => state.copyView);
|
|
1316
|
-
// const copyVizScrollView = useHeatmapVizScrollStore((state) => state.copyView);
|
|
1464
|
+
const copyLiveView = useHeatmapLiveStore((state) => state.copyView);
|
|
1317
1465
|
const clearDataView = useHeatmapDataStore((state) => state.clearView);
|
|
1318
1466
|
const clearSettingView = useHeatmapSettingStore((state) => state.clearView);
|
|
1319
1467
|
const clearVizView = useHeatmapVizStore((state) => state.clearView);
|
|
@@ -1322,6 +1470,7 @@ const useHeatmapCopyView = () => {
|
|
|
1322
1470
|
const clearVizHoverView = useHeatmapVizHoverStore((state) => state.clearView);
|
|
1323
1471
|
const clearVizScrollView = useHeatmapVizScrollStore((state) => state.clearView);
|
|
1324
1472
|
const clearVizAreaClickView = useHeatmapVizClickAreaStore((state) => state.clearView);
|
|
1473
|
+
const clearLiveView = useHeatmapLiveStore((state) => state.clearView);
|
|
1325
1474
|
const resetDataAll = useHeatmapDataStore((state) => state.resetAll);
|
|
1326
1475
|
const resetSettingAll = useHeatmapSettingStore((state) => state.resetAll);
|
|
1327
1476
|
const resetVizAll = useHeatmapVizStore((state) => state.resetAll);
|
|
@@ -1330,15 +1479,14 @@ const useHeatmapCopyView = () => {
|
|
|
1330
1479
|
const resetVizHoverAll = useHeatmapVizHoverStore((state) => state.resetAll);
|
|
1331
1480
|
const resetVizScrollViewAll = useHeatmapVizScrollStore((state) => state.resetAll);
|
|
1332
1481
|
const resetVizClickAreaAll = useHeatmapVizClickAreaStore((state) => state.resetAll);
|
|
1482
|
+
const resetLiveAll = useHeatmapLiveStore((state) => state.resetAll);
|
|
1333
1483
|
const copyView = (fromViewId, toViewId) => {
|
|
1334
1484
|
copyDataView(fromViewId, toViewId);
|
|
1335
1485
|
copySettingView(fromViewId, toViewId);
|
|
1336
1486
|
copyVizView(fromViewId, toViewId);
|
|
1337
|
-
// copyVizRectView(fromViewId, toViewId);
|
|
1338
1487
|
copyVizClickView(fromViewId, toViewId);
|
|
1339
|
-
// copyVizHoverView(fromViewId, toViewId);
|
|
1340
|
-
// copyVizScrollView(fromViewId, toViewId);
|
|
1341
1488
|
copyVizAreaClickView(fromViewId, toViewId);
|
|
1489
|
+
copyLiveView(fromViewId, toViewId);
|
|
1342
1490
|
};
|
|
1343
1491
|
const copyViewToMultiple = (fromViewId, toViewIds) => {
|
|
1344
1492
|
toViewIds.forEach((toViewId) => {
|
|
@@ -1354,6 +1502,7 @@ const useHeatmapCopyView = () => {
|
|
|
1354
1502
|
clearVizHoverView(viewId);
|
|
1355
1503
|
clearVizScrollView(viewId);
|
|
1356
1504
|
clearVizAreaClickView(viewId);
|
|
1505
|
+
clearLiveView(viewId);
|
|
1357
1506
|
};
|
|
1358
1507
|
const clearMultipleViews = (viewIds) => {
|
|
1359
1508
|
viewIds.forEach((viewId) => {
|
|
@@ -1369,6 +1518,7 @@ const useHeatmapCopyView = () => {
|
|
|
1369
1518
|
resetVizHoverAll();
|
|
1370
1519
|
resetVizScrollViewAll();
|
|
1371
1520
|
resetVizClickAreaAll();
|
|
1521
|
+
resetLiveAll();
|
|
1372
1522
|
};
|
|
1373
1523
|
return {
|
|
1374
1524
|
copyView,
|
|
@@ -1379,14 +1529,17 @@ const useHeatmapCopyView = () => {
|
|
|
1379
1529
|
};
|
|
1380
1530
|
};
|
|
1381
1531
|
|
|
1382
|
-
const
|
|
1532
|
+
const useHeatmapViewportByDevice = () => {
|
|
1383
1533
|
const deviceType = useHeatmapSettingContext((state) => state.deviceType);
|
|
1384
1534
|
const width = useMemo(() => calcWidthByDeviceType(deviceType), [deviceType]);
|
|
1385
|
-
|
|
1535
|
+
const height = useMemo(() => calcHeightByDeviceType(deviceType), [deviceType]);
|
|
1536
|
+
return { width, height };
|
|
1386
1537
|
function calcWidthByDeviceType(deviceType) {
|
|
1387
1538
|
if (!deviceType)
|
|
1388
1539
|
return 1440;
|
|
1389
1540
|
switch (deviceType) {
|
|
1541
|
+
case EDeviceType.DesktopLarge:
|
|
1542
|
+
return 1920;
|
|
1390
1543
|
case EDeviceType.Desktop:
|
|
1391
1544
|
return 1440;
|
|
1392
1545
|
case EDeviceType.Tablet:
|
|
@@ -1395,20 +1548,45 @@ const useHeatmapWidthByDevice = () => {
|
|
|
1395
1548
|
return 375;
|
|
1396
1549
|
}
|
|
1397
1550
|
}
|
|
1551
|
+
function calcHeightByDeviceType(deviceType) {
|
|
1552
|
+
if (!deviceType)
|
|
1553
|
+
return 900;
|
|
1554
|
+
switch (deviceType) {
|
|
1555
|
+
case EDeviceType.DesktopLarge:
|
|
1556
|
+
return 1080; // 1920×1080
|
|
1557
|
+
case EDeviceType.Desktop:
|
|
1558
|
+
return 900; // 1440×900
|
|
1559
|
+
case EDeviceType.Tablet:
|
|
1560
|
+
return 1024; // 768×1024 (iPad portrait)
|
|
1561
|
+
case EDeviceType.Mobile:
|
|
1562
|
+
return 812; // 375×812 (iPhone X/11/12/13)
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1398
1565
|
};
|
|
1399
1566
|
|
|
1400
|
-
const useRegisterConfig = ({ isLoading, isLoadingCanvas, }) => {
|
|
1567
|
+
const useRegisterConfig = ({ shopId, isLoading, isLoadingCanvas, excludeClassNames, }) => {
|
|
1401
1568
|
const mode = useHeatmapConfigStore((state) => state.mode);
|
|
1569
|
+
const shopIdStore = useHeatmapConfigStore((state) => state.shopId);
|
|
1402
1570
|
const deviceType = useHeatmapSettingContext((state) => state.deviceType);
|
|
1403
1571
|
const sidebarWidth = useHeatmapConfigStore((state) => state.sidebarWidth);
|
|
1404
1572
|
const setIsRendering = useHeatmapSettingContext((state) => state.setIsRendering);
|
|
1405
1573
|
const setIsLoadingDom = useHeatmapSettingContext((state) => state.setIsLoadingDom);
|
|
1406
1574
|
const setIsLoadingCanvas = useHeatmapSettingContext((state) => state.setIsLoadingCanvas);
|
|
1575
|
+
const setShopId = useHeatmapConfigStore((state) => state.setShopId);
|
|
1576
|
+
const setExcludeClassNames = useHeatmapConfigStore((state) => state.setExcludeClassNames);
|
|
1577
|
+
useEffect(() => {
|
|
1578
|
+
if (!shopId || !!shopIdStore || shopIdStore === shopId)
|
|
1579
|
+
return;
|
|
1580
|
+
setShopId(shopId);
|
|
1581
|
+
}, [shopId, setShopId, shopIdStore]);
|
|
1582
|
+
useEffect(() => {
|
|
1583
|
+
setExcludeClassNames(excludeClassNames || []);
|
|
1584
|
+
}, [excludeClassNames, setExcludeClassNames]);
|
|
1407
1585
|
useEffect(() => {
|
|
1408
1586
|
setIsRendering(true);
|
|
1409
1587
|
setTimeout(() => {
|
|
1410
1588
|
setIsRendering(false);
|
|
1411
|
-
},
|
|
1589
|
+
}, 500);
|
|
1412
1590
|
}, [mode, deviceType, sidebarWidth]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
1413
1591
|
useEffect(() => {
|
|
1414
1592
|
setIsRendering(!!isLoading);
|
|
@@ -1770,7 +1948,7 @@ class Logger {
|
|
|
1770
1948
|
}
|
|
1771
1949
|
}
|
|
1772
1950
|
// Export singleton instance
|
|
1773
|
-
const logger$
|
|
1951
|
+
const logger$3 = new Logger();
|
|
1774
1952
|
// Export factory function để tạo logger với config riêng
|
|
1775
1953
|
function createLogger(config = {}) {
|
|
1776
1954
|
const instance = new Logger();
|
|
@@ -2159,7 +2337,7 @@ function findElementByHash(props) {
|
|
|
2159
2337
|
}
|
|
2160
2338
|
}
|
|
2161
2339
|
catch (error) {
|
|
2162
|
-
logger$
|
|
2340
|
+
logger$3.warn(`Invalid selector "${selector}":`, error);
|
|
2163
2341
|
}
|
|
2164
2342
|
const elementByHash = iframeDocument.querySelector(`[data-clarity-hashalpha="${hash}"], [data-clarity-hash="${hash}"], [data-clarity-hashbeta="${hash}"]`);
|
|
2165
2343
|
return elementByHash;
|
|
@@ -2181,7 +2359,7 @@ function hydrateAreaNode(props) {
|
|
|
2181
2359
|
const { id, hash, selector } = persistedData;
|
|
2182
2360
|
const element = findElementByHash({ hash, selector, iframeDocument, vizRef });
|
|
2183
2361
|
if (!element) {
|
|
2184
|
-
logger$
|
|
2362
|
+
logger$3.warn(`Cannot hydrate area ${id}: element not found for hash ${hash} or selector ${selector}`);
|
|
2185
2363
|
return null;
|
|
2186
2364
|
}
|
|
2187
2365
|
const areaNode = buildAreaNode(element, hash, heatmapInfo, shadowRoot, persistedData);
|
|
@@ -2198,7 +2376,7 @@ function hydrateAreas(props) {
|
|
|
2198
2376
|
hydratedAreas.push(area);
|
|
2199
2377
|
}
|
|
2200
2378
|
}
|
|
2201
|
-
logger$
|
|
2379
|
+
logger$3.info(`Hydrated ${hydratedAreas.length} of ${clickAreas.length} persisted areas`);
|
|
2202
2380
|
return hydratedAreas;
|
|
2203
2381
|
}
|
|
2204
2382
|
/**
|
|
@@ -2902,16 +3080,16 @@ const calcCalloutPositionAbsolute = (props) => {
|
|
|
2902
3080
|
|
|
2903
3081
|
function validateAreaCreation(dataInfo, hash, areas) {
|
|
2904
3082
|
if (!dataInfo?.clickMapMetrics || !dataInfo?.totalClicks) {
|
|
2905
|
-
logger$
|
|
3083
|
+
logger$3.warn('Cannot create area: missing heatmap data');
|
|
2906
3084
|
return false;
|
|
2907
3085
|
}
|
|
2908
3086
|
if (!hash) {
|
|
2909
|
-
logger$
|
|
3087
|
+
logger$3.warn('Cannot create area: missing hash');
|
|
2910
3088
|
return false;
|
|
2911
3089
|
}
|
|
2912
3090
|
const alreadyExists = areas.some((area) => area.hash === hash);
|
|
2913
3091
|
if (alreadyExists) {
|
|
2914
|
-
logger$
|
|
3092
|
+
logger$3.warn(`Area already exists for element: ${hash}`);
|
|
2915
3093
|
return false;
|
|
2916
3094
|
}
|
|
2917
3095
|
return true;
|
|
@@ -2924,14 +3102,14 @@ function identifyConflictingAreas(area) {
|
|
|
2924
3102
|
// Case 1: New area is a child of an existing area
|
|
2925
3103
|
if (area.parentNode) {
|
|
2926
3104
|
conflicts.parentId = area.parentNode.id;
|
|
2927
|
-
logger$
|
|
3105
|
+
logger$3.info(`New area "${area.selector}" is a child of existing area "${area.parentNode.selector}". Will remove parent.`);
|
|
2928
3106
|
}
|
|
2929
3107
|
// Case 2: New area is a parent of existing area(s)
|
|
2930
3108
|
if (area.childNodes.size > 0) {
|
|
2931
3109
|
area.childNodes.forEach((childArea) => {
|
|
2932
3110
|
conflicts.childrenIds.push(childArea.id);
|
|
2933
3111
|
});
|
|
2934
|
-
logger$
|
|
3112
|
+
logger$3.info(`New area "${area.selector}" is a parent of ${area.childNodes.size} existing area(s). Will remove children.`);
|
|
2935
3113
|
}
|
|
2936
3114
|
return conflicts;
|
|
2937
3115
|
}
|
|
@@ -2982,7 +3160,7 @@ function useAreaCreation(options = {}) {
|
|
|
2982
3160
|
}
|
|
2983
3161
|
}
|
|
2984
3162
|
catch (error) {
|
|
2985
|
-
logger$
|
|
3163
|
+
logger$3.error('Failed to create area:', error);
|
|
2986
3164
|
}
|
|
2987
3165
|
}, [dataInfo, areas, addArea, removeArea, removeClickArea, customShadowRoot, onAreaCreated]);
|
|
2988
3166
|
return {
|
|
@@ -3097,16 +3275,16 @@ function useAreaHydration(options) {
|
|
|
3097
3275
|
return;
|
|
3098
3276
|
if (!dataInfo)
|
|
3099
3277
|
return;
|
|
3100
|
-
logger$
|
|
3278
|
+
logger$3.info(`Hydrating ${clickAreas.length} persisted areas...`);
|
|
3101
3279
|
const hydratedAreas = hydrateAreas({ clickAreas, heatmapInfo: dataInfo, vizRef, shadowRoot });
|
|
3102
3280
|
if (!hydratedAreas?.length) {
|
|
3103
|
-
logger$
|
|
3281
|
+
logger$3.warn('No areas could be hydrated - all elements may have been removed from DOM');
|
|
3104
3282
|
return;
|
|
3105
3283
|
}
|
|
3106
3284
|
setIsInitializing(true);
|
|
3107
3285
|
buildAreaGraph(hydratedAreas);
|
|
3108
3286
|
setAreas(hydratedAreas);
|
|
3109
|
-
logger$
|
|
3287
|
+
logger$3.info(`Successfully hydrated ${hydratedAreas.length} areas`);
|
|
3110
3288
|
}, [dataInfo, vizRef, isInitializing, clickAreas]);
|
|
3111
3289
|
useEffect(() => {
|
|
3112
3290
|
if (!enabled)
|
|
@@ -3240,7 +3418,7 @@ function useAreaRectSync(options) {
|
|
|
3240
3418
|
area.rect.update(newRect);
|
|
3241
3419
|
}
|
|
3242
3420
|
catch (error) {
|
|
3243
|
-
logger$
|
|
3421
|
+
logger$3.error(`Failed to update rect for area ${area.id}:`, error);
|
|
3244
3422
|
}
|
|
3245
3423
|
});
|
|
3246
3424
|
buildAreaGraph(areas);
|
|
@@ -3345,18 +3523,20 @@ const useAreaClickmap = () => {
|
|
|
3345
3523
|
const useClickmap = () => {
|
|
3346
3524
|
const vizRef = useHeatmapVizRectContext((s) => s.vizRef);
|
|
3347
3525
|
const clickmap = useHeatmapDataContext((s) => s.clickmap);
|
|
3348
|
-
const
|
|
3526
|
+
const isDomLoaded = useHeatmapVizContext((s) => s.isDomLoaded);
|
|
3349
3527
|
const start = useCallback(() => {
|
|
3350
|
-
if (!vizRef || !clickmap || clickmap.length === 0 || !
|
|
3528
|
+
if (!vizRef || !clickmap || clickmap.length === 0 || !isDomLoaded)
|
|
3351
3529
|
return;
|
|
3352
3530
|
try {
|
|
3353
|
-
|
|
3354
|
-
|
|
3531
|
+
requestIdleCallback(() => {
|
|
3532
|
+
vizRef?.clearmap?.();
|
|
3533
|
+
vizRef?.clickmap?.(clickmap);
|
|
3534
|
+
}, { timeout: 300 });
|
|
3355
3535
|
}
|
|
3356
3536
|
catch (error) {
|
|
3357
3537
|
console.error(`🚀 🐥 ~ useClickmap ~ error:`, error);
|
|
3358
3538
|
}
|
|
3359
|
-
}, [vizRef, clickmap,
|
|
3539
|
+
}, [vizRef, clickmap, isDomLoaded]);
|
|
3360
3540
|
return { start };
|
|
3361
3541
|
};
|
|
3362
3542
|
|
|
@@ -3364,6 +3544,7 @@ const useScrollmap = () => {
|
|
|
3364
3544
|
const vizRef = useHeatmapVizRectContext((s) => s.vizRef);
|
|
3365
3545
|
const scrollType = useHeatmapSettingContext((s) => s.scrollType);
|
|
3366
3546
|
const scrollmap = useHeatmapDataContext((s) => s.scrollmap);
|
|
3547
|
+
const isDomLoaded = useHeatmapVizContext((s) => s.isDomLoaded);
|
|
3367
3548
|
useMemo(() => {
|
|
3368
3549
|
switch (scrollType) {
|
|
3369
3550
|
case EScrollType.Depth:
|
|
@@ -3377,16 +3558,18 @@ const useScrollmap = () => {
|
|
|
3377
3558
|
}
|
|
3378
3559
|
}, [scrollmap, scrollType]);
|
|
3379
3560
|
const start = useCallback(() => {
|
|
3380
|
-
if (!vizRef || !scrollmap || scrollmap.length === 0)
|
|
3561
|
+
if (!vizRef || !scrollmap || scrollmap.length === 0 || !isDomLoaded)
|
|
3381
3562
|
return;
|
|
3382
3563
|
try {
|
|
3383
|
-
|
|
3384
|
-
|
|
3564
|
+
requestIdleCallback(() => {
|
|
3565
|
+
vizRef?.clearmap?.();
|
|
3566
|
+
vizRef?.scrollmap?.(scrollmap);
|
|
3567
|
+
}, { timeout: 300 });
|
|
3385
3568
|
}
|
|
3386
3569
|
catch (error) {
|
|
3387
|
-
logger$
|
|
3570
|
+
logger$3.error(`🚀 🐥 ~ useScrollmap ~ error:`, error);
|
|
3388
3571
|
}
|
|
3389
|
-
}, [vizRef, scrollmap]);
|
|
3572
|
+
}, [vizRef, scrollmap, isDomLoaded]);
|
|
3390
3573
|
return { start };
|
|
3391
3574
|
};
|
|
3392
3575
|
|
|
@@ -3550,7 +3733,7 @@ const useHeatmapEffects = ({ isVisible }) => {
|
|
|
3550
3733
|
};
|
|
3551
3734
|
|
|
3552
3735
|
const useHeatmapElementPosition = ({ iframeRef, wrapperRef, visualizer }) => {
|
|
3553
|
-
const
|
|
3736
|
+
const viewport = useHeatmapViewportByDevice();
|
|
3554
3737
|
const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
|
|
3555
3738
|
const widthScale = useHeatmapVizContext((s) => s.widthScale);
|
|
3556
3739
|
const getRect = useCallback((element) => {
|
|
@@ -3578,17 +3761,17 @@ const useHeatmapElementPosition = ({ iframeRef, wrapperRef, visualizer }) => {
|
|
|
3578
3761
|
const outOfBounds = adjustedTop < 0 ||
|
|
3579
3762
|
adjustedTop > (iframeHeight || Infinity) ||
|
|
3580
3763
|
layout.left < 0 ||
|
|
3581
|
-
(typeof
|
|
3764
|
+
(typeof viewport.width === 'number' && layout.left > viewport.width);
|
|
3582
3765
|
if (outOfBounds)
|
|
3583
3766
|
return null;
|
|
3584
3767
|
return {
|
|
3585
3768
|
left: layout.left,
|
|
3586
3769
|
top: adjustedTop,
|
|
3587
|
-
width: Math.min(layout.width,
|
|
3770
|
+
width: Math.min(layout.width, viewport.width || layout.width),
|
|
3588
3771
|
height: layout.height,
|
|
3589
3772
|
outOfBounds,
|
|
3590
3773
|
};
|
|
3591
|
-
}, [iframeRef, wrapperRef, visualizer,
|
|
3774
|
+
}, [iframeRef, wrapperRef, visualizer, viewport, iframeHeight, widthScale]);
|
|
3592
3775
|
return { getRect };
|
|
3593
3776
|
};
|
|
3594
3777
|
|
|
@@ -3855,7 +4038,7 @@ var MessageType;
|
|
|
3855
4038
|
})(MessageType || (MessageType = {}));
|
|
3856
4039
|
function useVizLiveIframeMsg(options = {}) {
|
|
3857
4040
|
const { trustedOrigins = [], onMessage } = options;
|
|
3858
|
-
const addPayload =
|
|
4041
|
+
const addPayload = useHeatmapLiveContext((s) => s.addPayload);
|
|
3859
4042
|
const [isReady, setIsReady] = useState(false);
|
|
3860
4043
|
const iframeRef = useRef(null);
|
|
3861
4044
|
const isValidOrigin = useCallback((origin) => {
|
|
@@ -3881,7 +4064,7 @@ function useVizLiveIframeMsg(options = {}) {
|
|
|
3881
4064
|
switch (message.type) {
|
|
3882
4065
|
case MessageType.GX_DOM_TRACKING_PAYLOAD:
|
|
3883
4066
|
if (message.payload) {
|
|
3884
|
-
const data =
|
|
4067
|
+
const data = JSON.parse(message.payload);
|
|
3885
4068
|
if (data) {
|
|
3886
4069
|
addPayload(data);
|
|
3887
4070
|
}
|
|
@@ -3904,21 +4087,374 @@ function useVizLiveIframeMsg(options = {}) {
|
|
|
3904
4087
|
};
|
|
3905
4088
|
}
|
|
3906
4089
|
|
|
4090
|
+
/**
|
|
4091
|
+
* Unified performance timing utility.
|
|
4092
|
+
*
|
|
4093
|
+
* Two complementary tools:
|
|
4094
|
+
*
|
|
4095
|
+
* 1. `perf` — global DevTools session recorder.
|
|
4096
|
+
* Stores structured timing in `window.__gemxPerf` for inspection.
|
|
4097
|
+
* Used by the iframe-processor rendering pipeline.
|
|
4098
|
+
*
|
|
4099
|
+
* perf.startSession('render-1');
|
|
4100
|
+
* const t = perf.mark('viewport.run');
|
|
4101
|
+
* perf.measure('viewport.run', t);
|
|
4102
|
+
* perf.endSession();
|
|
4103
|
+
*
|
|
4104
|
+
* 2. `createPerfTimer` — per-module console logger factory.
|
|
4105
|
+
* Logs prefixed timings to the console AND records entries into the
|
|
4106
|
+
* active global session so they appear in `window.__gemxPerf` too.
|
|
4107
|
+
*
|
|
4108
|
+
* const timer = createPerfTimer('Render');
|
|
4109
|
+
* const t0 = timer.mark('start');
|
|
4110
|
+
* await timer.wrap('visualizer.html', () => visualizer.html(...));
|
|
4111
|
+
* timer.measure('total', t0);
|
|
4112
|
+
*/
|
|
4113
|
+
const s = {
|
|
4114
|
+
enabled: true,
|
|
4115
|
+
current: null,
|
|
4116
|
+
sessions: [],
|
|
4117
|
+
maxSessions: 20,
|
|
4118
|
+
};
|
|
4119
|
+
// ── Global singleton functions ────────────────────────────────────────────────
|
|
4120
|
+
function startSession(id) {
|
|
4121
|
+
if (!s.enabled)
|
|
4122
|
+
return;
|
|
4123
|
+
s.current = { id, startedAt: performance.now(), entries: [] };
|
|
4124
|
+
}
|
|
4125
|
+
function endSession() {
|
|
4126
|
+
if (!s.enabled || !s.current)
|
|
4127
|
+
return null;
|
|
4128
|
+
const session = s.current;
|
|
4129
|
+
session.total = performance.now() - session.startedAt;
|
|
4130
|
+
s.sessions = [session, ...s.sessions].slice(0, s.maxSessions);
|
|
4131
|
+
s.current = null;
|
|
4132
|
+
flush();
|
|
4133
|
+
return session;
|
|
4134
|
+
}
|
|
4135
|
+
/** Record a point-in-time mark. Returns `performance.now()` for use with measure(). */
|
|
4136
|
+
function globalMark(label) {
|
|
4137
|
+
const now = performance.now();
|
|
4138
|
+
if (s.enabled && s.current) {
|
|
4139
|
+
s.current.entries.push({ label, t: now - s.current.startedAt });
|
|
4140
|
+
}
|
|
4141
|
+
return now;
|
|
4142
|
+
}
|
|
4143
|
+
/** Record a duration from a previous mark() timestamp. */
|
|
4144
|
+
function globalMeasure(label, t0) {
|
|
4145
|
+
const duration = performance.now() - t0;
|
|
4146
|
+
if (s.enabled && s.current) {
|
|
4147
|
+
s.current.entries.push({ label, t: t0 - s.current.startedAt, duration });
|
|
4148
|
+
}
|
|
4149
|
+
return duration;
|
|
4150
|
+
}
|
|
4151
|
+
function getReport() {
|
|
4152
|
+
return {
|
|
4153
|
+
sessions: s.sessions,
|
|
4154
|
+
latest: s.sessions[0] ?? null,
|
|
4155
|
+
};
|
|
4156
|
+
}
|
|
4157
|
+
function clearSessions() {
|
|
4158
|
+
s.current = null;
|
|
4159
|
+
s.sessions = [];
|
|
4160
|
+
if (typeof window !== 'undefined')
|
|
4161
|
+
delete window.__gemxPerf;
|
|
4162
|
+
}
|
|
4163
|
+
function enableGlobal() {
|
|
4164
|
+
s.enabled = true;
|
|
4165
|
+
}
|
|
4166
|
+
function disableGlobal() {
|
|
4167
|
+
s.enabled = false;
|
|
4168
|
+
}
|
|
4169
|
+
function flush() {
|
|
4170
|
+
if (typeof window === 'undefined')
|
|
4171
|
+
return;
|
|
4172
|
+
window.__gemxPerf = getReport();
|
|
4173
|
+
}
|
|
4174
|
+
// ── Global singleton export ───────────────────────────────────────────────────
|
|
4175
|
+
const perf$3 = {
|
|
4176
|
+
startSession,
|
|
4177
|
+
endSession,
|
|
4178
|
+
mark: globalMark,
|
|
4179
|
+
measure: globalMeasure,
|
|
4180
|
+
getReport,
|
|
4181
|
+
clear: clearSessions,
|
|
4182
|
+
enable: enableGlobal,
|
|
4183
|
+
disable: disableGlobal,
|
|
4184
|
+
};
|
|
4185
|
+
// ── createPerfTimer factory ───────────────────────────────────────────────────
|
|
4186
|
+
function createPerfTimer(config) {
|
|
4187
|
+
let cfg = typeof config === 'string' ? { prefix: config, enabled: true } : { enabled: true, ...config };
|
|
4188
|
+
function log(icon, label, extra) {
|
|
4189
|
+
if (!cfg.enabled)
|
|
4190
|
+
return;
|
|
4191
|
+
const suffix = extra ? ` — ${extra}` : '';
|
|
4192
|
+
console.log(`[${cfg.prefix}] ${icon} ${label}${suffix}`);
|
|
4193
|
+
}
|
|
4194
|
+
return {
|
|
4195
|
+
configure(next) {
|
|
4196
|
+
cfg = { ...cfg, ...next };
|
|
4197
|
+
},
|
|
4198
|
+
mark(label) {
|
|
4199
|
+
const t = globalMark(`[${cfg.prefix}] ${label}`);
|
|
4200
|
+
log('⏱', label);
|
|
4201
|
+
return t;
|
|
4202
|
+
},
|
|
4203
|
+
measure(label, from) {
|
|
4204
|
+
globalMeasure(`[${cfg.prefix}] ${label}`, from);
|
|
4205
|
+
const ms = (performance.now() - from).toFixed(1);
|
|
4206
|
+
log('✅', label, `${ms}ms`);
|
|
4207
|
+
},
|
|
4208
|
+
async wrap(label, fn) {
|
|
4209
|
+
const t = globalMark(`[${cfg.prefix}] ${label}`);
|
|
4210
|
+
log('⏱', label);
|
|
4211
|
+
const result = await fn();
|
|
4212
|
+
const duration = globalMeasure(`[${cfg.prefix}] ${label}`, t);
|
|
4213
|
+
log('✅', label, `${duration.toFixed(1)}ms`);
|
|
4214
|
+
return result;
|
|
4215
|
+
},
|
|
4216
|
+
};
|
|
4217
|
+
}
|
|
4218
|
+
|
|
3907
4219
|
/**
|
|
3908
4220
|
* DOM observation setup — ResizeObserver + MutationObserver.
|
|
3909
4221
|
* Returns a cleanup function that disconnects both observers.
|
|
3910
4222
|
*/
|
|
3911
|
-
createLogger({ enabled: false, prefix: 'IframeHeightObserver' });
|
|
4223
|
+
const logger$2 = createLogger({ enabled: false, prefix: 'IframeHeightObserver' });
|
|
4224
|
+
function setup(doc, onChange) {
|
|
4225
|
+
const resizeObserver = new ResizeObserver(onChange);
|
|
4226
|
+
resizeObserver.observe(doc.documentElement);
|
|
4227
|
+
resizeObserver.observe(doc.body);
|
|
4228
|
+
const mutationObserver = new MutationObserver(onChange);
|
|
4229
|
+
mutationObserver.observe(doc.body, {
|
|
4230
|
+
childList: true,
|
|
4231
|
+
subtree: true,
|
|
4232
|
+
attributes: true,
|
|
4233
|
+
attributeFilter: ['style', 'class', 'hidden', 'data-v'],
|
|
4234
|
+
});
|
|
4235
|
+
logger$2.log('DOM observers started (ResizeObserver + MutationObserver)');
|
|
4236
|
+
return () => {
|
|
4237
|
+
resizeObserver.disconnect();
|
|
4238
|
+
mutationObserver.disconnect();
|
|
4239
|
+
logger$2.log('DOM observers disconnected');
|
|
4240
|
+
};
|
|
4241
|
+
}
|
|
3912
4242
|
|
|
3913
4243
|
/**
|
|
3914
4244
|
* Height Observer Processor
|
|
3915
4245
|
* Background observer — watches for iframe content height changes.
|
|
3916
4246
|
*/
|
|
3917
|
-
|
|
4247
|
+
// ── Module-level functions ────────────────────────────────────────────────────
|
|
4248
|
+
function clearTimers(s) {
|
|
4249
|
+
if (s.throttleTimeout) {
|
|
4250
|
+
clearTimeout(s.throttleTimeout);
|
|
4251
|
+
s.throttleTimeout = null;
|
|
4252
|
+
}
|
|
4253
|
+
if (s.debounceTimeout) {
|
|
4254
|
+
clearTimeout(s.debounceTimeout);
|
|
4255
|
+
s.debounceTimeout = null;
|
|
4256
|
+
}
|
|
4257
|
+
}
|
|
4258
|
+
function getActualHeight(s) {
|
|
4259
|
+
if (!s.iframe?.contentDocument)
|
|
4260
|
+
return 0;
|
|
4261
|
+
const { documentElement: docEl, body } = s.iframe.contentDocument;
|
|
4262
|
+
const heights = [docEl.scrollHeight, docEl.offsetHeight, body.scrollHeight, body.offsetHeight];
|
|
4263
|
+
const maxHeight = Math.max(...heights.filter((h) => h > 0));
|
|
4264
|
+
s.logger.log('Height sources:', {
|
|
4265
|
+
'documentElement.scrollHeight': docEl.scrollHeight,
|
|
4266
|
+
'documentElement.offsetHeight': docEl.offsetHeight,
|
|
4267
|
+
'body.scrollHeight': body.scrollHeight,
|
|
4268
|
+
'body.offsetHeight': body.offsetHeight,
|
|
4269
|
+
maxHeight,
|
|
4270
|
+
});
|
|
4271
|
+
return maxHeight;
|
|
4272
|
+
}
|
|
4273
|
+
async function processHeightChange(s, newHeight) {
|
|
4274
|
+
if (!s.iframe || !s.config)
|
|
4275
|
+
return;
|
|
4276
|
+
s.isProcessing = true;
|
|
4277
|
+
s.logger.log(`Processing height change: ${newHeight}px`);
|
|
4278
|
+
try {
|
|
4279
|
+
const result = {
|
|
4280
|
+
height: newHeight,
|
|
4281
|
+
width: s.iframe.contentWindow?.innerWidth ?? 0,
|
|
4282
|
+
};
|
|
4283
|
+
s.lastHeight = newHeight;
|
|
4284
|
+
s.logger.log('Height change processed:', result);
|
|
4285
|
+
s.config.onHeightChange?.(result);
|
|
4286
|
+
window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', { detail: result }));
|
|
4287
|
+
}
|
|
4288
|
+
catch (error) {
|
|
4289
|
+
s.logger.error('Failed to process height change:', error);
|
|
4290
|
+
s.config.onError?.(error);
|
|
4291
|
+
}
|
|
4292
|
+
finally {
|
|
4293
|
+
s.isProcessing = false;
|
|
4294
|
+
}
|
|
4295
|
+
}
|
|
4296
|
+
function handleHeightChange(s) {
|
|
4297
|
+
if (s.isProcessing || s.throttleTimeout)
|
|
4298
|
+
return;
|
|
4299
|
+
s.throttleTimeout = setTimeout(() => {
|
|
4300
|
+
s.throttleTimeout = null;
|
|
4301
|
+
const currentHeight = getActualHeight(s);
|
|
4302
|
+
if (currentHeight === s.lastHeight)
|
|
4303
|
+
return;
|
|
4304
|
+
s.logger.log(`Height changed: ${s.lastHeight}px -> ${currentHeight}px`);
|
|
4305
|
+
if (s.debounceTimeout)
|
|
4306
|
+
clearTimeout(s.debounceTimeout);
|
|
4307
|
+
s.debounceTimeout = setTimeout(() => {
|
|
4308
|
+
s.debounceTimeout = null;
|
|
4309
|
+
processHeightChange(s, currentHeight);
|
|
4310
|
+
}, s.debounceMs);
|
|
4311
|
+
}, s.throttleMs);
|
|
4312
|
+
}
|
|
4313
|
+
function observe(s) {
|
|
4314
|
+
if (!s.iframe?.contentDocument?.body) {
|
|
4315
|
+
s.logger.warn('Cannot observe height changes: iframe body not found');
|
|
4316
|
+
return;
|
|
4317
|
+
}
|
|
4318
|
+
s.observerCleanup?.();
|
|
4319
|
+
s.lastHeight = s.iframe.contentDocument.documentElement.scrollHeight;
|
|
4320
|
+
s.logger.log('Initial height:', s.lastHeight);
|
|
4321
|
+
s.observerCleanup = setup(s.iframe.contentDocument, () => handleHeightChange(s));
|
|
4322
|
+
}
|
|
4323
|
+
function start$5(s, cfg) {
|
|
4324
|
+
if (s.running) {
|
|
4325
|
+
s.logger.warn('Observer is already running. Call stop() first.');
|
|
4326
|
+
return;
|
|
4327
|
+
}
|
|
4328
|
+
s.iframe = cfg.iframe;
|
|
4329
|
+
s.config = cfg;
|
|
4330
|
+
s.throttleMs = cfg.throttleMs ?? 25;
|
|
4331
|
+
s.debounceMs = cfg.debounceMs ?? 500;
|
|
4332
|
+
s.running = true;
|
|
4333
|
+
observe(s);
|
|
4334
|
+
s.logger.log('Height observer started');
|
|
4335
|
+
}
|
|
4336
|
+
function stop$5(s) {
|
|
4337
|
+
if (!s.running)
|
|
4338
|
+
return;
|
|
4339
|
+
s.observerCleanup?.();
|
|
4340
|
+
s.observerCleanup = null;
|
|
4341
|
+
clearTimers(s);
|
|
4342
|
+
s.iframe = null;
|
|
4343
|
+
s.config = null;
|
|
4344
|
+
s.lastHeight = 0;
|
|
4345
|
+
s.isProcessing = false;
|
|
4346
|
+
s.running = false;
|
|
4347
|
+
s.logger.log('Height observer stopped');
|
|
4348
|
+
}
|
|
4349
|
+
function clear(s) {
|
|
4350
|
+
s.observerCleanup?.();
|
|
4351
|
+
s.observerCleanup = null;
|
|
4352
|
+
clearTimers(s);
|
|
4353
|
+
s.lastHeight = 0;
|
|
4354
|
+
s.isProcessing = false;
|
|
4355
|
+
}
|
|
4356
|
+
function updateConfig$3(s, cfg) {
|
|
4357
|
+
if (!s.running || !s.config) {
|
|
4358
|
+
s.logger.warn('Observer is not running.');
|
|
4359
|
+
return;
|
|
4360
|
+
}
|
|
4361
|
+
s.config = { ...s.config, ...cfg };
|
|
4362
|
+
if (cfg.throttleMs !== undefined)
|
|
4363
|
+
s.throttleMs = cfg.throttleMs;
|
|
4364
|
+
if (cfg.debounceMs !== undefined)
|
|
4365
|
+
s.debounceMs = cfg.debounceMs;
|
|
4366
|
+
s.logger.configure({ enabled: !!s.config.debug });
|
|
4367
|
+
s.logger.log('Config updated');
|
|
4368
|
+
}
|
|
4369
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
4370
|
+
function createHeightObserver() {
|
|
4371
|
+
const s = {
|
|
4372
|
+
logger: createLogger({ enabled: true, prefix: 'IframeHeightObserver' }),
|
|
4373
|
+
iframe: null,
|
|
4374
|
+
config: null,
|
|
4375
|
+
observerCleanup: null,
|
|
4376
|
+
lastHeight: 0,
|
|
4377
|
+
throttleTimeout: null,
|
|
4378
|
+
debounceTimeout: null,
|
|
4379
|
+
isProcessing: false,
|
|
4380
|
+
throttleMs: 25,
|
|
4381
|
+
debounceMs: 500,
|
|
4382
|
+
running: false,
|
|
4383
|
+
};
|
|
4384
|
+
return {
|
|
4385
|
+
start: (cfg) => start$5(s, cfg),
|
|
4386
|
+
stop: () => stop$5(s),
|
|
4387
|
+
observe: () => observe(s),
|
|
4388
|
+
clear: () => clear(s),
|
|
4389
|
+
updateConfig: (cfg) => updateConfig$3(s, cfg),
|
|
4390
|
+
getCurrentHeight: () => s.lastHeight,
|
|
4391
|
+
isRunning: () => s.running,
|
|
4392
|
+
getStateInfo: () => ({
|
|
4393
|
+
isRunning: s.running,
|
|
4394
|
+
lastHeight: s.lastHeight,
|
|
4395
|
+
isProcessing: s.isProcessing,
|
|
4396
|
+
hasObservers: !!s.observerCleanup,
|
|
4397
|
+
}),
|
|
4398
|
+
};
|
|
4399
|
+
}
|
|
4400
|
+
|
|
4401
|
+
/**
|
|
4402
|
+
* Window-level event management for the navigation processor.
|
|
4403
|
+
*
|
|
4404
|
+
* Responsibilities:
|
|
4405
|
+
* - Subscribe to events dispatched by this processor (for logging/hooks)
|
|
4406
|
+
* - Dispatch navigation events to the parent window
|
|
4407
|
+
*/
|
|
4408
|
+
// ── Module-level functions ────────────────────────────────────────────────────
|
|
4409
|
+
function attach$1(s, debug) {
|
|
4410
|
+
s.logger.configure({ enabled: !!debug });
|
|
4411
|
+
s.navigationBlockedListener = (e) => {
|
|
4412
|
+
const ev = e;
|
|
4413
|
+
s.logger.log('Navigation blocked:', ev.detail.url);
|
|
4414
|
+
};
|
|
4415
|
+
s.formSubmitWindowListener = (e) => {
|
|
4416
|
+
const ev = e;
|
|
4417
|
+
s.logger.log('Form submitted:', ev.detail.data);
|
|
4418
|
+
};
|
|
4419
|
+
window.addEventListener('iframe-navigation-blocked', s.navigationBlockedListener);
|
|
4420
|
+
window.addEventListener('iframe-form-submit', s.formSubmitWindowListener);
|
|
4421
|
+
}
|
|
4422
|
+
function detach$1(s) {
|
|
4423
|
+
if (s.navigationBlockedListener) {
|
|
4424
|
+
window.removeEventListener('iframe-navigation-blocked', s.navigationBlockedListener);
|
|
4425
|
+
s.navigationBlockedListener = null;
|
|
4426
|
+
}
|
|
4427
|
+
if (s.formSubmitWindowListener) {
|
|
4428
|
+
window.removeEventListener('iframe-form-submit', s.formSubmitWindowListener);
|
|
4429
|
+
s.formSubmitWindowListener = null;
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
function dispatchBlocked(url, showMessage) {
|
|
4433
|
+
if (showMessage)
|
|
4434
|
+
alert(`Navigation blocked: ${url}`);
|
|
4435
|
+
window.dispatchEvent(new CustomEvent('iframe-navigation-blocked', { detail: { url } }));
|
|
4436
|
+
}
|
|
4437
|
+
function dispatchFormSubmit(form, data) {
|
|
4438
|
+
window.dispatchEvent(new CustomEvent('iframe-form-submit', { detail: { form, data } }));
|
|
4439
|
+
}
|
|
4440
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
4441
|
+
function createNavigationListeners() {
|
|
4442
|
+
const s = {
|
|
4443
|
+
logger: createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' }),
|
|
4444
|
+
navigationBlockedListener: null,
|
|
4445
|
+
formSubmitWindowListener: null,
|
|
4446
|
+
};
|
|
4447
|
+
return {
|
|
4448
|
+
attach: (debug) => attach$1(s, debug),
|
|
4449
|
+
detach: () => detach$1(s),
|
|
4450
|
+
dispatchBlocked,
|
|
4451
|
+
dispatchFormSubmit,
|
|
4452
|
+
};
|
|
4453
|
+
}
|
|
3918
4454
|
|
|
3919
|
-
const logger$
|
|
4455
|
+
const logger$1 = createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' });
|
|
3920
4456
|
function configure$1(debug) {
|
|
3921
|
-
logger$
|
|
4457
|
+
logger$1.configure({ enabled: debug });
|
|
3922
4458
|
}
|
|
3923
4459
|
// ─── DOM Utilities ────────────────────────────────────────────────────────────
|
|
3924
4460
|
function disableAllLinks(doc) {
|
|
@@ -3942,10 +4478,10 @@ function setupLinkBlocker(doc, isEnabled, onBlocked) {
|
|
|
3942
4478
|
return;
|
|
3943
4479
|
const href = link.getAttribute('href');
|
|
3944
4480
|
if (!href || href === '' || href === '#' || href.startsWith('#')) {
|
|
3945
|
-
logger$
|
|
4481
|
+
logger$1.log('Allowed hash navigation:', href);
|
|
3946
4482
|
return;
|
|
3947
4483
|
}
|
|
3948
|
-
logger$
|
|
4484
|
+
logger$1.log('Blocked link navigation to:', href);
|
|
3949
4485
|
e.preventDefault();
|
|
3950
4486
|
e.stopPropagation();
|
|
3951
4487
|
e.stopImmediatePropagation();
|
|
@@ -3959,7 +4495,7 @@ function setupLinkBlocker(doc, isEnabled, onBlocked) {
|
|
|
3959
4495
|
return;
|
|
3960
4496
|
const href = link.getAttribute('href');
|
|
3961
4497
|
if (href && !href.startsWith('#')) {
|
|
3962
|
-
logger$
|
|
4498
|
+
logger$1.log('Blocked auxclick navigation');
|
|
3963
4499
|
e.preventDefault();
|
|
3964
4500
|
e.stopPropagation();
|
|
3965
4501
|
e.stopImmediatePropagation();
|
|
@@ -3980,7 +4516,7 @@ function setupFormBlocker(doc, isEnabled, onBlocked, onFormSubmit) {
|
|
|
3980
4516
|
const form = e.target;
|
|
3981
4517
|
const action = form.getAttribute('action');
|
|
3982
4518
|
if (!action || action === '' || action === '#') {
|
|
3983
|
-
logger$
|
|
4519
|
+
logger$1.log('Allowed same-page form');
|
|
3984
4520
|
e.preventDefault();
|
|
3985
4521
|
const data = {};
|
|
3986
4522
|
new FormData(form).forEach((value, key) => {
|
|
@@ -3989,7 +4525,7 @@ function setupFormBlocker(doc, isEnabled, onBlocked, onFormSubmit) {
|
|
|
3989
4525
|
onFormSubmit(form, data);
|
|
3990
4526
|
return;
|
|
3991
4527
|
}
|
|
3992
|
-
logger$
|
|
4528
|
+
logger$1.log('Blocked form submission to:', action);
|
|
3993
4529
|
e.preventDefault();
|
|
3994
4530
|
e.stopPropagation();
|
|
3995
4531
|
e.stopImmediatePropagation();
|
|
@@ -4003,7 +4539,7 @@ function setupWindowOpenBlocker(win, originalOpen, isEnabled, onBlocked) {
|
|
|
4003
4539
|
if (!isEnabled())
|
|
4004
4540
|
return originalOpen(...args);
|
|
4005
4541
|
const url = args[0]?.toString() || 'popup';
|
|
4006
|
-
logger$
|
|
4542
|
+
logger$1.log('Blocked window.open:', url);
|
|
4007
4543
|
onBlocked(url);
|
|
4008
4544
|
return null;
|
|
4009
4545
|
});
|
|
@@ -4015,14 +4551,14 @@ function setupUnloadBlocker(win, isEnabled) {
|
|
|
4015
4551
|
const beforeUnloadListener = (e) => {
|
|
4016
4552
|
if (!isEnabled())
|
|
4017
4553
|
return;
|
|
4018
|
-
logger$
|
|
4554
|
+
logger$1.log('Blocked beforeunload');
|
|
4019
4555
|
e.preventDefault();
|
|
4020
4556
|
e.returnValue = '';
|
|
4021
4557
|
};
|
|
4022
4558
|
const unloadListener = (e) => {
|
|
4023
4559
|
if (!isEnabled())
|
|
4024
4560
|
return;
|
|
4025
|
-
logger$
|
|
4561
|
+
logger$1.log('Blocked unload');
|
|
4026
4562
|
e.preventDefault();
|
|
4027
4563
|
e.stopPropagation();
|
|
4028
4564
|
};
|
|
@@ -4039,65 +4575,14 @@ function setupDOMMonitor(doc) {
|
|
|
4039
4575
|
return () => observer.disconnect();
|
|
4040
4576
|
}
|
|
4041
4577
|
|
|
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
4578
|
/**
|
|
4088
4579
|
* Navigation Processor
|
|
4089
4580
|
* Continuous guard — blocks all navigation attempts within the iframe.
|
|
4090
4581
|
*/
|
|
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.');
|
|
4582
|
+
// ── Module-level functions ────────────────────────────────────────────────────
|
|
4583
|
+
function start$4(s, iframe, cfg) {
|
|
4584
|
+
if (s.running) {
|
|
4585
|
+
s.logger.warn('Blocker is already running. Call stop() first.');
|
|
4101
4586
|
return;
|
|
4102
4587
|
}
|
|
4103
4588
|
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
@@ -4106,76 +4591,114 @@ function start$5(iframe, cfg) {
|
|
|
4106
4591
|
const doc = iframe.contentDocument;
|
|
4107
4592
|
const win = iframe.contentWindow;
|
|
4108
4593
|
const originalOpen = win.open.bind(win);
|
|
4109
|
-
logger
|
|
4594
|
+
s.logger.configure({ enabled: !!cfg?.debug });
|
|
4110
4595
|
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),
|
|
4596
|
+
s.cleanups = [
|
|
4597
|
+
setupLinkBlocker(doc, () => s.isEnabled, (url) => s.listeners.dispatchBlocked(url, s.showMessage)),
|
|
4598
|
+
setupFormBlocker(doc, () => s.isEnabled, (url) => s.listeners.dispatchBlocked(url, s.showMessage), s.listeners.dispatchFormSubmit),
|
|
4599
|
+
setupWindowOpenBlocker(win, originalOpen, () => s.isEnabled, (url) => s.listeners.dispatchBlocked(url, s.showMessage)),
|
|
4600
|
+
setupUnloadBlocker(win, () => s.isEnabled),
|
|
4116
4601
|
setupDOMMonitor(doc),
|
|
4117
4602
|
];
|
|
4118
|
-
attach
|
|
4119
|
-
running
|
|
4120
|
-
logger
|
|
4603
|
+
s.listeners.attach(cfg?.debug);
|
|
4604
|
+
s.running = true;
|
|
4605
|
+
s.logger.log('Started');
|
|
4121
4606
|
}
|
|
4122
|
-
function stop$
|
|
4123
|
-
if (!running
|
|
4607
|
+
function stop$4(s) {
|
|
4608
|
+
if (!s.running)
|
|
4124
4609
|
return;
|
|
4125
|
-
cleanups.forEach((fn) => fn());
|
|
4126
|
-
cleanups = [];
|
|
4127
|
-
detach
|
|
4128
|
-
isEnabled = false;
|
|
4129
|
-
showMessage = false;
|
|
4130
|
-
running
|
|
4131
|
-
logger
|
|
4132
|
-
}
|
|
4133
|
-
function enable() {
|
|
4134
|
-
if (!running
|
|
4135
|
-
logger
|
|
4610
|
+
s.cleanups.forEach((fn) => fn());
|
|
4611
|
+
s.cleanups = [];
|
|
4612
|
+
s.listeners.detach();
|
|
4613
|
+
s.isEnabled = false;
|
|
4614
|
+
s.showMessage = false;
|
|
4615
|
+
s.running = false;
|
|
4616
|
+
s.logger.log('Stopped');
|
|
4617
|
+
}
|
|
4618
|
+
function enable(s) {
|
|
4619
|
+
if (!s.running) {
|
|
4620
|
+
s.logger.warn('Blocker is not running.');
|
|
4621
|
+
return;
|
|
4622
|
+
}
|
|
4623
|
+
s.isEnabled = true;
|
|
4624
|
+
s.logger.log('Navigation blocking enabled');
|
|
4625
|
+
}
|
|
4626
|
+
function disable(s) {
|
|
4627
|
+
if (!s.running) {
|
|
4628
|
+
s.logger.warn('Blocker is not running.');
|
|
4629
|
+
return;
|
|
4630
|
+
}
|
|
4631
|
+
s.isEnabled = false;
|
|
4632
|
+
s.logger.log('Navigation blocking disabled');
|
|
4633
|
+
}
|
|
4634
|
+
function enableMessage(s) {
|
|
4635
|
+
if (!s.running) {
|
|
4636
|
+
s.logger.warn('Blocker is not running.');
|
|
4637
|
+
return;
|
|
4638
|
+
}
|
|
4639
|
+
s.showMessage = true;
|
|
4640
|
+
s.logger.log('Navigation blocking message enabled');
|
|
4641
|
+
}
|
|
4642
|
+
function disableMessage(s) {
|
|
4643
|
+
if (!s.running) {
|
|
4644
|
+
s.logger.warn('Blocker is not running.');
|
|
4136
4645
|
return;
|
|
4137
4646
|
}
|
|
4138
|
-
|
|
4139
|
-
logger
|
|
4647
|
+
s.showMessage = false;
|
|
4648
|
+
s.logger.log('Navigation blocking message disabled');
|
|
4649
|
+
}
|
|
4650
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
4651
|
+
function createNavigationBlocker() {
|
|
4652
|
+
const s = {
|
|
4653
|
+
logger: createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' }),
|
|
4654
|
+
listeners: createNavigationListeners(),
|
|
4655
|
+
isEnabled: false,
|
|
4656
|
+
showMessage: false,
|
|
4657
|
+
running: false,
|
|
4658
|
+
cleanups: [],
|
|
4659
|
+
};
|
|
4660
|
+
return {
|
|
4661
|
+
start: (iframe, cfg) => start$4(s, iframe, cfg),
|
|
4662
|
+
stop: () => stop$4(s),
|
|
4663
|
+
enable: () => enable(s),
|
|
4664
|
+
disable: () => disable(s),
|
|
4665
|
+
enableMessage: () => enableMessage(s),
|
|
4666
|
+
disableMessage: () => disableMessage(s),
|
|
4667
|
+
isRunning: () => s.running,
|
|
4668
|
+
isBlockingEnabled: () => s.isEnabled,
|
|
4669
|
+
getStateInfo: () => ({ isRunning: s.running, isEnabled: s.isEnabled, showMessage: s.showMessage }),
|
|
4670
|
+
};
|
|
4140
4671
|
}
|
|
4141
4672
|
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4673
|
+
// ── Module-level functions ────────────────────────────────────────────────────
|
|
4674
|
+
function attach(s, debug) {
|
|
4675
|
+
s.logger.configure({ enabled: !!debug });
|
|
4676
|
+
s.dimensionsListener = (e) => {
|
|
4677
|
+
// const ev = e as CustomEvent<IframeDimensionsDetail>;
|
|
4678
|
+
// s.logger.log('Dimensions applied:', ev.detail);
|
|
4679
|
+
};
|
|
4680
|
+
window.addEventListener('iframe-dimensions-applied', s.dimensionsListener);
|
|
4149
4681
|
}
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4682
|
+
function detach(s) {
|
|
4683
|
+
if (s.dimensionsListener) {
|
|
4684
|
+
window.removeEventListener('iframe-dimensions-applied', s.dimensionsListener);
|
|
4685
|
+
s.dimensionsListener = null;
|
|
4686
|
+
}
|
|
4687
|
+
}
|
|
4688
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
4689
|
+
function createViewportListeners() {
|
|
4690
|
+
const s = {
|
|
4691
|
+
logger: createLogger({ enabled: false, prefix: 'ViewportReplacer' }),
|
|
4692
|
+
dimensionsListener: null,
|
|
4693
|
+
};
|
|
4694
|
+
return {
|
|
4695
|
+
attach: (debug) => attach(s, debug),
|
|
4696
|
+
detach: () => detach(s),
|
|
4697
|
+
};
|
|
4163
4698
|
}
|
|
4164
4699
|
|
|
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
4700
|
const DEFAULT_TOLERANCE_PX = 5;
|
|
4178
|
-
const VIEWPORT_UNIT_REGEX = /([
|
|
4701
|
+
const VIEWPORT_UNIT_REGEX = /([-.\\d]+)(vh|svh|lvh|dvh|%)/gi;
|
|
4179
4702
|
const DEFAULT_CSS_VALUES = ['none', 'auto', 'normal', '0px'];
|
|
4180
4703
|
const CRITICAL_PROPERTIES = [
|
|
4181
4704
|
'display',
|
|
@@ -4212,424 +4735,216 @@ const CRITICAL_PROPERTIES = [
|
|
|
4212
4735
|
'grid-template-rows',
|
|
4213
4736
|
'gap',
|
|
4214
4737
|
];
|
|
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) {
|
|
4738
|
+
|
|
4739
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
4740
|
+
function getViewportUnitMap(s) {
|
|
4741
|
+
if (!s.config)
|
|
4232
4742
|
throw new Error('Config is not initialized');
|
|
4233
|
-
}
|
|
4234
4743
|
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
|
|
4744
|
+
vh: s.config.targetHeight,
|
|
4745
|
+
svh: s.config.targetHeight,
|
|
4746
|
+
lvh: s.config.targetHeight,
|
|
4747
|
+
dvh: s.config.targetHeight,
|
|
4748
|
+
vw: s.config.targetWidth,
|
|
4749
|
+
svw: s.config.targetWidth,
|
|
4750
|
+
lvw: s.config.targetWidth,
|
|
4751
|
+
dvw: s.config.targetWidth,
|
|
4243
4752
|
};
|
|
4244
4753
|
}
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
*/
|
|
4248
|
-
function calculateExpectedPx(value, unit) {
|
|
4249
|
-
if (!config$2) {
|
|
4754
|
+
function calculateExpectedPx(s, value, unit) {
|
|
4755
|
+
if (!s.config)
|
|
4250
4756
|
throw new Error('Config is not initialized');
|
|
4251
|
-
}
|
|
4252
4757
|
const unitLower = unit.toLowerCase();
|
|
4253
|
-
if (unitLower === '%')
|
|
4254
|
-
return (value / 100) * config
|
|
4255
|
-
|
|
4256
|
-
const unitMap = getViewportUnitMap();
|
|
4257
|
-
return (value / 100) * (unitMap[unitLower] || 0);
|
|
4758
|
+
if (unitLower === '%')
|
|
4759
|
+
return (value / 100) * s.config.targetHeight;
|
|
4760
|
+
return (value / 100) * (getViewportUnitMap(s)[unitLower] || 0);
|
|
4258
4761
|
}
|
|
4259
|
-
/**
|
|
4260
|
-
* Check if a CSS value is a default/initial value that should be skipped
|
|
4261
|
-
*/
|
|
4262
4762
|
function isDefaultCssValue(value) {
|
|
4263
4763
|
return DEFAULT_CSS_VALUES.includes(value);
|
|
4264
4764
|
}
|
|
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) {
|
|
4765
|
+
function shouldReplaceValue(s, computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
|
|
4766
|
+
if (!s.config)
|
|
4272
4767
|
return false;
|
|
4273
|
-
}
|
|
4274
|
-
// Parse computed value (should be in px)
|
|
4275
4768
|
const computedPx = parseFloat(computedValue);
|
|
4276
|
-
if (isNaN(computedPx))
|
|
4277
|
-
return false;
|
|
4278
|
-
}
|
|
4279
|
-
// Parse original value to check what it should be
|
|
4769
|
+
if (isNaN(computedPx))
|
|
4770
|
+
return false;
|
|
4280
4771
|
const regex = new RegExp(VIEWPORT_UNIT_REGEX.source, VIEWPORT_UNIT_REGEX.flags);
|
|
4281
4772
|
const match = originalValue.match(regex);
|
|
4282
|
-
if (!match)
|
|
4283
|
-
return false;
|
|
4284
|
-
}
|
|
4773
|
+
if (!match)
|
|
4774
|
+
return false;
|
|
4285
4775
|
const [, value, unit] = match;
|
|
4286
4776
|
const num = parseFloat(value);
|
|
4287
|
-
if (isNaN(num))
|
|
4777
|
+
if (isNaN(num))
|
|
4288
4778
|
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)
|
|
4779
|
+
const expectedPx = calculateExpectedPx(s, num, unit);
|
|
4293
4780
|
const diff = Math.abs(computedPx - expectedPx);
|
|
4294
4781
|
if (diff <= tolerance) {
|
|
4295
|
-
|
|
4296
|
-
logger$5.log(`OK to replace: computed=${computedValue} matches expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
|
|
4782
|
+
s.logger.log(`OK to replace: computed=${computedValue} matches expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
|
|
4297
4783
|
return true;
|
|
4298
4784
|
}
|
|
4299
|
-
|
|
4300
|
-
logger$5.log(`Skip replace: computed=${computedValue} differs from expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px) - keeping current value`);
|
|
4785
|
+
s.logger.log(`Skip replace: computed=${computedValue} differs from expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
|
|
4301
4786
|
return false;
|
|
4302
4787
|
}
|
|
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)) {
|
|
4788
|
+
function applyPropertyWithVerification(s, element, prop, computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
|
|
4789
|
+
if (originalValue && shouldReplaceValue(s, computedValue, originalValue, tolerance)) {
|
|
4309
4790
|
element.style.setProperty(prop, computedValue, 'important');
|
|
4310
4791
|
return true;
|
|
4311
4792
|
}
|
|
4312
4793
|
else if (!originalValue) {
|
|
4313
|
-
// No original value tracked, use old behavior
|
|
4314
4794
|
element.style.setProperty(prop, computedValue, 'important');
|
|
4315
4795
|
return true;
|
|
4316
4796
|
}
|
|
4317
4797
|
return false;
|
|
4318
4798
|
}
|
|
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.');
|
|
4799
|
+
// ── Exported module-level functions ───────────────────────────────────────────
|
|
4800
|
+
function start$3(s, d, w, cfg, options = {}) {
|
|
4801
|
+
if (s.running) {
|
|
4802
|
+
s.logger.warn('Enforcer is already running. Call stop() first.');
|
|
4329
4803
|
return;
|
|
4330
4804
|
}
|
|
4331
|
-
doc
|
|
4332
|
-
win
|
|
4333
|
-
config
|
|
4334
|
-
running
|
|
4335
|
-
logger
|
|
4336
|
-
logger
|
|
4805
|
+
s.doc = d;
|
|
4806
|
+
s.win = w;
|
|
4807
|
+
s.config = cfg;
|
|
4808
|
+
s.running = true;
|
|
4809
|
+
s.logger.configure({ enabled: !!options.debug });
|
|
4810
|
+
s.logger.log('Started');
|
|
4337
4811
|
}
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4812
|
+
function stop$3(s) {
|
|
4813
|
+
if (!s.running)
|
|
4814
|
+
return;
|
|
4815
|
+
s.doc = null;
|
|
4816
|
+
s.win = null;
|
|
4817
|
+
s.config = null;
|
|
4818
|
+
s.elementsWithViewportUnits.clear();
|
|
4819
|
+
s.originalValues = new WeakMap();
|
|
4820
|
+
s.running = false;
|
|
4821
|
+
s.logger.log('Stopped');
|
|
4822
|
+
}
|
|
4823
|
+
function reset(s) {
|
|
4824
|
+
if (!s.running) {
|
|
4825
|
+
s.logger.warn('Enforcer is not running. Call start() first.');
|
|
4343
4826
|
return;
|
|
4344
4827
|
}
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
elementsWithViewportUnits$1.clear();
|
|
4349
|
-
originalValues$1 = new WeakMap();
|
|
4350
|
-
running$3 = false;
|
|
4351
|
-
logger$5.log('Computed style enforcer stopped');
|
|
4828
|
+
s.elementsWithViewportUnits.clear();
|
|
4829
|
+
s.originalValues = new WeakMap();
|
|
4830
|
+
s.logger.log('Reset');
|
|
4352
4831
|
}
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
*/
|
|
4357
|
-
function trackElement(element, propertyOriginalValues) {
|
|
4358
|
-
if (!running$3) {
|
|
4359
|
-
logger$5.warn('Enforcer is not running. Call start() first.');
|
|
4832
|
+
function trackElement(s, element, propertyOriginalValues) {
|
|
4833
|
+
if (!s.running) {
|
|
4834
|
+
s.logger.warn('Enforcer is not running. Call start() first.');
|
|
4360
4835
|
return;
|
|
4361
4836
|
}
|
|
4362
|
-
elementsWithViewportUnits
|
|
4363
|
-
|
|
4364
|
-
let elementOriginals = originalValues$1.get(element);
|
|
4837
|
+
s.elementsWithViewportUnits.add(element);
|
|
4838
|
+
let elementOriginals = s.originalValues.get(element);
|
|
4365
4839
|
if (!elementOriginals) {
|
|
4366
4840
|
elementOriginals = new Map();
|
|
4367
|
-
originalValues
|
|
4841
|
+
s.originalValues.set(element, elementOriginals);
|
|
4368
4842
|
}
|
|
4369
|
-
// Merge property original values (don't override existing)
|
|
4370
4843
|
propertyOriginalValues.forEach((value, prop) => {
|
|
4371
|
-
if (!elementOriginals.has(prop))
|
|
4844
|
+
if (!elementOriginals.has(prop))
|
|
4372
4845
|
elementOriginals.set(prop, value);
|
|
4373
|
-
}
|
|
4374
4846
|
});
|
|
4375
4847
|
}
|
|
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.');
|
|
4848
|
+
function processElement(s, element, options = {}) {
|
|
4849
|
+
if (!s.running || !s.doc || !s.win || !s.config) {
|
|
4850
|
+
s.logger.warn('Enforcer is not running.');
|
|
4382
4851
|
return 0;
|
|
4383
4852
|
}
|
|
4384
|
-
if (!elementsWithViewportUnits
|
|
4853
|
+
if (!s.elementsWithViewportUnits.has(element))
|
|
4385
4854
|
return 0;
|
|
4386
|
-
}
|
|
4387
4855
|
const htmlElement = element;
|
|
4388
|
-
const computed = win
|
|
4856
|
+
const computed = s.win.getComputedStyle(htmlElement);
|
|
4389
4857
|
const inlineStyle = htmlElement.style;
|
|
4390
|
-
const elementOriginals = originalValues
|
|
4858
|
+
const elementOriginals = s.originalValues.get(element);
|
|
4391
4859
|
const tolerance = options.tolerance ?? DEFAULT_TOLERANCE_PX;
|
|
4392
4860
|
let count = 0;
|
|
4393
4861
|
CRITICAL_PROPERTIES.forEach((prop) => {
|
|
4394
4862
|
const computedValue = computed.getPropertyValue(prop);
|
|
4395
4863
|
const inlineValue = inlineStyle.getPropertyValue(prop);
|
|
4396
|
-
if (computedValue && (!inlineValue || inlineValue !== computedValue)) {
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
count++;
|
|
4401
|
-
}
|
|
4402
|
-
}
|
|
4864
|
+
if (computedValue && (!inlineValue || inlineValue !== computedValue) && !isDefaultCssValue(computedValue)) {
|
|
4865
|
+
const originalValue = elementOriginals?.get(prop) || '';
|
|
4866
|
+
if (applyPropertyWithVerification(s, htmlElement, prop, computedValue, originalValue, tolerance))
|
|
4867
|
+
count++;
|
|
4403
4868
|
}
|
|
4404
4869
|
});
|
|
4405
4870
|
return count;
|
|
4406
4871
|
}
|
|
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.');
|
|
4872
|
+
function processAll(s, options = {}) {
|
|
4873
|
+
if (!s.running || !s.doc || !s.win || !s.config) {
|
|
4874
|
+
s.logger.warn('Enforcer is not running.');
|
|
4414
4875
|
return 0;
|
|
4415
4876
|
}
|
|
4416
4877
|
let totalCount = 0;
|
|
4417
|
-
elementsWithViewportUnits
|
|
4418
|
-
totalCount += processElement(element, options);
|
|
4878
|
+
s.elementsWithViewportUnits.forEach((element) => {
|
|
4879
|
+
totalCount += processElement(s, element, options);
|
|
4419
4880
|
});
|
|
4420
|
-
logger
|
|
4881
|
+
s.logger.log(`Enforced ${totalCount} computed styles for ${s.elementsWithViewportUnits.size} elements`);
|
|
4421
4882
|
return totalCount;
|
|
4422
4883
|
}
|
|
4884
|
+
function updateConfig$2(s, cfg) {
|
|
4885
|
+
if (!s.running || !s.config) {
|
|
4886
|
+
s.logger.warn('Enforcer is not running.');
|
|
4887
|
+
return;
|
|
4888
|
+
}
|
|
4889
|
+
s.config = { ...s.config, ...cfg };
|
|
4890
|
+
s.logger.log('Config updated:', cfg);
|
|
4891
|
+
}
|
|
4423
4892
|
|
|
4424
4893
|
/**
|
|
4425
|
-
*
|
|
4426
|
-
*
|
|
4894
|
+
* Computed Style Enforcer
|
|
4895
|
+
* Enforces computed CSS styles with viewport unit verification.
|
|
4427
4896
|
*/
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
const
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
}
|
|
4439
|
-
// ─── Unit conversion ─────────────────────────────────────────────────────────
|
|
4440
|
-
function px(value) {
|
|
4441
|
-
return `${value.toFixed(2)}px`;
|
|
4442
|
-
}
|
|
4443
|
-
function getUnitMap(ctx) {
|
|
4897
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
4898
|
+
function createEnforcer() {
|
|
4899
|
+
const s = {
|
|
4900
|
+
logger: createLogger({ enabled: false, prefix: 'ComputedStyleEnforcer' }),
|
|
4901
|
+
doc: null,
|
|
4902
|
+
win: null,
|
|
4903
|
+
config: null,
|
|
4904
|
+
elementsWithViewportUnits: new Set(),
|
|
4905
|
+
originalValues: new WeakMap(),
|
|
4906
|
+
running: false,
|
|
4907
|
+
};
|
|
4444
4908
|
return {
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4909
|
+
start: (d, w, cfg, options) => start$3(s, d, w, cfg, options),
|
|
4910
|
+
stop: () => stop$3(s),
|
|
4911
|
+
reset: () => reset(s),
|
|
4912
|
+
trackElement: (element, propertyOriginalValues) => trackElement(s, element, propertyOriginalValues),
|
|
4913
|
+
processElement: (element, options) => processElement(s, element, options),
|
|
4914
|
+
processAll: (options) => processAll(s, options),
|
|
4915
|
+
updateConfig: (cfg) => updateConfig$2(s, cfg),
|
|
4916
|
+
getStateInfo: () => ({
|
|
4917
|
+
isRunning: s.running,
|
|
4918
|
+
trackedElementsCount: s.elementsWithViewportUnits.size,
|
|
4919
|
+
hasConfig: !!s.config,
|
|
4920
|
+
}),
|
|
4921
|
+
isRunning: () => s.running,
|
|
4453
4922
|
};
|
|
4454
4923
|
}
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
}
|
|
4461
|
-
function convert(value, unit, ctx) {
|
|
4462
|
-
const num = parseFloat(value);
|
|
4463
|
-
return isNaN(num) ? value : px(toPx(num, unit, ctx));
|
|
4464
|
-
}
|
|
4465
|
-
function isHeightRelated(prop) {
|
|
4466
|
-
return HEIGHT_RELATED_PROPERTIES.includes(prop);
|
|
4467
|
-
}
|
|
4468
|
-
/**
|
|
4469
|
-
* Use `matchOffset` (from replace() callback) instead of indexOf to get the
|
|
4470
|
-
* exact position of the current match — avoids false matches for duplicate values.
|
|
4924
|
+
|
|
4925
|
+
const registry$1 = [];
|
|
4926
|
+
/**
|
|
4927
|
+
* Register a global fix.
|
|
4928
|
+
* Fixes are run in registration order.
|
|
4471
4929
|
*/
|
|
4472
|
-
function
|
|
4473
|
-
|
|
4474
|
-
const m = before.match(/([a-z-]+)\s*:\s*[^;{}]*$/i);
|
|
4475
|
-
return m ? m[1].toLowerCase() : '';
|
|
4476
|
-
}
|
|
4477
|
-
function replaceInText(cssText, ctx) {
|
|
4478
|
-
return cssText.replace(createRegex(), (match, value, unit, offset) => {
|
|
4479
|
-
if (unit === '%') {
|
|
4480
|
-
return isHeightRelated(extractProperty(cssText, offset)) ? convert(value, unit, ctx) : match;
|
|
4481
|
-
}
|
|
4482
|
-
return convert(value, unit, ctx);
|
|
4483
|
-
});
|
|
4484
|
-
}
|
|
4485
|
-
// ─── Element tracking ─────────────────────────────────────────────────────────
|
|
4486
|
-
function trackSelector(selector, propOriginals, ctx) {
|
|
4487
|
-
try {
|
|
4488
|
-
ctx.doc.querySelectorAll(selector).forEach((el) => {
|
|
4489
|
-
elementsWithViewportUnits.add(el);
|
|
4490
|
-
let originals = originalValues.get(el);
|
|
4491
|
-
if (!originals) {
|
|
4492
|
-
originals = new Map();
|
|
4493
|
-
originalValues.set(el, originals);
|
|
4494
|
-
}
|
|
4495
|
-
propOriginals.forEach((v, k) => {
|
|
4496
|
-
if (!originals.has(k))
|
|
4497
|
-
originals.set(k, v);
|
|
4498
|
-
});
|
|
4499
|
-
trackElement(el, propOriginals);
|
|
4500
|
-
});
|
|
4501
|
-
}
|
|
4502
|
-
catch {
|
|
4503
|
-
logger$4.warn('Invalid selector, skipping:', selector);
|
|
4504
|
-
}
|
|
4505
|
-
}
|
|
4506
|
-
// ─── CSS processing ───────────────────────────────────────────────────────────
|
|
4507
|
-
function processInlineStyles(ctx) {
|
|
4508
|
-
let count = 0;
|
|
4509
|
-
ctx.doc.querySelectorAll('[style]').forEach((el) => {
|
|
4510
|
-
const style = el.getAttribute('style');
|
|
4511
|
-
if (style && createRegex().test(style)) {
|
|
4512
|
-
elementsWithViewportUnits.add(el);
|
|
4513
|
-
el.setAttribute('style', replaceInText(style, ctx));
|
|
4514
|
-
count++;
|
|
4515
|
-
}
|
|
4516
|
-
});
|
|
4517
|
-
logger$4.log(`Replaced ${count} inline style elements`);
|
|
4518
|
-
return count;
|
|
4519
|
-
}
|
|
4520
|
-
function processStyleTags(ctx) {
|
|
4521
|
-
let count = 0;
|
|
4522
|
-
ctx.doc.querySelectorAll('style').forEach((tag) => {
|
|
4523
|
-
const css = tag.textContent || '';
|
|
4524
|
-
if (createRegex().test(css)) {
|
|
4525
|
-
tag.textContent = replaceInText(css, ctx);
|
|
4526
|
-
count++;
|
|
4527
|
-
}
|
|
4528
|
-
});
|
|
4529
|
-
logger$4.log(`Replaced ${count} <style> tags`);
|
|
4530
|
-
return count;
|
|
4531
|
-
}
|
|
4532
|
-
function processRule(rule, ctx) {
|
|
4533
|
-
let count = 0;
|
|
4534
|
-
if ('style' in rule && rule.style) {
|
|
4535
|
-
const cssRule = rule;
|
|
4536
|
-
const style = cssRule.style;
|
|
4537
|
-
let hasVp = false;
|
|
4538
|
-
const propOriginals = new Map();
|
|
4539
|
-
for (let i = 0; i < style.length; i++) {
|
|
4540
|
-
const prop = style[i];
|
|
4541
|
-
const value = style.getPropertyValue(prop);
|
|
4542
|
-
if (value && createRegex().test(value)) {
|
|
4543
|
-
hasVp = true;
|
|
4544
|
-
propOriginals.set(prop, value);
|
|
4545
|
-
style.setProperty(prop, replaceInText(value, ctx), style.getPropertyPriority(prop));
|
|
4546
|
-
count++;
|
|
4547
|
-
}
|
|
4548
|
-
}
|
|
4549
|
-
if (hasVp && cssRule.selectorText)
|
|
4550
|
-
trackSelector(cssRule.selectorText, propOriginals, ctx);
|
|
4551
|
-
}
|
|
4552
|
-
if ('cssRules' in rule) {
|
|
4553
|
-
for (const r of Array.from(rule.cssRules || [])) {
|
|
4554
|
-
count += processRule(r, ctx);
|
|
4555
|
-
}
|
|
4556
|
-
}
|
|
4557
|
-
return count;
|
|
4930
|
+
function register$1(fix) {
|
|
4931
|
+
registry$1.push(fix);
|
|
4558
4932
|
}
|
|
4559
|
-
/**
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4933
|
+
/**
|
|
4934
|
+
* Returns all fixes that are active for the given context.
|
|
4935
|
+
* A fix is active if it has no `shouldApply`, or `shouldApply` returns true.
|
|
4936
|
+
*/
|
|
4937
|
+
function getActiveFixes(ctx) {
|
|
4938
|
+
return registry$1.filter((fix) => {
|
|
4565
4939
|
try {
|
|
4566
|
-
|
|
4567
|
-
total += processRule(rule, ctx);
|
|
4568
|
-
}
|
|
4940
|
+
return !fix.shouldApply || fix.shouldApply(ctx);
|
|
4569
4941
|
}
|
|
4570
|
-
catch
|
|
4571
|
-
|
|
4942
|
+
catch {
|
|
4943
|
+
return false;
|
|
4572
4944
|
}
|
|
4573
4945
|
});
|
|
4574
|
-
logger$4.log(`Replaced ${total} rules in inline stylesheets`);
|
|
4575
|
-
return total;
|
|
4576
|
-
}
|
|
4577
|
-
async function processLinkedStylesheets(ctx) {
|
|
4578
|
-
const links = ctx.doc.querySelectorAll('link[rel="stylesheet"]');
|
|
4579
|
-
let count = 0;
|
|
4580
|
-
for (const link of Array.from(links)) {
|
|
4581
|
-
// Skip cross-origin — already in browser CSSOM, handled via processStylesheets
|
|
4582
|
-
if (link.href && !link.href.startsWith(ctx.win.location.origin)) {
|
|
4583
|
-
logger$4.log('Skipping cross-origin CSS:', link.href);
|
|
4584
|
-
continue;
|
|
4585
|
-
}
|
|
4586
|
-
try {
|
|
4587
|
-
const res = await fetch(link.href);
|
|
4588
|
-
let css = await res.text();
|
|
4589
|
-
if (createRegex().test(css)) {
|
|
4590
|
-
css = replaceInText(css, ctx);
|
|
4591
|
-
const style = ctx.doc.createElement('style');
|
|
4592
|
-
style.textContent = css;
|
|
4593
|
-
style.dataset.originalHref = link.href;
|
|
4594
|
-
link.parentNode?.insertBefore(style, link);
|
|
4595
|
-
link.remove();
|
|
4596
|
-
count++;
|
|
4597
|
-
}
|
|
4598
|
-
}
|
|
4599
|
-
catch (e) {
|
|
4600
|
-
logger$4.warn('Cannot load CSS:', link.href, e);
|
|
4601
|
-
}
|
|
4602
|
-
}
|
|
4603
|
-
logger$4.log(`Replaced ${count} linked CSS files`);
|
|
4604
|
-
return count;
|
|
4605
|
-
}
|
|
4606
|
-
// ─── Public entry point ───────────────────────────────────────────────────────
|
|
4607
|
-
async function process$1(ctx) {
|
|
4608
|
-
logger$4.configure({ enabled: !!ctx.debug });
|
|
4609
|
-
// Reset tracking state from any previous run
|
|
4610
|
-
elementsWithViewportUnits = new Set();
|
|
4611
|
-
originalValues = new WeakMap();
|
|
4612
|
-
processInlineStyles(ctx);
|
|
4613
|
-
processStyleTags(ctx);
|
|
4614
|
-
processStylesheets(ctx);
|
|
4615
|
-
await processLinkedStylesheets(ctx);
|
|
4616
|
-
// Wait for browser to apply the replaced styles
|
|
4617
|
-
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
4618
|
-
// Enforce final computed styles to inline with !important
|
|
4619
|
-
const count = processAll({ debug: !!ctx.debug });
|
|
4620
|
-
logger$4.log(`Enforced ${count} computed styles for ${elementsWithViewportUnits.size} tracked elements`);
|
|
4621
4946
|
}
|
|
4622
4947
|
|
|
4623
|
-
/**
|
|
4624
|
-
* Built-in global fix — always runs, no shouldApply condition.
|
|
4625
|
-
* Registered first so it runs before any other global process hooks.
|
|
4626
|
-
*/
|
|
4627
|
-
register$1({
|
|
4628
|
-
name: 'viewport-unit-replacer',
|
|
4629
|
-
description: 'Core: convert vh/vw/svh/dvh/% to px values across all iframe CSS',
|
|
4630
|
-
process: process$1,
|
|
4631
|
-
});
|
|
4632
|
-
|
|
4633
4948
|
/**
|
|
4634
4949
|
* GemPages v7 Slider Fix
|
|
4635
4950
|
*
|
|
@@ -4713,6 +5028,9 @@ function getMaxWByDeviceType(deviceType) {
|
|
|
4713
5028
|
// ─── Main fix ─────────────────────────────────────────────────────────────────
|
|
4714
5029
|
function afterProcess$1({ doc, targetWidth, deviceType }) {
|
|
4715
5030
|
doc.querySelectorAll(SLIDER_ITEM_SELECTOR).forEach((item) => {
|
|
5031
|
+
// When !gp-min-w-full is set, the item fills 100% width via Tailwind — skip manual width override
|
|
5032
|
+
if (item.classList.contains('!gp-min-w-full'))
|
|
5033
|
+
return;
|
|
4716
5034
|
const originalWidth = parseFloat(item.style.minWidth) || parseFloat(item.style.maxWidth) || 0;
|
|
4717
5035
|
if (!originalWidth)
|
|
4718
5036
|
return;
|
|
@@ -4813,23 +5131,6 @@ register$1({
|
|
|
4813
5131
|
afterProcess,
|
|
4814
5132
|
});
|
|
4815
5133
|
|
|
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
5134
|
/**
|
|
4834
5135
|
* Default iframe dimension calculation.
|
|
4835
5136
|
* Used as fallback when no fix overrides getDimensions().
|
|
@@ -4853,41 +5154,58 @@ function getFinalWidth(doc) {
|
|
|
4853
5154
|
* Phase 3: afterProcess (shop → global)
|
|
4854
5155
|
* Phase 4: getDimensions (shop → global → default)
|
|
4855
5156
|
*/
|
|
4856
|
-
const logger
|
|
5157
|
+
const logger = createLogger({ enabled: false, prefix: 'ViewportReplacer' });
|
|
4857
5158
|
function configure(debug) {
|
|
4858
|
-
logger
|
|
5159
|
+
logger.configure({ enabled: debug });
|
|
4859
5160
|
}
|
|
4860
5161
|
async function run$1(ctx, activeGlobal, shopFix) {
|
|
4861
5162
|
// ── Phase 1: beforeProcess ────────────────────────────────────────────────
|
|
5163
|
+
const t1 = perf$3.mark('phase1.beforeProcess');
|
|
4862
5164
|
for (const fix of activeGlobal) {
|
|
4863
5165
|
if (fix.beforeProcess) {
|
|
4864
|
-
logger
|
|
5166
|
+
logger.log(`[beforeProcess] ${fix.name}`);
|
|
5167
|
+
const t = perf$3.mark(`phase1.${fix.name}.beforeProcess`);
|
|
4865
5168
|
await fix.beforeProcess(ctx);
|
|
5169
|
+
perf$3.measure(`phase1.${fix.name}.beforeProcess`, t);
|
|
4866
5170
|
}
|
|
4867
5171
|
}
|
|
4868
5172
|
if (shopFix?.beforeProcess) {
|
|
4869
|
-
logger
|
|
5173
|
+
logger.log('[beforeProcess] shop');
|
|
5174
|
+
const t = perf$3.mark('phase1.shop.beforeProcess');
|
|
4870
5175
|
await shopFix.beforeProcess(ctx);
|
|
5176
|
+
perf$3.measure('phase1.shop.beforeProcess', t);
|
|
4871
5177
|
}
|
|
5178
|
+
perf$3.measure('phase1.beforeProcess', t1);
|
|
4872
5179
|
// ── Phase 2: process ──────────────────────────────────────────────────────
|
|
5180
|
+
const t2 = perf$3.mark('phase2.process');
|
|
4873
5181
|
for (const fix of activeGlobal) {
|
|
4874
5182
|
if (fix.process) {
|
|
4875
|
-
logger
|
|
5183
|
+
logger.log(`[process] ${fix.name}`);
|
|
5184
|
+
const t = perf$3.mark(`phase2.${fix.name}.process`);
|
|
4876
5185
|
await fix.process(ctx);
|
|
5186
|
+
perf$3.measure(`phase2.${fix.name}.process`, t);
|
|
4877
5187
|
}
|
|
4878
5188
|
}
|
|
5189
|
+
perf$3.measure('phase2.process', t2);
|
|
4879
5190
|
// ── Phase 3: afterProcess ─────────────────────────────────────────────────
|
|
5191
|
+
const t3 = perf$3.mark('phase3.afterProcess');
|
|
4880
5192
|
if (shopFix?.afterProcess) {
|
|
4881
|
-
logger
|
|
5193
|
+
logger.log('[afterProcess] shop');
|
|
5194
|
+
const t = perf$3.mark('phase3.shop.afterProcess');
|
|
4882
5195
|
await shopFix.afterProcess(ctx);
|
|
5196
|
+
perf$3.measure('phase3.shop.afterProcess', t);
|
|
4883
5197
|
}
|
|
4884
5198
|
for (const fix of activeGlobal) {
|
|
4885
5199
|
if (fix.afterProcess) {
|
|
4886
|
-
logger
|
|
5200
|
+
logger.log(`[afterProcess] ${fix.name}`);
|
|
5201
|
+
const t = perf$3.mark(`phase3.${fix.name}.afterProcess`);
|
|
4887
5202
|
await fix.afterProcess(ctx);
|
|
5203
|
+
perf$3.measure(`phase3.${fix.name}.afterProcess`, t);
|
|
4888
5204
|
}
|
|
4889
5205
|
}
|
|
5206
|
+
perf$3.measure('phase3.afterProcess', t3);
|
|
4890
5207
|
// ── Phase 4: getDimensions ────────────────────────────────────────────────
|
|
5208
|
+
const t4 = perf$3.mark('phase4.getDimensions');
|
|
4891
5209
|
return new Promise((resolve) => {
|
|
4892
5210
|
requestAnimationFrame(() => {
|
|
4893
5211
|
let dimensions = null;
|
|
@@ -4895,14 +5213,14 @@ async function run$1(ctx, activeGlobal, shopFix) {
|
|
|
4895
5213
|
if (shopFix?.getDimensions) {
|
|
4896
5214
|
dimensions = shopFix.getDimensions(ctx);
|
|
4897
5215
|
if (dimensions)
|
|
4898
|
-
logger
|
|
5216
|
+
logger.log('Dimensions from shop fix:', dimensions);
|
|
4899
5217
|
}
|
|
4900
5218
|
if (!dimensions) {
|
|
4901
5219
|
for (const fix of activeGlobal) {
|
|
4902
5220
|
if (fix.getDimensions) {
|
|
4903
5221
|
dimensions = fix.getDimensions(ctx);
|
|
4904
5222
|
if (dimensions) {
|
|
4905
|
-
logger
|
|
5223
|
+
logger.log(`Dimensions from global fix [${fix.name}]:`, dimensions);
|
|
4906
5224
|
break;
|
|
4907
5225
|
}
|
|
4908
5226
|
}
|
|
@@ -4911,7 +5229,8 @@ async function run$1(ctx, activeGlobal, shopFix) {
|
|
|
4911
5229
|
if (!dimensions) {
|
|
4912
5230
|
dimensions = { height: getFinalHeight(ctx.doc, ctx.win), width: getFinalWidth(ctx.doc) };
|
|
4913
5231
|
}
|
|
4914
|
-
logger
|
|
5232
|
+
logger.log('Final dimensions:', dimensions);
|
|
5233
|
+
perf$3.measure('phase4.getDimensions', t4);
|
|
4915
5234
|
resolve(dimensions);
|
|
4916
5235
|
});
|
|
4917
5236
|
});
|
|
@@ -4988,233 +5307,288 @@ register(`566240210141053597`, {
|
|
|
4988
5307
|
afterProcess: restoreAndFixLayout,
|
|
4989
5308
|
});
|
|
4990
5309
|
|
|
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.');
|
|
5310
|
+
// ── Module-level functions ────────────────────────────────────────────────────
|
|
5311
|
+
function start$2(s, iframe, cfg) {
|
|
5312
|
+
if (s.running) {
|
|
5313
|
+
s.logger.warn('Already running. Call stop() first.');
|
|
5002
5314
|
return;
|
|
5003
5315
|
}
|
|
5004
5316
|
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
5005
5317
|
throw new Error('Iframe document or window not accessible');
|
|
5006
5318
|
}
|
|
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 });
|
|
5319
|
+
s.doc = iframe.contentDocument;
|
|
5320
|
+
s.win = iframe.contentWindow;
|
|
5321
|
+
s.config = cfg;
|
|
5322
|
+
s.running = true;
|
|
5323
|
+
s.shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
|
|
5324
|
+
if (s.shopFix)
|
|
5325
|
+
s.logger.log(`Shop fix loaded for "${cfg.shopId}":`, s.shopFix.description ?? '(no description)');
|
|
5326
|
+
s.logger.configure({ enabled: !!cfg.debug });
|
|
5016
5327
|
configure(!!cfg.debug);
|
|
5017
|
-
start
|
|
5018
|
-
attach(cfg.debug);
|
|
5019
|
-
logger
|
|
5328
|
+
s.enforcer.start(s.doc, s.win, cfg, { debug: !!cfg.debug });
|
|
5329
|
+
s.listeners.attach(cfg.debug);
|
|
5330
|
+
s.logger.log('Started');
|
|
5020
5331
|
}
|
|
5021
|
-
function stop$
|
|
5022
|
-
if (!running
|
|
5332
|
+
function stop$2(s) {
|
|
5333
|
+
if (!s.running)
|
|
5023
5334
|
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
|
|
5335
|
+
s.enforcer.stop();
|
|
5336
|
+
s.listeners.detach();
|
|
5337
|
+
s.doc = null;
|
|
5338
|
+
s.win = null;
|
|
5339
|
+
s.config = null;
|
|
5340
|
+
s.shopFix = null;
|
|
5341
|
+
s.running = false;
|
|
5342
|
+
s.logger.log('Stopped');
|
|
5343
|
+
}
|
|
5344
|
+
async function run(s) {
|
|
5345
|
+
if (!s.running || !s.doc || !s.win || !s.config) {
|
|
5346
|
+
s.logger.warn('Not running. Call start() first.');
|
|
5036
5347
|
return { height: 1000, width: 1000 };
|
|
5037
5348
|
}
|
|
5038
5349
|
const ctx = {
|
|
5039
|
-
doc,
|
|
5040
|
-
win,
|
|
5041
|
-
deviceType: config
|
|
5042
|
-
targetWidth: config
|
|
5043
|
-
targetHeight: config
|
|
5044
|
-
debug: config
|
|
5350
|
+
doc: s.doc,
|
|
5351
|
+
win: s.win,
|
|
5352
|
+
deviceType: s.config.deviceType,
|
|
5353
|
+
targetWidth: s.config.targetWidth,
|
|
5354
|
+
targetHeight: s.config.targetHeight,
|
|
5355
|
+
debug: s.config.debug,
|
|
5356
|
+
enforcer: s.enforcer,
|
|
5045
5357
|
};
|
|
5046
5358
|
const activeGlobal = getActiveFixes(ctx);
|
|
5047
|
-
if (activeGlobal.length > 0)
|
|
5048
|
-
logger
|
|
5049
|
-
|
|
5359
|
+
if (activeGlobal.length > 0)
|
|
5360
|
+
s.logger.log(`Active global fixes: ${activeGlobal.map((f) => f.name).join(', ')}`);
|
|
5361
|
+
const tRun = perf$3.mark('viewport.run');
|
|
5050
5362
|
try {
|
|
5051
|
-
|
|
5363
|
+
const result = await run$1(ctx, activeGlobal, s.shopFix);
|
|
5364
|
+
perf$3.measure('viewport.run', tRun);
|
|
5365
|
+
return result;
|
|
5052
5366
|
}
|
|
5053
5367
|
catch (err) {
|
|
5054
|
-
|
|
5055
|
-
|
|
5368
|
+
perf$3.measure('viewport.run', tRun);
|
|
5369
|
+
s.logger.error('Critical error:', err);
|
|
5370
|
+
return { height: s.doc.body?.scrollHeight || 1000, width: s.doc.body?.scrollWidth || 1000 };
|
|
5056
5371
|
}
|
|
5057
5372
|
}
|
|
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.');
|
|
5373
|
+
function updateConfig$1(s, cfg) {
|
|
5374
|
+
if (!s.running || !s.config) {
|
|
5375
|
+
s.logger.warn('Not running. Call start() first.');
|
|
5076
5376
|
return;
|
|
5077
5377
|
}
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
logger.log('
|
|
5083
|
-
|
|
5378
|
+
s.config = { ...s.config, ...cfg };
|
|
5379
|
+
if (cfg.shopId !== undefined)
|
|
5380
|
+
s.shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
|
|
5381
|
+
s.enforcer.updateConfig(cfg);
|
|
5382
|
+
s.logger.log('Config updated');
|
|
5383
|
+
}
|
|
5384
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
5385
|
+
function createViewportProcessor() {
|
|
5386
|
+
const s = {
|
|
5387
|
+
logger: createLogger({ enabled: false, prefix: 'ViewportReplacer' }),
|
|
5388
|
+
enforcer: createEnforcer(),
|
|
5389
|
+
listeners: createViewportListeners(),
|
|
5390
|
+
doc: null,
|
|
5391
|
+
win: null,
|
|
5392
|
+
config: null,
|
|
5393
|
+
shopFix: null,
|
|
5394
|
+
running: false,
|
|
5395
|
+
};
|
|
5396
|
+
return {
|
|
5397
|
+
start: (iframe, cfg) => start$2(s, iframe, cfg),
|
|
5398
|
+
stop: () => stop$2(s),
|
|
5399
|
+
run: () => run(s),
|
|
5400
|
+
updateConfig: (cfg) => updateConfig$1(s, cfg),
|
|
5401
|
+
isRunning: () => s.running,
|
|
5402
|
+
};
|
|
5084
5403
|
}
|
|
5085
|
-
|
|
5086
|
-
|
|
5404
|
+
|
|
5405
|
+
// ── Module-level functions ────────────────────────────────────────────────────
|
|
5406
|
+
function dispatchDimensionsEvent(dimensions) {
|
|
5407
|
+
window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', { detail: dimensions }));
|
|
5408
|
+
}
|
|
5409
|
+
async function process(s) {
|
|
5410
|
+
if (!s.iframe || !s.config)
|
|
5087
5411
|
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'));
|
|
5412
|
+
if (!s.iframe.contentDocument || !s.iframe.contentWindow) {
|
|
5413
|
+
s.logger.error('Cannot access iframe document');
|
|
5414
|
+
s.config.onError?.(new Error('Cannot access iframe document'));
|
|
5106
5415
|
return;
|
|
5107
5416
|
}
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5417
|
+
const sessionId = `render-${Date.now()}`;
|
|
5418
|
+
perf$3.startSession(sessionId);
|
|
5419
|
+
const t0 = perf$3.mark('orchestrator.process');
|
|
5420
|
+
try {
|
|
5421
|
+
s.logger.groupCollapsed('Processing...');
|
|
5422
|
+
s.viewportReplacer.start(s.iframe, s.config);
|
|
5423
|
+
s.navigationBlocker.start(s.iframe, { debug: s.config.debug });
|
|
5424
|
+
const result = await s.viewportReplacer.run();
|
|
5425
|
+
perf$3.measure('orchestrator.process', t0);
|
|
5426
|
+
perf$3.endSession();
|
|
5427
|
+
s.logger.groupEnd();
|
|
5428
|
+
s.logger.log('Process completed:', result);
|
|
5429
|
+
s.config.onSuccess?.(result);
|
|
5430
|
+
dispatchDimensionsEvent(result);
|
|
5111
5431
|
}
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5432
|
+
catch (error) {
|
|
5433
|
+
perf$3.measure('orchestrator.process', t0);
|
|
5434
|
+
perf$3.endSession();
|
|
5435
|
+
s.logger.error('Failed to process:', error);
|
|
5436
|
+
s.config.onError?.(error);
|
|
5115
5437
|
}
|
|
5116
5438
|
}
|
|
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'));
|
|
5439
|
+
async function initialize(s) {
|
|
5440
|
+
if (!s.iframe || !s.config) {
|
|
5441
|
+
s.logger.error('iframe not found');
|
|
5442
|
+
s.config?.onError?.(new Error('iframe not found'));
|
|
5123
5443
|
return;
|
|
5124
5444
|
}
|
|
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();
|
|
5445
|
+
if (s.iframe.contentDocument?.readyState === 'complete') {
|
|
5446
|
+
await process(s);
|
|
5135
5447
|
}
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5448
|
+
else {
|
|
5449
|
+
s.loadListener = () => process(s);
|
|
5450
|
+
s.iframe.addEventListener('load', s.loadListener);
|
|
5139
5451
|
}
|
|
5140
5452
|
}
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5453
|
+
function start$1(s, cfg) {
|
|
5454
|
+
if (s.running) {
|
|
5455
|
+
s.logger.warn('Fixer is already running. Call stop() first.');
|
|
5456
|
+
return;
|
|
5457
|
+
}
|
|
5458
|
+
s.iframe = cfg.iframe;
|
|
5459
|
+
s.config = cfg;
|
|
5460
|
+
s.running = true;
|
|
5461
|
+
s.logger.configure({ enabled: !!cfg.debug });
|
|
5462
|
+
s.logger.log('Started');
|
|
5463
|
+
initialize(s);
|
|
5148
5464
|
}
|
|
5149
|
-
function
|
|
5150
|
-
|
|
5465
|
+
function stop$1(s) {
|
|
5466
|
+
if (!s.running)
|
|
5467
|
+
return;
|
|
5468
|
+
s.viewportReplacer.stop();
|
|
5469
|
+
s.heightObserver.stop();
|
|
5470
|
+
s.navigationBlocker.stop();
|
|
5471
|
+
if (s.iframe && s.loadListener) {
|
|
5472
|
+
s.iframe.removeEventListener('load', s.loadListener);
|
|
5473
|
+
s.loadListener = null;
|
|
5474
|
+
}
|
|
5475
|
+
s.iframe = null;
|
|
5476
|
+
s.config = null;
|
|
5477
|
+
s.running = false;
|
|
5478
|
+
s.logger.log('Stopped');
|
|
5479
|
+
}
|
|
5480
|
+
async function recalculate$1(s) {
|
|
5481
|
+
if (!s.running) {
|
|
5482
|
+
s.logger.warn('Fixer is not running.');
|
|
5483
|
+
return;
|
|
5484
|
+
}
|
|
5485
|
+
s.logger.log('Recalculating...');
|
|
5486
|
+
await process(s);
|
|
5151
5487
|
}
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
function enableNavigationBlocking$2() {
|
|
5156
|
-
if (!running$1) {
|
|
5157
|
-
logger.warn('Fixer is not running. Call start() first.');
|
|
5488
|
+
function updateConfig(s, cfg) {
|
|
5489
|
+
if (!s.running || !s.config) {
|
|
5490
|
+
s.logger.warn('Fixer is not running.');
|
|
5158
5491
|
return;
|
|
5159
5492
|
}
|
|
5160
|
-
|
|
5493
|
+
s.config = { ...s.config, ...cfg };
|
|
5494
|
+
s.viewportReplacer.updateConfig(cfg);
|
|
5495
|
+
s.logger.log('Config updated');
|
|
5496
|
+
}
|
|
5497
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
5498
|
+
function createOrchestrator() {
|
|
5499
|
+
const s = {
|
|
5500
|
+
logger: createLogger({ enabled: false, prefix: 'IframeFixer' }),
|
|
5501
|
+
viewportReplacer: createViewportProcessor(),
|
|
5502
|
+
navigationBlocker: createNavigationBlocker(),
|
|
5503
|
+
heightObserver: createHeightObserver(),
|
|
5504
|
+
iframe: null,
|
|
5505
|
+
config: null,
|
|
5506
|
+
running: false,
|
|
5507
|
+
loadListener: null,
|
|
5508
|
+
};
|
|
5509
|
+
return {
|
|
5510
|
+
start: (cfg) => start$1(s, cfg),
|
|
5511
|
+
stop: () => stop$1(s),
|
|
5512
|
+
recalculate: () => recalculate$1(s),
|
|
5513
|
+
updateConfig: (cfg) => updateConfig(s, cfg),
|
|
5514
|
+
enableNavigationBlocking: () => s.navigationBlocker.enable(),
|
|
5515
|
+
enableNavigationBlockingMessage: () => s.navigationBlocker.enableMessage(),
|
|
5516
|
+
disableNavigationBlocking: () => s.navigationBlocker.disable(),
|
|
5517
|
+
disableNavigationBlockingMessage: () => s.navigationBlocker.disableMessage(),
|
|
5518
|
+
isRunning: () => s.running,
|
|
5519
|
+
getStateInfo: () => ({
|
|
5520
|
+
isRunning: s.running,
|
|
5521
|
+
hasIframe: !!s.iframe,
|
|
5522
|
+
hasConfig: !!s.config,
|
|
5523
|
+
hasNavigationBlocker: s.navigationBlocker.isRunning(),
|
|
5524
|
+
hasHeightObserver: s.heightObserver.isRunning(),
|
|
5525
|
+
viewportReplacerRunning: s.viewportReplacer.isRunning(),
|
|
5526
|
+
}),
|
|
5527
|
+
};
|
|
5161
5528
|
}
|
|
5162
5529
|
|
|
5163
5530
|
/**
|
|
5164
|
-
* Iframe Helper
|
|
5165
|
-
*
|
|
5531
|
+
* Iframe Helper — factory entry point.
|
|
5532
|
+
*
|
|
5533
|
+
* Each call to `createIframeHelper()` returns a fully isolated instance
|
|
5534
|
+
* with its own processor state. Use one instance per iframe.
|
|
5166
5535
|
*/
|
|
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.');
|
|
5536
|
+
// ── Module-level functions ────────────────────────────────────────────────────
|
|
5537
|
+
function start(s, config) {
|
|
5538
|
+
if (s.running) {
|
|
5539
|
+
console.warn('[IframeHelper] Already running. Call stop() first.');
|
|
5177
5540
|
return;
|
|
5178
5541
|
}
|
|
5179
|
-
start
|
|
5180
|
-
running = true;
|
|
5542
|
+
s.fixer.start(config);
|
|
5543
|
+
s.running = true;
|
|
5181
5544
|
}
|
|
5182
|
-
function stop
|
|
5183
|
-
if (!running)
|
|
5545
|
+
function stop(s) {
|
|
5546
|
+
if (!s.running)
|
|
5184
5547
|
return;
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
running = false;
|
|
5548
|
+
s.fixer.stop();
|
|
5549
|
+
s.running = false;
|
|
5188
5550
|
}
|
|
5189
|
-
function
|
|
5190
|
-
if (!running) {
|
|
5191
|
-
console.warn('[
|
|
5551
|
+
async function recalculate(s) {
|
|
5552
|
+
if (!s.running) {
|
|
5553
|
+
console.warn('[IframeHelper] Not running. Call start() first.');
|
|
5192
5554
|
return;
|
|
5193
5555
|
}
|
|
5194
|
-
|
|
5556
|
+
await s.fixer.recalculate();
|
|
5195
5557
|
}
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5558
|
+
function enableNavigationBlocking(s) {
|
|
5559
|
+
if (!s.running) {
|
|
5560
|
+
console.warn('[IframeHelper] Not running. Call start() first.');
|
|
5561
|
+
return;
|
|
5562
|
+
}
|
|
5563
|
+
s.fixer.enableNavigationBlocking();
|
|
5202
5564
|
}
|
|
5203
|
-
|
|
5204
|
-
|
|
5565
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
5566
|
+
function createIframeHelper() {
|
|
5567
|
+
const s = {
|
|
5568
|
+
fixer: createOrchestrator(),
|
|
5569
|
+
running: false,
|
|
5570
|
+
};
|
|
5571
|
+
return {
|
|
5572
|
+
start: (config) => start(s, config),
|
|
5573
|
+
stop: () => stop(s),
|
|
5574
|
+
recalculate: () => recalculate(s),
|
|
5575
|
+
enableNavigationBlocking: () => enableNavigationBlocking(s),
|
|
5576
|
+
isRunning: () => s.running,
|
|
5577
|
+
};
|
|
5205
5578
|
}
|
|
5206
5579
|
|
|
5580
|
+
const iframeHelper = createIframeHelper();
|
|
5207
5581
|
function useVizLiveRender() {
|
|
5208
5582
|
const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
|
|
5209
5583
|
const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
|
|
5210
5584
|
const wrapperWidth = useHeatmapVizRectContext((s) => s.wrapperWidth);
|
|
5211
|
-
const
|
|
5212
|
-
const htmlContent =
|
|
5213
|
-
const targetUrl =
|
|
5585
|
+
const setIsDomLoaded = useHeatmapVizContext((s) => s.setIsDomLoaded);
|
|
5586
|
+
const htmlContent = useHeatmapLiveContext((s) => s.htmlContent);
|
|
5587
|
+
const targetUrl = useHeatmapLiveContext((s) => s.targetUrl);
|
|
5214
5588
|
const deviceType = useHeatmapSettingContext((s) => s.deviceType);
|
|
5215
|
-
const renderMode =
|
|
5216
|
-
const storefrontPassword =
|
|
5217
|
-
|
|
5589
|
+
const renderMode = useHeatmapLiveContext((s) => s.renderMode);
|
|
5590
|
+
const storefrontPassword = useHeatmapLiveContext((s) => s.storefrontPassword);
|
|
5591
|
+
useHeatmapViewportByDevice();
|
|
5218
5592
|
const { iframeRef, isReady } = useVizLiveIframeMsg();
|
|
5219
5593
|
// Handle iframe rendering based on mode
|
|
5220
5594
|
useEffect(() => {
|
|
@@ -5254,10 +5628,10 @@ function useVizLiveRender() {
|
|
|
5254
5628
|
const hasContent = (renderMode === 'portal' && targetUrl) || (renderMode === 'inline' && htmlContent);
|
|
5255
5629
|
if (!iframe || !hasContent)
|
|
5256
5630
|
return;
|
|
5257
|
-
|
|
5258
|
-
|
|
5631
|
+
setIsDomLoaded(true);
|
|
5632
|
+
startIframe$1(iframe, deviceType, { width: wrapperWidth, height: wrapperHeight }, (height) => {
|
|
5259
5633
|
height && setIframeHeight(height);
|
|
5260
|
-
|
|
5634
|
+
setIsDomLoaded(true);
|
|
5261
5635
|
});
|
|
5262
5636
|
return () => { };
|
|
5263
5637
|
}, [
|
|
@@ -5269,7 +5643,7 @@ function useVizLiveRender() {
|
|
|
5269
5643
|
targetUrl,
|
|
5270
5644
|
htmlContent,
|
|
5271
5645
|
iframeRef,
|
|
5272
|
-
|
|
5646
|
+
setIsDomLoaded,
|
|
5273
5647
|
setIframeHeight,
|
|
5274
5648
|
]);
|
|
5275
5649
|
return {
|
|
@@ -5288,9 +5662,9 @@ function buildPortalUrl(targetUrl, storefrontPassword) {
|
|
|
5288
5662
|
const portalServiceUrl = getPortalServiceUrl();
|
|
5289
5663
|
return `${portalServiceUrl}/?${params.toString()}`;
|
|
5290
5664
|
}
|
|
5291
|
-
function
|
|
5292
|
-
stop();
|
|
5293
|
-
start({
|
|
5665
|
+
function startIframe$1(iframe, deviceType = EDeviceType.Desktop, rect, onSuccess) {
|
|
5666
|
+
iframeHelper.stop();
|
|
5667
|
+
iframeHelper.start({
|
|
5294
5668
|
deviceType: deviceType,
|
|
5295
5669
|
targetWidth: rect.width,
|
|
5296
5670
|
targetHeight: rect.height,
|
|
@@ -5301,8 +5675,111 @@ function initIframeHelper$1(iframe, deviceType = EDeviceType.Desktop, rect, onSu
|
|
|
5301
5675
|
},
|
|
5302
5676
|
});
|
|
5303
5677
|
// fixer.recalculate();
|
|
5304
|
-
enableNavigationBlocking();
|
|
5678
|
+
iframeHelper.enableNavigationBlocking();
|
|
5679
|
+
}
|
|
5680
|
+
|
|
5681
|
+
const DEFAULT_CONFIG = {
|
|
5682
|
+
dbName: 'gx-viz-html-cache',
|
|
5683
|
+
maxEntries: 20,
|
|
5684
|
+
ttlMs: 24 * 60 * 60 * 1000, // 24 hours
|
|
5685
|
+
cacheVersion: 3.0,
|
|
5686
|
+
};
|
|
5687
|
+
let _config = { ...DEFAULT_CONFIG };
|
|
5688
|
+
function getHtmlCacheConfig() {
|
|
5689
|
+
return _config;
|
|
5690
|
+
}
|
|
5691
|
+
/** Build a full cache key that includes the cache version to handle invalidation. */
|
|
5692
|
+
function buildCacheKey(baseKey, shortCircuitStrategy = 0) {
|
|
5693
|
+
return `v${_config.cacheVersion}:${baseKey}:${shortCircuitStrategy}`;
|
|
5694
|
+
}
|
|
5695
|
+
|
|
5696
|
+
const STORE_NAME = 'entries';
|
|
5697
|
+
const IDB_SCHEMA_VERSION = 1;
|
|
5698
|
+
function openDb() {
|
|
5699
|
+
const { dbName } = getHtmlCacheConfig();
|
|
5700
|
+
return new Promise((resolve, reject) => {
|
|
5701
|
+
const req = indexedDB.open(dbName, IDB_SCHEMA_VERSION);
|
|
5702
|
+
req.onupgradeneeded = () => {
|
|
5703
|
+
const db = req.result;
|
|
5704
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
5705
|
+
const store = db.createObjectStore(STORE_NAME, { keyPath: 'key' });
|
|
5706
|
+
store.createIndex('timestamp', 'timestamp');
|
|
5707
|
+
}
|
|
5708
|
+
};
|
|
5709
|
+
req.onsuccess = () => resolve(req.result);
|
|
5710
|
+
req.onerror = () => reject(req.error);
|
|
5711
|
+
});
|
|
5305
5712
|
}
|
|
5713
|
+
async function evict(db) {
|
|
5714
|
+
const { maxEntries } = getHtmlCacheConfig();
|
|
5715
|
+
return new Promise((resolve) => {
|
|
5716
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
5717
|
+
const store = tx.objectStore(STORE_NAME);
|
|
5718
|
+
const countReq = store.count();
|
|
5719
|
+
countReq.onsuccess = () => {
|
|
5720
|
+
if (countReq.result <= maxEntries) {
|
|
5721
|
+
resolve();
|
|
5722
|
+
return;
|
|
5723
|
+
}
|
|
5724
|
+
const idx = store.index('timestamp');
|
|
5725
|
+
const cursorReq = idx.openCursor();
|
|
5726
|
+
let toDelete = countReq.result - maxEntries;
|
|
5727
|
+
cursorReq.onsuccess = () => {
|
|
5728
|
+
const cursor = cursorReq.result;
|
|
5729
|
+
if (cursor && toDelete > 0) {
|
|
5730
|
+
cursor.delete();
|
|
5731
|
+
toDelete--;
|
|
5732
|
+
cursor.continue();
|
|
5733
|
+
}
|
|
5734
|
+
else {
|
|
5735
|
+
resolve();
|
|
5736
|
+
}
|
|
5737
|
+
};
|
|
5738
|
+
cursorReq.onerror = () => resolve();
|
|
5739
|
+
};
|
|
5740
|
+
countReq.onerror = () => resolve();
|
|
5741
|
+
});
|
|
5742
|
+
}
|
|
5743
|
+
const htmlCache = {
|
|
5744
|
+
async get(key) {
|
|
5745
|
+
try {
|
|
5746
|
+
const { ttlMs } = getHtmlCacheConfig();
|
|
5747
|
+
const db = await openDb();
|
|
5748
|
+
return new Promise((resolve) => {
|
|
5749
|
+
const tx = db.transaction(STORE_NAME, 'readonly');
|
|
5750
|
+
const req = tx.objectStore(STORE_NAME).get(key);
|
|
5751
|
+
req.onsuccess = () => {
|
|
5752
|
+
const entry = req.result;
|
|
5753
|
+
if (!entry || Date.now() - entry.timestamp > ttlMs) {
|
|
5754
|
+
resolve(null);
|
|
5755
|
+
}
|
|
5756
|
+
else {
|
|
5757
|
+
resolve(entry);
|
|
5758
|
+
}
|
|
5759
|
+
};
|
|
5760
|
+
req.onerror = () => resolve(null);
|
|
5761
|
+
});
|
|
5762
|
+
}
|
|
5763
|
+
catch {
|
|
5764
|
+
return null;
|
|
5765
|
+
}
|
|
5766
|
+
},
|
|
5767
|
+
async set(entry) {
|
|
5768
|
+
try {
|
|
5769
|
+
const db = await openDb();
|
|
5770
|
+
await new Promise((resolve, reject) => {
|
|
5771
|
+
const tx = db.transaction(STORE_NAME, 'readwrite');
|
|
5772
|
+
tx.objectStore(STORE_NAME).put(entry);
|
|
5773
|
+
tx.oncomplete = () => resolve();
|
|
5774
|
+
tx.onerror = () => reject(tx.error);
|
|
5775
|
+
});
|
|
5776
|
+
await evict(db);
|
|
5777
|
+
}
|
|
5778
|
+
catch {
|
|
5779
|
+
// ignore cache write errors
|
|
5780
|
+
}
|
|
5781
|
+
},
|
|
5782
|
+
};
|
|
5306
5783
|
|
|
5307
5784
|
const CANVAS_ID = 'clarity-heatmap-canvas';
|
|
5308
5785
|
const ATTENTION_HUES = [240, 210, 180, 150, 120, 90, 60, 30, 0];
|
|
@@ -5512,6 +5989,316 @@ class AttentionMapRenderer {
|
|
|
5512
5989
|
};
|
|
5513
5990
|
}
|
|
5514
5991
|
|
|
5992
|
+
var Event;
|
|
5993
|
+
(function (Event) {
|
|
5994
|
+
/* Data */
|
|
5995
|
+
Event[Event["Metric"] = 0] = "Metric";
|
|
5996
|
+
Event[Event["Dimension"] = 1] = "Dimension";
|
|
5997
|
+
Event[Event["Upload"] = 2] = "Upload";
|
|
5998
|
+
Event[Event["Upgrade"] = 3] = "Upgrade";
|
|
5999
|
+
Event[Event["Baseline"] = 4] = "Baseline";
|
|
6000
|
+
Event[Event["Discover"] = 5] = "Discover";
|
|
6001
|
+
Event[Event["Mutation"] = 6] = "Mutation";
|
|
6002
|
+
Event[Event["Region"] = 7] = "Region";
|
|
6003
|
+
Event[Event["Document"] = 8] = "Document";
|
|
6004
|
+
Event[Event["Click"] = 9] = "Click";
|
|
6005
|
+
Event[Event["Scroll"] = 10] = "Scroll";
|
|
6006
|
+
Event[Event["Resize"] = 11] = "Resize";
|
|
6007
|
+
Event[Event["MouseMove"] = 12] = "MouseMove";
|
|
6008
|
+
Event[Event["MouseDown"] = 13] = "MouseDown";
|
|
6009
|
+
Event[Event["MouseUp"] = 14] = "MouseUp";
|
|
6010
|
+
Event[Event["MouseWheel"] = 15] = "MouseWheel";
|
|
6011
|
+
Event[Event["DoubleClick"] = 16] = "DoubleClick";
|
|
6012
|
+
Event[Event["TouchStart"] = 17] = "TouchStart";
|
|
6013
|
+
Event[Event["TouchEnd"] = 18] = "TouchEnd";
|
|
6014
|
+
Event[Event["TouchMove"] = 19] = "TouchMove";
|
|
6015
|
+
Event[Event["TouchCancel"] = 20] = "TouchCancel";
|
|
6016
|
+
Event[Event["Selection"] = 21] = "Selection";
|
|
6017
|
+
Event[Event["Timeline"] = 22] = "Timeline";
|
|
6018
|
+
Event[Event["Page"] = 23] = "Page";
|
|
6019
|
+
Event[Event["Custom"] = 24] = "Custom";
|
|
6020
|
+
Event[Event["Ping"] = 25] = "Ping";
|
|
6021
|
+
Event[Event["Unload"] = 26] = "Unload";
|
|
6022
|
+
Event[Event["Input"] = 27] = "Input";
|
|
6023
|
+
Event[Event["Visibility"] = 28] = "Visibility";
|
|
6024
|
+
Event[Event["Navigation"] = 29] = "Navigation";
|
|
6025
|
+
/**
|
|
6026
|
+
* @deprecated No longer support Network Connection
|
|
6027
|
+
*/
|
|
6028
|
+
Event[Event["Connection"] = 30] = "Connection";
|
|
6029
|
+
Event[Event["ScriptError"] = 31] = "ScriptError";
|
|
6030
|
+
/**
|
|
6031
|
+
* @deprecated No longer support Image Error
|
|
6032
|
+
*/
|
|
6033
|
+
Event[Event["ImageError"] = 32] = "ImageError";
|
|
6034
|
+
Event[Event["Log"] = 33] = "Log";
|
|
6035
|
+
Event[Event["Variable"] = 34] = "Variable";
|
|
6036
|
+
Event[Event["Limit"] = 35] = "Limit";
|
|
6037
|
+
Event[Event["Summary"] = 36] = "Summary";
|
|
6038
|
+
/**
|
|
6039
|
+
* @deprecated No longer support Box event
|
|
6040
|
+
*/
|
|
6041
|
+
Event[Event["Box"] = 37] = "Box";
|
|
6042
|
+
Event[Event["Clipboard"] = 38] = "Clipboard";
|
|
6043
|
+
Event[Event["Submit"] = 39] = "Submit";
|
|
6044
|
+
Event[Event["Extract"] = 40] = "Extract";
|
|
6045
|
+
Event[Event["Fraud"] = 41] = "Fraud";
|
|
6046
|
+
Event[Event["Change"] = 42] = "Change";
|
|
6047
|
+
Event[Event["Snapshot"] = 43] = "Snapshot";
|
|
6048
|
+
Event[Event["Animation"] = 44] = "Animation";
|
|
6049
|
+
Event[Event["StyleSheetAdoption"] = 45] = "StyleSheetAdoption";
|
|
6050
|
+
Event[Event["StyleSheetUpdate"] = 46] = "StyleSheetUpdate";
|
|
6051
|
+
Event[Event["Consent"] = 47] = "Consent";
|
|
6052
|
+
Event[Event["ContextMenu"] = 48] = "ContextMenu";
|
|
6053
|
+
// 49 is reserved for internal use
|
|
6054
|
+
Event[Event["Focus"] = 50] = "Focus";
|
|
6055
|
+
Event[Event["CustomElement"] = 51] = "CustomElement";
|
|
6056
|
+
Event[Event["Chat"] = 52] = "Chat";
|
|
6057
|
+
// Apps specific events
|
|
6058
|
+
Event[Event["WebViewDiscover"] = 100] = "WebViewDiscover";
|
|
6059
|
+
Event[Event["WebViewMutation"] = 101] = "WebViewMutation";
|
|
6060
|
+
Event[Event["MutationError"] = 102] = "MutationError";
|
|
6061
|
+
Event[Event["FragmentVisibility"] = 103] = "FragmentVisibility";
|
|
6062
|
+
Event[Event["Keystrokes"] = 104] = "Keystrokes";
|
|
6063
|
+
Event[Event["BackGesture"] = 105] = "BackGesture";
|
|
6064
|
+
Event[Event["WebViewStatus"] = 106] = "WebViewStatus";
|
|
6065
|
+
Event[Event["AppInstallReferrer"] = 107] = "AppInstallReferrer";
|
|
6066
|
+
// 200-300 reserved for internal use
|
|
6067
|
+
})(Event || (Event = {}));
|
|
6068
|
+
|
|
6069
|
+
var Constant;
|
|
6070
|
+
(function (Constant) {
|
|
6071
|
+
Constant["Empty"] = "";
|
|
6072
|
+
Constant["SvgPrefix"] = "svg:";
|
|
6073
|
+
Constant["DataPrefix"] = "data:";
|
|
6074
|
+
Constant["IFramePrefix"] = "iframe:";
|
|
6075
|
+
Constant["SvgNamespace"] = "http://www.w3.org/2000/svg";
|
|
6076
|
+
Constant["Id"] = "id";
|
|
6077
|
+
Constant["Class"] = "class";
|
|
6078
|
+
Constant["Style"] = "style";
|
|
6079
|
+
Constant["Href"] = "href";
|
|
6080
|
+
Constant["Src"] = "src";
|
|
6081
|
+
Constant["Srcset"] = "srcset";
|
|
6082
|
+
Constant["Hash"] = "#";
|
|
6083
|
+
Constant["Dot"] = ".";
|
|
6084
|
+
Constant["Separator"] = ">";
|
|
6085
|
+
Constant["Tilde"] = "~";
|
|
6086
|
+
Constant["Bang"] = "!";
|
|
6087
|
+
Constant["Period"] = ".";
|
|
6088
|
+
Constant["Comma"] = ",";
|
|
6089
|
+
Constant["DataAttribute"] = "data-";
|
|
6090
|
+
Constant["MaskData"] = "data-clarity-mask";
|
|
6091
|
+
Constant["UnmaskData"] = "data-clarity-unmask";
|
|
6092
|
+
Constant["RegionData"] = "data-clarity-region";
|
|
6093
|
+
Constant["GXDialogModal"] = "gx-dialog-modal";
|
|
6094
|
+
Constant["Type"] = "type";
|
|
6095
|
+
Constant["Submit"] = "submit";
|
|
6096
|
+
Constant["Name"] = "name";
|
|
6097
|
+
Constant["Base"] = "*B";
|
|
6098
|
+
Constant["SameOrigin"] = "*O";
|
|
6099
|
+
Constant["Object"] = "object";
|
|
6100
|
+
Constant["Function"] = "function";
|
|
6101
|
+
Constant["StyleTag"] = "STYLE";
|
|
6102
|
+
Constant["LinkTag"] = "LINK";
|
|
6103
|
+
Constant["InputTag"] = "INPUT";
|
|
6104
|
+
Constant["IFrameTag"] = "IFRAME";
|
|
6105
|
+
Constant["ImageTag"] = "IMG";
|
|
6106
|
+
Constant["TitleTag"] = "TITLE";
|
|
6107
|
+
Constant["BodyTag"] = "BODY";
|
|
6108
|
+
Constant["SvgTag"] = "svg:svg";
|
|
6109
|
+
Constant["BaseTag"] = "BASE";
|
|
6110
|
+
Constant["NativeCode"] = "[native code]";
|
|
6111
|
+
Constant["DocumentTag"] = "*D";
|
|
6112
|
+
Constant["ShadowDomTag"] = "*S";
|
|
6113
|
+
Constant["PolyfillShadowDomTag"] = "*P";
|
|
6114
|
+
Constant["TextTag"] = "*T";
|
|
6115
|
+
Constant["SuspendMutationTag"] = "*M";
|
|
6116
|
+
Constant["ChildList"] = "childList";
|
|
6117
|
+
Constant["Attributes"] = "attributes";
|
|
6118
|
+
Constant["CharacterData"] = "characterData";
|
|
6119
|
+
Constant["Throttle"] = "throttle";
|
|
6120
|
+
Constant["LoadEvent"] = "load";
|
|
6121
|
+
Constant["Pixel"] = "px";
|
|
6122
|
+
Constant["BorderBox"] = "border-box";
|
|
6123
|
+
Constant["Value"] = "value";
|
|
6124
|
+
Constant["MutationObserver"] = "MutationObserver";
|
|
6125
|
+
Constant["JsonLD"] = "application/ld+json";
|
|
6126
|
+
Constant["String"] = "string";
|
|
6127
|
+
Constant["Number"] = "number";
|
|
6128
|
+
Constant["Disable"] = "disable";
|
|
6129
|
+
Constant["HTML"] = "HTML";
|
|
6130
|
+
Constant["Property"] = "property";
|
|
6131
|
+
Constant["Content"] = "content";
|
|
6132
|
+
Constant["Generator"] = "generator";
|
|
6133
|
+
Constant["ogType"] = "og:type";
|
|
6134
|
+
Constant["ogTitle"] = "og:title";
|
|
6135
|
+
Constant["SvgStyle"] = "svg:style";
|
|
6136
|
+
Constant["StyleSheet"] = "stylesheet";
|
|
6137
|
+
})(Constant || (Constant = {}));
|
|
6138
|
+
|
|
6139
|
+
var ShortCircuitStrategy;
|
|
6140
|
+
(function (ShortCircuitStrategy) {
|
|
6141
|
+
ShortCircuitStrategy[ShortCircuitStrategy["None"] = 0] = "None";
|
|
6142
|
+
ShortCircuitStrategy[ShortCircuitStrategy["HashFirstTimestamp"] = 1] = "HashFirstTimestamp";
|
|
6143
|
+
ShortCircuitStrategy[ShortCircuitStrategy["HashFirstTimestampPlusBuffer"] = 2] = "HashFirstTimestampPlusBuffer";
|
|
6144
|
+
ShortCircuitStrategy[ShortCircuitStrategy["HashBeforeDeleted"] = 3] = "HashBeforeDeleted";
|
|
6145
|
+
})(ShortCircuitStrategy || (ShortCircuitStrategy = {}));
|
|
6146
|
+
|
|
6147
|
+
function isShadowDomNode(tag) {
|
|
6148
|
+
return tag === Constant.ShadowDomTag || tag === Constant.PolyfillShadowDomTag;
|
|
6149
|
+
}
|
|
6150
|
+
/** Scan the rendered DOM (including nested shadow roots) to collect tag names of shadow host elements. */
|
|
6151
|
+
function collectShadowHostTags(root, tags = new Set()) {
|
|
6152
|
+
root.querySelectorAll('*').forEach((el) => {
|
|
6153
|
+
if (el.shadowRoot) {
|
|
6154
|
+
tags.add(el.tagName);
|
|
6155
|
+
collectShadowHostTags(el.shadowRoot, tags);
|
|
6156
|
+
}
|
|
6157
|
+
});
|
|
6158
|
+
return tags;
|
|
6159
|
+
}
|
|
6160
|
+
/** Build a shadow subtree ID set from all DOM events.
|
|
6161
|
+
* Two-pass cascade to handle any event ordering:
|
|
6162
|
+
* Pass 1 — seed *S/*P node IDs.
|
|
6163
|
+
* Pass 2 — cascade: any node whose parent is in the set is also in the set (repeat until stable). */
|
|
6164
|
+
function buildShadowSubtreeIds(allDomEvents) {
|
|
6165
|
+
const subtreeIds = new Set();
|
|
6166
|
+
for (const e of allDomEvents) {
|
|
6167
|
+
const data = e.data;
|
|
6168
|
+
for (const node of data ?? []) {
|
|
6169
|
+
if (isShadowDomNode(node.tag))
|
|
6170
|
+
subtreeIds.add(node.id);
|
|
6171
|
+
}
|
|
6172
|
+
}
|
|
6173
|
+
let changed = true;
|
|
6174
|
+
while (changed) {
|
|
6175
|
+
changed = false;
|
|
6176
|
+
for (const e of allDomEvents) {
|
|
6177
|
+
const data = e.data;
|
|
6178
|
+
for (const node of data ?? []) {
|
|
6179
|
+
if (!subtreeIds.has(node.id) && subtreeIds.has(node.parent)) {
|
|
6180
|
+
subtreeIds.add(node.id);
|
|
6181
|
+
changed = true;
|
|
6182
|
+
}
|
|
6183
|
+
}
|
|
6184
|
+
}
|
|
6185
|
+
}
|
|
6186
|
+
return subtreeIds;
|
|
6187
|
+
}
|
|
6188
|
+
function filterShadowNodes(data, subtreeIds, shadowHostTags) {
|
|
6189
|
+
return (data?.filter((node) => {
|
|
6190
|
+
if (isShadowDomNode(node.tag))
|
|
6191
|
+
return true;
|
|
6192
|
+
if (shadowHostTags.has(node.tag ?? ''))
|
|
6193
|
+
return true;
|
|
6194
|
+
return subtreeIds.has(node.id);
|
|
6195
|
+
}) ?? []);
|
|
6196
|
+
}
|
|
6197
|
+
/** Extract shadow DOM nodes from merged.dom (initial Discover event, processed by setup()).
|
|
6198
|
+
* Returns a filtered copy of the dom event, or null if no shadow DOM present. */
|
|
6199
|
+
function extractSpecialDom(dom, events, shadowHostTags) {
|
|
6200
|
+
const mutationEvents = events.filter((e) => e.event === Event.Mutation);
|
|
6201
|
+
const subtreeIds = buildShadowSubtreeIds([dom, ...mutationEvents]);
|
|
6202
|
+
const shadowNodes = filterShadowNodes(dom.data, subtreeIds, shadowHostTags);
|
|
6203
|
+
return shadowNodes.length ? { ...dom, data: shadowNodes } : null;
|
|
6204
|
+
}
|
|
6205
|
+
/** Extract shadow DOM mutations + StyleSheet + CustomElement events from merged.events. */
|
|
6206
|
+
function extractSpecialEvents(events, dom, shadowHostTags) {
|
|
6207
|
+
const mutationEvents = events.filter((e) => e.event === Event.Mutation);
|
|
6208
|
+
const subtreeIds = buildShadowSubtreeIds([dom, ...mutationEvents]);
|
|
6209
|
+
const result = [];
|
|
6210
|
+
for (const e of events) {
|
|
6211
|
+
const ev = e.event;
|
|
6212
|
+
if (ev === Event.StyleSheetAdoption ||
|
|
6213
|
+
ev === Event.StyleSheetUpdate ||
|
|
6214
|
+
ev === Event.CustomElement) {
|
|
6215
|
+
result.push(e);
|
|
6216
|
+
continue;
|
|
6217
|
+
}
|
|
6218
|
+
if (ev === Event.Mutation) {
|
|
6219
|
+
const shadowNodes = filterShadowNodes(e.data, subtreeIds, shadowHostTags);
|
|
6220
|
+
if (shadowNodes.length)
|
|
6221
|
+
result.push({ ...e, data: shadowNodes });
|
|
6222
|
+
}
|
|
6223
|
+
}
|
|
6224
|
+
return result;
|
|
6225
|
+
}
|
|
6226
|
+
|
|
6227
|
+
// utils/retry.ts
|
|
6228
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
6229
|
+
/**
|
|
6230
|
+
* Retry until the callback returns truthy, or throw if the limit is exceeded.
|
|
6231
|
+
*
|
|
6232
|
+
* @example
|
|
6233
|
+
* await retry(() => doc.readyState === 'complete', { timeout: 5000, label: 'DOM ready' });
|
|
6234
|
+
*
|
|
6235
|
+
* @example
|
|
6236
|
+
* const el = await retry(() => document.getElementById('app'), { maxRetries: 20 });
|
|
6237
|
+
*/
|
|
6238
|
+
async function retry(callback, options = {}) {
|
|
6239
|
+
const { interval = 100, label = 'Retry' } = options;
|
|
6240
|
+
const maxRetries = options.timeout != null ? Math.ceil(options.timeout / interval) : (options.maxRetries ?? 50);
|
|
6241
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
6242
|
+
console.log(`🔄 [${label}] attempt ${attempt}/${maxRetries}`);
|
|
6243
|
+
const result = await callback();
|
|
6244
|
+
if (result) {
|
|
6245
|
+
return result;
|
|
6246
|
+
}
|
|
6247
|
+
if (attempt < maxRetries) {
|
|
6248
|
+
await delay(interval);
|
|
6249
|
+
}
|
|
6250
|
+
}
|
|
6251
|
+
const totalMs = maxRetries * interval;
|
|
6252
|
+
throw new Error(`[${label}] Timed out after ${maxRetries} retries (${totalMs}ms)`);
|
|
6253
|
+
}
|
|
6254
|
+
|
|
6255
|
+
const perf$2 = createPerfTimer('Render');
|
|
6256
|
+
const YIELD_INTERVAL_MS = 16;
|
|
6257
|
+
async function yieldToMain() {
|
|
6258
|
+
if ('scheduler' in globalThis && typeof globalThis.scheduler?.yield === 'function') {
|
|
6259
|
+
await globalThis.scheduler.yield();
|
|
6260
|
+
}
|
|
6261
|
+
else {
|
|
6262
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
6263
|
+
}
|
|
6264
|
+
}
|
|
6265
|
+
const renderLoop = async (ctx, options) => {
|
|
6266
|
+
const { events, useproxy } = options;
|
|
6267
|
+
const shortCircuitStrategy = options.shortCircuitStrategy ?? ShortCircuitStrategy.None;
|
|
6268
|
+
const hash = options.hash ?? null;
|
|
6269
|
+
const t0 = perf$2.mark('RenderLoop start');
|
|
6270
|
+
let lastYield = performance.now();
|
|
6271
|
+
const totalEvents = events.length;
|
|
6272
|
+
for (let i = 0; i < totalEvents; i++) {
|
|
6273
|
+
const entry = events[i];
|
|
6274
|
+
const entryEvent = entry.event;
|
|
6275
|
+
const now = performance.now();
|
|
6276
|
+
if (now - lastYield > YIELD_INTERVAL_MS) {
|
|
6277
|
+
console.log(`[RenderLoop] ${i}/${totalEvents} time:`, now - lastYield);
|
|
6278
|
+
await yieldToMain();
|
|
6279
|
+
lastYield = performance.now();
|
|
6280
|
+
}
|
|
6281
|
+
switch (entryEvent) {
|
|
6282
|
+
case Event.StyleSheetAdoption:
|
|
6283
|
+
case Event.StyleSheetUpdate:
|
|
6284
|
+
ctx.layout.styleChange(entry);
|
|
6285
|
+
break;
|
|
6286
|
+
case Event.CustomElement:
|
|
6287
|
+
ctx.layout.customElement(entry);
|
|
6288
|
+
break;
|
|
6289
|
+
case Event.Mutation: {
|
|
6290
|
+
const domEvent = entry;
|
|
6291
|
+
ctx.renderTime = domEvent.time;
|
|
6292
|
+
if (ctx.shortCircuitRendering(shortCircuitStrategy, domEvent, hash))
|
|
6293
|
+
return;
|
|
6294
|
+
ctx.layout.markup(domEvent, useproxy);
|
|
6295
|
+
break;
|
|
6296
|
+
}
|
|
6297
|
+
}
|
|
6298
|
+
}
|
|
6299
|
+
perf$2.measure('RenderLoop', t0);
|
|
6300
|
+
};
|
|
6301
|
+
|
|
5515
6302
|
class GXVisualizer extends Visualizer {
|
|
5516
6303
|
attentionMap;
|
|
5517
6304
|
originalClearmap;
|
|
@@ -5519,25 +6306,43 @@ class GXVisualizer extends Visualizer {
|
|
|
5519
6306
|
constructor() {
|
|
5520
6307
|
super();
|
|
5521
6308
|
this.attentionMap = new AttentionMapRenderer(null);
|
|
5522
|
-
// Save references to base implementations before overriding
|
|
5523
6309
|
this.originalSetup = this.setup;
|
|
5524
6310
|
this.originalClearmap = this.clearmap;
|
|
5525
6311
|
this.clearmap = this.clearmapOverride;
|
|
5526
6312
|
this.setup = this.setupOverride;
|
|
5527
6313
|
}
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
6314
|
+
htmlRender = async (props) => {
|
|
6315
|
+
const { decoded, target, portalCanvasId, useproxy, logerror } = props;
|
|
6316
|
+
if (!decoded || decoded.length === 0 || !target)
|
|
6317
|
+
return this;
|
|
6318
|
+
try {
|
|
6319
|
+
const merged = this.mergeForHtml(decoded);
|
|
6320
|
+
await this.setup(target, { version: decoded[0].envelope.version, dom: merged.dom, useproxy, portalCanvasId });
|
|
6321
|
+
await this.renderLoop(this, { events: merged.events, target, useproxy });
|
|
6322
|
+
}
|
|
6323
|
+
catch (e) {
|
|
6324
|
+
if (logerror)
|
|
6325
|
+
logerror(e);
|
|
6326
|
+
}
|
|
5536
6327
|
return this;
|
|
5537
6328
|
};
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
6329
|
+
htmlCached = async (cacheKey, options) => {
|
|
6330
|
+
const { decoded, target } = options;
|
|
6331
|
+
if (!decoded || decoded.length === 0 || !target)
|
|
6332
|
+
return this;
|
|
6333
|
+
const fullKey = buildCacheKey(cacheKey, options.shortCircuitStrategy);
|
|
6334
|
+
const cached = await htmlCache.get(fullKey);
|
|
6335
|
+
if (cached) {
|
|
6336
|
+
try {
|
|
6337
|
+
await this.buildHtmlByCached(cached, options);
|
|
6338
|
+
return this;
|
|
6339
|
+
}
|
|
6340
|
+
catch (e) {
|
|
6341
|
+
options?.logerror?.(e);
|
|
6342
|
+
}
|
|
6343
|
+
}
|
|
6344
|
+
await this.buildHtmlForCache(fullKey, options);
|
|
6345
|
+
return this;
|
|
5541
6346
|
};
|
|
5542
6347
|
/**
|
|
5543
6348
|
* Render attention/engagement map.
|
|
@@ -5549,75 +6354,229 @@ class GXVisualizer extends Visualizer {
|
|
|
5549
6354
|
this.clearmapOverride();
|
|
5550
6355
|
this.attentionMap.attention(attentionData, avgFold, this, isSecondary);
|
|
5551
6356
|
};
|
|
6357
|
+
buildHtmlByCached = async (cached, options) => {
|
|
6358
|
+
const { target, useproxy, portalCanvasId } = options;
|
|
6359
|
+
if (!cached || !target)
|
|
6360
|
+
throw new Error('Failed to render HTML cached');
|
|
6361
|
+
const doc = target.document;
|
|
6362
|
+
target.window;
|
|
6363
|
+
try {
|
|
6364
|
+
await this.setup(target, { version: cached.version, useproxy, portalCanvasId });
|
|
6365
|
+
doc.open();
|
|
6366
|
+
doc.write(cached.html);
|
|
6367
|
+
doc.close();
|
|
6368
|
+
const process = async () => {
|
|
6369
|
+
this.layout.hydrate(doc);
|
|
6370
|
+
// Replay shadow DOM from initial Discover event
|
|
6371
|
+
if (cached.specialDom) {
|
|
6372
|
+
this.layout.markup(cached.specialDom, useproxy);
|
|
6373
|
+
}
|
|
6374
|
+
// Replay shadow DOM mutations + StyleSheet + CustomElement
|
|
6375
|
+
await this.renderLoop(this, { ...options, events: cached.specialEvents });
|
|
6376
|
+
};
|
|
6377
|
+
await retry(() => doc.readyState === 'complete', { timeout: 30000, label: 'DOM ready' });
|
|
6378
|
+
await process();
|
|
6379
|
+
return this;
|
|
6380
|
+
}
|
|
6381
|
+
catch (e) {
|
|
6382
|
+
throw new Error('Failed to render HTML cached', { cause: e });
|
|
6383
|
+
}
|
|
6384
|
+
};
|
|
6385
|
+
buildHtmlForCache = async (cacheKey, options) => {
|
|
6386
|
+
const { decoded, target, useproxy, portalCanvasId, logerror } = options;
|
|
6387
|
+
if (!decoded || decoded.length === 0 || !target)
|
|
6388
|
+
return this;
|
|
6389
|
+
try {
|
|
6390
|
+
const merged = this.mergeForHtml(decoded);
|
|
6391
|
+
await this.setup(target, { version: decoded[0].envelope.version, dom: merged.dom, useproxy, portalCanvasId });
|
|
6392
|
+
await this.renderLoop(this, { events: merged.events, target, useproxy });
|
|
6393
|
+
const timestamp = Date.now();
|
|
6394
|
+
const version = decoded[0].envelope.version;
|
|
6395
|
+
const html = target.document.documentElement.outerHTML;
|
|
6396
|
+
const shadowHostTags = collectShadowHostTags(target.document);
|
|
6397
|
+
const specialDom = extractSpecialDom(merged.dom, merged.events, shadowHostTags);
|
|
6398
|
+
const specialEvents = extractSpecialEvents(merged.events, merged.dom, shadowHostTags);
|
|
6399
|
+
void htmlCache.set({ key: cacheKey, html, specialDom, specialEvents, version, timestamp });
|
|
6400
|
+
}
|
|
6401
|
+
catch (e) {
|
|
6402
|
+
if (logerror)
|
|
6403
|
+
logerror(e);
|
|
6404
|
+
}
|
|
6405
|
+
return this;
|
|
6406
|
+
};
|
|
6407
|
+
renderLoop = async (ctx, options) => {
|
|
6408
|
+
await renderLoop(ctx, options);
|
|
6409
|
+
};
|
|
6410
|
+
setupOverride = async (target, options) => {
|
|
6411
|
+
this.attentionMap?.clear();
|
|
6412
|
+
await this.originalSetup(target, options);
|
|
6413
|
+
this.attentionMap = new AttentionMapRenderer(this.state);
|
|
6414
|
+
return this;
|
|
6415
|
+
};
|
|
6416
|
+
clearmapOverride = () => {
|
|
6417
|
+
this.originalClearmap();
|
|
6418
|
+
this.attentionMap?.clear();
|
|
6419
|
+
};
|
|
5552
6420
|
}
|
|
5553
6421
|
|
|
5554
|
-
const
|
|
5555
|
-
|
|
5556
|
-
const
|
|
5557
|
-
const vizRef = useHeatmapVizRectContext((s) => s.vizRef);
|
|
5558
|
-
const setVizRef = useHeatmapVizRectContext((s) => s.setVizRef);
|
|
5559
|
-
const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
|
|
5560
|
-
const setIsRenderViz = useHeatmapVizContext((s) => s.setIsRenderViz);
|
|
5561
|
-
const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
|
|
5562
|
-
const contentWidth = useHeatmapWidthByDevice();
|
|
6422
|
+
const perf$1 = createPerfTimer('Render');
|
|
6423
|
+
const useHeatmapIframeProcessor = () => {
|
|
6424
|
+
const shopId = useHeatmapConfigStore((s) => s.shopId);
|
|
5563
6425
|
const deviceType = useHeatmapSettingContext((s) => s.deviceType);
|
|
5564
|
-
const
|
|
5565
|
-
const
|
|
5566
|
-
|
|
6426
|
+
const viewport = useHeatmapViewportByDevice();
|
|
6427
|
+
const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
|
|
6428
|
+
const setIsDomLoaded = useHeatmapVizContext((s) => s.setIsDomLoaded);
|
|
6429
|
+
const helperRef = useRef(null);
|
|
6430
|
+
const pendingRef = useRef(null);
|
|
6431
|
+
const reset = useCallback(() => {
|
|
6432
|
+
pendingRef.current = null;
|
|
6433
|
+
}, []);
|
|
6434
|
+
const run = useCallback((iframe, t0, abort) => {
|
|
6435
|
+
if (viewport.width === 0 || viewport.height === 0) {
|
|
6436
|
+
pendingRef.current = { iframe, t0, abort };
|
|
5567
6437
|
return;
|
|
5568
|
-
|
|
6438
|
+
}
|
|
6439
|
+
startIframe({
|
|
6440
|
+
helperRef,
|
|
6441
|
+
iframe,
|
|
6442
|
+
shopId,
|
|
6443
|
+
deviceType,
|
|
6444
|
+
size: viewport,
|
|
6445
|
+
t0,
|
|
6446
|
+
onSuccess: (height) => {
|
|
6447
|
+
if (abort.signal.aborted)
|
|
6448
|
+
return;
|
|
6449
|
+
if (height)
|
|
6450
|
+
setIframeHeight(height);
|
|
6451
|
+
setIsDomLoaded(true);
|
|
6452
|
+
},
|
|
6453
|
+
});
|
|
6454
|
+
}, [deviceType]);
|
|
6455
|
+
// Retry when dims become available
|
|
6456
|
+
useEffect(() => {
|
|
6457
|
+
if (viewport.width === 0 || viewport.height === 0)
|
|
5569
6458
|
return;
|
|
5570
|
-
|
|
5571
|
-
if (!vizRef)
|
|
5572
|
-
setVizRef(visualizer);
|
|
5573
|
-
setIsRenderViz(false);
|
|
5574
|
-
const iframe = iframeRef.current;
|
|
5575
|
-
if (!iframe?.contentWindow)
|
|
6459
|
+
if (!pendingRef.current)
|
|
5576
6460
|
return;
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
6461
|
+
const { iframe, t0, abort } = pendingRef.current;
|
|
6462
|
+
pendingRef.current = null;
|
|
6463
|
+
if (abort.signal.aborted)
|
|
6464
|
+
return;
|
|
6465
|
+
startIframe({
|
|
6466
|
+
helperRef,
|
|
6467
|
+
iframe,
|
|
6468
|
+
shopId,
|
|
6469
|
+
deviceType,
|
|
6470
|
+
size: viewport,
|
|
6471
|
+
t0,
|
|
6472
|
+
onSuccess: (height) => {
|
|
6473
|
+
if (abort.signal.aborted)
|
|
6474
|
+
return;
|
|
6475
|
+
if (height)
|
|
6476
|
+
setIframeHeight(height);
|
|
6477
|
+
setIsDomLoaded(true);
|
|
6478
|
+
},
|
|
5582
6479
|
});
|
|
5583
|
-
|
|
5584
|
-
}, [wrapperHeight, contentWidth, deviceType]);
|
|
6480
|
+
}, [viewport]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
5585
6481
|
useEffect(() => {
|
|
5586
|
-
if (!data || data.length === 0)
|
|
5587
|
-
return;
|
|
5588
|
-
const decoded = decodeArrayClarity(data);
|
|
5589
|
-
renderHeatmap(decoded);
|
|
5590
6482
|
return () => {
|
|
5591
|
-
|
|
6483
|
+
helperRef.current?.stop();
|
|
6484
|
+
helperRef.current = null;
|
|
5592
6485
|
};
|
|
5593
|
-
}, [
|
|
5594
|
-
return {
|
|
5595
|
-
iframeRef,
|
|
5596
|
-
};
|
|
6486
|
+
}, []);
|
|
6487
|
+
return { run, reset };
|
|
5597
6488
|
};
|
|
5598
|
-
|
|
6489
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
6490
|
+
function startIframe({ helperRef, iframe, shopId, deviceType = EDeviceType.Desktop, size, t0, onSuccess, }) {
|
|
5599
6491
|
const docWidth = size.width ?? 0;
|
|
5600
6492
|
const docHeight = size.height ?? 0;
|
|
5601
6493
|
if (docHeight === 0)
|
|
5602
6494
|
return;
|
|
5603
|
-
stop();
|
|
5604
|
-
start
|
|
5605
|
-
|
|
6495
|
+
helperRef.current?.stop();
|
|
6496
|
+
const tHelper = perf$1.mark('IframeHelper.start');
|
|
6497
|
+
const helper = createIframeHelper();
|
|
6498
|
+
helperRef.current = helper;
|
|
6499
|
+
helper.start({
|
|
6500
|
+
deviceType,
|
|
5606
6501
|
targetWidth: docWidth,
|
|
5607
6502
|
targetHeight: docHeight,
|
|
5608
|
-
iframe
|
|
6503
|
+
iframe,
|
|
5609
6504
|
debug: true,
|
|
6505
|
+
shopId,
|
|
5610
6506
|
onSuccess: (data) => {
|
|
6507
|
+
perf$1.measure('IframeHelper processing', tHelper);
|
|
6508
|
+
perf$1.measure('Total render', t0);
|
|
5611
6509
|
iframe.style.height = `${data.height}px`;
|
|
5612
6510
|
onSuccess(data.height);
|
|
5613
6511
|
},
|
|
5614
6512
|
});
|
|
5615
|
-
// fixer.recalculate();
|
|
5616
6513
|
}
|
|
5617
6514
|
|
|
6515
|
+
const perf = createPerfTimer('Render');
|
|
6516
|
+
const useHeatmapRenderDom = () => {
|
|
6517
|
+
const viewId = useViewIdContext();
|
|
6518
|
+
const data = useHeatmapDataContext((s) => s.data);
|
|
6519
|
+
const excludeClassNames = useHeatmapConfigStore((s) => s.excludeClassNames);
|
|
6520
|
+
const setVizRef = useHeatmapVizRectContext((s) => s.setVizRef);
|
|
6521
|
+
const vizRef = useHeatmapVizRectContext((s) => s.vizRef);
|
|
6522
|
+
const setIsDomLoaded = useHeatmapVizContext((s) => s.setIsDomLoaded);
|
|
6523
|
+
const deviceType = useHeatmapSettingContext((s) => s.deviceType);
|
|
6524
|
+
const heatmapType = useHeatmapSettingContext((s) => s.heatmapType);
|
|
6525
|
+
const elementToShow = useHeatmapDataContext((s) => s.dataInfo?.elementToShow);
|
|
6526
|
+
const dataHash = useHeatmapDataContext((s) => s.dataHash);
|
|
6527
|
+
const iframeRef = useRef(null);
|
|
6528
|
+
const abortRef = useRef(null);
|
|
6529
|
+
const elementToShowRef = useRef(null);
|
|
6530
|
+
const dataHashRef = useRef(null);
|
|
6531
|
+
const heatmapTypeRef = useRef(heatmapType);
|
|
6532
|
+
elementToShowRef.current = elementToShow ?? null;
|
|
6533
|
+
dataHashRef.current = dataHash ?? null;
|
|
6534
|
+
heatmapTypeRef.current = heatmapType;
|
|
6535
|
+
const { run: runIframeSetup, reset: resetIframeSetup } = useHeatmapIframeProcessor();
|
|
6536
|
+
const renderHeatmap = useCallback(async (payloads) => {
|
|
6537
|
+
if (!payloads || payloads.length === 0)
|
|
6538
|
+
return;
|
|
6539
|
+
const iframe = iframeRef.current;
|
|
6540
|
+
const contentWindow = iframe?.contentWindow;
|
|
6541
|
+
if (!contentWindow)
|
|
6542
|
+
return;
|
|
6543
|
+
abortRef.current?.abort();
|
|
6544
|
+
const abort = new AbortController();
|
|
6545
|
+
abortRef.current = abort;
|
|
6546
|
+
resetIframeSetup();
|
|
6547
|
+
const t0 = perf.mark('RenderHeatmap start');
|
|
6548
|
+
const visualizer = vizRef ?? new GXVisualizer();
|
|
6549
|
+
if (!vizRef)
|
|
6550
|
+
setVizRef(visualizer);
|
|
6551
|
+
visualizer.configure({ excludeClassNames });
|
|
6552
|
+
setIsDomLoaded(false);
|
|
6553
|
+
// Phase 1: render DOM — does not depend on contentWidth/wrapperHeight
|
|
6554
|
+
const cacheKey = dataHashRef.current;
|
|
6555
|
+
const options = {
|
|
6556
|
+
decoded: payloads,
|
|
6557
|
+
target: contentWindow,
|
|
6558
|
+
portalCanvasId: viewId,
|
|
6559
|
+
logerror: (error) => {
|
|
6560
|
+
console.error('Error rendering HTML', error);
|
|
6561
|
+
},
|
|
6562
|
+
};
|
|
6563
|
+
await perf.wrap('RenderHtml', () => cacheKey ? visualizer.htmlCached(cacheKey, options) : visualizer.htmlRender(options));
|
|
6564
|
+
if (abort.signal.aborted)
|
|
6565
|
+
return;
|
|
6566
|
+
// Phase 2: iframe setup — deferred to useIframeSetup (handles dims dependency)
|
|
6567
|
+
runIframeSetup(iframe, t0, abort);
|
|
6568
|
+
}, [deviceType]);
|
|
6569
|
+
useEffect(() => {
|
|
6570
|
+
if (!data || data.length === 0)
|
|
6571
|
+
return;
|
|
6572
|
+
renderHeatmap(decodeArrayClarity(data));
|
|
6573
|
+
}, [data, renderHeatmap]);
|
|
6574
|
+
return { iframeRef };
|
|
6575
|
+
};
|
|
6576
|
+
|
|
5618
6577
|
const useReplayRender = () => {
|
|
5619
6578
|
const data = useHeatmapDataContext((s) => s.data);
|
|
5620
|
-
const
|
|
6579
|
+
const setIsDomLoaded = useHeatmapVizContext((s) => s.setIsDomLoaded);
|
|
5621
6580
|
const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
|
|
5622
6581
|
const visualizerRef = useRef(null);
|
|
5623
6582
|
const iframeRef = useRef(null);
|
|
@@ -5637,7 +6596,7 @@ const useReplayRender = () => {
|
|
|
5637
6596
|
version: envelope.version,
|
|
5638
6597
|
onresize: (height) => {
|
|
5639
6598
|
height && setIframeHeight(height);
|
|
5640
|
-
|
|
6599
|
+
setIsDomLoaded(true);
|
|
5641
6600
|
},
|
|
5642
6601
|
mobile,
|
|
5643
6602
|
vNext: true,
|
|
@@ -5740,10 +6699,12 @@ const useReplayRender = () => {
|
|
|
5740
6699
|
const useHeatmapRenderByMode = (mode) => {
|
|
5741
6700
|
const heatmapResult = useMemo(() => {
|
|
5742
6701
|
switch (mode) {
|
|
5743
|
-
case
|
|
5744
|
-
return
|
|
5745
|
-
case
|
|
6702
|
+
case EHeatmapMode.Heatmap:
|
|
6703
|
+
return useHeatmapRenderDom;
|
|
6704
|
+
case EHeatmapMode.Replay:
|
|
5746
6705
|
return useReplayRender;
|
|
6706
|
+
default:
|
|
6707
|
+
return useHeatmapRenderDom;
|
|
5747
6708
|
}
|
|
5748
6709
|
}, [mode]);
|
|
5749
6710
|
return heatmapResult();
|
|
@@ -5778,22 +6739,10 @@ const useContainerDimensions = (props) => {
|
|
|
5778
6739
|
return { containerWidth, containerHeight };
|
|
5779
6740
|
};
|
|
5780
6741
|
|
|
5781
|
-
const useContentDimensions = ({ iframeRef }) => {
|
|
5782
|
-
const contentWidth = useHeatmapWidthByDevice();
|
|
5783
|
-
useEffect(() => {
|
|
5784
|
-
if (!contentWidth)
|
|
5785
|
-
return;
|
|
5786
|
-
if (!iframeRef.current)
|
|
5787
|
-
return;
|
|
5788
|
-
// iframeRef.current.width = `${contentWidth}px`;
|
|
5789
|
-
}, [contentWidth, iframeRef]);
|
|
5790
|
-
return { contentWidth };
|
|
5791
|
-
};
|
|
5792
|
-
|
|
5793
6742
|
const useObserveIframeHeight = (props) => {
|
|
5794
6743
|
const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
|
|
5795
6744
|
const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
|
|
5796
|
-
const
|
|
6745
|
+
const isDomLoaded = useHeatmapVizContext((s) => s.isDomLoaded);
|
|
5797
6746
|
const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
|
|
5798
6747
|
const { iframeRef } = props;
|
|
5799
6748
|
const resizeObserverRef = useRef(null);
|
|
@@ -5854,7 +6803,7 @@ const useObserveIframeHeight = (props) => {
|
|
|
5854
6803
|
}, [updateIframeHeight]);
|
|
5855
6804
|
useEffect(() => {
|
|
5856
6805
|
const iframe = iframeRef.current;
|
|
5857
|
-
if (!iframe || !iframeHeight || !
|
|
6806
|
+
if (!iframe || !iframeHeight || !isDomLoaded)
|
|
5858
6807
|
return;
|
|
5859
6808
|
const setupObservers = () => {
|
|
5860
6809
|
try {
|
|
@@ -5916,7 +6865,7 @@ const useObserveIframeHeight = (props) => {
|
|
|
5916
6865
|
}
|
|
5917
6866
|
iframe.removeEventListener('load', setupObservers);
|
|
5918
6867
|
};
|
|
5919
|
-
}, [iframeRef, iframeHeight,
|
|
6868
|
+
}, [iframeRef, iframeHeight, isDomLoaded]);
|
|
5920
6869
|
return {};
|
|
5921
6870
|
};
|
|
5922
6871
|
|
|
@@ -5929,9 +6878,10 @@ const useScaleCalculation = (props) => {
|
|
|
5929
6878
|
const setScale = useHeatmapVizContext((s) => s.setScale);
|
|
5930
6879
|
const setIsScaledToFit = useHeatmapVizContext((s) => s.setIsScaledToFit);
|
|
5931
6880
|
const setMinZoomRatio = useHeatmapVizContext((s) => s.setMinZoomRatio);
|
|
5932
|
-
const
|
|
6881
|
+
const viewport = useHeatmapViewportByDevice();
|
|
6882
|
+
const { containerWidth, containerHeight, iframeHeight } = props;
|
|
5933
6883
|
const calculateScaleResult = useCallback(() => {
|
|
5934
|
-
if (containerWidth > 0 &&
|
|
6884
|
+
if (containerWidth > 0 && viewport.width > 0 && containerHeight > 0 && iframeHeight > 0) {
|
|
5935
6885
|
// 1. Calculate available dimensions
|
|
5936
6886
|
const availableWidth = containerWidth - HEATMAP_CONFIG['padding'] * 2;
|
|
5937
6887
|
const toolbarHeight = HEATMAP_CONFIG['heightToolbar'] || 0;
|
|
@@ -5939,12 +6889,12 @@ const useScaleCalculation = (props) => {
|
|
|
5939
6889
|
const availableHeight = containerHeight - toolbarHeight - paddingTotal;
|
|
5940
6890
|
// 2. Calculate widthScale (base scale to fit content width into container width)
|
|
5941
6891
|
// This represents 100% zoom (fit to width)
|
|
5942
|
-
const widthScale = Math.min(availableWidth /
|
|
6892
|
+
const widthScale = Math.min(availableWidth / viewport.width, 1);
|
|
5943
6893
|
// 3. Calculate minZoomRatio (zoom ratio to fit height)
|
|
5944
6894
|
// At minZoomRatio, the content should fit entirely within the container height
|
|
5945
|
-
// Formula:
|
|
5946
|
-
// => minZoomRatio = (availableHeight / (
|
|
5947
|
-
const calculatedMinZoomRatio = (availableHeight / (
|
|
6895
|
+
// Formula: iframeHeight * widthScale * (minZoomRatio / 100) = availableHeight
|
|
6896
|
+
// => minZoomRatio = (availableHeight / (iframeHeight * widthScale)) * 100
|
|
6897
|
+
const calculatedMinZoomRatio = (availableHeight / (iframeHeight * widthScale)) * 100;
|
|
5948
6898
|
// Limit minZoomRatio: cannot exceed MAX_ZOOM_RATIO (100%)
|
|
5949
6899
|
// and should have a reasonable minimum (e.g., 1%)
|
|
5950
6900
|
const finalMinZoomRatio = Math.max(1, Math.min(calculatedMinZoomRatio, maxZoomRatio));
|
|
@@ -5963,7 +6913,7 @@ const useScaleCalculation = (props) => {
|
|
|
5963
6913
|
setIsScaledToFit(isCurrentlyFitted);
|
|
5964
6914
|
setMinZoomRatio(finalMinZoomRatio);
|
|
5965
6915
|
}
|
|
5966
|
-
}, [containerWidth, containerHeight,
|
|
6916
|
+
}, [containerWidth, containerHeight, viewport.width, iframeHeight, zoomRatio, maxZoomRatio]);
|
|
5967
6917
|
useEffect(() => {
|
|
5968
6918
|
calculateScaleResult();
|
|
5969
6919
|
}, [calculateScaleResult]);
|
|
@@ -5996,20 +6946,15 @@ const useHeatmapScale = (props) => {
|
|
|
5996
6946
|
// 1. Observe container dimensions
|
|
5997
6947
|
const { containerWidth, containerHeight } = useContainerDimensions({ wrapperRef });
|
|
5998
6948
|
// 2. Get content dimensions from config
|
|
5999
|
-
const
|
|
6949
|
+
const viewport = useHeatmapViewportByDevice();
|
|
6000
6950
|
// 3. Observe iframe height (now reacts to width changes)
|
|
6001
6951
|
useObserveIframeHeight({ iframeRef });
|
|
6002
6952
|
// 4. Calculate scale
|
|
6003
|
-
const { widthScale } = useScaleCalculation({
|
|
6004
|
-
containerWidth,
|
|
6005
|
-
containerHeight,
|
|
6006
|
-
contentWidth,
|
|
6007
|
-
contentHeight: iframeHeight,
|
|
6008
|
-
});
|
|
6953
|
+
const { widthScale } = useScaleCalculation({ containerWidth, containerHeight, iframeHeight });
|
|
6009
6954
|
// 5. Setup scroll sync
|
|
6010
6955
|
const { handleScroll } = useScrollSync({ widthScale, iframeRef });
|
|
6011
6956
|
const scaledHeight = iframeHeight * widthScale;
|
|
6012
|
-
const scaledWidth =
|
|
6957
|
+
const scaledWidth = viewport.width * widthScale;
|
|
6013
6958
|
return {
|
|
6014
6959
|
scaledWidth,
|
|
6015
6960
|
scaledHeight,
|
|
@@ -6215,10 +7160,10 @@ const useScrollmapZones = (options) => {
|
|
|
6215
7160
|
const newZones = createZones(scrollmap);
|
|
6216
7161
|
setZones(newZones);
|
|
6217
7162
|
setIsReady(true);
|
|
6218
|
-
logger$
|
|
7163
|
+
logger$3.log(`[useScrollmap] Created ${newZones.length} zones in ${mode} mode`);
|
|
6219
7164
|
}
|
|
6220
7165
|
catch (error) {
|
|
6221
|
-
logger$
|
|
7166
|
+
logger$3.error('[useScrollmap] Error:', error);
|
|
6222
7167
|
setIsReady(false);
|
|
6223
7168
|
}
|
|
6224
7169
|
}, [enabled, scrollmap, mode, createZones]);
|
|
@@ -7048,11 +7993,11 @@ const AutoScrollHandler = ({ visualRef }) => {
|
|
|
7048
7993
|
};
|
|
7049
7994
|
|
|
7050
7995
|
const PortalAreaRenderer = ({ iframeRef, visualRef, shadowRoot, onAreaCreated, onAreaClick, }) => {
|
|
7051
|
-
const
|
|
7996
|
+
const isDomLoaded = useHeatmapVizContext((s) => s.isDomLoaded);
|
|
7052
7997
|
const iframeDocument = iframeRef.current?.contentDocument || undefined;
|
|
7053
7998
|
const { shadowContainer, isReady } = useAreaRendererContainer(iframeDocument, shadowRoot);
|
|
7054
|
-
useAreaRectSync({ iframeDocument, shadowRoot, enabled: isReady &&
|
|
7055
|
-
useAreaPositionsUpdater({ iframeRef, visualRef, enabled: isReady &&
|
|
7999
|
+
useAreaRectSync({ iframeDocument, shadowRoot, enabled: isReady && isDomLoaded });
|
|
8000
|
+
useAreaPositionsUpdater({ iframeRef, visualRef, enabled: isReady && isDomLoaded });
|
|
7056
8001
|
if (!shadowContainer || !isReady)
|
|
7057
8002
|
return null;
|
|
7058
8003
|
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 +8006,7 @@ const PortalAreaRenderer = ({ iframeRef, visualRef, shadowRoot, onAreaCreated, o
|
|
|
7061
8006
|
const VizAreaClick = ({ iframeRef, visualRef, shadowRoot, autoCreateTopN = 10, enableOverlapResolution = true, onAreaClick, }) => {
|
|
7062
8007
|
const clickAreas = useHeatmapDataContext((s) => s.clickAreas);
|
|
7063
8008
|
const resetView = useHeatmapAreaClickContext((s) => s.resetView);
|
|
7064
|
-
const
|
|
8009
|
+
const isDomLoaded = useHeatmapVizContext((s) => s.isDomLoaded);
|
|
7065
8010
|
useAreaTopAutoDetect({ autoCreateTopN, shadowRoot, disabled: !!clickAreas?.length });
|
|
7066
8011
|
useAreaFilterVisible({ iframeRef, enableOverlapResolution });
|
|
7067
8012
|
useAreaHydration({ shadowRoot });
|
|
@@ -7070,7 +8015,7 @@ const VizAreaClick = ({ iframeRef, visualRef, shadowRoot, autoCreateTopN = 10, e
|
|
|
7070
8015
|
resetView();
|
|
7071
8016
|
};
|
|
7072
8017
|
}, []);
|
|
7073
|
-
if (!iframeRef.current || !
|
|
8018
|
+
if (!iframeRef.current || !isDomLoaded)
|
|
7074
8019
|
return null;
|
|
7075
8020
|
return (jsx(Fragment, { children: jsx(PortalAreaRenderer, { iframeRef: iframeRef, visualRef: visualRef, shadowRoot: shadowRoot, onAreaClick: onAreaClick }) }));
|
|
7076
8021
|
};
|
|
@@ -7201,7 +8146,7 @@ const useAnchorPosition = (calloutRef, props) => {
|
|
|
7201
8146
|
const ElementMissing = ({ show = true, visualRef }) => {
|
|
7202
8147
|
const widthScale = useHeatmapVizContext((s) => s.widthScale);
|
|
7203
8148
|
const missingElementRef = useRef(null);
|
|
7204
|
-
const
|
|
8149
|
+
const viewport = useHeatmapViewportByDevice();
|
|
7205
8150
|
const [scrollPosition, setScrollPosition] = useState({ scrollTop: 0, scrollLeft: 0 });
|
|
7206
8151
|
useEffect(() => {
|
|
7207
8152
|
const container = visualRef.current;
|
|
@@ -7231,7 +8176,7 @@ const ElementMissing = ({ show = true, visualRef }) => {
|
|
|
7231
8176
|
const containerHeight = containerRect?.height ?? 0;
|
|
7232
8177
|
const topPosition = scrollTop + (containerHeight + elementHeightCenter) / 2;
|
|
7233
8178
|
const topPositionScaled = topPosition / widthScale;
|
|
7234
|
-
const leftPosition =
|
|
8179
|
+
const leftPosition = viewport.width / 2;
|
|
7235
8180
|
return (jsxs(Fragment, { children: [jsx("div", { className: "missingElement-backdrop", style: {
|
|
7236
8181
|
position: 'absolute',
|
|
7237
8182
|
top: 0,
|
|
@@ -7356,7 +8301,7 @@ const ElementOverlayComponent = (props) => {
|
|
|
7356
8301
|
const { type, element, onClick, elementId, hideOutline } = props;
|
|
7357
8302
|
const widthScale = useHeatmapVizContext((s) => s.widthScale);
|
|
7358
8303
|
const viewportHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
|
|
7359
|
-
const
|
|
8304
|
+
const viewport = useHeatmapViewportByDevice();
|
|
7360
8305
|
const overlayStyle = useMemo(() => {
|
|
7361
8306
|
const isInvalid = !element || (element.width === 0 && element.height === 0);
|
|
7362
8307
|
if (isInvalid)
|
|
@@ -7373,7 +8318,7 @@ const ElementOverlayComponent = (props) => {
|
|
|
7373
8318
|
const isHovered = type === 'hovered';
|
|
7374
8319
|
const badgeWidthScale = isHovered ? 1 : widthScale;
|
|
7375
8320
|
const showCallout = !!element?.mousePosition && !isHovered;
|
|
7376
|
-
return (jsxs(Fragment$1, { children: [jsx("div", { onClick: onClick, className: `heatmapElement heatmapElement--${type} ${hideOutline ? 'heatmapElement--hide-outline' : ''}`, id: elementId, style: overlayStyle, children: showCallout && jsx(ElementCalloutOverlay, { ...props }) }), jsx(BackdropCanvas, { activeElement: overlayStyle, viewportWidth:
|
|
8321
|
+
return (jsxs(Fragment$1, { children: [jsx("div", { onClick: onClick, className: `heatmapElement heatmapElement--${type} ${hideOutline ? 'heatmapElement--hide-outline' : ''}`, id: elementId, style: overlayStyle, children: showCallout && jsx(ElementCalloutOverlay, { ...props }) }), jsx(BackdropCanvas, { activeElement: overlayStyle, viewportWidth: viewport.width, viewportHeight: viewportHeight, show: !isHovered }), jsx(RankBadge, { hash: element.hash, show: isHovered, index: element.rank, elementRect: element, widthScale: badgeWidthScale, clickOnElement: onClick })] }));
|
|
7377
8322
|
};
|
|
7378
8323
|
ElementOverlayComponent.displayName = 'ElementOverlay';
|
|
7379
8324
|
const ElementOverlay = memo(ElementOverlayComponent);
|
|
@@ -7438,7 +8383,7 @@ const HeatmapElements = (props) => {
|
|
|
7438
8383
|
};
|
|
7439
8384
|
|
|
7440
8385
|
const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
|
|
7441
|
-
const
|
|
8386
|
+
const viewport = useHeatmapViewportByDevice();
|
|
7442
8387
|
const dataInfo = useHeatmapDataContext((s) => s.dataInfo);
|
|
7443
8388
|
const vizRef = useHeatmapVizRectContext((s) => s.vizRef);
|
|
7444
8389
|
const visualizer = {
|
|
@@ -7452,7 +8397,7 @@ const VizElements = ({ iframeRef, visualRef, wrapperRef }) => {
|
|
|
7452
8397
|
if (!iframeRef.current)
|
|
7453
8398
|
return null;
|
|
7454
8399
|
return (jsx(HeatmapElements, { visualizer: visualizer, visualRef: visualRef, iframeRef: iframeRef, wrapperRef: wrapperRef, heatmapInfo: dataInfo, isVisible: true, positionMode: DEFAULT_POSITION_MODE, isHideTopRank: true, iframeDimensions: {
|
|
7455
|
-
width:
|
|
8400
|
+
width: viewport.width,
|
|
7456
8401
|
position: 'absolute',
|
|
7457
8402
|
top: 0,
|
|
7458
8403
|
left: 0,
|
|
@@ -7716,7 +8661,7 @@ const VizLoadingCanvas = () => {
|
|
|
7716
8661
|
const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHeight, onScroll, }) => {
|
|
7717
8662
|
const isLoadingCanvas = useHeatmapSettingContext((state) => state.isLoadingCanvas);
|
|
7718
8663
|
const widthScale = useHeatmapVizContext((s) => s.widthScale);
|
|
7719
|
-
const
|
|
8664
|
+
const viewport = useHeatmapViewportByDevice();
|
|
7720
8665
|
const contentHeight = calcContentHeight();
|
|
7721
8666
|
return (jsx("div", { ref: visualRef, className: "gx-hm-visual Polaris-Scrollable Polaris-Scrollable--vertical Polaris-Scrollable--scrollbarWidthThin Polaris-Scrollable--scrollbarGutterStable", onScroll: onScroll, style: {
|
|
7722
8667
|
overflowX: 'hidden',
|
|
@@ -7738,7 +8683,7 @@ const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHe
|
|
|
7738
8683
|
paddingBottom: HEATMAP_STYLE['viz']['paddingBottom'],
|
|
7739
8684
|
background: HEATMAP_STYLE['viz']['background'],
|
|
7740
8685
|
}, children: jsx("div", { className: "gx-hm-wrapper", ref: wrapperRef, style: {
|
|
7741
|
-
width:
|
|
8686
|
+
width: viewport.width,
|
|
7742
8687
|
height: iframeHeight,
|
|
7743
8688
|
transform: `scale(${widthScale})`,
|
|
7744
8689
|
transformOrigin: 'top center',
|
|
@@ -7751,14 +8696,14 @@ const WrapperVisual = ({ children, visualRef, wrapperRef, scaledHeight, iframeHe
|
|
|
7751
8696
|
}
|
|
7752
8697
|
};
|
|
7753
8698
|
|
|
7754
|
-
const VizDomRenderer = ({ mode
|
|
8699
|
+
const VizDomRenderer = ({ mode }) => {
|
|
7755
8700
|
const viewId = useViewIdContext();
|
|
7756
|
-
const
|
|
8701
|
+
const viewport = useHeatmapViewportByDevice();
|
|
7757
8702
|
const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
|
|
7758
8703
|
const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
|
|
7759
8704
|
const wrapperRef = useRef(null);
|
|
7760
8705
|
const visualRef = useRef(null);
|
|
7761
|
-
const { iframeRef } =
|
|
8706
|
+
const { iframeRef } = useHeatmapRenderDom();
|
|
7762
8707
|
const { scaledHeight, handleScroll } = useHeatmapScale({ wrapperRef, iframeRef, visualRef });
|
|
7763
8708
|
useHeatmapCanvas();
|
|
7764
8709
|
useRenderCount('VizDomRenderer');
|
|
@@ -7766,7 +8711,7 @@ const VizDomRenderer = ({ mode = 'heatmap' }) => {
|
|
|
7766
8711
|
const scrollTop = e.currentTarget.scrollTop;
|
|
7767
8712
|
handleScroll(scrollTop);
|
|
7768
8713
|
};
|
|
7769
|
-
return (jsxs(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, onScroll: onScroll, iframeHeight: iframeHeight, children: [jsx(VizClickmap, { iframeRef: iframeRef, visualRef: visualRef, wrapperRef: wrapperRef }), jsx("iframe", { ...HEATMAP_IFRAME, id: `clarity-iframe-${viewId}`, ref: iframeRef, width:
|
|
8714
|
+
return (jsxs(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, onScroll: onScroll, iframeHeight: iframeHeight, children: [jsx(VizClickmap, { iframeRef: iframeRef, visualRef: visualRef, wrapperRef: wrapperRef }), jsx("iframe", { ...HEATMAP_IFRAME, id: `clarity-iframe-${viewId}`, ref: iframeRef, width: viewport.width, height: wrapperHeight }), jsx(VizLoadingCanvas, {}), jsx(VizScrollMap, { visualRef: visualRef, iframeRef: iframeRef, wrapperRef: wrapperRef })] }));
|
|
7770
8715
|
};
|
|
7771
8716
|
|
|
7772
8717
|
const VizLoading = () => {
|
|
@@ -7783,8 +8728,9 @@ const VizLoading = () => {
|
|
|
7783
8728
|
const VizDomHeatmap = () => {
|
|
7784
8729
|
const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
|
|
7785
8730
|
const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
|
|
8731
|
+
const setWrapperHeight = useHeatmapVizRectContext((s) => s.setWrapperHeight);
|
|
7786
8732
|
const setVizRef = useHeatmapVizRectContext((s) => s.setVizRef);
|
|
7787
|
-
const
|
|
8733
|
+
const setIsDomLoaded = useHeatmapVizContext((s) => s.setIsDomLoaded);
|
|
7788
8734
|
const setSelectedElement = useHeatmapClickContext((s) => s.setSelectedElement);
|
|
7789
8735
|
const setHoveredElement = useHeatmapHoverContext((s) => s.setHoveredElement);
|
|
7790
8736
|
// const setSelectedArea = useHeatmapAreaClickContext((s) => s.setSelectedArea);
|
|
@@ -7794,7 +8740,8 @@ const VizDomHeatmap = () => {
|
|
|
7794
8740
|
const cleanUp = () => {
|
|
7795
8741
|
setVizRef(null);
|
|
7796
8742
|
setIframeHeight(0);
|
|
7797
|
-
|
|
8743
|
+
setWrapperHeight(0);
|
|
8744
|
+
setIsDomLoaded(false);
|
|
7798
8745
|
setSelectedElement(null);
|
|
7799
8746
|
setHoveredElement(null);
|
|
7800
8747
|
// setSelectedArea(null);
|
|
@@ -7803,13 +8750,13 @@ const VizDomHeatmap = () => {
|
|
|
7803
8750
|
};
|
|
7804
8751
|
useEffect(() => {
|
|
7805
8752
|
return cleanUp;
|
|
7806
|
-
}, []);
|
|
7807
|
-
return (jsxs(VizContainer, { isActive: true, children: [jsx(VizDomRenderer, {}), iframeHeight === 0 && jsx(VizLoading, {})] }));
|
|
8753
|
+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
8754
|
+
return (jsxs(VizContainer, { isActive: true, children: [jsx(VizDomRenderer, { mode: EHeatmapMode.Heatmap }), iframeHeight === 0 && jsx(VizLoading, {})] }));
|
|
7808
8755
|
};
|
|
7809
8756
|
VizDomHeatmap.displayName = 'VizDomHeatmap';
|
|
7810
8757
|
|
|
7811
8758
|
const VizLiveRenderer = () => {
|
|
7812
|
-
const
|
|
8759
|
+
const viewport = useHeatmapViewportByDevice();
|
|
7813
8760
|
const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
|
|
7814
8761
|
const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
|
|
7815
8762
|
const visualRef = useRef(null);
|
|
@@ -7820,13 +8767,13 @@ const VizLiveRenderer = () => {
|
|
|
7820
8767
|
const scrollTop = e.currentTarget.scrollTop;
|
|
7821
8768
|
handleScroll(scrollTop);
|
|
7822
8769
|
};
|
|
7823
|
-
return (jsx(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, iframeHeight: iframeHeight, onScroll: onScroll, children: jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width:
|
|
8770
|
+
return (jsx(WrapperVisual, { visualRef: visualRef, wrapperRef: wrapperRef, scaledHeight: scaledHeight, iframeHeight: iframeHeight, onScroll: onScroll, children: jsx("iframe", { ref: iframeRef, ...HEATMAP_IFRAME, width: viewport.width, height: wrapperHeight, scrolling: "no" }) }));
|
|
7824
8771
|
};
|
|
7825
8772
|
|
|
7826
8773
|
const VizLiveHeatmap = () => {
|
|
7827
8774
|
const iframeHeight = useHeatmapVizRectContext((s) => s.iframeHeight);
|
|
7828
8775
|
const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
|
|
7829
|
-
|
|
8776
|
+
useHeatmapLiveContext((s) => s.reset);
|
|
7830
8777
|
const CompVizLoading = useHeatmapControlStore((state) => state.controls.VizLoading);
|
|
7831
8778
|
// TODO: Remove this after testing
|
|
7832
8779
|
useEffect(() => {
|
|
@@ -7877,11 +8824,11 @@ const ContentTopBar = () => {
|
|
|
7877
8824
|
}, children: CompTopBar && jsx(CompTopBar, {}) }));
|
|
7878
8825
|
};
|
|
7879
8826
|
|
|
7880
|
-
const HeatmapLayout = ({ data, clickmap, clickAreas, scrollmap, attentionMap, controls, dataInfo, isLoading, isLoadingCanvas, }) => {
|
|
8827
|
+
const HeatmapLayout = ({ shopId, data, clickmap, clickAreas, scrollmap, attentionMap, controls, dataInfo, isLoading, isLoadingCanvas, excludeClassNames, }) => {
|
|
7881
8828
|
useRegisterControl(controls);
|
|
7882
8829
|
useRegisterData(data, dataInfo);
|
|
7883
8830
|
useRegisterHeatmap({ clickmap, scrollmap, clickAreas, attentionMap });
|
|
7884
|
-
useRegisterConfig({ isLoading, isLoadingCanvas });
|
|
8831
|
+
useRegisterConfig({ isLoading, isLoadingCanvas, shopId, excludeClassNames });
|
|
7885
8832
|
// performanceLogger.configure({
|
|
7886
8833
|
// enabled: true,
|
|
7887
8834
|
// logToConsole: false,
|
|
@@ -7911,4 +8858,4 @@ const HeatmapLayout = ({ data, clickmap, clickAreas, scrollmap, attentionMap, co
|
|
|
7911
8858
|
}
|
|
7912
8859
|
};
|
|
7913
8860
|
|
|
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,
|
|
8861
|
+
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, useHeatmapViewportByDevice, useHeatmapVizContext, useHeatmapVizRectContext, useHoveredElement, useMeasureFunction, useRegisterConfig, useRegisterControl, useRegisterData, useRegisterHeatmap, useRenderCount, useScrollmapZones, useTrackHookCall, useViewIdContext, useVizLiveRender, useWhyDidYouUpdate, useWrapperRefHeight, useZonePositions, withPerformanceTracking };
|