@gemx-dev/heatmap-react 3.5.89 → 3.5.91
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/helpers/index.d.ts +6 -6
- package/dist/esm/helpers/index.d.ts.map +1 -1
- package/dist/esm/helpers/viz-area-click/area-builder.d.ts.map +1 -1
- package/dist/esm/hooks/index.d.ts +0 -1
- package/dist/esm/hooks/index.d.ts.map +1 -1
- package/dist/esm/hooks/viz-live/useVizLiveRender.d.ts.map +1 -1
- package/dist/esm/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
- package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts +0 -3
- package/dist/esm/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
- package/dist/esm/index.js +1553 -2751
- package/dist/esm/index.mjs +1553 -2751
- package/dist/esm/{helpers/iframe-helper → libs/iframe-processor}/index.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/lifecycle.d.ts +10 -0
- package/dist/esm/libs/iframe-processor/lifecycle.d.ts.map +1 -0
- package/dist/{umd/helpers/iframe-helper/iframe-fixer.d.ts → esm/libs/iframe-processor/orchestrator.d.ts} +1 -1
- package/dist/{umd/helpers/iframe-helper/iframe-fixer.d.ts.map → esm/libs/iframe-processor/orchestrator.d.ts.map} +1 -1
- package/dist/esm/libs/iframe-processor/processors/height-observer/index.d.ts +20 -0
- package/dist/esm/libs/iframe-processor/processors/height-observer/index.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/height-observer/observers.d.ts +7 -0
- package/dist/esm/libs/iframe-processor/processors/height-observer/observers.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/height-observer/types.d.ts +10 -0
- package/dist/esm/libs/iframe-processor/processors/height-observer/types.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/navigation/blockers.d.ts +9 -0
- package/dist/esm/libs/iframe-processor/processors/navigation/blockers.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/navigation/index.d.ts +20 -0
- package/dist/esm/libs/iframe-processor/processors/navigation/index.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/navigation/listeners.d.ts +12 -0
- package/dist/esm/libs/iframe-processor/processors/navigation/listeners.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/navigation/types.d.ts +7 -0
- package/dist/esm/libs/iframe-processor/processors/navigation/types.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/dimensions.d.ts +7 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/dimensions.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/index.d.ts +2 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/index.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/fixes.d.ts +7 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/fixes.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/index.d.ts +2 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/index.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/gem-slider-item/fixes.d.ts +3 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/gem-slider-item/fixes.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/gem-slider-item/index.d.ts +2 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/gem-slider-item/index.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/index.d.ts +2 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/index.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/index.d.ts +16 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/index.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/registry.d.ts +14 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/registry.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/shopify-fixes/index.d.ts +2 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/shopify-fixes/index.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/shopify-fixes/theme-dawn/hero-banner.d.ts +14 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/shopify-fixes/theme-dawn/hero-banner.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/shopify-fixes/theme-dawn/index.d.ts +2 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/shopify-fixes/theme-dawn/index.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/types.d.ts +46 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/types.d.ts.map +1 -0
- package/dist/esm/{helpers/iframe-helper/iframe-viewport-replacer.d.ts → libs/iframe-processor/processors/viewport/index.d.ts} +2 -7
- package/dist/esm/libs/iframe-processor/processors/viewport/index.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/listeners.d.ts +3 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/listeners.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/pipeline.d.ts +17 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/pipeline.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/shop-overrides/index.d.ts +17 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/shop-overrides/index.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/shop-overrides/registry.d.ts +16 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/shop-overrides/registry.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/shop-overrides/shops/shop-566240210141053597/fixes.d.ts +11 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/shop-overrides/shops/shop-566240210141053597/fixes.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/shop-overrides/shops/shop-566240210141053597/index.d.ts +2 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/shop-overrides/shops/shop-566240210141053597/index.d.ts.map +1 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/shop-overrides/types.d.ts +53 -0
- package/dist/esm/libs/iframe-processor/processors/viewport/shop-overrides/types.d.ts.map +1 -0
- package/dist/esm/{helpers/iframe-helper/iframe-style-enforcer.d.ts → libs/iframe-processor/processors/viewport/style-enforcer.d.ts} +2 -2
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer.d.ts.map +1 -0
- package/dist/esm/libs/index.d.ts +1 -3
- package/dist/esm/libs/index.d.ts.map +1 -1
- package/dist/esm/libs/visualizer/AttentionMapRenderer.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/ClickHeatmapRenderer.d.ts.map +1 -0
- package/dist/esm/libs/{GXVisualizer.d.ts → visualizer/GXVisualizer.d.ts} +0 -2
- package/dist/esm/libs/visualizer/GXVisualizer.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/ScrollHeatmapRenderer.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/index.d.ts +4 -0
- package/dist/esm/libs/visualizer/index.d.ts.map +1 -0
- package/dist/esm/libs/visualizer/types.d.ts.map +1 -0
- package/dist/esm/types/iframe-helper.d.ts +4 -0
- package/dist/esm/types/iframe-helper.d.ts.map +1 -1
- package/dist/esm/{helpers/dom-utils.d.ts → utils/dom.d.ts} +1 -1
- package/dist/esm/utils/dom.d.ts.map +1 -0
- package/dist/esm/utils/index.d.ts +9 -0
- package/dist/esm/utils/index.d.ts.map +1 -0
- package/dist/esm/utils/logger.d.ts.map +1 -0
- package/dist/esm/utils/observable.d.ts.map +1 -0
- package/dist/esm/utils/throttle.d.ts.map +1 -0
- package/dist/umd/helpers/index.d.ts +6 -6
- package/dist/umd/helpers/index.d.ts.map +1 -1
- package/dist/umd/helpers/viz-area-click/area-builder.d.ts.map +1 -1
- package/dist/umd/hooks/index.d.ts +0 -1
- package/dist/umd/hooks/index.d.ts.map +1 -1
- package/dist/umd/hooks/viz-live/useVizLiveRender.d.ts.map +1 -1
- package/dist/umd/hooks/viz-render/useHeatmapRender.d.ts.map +1 -1
- package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts +0 -3
- package/dist/umd/hooks/viz-scale/useHeatmapScale.d.ts.map +1 -1
- package/dist/umd/index.js +2 -2
- package/dist/umd/{helpers/iframe-helper → libs/iframe-processor}/index.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/lifecycle.d.ts +10 -0
- package/dist/umd/libs/iframe-processor/lifecycle.d.ts.map +1 -0
- package/dist/{esm/helpers/iframe-helper/iframe-fixer.d.ts → umd/libs/iframe-processor/orchestrator.d.ts} +1 -1
- package/dist/{esm/helpers/iframe-helper/iframe-fixer.d.ts.map → umd/libs/iframe-processor/orchestrator.d.ts.map} +1 -1
- package/dist/umd/libs/iframe-processor/processors/height-observer/index.d.ts +20 -0
- package/dist/umd/libs/iframe-processor/processors/height-observer/index.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/height-observer/observers.d.ts +7 -0
- package/dist/umd/libs/iframe-processor/processors/height-observer/observers.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/height-observer/types.d.ts +10 -0
- package/dist/umd/libs/iframe-processor/processors/height-observer/types.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/navigation/blockers.d.ts +9 -0
- package/dist/umd/libs/iframe-processor/processors/navigation/blockers.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/navigation/index.d.ts +20 -0
- package/dist/umd/libs/iframe-processor/processors/navigation/index.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/navigation/listeners.d.ts +12 -0
- package/dist/umd/libs/iframe-processor/processors/navigation/listeners.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/navigation/types.d.ts +7 -0
- package/dist/umd/libs/iframe-processor/processors/navigation/types.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/dimensions.d.ts +7 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/dimensions.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/index.d.ts +2 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/index.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/fixes.d.ts +7 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/fixes.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/index.d.ts +2 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/index.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/gem-slider-item/fixes.d.ts +3 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/gem-slider-item/fixes.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/gem-slider-item/index.d.ts +2 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/gem-slider-item/index.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/index.d.ts +2 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/gp-v7-fixes/index.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/index.d.ts +16 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/index.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/registry.d.ts +14 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/registry.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/shopify-fixes/index.d.ts +2 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/shopify-fixes/index.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/shopify-fixes/theme-dawn/hero-banner.d.ts +14 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/shopify-fixes/theme-dawn/hero-banner.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/shopify-fixes/theme-dawn/index.d.ts +2 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/shopify-fixes/theme-dawn/index.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/types.d.ts +46 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/types.d.ts.map +1 -0
- package/dist/umd/{helpers/iframe-helper/iframe-viewport-replacer.d.ts → libs/iframe-processor/processors/viewport/index.d.ts} +2 -7
- package/dist/umd/libs/iframe-processor/processors/viewport/index.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/listeners.d.ts +3 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/listeners.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/pipeline.d.ts +17 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/pipeline.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/shop-overrides/index.d.ts +17 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/shop-overrides/index.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/shop-overrides/registry.d.ts +16 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/shop-overrides/registry.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/shop-overrides/shops/shop-566240210141053597/fixes.d.ts +11 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/shop-overrides/shops/shop-566240210141053597/fixes.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/shop-overrides/shops/shop-566240210141053597/index.d.ts +2 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/shop-overrides/shops/shop-566240210141053597/index.d.ts.map +1 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/shop-overrides/types.d.ts +53 -0
- package/dist/umd/libs/iframe-processor/processors/viewport/shop-overrides/types.d.ts.map +1 -0
- package/dist/umd/{helpers/iframe-helper/iframe-style-enforcer.d.ts → libs/iframe-processor/processors/viewport/style-enforcer.d.ts} +2 -2
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer.d.ts.map +1 -0
- package/dist/umd/libs/index.d.ts +1 -3
- package/dist/umd/libs/index.d.ts.map +1 -1
- package/dist/umd/libs/visualizer/AttentionMapRenderer.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/ClickHeatmapRenderer.d.ts.map +1 -0
- package/dist/umd/libs/{GXVisualizer.d.ts → visualizer/GXVisualizer.d.ts} +0 -2
- package/dist/umd/libs/visualizer/GXVisualizer.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/ScrollHeatmapRenderer.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/index.d.ts +4 -0
- package/dist/umd/libs/visualizer/index.d.ts.map +1 -0
- package/dist/umd/libs/visualizer/types.d.ts.map +1 -0
- package/dist/umd/types/iframe-helper.d.ts +4 -0
- package/dist/umd/types/iframe-helper.d.ts.map +1 -1
- package/dist/umd/{helpers/dom-utils.d.ts → utils/dom.d.ts} +1 -1
- package/dist/umd/utils/dom.d.ts.map +1 -0
- package/dist/umd/utils/index.d.ts +9 -0
- package/dist/umd/utils/index.d.ts.map +1 -0
- package/dist/umd/utils/logger.d.ts.map +1 -0
- package/dist/umd/utils/observable.d.ts.map +1 -0
- package/dist/umd/utils/throttle.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/esm/helpers/dom-utils.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/iframe-height-observer.d.ts +0 -35
- package/dist/esm/helpers/iframe-helper/iframe-height-observer.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/iframe-navigation-blocker.d.ts +0 -52
- package/dist/esm/helpers/iframe-helper/iframe-navigation-blocker.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/iframe-style-enforcer.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/iframe-viewport-replacer.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base/base-style-replacer.d.ts +0 -61
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base/base-style-replacer.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base/flickity-fixer.d.ts +0 -10
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base/flickity-fixer.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base/index.d.ts +0 -9
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base/index.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base/observer-manager.d.ts +0 -14
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base/observer-manager.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base/sticky-cart-detector.d.ts +0 -12
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base/sticky-cart-detector.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base/swiper-fixer.d.ts +0 -12
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base/swiper-fixer.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/attribute-functions.d.ts +0 -9
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/attribute-functions.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/class-style-functions.d.ts +0 -29
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/class-style-functions.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/constants.d.ts +0 -24
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/constants.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/context-interface.d.ts +0 -29
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/context-interface.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/display-functions.d.ts +0 -17
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/display-functions.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/dom-injection-functions.d.ts +0 -17
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/dom-injection-functions.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/function-binder.d.ts +0 -33
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/function-binder.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/index.d.ts +0 -11
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/index.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/types.d.ts +0 -18
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/base-functions/types.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/case-specific-functions/content/content-functions.d.ts +0 -13
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/case-specific-functions/content/content-functions.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/case-specific-functions/images/image-functions.d.ts +0 -21
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/case-specific-functions/images/image-functions.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/case-specific-functions/index.d.ts +0 -11
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/case-specific-functions/index.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/case-specific-functions/layout/layout-functions.d.ts +0 -29
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/case-specific-functions/layout/layout-functions.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/case-specific-functions/popups/popup-functions.d.ts +0 -21
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/case-specific-functions/popups/popup-functions.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/case-specific-functions/shopify/shopify-functions.d.ts +0 -25
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/case-specific-functions/shopify/shopify-functions.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/case-specific-functions/sliders/slider-functions.d.ts +0 -29
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/case-specific-functions/sliders/slider-functions.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/index.d.ts +0 -7
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/index.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/init.d.ts +0 -9
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/init.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/mappings/desktop-mappings.d.ts +0 -7
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/mappings/desktop-mappings.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/mappings/mobile-mappings.d.ts +0 -7
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/mappings/mobile-mappings.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/add-dad-fuel5reasons-section-missing-slider-classes.d.ts +0 -6
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/add-dad-fuel5reasons-section-missing-slider-classes.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/fix-jocko-fuel-featured-stories-section.d.ts +0 -6
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/fix-jocko-fuel-featured-stories-section.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/index.d.ts +0 -19
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/index.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-balance-coffee-newsletter-form-container-display.d.ts +0 -6
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-balance-coffee-newsletter-form-container-display.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-boom-beauty-mobile-nav-menu-drawer-height.d.ts +0 -6
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-boom-beauty-mobile-nav-menu-drawer-height.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-cookie-diet-footer-newsletter-form-display.d.ts +0 -6
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-cookie-diet-footer-newsletter-form-display.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-dad-fuel-ingredient-highlights-section-image.d.ts +0 -6
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-dad-fuel-ingredient-highlights-section-image.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-get-thin-md-weight-loss-form-element-display.d.ts +0 -3
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-get-thin-md-weight-loss-form-element-display.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-mag-bak-add-on-toggle-display.d.ts +0 -6
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-mag-bak-add-on-toggle-display.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-pup-labs-mobile-search-opacity.d.ts +0 -6
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-pup-labs-mobile-search-opacity.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-rinse-bath-and-body-header-left-icons-display.d.ts +0 -6
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-rinse-bath-and-body-header-left-icons-display.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-try-snow-header-menu-icon-display.d.ts +0 -6
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-try-snow-header-menu-icon-display.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/set-bomix-mobile-mega-menu-width.d.ts +0 -6
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/set-bomix-mobile-mega-menu-width.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/set-jocko-product-page-swiper-sliders.d.ts +0 -6
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/set-jocko-product-page-swiper-sliders.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/set-vita-coco-slick-slider-inactive-slide-opacity.d.ts +0 -6
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/methods/mobile/set-vita-coco-slick-slider-inactive-slide-opacity.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/screenshot-fixes-main.d.ts +0 -220
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/screenshot-fixes-main.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/screenshot-fixes-refactored.d.ts +0 -58
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/screenshot-fixes-refactored.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/third-party-apps/anita-screenshot-fixes.d.ts +0 -589
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/third-party-apps/anita-screenshot-fixes.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/third-party-apps/forson-screenshot-fixes.d.ts +0 -57
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/third-party-apps/forson-screenshot-fixes.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/third-party-apps/general-site-fixes.d.ts +0 -88
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/third-party-apps/general-site-fixes.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/third-party-apps/index.d.ts +0 -15
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/third-party-apps/index.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/third-party-apps/loading-background-fixes.d.ts +0 -24
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/third-party-apps/loading-background-fixes.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/types.d.ts +0 -70
- package/dist/esm/helpers/iframe-helper/screenshot-fixes/types.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/start.d.ts +0 -58
- package/dist/esm/helpers/iframe-helper/start.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/style-fixer/base-replacer.d.ts +0 -54
- package/dist/esm/helpers/iframe-helper/style-fixer/base-replacer.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/style-fixer/general-fixer.d.ts +0 -54
- package/dist/esm/helpers/iframe-helper/style-fixer/general-fixer.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/style-fixer/index.d.ts +0 -12
- package/dist/esm/helpers/iframe-helper/style-fixer/index.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/style-fixer/main-fixer.d.ts +0 -32
- package/dist/esm/helpers/iframe-helper/style-fixer/main-fixer.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/style-fixer/observer-manager.d.ts +0 -14
- package/dist/esm/helpers/iframe-helper/style-fixer/observer-manager.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/style-fixer/site-specific-replacer.d.ts +0 -25
- package/dist/esm/helpers/iframe-helper/style-fixer/site-specific-replacer.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/style-fixer/sticky-detector.d.ts +0 -12
- package/dist/esm/helpers/iframe-helper/style-fixer/sticky-detector.d.ts.map +0 -1
- package/dist/esm/helpers/iframe-helper/style-fixer/types.d.ts +0 -40
- package/dist/esm/helpers/iframe-helper/style-fixer/types.d.ts.map +0 -1
- package/dist/esm/helpers/logger.d.ts.map +0 -1
- package/dist/esm/helpers/observable.d.ts.map +0 -1
- package/dist/esm/helpers/throttle.d.ts.map +0 -1
- package/dist/esm/hooks/viz-iframe/index.d.ts +0 -2
- package/dist/esm/hooks/viz-iframe/index.d.ts.map +0 -1
- package/dist/esm/hooks/viz-iframe/useIframeHeightProcessor.d.ts +0 -49
- package/dist/esm/hooks/viz-iframe/useIframeHeightProcessor.d.ts.map +0 -1
- package/dist/esm/libs/AttentionMapRenderer.d.ts.map +0 -1
- package/dist/esm/libs/ClickHeatmapRenderer.d.ts.map +0 -1
- package/dist/esm/libs/GXVisualizer.d.ts.map +0 -1
- package/dist/esm/libs/ScrollHeatmapRenderer.d.ts.map +0 -1
- package/dist/esm/libs/types.d.ts.map +0 -1
- package/dist/umd/helpers/dom-utils.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/iframe-height-observer.d.ts +0 -35
- package/dist/umd/helpers/iframe-helper/iframe-height-observer.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/iframe-navigation-blocker.d.ts +0 -52
- package/dist/umd/helpers/iframe-helper/iframe-navigation-blocker.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/iframe-style-enforcer.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/iframe-viewport-replacer.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base/base-style-replacer.d.ts +0 -61
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base/base-style-replacer.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base/flickity-fixer.d.ts +0 -10
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base/flickity-fixer.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base/index.d.ts +0 -9
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base/index.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base/observer-manager.d.ts +0 -14
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base/observer-manager.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base/sticky-cart-detector.d.ts +0 -12
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base/sticky-cart-detector.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base/swiper-fixer.d.ts +0 -12
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base/swiper-fixer.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/attribute-functions.d.ts +0 -9
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/attribute-functions.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/class-style-functions.d.ts +0 -29
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/class-style-functions.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/constants.d.ts +0 -24
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/constants.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/context-interface.d.ts +0 -29
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/context-interface.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/display-functions.d.ts +0 -17
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/display-functions.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/dom-injection-functions.d.ts +0 -17
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/dom-injection-functions.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/function-binder.d.ts +0 -33
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/function-binder.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/index.d.ts +0 -11
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/index.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/types.d.ts +0 -18
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/base-functions/types.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/case-specific-functions/content/content-functions.d.ts +0 -13
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/case-specific-functions/content/content-functions.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/case-specific-functions/images/image-functions.d.ts +0 -21
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/case-specific-functions/images/image-functions.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/case-specific-functions/index.d.ts +0 -11
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/case-specific-functions/index.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/case-specific-functions/layout/layout-functions.d.ts +0 -29
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/case-specific-functions/layout/layout-functions.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/case-specific-functions/popups/popup-functions.d.ts +0 -21
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/case-specific-functions/popups/popup-functions.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/case-specific-functions/shopify/shopify-functions.d.ts +0 -25
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/case-specific-functions/shopify/shopify-functions.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/case-specific-functions/sliders/slider-functions.d.ts +0 -29
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/case-specific-functions/sliders/slider-functions.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/index.d.ts +0 -7
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/index.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/init.d.ts +0 -9
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/init.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/mappings/desktop-mappings.d.ts +0 -7
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/mappings/desktop-mappings.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/mappings/mobile-mappings.d.ts +0 -7
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/mappings/mobile-mappings.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/add-dad-fuel5reasons-section-missing-slider-classes.d.ts +0 -6
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/add-dad-fuel5reasons-section-missing-slider-classes.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/fix-jocko-fuel-featured-stories-section.d.ts +0 -6
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/fix-jocko-fuel-featured-stories-section.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/index.d.ts +0 -19
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/index.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-balance-coffee-newsletter-form-container-display.d.ts +0 -6
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-balance-coffee-newsletter-form-container-display.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-boom-beauty-mobile-nav-menu-drawer-height.d.ts +0 -6
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-boom-beauty-mobile-nav-menu-drawer-height.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-cookie-diet-footer-newsletter-form-display.d.ts +0 -6
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-cookie-diet-footer-newsletter-form-display.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-dad-fuel-ingredient-highlights-section-image.d.ts +0 -6
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-dad-fuel-ingredient-highlights-section-image.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-get-thin-md-weight-loss-form-element-display.d.ts +0 -3
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-get-thin-md-weight-loss-form-element-display.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-mag-bak-add-on-toggle-display.d.ts +0 -6
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-mag-bak-add-on-toggle-display.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-pup-labs-mobile-search-opacity.d.ts +0 -6
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-pup-labs-mobile-search-opacity.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-rinse-bath-and-body-header-left-icons-display.d.ts +0 -6
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-rinse-bath-and-body-header-left-icons-display.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-try-snow-header-menu-icon-display.d.ts +0 -6
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/remove-try-snow-header-menu-icon-display.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/set-bomix-mobile-mega-menu-width.d.ts +0 -6
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/set-bomix-mobile-mega-menu-width.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/set-jocko-product-page-swiper-sliders.d.ts +0 -6
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/set-jocko-product-page-swiper-sliders.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/set-vita-coco-slick-slider-inactive-slide-opacity.d.ts +0 -6
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/methods/mobile/set-vita-coco-slick-slider-inactive-slide-opacity.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/screenshot-fixes-main.d.ts +0 -220
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/screenshot-fixes-main.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/screenshot-fixes-refactored.d.ts +0 -58
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/screenshot-fixes-refactored.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/third-party-apps/anita-screenshot-fixes.d.ts +0 -589
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/third-party-apps/anita-screenshot-fixes.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/third-party-apps/forson-screenshot-fixes.d.ts +0 -57
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/third-party-apps/forson-screenshot-fixes.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/third-party-apps/general-site-fixes.d.ts +0 -88
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/third-party-apps/general-site-fixes.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/third-party-apps/index.d.ts +0 -15
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/third-party-apps/index.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/third-party-apps/loading-background-fixes.d.ts +0 -24
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/third-party-apps/loading-background-fixes.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/types.d.ts +0 -70
- package/dist/umd/helpers/iframe-helper/screenshot-fixes/types.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/start.d.ts +0 -58
- package/dist/umd/helpers/iframe-helper/start.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/style-fixer/base-replacer.d.ts +0 -54
- package/dist/umd/helpers/iframe-helper/style-fixer/base-replacer.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/style-fixer/general-fixer.d.ts +0 -54
- package/dist/umd/helpers/iframe-helper/style-fixer/general-fixer.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/style-fixer/index.d.ts +0 -12
- package/dist/umd/helpers/iframe-helper/style-fixer/index.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/style-fixer/main-fixer.d.ts +0 -32
- package/dist/umd/helpers/iframe-helper/style-fixer/main-fixer.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/style-fixer/observer-manager.d.ts +0 -14
- package/dist/umd/helpers/iframe-helper/style-fixer/observer-manager.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/style-fixer/site-specific-replacer.d.ts +0 -25
- package/dist/umd/helpers/iframe-helper/style-fixer/site-specific-replacer.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/style-fixer/sticky-detector.d.ts +0 -12
- package/dist/umd/helpers/iframe-helper/style-fixer/sticky-detector.d.ts.map +0 -1
- package/dist/umd/helpers/iframe-helper/style-fixer/types.d.ts +0 -40
- package/dist/umd/helpers/iframe-helper/style-fixer/types.d.ts.map +0 -1
- package/dist/umd/helpers/logger.d.ts.map +0 -1
- package/dist/umd/helpers/observable.d.ts.map +0 -1
- package/dist/umd/helpers/throttle.d.ts.map +0 -1
- package/dist/umd/hooks/viz-iframe/index.d.ts +0 -2
- package/dist/umd/hooks/viz-iframe/index.d.ts.map +0 -1
- package/dist/umd/hooks/viz-iframe/useIframeHeightProcessor.d.ts +0 -49
- package/dist/umd/hooks/viz-iframe/useIframeHeightProcessor.d.ts.map +0 -1
- package/dist/umd/libs/AttentionMapRenderer.d.ts.map +0 -1
- package/dist/umd/libs/ClickHeatmapRenderer.d.ts.map +0 -1
- package/dist/umd/libs/GXVisualizer.d.ts.map +0 -1
- package/dist/umd/libs/ScrollHeatmapRenderer.d.ts.map +0 -1
- package/dist/umd/libs/types.d.ts.map +0 -1
- /package/dist/esm/{helpers/iframe-helper → libs/iframe-processor}/index.d.ts +0 -0
- /package/dist/esm/libs/{AttentionMapRenderer.d.ts → visualizer/AttentionMapRenderer.d.ts} +0 -0
- /package/dist/esm/libs/{ClickHeatmapRenderer.d.ts → visualizer/ClickHeatmapRenderer.d.ts} +0 -0
- /package/dist/esm/libs/{ScrollHeatmapRenderer.d.ts → visualizer/ScrollHeatmapRenderer.d.ts} +0 -0
- /package/dist/esm/libs/{types.d.ts → visualizer/types.d.ts} +0 -0
- /package/dist/esm/{helpers → utils}/logger.d.ts +0 -0
- /package/dist/esm/{helpers → utils}/observable.d.ts +0 -0
- /package/dist/esm/{helpers → utils}/throttle.d.ts +0 -0
- /package/dist/umd/{helpers/iframe-helper → libs/iframe-processor}/index.d.ts +0 -0
- /package/dist/umd/libs/{AttentionMapRenderer.d.ts → visualizer/AttentionMapRenderer.d.ts} +0 -0
- /package/dist/umd/libs/{ClickHeatmapRenderer.d.ts → visualizer/ClickHeatmapRenderer.d.ts} +0 -0
- /package/dist/umd/libs/{ScrollHeatmapRenderer.d.ts → visualizer/ScrollHeatmapRenderer.d.ts} +0 -0
- /package/dist/umd/libs/{types.d.ts → visualizer/types.d.ts} +0 -0
- /package/dist/umd/{helpers → utils}/logger.d.ts +0 -0
- /package/dist/umd/{helpers → utils}/observable.d.ts +0 -0
- /package/dist/umd/{helpers → utils}/throttle.d.ts +0 -0
package/dist/esm/index.js
CHANGED
|
@@ -1483,32 +1483,57 @@ const useRegisterHeatmap = ({ clickmap, scrollmap, clickAreas, attentionMap }) =
|
|
|
1483
1483
|
};
|
|
1484
1484
|
|
|
1485
1485
|
/**
|
|
1486
|
-
*
|
|
1486
|
+
* Draw a backdrop overlay on canvas with a cutout for the active element
|
|
1487
|
+
* This creates a "spotlight" effect highlighting the active element
|
|
1487
1488
|
*/
|
|
1488
|
-
|
|
1489
|
-
const
|
|
1490
|
-
const
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
|
-
|
|
1489
|
+
const drawBackdropWithCutout = (options) => {
|
|
1490
|
+
const { canvas, activeRect, backdropColor = '#000000', backdropOpacity = 0.5, cutoutExpansion = 0 } = options;
|
|
1491
|
+
const ctx = canvas.getContext('2d');
|
|
1492
|
+
if (!ctx)
|
|
1493
|
+
return;
|
|
1494
|
+
const { width: canvasWidth, height: canvasHeight } = canvas;
|
|
1495
|
+
// Apply expansion to the cutout rect
|
|
1496
|
+
const top = Math.max(0, activeRect.top - cutoutExpansion);
|
|
1497
|
+
const left = Math.max(0, activeRect.left - cutoutExpansion);
|
|
1498
|
+
const width = Math.min(canvasWidth - left, activeRect.width + cutoutExpansion * 2);
|
|
1499
|
+
const height = Math.min(canvasHeight - top, activeRect.height + cutoutExpansion * 2);
|
|
1500
|
+
// Clear previous drawing
|
|
1501
|
+
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
|
|
1502
|
+
// Set backdrop style
|
|
1503
|
+
ctx.fillStyle = backdropColor;
|
|
1504
|
+
ctx.globalAlpha = backdropOpacity;
|
|
1505
|
+
// Draw backdrop in 4 rectangles around the active element
|
|
1506
|
+
// This creates a cutout effect
|
|
1507
|
+
// Top rectangle (above active element)
|
|
1508
|
+
if (top > 0) {
|
|
1509
|
+
ctx.fillRect(0, 0, canvasWidth, top);
|
|
1510
|
+
}
|
|
1511
|
+
// Bottom rectangle (below active element)
|
|
1512
|
+
const bottomY = top + height;
|
|
1513
|
+
if (bottomY < canvasHeight) {
|
|
1514
|
+
ctx.fillRect(0, bottomY, canvasWidth, canvasHeight - bottomY);
|
|
1515
|
+
}
|
|
1516
|
+
// Left rectangle (left of active element)
|
|
1517
|
+
if (left > 0) {
|
|
1518
|
+
ctx.fillRect(0, top, left, height);
|
|
1519
|
+
}
|
|
1520
|
+
// Right rectangle (right of active element)
|
|
1521
|
+
const rightX = left + width;
|
|
1522
|
+
if (rightX < canvasWidth) {
|
|
1523
|
+
ctx.fillRect(rightX, top, canvasWidth - rightX, height);
|
|
1524
|
+
}
|
|
1525
|
+
// Reset alpha
|
|
1526
|
+
ctx.globalAlpha = 1.0;
|
|
1527
|
+
};
|
|
1528
|
+
/**
|
|
1529
|
+
* Clear the entire canvas
|
|
1530
|
+
*/
|
|
1531
|
+
const clearCanvas = (canvas) => {
|
|
1532
|
+
const ctx = canvas.getContext('2d');
|
|
1533
|
+
if (!ctx)
|
|
1534
|
+
return;
|
|
1535
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
1536
|
+
};
|
|
1512
1537
|
|
|
1513
1538
|
function isElementInViewport(elementRect, visualRef, scale) {
|
|
1514
1539
|
if (!elementRect)
|
|
@@ -1546,6 +1571,12 @@ function isElementRectInViewport(elementRect, visualRect, scale) {
|
|
|
1546
1571
|
return elementTop > viewportTop && elementBottom < viewportBottom;
|
|
1547
1572
|
}
|
|
1548
1573
|
|
|
1574
|
+
function isMobileDevice(userAgent) {
|
|
1575
|
+
if (!userAgent)
|
|
1576
|
+
return false;
|
|
1577
|
+
return /android|webos|iphone|ipad|ipod|blackberry|windows phone|opera mini|iemobile|mobile|silk|fennec|bada|tizen|symbian|nokia|palmsource|meego|sailfish|kindle|playbook|bb10|rim/i.test(userAgent);
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1549
1580
|
const CLARITY_HEATMAP_CANVAS_ID = 'clarity-heatmap-canvas';
|
|
1550
1581
|
const HEATMAP_ELEMENT_ATTRIBUTE = 'data-clarity-hashalpha';
|
|
1551
1582
|
function isIgnoredCanvas(element) {
|
|
@@ -1602,324 +1633,36 @@ function getElementHash(element) {
|
|
|
1602
1633
|
return element.getAttribute('data-clarity-hashbeta') || element.getAttribute('data-clarity-hashalpha');
|
|
1603
1634
|
}
|
|
1604
1635
|
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
const AREA_CONTAINER_STYLES = `
|
|
1611
|
-
position: absolute;
|
|
1612
|
-
top: 0;
|
|
1613
|
-
left: 0;
|
|
1614
|
-
width: 100%;
|
|
1615
|
-
height: 100%;
|
|
1616
|
-
pointer-events: none;
|
|
1617
|
-
z-index: 999999;
|
|
1618
|
-
`;
|
|
1619
|
-
const AREA_INNER_CONTAINER_STYLES = `
|
|
1620
|
-
position: relative;
|
|
1621
|
-
width: 100%;
|
|
1622
|
-
height: 100%;
|
|
1623
|
-
`;
|
|
1624
|
-
const AREA_COLOR_GRADIENT = [
|
|
1625
|
-
[0, 0, 255], // Blue
|
|
1626
|
-
[0, 255, 255], // Cyan
|
|
1627
|
-
[0, 255, 0], // Green
|
|
1628
|
-
[255, 255, 0], // Yellow
|
|
1629
|
-
[255, 0, 0], // Red
|
|
1630
|
-
];
|
|
1631
|
-
const AREA_RENDERER_SELECTORS = {
|
|
1632
|
-
containerAttribute: AREA_MAP_DIV_ATTRIBUTE,
|
|
1633
|
-
containerSelector: `[${AREA_MAP_DIV_ATTRIBUTE}]`,
|
|
1634
|
-
innerContainerClass: HEATMAP_AREA_CONTAINER_CLASS,
|
|
1635
|
-
innerContainerSelector: HEATMAP_AREA_CONTAINER_SELECTOR,
|
|
1636
|
-
};
|
|
1637
|
-
|
|
1638
|
-
const CALLOUT_PADDING = 0;
|
|
1639
|
-
const CALLOUT_ARROW_SIZE = 8;
|
|
1640
|
-
const CALLOUT_OFFSET = { x: -8, y: 0 };
|
|
1641
|
-
const CALLOUT_ALIGNMENT = 'left';
|
|
1642
|
-
const CLICKED_ELEMENT_ID_BASE = 'gx-hm-clicked-element';
|
|
1643
|
-
const SECONDARY_CLICKED_ELEMENT_ID_BASE = 'gx-hm-secondary-clicked-element';
|
|
1644
|
-
const HOVERED_ELEMENT_ID_BASE = 'gx-hm-hovered-element';
|
|
1645
|
-
const SECONDARY_HOVERED_ELEMENT_ID_BASE = 'gx-hm-secondary-hovered-element';
|
|
1646
|
-
const DEFAULT_POSITION_MODE = 'absolute';
|
|
1647
|
-
|
|
1648
|
-
/**
|
|
1649
|
-
* Get color from click distribution percentage (0-100)
|
|
1650
|
-
*/
|
|
1651
|
-
function getColorFromClickDist(clickDist) {
|
|
1652
|
-
// Ensure clickDist is in range [0, 100]
|
|
1653
|
-
const normalizedDist = Math.max(0, Math.min(100, clickDist));
|
|
1654
|
-
// Calculate gradient index
|
|
1655
|
-
const maxIndex = AREA_COLOR_GRADIENT.length - 1;
|
|
1656
|
-
const index = Math.floor((normalizedDist / 100) * maxIndex);
|
|
1657
|
-
const clampedIndex = Math.min(index, maxIndex);
|
|
1658
|
-
const [r, g, b] = AREA_COLOR_GRADIENT[clampedIndex];
|
|
1659
|
-
// Return rgba with 60% opacity
|
|
1660
|
-
return `rgba(${r}, ${g}, ${b}, 0.6)`;
|
|
1661
|
-
}
|
|
1662
|
-
/**
|
|
1663
|
-
* Get hover color (slightly lighter) from click distribution
|
|
1664
|
-
*/
|
|
1665
|
-
function getHoverColorFromClickDist(clickDist) {
|
|
1666
|
-
const normalizedDist = Math.max(0, Math.min(100, clickDist));
|
|
1667
|
-
const maxIndex = AREA_COLOR_GRADIENT.length - 1;
|
|
1668
|
-
const index = Math.floor((normalizedDist / 100) * maxIndex);
|
|
1669
|
-
const clampedIndex = Math.min(index, maxIndex);
|
|
1670
|
-
const [r, g, b] = AREA_COLOR_GRADIENT[clampedIndex];
|
|
1671
|
-
// Return rgba with 80% opacity for hover
|
|
1672
|
-
return `rgba(${r}, ${g}, ${b}, 0.8)`;
|
|
1673
|
-
}
|
|
1674
|
-
/**
|
|
1675
|
-
* Calculate click distribution percentage from total clicks
|
|
1676
|
-
*/
|
|
1677
|
-
function calculateClickDistribution(elementClicks, totalClicks) {
|
|
1678
|
-
if (totalClicks === 0)
|
|
1679
|
-
return 0;
|
|
1680
|
-
return (elementClicks / totalClicks) * 100;
|
|
1681
|
-
}
|
|
1682
|
-
|
|
1683
|
-
function getElementRect(element, _shadowRoot) {
|
|
1684
|
-
const rect = element.getBoundingClientRect();
|
|
1685
|
-
const width = rect.width;
|
|
1686
|
-
const height = rect.height;
|
|
1687
|
-
const doc = element.ownerDocument || document;
|
|
1688
|
-
const scrollTop = doc.documentElement?.scrollTop || doc.body?.scrollTop || 0;
|
|
1689
|
-
const scrollLeft = doc.documentElement?.scrollLeft || doc.body?.scrollLeft || 0;
|
|
1690
|
-
const top = rect.top + scrollTop;
|
|
1691
|
-
const left = rect.left + scrollLeft;
|
|
1692
|
-
const absoluteLeft = left;
|
|
1693
|
-
const absoluteTop = top;
|
|
1694
|
-
const absoluteRight = absoluteLeft + width;
|
|
1695
|
-
const absoluteBottom = absoluteTop + height;
|
|
1696
|
-
return {
|
|
1697
|
-
width,
|
|
1698
|
-
height,
|
|
1699
|
-
top,
|
|
1700
|
-
left,
|
|
1701
|
-
absoluteLeft,
|
|
1702
|
-
absoluteTop,
|
|
1703
|
-
absoluteRight,
|
|
1704
|
-
absoluteBottom,
|
|
1705
|
-
outOfBounds: false,
|
|
1636
|
+
class Logger {
|
|
1637
|
+
config = {
|
|
1638
|
+
enabled: false,
|
|
1639
|
+
prefix: '',
|
|
1640
|
+
timestamp: false,
|
|
1706
1641
|
};
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
return false;
|
|
1642
|
+
/**
|
|
1643
|
+
* Cấu hình logger
|
|
1644
|
+
* @param config - Cấu hình logger
|
|
1645
|
+
*/
|
|
1646
|
+
configure(config) {
|
|
1647
|
+
this.config = { ...this.config, ...config };
|
|
1714
1648
|
}
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
const r2 = area2.rect.value;
|
|
1721
|
-
if (!r1 || !r2)
|
|
1722
|
-
return false;
|
|
1723
|
-
return ((r1.absoluteBottom > r2.absoluteTop &&
|
|
1724
|
-
r1.absoluteTop < r2.absoluteBottom &&
|
|
1725
|
-
r1.absoluteRight > r2.absoluteLeft &&
|
|
1726
|
-
r1.absoluteLeft < r2.absoluteRight) ||
|
|
1727
|
-
(r2.absoluteBottom > r1.absoluteTop &&
|
|
1728
|
-
r2.absoluteTop < r1.absoluteBottom &&
|
|
1729
|
-
r2.absoluteRight > r1.absoluteLeft &&
|
|
1730
|
-
r2.absoluteLeft < r1.absoluteRight));
|
|
1731
|
-
}
|
|
1732
|
-
function isAreaContainedIn(area1, area2) {
|
|
1733
|
-
const r1 = area1.rect.value;
|
|
1734
|
-
const r2 = area2.rect.value;
|
|
1735
|
-
if (!r1 || !r2)
|
|
1736
|
-
return false;
|
|
1737
|
-
return (r1.absoluteTop >= r2.absoluteTop &&
|
|
1738
|
-
r1.absoluteBottom <= r2.absoluteBottom &&
|
|
1739
|
-
r1.absoluteLeft >= r2.absoluteLeft &&
|
|
1740
|
-
r1.absoluteRight <= r2.absoluteRight);
|
|
1741
|
-
}
|
|
1742
|
-
function isElementAncestorOf(ancestor, descendant, doc) {
|
|
1743
|
-
return ancestor.contains(descendant);
|
|
1744
|
-
}
|
|
1745
|
-
function isElementSelectable(element, index, elements) {
|
|
1746
|
-
if (isIgnoredCanvas(element)) {
|
|
1747
|
-
return false;
|
|
1649
|
+
/**
|
|
1650
|
+
* Lấy cấu hình hiện tại
|
|
1651
|
+
*/
|
|
1652
|
+
getConfig() {
|
|
1653
|
+
return { ...this.config };
|
|
1748
1654
|
}
|
|
1749
|
-
|
|
1750
|
-
|
|
1655
|
+
/**
|
|
1656
|
+
* Bật logger
|
|
1657
|
+
*/
|
|
1658
|
+
enable() {
|
|
1659
|
+
this.config.enabled = true;
|
|
1751
1660
|
}
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
function sortAreasByClickDist(areas) {
|
|
1758
|
-
return [...areas].sort((a, b) => {
|
|
1759
|
-
if (a.clickDist !== b.clickDist) {
|
|
1760
|
-
return b.clickDist - a.clickDist;
|
|
1761
|
-
}
|
|
1762
|
-
return b.totalclicks - a.totalclicks;
|
|
1763
|
-
});
|
|
1764
|
-
}
|
|
1765
|
-
function isRectTooSmallForLabel(rect) {
|
|
1766
|
-
return rect.width < 67 || rect.height < 30;
|
|
1767
|
-
}
|
|
1768
|
-
|
|
1769
|
-
function getElementSelector(element) {
|
|
1770
|
-
if (element.id) {
|
|
1771
|
-
return `#${element.id}`;
|
|
1772
|
-
}
|
|
1773
|
-
if (element.className) {
|
|
1774
|
-
const classes = Array.from(element.classList).join('.');
|
|
1775
|
-
if (classes) {
|
|
1776
|
-
return `${element.tagName.toLowerCase()}.${classes}`;
|
|
1777
|
-
}
|
|
1778
|
-
}
|
|
1779
|
-
return element.tagName.toLowerCase();
|
|
1780
|
-
}
|
|
1781
|
-
/**
|
|
1782
|
-
* Calculate total clicks for an element including all its child elements
|
|
1783
|
-
* @param element - The parent element
|
|
1784
|
-
* @param elementMapInfo - Map of hash to element click info
|
|
1785
|
-
* @returns Total clicks for element + all descendants
|
|
1786
|
-
*/
|
|
1787
|
-
function calculateTotalClicksWithChildren(element, clickMapMetrics) {
|
|
1788
|
-
let totalClicks = 0;
|
|
1789
|
-
// Get clicks for the element itself
|
|
1790
|
-
const elementHash = getElementHash(element);
|
|
1791
|
-
if (elementHash) {
|
|
1792
|
-
const elementInfo = clickMapMetrics[elementHash];
|
|
1793
|
-
totalClicks += elementInfo?.totalClicked.value ?? 0;
|
|
1794
|
-
}
|
|
1795
|
-
const children = element.querySelectorAll('*');
|
|
1796
|
-
children.forEach((child) => {
|
|
1797
|
-
const childHash = getElementHash(child);
|
|
1798
|
-
if (childHash) {
|
|
1799
|
-
const childInfo = clickMapMetrics[childHash];
|
|
1800
|
-
totalClicks += childInfo?.totalClicked.value ?? 0;
|
|
1801
|
-
}
|
|
1802
|
-
});
|
|
1803
|
-
return totalClicks;
|
|
1804
|
-
}
|
|
1805
|
-
function buildAreaNode(element, hash, heatmapInfo, shadowRoot, persistedData) {
|
|
1806
|
-
if (!heatmapInfo.clickMapMetrics)
|
|
1807
|
-
return;
|
|
1808
|
-
const totalClicks = heatmapInfo.totalClicks || 0;
|
|
1809
|
-
const elementInfo = heatmapInfo.clickMapMetrics[hash];
|
|
1810
|
-
// Calculate total clicks including all child elements
|
|
1811
|
-
const elementClicks = calculateTotalClicksWithChildren(element, heatmapInfo.clickMapMetrics);
|
|
1812
|
-
const clickDist = calculateClickDistribution(elementClicks, totalClicks);
|
|
1813
|
-
const rect = getElementRect(element);
|
|
1814
|
-
const color = getColorFromClickDist(clickDist);
|
|
1815
|
-
const hoverColor = getHoverColorFromClickDist(clickDist);
|
|
1816
|
-
const areaNode = {
|
|
1817
|
-
kind: persistedData?.kind || 'area',
|
|
1818
|
-
id: persistedData?.id || `${hash}_${Date.now()}`,
|
|
1819
|
-
hash,
|
|
1820
|
-
selector: persistedData?.selector || elementInfo?.selector || getElementSelector(element),
|
|
1821
|
-
// DOM references
|
|
1822
|
-
element,
|
|
1823
|
-
areaElement: null,
|
|
1824
|
-
shadowElement: null,
|
|
1825
|
-
shadowStyleElement: null,
|
|
1826
|
-
// Graph structure
|
|
1827
|
-
parentNode: null,
|
|
1828
|
-
childNodes: new Set(),
|
|
1829
|
-
// Position
|
|
1830
|
-
rect: createObservable(rect),
|
|
1831
|
-
isFixed: isElementFixed(element),
|
|
1832
|
-
priority: false,
|
|
1833
|
-
// Click tracking
|
|
1834
|
-
totalclicks: elementClicks,
|
|
1835
|
-
cumulativeClicks: elementClicks,
|
|
1836
|
-
cumulativeMaxClicks: totalClicks,
|
|
1837
|
-
clickDist,
|
|
1838
|
-
hasClickInfo: true,
|
|
1839
|
-
// Visual
|
|
1840
|
-
color,
|
|
1841
|
-
hoverColor,
|
|
1842
|
-
// Lifecycle
|
|
1843
|
-
changeObserver: null,
|
|
1844
|
-
};
|
|
1845
|
-
return areaNode;
|
|
1846
|
-
}
|
|
1847
|
-
function getTopElementsByClicks(clickMapMetrics, topN = 10) {
|
|
1848
|
-
const elements = Object.entries(clickMapMetrics)
|
|
1849
|
-
.map(([hash, info]) => ({
|
|
1850
|
-
hash,
|
|
1851
|
-
totalclicks: info.totalClicked.value ?? 0,
|
|
1852
|
-
selector: info.selector || '',
|
|
1853
|
-
}))
|
|
1854
|
-
.sort((a, b) => b.totalclicks - a.totalclicks)
|
|
1855
|
-
.slice(0, topN);
|
|
1856
|
-
return elements;
|
|
1857
|
-
}
|
|
1858
|
-
|
|
1859
|
-
/**
|
|
1860
|
-
* Build parent-child relationships between areas based on DOM hierarchy
|
|
1861
|
-
* @param areas - Array of area nodes to build relationships for
|
|
1862
|
-
*/
|
|
1863
|
-
function buildAreaGraph(areas) {
|
|
1864
|
-
// Clear existing relationships
|
|
1865
|
-
areas.forEach((area) => {
|
|
1866
|
-
area.parentNode = null;
|
|
1867
|
-
area.childNodes.clear();
|
|
1868
|
-
});
|
|
1869
|
-
// Build relationships based on DOM containment
|
|
1870
|
-
for (let i = 0; i < areas.length; i++) {
|
|
1871
|
-
const area = areas[i];
|
|
1872
|
-
for (let j = 0; j < areas.length; j++) {
|
|
1873
|
-
if (i === j)
|
|
1874
|
-
continue;
|
|
1875
|
-
const otherArea = areas[j];
|
|
1876
|
-
// Check if area's element is contained within otherArea's element
|
|
1877
|
-
if (otherArea.element.contains(area.element)) {
|
|
1878
|
-
// Find the closest parent (not just any ancestor)
|
|
1879
|
-
if (!area.parentNode || area.parentNode.element.contains(otherArea.element)) {
|
|
1880
|
-
// Remove from old parent if exists
|
|
1881
|
-
if (area.parentNode) {
|
|
1882
|
-
area.parentNode.childNodes.delete(area);
|
|
1883
|
-
}
|
|
1884
|
-
// Set new parent
|
|
1885
|
-
area.parentNode = otherArea;
|
|
1886
|
-
otherArea.childNodes.add(area);
|
|
1887
|
-
}
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1890
|
-
}
|
|
1891
|
-
}
|
|
1892
|
-
|
|
1893
|
-
class Logger {
|
|
1894
|
-
config = {
|
|
1895
|
-
enabled: false,
|
|
1896
|
-
prefix: '',
|
|
1897
|
-
timestamp: false,
|
|
1898
|
-
};
|
|
1899
|
-
/**
|
|
1900
|
-
* Cấu hình logger
|
|
1901
|
-
* @param config - Cấu hình logger
|
|
1902
|
-
*/
|
|
1903
|
-
configure(config) {
|
|
1904
|
-
this.config = { ...this.config, ...config };
|
|
1905
|
-
}
|
|
1906
|
-
/**
|
|
1907
|
-
* Lấy cấu hình hiện tại
|
|
1908
|
-
*/
|
|
1909
|
-
getConfig() {
|
|
1910
|
-
return { ...this.config };
|
|
1911
|
-
}
|
|
1912
|
-
/**
|
|
1913
|
-
* Bật logger
|
|
1914
|
-
*/
|
|
1915
|
-
enable() {
|
|
1916
|
-
this.config.enabled = true;
|
|
1917
|
-
}
|
|
1918
|
-
/**
|
|
1919
|
-
* Tắt logger
|
|
1920
|
-
*/
|
|
1921
|
-
disable() {
|
|
1922
|
-
this.config.enabled = false;
|
|
1661
|
+
/**
|
|
1662
|
+
* Tắt logger
|
|
1663
|
+
*/
|
|
1664
|
+
disable() {
|
|
1665
|
+
this.config.enabled = false;
|
|
1923
1666
|
}
|
|
1924
1667
|
/**
|
|
1925
1668
|
* Format message với prefix và timestamp
|
|
@@ -2027,7 +1770,7 @@ class Logger {
|
|
|
2027
1770
|
}
|
|
2028
1771
|
}
|
|
2029
1772
|
// Export singleton instance
|
|
2030
|
-
const logger$
|
|
1773
|
+
const logger$9 = new Logger();
|
|
2031
1774
|
// Export factory function để tạo logger với config riêng
|
|
2032
1775
|
function createLogger(config = {}) {
|
|
2033
1776
|
const instance = new Logger();
|
|
@@ -2035,174 +1778,503 @@ function createLogger(config = {}) {
|
|
|
2035
1778
|
return instance;
|
|
2036
1779
|
}
|
|
2037
1780
|
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
const
|
|
2043
|
-
const
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
1781
|
+
/**
|
|
1782
|
+
* Create an observable value with subscribe/unsubscribe pattern
|
|
1783
|
+
*/
|
|
1784
|
+
function createObservable(initialValue) {
|
|
1785
|
+
const subscribers = new Set();
|
|
1786
|
+
const observable = {
|
|
1787
|
+
value: initialValue,
|
|
1788
|
+
observe: (callback) => {
|
|
1789
|
+
subscribers.add(callback);
|
|
1790
|
+
// Immediately call with current value
|
|
1791
|
+
if (observable.value !== undefined) {
|
|
1792
|
+
callback(observable.value);
|
|
1793
|
+
}
|
|
1794
|
+
},
|
|
1795
|
+
unobserve: (callback) => {
|
|
1796
|
+
subscribers.delete(callback);
|
|
1797
|
+
},
|
|
1798
|
+
update: (newValue) => {
|
|
1799
|
+
observable.value = newValue;
|
|
1800
|
+
// Notify all subscribers
|
|
1801
|
+
subscribers.forEach((callback) => {
|
|
1802
|
+
callback(newValue);
|
|
1803
|
+
});
|
|
2059
1804
|
},
|
|
2060
1805
|
};
|
|
2061
|
-
|
|
2062
|
-
function decodeClarity(payload) {
|
|
2063
|
-
try {
|
|
2064
|
-
return decode(payload);
|
|
2065
|
-
}
|
|
2066
|
-
catch (_error) {
|
|
2067
|
-
return null;
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
function decodeArrayClarity(items) {
|
|
2071
|
-
return items.map((item) => decodeClarity(item)).filter((item) => item !== null);
|
|
1806
|
+
return observable;
|
|
2072
1807
|
}
|
|
2073
1808
|
|
|
2074
|
-
function
|
|
2075
|
-
|
|
2076
|
-
if (vizRef) {
|
|
2077
|
-
const element = vizRef.get(hash);
|
|
2078
|
-
return element;
|
|
2079
|
-
}
|
|
2080
|
-
// Fallback
|
|
2081
|
-
if (!iframeDocument)
|
|
2082
|
-
return null;
|
|
2083
|
-
try {
|
|
2084
|
-
const element = selector ? iframeDocument.querySelector(selector) : null;
|
|
2085
|
-
if (element) {
|
|
2086
|
-
return element;
|
|
2087
|
-
}
|
|
2088
|
-
}
|
|
2089
|
-
catch (error) {
|
|
2090
|
-
logger$4.warn(`Invalid selector "${selector}":`, error);
|
|
2091
|
-
}
|
|
2092
|
-
const elementByHash = iframeDocument.querySelector(`[data-clarity-hashalpha="${hash}"], [data-clarity-hash="${hash}"], [data-clarity-hashbeta="${hash}"]`);
|
|
2093
|
-
return elementByHash;
|
|
1809
|
+
function sortEvents(a, b) {
|
|
1810
|
+
return a.time - b.time;
|
|
2094
1811
|
}
|
|
2095
1812
|
|
|
2096
1813
|
/**
|
|
2097
|
-
*
|
|
2098
|
-
*
|
|
2099
|
-
*
|
|
2100
|
-
* @param persistedData - Minimal data from database
|
|
2101
|
-
* @param iframeDocument - Document to find element in
|
|
2102
|
-
* @param heatmapInfo - Heatmap data for click calculations
|
|
2103
|
-
* @param vizRef - Map of hash to elements
|
|
2104
|
-
* @param shadowRoot - Optional shadow root for rect calculation
|
|
2105
|
-
* @returns Full area node or null if element not found
|
|
1814
|
+
* Throttle a function using requestAnimationFrame
|
|
1815
|
+
* Ensures the callback is called at most once per animation frame
|
|
2106
1816
|
*/
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
const
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
}
|
|
1817
|
+
const throttleRAF = (callback) => {
|
|
1818
|
+
let rafId = null;
|
|
1819
|
+
let latestArgs = null;
|
|
1820
|
+
const throttled = (...args) => {
|
|
1821
|
+
// Store the latest arguments
|
|
1822
|
+
latestArgs = args;
|
|
1823
|
+
// If already scheduled, do nothing
|
|
1824
|
+
if (rafId !== null)
|
|
1825
|
+
return;
|
|
1826
|
+
// Schedule the callback for the next animation frame
|
|
1827
|
+
rafId = requestAnimationFrame(() => {
|
|
1828
|
+
if (latestArgs !== null) {
|
|
1829
|
+
callback(...latestArgs);
|
|
1830
|
+
latestArgs = null;
|
|
1831
|
+
}
|
|
1832
|
+
rafId = null;
|
|
1833
|
+
});
|
|
1834
|
+
};
|
|
1835
|
+
// Add cancel method to clear pending RAF
|
|
1836
|
+
throttled.cancel = () => {
|
|
1837
|
+
if (rafId !== null) {
|
|
1838
|
+
cancelAnimationFrame(rafId);
|
|
1839
|
+
rafId = null;
|
|
1840
|
+
latestArgs = null;
|
|
1841
|
+
}
|
|
1842
|
+
};
|
|
1843
|
+
return throttled;
|
|
1844
|
+
};
|
|
1845
|
+
|
|
1846
|
+
const AREA_HOVER_BOX_SHADOW = '0 0 0 1px #0078D4, 0 0 0 1px #0078D4 inset, 0 0 0 2px white inset';
|
|
1847
|
+
const AREA_HOVER_ELEMENT_ID = 'clarity-edit-hover';
|
|
1848
|
+
const AREA_MAP_DIV_ATTRIBUTE = 'data-clarity-area-map-div';
|
|
1849
|
+
const HEATMAP_AREA_CONTAINER_CLASS = 'heatmap-area-container';
|
|
1850
|
+
const HEATMAP_AREA_CONTAINER_SELECTOR = `.${HEATMAP_AREA_CONTAINER_CLASS}`;
|
|
1851
|
+
const AREA_CONTAINER_STYLES = `
|
|
1852
|
+
position: absolute;
|
|
1853
|
+
top: 0;
|
|
1854
|
+
left: 0;
|
|
1855
|
+
width: 100%;
|
|
1856
|
+
height: 100%;
|
|
1857
|
+
pointer-events: none;
|
|
1858
|
+
z-index: 999999;
|
|
1859
|
+
`;
|
|
1860
|
+
const AREA_INNER_CONTAINER_STYLES = `
|
|
1861
|
+
position: relative;
|
|
1862
|
+
width: 100%;
|
|
1863
|
+
height: 100%;
|
|
1864
|
+
`;
|
|
1865
|
+
const AREA_COLOR_GRADIENT = [
|
|
1866
|
+
[0, 0, 255], // Blue
|
|
1867
|
+
[0, 255, 255], // Cyan
|
|
1868
|
+
[0, 255, 0], // Green
|
|
1869
|
+
[255, 255, 0], // Yellow
|
|
1870
|
+
[255, 0, 0], // Red
|
|
1871
|
+
];
|
|
1872
|
+
const AREA_RENDERER_SELECTORS = {
|
|
1873
|
+
containerAttribute: AREA_MAP_DIV_ATTRIBUTE,
|
|
1874
|
+
containerSelector: `[${AREA_MAP_DIV_ATTRIBUTE}]`,
|
|
1875
|
+
innerContainerClass: HEATMAP_AREA_CONTAINER_CLASS,
|
|
1876
|
+
innerContainerSelector: HEATMAP_AREA_CONTAINER_SELECTOR,
|
|
1877
|
+
};
|
|
1878
|
+
|
|
1879
|
+
const CALLOUT_PADDING = 0;
|
|
1880
|
+
const CALLOUT_ARROW_SIZE = 8;
|
|
1881
|
+
const CALLOUT_OFFSET = { x: -8, y: 0 };
|
|
1882
|
+
const CALLOUT_ALIGNMENT = 'left';
|
|
1883
|
+
const CLICKED_ELEMENT_ID_BASE = 'gx-hm-clicked-element';
|
|
1884
|
+
const SECONDARY_CLICKED_ELEMENT_ID_BASE = 'gx-hm-secondary-clicked-element';
|
|
1885
|
+
const HOVERED_ELEMENT_ID_BASE = 'gx-hm-hovered-element';
|
|
1886
|
+
const SECONDARY_HOVERED_ELEMENT_ID_BASE = 'gx-hm-secondary-hovered-element';
|
|
1887
|
+
const DEFAULT_POSITION_MODE = 'absolute';
|
|
1888
|
+
|
|
2132
1889
|
/**
|
|
2133
|
-
*
|
|
1890
|
+
* Get color from click distribution percentage (0-100)
|
|
2134
1891
|
*/
|
|
2135
|
-
function
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
1892
|
+
function getColorFromClickDist(clickDist) {
|
|
1893
|
+
// Ensure clickDist is in range [0, 100]
|
|
1894
|
+
const normalizedDist = Math.max(0, Math.min(100, clickDist));
|
|
1895
|
+
// Calculate gradient index
|
|
1896
|
+
const maxIndex = AREA_COLOR_GRADIENT.length - 1;
|
|
1897
|
+
const index = Math.floor((normalizedDist / 100) * maxIndex);
|
|
1898
|
+
const clampedIndex = Math.min(index, maxIndex);
|
|
1899
|
+
const [r, g, b] = AREA_COLOR_GRADIENT[clampedIndex];
|
|
1900
|
+
// Return rgba with 60% opacity
|
|
1901
|
+
return `rgba(${r}, ${g}, ${b}, 0.6)`;
|
|
2142
1902
|
}
|
|
2143
1903
|
/**
|
|
2144
|
-
*
|
|
1904
|
+
* Get hover color (slightly lighter) from click distribution
|
|
2145
1905
|
*/
|
|
2146
|
-
function
|
|
2147
|
-
|
|
1906
|
+
function getHoverColorFromClickDist(clickDist) {
|
|
1907
|
+
const normalizedDist = Math.max(0, Math.min(100, clickDist));
|
|
1908
|
+
const maxIndex = AREA_COLOR_GRADIENT.length - 1;
|
|
1909
|
+
const index = Math.floor((normalizedDist / 100) * maxIndex);
|
|
1910
|
+
const clampedIndex = Math.min(index, maxIndex);
|
|
1911
|
+
const [r, g, b] = AREA_COLOR_GRADIENT[clampedIndex];
|
|
1912
|
+
// Return rgba with 80% opacity for hover
|
|
1913
|
+
return `rgba(${r}, ${g}, ${b}, 0.8)`;
|
|
2148
1914
|
}
|
|
2149
|
-
|
|
2150
1915
|
/**
|
|
2151
|
-
*
|
|
2152
|
-
*
|
|
2153
|
-
* Priority Rules (in order):
|
|
2154
|
-
* 1. Priority flag (manually set areas win)
|
|
2155
|
-
* 2. Click distribution (higher % wins)
|
|
2156
|
-
* 3. Total clicks (more clicks wins)
|
|
2157
|
-
* 4. DOM containment (parent contains child, parent wins)
|
|
2158
|
-
* 5. Size (smaller areas win - more specific)
|
|
1916
|
+
* Calculate click distribution percentage from total clicks
|
|
2159
1917
|
*/
|
|
2160
|
-
function
|
|
2161
|
-
if (
|
|
2162
|
-
return
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
1918
|
+
function calculateClickDistribution(elementClicks, totalClicks) {
|
|
1919
|
+
if (totalClicks === 0)
|
|
1920
|
+
return 0;
|
|
1921
|
+
return (elementClicks / totalClicks) * 100;
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
function getElementRect(element, _shadowRoot) {
|
|
1925
|
+
const rect = element.getBoundingClientRect();
|
|
1926
|
+
const width = rect.width;
|
|
1927
|
+
const height = rect.height;
|
|
1928
|
+
const doc = element.ownerDocument || document;
|
|
1929
|
+
const scrollTop = doc.documentElement?.scrollTop || doc.body?.scrollTop || 0;
|
|
1930
|
+
const scrollLeft = doc.documentElement?.scrollLeft || doc.body?.scrollLeft || 0;
|
|
1931
|
+
const top = rect.top + scrollTop;
|
|
1932
|
+
const left = rect.left + scrollLeft;
|
|
1933
|
+
const absoluteLeft = left;
|
|
1934
|
+
const absoluteTop = top;
|
|
1935
|
+
const absoluteRight = absoluteLeft + width;
|
|
1936
|
+
const absoluteBottom = absoluteTop + height;
|
|
1937
|
+
return {
|
|
1938
|
+
width,
|
|
1939
|
+
height,
|
|
1940
|
+
top,
|
|
1941
|
+
left,
|
|
1942
|
+
absoluteLeft,
|
|
1943
|
+
absoluteTop,
|
|
1944
|
+
absoluteRight,
|
|
1945
|
+
absoluteBottom,
|
|
1946
|
+
outOfBounds: false,
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
function isElementFixed(element) {
|
|
1950
|
+
if (getComputedStyle(element).position === 'fixed') {
|
|
1951
|
+
return true;
|
|
1952
|
+
}
|
|
1953
|
+
if (element.nodeName === 'HTML') {
|
|
1954
|
+
return false;
|
|
1955
|
+
}
|
|
1956
|
+
const parent = element.parentElement;
|
|
1957
|
+
return parent ? isElementFixed(parent) : false;
|
|
1958
|
+
}
|
|
1959
|
+
function doAreasOverlap(area1, area2) {
|
|
1960
|
+
const r1 = area1.rect.value;
|
|
1961
|
+
const r2 = area2.rect.value;
|
|
1962
|
+
if (!r1 || !r2)
|
|
1963
|
+
return false;
|
|
1964
|
+
return ((r1.absoluteBottom > r2.absoluteTop &&
|
|
1965
|
+
r1.absoluteTop < r2.absoluteBottom &&
|
|
1966
|
+
r1.absoluteRight > r2.absoluteLeft &&
|
|
1967
|
+
r1.absoluteLeft < r2.absoluteRight) ||
|
|
1968
|
+
(r2.absoluteBottom > r1.absoluteTop &&
|
|
1969
|
+
r2.absoluteTop < r1.absoluteBottom &&
|
|
1970
|
+
r2.absoluteRight > r1.absoluteLeft &&
|
|
1971
|
+
r2.absoluteLeft < r1.absoluteRight));
|
|
1972
|
+
}
|
|
1973
|
+
function isAreaContainedIn(area1, area2) {
|
|
1974
|
+
const r1 = area1.rect.value;
|
|
1975
|
+
const r2 = area2.rect.value;
|
|
1976
|
+
if (!r1 || !r2)
|
|
1977
|
+
return false;
|
|
1978
|
+
return (r1.absoluteTop >= r2.absoluteTop &&
|
|
1979
|
+
r1.absoluteBottom <= r2.absoluteBottom &&
|
|
1980
|
+
r1.absoluteLeft >= r2.absoluteLeft &&
|
|
1981
|
+
r1.absoluteRight <= r2.absoluteRight);
|
|
1982
|
+
}
|
|
1983
|
+
function isElementAncestorOf(ancestor, descendant, doc) {
|
|
1984
|
+
return ancestor.contains(descendant);
|
|
1985
|
+
}
|
|
1986
|
+
function isElementSelectable(element, index, elements) {
|
|
1987
|
+
if (isIgnoredCanvas(element)) {
|
|
1988
|
+
return false;
|
|
1989
|
+
}
|
|
1990
|
+
if (element.hasAttribute(AREA_MAP_DIV_ATTRIBUTE)) {
|
|
1991
|
+
return false;
|
|
1992
|
+
}
|
|
1993
|
+
if (index === 0 && elements.length > 1 && element.nodeName === 'BODY') {
|
|
1994
|
+
return false;
|
|
1995
|
+
}
|
|
1996
|
+
return true;
|
|
1997
|
+
}
|
|
1998
|
+
function sortAreasByClickDist(areas) {
|
|
1999
|
+
return [...areas].sort((a, b) => {
|
|
2000
|
+
if (a.clickDist !== b.clickDist) {
|
|
2001
|
+
return b.clickDist - a.clickDist;
|
|
2176
2002
|
}
|
|
2003
|
+
return b.totalclicks - a.totalclicks;
|
|
2177
2004
|
});
|
|
2178
|
-
return Array.from(visibleAreas);
|
|
2179
2005
|
}
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
// No overlap, skip grouping
|
|
2193
|
-
return;
|
|
2006
|
+
function isRectTooSmallForLabel(rect) {
|
|
2007
|
+
return rect.width < 67 || rect.height < 30;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
function getElementSelector(element) {
|
|
2011
|
+
if (element.id) {
|
|
2012
|
+
return `#${element.id}`;
|
|
2013
|
+
}
|
|
2014
|
+
if (element.className) {
|
|
2015
|
+
const classes = Array.from(element.classList).join('.');
|
|
2016
|
+
if (classes) {
|
|
2017
|
+
return `${element.tagName.toLowerCase()}.${classes}`;
|
|
2194
2018
|
}
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2019
|
+
}
|
|
2020
|
+
return element.tagName.toLowerCase();
|
|
2021
|
+
}
|
|
2022
|
+
/**
|
|
2023
|
+
* Calculate total clicks for an element including all its child elements
|
|
2024
|
+
* @param element - The parent element
|
|
2025
|
+
* @param elementMapInfo - Map of hash to element click info
|
|
2026
|
+
* @returns Total clicks for element + all descendants
|
|
2027
|
+
*/
|
|
2028
|
+
function calculateTotalClicksWithChildren(element, clickMapMetrics) {
|
|
2029
|
+
let totalClicks = 0;
|
|
2030
|
+
// Get clicks for the element itself
|
|
2031
|
+
const elementHash = getElementHash(element);
|
|
2032
|
+
if (elementHash) {
|
|
2033
|
+
const elementInfo = clickMapMetrics[elementHash];
|
|
2034
|
+
totalClicks += elementInfo?.totalClicked.value ?? 0;
|
|
2035
|
+
}
|
|
2036
|
+
const children = element.querySelectorAll('*');
|
|
2037
|
+
children.forEach((child) => {
|
|
2038
|
+
const childHash = getElementHash(child);
|
|
2039
|
+
if (childHash) {
|
|
2040
|
+
const childInfo = clickMapMetrics[childHash];
|
|
2041
|
+
totalClicks += childInfo?.totalClicked.value ?? 0;
|
|
2042
|
+
}
|
|
2043
|
+
});
|
|
2044
|
+
return totalClicks;
|
|
2045
|
+
}
|
|
2046
|
+
function buildAreaNode(element, hash, heatmapInfo, shadowRoot, persistedData) {
|
|
2047
|
+
if (!heatmapInfo.clickMapMetrics)
|
|
2048
|
+
return;
|
|
2049
|
+
const totalClicks = heatmapInfo.totalClicks || 0;
|
|
2050
|
+
const elementInfo = heatmapInfo.clickMapMetrics[hash];
|
|
2051
|
+
// Calculate total clicks including all child elements
|
|
2052
|
+
const elementClicks = calculateTotalClicksWithChildren(element, heatmapInfo.clickMapMetrics);
|
|
2053
|
+
const clickDist = calculateClickDistribution(elementClicks, totalClicks);
|
|
2054
|
+
const rect = getElementRect(element);
|
|
2055
|
+
const color = getColorFromClickDist(clickDist);
|
|
2056
|
+
const hoverColor = getHoverColorFromClickDist(clickDist);
|
|
2057
|
+
const areaNode = {
|
|
2058
|
+
kind: persistedData?.kind || 'area',
|
|
2059
|
+
id: persistedData?.id || `${hash}_${Date.now()}`,
|
|
2060
|
+
hash,
|
|
2061
|
+
selector: persistedData?.selector || elementInfo?.selector || getElementSelector(element),
|
|
2062
|
+
// DOM references
|
|
2063
|
+
element,
|
|
2064
|
+
areaElement: null,
|
|
2065
|
+
shadowElement: null,
|
|
2066
|
+
shadowStyleElement: null,
|
|
2067
|
+
// Graph structure
|
|
2068
|
+
parentNode: null,
|
|
2069
|
+
childNodes: new Set(),
|
|
2070
|
+
// Position
|
|
2071
|
+
rect: createObservable(rect),
|
|
2072
|
+
isFixed: isElementFixed(element),
|
|
2073
|
+
priority: false,
|
|
2074
|
+
// Click tracking
|
|
2075
|
+
totalclicks: elementClicks,
|
|
2076
|
+
cumulativeClicks: elementClicks,
|
|
2077
|
+
cumulativeMaxClicks: totalClicks,
|
|
2078
|
+
clickDist,
|
|
2079
|
+
hasClickInfo: true,
|
|
2080
|
+
// Visual
|
|
2081
|
+
color,
|
|
2082
|
+
hoverColor,
|
|
2083
|
+
// Lifecycle
|
|
2084
|
+
changeObserver: null,
|
|
2085
|
+
};
|
|
2086
|
+
return areaNode;
|
|
2087
|
+
}
|
|
2088
|
+
function getTopElementsByClicks(clickMapMetrics, topN = 10) {
|
|
2089
|
+
const elements = Object.entries(clickMapMetrics)
|
|
2090
|
+
.map(([hash, info]) => ({
|
|
2091
|
+
hash,
|
|
2092
|
+
totalclicks: info.totalClicked.value ?? 0,
|
|
2093
|
+
selector: info.selector || '',
|
|
2094
|
+
}))
|
|
2095
|
+
.sort((a, b) => b.totalclicks - a.totalclicks)
|
|
2096
|
+
.slice(0, topN);
|
|
2097
|
+
return elements;
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
/**
|
|
2101
|
+
* Build parent-child relationships between areas based on DOM hierarchy
|
|
2102
|
+
* @param areas - Array of area nodes to build relationships for
|
|
2103
|
+
*/
|
|
2104
|
+
function buildAreaGraph(areas) {
|
|
2105
|
+
// Clear existing relationships
|
|
2106
|
+
areas.forEach((area) => {
|
|
2107
|
+
area.parentNode = null;
|
|
2108
|
+
area.childNodes.clear();
|
|
2109
|
+
});
|
|
2110
|
+
// Build relationships based on DOM containment
|
|
2111
|
+
for (let i = 0; i < areas.length; i++) {
|
|
2112
|
+
const area = areas[i];
|
|
2113
|
+
for (let j = 0; j < areas.length; j++) {
|
|
2114
|
+
if (i === j)
|
|
2115
|
+
continue;
|
|
2116
|
+
const otherArea = areas[j];
|
|
2117
|
+
// Check if area's element is contained within otherArea's element
|
|
2118
|
+
if (otherArea.element.contains(area.element)) {
|
|
2119
|
+
// Find the closest parent (not just any ancestor)
|
|
2120
|
+
if (!area.parentNode || area.parentNode.element.contains(otherArea.element)) {
|
|
2121
|
+
// Remove from old parent if exists
|
|
2122
|
+
if (area.parentNode) {
|
|
2123
|
+
area.parentNode.childNodes.delete(area);
|
|
2124
|
+
}
|
|
2125
|
+
// Set new parent
|
|
2126
|
+
area.parentNode = otherArea;
|
|
2127
|
+
otherArea.childNodes.add(area);
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
function decodeClarity(payload) {
|
|
2135
|
+
try {
|
|
2136
|
+
return decode(payload);
|
|
2137
|
+
}
|
|
2138
|
+
catch (_error) {
|
|
2139
|
+
return null;
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
function decodeArrayClarity(items) {
|
|
2143
|
+
return items.map((item) => decodeClarity(item)).filter((item) => item !== null);
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
function findElementByHash(props) {
|
|
2147
|
+
const { hash, selector, iframeDocument, vizRef } = props;
|
|
2148
|
+
if (vizRef) {
|
|
2149
|
+
const element = vizRef.get(hash);
|
|
2150
|
+
return element;
|
|
2151
|
+
}
|
|
2152
|
+
// Fallback
|
|
2153
|
+
if (!iframeDocument)
|
|
2154
|
+
return null;
|
|
2155
|
+
try {
|
|
2156
|
+
const element = selector ? iframeDocument.querySelector(selector) : null;
|
|
2157
|
+
if (element) {
|
|
2158
|
+
return element;
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
catch (error) {
|
|
2162
|
+
logger$9.warn(`Invalid selector "${selector}":`, error);
|
|
2163
|
+
}
|
|
2164
|
+
const elementByHash = iframeDocument.querySelector(`[data-clarity-hashalpha="${hash}"], [data-clarity-hash="${hash}"], [data-clarity-hashbeta="${hash}"]`);
|
|
2165
|
+
return elementByHash;
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
/**
|
|
2169
|
+
* Hydrates persisted area data into full area node
|
|
2170
|
+
* Finds element in DOM and calculates all runtime values
|
|
2171
|
+
*
|
|
2172
|
+
* @param persistedData - Minimal data from database
|
|
2173
|
+
* @param iframeDocument - Document to find element in
|
|
2174
|
+
* @param heatmapInfo - Heatmap data for click calculations
|
|
2175
|
+
* @param vizRef - Map of hash to elements
|
|
2176
|
+
* @param shadowRoot - Optional shadow root for rect calculation
|
|
2177
|
+
* @returns Full area node or null if element not found
|
|
2178
|
+
*/
|
|
2179
|
+
function hydrateAreaNode(props) {
|
|
2180
|
+
const { persistedData, iframeDocument, heatmapInfo, vizRef, shadowRoot } = props;
|
|
2181
|
+
const { id, hash, selector } = persistedData;
|
|
2182
|
+
const element = findElementByHash({ hash, selector, iframeDocument, vizRef });
|
|
2183
|
+
if (!element) {
|
|
2184
|
+
logger$9.warn(`Cannot hydrate area ${id}: element not found for hash ${hash} or selector ${selector}`);
|
|
2185
|
+
return null;
|
|
2186
|
+
}
|
|
2187
|
+
const areaNode = buildAreaNode(element, hash, heatmapInfo, shadowRoot, persistedData);
|
|
2188
|
+
if (!areaNode)
|
|
2189
|
+
return null;
|
|
2190
|
+
return areaNode;
|
|
2191
|
+
}
|
|
2192
|
+
function hydrateAreas(props) {
|
|
2193
|
+
const { clickAreas, iframeDocument, heatmapInfo, vizRef, shadowRoot } = props;
|
|
2194
|
+
const hydratedAreas = [];
|
|
2195
|
+
for (const persistedData of clickAreas) {
|
|
2196
|
+
const area = hydrateAreaNode({ persistedData, iframeDocument, heatmapInfo, vizRef, shadowRoot });
|
|
2197
|
+
if (area) {
|
|
2198
|
+
hydratedAreas.push(area);
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
logger$9.info(`Hydrated ${hydratedAreas.length} of ${clickAreas.length} persisted areas`);
|
|
2202
|
+
return hydratedAreas;
|
|
2203
|
+
}
|
|
2204
|
+
/**
|
|
2205
|
+
* Serializes area node to persisted data for database storage
|
|
2206
|
+
*/
|
|
2207
|
+
function serializeAreaNode(area) {
|
|
2208
|
+
return {
|
|
2209
|
+
kind: area.kind,
|
|
2210
|
+
id: area.id,
|
|
2211
|
+
hash: area.hash,
|
|
2212
|
+
selector: area.selector,
|
|
2213
|
+
};
|
|
2214
|
+
}
|
|
2215
|
+
/**
|
|
2216
|
+
* Serializes multiple areas for database storage
|
|
2217
|
+
*/
|
|
2218
|
+
function serializeAreas(areas) {
|
|
2219
|
+
return areas.map(serializeAreaNode);
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
/**
|
|
2223
|
+
* Resolve overlapping areas by priority rules
|
|
2224
|
+
*
|
|
2225
|
+
* Priority Rules (in order):
|
|
2226
|
+
* 1. Priority flag (manually set areas win)
|
|
2227
|
+
* 2. Click distribution (higher % wins)
|
|
2228
|
+
* 3. Total clicks (more clicks wins)
|
|
2229
|
+
* 4. DOM containment (parent contains child, parent wins)
|
|
2230
|
+
* 5. Size (smaller areas win - more specific)
|
|
2231
|
+
*/
|
|
2232
|
+
function resolveOverlaps(areas, iframeDocument) {
|
|
2233
|
+
if (areas.length === 0)
|
|
2234
|
+
return [];
|
|
2235
|
+
// Group overlapping areas
|
|
2236
|
+
const overlapGroups = findOverlapGroups(areas);
|
|
2237
|
+
// Resolve each group
|
|
2238
|
+
const visibleAreas = new Set();
|
|
2239
|
+
overlapGroups.forEach((group) => {
|
|
2240
|
+
const winner = resolveOverlapGroup(group, iframeDocument);
|
|
2241
|
+
visibleAreas.add(winner);
|
|
2242
|
+
});
|
|
2243
|
+
// Add non-overlapping areas
|
|
2244
|
+
areas.forEach((area) => {
|
|
2245
|
+
const hasOverlap = overlapGroups.some((group) => group.areas.includes(area));
|
|
2246
|
+
if (!hasOverlap) {
|
|
2247
|
+
visibleAreas.add(area);
|
|
2248
|
+
}
|
|
2249
|
+
});
|
|
2250
|
+
return Array.from(visibleAreas);
|
|
2251
|
+
}
|
|
2252
|
+
/**
|
|
2253
|
+
* Find groups of overlapping areas
|
|
2254
|
+
*/
|
|
2255
|
+
function findOverlapGroups(areas) {
|
|
2256
|
+
const groups = [];
|
|
2257
|
+
const processed = new Set();
|
|
2258
|
+
areas.forEach((area) => {
|
|
2259
|
+
if (processed.has(area.id))
|
|
2260
|
+
return;
|
|
2261
|
+
// Find all areas that overlap with this one
|
|
2262
|
+
const overlapping = areas.filter((other) => other.id !== area.id && doAreasOverlap(area, other));
|
|
2263
|
+
if (overlapping.length === 0) {
|
|
2264
|
+
// No overlap, skip grouping
|
|
2265
|
+
return;
|
|
2266
|
+
}
|
|
2267
|
+
// Create group with this area and all overlapping
|
|
2268
|
+
const groupAreas = [area, ...overlapping];
|
|
2269
|
+
groupAreas.forEach((a) => processed.add(a.id));
|
|
2270
|
+
// Placeholder - will be resolved later
|
|
2271
|
+
groups.push({
|
|
2272
|
+
areas: groupAreas,
|
|
2273
|
+
winner: area,
|
|
2274
|
+
hidden: [],
|
|
2275
|
+
});
|
|
2276
|
+
});
|
|
2277
|
+
return groups;
|
|
2206
2278
|
}
|
|
2207
2279
|
/**
|
|
2208
2280
|
* Resolve a single overlap group to find the winner
|
|
@@ -2686,1357 +2758,160 @@ const constrainToViewport = (candidate, options) => {
|
|
|
2686
2758
|
const getScrollOffset = (visualRef) => {
|
|
2687
2759
|
if (!visualRef?.current)
|
|
2688
2760
|
return;
|
|
2689
|
-
return {
|
|
2690
|
-
top: visualRef.current.scrollTop,
|
|
2691
|
-
left: visualRef.current.scrollLeft,
|
|
2692
|
-
};
|
|
2693
|
-
};
|
|
2694
|
-
/**
|
|
2695
|
-
* Create adjusted container rect for absolute positioning
|
|
2696
|
-
* - With scroll: represents visible area in container coordinates
|
|
2697
|
-
* - Without scroll: represents full container in container coordinates
|
|
2698
|
-
*/
|
|
2699
|
-
const createAdjustedContainerRect = (options) => {
|
|
2700
|
-
const { containerElm, scale, isAbsolute, visualRef } = options;
|
|
2701
|
-
const containerRect = containerElm.getBoundingClientRect();
|
|
2702
|
-
const scrollOffset = getScrollOffset(visualRef);
|
|
2703
|
-
// No scale = fixed positioning, use raw rect
|
|
2704
|
-
if (!scale)
|
|
2705
|
-
return containerRect;
|
|
2706
|
-
const scaledWidth = containerRect.width / scale;
|
|
2707
|
-
const scaledHeight = containerRect.height / scale;
|
|
2708
|
-
// Absolute positioning with scroll offset
|
|
2709
|
-
if (isAbsolute && scrollOffset) {
|
|
2710
|
-
return {
|
|
2711
|
-
...containerRect,
|
|
2712
|
-
top: scrollOffset.top,
|
|
2713
|
-
left: scrollOffset.left,
|
|
2714
|
-
right: scrollOffset.left + scaledWidth,
|
|
2715
|
-
bottom: scrollOffset.top + scaledHeight,
|
|
2716
|
-
width: scaledWidth,
|
|
2717
|
-
height: scaledHeight,
|
|
2718
|
-
};
|
|
2719
|
-
}
|
|
2720
|
-
// Absolute positioning without scroll
|
|
2721
|
-
return {
|
|
2722
|
-
...containerRect,
|
|
2723
|
-
top: 0,
|
|
2724
|
-
left: 0,
|
|
2725
|
-
right: scaledWidth,
|
|
2726
|
-
width: scaledWidth,
|
|
2727
|
-
bottom: scaledHeight,
|
|
2728
|
-
height: scaledHeight,
|
|
2729
|
-
};
|
|
2730
|
-
};
|
|
2731
|
-
const calcCalloutPosition = (options) => {
|
|
2732
|
-
const { targetElm, calloutElm, setPosition, positionMode, widthScale, visualRef } = options;
|
|
2733
|
-
const offset = options.offset ?? CALLOUT_OFFSET;
|
|
2734
|
-
const alignment = options.alignment ?? CALLOUT_ALIGNMENT;
|
|
2735
|
-
const padding = CALLOUT_PADDING;
|
|
2736
|
-
const arrowSize = CALLOUT_ARROW_SIZE;
|
|
2737
|
-
return () => {
|
|
2738
|
-
const isAbsolute = positionMode === 'absolute';
|
|
2739
|
-
const scale = isAbsolute ? widthScale : 1;
|
|
2740
|
-
// Determine container element based on positioning mode
|
|
2741
|
-
// - Absolute: portal container (parent of callout)
|
|
2742
|
-
// - Fixed: visual container (scrollable area)
|
|
2743
|
-
const containerElm = isAbsolute ? calloutElm.parentElement : visualRef?.current;
|
|
2744
|
-
if (!containerElm)
|
|
2745
|
-
return;
|
|
2746
|
-
const viewport = getContainerViewport(containerElm);
|
|
2747
|
-
const visualViewport = getVisualDomViewport(visualRef?.current, scale);
|
|
2748
|
-
const rectDimensions = getElementDimensions({ targetElm, calloutElm, scale, containerElm });
|
|
2749
|
-
const containerRect = createAdjustedContainerRect({ containerElm, scale, isAbsolute, visualRef });
|
|
2750
|
-
const options = {
|
|
2751
|
-
rectDimensions,
|
|
2752
|
-
viewport,
|
|
2753
|
-
visualViewport,
|
|
2754
|
-
alignment,
|
|
2755
|
-
offset,
|
|
2756
|
-
padding,
|
|
2757
|
-
arrowSize,
|
|
2758
|
-
containerRect,
|
|
2759
|
-
widthScale,
|
|
2760
|
-
};
|
|
2761
|
-
const candidates = generateAllCandidates(options);
|
|
2762
|
-
const candidate = selectBestPosition(candidates);
|
|
2763
|
-
// Constrain to viewport/container bounds
|
|
2764
|
-
const constrainedCandidate = constrainToViewport(candidate, options);
|
|
2765
|
-
// Final callout position
|
|
2766
|
-
const finalPosition = {
|
|
2767
|
-
top: constrainedCandidate.top,
|
|
2768
|
-
left: constrainedCandidate.left,
|
|
2769
|
-
placement: candidate.placement,
|
|
2770
|
-
horizontalAlign: candidate.horizontalAlign,
|
|
2771
|
-
};
|
|
2772
|
-
setPosition(finalPosition);
|
|
2773
|
-
};
|
|
2774
|
-
};
|
|
2775
|
-
const calcCalloutPositionAbsolute = (props) => {
|
|
2776
|
-
const { widthScale, calloutElm, containerElm, element, setPosition } = props;
|
|
2777
|
-
const mousePosition = element?.mousePosition;
|
|
2778
|
-
if (!mousePosition)
|
|
2779
|
-
return;
|
|
2780
|
-
const padding = props.padding ?? CALLOUT_PADDING;
|
|
2781
|
-
const arrowSize = props.arrowSize ?? CALLOUT_ARROW_SIZE;
|
|
2782
|
-
const rawCalloutRect = calloutElm.getBoundingClientRect();
|
|
2783
|
-
if (rawCalloutRect.width === 0 || rawCalloutRect.height === 0)
|
|
2784
|
-
return;
|
|
2785
|
-
const containerRect = containerElm.getBoundingClientRect();
|
|
2786
|
-
const mouseX = mousePosition.x;
|
|
2787
|
-
const mouseY = mousePosition.y;
|
|
2788
|
-
const targetRect = {
|
|
2789
|
-
top: mouseY,
|
|
2790
|
-
left: mouseX,
|
|
2791
|
-
right: mouseX + 1,
|
|
2792
|
-
bottom: mouseY + 1,
|
|
2793
|
-
width: 1,
|
|
2794
|
-
height: 1,
|
|
2795
|
-
x: mouseX,
|
|
2796
|
-
y: mouseY,
|
|
2797
|
-
toJSON: () => ({}),
|
|
2798
|
-
};
|
|
2799
|
-
const rectDimensions = {
|
|
2800
|
-
targetRect,
|
|
2801
|
-
calloutRect: getScaledCalloutRect(),
|
|
2802
|
-
targetAbsoluteRect: {
|
|
2803
|
-
top: element.top,
|
|
2804
|
-
left: element.left,
|
|
2805
|
-
},
|
|
2806
|
-
};
|
|
2807
|
-
const viewport = getContainerViewport(containerElm);
|
|
2808
|
-
const options = {
|
|
2809
|
-
rectDimensions,
|
|
2810
|
-
viewport,
|
|
2811
|
-
alignment: CALLOUT_ALIGNMENT,
|
|
2812
|
-
offset: CALLOUT_OFFSET,
|
|
2813
|
-
padding,
|
|
2814
|
-
arrowSize,
|
|
2815
|
-
containerRect,
|
|
2816
|
-
widthScale,
|
|
2817
|
-
};
|
|
2818
|
-
const candidates = generateAllCandidates(options);
|
|
2819
|
-
const bestPosition = selectBestPosition(candidates);
|
|
2820
|
-
const finalPosition = {
|
|
2821
|
-
top: bestPosition.top,
|
|
2822
|
-
left: bestPosition.left,
|
|
2823
|
-
placement: bestPosition.placement,
|
|
2824
|
-
horizontalAlign: bestPosition.horizontalAlign,
|
|
2825
|
-
};
|
|
2826
|
-
setPosition(finalPosition);
|
|
2827
|
-
// const styleBestPosition = getStyleFromCandidate(bestPosition, widthScale);
|
|
2828
|
-
// onChange(styleBestPosition);
|
|
2829
|
-
};
|
|
2830
|
-
|
|
2831
|
-
/**
|
|
2832
|
-
* Throttle a function using requestAnimationFrame
|
|
2833
|
-
* Ensures the callback is called at most once per animation frame
|
|
2834
|
-
*/
|
|
2835
|
-
const throttleRAF = (callback) => {
|
|
2836
|
-
let rafId = null;
|
|
2837
|
-
let latestArgs = null;
|
|
2838
|
-
const throttled = (...args) => {
|
|
2839
|
-
// Store the latest arguments
|
|
2840
|
-
latestArgs = args;
|
|
2841
|
-
// If already scheduled, do nothing
|
|
2842
|
-
if (rafId !== null)
|
|
2843
|
-
return;
|
|
2844
|
-
// Schedule the callback for the next animation frame
|
|
2845
|
-
rafId = requestAnimationFrame(() => {
|
|
2846
|
-
if (latestArgs !== null) {
|
|
2847
|
-
callback(...latestArgs);
|
|
2848
|
-
latestArgs = null;
|
|
2849
|
-
}
|
|
2850
|
-
rafId = null;
|
|
2851
|
-
});
|
|
2852
|
-
};
|
|
2853
|
-
// Add cancel method to clear pending RAF
|
|
2854
|
-
throttled.cancel = () => {
|
|
2855
|
-
if (rafId !== null) {
|
|
2856
|
-
cancelAnimationFrame(rafId);
|
|
2857
|
-
rafId = null;
|
|
2858
|
-
latestArgs = null;
|
|
2859
|
-
}
|
|
2860
|
-
};
|
|
2861
|
-
return throttled;
|
|
2862
|
-
};
|
|
2863
|
-
|
|
2864
|
-
/**
|
|
2865
|
-
* IframeHeightProcessor Types
|
|
2866
|
-
* Complete TypeScript types for iframe height processing system
|
|
2867
|
-
*/
|
|
2868
|
-
const TAGS_TO_PROCESS = [
|
|
2869
|
-
'div',
|
|
2870
|
-
'section',
|
|
2871
|
-
'iframe',
|
|
2872
|
-
'img',
|
|
2873
|
-
'a',
|
|
2874
|
-
'header',
|
|
2875
|
-
'main',
|
|
2876
|
-
'h1',
|
|
2877
|
-
'h2',
|
|
2878
|
-
'h3',
|
|
2879
|
-
'h4',
|
|
2880
|
-
'h5',
|
|
2881
|
-
'button',
|
|
2882
|
-
'ul',
|
|
2883
|
-
'svg',
|
|
2884
|
-
'li',
|
|
2885
|
-
'cart-drawer',
|
|
2886
|
-
'footer',
|
|
2887
|
-
'collapsible-content',
|
|
2888
|
-
'section-animate',
|
|
2889
|
-
'video',
|
|
2890
|
-
];
|
|
2891
|
-
const ANIMATION_CLASSES_TO_REMOVE = [
|
|
2892
|
-
'Image--zoomOut',
|
|
2893
|
-
'Image--fadeIn',
|
|
2894
|
-
'transition--blur-up',
|
|
2895
|
-
'header-fixed',
|
|
2896
|
-
'lazyframe',
|
|
2897
|
-
'lazyframe--loaded',
|
|
2898
|
-
'lazymap',
|
|
2899
|
-
'pplr',
|
|
2900
|
-
'site-header--stuck',
|
|
2901
|
-
'animate--slide-in',
|
|
2902
|
-
'animated-element',
|
|
2903
|
-
'lazyPicture__elem',
|
|
2904
|
-
'jdgm-hidden',
|
|
2905
|
-
'splide',
|
|
2906
|
-
'list-collections__slide-overlay',
|
|
2907
|
-
'onetrust-pc-dark-filter',
|
|
2908
|
-
'featured-blog__header-image',
|
|
2909
|
-
'overlay', // Special case: only remove if NOT js-search-overlay
|
|
2910
|
-
];
|
|
2911
|
-
const LAZY_LOAD_CLASSES_TO_REMOVE = [
|
|
2912
|
-
'lazyloaded',
|
|
2913
|
-
'lazyautosizes',
|
|
2914
|
-
'autosizes',
|
|
2915
|
-
'lazyload',
|
|
2916
|
-
'Image--fadeIn',
|
|
2917
|
-
'Image--lazyLoaded',
|
|
2918
|
-
'Image--lazyLoad',
|
|
2919
|
-
'lazypreload',
|
|
2920
|
-
'transition--fade-in',
|
|
2921
|
-
];
|
|
2922
|
-
const ELEMENTS_TO_SKIP_OPACITY = [
|
|
2923
|
-
'header-menu',
|
|
2924
|
-
'header-megamenu',
|
|
2925
|
-
'header-dropdown',
|
|
2926
|
-
'image-overlay',
|
|
2927
|
-
'product-item__bg__under',
|
|
2928
|
-
'transition-opacity',
|
|
2929
|
-
'mm-drawer-cart-filter',
|
|
2930
|
-
'transition',
|
|
2931
|
-
'navigation__container',
|
|
2932
|
-
'predictive__content-mobile',
|
|
2933
|
-
'multiply-mode__target',
|
|
2934
|
-
'product-card__img',
|
|
2935
|
-
'feature__description',
|
|
2936
|
-
'slider-item',
|
|
2937
|
-
'rtnu-header__mobile-nav',
|
|
2938
|
-
'splide__slide',
|
|
2939
|
-
'sub-menu',
|
|
2940
|
-
'swiper-slide',
|
|
2941
|
-
'dropdown-menu',
|
|
2942
|
-
'header__mask',
|
|
2943
|
-
'announcement_block',
|
|
2944
|
-
'bottom_sticky',
|
|
2945
|
-
'stickyatc',
|
|
2946
|
-
'g-header__menu',
|
|
2947
|
-
'mobile-menu',
|
|
2948
|
-
'jc-absolute',
|
|
2949
|
-
];
|
|
2950
|
-
|
|
2951
|
-
/**
|
|
2952
|
-
* IframeHeightProcessor Utils
|
|
2953
|
-
* Helper functions for iframe height processing
|
|
2954
|
-
*/
|
|
2955
|
-
/**
|
|
2956
|
-
* Get iframe element by ID
|
|
2957
|
-
*/
|
|
2958
|
-
function getIframeElement(iframeId) {
|
|
2959
|
-
return document.getElementById(iframeId);
|
|
2960
|
-
}
|
|
2961
|
-
/**
|
|
2962
|
-
* Get iframe content document
|
|
2963
|
-
*/
|
|
2964
|
-
function getIframeDocument(iframe) {
|
|
2965
|
-
try {
|
|
2966
|
-
return iframe.contentDocument || iframe.contentWindow?.document || null;
|
|
2967
|
-
}
|
|
2968
|
-
catch (error) {
|
|
2969
|
-
console.warn('Cannot access iframe document:', error);
|
|
2970
|
-
return null;
|
|
2971
|
-
}
|
|
2972
|
-
}
|
|
2973
|
-
/**
|
|
2974
|
-
* Get iframe content window
|
|
2975
|
-
*/
|
|
2976
|
-
function getIframeWindow(iframe) {
|
|
2977
|
-
try {
|
|
2978
|
-
return iframe.contentWindow;
|
|
2979
|
-
}
|
|
2980
|
-
catch (error) {
|
|
2981
|
-
console.warn('Cannot access iframe window:', error);
|
|
2982
|
-
return null;
|
|
2983
|
-
}
|
|
2984
|
-
}
|
|
2985
|
-
/**
|
|
2986
|
-
* Calculate iframe height from multiple sources
|
|
2987
|
-
* Returns the maximum height from body and documentElement
|
|
2988
|
-
*/
|
|
2989
|
-
function calculateIframeHeight(doc) {
|
|
2990
|
-
const body = doc.body;
|
|
2991
|
-
const docElement = doc.documentElement;
|
|
2992
|
-
const bodyOffsetHeight = body ? body.offsetHeight : 0;
|
|
2993
|
-
const bodyScrollHeight = body ? body.scrollHeight : 0;
|
|
2994
|
-
const documentElementOffsetHeight = docElement ? docElement.offsetHeight : 0;
|
|
2995
|
-
const documentElementClientHeight = docElement ? docElement.clientHeight : 0;
|
|
2996
|
-
const documentElementScrollHeight = docElement ? docElement.scrollHeight : 0;
|
|
2997
|
-
const calculatedHeight = Math.max(bodyOffsetHeight, bodyScrollHeight, documentElementOffsetHeight, documentElementClientHeight, documentElementScrollHeight);
|
|
2998
|
-
return {
|
|
2999
|
-
bodyOffsetHeight,
|
|
3000
|
-
bodyScrollHeight,
|
|
3001
|
-
documentElementOffsetHeight,
|
|
3002
|
-
documentElementClientHeight,
|
|
3003
|
-
documentElementScrollHeight,
|
|
3004
|
-
calculatedHeight,
|
|
3005
|
-
};
|
|
3006
|
-
}
|
|
3007
|
-
/**
|
|
3008
|
-
* Calculate iframe width
|
|
3009
|
-
*/
|
|
3010
|
-
function calculateIframeWidth(doc) {
|
|
3011
|
-
const body = doc.body;
|
|
3012
|
-
const docElement = doc.documentElement;
|
|
3013
|
-
return Math.max(body ? body.offsetWidth : 0, body ? body.scrollWidth : 0, docElement ? docElement.offsetWidth : 0, docElement ? docElement.clientWidth : 0, docElement ? docElement.scrollWidth : 0);
|
|
3014
|
-
}
|
|
3015
|
-
/**
|
|
3016
|
-
* Check if element is a fixed drawer
|
|
3017
|
-
*/
|
|
3018
|
-
function isFixedDrawer(element) {
|
|
3019
|
-
if (!element.classList.contains('drawer__content')) {
|
|
3020
|
-
return false;
|
|
3021
|
-
}
|
|
3022
|
-
const style = window.getComputedStyle(element);
|
|
3023
|
-
return (style.getPropertyValue('position') === 'fixed' &&
|
|
3024
|
-
style.getPropertyValue('top') === '0px' &&
|
|
3025
|
-
style.getPropertyValue('left') === '0px');
|
|
3026
|
-
}
|
|
3027
|
-
/**
|
|
3028
|
-
* Check if element is an image element (img, background-image, or data-bgset)
|
|
3029
|
-
*/
|
|
3030
|
-
function isImageElement(element) {
|
|
3031
|
-
if (element.tagName.toLowerCase() === 'img') {
|
|
3032
|
-
return true;
|
|
3033
|
-
}
|
|
3034
|
-
const computedStyle = window.getComputedStyle(element);
|
|
3035
|
-
const bgImage = computedStyle.getPropertyValue('background-image');
|
|
3036
|
-
if (bgImage && /url\(.+?\)/.test(bgImage)) {
|
|
3037
|
-
return true;
|
|
3038
|
-
}
|
|
3039
|
-
if (element.getAttribute('data-bgset')) {
|
|
3040
|
-
return true;
|
|
3041
|
-
}
|
|
3042
|
-
return false;
|
|
3043
|
-
}
|
|
3044
|
-
/**
|
|
3045
|
-
* Convert height to viewport units if applicable
|
|
3046
|
-
*/
|
|
3047
|
-
function convertToViewportHeight(heightPx, viewportHeight, threshold = 60) {
|
|
3048
|
-
if (heightPx >= viewportHeight) {
|
|
3049
|
-
return '100vh';
|
|
3050
|
-
}
|
|
3051
|
-
const percentage = (heightPx / viewportHeight) * 100;
|
|
3052
|
-
if (percentage > threshold) {
|
|
3053
|
-
return `${Math.round(percentage)}vh`;
|
|
3054
|
-
}
|
|
3055
|
-
return null;
|
|
3056
|
-
}
|
|
3057
|
-
/**
|
|
3058
|
-
* Parse srcset string and get appropriate image URL based on width
|
|
3059
|
-
*/
|
|
3060
|
-
function getImageURLFromSrcSet(srcset, targetWidth) {
|
|
3061
|
-
if (srcset.startsWith('data:image')) {
|
|
3062
|
-
return '';
|
|
3063
|
-
}
|
|
3064
|
-
const sources = srcset.split(',').filter((s) => !!s);
|
|
3065
|
-
for (const source of sources) {
|
|
3066
|
-
const parts = source
|
|
3067
|
-
.trim()
|
|
3068
|
-
.split(' ')
|
|
3069
|
-
.filter((p) => !!p);
|
|
3070
|
-
const url = parts[0];
|
|
3071
|
-
const descriptor = parts[1];
|
|
3072
|
-
if (descriptor) {
|
|
3073
|
-
const width = parseInt(descriptor.slice(0, -1), 10);
|
|
3074
|
-
if (targetWidth <= width) {
|
|
3075
|
-
return url;
|
|
3076
|
-
}
|
|
3077
|
-
}
|
|
3078
|
-
}
|
|
3079
|
-
// Return last source as fallback
|
|
3080
|
-
const lastSource = sources[sources.length - 1].trim();
|
|
3081
|
-
const parts = lastSource.split(' ');
|
|
3082
|
-
if (parts.length > 3) {
|
|
3083
|
-
throw new Error('Invalid src URL in srcset');
|
|
3084
|
-
}
|
|
3085
|
-
return parts[0];
|
|
3086
|
-
}
|
|
3087
|
-
/**
|
|
3088
|
-
* Get background image URL from data-bgset attribute
|
|
3089
|
-
*/
|
|
3090
|
-
function getBackgroundImageFromBgSet(bgset, targetWidth) {
|
|
3091
|
-
const sources = bgset.split(',');
|
|
3092
|
-
for (const source of sources) {
|
|
3093
|
-
const parts = source.trim().split(' ');
|
|
3094
|
-
if (parts.length >= 3) {
|
|
3095
|
-
const url = parts[0];
|
|
3096
|
-
const width = parseInt(parts[1], 10);
|
|
3097
|
-
if (targetWidth < width) {
|
|
3098
|
-
return url;
|
|
3099
|
-
}
|
|
3100
|
-
}
|
|
3101
|
-
}
|
|
3102
|
-
return null;
|
|
3103
|
-
}
|
|
3104
|
-
/**
|
|
3105
|
-
* Replace placeholder in image URL (e.g., {width}, {height}, %7Bwidth%7D)
|
|
3106
|
-
*/
|
|
3107
|
-
function replaceImagePlaceholder(url, placeholder, value) {
|
|
3108
|
-
const patterns = [
|
|
3109
|
-
new RegExp(`\\{${placeholder}\\}`, 'g'),
|
|
3110
|
-
new RegExp(`%7B${placeholder}%7D`, 'gi'),
|
|
3111
|
-
];
|
|
3112
|
-
let result = url;
|
|
3113
|
-
for (const pattern of patterns) {
|
|
3114
|
-
result = result.replace(pattern, String(value));
|
|
3115
|
-
}
|
|
3116
|
-
return result;
|
|
3117
|
-
}
|
|
3118
|
-
/**
|
|
3119
|
-
* Get computed height attributes object
|
|
3120
|
-
*/
|
|
3121
|
-
function getComputedHeightAttributes(element, computedStyle, windowHeight, windowWidth) {
|
|
3122
|
-
return {
|
|
3123
|
-
actualHeight: computedStyle.height,
|
|
3124
|
-
actualWidth: computedStyle.width,
|
|
3125
|
-
actualMaxHeight: computedStyle.maxHeight,
|
|
3126
|
-
actualMaxWidth: computedStyle.maxWidth,
|
|
3127
|
-
actualMinHeight: computedStyle.minHeight,
|
|
3128
|
-
actualMinWidth: computedStyle.minWidth,
|
|
3129
|
-
windowHeight: String(windowHeight),
|
|
3130
|
-
windowWidth: String(windowWidth),
|
|
3131
|
-
elementScrollHeight: String(element.scrollHeight),
|
|
3132
|
-
};
|
|
3133
|
-
}
|
|
3134
|
-
/**
|
|
3135
|
-
* Set computed height attributes on element
|
|
3136
|
-
*/
|
|
3137
|
-
function setComputedHeightAttributes(element, attributes) {
|
|
3138
|
-
Object.entries(attributes).forEach(([key, value]) => {
|
|
3139
|
-
if (value !== undefined) {
|
|
3140
|
-
element.setAttribute(key, value);
|
|
3141
|
-
}
|
|
3142
|
-
});
|
|
3143
|
-
}
|
|
3144
|
-
/**
|
|
3145
|
-
* Remove all height-related attributes
|
|
3146
|
-
*/
|
|
3147
|
-
function removeHeightAttributes(element) {
|
|
3148
|
-
const attrs = [
|
|
3149
|
-
'actualHeight',
|
|
3150
|
-
'actualWidth',
|
|
3151
|
-
'actualMaxHeight',
|
|
3152
|
-
'actualMaxWidth',
|
|
3153
|
-
'actualMinHeight',
|
|
3154
|
-
'actualMinWidth',
|
|
3155
|
-
'windowHeight',
|
|
3156
|
-
'windowWidth',
|
|
3157
|
-
'elementScrollHeight',
|
|
3158
|
-
'viewportHeight',
|
|
3159
|
-
'viewportMinHeight',
|
|
3160
|
-
'viewportWidth',
|
|
3161
|
-
];
|
|
3162
|
-
attrs.forEach((attr) => element.removeAttribute(attr));
|
|
3163
|
-
}
|
|
3164
|
-
/**
|
|
3165
|
-
* Log with optional debug flag
|
|
3166
|
-
*/
|
|
3167
|
-
function log(message, data, debug = false) {
|
|
3168
|
-
if (debug || (typeof window !== 'undefined' && window.debugMode)) {
|
|
3169
|
-
if (data !== undefined) {
|
|
3170
|
-
console.log(`[IframeHeightProcessor] ${message}`, data);
|
|
3171
|
-
}
|
|
3172
|
-
else {
|
|
3173
|
-
console.log(`[IframeHeightProcessor] ${message}`);
|
|
3174
|
-
}
|
|
3175
|
-
}
|
|
3176
|
-
}
|
|
3177
|
-
/**
|
|
3178
|
-
* Check if element should skip opacity setting
|
|
3179
|
-
*/
|
|
3180
|
-
function shouldSkipOpacitySetting(element, classList) {
|
|
3181
|
-
const rect = element.getBoundingClientRect();
|
|
3182
|
-
// Skip if element is in top 300px
|
|
3183
|
-
if (rect.top < 300) {
|
|
3184
|
-
return true;
|
|
3185
|
-
}
|
|
3186
|
-
// Skip empty divs
|
|
3187
|
-
if (element.tagName.toLowerCase() === 'div' && element.childElementCount === 0) {
|
|
3188
|
-
return true;
|
|
3189
|
-
}
|
|
3190
|
-
// Skip if has specific classes
|
|
3191
|
-
return classList.some((cls) => element.classList.contains(cls));
|
|
3192
|
-
}
|
|
3193
|
-
|
|
3194
|
-
/**
|
|
3195
|
-
* IframeHeightProcessor
|
|
3196
|
-
* Core class for processing iframe heights, capturing computed styles, and fixing layout issues
|
|
3197
|
-
*/
|
|
3198
|
-
class IframeHeightProcessor {
|
|
3199
|
-
config;
|
|
3200
|
-
iframe = null;
|
|
3201
|
-
iframeDoc = null;
|
|
3202
|
-
iframeWindow = null;
|
|
3203
|
-
initialStyles = [];
|
|
3204
|
-
lastKnownHeight = 0;
|
|
3205
|
-
constructor(config) {
|
|
3206
|
-
this.config = {
|
|
3207
|
-
defaultHeight: 800,
|
|
3208
|
-
debug: false,
|
|
3209
|
-
selectedScreenshotData: null,
|
|
3210
|
-
isCompatibleWithInteractiveMode: true,
|
|
3211
|
-
isRunningInInteractiveMode: false,
|
|
3212
|
-
...config,
|
|
3213
|
-
};
|
|
3214
|
-
this.initialize();
|
|
3215
|
-
}
|
|
3216
|
-
/**
|
|
3217
|
-
* Initialize processor - get iframe references
|
|
3218
|
-
*/
|
|
3219
|
-
initialize() {
|
|
3220
|
-
this.iframe = getIframeElement(this.config.iframeId);
|
|
3221
|
-
if (!this.iframe) {
|
|
3222
|
-
throw new Error(`Iframe with ID "${this.config.iframeId}" not found`);
|
|
3223
|
-
}
|
|
3224
|
-
this.iframeDoc = getIframeDocument(this.iframe);
|
|
3225
|
-
this.iframeWindow = getIframeWindow(this.iframe);
|
|
3226
|
-
if (!this.iframeDoc || !this.iframeWindow) {
|
|
3227
|
-
throw new Error('Cannot access iframe document or window');
|
|
3228
|
-
}
|
|
3229
|
-
log('Initialized', { iframeId: this.config.iframeId }, this.config.debug);
|
|
3230
|
-
}
|
|
3231
|
-
/**
|
|
3232
|
-
* Get current iframe height
|
|
3233
|
-
*/
|
|
3234
|
-
getIframeHeight() {
|
|
3235
|
-
if (!this.iframeDoc) {
|
|
3236
|
-
return 0;
|
|
3237
|
-
}
|
|
3238
|
-
const metrics = calculateIframeHeight(this.iframeDoc);
|
|
3239
|
-
return metrics.calculatedHeight;
|
|
3240
|
-
}
|
|
3241
|
-
/**
|
|
3242
|
-
* Get current iframe width
|
|
3243
|
-
*/
|
|
3244
|
-
getIframeWidth() {
|
|
3245
|
-
if (!this.iframeDoc) {
|
|
3246
|
-
return this.config.iframeWidth;
|
|
3247
|
-
}
|
|
3248
|
-
return calculateIframeWidth(this.iframeDoc);
|
|
3249
|
-
}
|
|
3250
|
-
/**
|
|
3251
|
-
* Get iframe document height (alternative method)
|
|
3252
|
-
*/
|
|
3253
|
-
getIframeDocumentHeight() {
|
|
3254
|
-
if (!this.iframe)
|
|
3255
|
-
return 0;
|
|
3256
|
-
const doc = this.iframe.contentWindow?.document;
|
|
3257
|
-
if (!doc)
|
|
3258
|
-
return 0;
|
|
3259
|
-
const { body, documentElement } = doc;
|
|
3260
|
-
const heights = [
|
|
3261
|
-
body?.scrollHeight ?? 0,
|
|
3262
|
-
body?.offsetHeight ?? 0,
|
|
3263
|
-
documentElement?.scrollHeight ?? 0,
|
|
3264
|
-
documentElement?.offsetHeight ?? 0,
|
|
3265
|
-
documentElement?.clientHeight ?? 0,
|
|
3266
|
-
];
|
|
3267
|
-
return Math.max(...heights, 0);
|
|
3268
|
-
}
|
|
3269
|
-
/**
|
|
3270
|
-
* MAIN PIPELINE: Process iframe height
|
|
3271
|
-
* This is the main entry point that runs the full pipeline
|
|
3272
|
-
*/
|
|
3273
|
-
async processIframeHeight() {
|
|
3274
|
-
log('Starting iframe height processing pipeline...', null, this.config.debug);
|
|
3275
|
-
try {
|
|
3276
|
-
// Step 1: Capture computed heights
|
|
3277
|
-
this.captureComputedHeight();
|
|
3278
|
-
// Step 2: Clean up DOM
|
|
3279
|
-
this.cleanUpDOM();
|
|
3280
|
-
// Step 3: Fix heights
|
|
3281
|
-
this.fixHeights();
|
|
3282
|
-
// Step 4: Screenshot fixes (if height > default)
|
|
3283
|
-
const currentHeight = this.getIframeHeight();
|
|
3284
|
-
if (currentHeight > this.config.defaultHeight) {
|
|
3285
|
-
this.hideElementsIfLargeModal();
|
|
3286
|
-
}
|
|
3287
|
-
this.findScrollableElements();
|
|
3288
|
-
this.correctImageSrcs();
|
|
3289
|
-
this.correctHeightForCertainClasses();
|
|
3290
|
-
// Step 5: Track height
|
|
3291
|
-
this.lastKnownHeight = this.getIframeHeight();
|
|
3292
|
-
log('Iframe height processing completed', { height: this.lastKnownHeight }, this.config.debug);
|
|
3293
|
-
}
|
|
3294
|
-
catch (error) {
|
|
3295
|
-
console.error('[IframeHeightProcessor] Error processing iframe height:', error);
|
|
3296
|
-
throw error;
|
|
3297
|
-
}
|
|
3298
|
-
}
|
|
3299
|
-
/**
|
|
3300
|
-
* STEP 1: Capture Computed Heights
|
|
3301
|
-
* Saves all computed styles to element attributes
|
|
3302
|
-
*/
|
|
3303
|
-
captureComputedHeight() {
|
|
3304
|
-
if (!this.iframeDoc)
|
|
3305
|
-
return;
|
|
3306
|
-
log('Capturing computed heights...', null, this.config.debug);
|
|
3307
|
-
const body = this.iframeDoc.body;
|
|
3308
|
-
// Remove hidden elements
|
|
3309
|
-
body.querySelectorAll('.heatmap-com__hidden-element').forEach((el) => {
|
|
3310
|
-
el.classList.remove('heatmap-com__hidden-element');
|
|
3311
|
-
});
|
|
3312
|
-
// Hide GDPR overlay
|
|
3313
|
-
const gdprOverlay = body.querySelector('#gdpr-blocking-page-overlay');
|
|
3314
|
-
if (gdprOverlay) {
|
|
3315
|
-
gdprOverlay.style.display = 'none';
|
|
3316
|
-
}
|
|
3317
|
-
// Hide popup forms (if not in screenshot mode)
|
|
3318
|
-
if (!this.config.selectedScreenshotData) {
|
|
3319
|
-
const popups = body.querySelectorAll('[aria-label="POPUP Form"], [data-section-id="popup"]');
|
|
3320
|
-
popups.forEach((popup) => {
|
|
3321
|
-
const parent = popup.parentElement;
|
|
3322
|
-
if (parent) {
|
|
3323
|
-
parent.style.setProperty('display', 'none', 'important');
|
|
3324
|
-
}
|
|
3325
|
-
});
|
|
3326
|
-
}
|
|
3327
|
-
// Remove media-transparent class
|
|
3328
|
-
body.querySelectorAll('.media--transparent').forEach((el) => {
|
|
3329
|
-
el.classList.remove('media--transparent');
|
|
3330
|
-
});
|
|
3331
|
-
// Process each tag type
|
|
3332
|
-
TAGS_TO_PROCESS.forEach((tag) => {
|
|
3333
|
-
this.captureComputedHeightForTag(tag);
|
|
3334
|
-
});
|
|
3335
|
-
// Special fixes
|
|
3336
|
-
this.applySwiperSlideWidthFix();
|
|
3337
|
-
this.applyCustomBlocksFix();
|
|
3338
|
-
this.applyParallaxContainerFix();
|
|
3339
|
-
this.applyHeaderPositionFix();
|
|
3340
|
-
log('Computed heights captured', null, this.config.debug);
|
|
3341
|
-
}
|
|
3342
|
-
/**
|
|
3343
|
-
* Capture computed height for a specific tag
|
|
3344
|
-
*/
|
|
3345
|
-
captureComputedHeightForTag(tagName) {
|
|
3346
|
-
if (!this.iframeDoc)
|
|
3347
|
-
return;
|
|
3348
|
-
const elements = this.iframeDoc.querySelectorAll(tagName);
|
|
3349
|
-
const viewportHeight = this.config.defaultHeight;
|
|
3350
|
-
elements.forEach((element) => {
|
|
3351
|
-
const el = element;
|
|
3352
|
-
const computedStyle = window.getComputedStyle(el);
|
|
3353
|
-
// Force important padding if > 10px
|
|
3354
|
-
const paddingTop = parseInt(computedStyle.getPropertyValue('padding-top'), 10) || 0;
|
|
3355
|
-
const paddingBottom = parseInt(computedStyle.getPropertyValue('padding-bottom'), 10) || 0;
|
|
3356
|
-
if (paddingTop > 10) {
|
|
3357
|
-
el.style.setProperty('padding-top', `${paddingTop}px`, 'important');
|
|
3358
|
-
}
|
|
3359
|
-
if (paddingBottom > 10) {
|
|
3360
|
-
el.style.setProperty('padding-bottom', `${paddingBottom}px`, 'important');
|
|
3361
|
-
}
|
|
3362
|
-
// Remove old attributes
|
|
3363
|
-
removeHeightAttributes(el);
|
|
3364
|
-
// Get computed values
|
|
3365
|
-
const attrs = getComputedHeightAttributes(el, computedStyle, viewportHeight, this.config.iframeWidth);
|
|
3366
|
-
// Convert heights to viewport units if applicable
|
|
3367
|
-
const heightPx = parseFloat(computedStyle.height);
|
|
3368
|
-
if (!isNaN(heightPx)) {
|
|
3369
|
-
const vhHeight = convertToViewportHeight(heightPx, viewportHeight);
|
|
3370
|
-
if (vhHeight) {
|
|
3371
|
-
attrs.viewportHeight = vhHeight;
|
|
3372
|
-
}
|
|
3373
|
-
}
|
|
3374
|
-
const minHeightPx = parseFloat(computedStyle.minHeight);
|
|
3375
|
-
if (!isNaN(minHeightPx)) {
|
|
3376
|
-
const vhMinHeight = convertToViewportHeight(minHeightPx, viewportHeight);
|
|
3377
|
-
if (vhMinHeight) {
|
|
3378
|
-
attrs.viewportMinHeight = vhMinHeight;
|
|
3379
|
-
}
|
|
3380
|
-
}
|
|
3381
|
-
const widthPx = parseInt(computedStyle.width, 10);
|
|
3382
|
-
if (widthPx === this.config.iframeWidth) {
|
|
3383
|
-
attrs.viewportWidth = '100vw';
|
|
3384
|
-
}
|
|
3385
|
-
// Set all attributes
|
|
3386
|
-
setComputedHeightAttributes(el, attrs);
|
|
3387
|
-
// SVG special handling
|
|
3388
|
-
if (tagName.toLowerCase() === 'svg') {
|
|
3389
|
-
if (el.classList.contains('decor-svg') || el.parentElement?.classList.contains('decor')) {
|
|
3390
|
-
el.style.setProperty('width', `${computedStyle.width}`, 'important');
|
|
3391
|
-
el.style.setProperty('height', `${computedStyle.height}`, 'important');
|
|
3392
|
-
el.style.setProperty('transform', 'none', 'important');
|
|
3393
|
-
}
|
|
3394
|
-
}
|
|
3395
|
-
});
|
|
3396
|
-
}
|
|
3397
|
-
/**
|
|
3398
|
-
* STEP 2: Clean Up DOM
|
|
3399
|
-
*/
|
|
3400
|
-
cleanUpDOM() {
|
|
3401
|
-
log('Cleaning up DOM...', null, this.config.debug);
|
|
3402
|
-
this.fixImages();
|
|
3403
|
-
}
|
|
3404
|
-
/**
|
|
3405
|
-
* Fix lazy-loaded images
|
|
3406
|
-
*/
|
|
3407
|
-
fixImages() {
|
|
3408
|
-
if (!this.iframeDoc)
|
|
3409
|
-
return;
|
|
3410
|
-
const images = this.iframeDoc.querySelectorAll('img');
|
|
3411
|
-
const iframeContentDoc = this.iframeDoc;
|
|
3412
|
-
images.forEach((img) => {
|
|
3413
|
-
// Fix srcset from data attributes
|
|
3414
|
-
const srcset = img.getAttribute('srcset');
|
|
3415
|
-
const dataSrcset = img.getAttribute('data-srcset');
|
|
3416
|
-
const dataLazySrcset = img.getAttribute('data-lazy-srcset');
|
|
3417
|
-
const dataLazySrc = img.getAttribute('data-lazy-src');
|
|
3418
|
-
if ((srcset && srcset.startsWith('data:image') && dataSrcset) || (!srcset && dataSrcset)) {
|
|
3419
|
-
img.setAttribute('srcset', dataSrcset);
|
|
3420
|
-
}
|
|
3421
|
-
else if (!srcset && dataLazySrcset) {
|
|
3422
|
-
img.setAttribute('srcset', dataLazySrcset);
|
|
3423
|
-
}
|
|
3424
|
-
else if (!srcset && dataLazySrc) {
|
|
3425
|
-
img.setAttribute('srcset', dataLazySrc);
|
|
3426
|
-
}
|
|
3427
|
-
// Set opacity
|
|
3428
|
-
const hasBlurTransition = img.classList.contains('transition--blur-up');
|
|
3429
|
-
if (img.parentNode === iframeContentDoc.body) {
|
|
3430
|
-
img.style.display = 'none';
|
|
3431
|
-
}
|
|
3432
|
-
else {
|
|
3433
|
-
img.style.opacity = '1';
|
|
3434
|
-
if (hasBlurTransition) {
|
|
3435
|
-
img.style.setProperty('display', 'block', 'important');
|
|
3436
|
-
}
|
|
3437
|
-
}
|
|
3438
|
-
// Get best image URL
|
|
3439
|
-
if (img.currentSrc || img.getAttribute('data-src')) {
|
|
3440
|
-
let bestSrc = img.currentSrc;
|
|
3441
|
-
if (img.getAttribute('data-src')) {
|
|
3442
|
-
bestSrc = img.getAttribute('data-src');
|
|
3443
|
-
}
|
|
3444
|
-
const imgSrcset = img.getAttribute('srcset');
|
|
3445
|
-
if (imgSrcset) {
|
|
3446
|
-
try {
|
|
3447
|
-
const urlFromSrcset = getImageURLFromSrcSet(imgSrcset, this.config.iframeWidth);
|
|
3448
|
-
bestSrc = urlFromSrcset.replace(/.*https:/, 'https:') || bestSrc;
|
|
3449
|
-
}
|
|
3450
|
-
catch {
|
|
3451
|
-
// Use current src as fallback
|
|
3452
|
-
}
|
|
3453
|
-
}
|
|
3454
|
-
// Remove lazy loading classes
|
|
3455
|
-
LAZY_LOAD_CLASSES_TO_REMOVE.forEach((cls) => {
|
|
3456
|
-
img.classList.remove(cls);
|
|
3457
|
-
});
|
|
3458
|
-
// Set src
|
|
3459
|
-
img.setAttribute('src', bestSrc);
|
|
3460
|
-
}
|
|
3461
|
-
});
|
|
3462
|
-
}
|
|
3463
|
-
/**
|
|
3464
|
-
* STEP 3: Fix Heights
|
|
3465
|
-
* Apply height fixes for all elements
|
|
3466
|
-
*/
|
|
3467
|
-
fixHeights() {
|
|
3468
|
-
log('Fixing heights...', null, this.config.debug);
|
|
3469
|
-
const result = {
|
|
3470
|
-
processed: 0,
|
|
3471
|
-
fixed: 0,
|
|
3472
|
-
errors: 0,
|
|
3473
|
-
skipped: 0,
|
|
3474
|
-
};
|
|
3475
|
-
TAGS_TO_PROCESS.forEach((tag) => {
|
|
3476
|
-
const tagResult = this.fixActualHeight(tag);
|
|
3477
|
-
result.processed += tagResult.processed;
|
|
3478
|
-
result.fixed += tagResult.fixed;
|
|
3479
|
-
result.errors += tagResult.errors;
|
|
3480
|
-
result.skipped += tagResult.skipped;
|
|
3481
|
-
});
|
|
3482
|
-
log('Heights fixed', result, this.config.debug);
|
|
3483
|
-
return result;
|
|
3484
|
-
}
|
|
3485
|
-
/**
|
|
3486
|
-
* Fix actual height for specific tag
|
|
3487
|
-
*/
|
|
3488
|
-
fixActualHeight(tagName) {
|
|
3489
|
-
if (!this.iframeDoc) {
|
|
3490
|
-
return { processed: 0, fixed: 0, errors: 0, skipped: 0 };
|
|
3491
|
-
}
|
|
3492
|
-
const result = { processed: 0, fixed: 0, errors: 0, skipped: 0 };
|
|
3493
|
-
const elements = this.iframeDoc.querySelectorAll(tagName);
|
|
3494
|
-
elements.forEach((element) => {
|
|
3495
|
-
result.processed++;
|
|
3496
|
-
try {
|
|
3497
|
-
const el = element;
|
|
3498
|
-
const computedStyle = window.getComputedStyle(el);
|
|
3499
|
-
// Apply all element fixes
|
|
3500
|
-
this.fixElementOpacity(el, computedStyle);
|
|
3501
|
-
this.removeZeroHeightAttribute(el);
|
|
3502
|
-
this.fixFlexBasis(el, computedStyle);
|
|
3503
|
-
this.fixHiddenProductItem(el, computedStyle);
|
|
3504
|
-
this.removeAnimationClasses(el);
|
|
3505
|
-
this.fixImageOrBackground(el, tagName);
|
|
3506
|
-
this.fixAnimateOnScroll(el);
|
|
3507
|
-
this.fixViewportWidth(el);
|
|
3508
|
-
// HEIGHT FIXING LOGIC
|
|
3509
|
-
this.applyHeightFix(el);
|
|
3510
|
-
result.fixed++;
|
|
3511
|
-
}
|
|
3512
|
-
catch (error) {
|
|
3513
|
-
result.errors++;
|
|
3514
|
-
console.error(`Error fixing height for ${tagName}:`, error);
|
|
3515
|
-
}
|
|
3516
|
-
});
|
|
3517
|
-
return result;
|
|
3518
|
-
}
|
|
3519
|
-
/**
|
|
3520
|
-
* Set opacity = 1 if element is visible and not in skip list
|
|
3521
|
-
*/
|
|
3522
|
-
fixElementOpacity(el, computedStyle) {
|
|
3523
|
-
if (computedStyle.display !== 'none' && !shouldSkipOpacitySetting(el, ELEMENTS_TO_SKIP_OPACITY)) {
|
|
3524
|
-
el.style.opacity = '1';
|
|
3525
|
-
}
|
|
3526
|
-
}
|
|
3527
|
-
/**
|
|
3528
|
-
* Remove actualHeight='0px' attribute
|
|
3529
|
-
*/
|
|
3530
|
-
removeZeroHeightAttribute(el) {
|
|
3531
|
-
if (el.getAttribute('actualHeight') === '0px') {
|
|
3532
|
-
el.removeAttribute('actualHeight');
|
|
3533
|
-
}
|
|
3534
|
-
}
|
|
3535
|
-
/**
|
|
3536
|
-
* Fix flex-basis: 100% by converting to auto + width: 100%
|
|
3537
|
-
*/
|
|
3538
|
-
fixFlexBasis(el, computedStyle) {
|
|
3539
|
-
if (computedStyle.getPropertyValue('flex-basis') === '100%') {
|
|
3540
|
-
el.style.setProperty('flex-basis', 'auto');
|
|
3541
|
-
el.style.setProperty('width', '100%');
|
|
3542
|
-
}
|
|
3543
|
-
}
|
|
3544
|
-
/**
|
|
3545
|
-
* Fix ProductItem elements with opacity=1 but visibility=hidden
|
|
3546
|
-
*/
|
|
3547
|
-
fixHiddenProductItem(el, computedStyle) {
|
|
3548
|
-
if (computedStyle.opacity === '1' &&
|
|
3549
|
-
computedStyle.visibility === 'hidden' &&
|
|
3550
|
-
el.classList.toString().includes('ProductItem')) {
|
|
3551
|
-
el.style.visibility = 'visible';
|
|
3552
|
-
}
|
|
3553
|
-
}
|
|
3554
|
-
/**
|
|
3555
|
-
* Remove animation and lazy-load classes that prevent rendering
|
|
3556
|
-
*/
|
|
3557
|
-
removeAnimationClasses(el) {
|
|
3558
|
-
ANIMATION_CLASSES_TO_REMOVE.forEach((cls) => {
|
|
3559
|
-
if (el.classList.contains(cls)) {
|
|
3560
|
-
// Skip overlay with js-search-overlay
|
|
3561
|
-
if (cls === 'overlay' && el.classList.contains('js-search-overlay')) {
|
|
3562
|
-
return;
|
|
3563
|
-
}
|
|
3564
|
-
el.classList.remove(cls);
|
|
3565
|
-
}
|
|
3566
|
-
});
|
|
3567
|
-
}
|
|
3568
|
-
/**
|
|
3569
|
-
* Fix images or background images based on tag type
|
|
3570
|
-
*/
|
|
3571
|
-
fixImageOrBackground(el, tagName) {
|
|
3572
|
-
if (tagName.toLowerCase() === 'img') {
|
|
3573
|
-
this.fixImagePlaceholders(el);
|
|
3574
|
-
}
|
|
3575
|
-
else {
|
|
3576
|
-
this.setBackgroundImage(el);
|
|
3577
|
-
}
|
|
3578
|
-
}
|
|
3579
|
-
/**
|
|
3580
|
-
* Fix AOS (Animate On Scroll) elements - force visibility
|
|
3581
|
-
*/
|
|
3582
|
-
fixAnimateOnScroll(el) {
|
|
3583
|
-
if (el.getAttribute('data-aos')) {
|
|
3584
|
-
el.style.opacity = '1';
|
|
3585
|
-
el.style.visibility = 'visible';
|
|
3586
|
-
}
|
|
3587
|
-
}
|
|
3588
|
-
/**
|
|
3589
|
-
* Fix viewport width elements (100vw → 100%)
|
|
3590
|
-
*/
|
|
3591
|
-
fixViewportWidth(el) {
|
|
3592
|
-
if (el.getAttribute('viewportWidth') === '100vw') {
|
|
3593
|
-
el.style.width = '100%';
|
|
3594
|
-
}
|
|
3595
|
-
}
|
|
3596
|
-
/**
|
|
3597
|
-
* Apply height fix logic to element
|
|
3598
|
-
* ⚠️ CRITICAL: This logic must match line 13258-13306 exactly
|
|
3599
|
-
*/
|
|
3600
|
-
applyHeightFix(el) {
|
|
3601
|
-
// Check if element is fixed drawer (skip height fixes)
|
|
3602
|
-
if (isFixedDrawer(el)) {
|
|
3603
|
-
el.setAttribute('heightReset', 'true');
|
|
3604
|
-
return;
|
|
3605
|
-
}
|
|
3606
|
-
const actualHeight = el.getAttribute('actualHeight');
|
|
3607
|
-
const hasStyleAttr = el.getAttribute('style');
|
|
3608
|
-
const isImage = isImageElement(el);
|
|
3609
|
-
const actualHeightNum = parseInt(actualHeight || '0', 10);
|
|
3610
|
-
// ===== START OF NESTED IF-ELSE CHAIN (line 13259-13306) =====
|
|
3611
|
-
// Case 1: actualHeight = '100%'
|
|
3612
|
-
if (actualHeight === '100%') {
|
|
3613
|
-
console.log(`🚀 🐥 ~ IframeHeightProcessor ~ applyHeightFix ~ actualHeight:`, actualHeight);
|
|
3614
|
-
el.style.setProperty('height', 'max-content', 'important');
|
|
3615
|
-
el.setAttribute('heightReset', 'true');
|
|
3616
|
-
}
|
|
3617
|
-
// Case 2: Image elements with height 50-800px
|
|
3618
|
-
else if (isImage && actualHeightNum >= 50 && actualHeightNum <= 800) {
|
|
3619
|
-
el.style.setProperty('height', actualHeight, 'important');
|
|
3620
|
-
el.setAttribute('heightReset', 'true');
|
|
3621
|
-
}
|
|
3622
|
-
// Case 3: Has inline height style and actualHeight > 800px
|
|
3623
|
-
else if (hasStyleAttr &&
|
|
3624
|
-
hasStyleAttr.includes('height') &&
|
|
3625
|
-
hasStyleAttr.includes('height') && // Double check like original (line 13270-13271)
|
|
3626
|
-
parseFloat(actualHeight || '0') > 800 &&
|
|
3627
|
-
!el.getAttribute('src-changed')) {
|
|
3628
|
-
el.style.setProperty('height', 'max-content', 'important');
|
|
3629
|
-
el.setAttribute('heightReset', 'true');
|
|
3630
|
-
}
|
|
3631
|
-
// Case 4: All other cases (nested logic)
|
|
3632
|
-
else {
|
|
3633
|
-
// 4A: Check actualHeight !== 'none'
|
|
3634
|
-
if (actualHeight && actualHeight !== 'none') {
|
|
3635
|
-
// 4A1: height = '0px' → reset
|
|
3636
|
-
if (actualHeight === '0px') {
|
|
3637
|
-
el.style.height = '';
|
|
3638
|
-
el.style.minHeight = 'auto';
|
|
3639
|
-
}
|
|
3640
|
-
// 4A2: Mobile (deviceType=3): 700-900px
|
|
3641
|
-
else if (actualHeightNum >= 700 && actualHeightNum <= 900 && this.config.deviceType === 3) {
|
|
3642
|
-
const maxHeight = Math.max(el.offsetHeight, el.scrollHeight, actualHeightNum);
|
|
3643
|
-
el.style.setProperty('height', `${maxHeight}px`, 'important');
|
|
3644
|
-
}
|
|
3645
|
-
// 4A3: Desktop/Tablet: 700-1400px
|
|
3646
|
-
else if (actualHeightNum >= 700 && actualHeightNum <= 1400 && this.config.deviceType !== 3) {
|
|
3647
|
-
const maxHeight = Math.max(el.offsetHeight, el.scrollHeight, actualHeightNum);
|
|
3648
|
-
el.style.setProperty('height', `${maxHeight}px`, 'important');
|
|
3649
|
-
}
|
|
3650
|
-
}
|
|
3651
|
-
// 4B: Fix maxHeight (line 13294-13297)
|
|
3652
|
-
const actualMaxHeight = el.getAttribute('actualMaxHeight');
|
|
3653
|
-
if (actualMaxHeight && actualMaxHeight !== 'none') {
|
|
3654
|
-
if (actualHeight === '0px') {
|
|
3655
|
-
el.style.height = '';
|
|
3656
|
-
el.style.maxHeight = 'auto';
|
|
3657
|
-
}
|
|
3658
|
-
else {
|
|
3659
|
-
// BUG FIX #1: Original code has typo - sets 'max-height' to 'max-height' string!
|
|
3660
|
-
// This is intentional in original code (line 13297)
|
|
3661
|
-
el.style.setProperty('max-height', 'max-height', 'important');
|
|
3662
|
-
}
|
|
3663
|
-
}
|
|
3664
|
-
// 4C: Fix minHeight if computedStyle.minHeight exists (line 13298-13300)
|
|
3665
|
-
const computedStyle = window.getComputedStyle(el);
|
|
3666
|
-
const actualMinHeight = el.getAttribute('actualMinHeight');
|
|
3667
|
-
if (computedStyle.minHeight && parseFloat(actualMinHeight || '0') >= 100) {
|
|
3668
|
-
el.style.setProperty('min-height', actualMinHeight, 'important');
|
|
3669
|
-
}
|
|
3670
|
-
}
|
|
3671
|
-
// ===== OUTSIDE THE MAIN IF-ELSE (line 13302-13305) =====
|
|
3672
|
-
// These ALWAYS run regardless of above conditions
|
|
3673
|
-
// Always set min-height if >= 100
|
|
3674
|
-
const actualMinHeight = el.getAttribute('actualMinHeight');
|
|
3675
|
-
if (parseFloat(actualMinHeight || '0') >= 100) {
|
|
3676
|
-
el.style.setProperty('min-height', actualMinHeight, 'important');
|
|
3677
|
-
}
|
|
3678
|
-
// Always set min-height if actualMinHeight = '100%'
|
|
3679
|
-
if (actualMinHeight === '100%') {
|
|
3680
|
-
el.style.setProperty('min-height', actualHeight, 'important');
|
|
3681
|
-
}
|
|
3682
|
-
}
|
|
3683
|
-
/**
|
|
3684
|
-
* Fix image placeholders ({width}, {height}, %7Bwidth%7D, etc.)
|
|
3685
|
-
*/
|
|
3686
|
-
fixImagePlaceholders(img) {
|
|
3687
|
-
const src = img.src;
|
|
3688
|
-
const dataWidths = img.getAttribute('data-widths');
|
|
3689
|
-
if (!dataWidths) {
|
|
3690
|
-
return;
|
|
3691
|
-
}
|
|
3692
|
-
let widths;
|
|
3693
|
-
try {
|
|
3694
|
-
widths = JSON.parse(dataWidths);
|
|
3695
|
-
}
|
|
3696
|
-
catch {
|
|
3697
|
-
return;
|
|
3698
|
-
}
|
|
3699
|
-
const maxWidth = widths[widths.length - 1] || 2000;
|
|
3700
|
-
let newSrc = src;
|
|
3701
|
-
// Replace {width} or %7Bwidth%7D
|
|
3702
|
-
newSrc = replaceImagePlaceholder(newSrc, 'width', maxWidth);
|
|
3703
|
-
// Replace {height} or %7Bheight%7D
|
|
3704
|
-
newSrc = replaceImagePlaceholder(newSrc, 'height', maxWidth);
|
|
3705
|
-
if (newSrc !== src) {
|
|
3706
|
-
img.setAttribute('src', newSrc);
|
|
3707
|
-
}
|
|
3708
|
-
}
|
|
3709
|
-
/**
|
|
3710
|
-
* Set background image from data-bgset
|
|
3711
|
-
*/
|
|
3712
|
-
setBackgroundImage(el) {
|
|
3713
|
-
const bgset = el.getAttribute('data-bgset');
|
|
3714
|
-
if (!bgset)
|
|
3715
|
-
return;
|
|
3716
|
-
const url = getBackgroundImageFromBgSet(bgset, this.config.iframeWidth);
|
|
3717
|
-
if (url) {
|
|
3718
|
-
el.style.backgroundImage = `url(${url})`;
|
|
3719
|
-
}
|
|
3720
|
-
}
|
|
3721
|
-
/**
|
|
3722
|
-
* STEP 4: Hide large modals
|
|
3723
|
-
*/
|
|
3724
|
-
hideElementsIfLargeModal() {
|
|
3725
|
-
if (!this.iframeDoc || this.config.selectedScreenshotData) {
|
|
3726
|
-
return [];
|
|
3727
|
-
}
|
|
3728
|
-
log('Hiding large modals...', null, this.config.debug);
|
|
3729
|
-
const results = [];
|
|
3730
|
-
const body = this.iframeDoc.body;
|
|
3731
|
-
const allElements = Array.from(body.querySelectorAll('*'));
|
|
3732
|
-
allElements.forEach((el) => {
|
|
3733
|
-
const style = window.getComputedStyle(el);
|
|
3734
|
-
const opacity = parseFloat(style.getPropertyValue('opacity'));
|
|
3735
|
-
const visibility = style.getPropertyValue('visibility');
|
|
3736
|
-
const display = style.getPropertyValue('display');
|
|
3737
|
-
const zIndex = parseInt(style.getPropertyValue('z-index'), 10);
|
|
3738
|
-
const position = style.getPropertyValue('position');
|
|
3739
|
-
const isFixed = position === 'fixed';
|
|
3740
|
-
const isVisible = visibility !== 'hidden' && display !== 'none' && opacity > 0;
|
|
3741
|
-
const hasHighZIndex = zIndex > 0;
|
|
3742
|
-
if (isFixed && isVisible && hasHighZIndex) {
|
|
3743
|
-
const rect = el.getBoundingClientRect();
|
|
3744
|
-
const shouldHide = rect.height > this.config.defaultHeight;
|
|
3745
|
-
results.push({
|
|
3746
|
-
element: el,
|
|
3747
|
-
isModal: true,
|
|
3748
|
-
isFixed,
|
|
3749
|
-
zIndex,
|
|
3750
|
-
height: rect.height,
|
|
3751
|
-
shouldHide,
|
|
3752
|
-
});
|
|
3753
|
-
if (shouldHide) {
|
|
3754
|
-
el.style.setProperty('display', 'none', 'important');
|
|
3755
|
-
}
|
|
3756
|
-
}
|
|
3757
|
-
});
|
|
3758
|
-
log('Large modals hidden', { count: results.filter((r) => r.shouldHide).length }, this.config.debug);
|
|
3759
|
-
return results;
|
|
3760
|
-
}
|
|
3761
|
-
/**
|
|
3762
|
-
* Find scrollable elements and hide children outside viewport
|
|
3763
|
-
*/
|
|
3764
|
-
findScrollableElements() {
|
|
3765
|
-
if (!this.iframeDoc)
|
|
3766
|
-
return [];
|
|
3767
|
-
log('Finding scrollable elements...', null, this.config.debug);
|
|
3768
|
-
const results = [];
|
|
3769
|
-
const allElements = Array.from(this.iframeDoc.body.querySelectorAll('*'));
|
|
3770
|
-
allElements.forEach((el) => {
|
|
3771
|
-
const style = window.getComputedStyle(el);
|
|
3772
|
-
const overflowY = style.overflowY;
|
|
3773
|
-
if (overflowY === 'scroll' || overflowY === 'auto') {
|
|
3774
|
-
const rect = el.getBoundingClientRect();
|
|
3775
|
-
const isInViewport = rect.top >= 0 && rect.bottom <= this.config.defaultHeight;
|
|
3776
|
-
if (isInViewport && el.offsetHeight <= 800) {
|
|
3777
|
-
let hasHiddenChildren = false;
|
|
3778
|
-
Array.from(el.children).forEach((child) => {
|
|
3779
|
-
const childEl = child;
|
|
3780
|
-
const childRect = childEl.getBoundingClientRect();
|
|
3781
|
-
const parentRect = el.getBoundingClientRect();
|
|
3782
|
-
// Check if child is outside parent bounds
|
|
3783
|
-
const isOutside = childRect.top < parentRect.top ||
|
|
3784
|
-
childRect.bottom > parentRect.bottom ||
|
|
3785
|
-
childRect.left < parentRect.left ||
|
|
3786
|
-
childRect.right > parentRect.right;
|
|
3787
|
-
if (isOutside) {
|
|
3788
|
-
childEl.classList.add('heatmap-com__hidden-element');
|
|
3789
|
-
hasHiddenChildren = true;
|
|
3790
|
-
// Also hide descendants
|
|
3791
|
-
this.hideDescendants(childEl);
|
|
3792
|
-
}
|
|
3793
|
-
});
|
|
3794
|
-
results.push({
|
|
3795
|
-
element: el,
|
|
3796
|
-
overflowY,
|
|
3797
|
-
height: el.offsetHeight,
|
|
3798
|
-
scrollHeight: el.scrollHeight,
|
|
3799
|
-
hasHiddenChildren,
|
|
3800
|
-
});
|
|
3801
|
-
}
|
|
3802
|
-
}
|
|
3803
|
-
});
|
|
3804
|
-
log('Scrollable elements found', { count: results.length }, this.config.debug);
|
|
3805
|
-
return results;
|
|
3806
|
-
}
|
|
3807
|
-
/**
|
|
3808
|
-
* Hide all descendants of an element
|
|
3809
|
-
*/
|
|
3810
|
-
hideDescendants(element) {
|
|
3811
|
-
Array.from(element.querySelectorAll('*')).forEach((descendant) => {
|
|
3812
|
-
descendant.classList.add('heatmap-com__hidden-element');
|
|
3813
|
-
});
|
|
3814
|
-
}
|
|
3815
|
-
/**
|
|
3816
|
-
* Correct image sources (fix placeholders)
|
|
3817
|
-
*/
|
|
3818
|
-
correctImageSrcs() {
|
|
3819
|
-
if (!this.iframeDoc)
|
|
3820
|
-
return;
|
|
3821
|
-
log('Correcting image sources...', null, this.config.debug);
|
|
3822
|
-
const images = this.iframeDoc.querySelectorAll('img');
|
|
3823
|
-
images.forEach((img) => {
|
|
3824
|
-
const style = window.getComputedStyle(img);
|
|
3825
|
-
// Remove blur filter
|
|
3826
|
-
if (style.getPropertyValue('filter').includes('blur')) {
|
|
3827
|
-
img.style.filter = 'none';
|
|
3828
|
-
}
|
|
3829
|
-
// Fix width for full-width images
|
|
3830
|
-
const actualWidth = parseInt(img.getAttribute('actualwidth') || '0', 10);
|
|
3831
|
-
if (actualWidth >= this.config.iframeWidth - 2) {
|
|
3832
|
-
img.style.setProperty('width', img.getAttribute('actualwidth'));
|
|
3833
|
-
}
|
|
3834
|
-
// Fix URL placeholders
|
|
3835
|
-
this.fixImagePlaceholders(img);
|
|
3836
|
-
});
|
|
3837
|
-
}
|
|
3838
|
-
/**
|
|
3839
|
-
* Correct height for certain classes
|
|
3840
|
-
*/
|
|
3841
|
-
correctHeightForCertainClasses() {
|
|
3842
|
-
if (!this.iframeDoc)
|
|
3843
|
-
return;
|
|
3844
|
-
log('Correcting specific class heights...', null, this.config.debug);
|
|
3845
|
-
// Fix navPages-container
|
|
3846
|
-
const navPages = this.iframeDoc.querySelectorAll('.navPages-container');
|
|
3847
|
-
navPages.forEach((el) => {
|
|
3848
|
-
el.style.height = '';
|
|
3849
|
-
});
|
|
3850
|
-
}
|
|
3851
|
-
/**
|
|
3852
|
-
* Monitor divs in iframe (save initial styles)
|
|
3853
|
-
*/
|
|
3854
|
-
monitorDivsInIframe() {
|
|
3855
|
-
if (!this.iframeDoc)
|
|
3856
|
-
return;
|
|
3857
|
-
log('Monitoring divs in iframe...', null, this.config.debug);
|
|
3858
|
-
const divs = Array.from(this.iframeDoc.querySelectorAll('div')).filter((div) => div.children.length > 0);
|
|
3859
|
-
this.initialStyles = [];
|
|
3860
|
-
divs.forEach((div) => {
|
|
3861
|
-
if (!shouldSkipOpacitySetting(div, ELEMENTS_TO_SKIP_OPACITY)) {
|
|
3862
|
-
const style = window.getComputedStyle(div);
|
|
3863
|
-
this.initialStyles.push({
|
|
3864
|
-
element: div,
|
|
3865
|
-
opacity: style.getPropertyValue('opacity'),
|
|
3866
|
-
display: style.getPropertyValue('display'),
|
|
3867
|
-
});
|
|
3868
|
-
}
|
|
3869
|
-
});
|
|
3870
|
-
log('Monitoring started', { count: this.initialStyles.length }, this.config.debug);
|
|
3871
|
-
}
|
|
3872
|
-
/**
|
|
3873
|
-
* Check height difference and trigger reprocessing if needed
|
|
3874
|
-
*/
|
|
3875
|
-
checkHeightDifference() {
|
|
3876
|
-
const currentHeight = this.getIframeHeight();
|
|
3877
|
-
if (currentHeight === 0) {
|
|
3878
|
-
const fallbackHeight = this.getIframeDocumentHeight();
|
|
3879
|
-
if (fallbackHeight > 0) {
|
|
3880
|
-
log(`getIframeHeight returned 0 - using DOM fallback: ${fallbackHeight}px`, null, this.config.debug);
|
|
3881
|
-
return false;
|
|
3882
|
-
}
|
|
3883
|
-
log('Unable to determine iframe height', null, this.config.debug);
|
|
3884
|
-
return false;
|
|
3885
|
-
}
|
|
3886
|
-
const diff = Math.abs(currentHeight - this.lastKnownHeight);
|
|
3887
|
-
if (diff <= 50) {
|
|
3888
|
-
return false; // No significant change
|
|
3889
|
-
}
|
|
3890
|
-
if (currentHeight > this.lastKnownHeight) {
|
|
3891
|
-
log(`Height increased: ${this.lastKnownHeight}px → ${currentHeight}px (diff: ${diff}px)`, null, this.config.debug);
|
|
3892
|
-
this.lastKnownHeight = currentHeight;
|
|
3893
|
-
return true;
|
|
3894
|
-
}
|
|
3895
|
-
return false;
|
|
3896
|
-
}
|
|
3897
|
-
/**
|
|
3898
|
-
* Get last known height
|
|
3899
|
-
*/
|
|
3900
|
-
getLastKnownHeight() {
|
|
3901
|
-
return this.lastKnownHeight;
|
|
3902
|
-
}
|
|
3903
|
-
/**
|
|
3904
|
-
* Set last known height
|
|
3905
|
-
*/
|
|
3906
|
-
setLastKnownHeight(height) {
|
|
3907
|
-
this.lastKnownHeight = height;
|
|
3908
|
-
}
|
|
3909
|
-
// ========== SPECIAL FIXES ==========
|
|
3910
|
-
applySwiperSlideWidthFix() {
|
|
3911
|
-
if (!this.iframeDoc)
|
|
3912
|
-
return;
|
|
3913
|
-
const swiperSlides = this.iframeDoc.querySelectorAll('.swiper-slide.swiper-slide-active');
|
|
3914
|
-
swiperSlides.forEach((slide) => {
|
|
3915
|
-
const el = slide;
|
|
3916
|
-
const style = el.getAttribute('style');
|
|
3917
|
-
if (style && style.includes('width')) {
|
|
3918
|
-
const computedWidth = window.getComputedStyle(el).width;
|
|
3919
|
-
const actualWidth = el.getAttribute('actualWidth');
|
|
3920
|
-
if (computedWidth === actualWidth) {
|
|
3921
|
-
el.style.setProperty('width', '100%');
|
|
3922
|
-
}
|
|
3923
|
-
}
|
|
3924
|
-
});
|
|
3925
|
-
}
|
|
3926
|
-
applyCustomBlocksFix() {
|
|
3927
|
-
if (!this.iframeDoc)
|
|
3928
|
-
return;
|
|
3929
|
-
if (this.config.iframeWidth > 450)
|
|
3930
|
-
return; // Only for mobile
|
|
3931
|
-
const customBlocks = this.iframeDoc.querySelectorAll('.Our-Picks .custom-blk ul li');
|
|
3932
|
-
customBlocks.forEach((block) => {
|
|
3933
|
-
const el = block;
|
|
3934
|
-
el.style.setProperty('width', 'calc(50% - 80px)', 'important');
|
|
3935
|
-
el.querySelectorAll('img').forEach((img) => {
|
|
3936
|
-
img.style.setProperty('height', 'max-content', 'important');
|
|
3937
|
-
img.removeAttribute('actualHeight');
|
|
3938
|
-
});
|
|
3939
|
-
});
|
|
3940
|
-
}
|
|
3941
|
-
applyParallaxContainerFix() {
|
|
3942
|
-
if (!this.iframeDoc)
|
|
3943
|
-
return;
|
|
3944
|
-
const containers = this.iframeDoc.querySelectorAll('.background-media-text__container');
|
|
3945
|
-
containers.forEach((container) => {
|
|
3946
|
-
const firstChild = container.firstElementChild;
|
|
3947
|
-
if (firstChild && firstChild.classList.contains('parallax-container')) {
|
|
3948
|
-
container.removeAttribute('actualHeight');
|
|
3949
|
-
}
|
|
3950
|
-
});
|
|
3951
|
-
}
|
|
3952
|
-
applyHeaderPositionFix() {
|
|
3953
|
-
if (!this.iframeDoc)
|
|
3954
|
-
return;
|
|
3955
|
-
const header = this.iframeDoc.querySelector('.shopify-section.shopify-section-group-header-group.shopify-section--header');
|
|
3956
|
-
if (!header)
|
|
3957
|
-
return;
|
|
3958
|
-
const actualHeight = parseInt(header.getAttribute('actualHeight') || '0', 10);
|
|
3959
|
-
if (actualHeight === 52 || actualHeight === 62) {
|
|
3960
|
-
header.style.setProperty('top', '40px', 'important');
|
|
3961
|
-
}
|
|
3962
|
-
}
|
|
3963
|
-
/**
|
|
3964
|
-
* Destroy processor and clean up
|
|
3965
|
-
*/
|
|
3966
|
-
destroy() {
|
|
3967
|
-
this.initialStyles = [];
|
|
3968
|
-
this.iframe = null;
|
|
3969
|
-
this.iframeDoc = null;
|
|
3970
|
-
this.iframeWindow = null;
|
|
3971
|
-
log('Processor destroyed', null, this.config.debug);
|
|
3972
|
-
}
|
|
3973
|
-
}
|
|
3974
|
-
|
|
3975
|
-
/**
|
|
3976
|
-
* Draw a backdrop overlay on canvas with a cutout for the active element
|
|
3977
|
-
* This creates a "spotlight" effect highlighting the active element
|
|
3978
|
-
*/
|
|
3979
|
-
const drawBackdropWithCutout = (options) => {
|
|
3980
|
-
const { canvas, activeRect, backdropColor = '#000000', backdropOpacity = 0.5, cutoutExpansion = 0 } = options;
|
|
3981
|
-
const ctx = canvas.getContext('2d');
|
|
3982
|
-
if (!ctx)
|
|
3983
|
-
return;
|
|
3984
|
-
const { width: canvasWidth, height: canvasHeight } = canvas;
|
|
3985
|
-
// Apply expansion to the cutout rect
|
|
3986
|
-
const top = Math.max(0, activeRect.top - cutoutExpansion);
|
|
3987
|
-
const left = Math.max(0, activeRect.left - cutoutExpansion);
|
|
3988
|
-
const width = Math.min(canvasWidth - left, activeRect.width + cutoutExpansion * 2);
|
|
3989
|
-
const height = Math.min(canvasHeight - top, activeRect.height + cutoutExpansion * 2);
|
|
3990
|
-
// Clear previous drawing
|
|
3991
|
-
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
|
|
3992
|
-
// Set backdrop style
|
|
3993
|
-
ctx.fillStyle = backdropColor;
|
|
3994
|
-
ctx.globalAlpha = backdropOpacity;
|
|
3995
|
-
// Draw backdrop in 4 rectangles around the active element
|
|
3996
|
-
// This creates a cutout effect
|
|
3997
|
-
// Top rectangle (above active element)
|
|
3998
|
-
if (top > 0) {
|
|
3999
|
-
ctx.fillRect(0, 0, canvasWidth, top);
|
|
4000
|
-
}
|
|
4001
|
-
// Bottom rectangle (below active element)
|
|
4002
|
-
const bottomY = top + height;
|
|
4003
|
-
if (bottomY < canvasHeight) {
|
|
4004
|
-
ctx.fillRect(0, bottomY, canvasWidth, canvasHeight - bottomY);
|
|
4005
|
-
}
|
|
4006
|
-
// Left rectangle (left of active element)
|
|
4007
|
-
if (left > 0) {
|
|
4008
|
-
ctx.fillRect(0, top, left, height);
|
|
4009
|
-
}
|
|
4010
|
-
// Right rectangle (right of active element)
|
|
4011
|
-
const rightX = left + width;
|
|
4012
|
-
if (rightX < canvasWidth) {
|
|
4013
|
-
ctx.fillRect(rightX, top, canvasWidth - rightX, height);
|
|
4014
|
-
}
|
|
4015
|
-
// Reset alpha
|
|
4016
|
-
ctx.globalAlpha = 1.0;
|
|
2761
|
+
return {
|
|
2762
|
+
top: visualRef.current.scrollTop,
|
|
2763
|
+
left: visualRef.current.scrollLeft,
|
|
2764
|
+
};
|
|
4017
2765
|
};
|
|
4018
2766
|
/**
|
|
4019
|
-
*
|
|
2767
|
+
* Create adjusted container rect for absolute positioning
|
|
2768
|
+
* - With scroll: represents visible area in container coordinates
|
|
2769
|
+
* - Without scroll: represents full container in container coordinates
|
|
4020
2770
|
*/
|
|
4021
|
-
const
|
|
4022
|
-
const
|
|
4023
|
-
|
|
2771
|
+
const createAdjustedContainerRect = (options) => {
|
|
2772
|
+
const { containerElm, scale, isAbsolute, visualRef } = options;
|
|
2773
|
+
const containerRect = containerElm.getBoundingClientRect();
|
|
2774
|
+
const scrollOffset = getScrollOffset(visualRef);
|
|
2775
|
+
// No scale = fixed positioning, use raw rect
|
|
2776
|
+
if (!scale)
|
|
2777
|
+
return containerRect;
|
|
2778
|
+
const scaledWidth = containerRect.width / scale;
|
|
2779
|
+
const scaledHeight = containerRect.height / scale;
|
|
2780
|
+
// Absolute positioning with scroll offset
|
|
2781
|
+
if (isAbsolute && scrollOffset) {
|
|
2782
|
+
return {
|
|
2783
|
+
...containerRect,
|
|
2784
|
+
top: scrollOffset.top,
|
|
2785
|
+
left: scrollOffset.left,
|
|
2786
|
+
right: scrollOffset.left + scaledWidth,
|
|
2787
|
+
bottom: scrollOffset.top + scaledHeight,
|
|
2788
|
+
width: scaledWidth,
|
|
2789
|
+
height: scaledHeight,
|
|
2790
|
+
};
|
|
2791
|
+
}
|
|
2792
|
+
// Absolute positioning without scroll
|
|
2793
|
+
return {
|
|
2794
|
+
...containerRect,
|
|
2795
|
+
top: 0,
|
|
2796
|
+
left: 0,
|
|
2797
|
+
right: scaledWidth,
|
|
2798
|
+
width: scaledWidth,
|
|
2799
|
+
bottom: scaledHeight,
|
|
2800
|
+
height: scaledHeight,
|
|
2801
|
+
};
|
|
2802
|
+
};
|
|
2803
|
+
const calcCalloutPosition = (options) => {
|
|
2804
|
+
const { targetElm, calloutElm, setPosition, positionMode, widthScale, visualRef } = options;
|
|
2805
|
+
const offset = options.offset ?? CALLOUT_OFFSET;
|
|
2806
|
+
const alignment = options.alignment ?? CALLOUT_ALIGNMENT;
|
|
2807
|
+
const padding = CALLOUT_PADDING;
|
|
2808
|
+
const arrowSize = CALLOUT_ARROW_SIZE;
|
|
2809
|
+
return () => {
|
|
2810
|
+
const isAbsolute = positionMode === 'absolute';
|
|
2811
|
+
const scale = isAbsolute ? widthScale : 1;
|
|
2812
|
+
// Determine container element based on positioning mode
|
|
2813
|
+
// - Absolute: portal container (parent of callout)
|
|
2814
|
+
// - Fixed: visual container (scrollable area)
|
|
2815
|
+
const containerElm = isAbsolute ? calloutElm.parentElement : visualRef?.current;
|
|
2816
|
+
if (!containerElm)
|
|
2817
|
+
return;
|
|
2818
|
+
const viewport = getContainerViewport(containerElm);
|
|
2819
|
+
const visualViewport = getVisualDomViewport(visualRef?.current, scale);
|
|
2820
|
+
const rectDimensions = getElementDimensions({ targetElm, calloutElm, scale, containerElm });
|
|
2821
|
+
const containerRect = createAdjustedContainerRect({ containerElm, scale, isAbsolute, visualRef });
|
|
2822
|
+
const options = {
|
|
2823
|
+
rectDimensions,
|
|
2824
|
+
viewport,
|
|
2825
|
+
visualViewport,
|
|
2826
|
+
alignment,
|
|
2827
|
+
offset,
|
|
2828
|
+
padding,
|
|
2829
|
+
arrowSize,
|
|
2830
|
+
containerRect,
|
|
2831
|
+
widthScale,
|
|
2832
|
+
};
|
|
2833
|
+
const candidates = generateAllCandidates(options);
|
|
2834
|
+
const candidate = selectBestPosition(candidates);
|
|
2835
|
+
// Constrain to viewport/container bounds
|
|
2836
|
+
const constrainedCandidate = constrainToViewport(candidate, options);
|
|
2837
|
+
// Final callout position
|
|
2838
|
+
const finalPosition = {
|
|
2839
|
+
top: constrainedCandidate.top,
|
|
2840
|
+
left: constrainedCandidate.left,
|
|
2841
|
+
placement: candidate.placement,
|
|
2842
|
+
horizontalAlign: candidate.horizontalAlign,
|
|
2843
|
+
};
|
|
2844
|
+
setPosition(finalPosition);
|
|
2845
|
+
};
|
|
2846
|
+
};
|
|
2847
|
+
const calcCalloutPositionAbsolute = (props) => {
|
|
2848
|
+
const { widthScale, calloutElm, containerElm, element, setPosition } = props;
|
|
2849
|
+
const mousePosition = element?.mousePosition;
|
|
2850
|
+
if (!mousePosition)
|
|
4024
2851
|
return;
|
|
4025
|
-
|
|
2852
|
+
const padding = props.padding ?? CALLOUT_PADDING;
|
|
2853
|
+
const arrowSize = props.arrowSize ?? CALLOUT_ARROW_SIZE;
|
|
2854
|
+
const rawCalloutRect = calloutElm.getBoundingClientRect();
|
|
2855
|
+
if (rawCalloutRect.width === 0 || rawCalloutRect.height === 0)
|
|
2856
|
+
return;
|
|
2857
|
+
const containerRect = containerElm.getBoundingClientRect();
|
|
2858
|
+
const mouseX = mousePosition.x;
|
|
2859
|
+
const mouseY = mousePosition.y;
|
|
2860
|
+
const targetRect = {
|
|
2861
|
+
top: mouseY,
|
|
2862
|
+
left: mouseX,
|
|
2863
|
+
right: mouseX + 1,
|
|
2864
|
+
bottom: mouseY + 1,
|
|
2865
|
+
width: 1,
|
|
2866
|
+
height: 1,
|
|
2867
|
+
x: mouseX,
|
|
2868
|
+
y: mouseY,
|
|
2869
|
+
toJSON: () => ({}),
|
|
2870
|
+
};
|
|
2871
|
+
const rectDimensions = {
|
|
2872
|
+
targetRect,
|
|
2873
|
+
calloutRect: getScaledCalloutRect(),
|
|
2874
|
+
targetAbsoluteRect: {
|
|
2875
|
+
top: element.top,
|
|
2876
|
+
left: element.left,
|
|
2877
|
+
},
|
|
2878
|
+
};
|
|
2879
|
+
const viewport = getContainerViewport(containerElm);
|
|
2880
|
+
const options = {
|
|
2881
|
+
rectDimensions,
|
|
2882
|
+
viewport,
|
|
2883
|
+
alignment: CALLOUT_ALIGNMENT,
|
|
2884
|
+
offset: CALLOUT_OFFSET,
|
|
2885
|
+
padding,
|
|
2886
|
+
arrowSize,
|
|
2887
|
+
containerRect,
|
|
2888
|
+
widthScale,
|
|
2889
|
+
};
|
|
2890
|
+
const candidates = generateAllCandidates(options);
|
|
2891
|
+
const bestPosition = selectBestPosition(candidates);
|
|
2892
|
+
const finalPosition = {
|
|
2893
|
+
top: bestPosition.top,
|
|
2894
|
+
left: bestPosition.left,
|
|
2895
|
+
placement: bestPosition.placement,
|
|
2896
|
+
horizontalAlign: bestPosition.horizontalAlign,
|
|
2897
|
+
};
|
|
2898
|
+
setPosition(finalPosition);
|
|
2899
|
+
// const styleBestPosition = getStyleFromCandidate(bestPosition, widthScale);
|
|
2900
|
+
// onChange(styleBestPosition);
|
|
4026
2901
|
};
|
|
4027
2902
|
|
|
4028
2903
|
function validateAreaCreation(dataInfo, hash, areas) {
|
|
4029
2904
|
if (!dataInfo?.clickMapMetrics || !dataInfo?.totalClicks) {
|
|
4030
|
-
logger$
|
|
2905
|
+
logger$9.warn('Cannot create area: missing heatmap data');
|
|
4031
2906
|
return false;
|
|
4032
2907
|
}
|
|
4033
2908
|
if (!hash) {
|
|
4034
|
-
logger$
|
|
2909
|
+
logger$9.warn('Cannot create area: missing hash');
|
|
4035
2910
|
return false;
|
|
4036
2911
|
}
|
|
4037
2912
|
const alreadyExists = areas.some((area) => area.hash === hash);
|
|
4038
2913
|
if (alreadyExists) {
|
|
4039
|
-
logger$
|
|
2914
|
+
logger$9.warn(`Area already exists for element: ${hash}`);
|
|
4040
2915
|
return false;
|
|
4041
2916
|
}
|
|
4042
2917
|
return true;
|
|
@@ -4049,14 +2924,14 @@ function identifyConflictingAreas(area) {
|
|
|
4049
2924
|
// Case 1: New area is a child of an existing area
|
|
4050
2925
|
if (area.parentNode) {
|
|
4051
2926
|
conflicts.parentId = area.parentNode.id;
|
|
4052
|
-
logger$
|
|
2927
|
+
logger$9.info(`New area "${area.selector}" is a child of existing area "${area.parentNode.selector}". Will remove parent.`);
|
|
4053
2928
|
}
|
|
4054
2929
|
// Case 2: New area is a parent of existing area(s)
|
|
4055
2930
|
if (area.childNodes.size > 0) {
|
|
4056
2931
|
area.childNodes.forEach((childArea) => {
|
|
4057
2932
|
conflicts.childrenIds.push(childArea.id);
|
|
4058
2933
|
});
|
|
4059
|
-
logger$
|
|
2934
|
+
logger$9.info(`New area "${area.selector}" is a parent of ${area.childNodes.size} existing area(s). Will remove children.`);
|
|
4060
2935
|
}
|
|
4061
2936
|
return conflicts;
|
|
4062
2937
|
}
|
|
@@ -4107,7 +2982,7 @@ function useAreaCreation(options = {}) {
|
|
|
4107
2982
|
}
|
|
4108
2983
|
}
|
|
4109
2984
|
catch (error) {
|
|
4110
|
-
logger$
|
|
2985
|
+
logger$9.error('Failed to create area:', error);
|
|
4111
2986
|
}
|
|
4112
2987
|
}, [dataInfo, areas, addArea, removeArea, removeClickArea, customShadowRoot, onAreaCreated]);
|
|
4113
2988
|
return {
|
|
@@ -4222,16 +3097,16 @@ function useAreaHydration(options) {
|
|
|
4222
3097
|
return;
|
|
4223
3098
|
if (!dataInfo)
|
|
4224
3099
|
return;
|
|
4225
|
-
logger$
|
|
3100
|
+
logger$9.info(`Hydrating ${clickAreas.length} persisted areas...`);
|
|
4226
3101
|
const hydratedAreas = hydrateAreas({ clickAreas, heatmapInfo: dataInfo, vizRef, shadowRoot });
|
|
4227
3102
|
if (!hydratedAreas?.length) {
|
|
4228
|
-
logger$
|
|
3103
|
+
logger$9.warn('No areas could be hydrated - all elements may have been removed from DOM');
|
|
4229
3104
|
return;
|
|
4230
3105
|
}
|
|
4231
3106
|
setIsInitializing(true);
|
|
4232
3107
|
buildAreaGraph(hydratedAreas);
|
|
4233
3108
|
setAreas(hydratedAreas);
|
|
4234
|
-
logger$
|
|
3109
|
+
logger$9.info(`Successfully hydrated ${hydratedAreas.length} areas`);
|
|
4235
3110
|
}, [dataInfo, vizRef, isInitializing, clickAreas]);
|
|
4236
3111
|
useEffect(() => {
|
|
4237
3112
|
if (!enabled)
|
|
@@ -4365,7 +3240,7 @@ function useAreaRectSync(options) {
|
|
|
4365
3240
|
area.rect.update(newRect);
|
|
4366
3241
|
}
|
|
4367
3242
|
catch (error) {
|
|
4368
|
-
logger$
|
|
3243
|
+
logger$9.error(`Failed to update rect for area ${area.id}:`, error);
|
|
4369
3244
|
}
|
|
4370
3245
|
});
|
|
4371
3246
|
buildAreaGraph(areas);
|
|
@@ -4509,7 +3384,7 @@ const useScrollmap = () => {
|
|
|
4509
3384
|
vizRef?.scrollmap?.(scrollmap);
|
|
4510
3385
|
}
|
|
4511
3386
|
catch (error) {
|
|
4512
|
-
logger$
|
|
3387
|
+
logger$9.error(`🚀 🐥 ~ useScrollmap ~ error:`, error);
|
|
4513
3388
|
}
|
|
4514
3389
|
}, [vizRef, scrollmap]);
|
|
4515
3390
|
return { start };
|
|
@@ -4904,303 +3779,49 @@ const convertViewportToIframeCoords = (clientX, clientY, iframeRect, scale) => {
|
|
|
4904
3779
|
let x = clientX - iframeRect.left;
|
|
4905
3780
|
let y = clientY - iframeRect.top;
|
|
4906
3781
|
if (scale !== 1) {
|
|
4907
|
-
x /= scale;
|
|
4908
|
-
y /= scale;
|
|
4909
|
-
}
|
|
4910
|
-
return { x, y };
|
|
4911
|
-
};
|
|
4912
|
-
const findTargetElement = (doc, x, y, heatmapInfo) => {
|
|
4913
|
-
const elementsAtPoint = getElementsAtPoint(doc, Math.round(x), Math.round(y), {
|
|
4914
|
-
filterFn: (element) => element.hasAttribute(HEATMAP_ELEMENT_ATTRIBUTE),
|
|
4915
|
-
ignoreCanvas: true,
|
|
4916
|
-
});
|
|
4917
|
-
let dataElement = null;
|
|
4918
|
-
for (let i = 0; i < elementsAtPoint.length; i++) {
|
|
4919
|
-
const element = elementsAtPoint[i];
|
|
4920
|
-
const elementHash = getElementHash(element) ?? '';
|
|
4921
|
-
const isExistElmInfo = heatmapInfo.clickMapMetrics?.[elementHash];
|
|
4922
|
-
if (elementHash && isExistElmInfo) {
|
|
4923
|
-
const boundingBox = getBoundingBox(element);
|
|
4924
|
-
if (boundingBox) {
|
|
4925
|
-
dataElement = element;
|
|
4926
|
-
break;
|
|
4927
|
-
}
|
|
4928
|
-
}
|
|
4929
|
-
}
|
|
4930
|
-
if (dataElement) {
|
|
4931
|
-
return dataElement;
|
|
4932
|
-
}
|
|
4933
|
-
let targetElement = getElementAtPoint(doc, x, y);
|
|
4934
|
-
if (!targetElement) {
|
|
4935
|
-
targetElement = doc.elementFromPoint(x, y);
|
|
4936
|
-
}
|
|
4937
|
-
return targetElement;
|
|
4938
|
-
};
|
|
4939
|
-
const isIframeReady = (iframeRef, heatmapInfo) => {
|
|
4940
|
-
return !!(iframeRef.current?.contentDocument && heatmapInfo?.clickMapMetrics);
|
|
4941
|
-
};
|
|
4942
|
-
const isValidElement = (element, heatmapInfo) => {
|
|
4943
|
-
if (!element)
|
|
4944
|
-
return false;
|
|
4945
|
-
const hash = getElementHash(element);
|
|
4946
|
-
if (!hash)
|
|
4947
|
-
return false;
|
|
4948
|
-
return !!heatmapInfo?.clickMapMetrics?.[hash];
|
|
4949
|
-
};
|
|
4950
|
-
|
|
4951
|
-
function useIframeHeightProcessor(options) {
|
|
4952
|
-
const { iframeRef, iframeId: providedIframeId, iframeWidth, deviceType, defaultHeight = 800, debug = false, autoProcess = true, watchHeightChanges = false, shouldProcess = true, autoApplyHeight = false, onHeightChange, onProcessComplete, onProcessError, onHeightApplied, ...rest } = options;
|
|
4953
|
-
const [isProcessing, setIsProcessing] = useState(false);
|
|
4954
|
-
const [error, setError] = useState(null);
|
|
4955
|
-
const processorRef = useRef(null);
|
|
4956
|
-
const heightCheckIntervalRef = useRef(null);
|
|
4957
|
-
const iframeId = providedIframeId || iframeRef?.current?.id;
|
|
4958
|
-
const applyHeight = useCallback((targetHeight) => {
|
|
4959
|
-
const iframe = iframeRef?.current;
|
|
4960
|
-
if (!iframe) {
|
|
4961
|
-
if (debug) {
|
|
4962
|
-
console.warn('[useIframeHeightProcessor] Cannot apply height - iframe ref not available');
|
|
4963
|
-
}
|
|
4964
|
-
return;
|
|
4965
|
-
}
|
|
4966
|
-
try {
|
|
4967
|
-
if (debug) {
|
|
4968
|
-
console.log(`[useIframeHeightProcessor] Applying height: ${targetHeight}px`);
|
|
4969
|
-
}
|
|
4970
|
-
// 1. Set iframe height
|
|
4971
|
-
iframe.style.height = `${targetHeight}px`;
|
|
4972
|
-
// 2. Set body overflow = auto
|
|
4973
|
-
const iframeDoc = iframe.contentWindow?.document;
|
|
4974
|
-
if (iframeDoc?.body)
|
|
4975
|
-
iframeDoc.body.style.overflow = 'auto';
|
|
4976
|
-
// 3. Set container heights
|
|
4977
|
-
// const heatmapContainer = document.getElementById('heatmapContainer');
|
|
4978
|
-
// if (heatmapContainer) {
|
|
4979
|
-
// heatmapContainer.style.height = `${targetHeight}px`;
|
|
4980
|
-
// }
|
|
4981
|
-
// const loadingOuter = document.querySelector('.hsrLoadingOuter');
|
|
4982
|
-
// if (loadingOuter instanceof HTMLElement) {
|
|
4983
|
-
// loadingOuter.style.height = `${targetHeight}px`;
|
|
4984
|
-
// }
|
|
4985
|
-
// 5. Callback
|
|
4986
|
-
onHeightApplied?.(targetHeight);
|
|
4987
|
-
if (debug) {
|
|
4988
|
-
console.log(`[useIframeHeightProcessor] Height applied successfully: ${targetHeight}px`);
|
|
4989
|
-
}
|
|
4990
|
-
}
|
|
4991
|
-
catch (err) {
|
|
4992
|
-
const applyError = err;
|
|
4993
|
-
console.error('[useIframeHeightProcessor] Error applying height:', applyError);
|
|
4994
|
-
setError(applyError);
|
|
4995
|
-
}
|
|
4996
|
-
}, [iframeRef, onHeightApplied, debug]);
|
|
4997
|
-
const initializeProcessor = useCallback(() => {
|
|
4998
|
-
if (!iframeId || !iframeWidth || !deviceType) {
|
|
4999
|
-
return null;
|
|
5000
|
-
}
|
|
5001
|
-
try {
|
|
5002
|
-
const processor = new IframeHeightProcessor({
|
|
5003
|
-
iframeId,
|
|
5004
|
-
iframeWidth,
|
|
5005
|
-
deviceType,
|
|
5006
|
-
defaultHeight,
|
|
5007
|
-
debug,
|
|
5008
|
-
...rest,
|
|
5009
|
-
});
|
|
5010
|
-
return processor;
|
|
5011
|
-
}
|
|
5012
|
-
catch (err) {
|
|
5013
|
-
const error = err;
|
|
5014
|
-
setError(error);
|
|
5015
|
-
if (onProcessError) {
|
|
5016
|
-
onProcessError(error);
|
|
5017
|
-
}
|
|
5018
|
-
return null;
|
|
5019
|
-
}
|
|
5020
|
-
}, [iframeId, iframeWidth, deviceType, defaultHeight, debug, rest, onProcessError]);
|
|
5021
|
-
const waitForIframeReady = useCallback(async (maxWaitTime = 5000) => {
|
|
5022
|
-
const iframe = iframeRef?.current;
|
|
5023
|
-
if (!iframe) {
|
|
5024
|
-
if (debug) {
|
|
5025
|
-
console.warn('[useIframeHeightProcessor] Iframe ref not available');
|
|
5026
|
-
}
|
|
5027
|
-
return false;
|
|
5028
|
-
}
|
|
5029
|
-
const startTime = Date.now();
|
|
5030
|
-
return new Promise((resolve) => {
|
|
5031
|
-
const check = () => {
|
|
5032
|
-
const elapsed = Date.now() - startTime;
|
|
5033
|
-
if (elapsed > maxWaitTime) {
|
|
5034
|
-
if (debug) {
|
|
5035
|
-
console.error('[useIframeHeightProcessor] Timeout waiting for iframe ready');
|
|
5036
|
-
}
|
|
5037
|
-
resolve(false);
|
|
5038
|
-
return;
|
|
5039
|
-
}
|
|
5040
|
-
const hasContentWindow = !!iframe.contentWindow;
|
|
5041
|
-
const hasDocument = !!iframe.contentWindow?.document;
|
|
5042
|
-
const url = iframe.contentWindow?.document?.URL;
|
|
5043
|
-
const isReady = hasContentWindow && hasDocument && url && url !== 'about:blank';
|
|
5044
|
-
if (isReady) {
|
|
5045
|
-
if (debug) {
|
|
5046
|
-
console.log(`[useIframeHeightProcessor] Iframe ready after ${elapsed}ms`);
|
|
5047
|
-
}
|
|
5048
|
-
resolve(true);
|
|
5049
|
-
}
|
|
5050
|
-
else {
|
|
5051
|
-
if (debug && elapsed % 500 === 0) {
|
|
5052
|
-
console.log(`[useIframeHeightProcessor] Waiting for iframe (${elapsed}ms) - contentWindow: ${hasContentWindow}, document: ${hasDocument}, URL: ${url || 'none'}`);
|
|
5053
|
-
}
|
|
5054
|
-
setTimeout(check, 50);
|
|
5055
|
-
}
|
|
5056
|
-
};
|
|
5057
|
-
check();
|
|
5058
|
-
});
|
|
5059
|
-
}, [iframeRef, debug]);
|
|
5060
|
-
const process = useCallback(async () => {
|
|
5061
|
-
if (!shouldProcess) {
|
|
5062
|
-
if (debug) {
|
|
5063
|
-
console.log('[useIframeHeightProcessor] Skipping process - shouldProcess is false');
|
|
5064
|
-
}
|
|
5065
|
-
return;
|
|
5066
|
-
}
|
|
5067
|
-
// Wait for iframe to be ready
|
|
5068
|
-
const isIframeReady = await waitForIframeReady();
|
|
5069
|
-
if (!isIframeReady) {
|
|
5070
|
-
if (debug) {
|
|
5071
|
-
console.error('[useIframeHeightProcessor] Iframe not ready, cannot process');
|
|
5072
|
-
}
|
|
5073
|
-
return;
|
|
5074
|
-
}
|
|
5075
|
-
if (!processorRef.current) {
|
|
5076
|
-
processorRef.current = initializeProcessor();
|
|
5077
|
-
if (!processorRef.current)
|
|
5078
|
-
return;
|
|
5079
|
-
}
|
|
5080
|
-
setIsProcessing(true);
|
|
5081
|
-
setError(null);
|
|
5082
|
-
try {
|
|
5083
|
-
if (debug) {
|
|
5084
|
-
console.log('[useIframeHeightProcessor] Starting height processing...');
|
|
5085
|
-
}
|
|
5086
|
-
await processorRef.current.processIframeHeight();
|
|
5087
|
-
const calculatedHeight = processorRef.current.getIframeHeight();
|
|
5088
|
-
if (debug) {
|
|
5089
|
-
console.log(`[useIframeHeightProcessor] Height calculated: ${calculatedHeight}px`);
|
|
5090
|
-
}
|
|
5091
|
-
// Auto-apply if enabled
|
|
5092
|
-
if (autoApplyHeight)
|
|
5093
|
-
applyHeight(calculatedHeight);
|
|
5094
|
-
// Callback
|
|
5095
|
-
onProcessComplete?.({ height: calculatedHeight });
|
|
5096
|
-
}
|
|
5097
|
-
catch (err) {
|
|
5098
|
-
const error = err;
|
|
5099
|
-
console.error('[useIframeHeightProcessor] Processing error:', error);
|
|
5100
|
-
setError(error);
|
|
5101
|
-
if (onProcessError) {
|
|
5102
|
-
onProcessError(error);
|
|
5103
|
-
}
|
|
5104
|
-
}
|
|
5105
|
-
finally {
|
|
5106
|
-
setIsProcessing(false);
|
|
5107
|
-
}
|
|
5108
|
-
}, [
|
|
5109
|
-
initializeProcessor,
|
|
5110
|
-
autoApplyHeight,
|
|
5111
|
-
applyHeight,
|
|
5112
|
-
onProcessComplete,
|
|
5113
|
-
onProcessError,
|
|
5114
|
-
shouldProcess,
|
|
5115
|
-
debug,
|
|
5116
|
-
waitForIframeReady,
|
|
5117
|
-
]);
|
|
5118
|
-
const getHeight = useCallback(() => {
|
|
5119
|
-
if (!processorRef.current)
|
|
5120
|
-
return 0;
|
|
5121
|
-
return processorRef.current.getIframeHeight();
|
|
5122
|
-
}, []);
|
|
5123
|
-
const checkHeightChange = useCallback(() => {
|
|
5124
|
-
if (!processorRef.current)
|
|
5125
|
-
return false;
|
|
5126
|
-
const changed = processorRef.current.checkHeightDifference();
|
|
5127
|
-
if (!changed)
|
|
5128
|
-
return false;
|
|
5129
|
-
const newHeight = processorRef.current.getIframeHeight();
|
|
5130
|
-
console.log(`🚀 🐥 ~ useIframeHeightProcessor ~ newHeight:`, newHeight);
|
|
5131
|
-
onHeightChange?.(newHeight);
|
|
5132
|
-
return changed;
|
|
5133
|
-
}, [onHeightChange]);
|
|
5134
|
-
useEffect(() => {
|
|
5135
|
-
if (!watchHeightChanges || !shouldProcess)
|
|
5136
|
-
return;
|
|
5137
|
-
if (!processorRef.current) {
|
|
5138
|
-
processorRef.current = initializeProcessor();
|
|
5139
|
-
if (!processorRef.current)
|
|
5140
|
-
return;
|
|
5141
|
-
}
|
|
5142
|
-
heightCheckIntervalRef.current = setInterval(() => {
|
|
5143
|
-
checkHeightChange();
|
|
5144
|
-
}, 500);
|
|
5145
|
-
return () => {
|
|
5146
|
-
if (heightCheckIntervalRef.current) {
|
|
5147
|
-
clearInterval(heightCheckIntervalRef.current);
|
|
5148
|
-
}
|
|
5149
|
-
};
|
|
5150
|
-
}, [watchHeightChanges, initializeProcessor, checkHeightChange, shouldProcess]);
|
|
5151
|
-
useEffect(() => {
|
|
5152
|
-
if (!autoProcess || !shouldProcess)
|
|
5153
|
-
return;
|
|
5154
|
-
const timer = setTimeout(() => {
|
|
5155
|
-
process();
|
|
5156
|
-
}, 100);
|
|
5157
|
-
return () => {
|
|
5158
|
-
clearTimeout(timer);
|
|
5159
|
-
};
|
|
5160
|
-
}, [autoProcess, process, shouldProcess]);
|
|
5161
|
-
useEffect(() => {
|
|
5162
|
-
const handleScreenshotFixesComplete = async (event) => {
|
|
5163
|
-
const customEvent = event;
|
|
5164
|
-
const { iframeId: eventIframeId, heatmapInstanceIndex } = customEvent.detail || {};
|
|
5165
|
-
if (debug) {
|
|
5166
|
-
console.log(`[useIframeHeightProcessor] Screenshot fixes complete for ${eventIframeId}`, {
|
|
5167
|
-
heatmapInstanceIndex,
|
|
5168
|
-
});
|
|
5169
|
-
}
|
|
5170
|
-
// Small delay to ensure all DOM updates are complete
|
|
5171
|
-
setTimeout(async () => {
|
|
5172
|
-
if (debug) {
|
|
5173
|
-
console.log('[useIframeHeightProcessor] Running height processing after screenshot fixes');
|
|
5174
|
-
}
|
|
5175
|
-
await process();
|
|
5176
|
-
}, 50);
|
|
5177
|
-
};
|
|
5178
|
-
window.addEventListener('screenshotFixesComplete', handleScreenshotFixesComplete);
|
|
5179
|
-
return () => {
|
|
5180
|
-
window.removeEventListener('screenshotFixesComplete', handleScreenshotFixesComplete);
|
|
5181
|
-
};
|
|
5182
|
-
}, [process, debug]);
|
|
5183
|
-
useEffect(() => {
|
|
5184
|
-
return () => {
|
|
5185
|
-
if (processorRef.current) {
|
|
5186
|
-
processorRef.current.destroy();
|
|
5187
|
-
processorRef.current = null;
|
|
5188
|
-
}
|
|
5189
|
-
if (heightCheckIntervalRef.current) {
|
|
5190
|
-
clearInterval(heightCheckIntervalRef.current);
|
|
3782
|
+
x /= scale;
|
|
3783
|
+
y /= scale;
|
|
3784
|
+
}
|
|
3785
|
+
return { x, y };
|
|
3786
|
+
};
|
|
3787
|
+
const findTargetElement = (doc, x, y, heatmapInfo) => {
|
|
3788
|
+
const elementsAtPoint = getElementsAtPoint(doc, Math.round(x), Math.round(y), {
|
|
3789
|
+
filterFn: (element) => element.hasAttribute(HEATMAP_ELEMENT_ATTRIBUTE),
|
|
3790
|
+
ignoreCanvas: true,
|
|
3791
|
+
});
|
|
3792
|
+
let dataElement = null;
|
|
3793
|
+
for (let i = 0; i < elementsAtPoint.length; i++) {
|
|
3794
|
+
const element = elementsAtPoint[i];
|
|
3795
|
+
const elementHash = getElementHash(element) ?? '';
|
|
3796
|
+
const isExistElmInfo = heatmapInfo.clickMapMetrics?.[elementHash];
|
|
3797
|
+
if (elementHash && isExistElmInfo) {
|
|
3798
|
+
const boundingBox = getBoundingBox(element);
|
|
3799
|
+
if (boundingBox) {
|
|
3800
|
+
dataElement = element;
|
|
3801
|
+
break;
|
|
5191
3802
|
}
|
|
5192
|
-
}
|
|
5193
|
-
}
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
3803
|
+
}
|
|
3804
|
+
}
|
|
3805
|
+
if (dataElement) {
|
|
3806
|
+
return dataElement;
|
|
3807
|
+
}
|
|
3808
|
+
let targetElement = getElementAtPoint(doc, x, y);
|
|
3809
|
+
if (!targetElement) {
|
|
3810
|
+
targetElement = doc.elementFromPoint(x, y);
|
|
3811
|
+
}
|
|
3812
|
+
return targetElement;
|
|
3813
|
+
};
|
|
3814
|
+
const isIframeReady = (iframeRef, heatmapInfo) => {
|
|
3815
|
+
return !!(iframeRef.current?.contentDocument && heatmapInfo?.clickMapMetrics);
|
|
3816
|
+
};
|
|
3817
|
+
const isValidElement = (element, heatmapInfo) => {
|
|
3818
|
+
if (!element)
|
|
3819
|
+
return false;
|
|
3820
|
+
const hash = getElementHash(element);
|
|
3821
|
+
if (!hash)
|
|
3822
|
+
return false;
|
|
3823
|
+
return !!heatmapInfo?.clickMapMetrics?.[hash];
|
|
3824
|
+
};
|
|
5204
3825
|
|
|
5205
3826
|
/**
|
|
5206
3827
|
* Portal service configuration
|
|
@@ -5284,181 +3905,24 @@ function useVizLiveIframeMsg(options = {}) {
|
|
|
5284
3905
|
}
|
|
5285
3906
|
|
|
5286
3907
|
/**
|
|
5287
|
-
*
|
|
5288
|
-
*
|
|
5289
|
-
* @module iframe-height-observer
|
|
3908
|
+
* DOM observation setup — ResizeObserver + MutationObserver.
|
|
3909
|
+
* Returns a cleanup function that disconnects both observers.
|
|
5290
3910
|
*/
|
|
5291
|
-
createLogger({
|
|
5292
|
-
enabled: true,
|
|
5293
|
-
prefix: 'IframeHeightObserver',
|
|
5294
|
-
});
|
|
3911
|
+
createLogger({ enabled: false, prefix: 'IframeHeightObserver' });
|
|
5295
3912
|
|
|
5296
3913
|
/**
|
|
5297
|
-
*
|
|
5298
|
-
*
|
|
5299
|
-
* @module iframe-navigation-blocker
|
|
5300
|
-
*/
|
|
5301
|
-
const logger$3 = createLogger({
|
|
5302
|
-
enabled: false,
|
|
5303
|
-
prefix: 'IframeNavigationBlocker',
|
|
5304
|
-
});
|
|
5305
|
-
// ============================================================================
|
|
5306
|
-
// State
|
|
5307
|
-
// ============================================================================
|
|
5308
|
-
let doc$2 = null;
|
|
5309
|
-
let win$2 = null;
|
|
5310
|
-
let isEnabled = false;
|
|
5311
|
-
let showMessage = false;
|
|
5312
|
-
let originalWindowOpen = null;
|
|
5313
|
-
let mutationObservers = [];
|
|
5314
|
-
let running$4 = false;
|
|
5315
|
-
// Event listener references for cleanup
|
|
5316
|
-
let clickListener = null;
|
|
5317
|
-
let auxclickListener = null;
|
|
5318
|
-
let submitListener = null;
|
|
5319
|
-
let beforeUnloadListener = null;
|
|
5320
|
-
let unloadListener = null;
|
|
5321
|
-
// ============================================================================
|
|
5322
|
-
// Core API Functions
|
|
5323
|
-
// ============================================================================
|
|
5324
|
-
/**
|
|
5325
|
-
* Start navigation blocker
|
|
5326
|
-
* @param iframe - The iframe element to block navigation in
|
|
5327
|
-
* @param cfg - Blocker configuration
|
|
5328
|
-
*/
|
|
5329
|
-
function start$5(iframe, cfg) {
|
|
5330
|
-
if (running$4) {
|
|
5331
|
-
logger$3.warn('Blocker is already running. Call stop() first.');
|
|
5332
|
-
return;
|
|
5333
|
-
}
|
|
5334
|
-
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
5335
|
-
throw new Error('Iframe document or window not accessible');
|
|
5336
|
-
}
|
|
5337
|
-
doc$2 = iframe.contentDocument;
|
|
5338
|
-
win$2 = iframe.contentWindow;
|
|
5339
|
-
originalWindowOpen = win$2.open.bind(win$2);
|
|
5340
|
-
running$4 = true;
|
|
5341
|
-
logger$3.configure({ enabled: !!cfg?.debug });
|
|
5342
|
-
initialize$1();
|
|
5343
|
-
logger$3.log('Navigation blocker started');
|
|
5344
|
-
}
|
|
5345
|
-
/**
|
|
5346
|
-
* Stop navigation blocker and cleanup
|
|
5347
|
-
*/
|
|
5348
|
-
function stop$5() {
|
|
5349
|
-
if (!running$4) {
|
|
5350
|
-
return;
|
|
5351
|
-
}
|
|
5352
|
-
clear();
|
|
5353
|
-
doc$2 = null;
|
|
5354
|
-
win$2 = null;
|
|
5355
|
-
originalWindowOpen = null;
|
|
5356
|
-
running$4 = false;
|
|
5357
|
-
logger$3.log('Navigation blocker stopped');
|
|
5358
|
-
}
|
|
5359
|
-
/**
|
|
5360
|
-
* Initialize all blocking mechanisms
|
|
3914
|
+
* Height Observer Processor
|
|
3915
|
+
* Background observer — watches for iframe content height changes.
|
|
5361
3916
|
*/
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
logger$
|
|
5367
|
-
try {
|
|
5368
|
-
blockLinkNavigation();
|
|
5369
|
-
blockFormSubmissions();
|
|
5370
|
-
blockWindowOpen();
|
|
5371
|
-
blockBeforeUnload();
|
|
5372
|
-
monitorDOMChanges();
|
|
5373
|
-
// injectCSP(); // TODO: Uncomment this when we have a way to inject CSP
|
|
5374
|
-
}
|
|
5375
|
-
catch (error) {
|
|
5376
|
-
logger$3.error('Init error:', error);
|
|
5377
|
-
}
|
|
5378
|
-
}
|
|
5379
|
-
/**
|
|
5380
|
-
* Clear all observers and listeners
|
|
5381
|
-
*/
|
|
5382
|
-
function clear() {
|
|
5383
|
-
// Remove event listeners
|
|
5384
|
-
if (doc$2 && clickListener) {
|
|
5385
|
-
doc$2.removeEventListener('click', clickListener, true);
|
|
5386
|
-
clickListener = null;
|
|
5387
|
-
}
|
|
5388
|
-
if (doc$2 && auxclickListener) {
|
|
5389
|
-
doc$2.removeEventListener('auxclick', auxclickListener, true);
|
|
5390
|
-
auxclickListener = null;
|
|
5391
|
-
}
|
|
5392
|
-
if (doc$2 && submitListener) {
|
|
5393
|
-
doc$2.removeEventListener('submit', submitListener, true);
|
|
5394
|
-
submitListener = null;
|
|
5395
|
-
}
|
|
5396
|
-
if (win$2 && beforeUnloadListener) {
|
|
5397
|
-
win$2.removeEventListener('beforeunload', beforeUnloadListener, true);
|
|
5398
|
-
beforeUnloadListener = null;
|
|
5399
|
-
}
|
|
5400
|
-
if (win$2 && unloadListener) {
|
|
5401
|
-
win$2.removeEventListener('unload', unloadListener, true);
|
|
5402
|
-
unloadListener = null;
|
|
5403
|
-
}
|
|
5404
|
-
// Restore original window.open
|
|
5405
|
-
if (win$2 && originalWindowOpen) {
|
|
5406
|
-
win$2.open = originalWindowOpen;
|
|
5407
|
-
}
|
|
5408
|
-
// Disconnect mutation observers
|
|
5409
|
-
mutationObservers.forEach((obs) => obs.disconnect());
|
|
5410
|
-
mutationObservers = [];
|
|
5411
|
-
isEnabled = false;
|
|
5412
|
-
showMessage = false;
|
|
5413
|
-
}
|
|
5414
|
-
// ============================================================================
|
|
5415
|
-
// Blocking Functions
|
|
5416
|
-
// ============================================================================
|
|
5417
|
-
function blockLinkNavigation() {
|
|
5418
|
-
if (!doc$2)
|
|
5419
|
-
return;
|
|
5420
|
-
clickListener = (e) => {
|
|
5421
|
-
if (!isEnabled)
|
|
5422
|
-
return;
|
|
5423
|
-
const target = e.target;
|
|
5424
|
-
const link = target.closest('a');
|
|
5425
|
-
if (link) {
|
|
5426
|
-
const href = link.getAttribute('href');
|
|
5427
|
-
// Allow hash links and empty links
|
|
5428
|
-
if (!href || href === '' || href === '#' || href.startsWith('#')) {
|
|
5429
|
-
logger$3.log('Allowed hash navigation:', href);
|
|
5430
|
-
return;
|
|
5431
|
-
}
|
|
5432
|
-
logger$3.log('Blocked link navigation to:', href);
|
|
5433
|
-
e.preventDefault();
|
|
5434
|
-
e.stopPropagation();
|
|
5435
|
-
e.stopImmediatePropagation();
|
|
5436
|
-
notifyBlockedNavigation(href);
|
|
5437
|
-
}
|
|
5438
|
-
};
|
|
5439
|
-
auxclickListener = (e) => {
|
|
5440
|
-
if (!isEnabled)
|
|
5441
|
-
return;
|
|
5442
|
-
const target = e.target;
|
|
5443
|
-
const link = target.closest('a');
|
|
5444
|
-
if (link) {
|
|
5445
|
-
const href = link.getAttribute('href');
|
|
5446
|
-
if (href && !href.startsWith('#')) {
|
|
5447
|
-
logger$3.log('Blocked auxclick navigation');
|
|
5448
|
-
e.preventDefault();
|
|
5449
|
-
e.stopPropagation();
|
|
5450
|
-
e.stopImmediatePropagation();
|
|
5451
|
-
}
|
|
5452
|
-
}
|
|
5453
|
-
};
|
|
5454
|
-
doc$2.addEventListener('click', clickListener, true);
|
|
5455
|
-
doc$2.addEventListener('auxclick', auxclickListener, true);
|
|
5456
|
-
disableAllLinks();
|
|
3917
|
+
createLogger({ enabled: true, prefix: 'IframeHeightObserver' });
|
|
3918
|
+
|
|
3919
|
+
const logger$8 = createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' });
|
|
3920
|
+
function configure$1(debug) {
|
|
3921
|
+
logger$8.configure({ enabled: debug });
|
|
5457
3922
|
}
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
doc$2.querySelectorAll('a[href]').forEach((link) => {
|
|
3923
|
+
// ─── DOM Utilities ────────────────────────────────────────────────────────────
|
|
3924
|
+
function disableAllLinks(doc) {
|
|
3925
|
+
doc.querySelectorAll('a[href]').forEach((link) => {
|
|
5462
3926
|
const href = link.getAttribute('href');
|
|
5463
3927
|
if (href && !href.startsWith('#')) {
|
|
5464
3928
|
link.style.cursor = 'not-allowed';
|
|
@@ -5468,108 +3932,234 @@ function disableAllLinks() {
|
|
|
5468
3932
|
}
|
|
5469
3933
|
});
|
|
5470
3934
|
}
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
3935
|
+
// ─── Blockers ─────────────────────────────────────────────────────────────────
|
|
3936
|
+
function setupLinkBlocker(doc, isEnabled, onBlocked) {
|
|
3937
|
+
const clickListener = (e) => {
|
|
3938
|
+
if (!isEnabled())
|
|
3939
|
+
return;
|
|
3940
|
+
const link = e.target.closest('a');
|
|
3941
|
+
if (!link)
|
|
3942
|
+
return;
|
|
3943
|
+
const href = link.getAttribute('href');
|
|
3944
|
+
if (!href || href === '' || href === '#' || href.startsWith('#')) {
|
|
3945
|
+
logger$8.log('Allowed hash navigation:', href);
|
|
3946
|
+
return;
|
|
3947
|
+
}
|
|
3948
|
+
logger$8.log('Blocked link navigation to:', href);
|
|
3949
|
+
e.preventDefault();
|
|
3950
|
+
e.stopPropagation();
|
|
3951
|
+
e.stopImmediatePropagation();
|
|
3952
|
+
onBlocked(href);
|
|
3953
|
+
};
|
|
3954
|
+
const auxclickListener = (e) => {
|
|
3955
|
+
if (!isEnabled())
|
|
3956
|
+
return;
|
|
3957
|
+
const link = e.target.closest('a');
|
|
3958
|
+
if (!link)
|
|
3959
|
+
return;
|
|
3960
|
+
const href = link.getAttribute('href');
|
|
3961
|
+
if (href && !href.startsWith('#')) {
|
|
3962
|
+
logger$8.log('Blocked auxclick navigation');
|
|
3963
|
+
e.preventDefault();
|
|
3964
|
+
e.stopPropagation();
|
|
3965
|
+
e.stopImmediatePropagation();
|
|
3966
|
+
}
|
|
3967
|
+
};
|
|
3968
|
+
doc.addEventListener('click', clickListener, true);
|
|
3969
|
+
doc.addEventListener('auxclick', auxclickListener, true);
|
|
3970
|
+
disableAllLinks(doc);
|
|
3971
|
+
return () => {
|
|
3972
|
+
doc.removeEventListener('click', clickListener, true);
|
|
3973
|
+
doc.removeEventListener('auxclick', auxclickListener, true);
|
|
3974
|
+
};
|
|
3975
|
+
}
|
|
3976
|
+
function setupFormBlocker(doc, isEnabled, onBlocked, onFormSubmit) {
|
|
3977
|
+
const submitListener = (e) => {
|
|
3978
|
+
if (!isEnabled())
|
|
5476
3979
|
return;
|
|
5477
3980
|
const form = e.target;
|
|
5478
3981
|
const action = form.getAttribute('action');
|
|
5479
3982
|
if (!action || action === '' || action === '#') {
|
|
5480
|
-
logger$
|
|
3983
|
+
logger$8.log('Allowed same-page form');
|
|
5481
3984
|
e.preventDefault();
|
|
5482
|
-
|
|
3985
|
+
const data = {};
|
|
3986
|
+
new FormData(form).forEach((value, key) => {
|
|
3987
|
+
data[key] = value;
|
|
3988
|
+
});
|
|
3989
|
+
onFormSubmit(form, data);
|
|
5483
3990
|
return;
|
|
5484
3991
|
}
|
|
5485
|
-
logger$
|
|
3992
|
+
logger$8.log('Blocked form submission to:', action);
|
|
5486
3993
|
e.preventDefault();
|
|
5487
3994
|
e.stopPropagation();
|
|
5488
3995
|
e.stopImmediatePropagation();
|
|
5489
|
-
|
|
3996
|
+
onBlocked(action);
|
|
5490
3997
|
};
|
|
5491
|
-
doc
|
|
3998
|
+
doc.addEventListener('submit', submitListener, true);
|
|
3999
|
+
return () => doc.removeEventListener('submit', submitListener, true);
|
|
5492
4000
|
}
|
|
5493
|
-
function
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
if (!isEnabled) {
|
|
5498
|
-
return originalWindowOpen(...args);
|
|
5499
|
-
}
|
|
4001
|
+
function setupWindowOpenBlocker(win, originalOpen, isEnabled, onBlocked) {
|
|
4002
|
+
win.open = ((...args) => {
|
|
4003
|
+
if (!isEnabled())
|
|
4004
|
+
return originalOpen(...args);
|
|
5500
4005
|
const url = args[0]?.toString() || 'popup';
|
|
5501
|
-
logger$
|
|
5502
|
-
|
|
4006
|
+
logger$8.log('Blocked window.open:', url);
|
|
4007
|
+
onBlocked(url);
|
|
5503
4008
|
return null;
|
|
5504
4009
|
});
|
|
4010
|
+
return () => {
|
|
4011
|
+
win.open = originalOpen;
|
|
4012
|
+
};
|
|
5505
4013
|
}
|
|
5506
|
-
function
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
beforeUnloadListener = (e) => {
|
|
5510
|
-
if (!isEnabled)
|
|
4014
|
+
function setupUnloadBlocker(win, isEnabled) {
|
|
4015
|
+
const beforeUnloadListener = (e) => {
|
|
4016
|
+
if (!isEnabled())
|
|
5511
4017
|
return;
|
|
5512
|
-
logger$
|
|
4018
|
+
logger$8.log('Blocked beforeunload');
|
|
5513
4019
|
e.preventDefault();
|
|
5514
4020
|
e.returnValue = '';
|
|
5515
|
-
return '';
|
|
5516
4021
|
};
|
|
5517
|
-
unloadListener = (e) => {
|
|
5518
|
-
if (!isEnabled)
|
|
4022
|
+
const unloadListener = (e) => {
|
|
4023
|
+
if (!isEnabled())
|
|
5519
4024
|
return;
|
|
5520
|
-
logger$
|
|
4025
|
+
logger$8.log('Blocked unload');
|
|
5521
4026
|
e.preventDefault();
|
|
5522
4027
|
e.stopPropagation();
|
|
5523
4028
|
};
|
|
5524
|
-
win
|
|
5525
|
-
win
|
|
4029
|
+
win.addEventListener('beforeunload', beforeUnloadListener, true);
|
|
4030
|
+
win.addEventListener('unload', unloadListener, true);
|
|
4031
|
+
return () => {
|
|
4032
|
+
win.removeEventListener('beforeunload', beforeUnloadListener, true);
|
|
4033
|
+
win.removeEventListener('unload', unloadListener, true);
|
|
4034
|
+
};
|
|
5526
4035
|
}
|
|
5527
|
-
function
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
disableAllLinks();
|
|
5532
|
-
});
|
|
5533
|
-
observer.observe(doc$2.body, {
|
|
5534
|
-
childList: true,
|
|
5535
|
-
subtree: true,
|
|
5536
|
-
});
|
|
5537
|
-
mutationObservers.push(observer);
|
|
4036
|
+
function setupDOMMonitor(doc) {
|
|
4037
|
+
const observer = new MutationObserver(() => disableAllLinks(doc));
|
|
4038
|
+
observer.observe(doc.body, { childList: true, subtree: true });
|
|
4039
|
+
return () => observer.disconnect();
|
|
5538
4040
|
}
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
4041
|
+
|
|
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;
|
|
5545
4075
|
}
|
|
5546
|
-
window.dispatchEvent(new CustomEvent('iframe-navigation-blocked', {
|
|
5547
|
-
detail: { url },
|
|
5548
|
-
}));
|
|
5549
4076
|
}
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
});
|
|
5556
|
-
window.dispatchEvent(new CustomEvent('iframe-form-submit', {
|
|
5557
|
-
detail: { form, data },
|
|
5558
|
-
}));
|
|
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 } }));
|
|
5559
4082
|
}
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
4083
|
+
function dispatchFormSubmit(form, data) {
|
|
4084
|
+
window.dispatchEvent(new CustomEvent('iframe-form-submit', { detail: { form, data } }));
|
|
4085
|
+
}
|
|
4086
|
+
|
|
5563
4087
|
/**
|
|
5564
|
-
*
|
|
4088
|
+
* Navigation Processor
|
|
4089
|
+
* Continuous guard — blocks all navigation attempts within the iframe.
|
|
5565
4090
|
*/
|
|
4091
|
+
const logger$6 = createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' });
|
|
4092
|
+
// ─── State ────────────────────────────────────────────────────────────────────
|
|
4093
|
+
let isEnabled = false;
|
|
4094
|
+
let showMessage = false;
|
|
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.');
|
|
4101
|
+
return;
|
|
4102
|
+
}
|
|
4103
|
+
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
4104
|
+
throw new Error('Iframe document or window not accessible');
|
|
4105
|
+
}
|
|
4106
|
+
const doc = iframe.contentDocument;
|
|
4107
|
+
const win = iframe.contentWindow;
|
|
4108
|
+
const originalOpen = win.open.bind(win);
|
|
4109
|
+
logger$6.configure({ enabled: !!cfg?.debug });
|
|
4110
|
+
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),
|
|
4116
|
+
setupDOMMonitor(doc),
|
|
4117
|
+
];
|
|
4118
|
+
attach$1(cfg?.debug);
|
|
4119
|
+
running$4 = true;
|
|
4120
|
+
logger$6.log('Navigation blocker started');
|
|
4121
|
+
}
|
|
4122
|
+
function stop$5() {
|
|
4123
|
+
if (!running$4)
|
|
4124
|
+
return;
|
|
4125
|
+
cleanups.forEach((fn) => fn());
|
|
4126
|
+
cleanups = [];
|
|
4127
|
+
detach$1();
|
|
4128
|
+
isEnabled = false;
|
|
4129
|
+
showMessage = false;
|
|
4130
|
+
running$4 = false;
|
|
4131
|
+
logger$6.log('Navigation blocker stopped');
|
|
4132
|
+
}
|
|
5566
4133
|
function enable() {
|
|
5567
4134
|
if (!running$4) {
|
|
5568
|
-
logger$
|
|
4135
|
+
logger$6.warn('Blocker is not running. Call start() first.');
|
|
5569
4136
|
return;
|
|
5570
4137
|
}
|
|
5571
4138
|
isEnabled = true;
|
|
5572
|
-
logger$
|
|
4139
|
+
logger$6.log('Navigation blocking enabled');
|
|
4140
|
+
}
|
|
4141
|
+
|
|
4142
|
+
const registry$1 = [];
|
|
4143
|
+
/**
|
|
4144
|
+
* Register a global fix.
|
|
4145
|
+
* Fixes are run in registration order.
|
|
4146
|
+
*/
|
|
4147
|
+
function register$1(fix) {
|
|
4148
|
+
registry$1.push(fix);
|
|
4149
|
+
}
|
|
4150
|
+
/**
|
|
4151
|
+
* Returns all fixes that are active for the given context.
|
|
4152
|
+
* A fix is active if it has no `shouldApply`, or `shouldApply` returns true.
|
|
4153
|
+
*/
|
|
4154
|
+
function getActiveFixes(ctx) {
|
|
4155
|
+
return registry$1.filter((fix) => {
|
|
4156
|
+
try {
|
|
4157
|
+
return !fix.shouldApply || fix.shouldApply(ctx);
|
|
4158
|
+
}
|
|
4159
|
+
catch {
|
|
4160
|
+
return false;
|
|
4161
|
+
}
|
|
4162
|
+
});
|
|
5573
4163
|
}
|
|
5574
4164
|
|
|
5575
4165
|
/**
|
|
@@ -5577,7 +4167,7 @@ function enable() {
|
|
|
5577
4167
|
* Enforces computed CSS styles with viewport unit verification
|
|
5578
4168
|
* @module computed-style-enforcer
|
|
5579
4169
|
*/
|
|
5580
|
-
const logger$
|
|
4170
|
+
const logger$5 = createLogger({
|
|
5581
4171
|
enabled: false,
|
|
5582
4172
|
prefix: 'ComputedStyleEnforcer',
|
|
5583
4173
|
});
|
|
@@ -5585,7 +4175,7 @@ const logger$2 = createLogger({
|
|
|
5585
4175
|
// Constants
|
|
5586
4176
|
// ============================================================================
|
|
5587
4177
|
const DEFAULT_TOLERANCE_PX = 5;
|
|
5588
|
-
const VIEWPORT_UNIT_REGEX
|
|
4178
|
+
const VIEWPORT_UNIT_REGEX = /([-.\d]+)(vh|svh|lvh|dvh|%)/gi;
|
|
5589
4179
|
const DEFAULT_CSS_VALUES = ['none', 'auto', 'normal', '0px'];
|
|
5590
4180
|
const CRITICAL_PROPERTIES = [
|
|
5591
4181
|
'display',
|
|
@@ -5637,7 +4227,7 @@ let running$3 = false;
|
|
|
5637
4227
|
/**
|
|
5638
4228
|
* Get viewport unit map for conversion from current state
|
|
5639
4229
|
*/
|
|
5640
|
-
function getViewportUnitMap
|
|
4230
|
+
function getViewportUnitMap() {
|
|
5641
4231
|
if (!config$2) {
|
|
5642
4232
|
throw new Error('Config is not initialized');
|
|
5643
4233
|
}
|
|
@@ -5655,7 +4245,7 @@ function getViewportUnitMap$1() {
|
|
|
5655
4245
|
/**
|
|
5656
4246
|
* Calculate expected pixel value from viewport unit using current state
|
|
5657
4247
|
*/
|
|
5658
|
-
function calculateExpectedPx
|
|
4248
|
+
function calculateExpectedPx(value, unit) {
|
|
5659
4249
|
if (!config$2) {
|
|
5660
4250
|
throw new Error('Config is not initialized');
|
|
5661
4251
|
}
|
|
@@ -5663,7 +4253,7 @@ function calculateExpectedPx$1(value, unit) {
|
|
|
5663
4253
|
if (unitLower === '%') {
|
|
5664
4254
|
return (value / 100) * config$2.targetHeight;
|
|
5665
4255
|
}
|
|
5666
|
-
const unitMap = getViewportUnitMap
|
|
4256
|
+
const unitMap = getViewportUnitMap();
|
|
5667
4257
|
return (value / 100) * (unitMap[unitLower] || 0);
|
|
5668
4258
|
}
|
|
5669
4259
|
/**
|
|
@@ -5687,7 +4277,7 @@ function shouldReplaceValue(computedValue, originalValue, tolerance = DEFAULT_TO
|
|
|
5687
4277
|
return false; // Cannot verify, don't replace
|
|
5688
4278
|
}
|
|
5689
4279
|
// Parse original value to check what it should be
|
|
5690
|
-
const regex = new RegExp(VIEWPORT_UNIT_REGEX
|
|
4280
|
+
const regex = new RegExp(VIEWPORT_UNIT_REGEX.source, VIEWPORT_UNIT_REGEX.flags);
|
|
5691
4281
|
const match = originalValue.match(regex);
|
|
5692
4282
|
if (!match) {
|
|
5693
4283
|
return false; // No viewport units found, don't replace
|
|
@@ -5698,16 +4288,16 @@ function shouldReplaceValue(computedValue, originalValue, tolerance = DEFAULT_TO
|
|
|
5698
4288
|
return false;
|
|
5699
4289
|
}
|
|
5700
4290
|
// Calculate expected value based on unit and target config
|
|
5701
|
-
const expectedPx = calculateExpectedPx
|
|
4291
|
+
const expectedPx = calculateExpectedPx(num, unit);
|
|
5702
4292
|
// Check if computed value matches expected value (within tolerance)
|
|
5703
4293
|
const diff = Math.abs(computedPx - expectedPx);
|
|
5704
4294
|
if (diff <= tolerance) {
|
|
5705
4295
|
// Matches target config, OK to replace
|
|
5706
|
-
logger$
|
|
4296
|
+
logger$5.log(`OK to replace: computed=${computedValue} matches expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
|
|
5707
4297
|
return true;
|
|
5708
4298
|
}
|
|
5709
4299
|
// Different from target config, DON'T replace - value already has correct computation
|
|
5710
|
-
logger$
|
|
4300
|
+
logger$5.log(`Skip replace: computed=${computedValue} differs from expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px) - keeping current value`);
|
|
5711
4301
|
return false;
|
|
5712
4302
|
}
|
|
5713
4303
|
/**
|
|
@@ -5735,15 +4325,15 @@ function applyPropertyWithVerification(element, prop, computedValue, originalVal
|
|
|
5735
4325
|
*/
|
|
5736
4326
|
function start$4(d, w, cfg, options = {}) {
|
|
5737
4327
|
if (running$3) {
|
|
5738
|
-
logger$
|
|
4328
|
+
logger$5.warn('Enforcer is already running. Call stop() first.');
|
|
5739
4329
|
return;
|
|
5740
4330
|
}
|
|
5741
4331
|
doc$1 = d;
|
|
5742
4332
|
win$1 = w;
|
|
5743
4333
|
config$2 = cfg;
|
|
5744
4334
|
running$3 = true;
|
|
5745
|
-
logger$
|
|
5746
|
-
logger$
|
|
4335
|
+
logger$5.configure({ enabled: !!options.debug });
|
|
4336
|
+
logger$5.log('Computed style enforcer started');
|
|
5747
4337
|
}
|
|
5748
4338
|
/**
|
|
5749
4339
|
* Stop the enforcer and clear state
|
|
@@ -5758,7 +4348,7 @@ function stop$4() {
|
|
|
5758
4348
|
elementsWithViewportUnits$1.clear();
|
|
5759
4349
|
originalValues$1 = new WeakMap();
|
|
5760
4350
|
running$3 = false;
|
|
5761
|
-
logger$
|
|
4351
|
+
logger$5.log('Computed style enforcer stopped');
|
|
5762
4352
|
}
|
|
5763
4353
|
/**
|
|
5764
4354
|
* Track an element with viewport units
|
|
@@ -5766,7 +4356,7 @@ function stop$4() {
|
|
|
5766
4356
|
*/
|
|
5767
4357
|
function trackElement(element, propertyOriginalValues) {
|
|
5768
4358
|
if (!running$3) {
|
|
5769
|
-
logger$
|
|
4359
|
+
logger$5.warn('Enforcer is not running. Call start() first.');
|
|
5770
4360
|
return;
|
|
5771
4361
|
}
|
|
5772
4362
|
elementsWithViewportUnits$1.add(element);
|
|
@@ -5788,7 +4378,7 @@ function trackElement(element, propertyOriginalValues) {
|
|
|
5788
4378
|
*/
|
|
5789
4379
|
function processElement(element, options = {}) {
|
|
5790
4380
|
if (!running$3 || !doc$1 || !win$1 || !config$2) {
|
|
5791
|
-
logger$
|
|
4381
|
+
logger$5.warn('Enforcer is not running. Call start() first.');
|
|
5792
4382
|
return 0;
|
|
5793
4383
|
}
|
|
5794
4384
|
if (!elementsWithViewportUnits$1.has(element)) {
|
|
@@ -5820,321 +4410,185 @@ function processElement(element, options = {}) {
|
|
|
5820
4410
|
*/
|
|
5821
4411
|
function processAll(options = {}) {
|
|
5822
4412
|
if (!running$3 || !doc$1 || !win$1 || !config$2) {
|
|
5823
|
-
logger$
|
|
4413
|
+
logger$5.warn('Enforcer is not running. Call start() first.');
|
|
5824
4414
|
return 0;
|
|
5825
4415
|
}
|
|
5826
4416
|
let totalCount = 0;
|
|
5827
4417
|
elementsWithViewportUnits$1.forEach((element) => {
|
|
5828
4418
|
totalCount += processElement(element, options);
|
|
5829
4419
|
});
|
|
5830
|
-
logger$
|
|
5831
|
-
return totalCount;
|
|
5832
|
-
}
|
|
5833
|
-
|
|
5834
|
-
/**
|
|
5835
|
-
* Viewport Unit Replacer Module
|
|
5836
|
-
* Replaces viewport units (vh, vw, %) with pixel values in iframe
|
|
5837
|
-
* @module iframe-viewport-replacer
|
|
5838
|
-
*/
|
|
5839
|
-
const logger$1 = createLogger({
|
|
5840
|
-
enabled: false,
|
|
5841
|
-
prefix: 'ViewportReplacer',
|
|
5842
|
-
});
|
|
5843
|
-
// ============================================================================
|
|
5844
|
-
// Constants
|
|
5845
|
-
// ============================================================================
|
|
5846
|
-
const VIEWPORT_UNIT_REGEX = /([-.\d]+)(vh|svh|lvh|dvh|%)/gi;
|
|
5847
|
-
const HEIGHT_RELATED_PROPERTIES = ['height', 'min-height', 'max-height', 'top', 'bottom'];
|
|
5848
|
-
// ============================================================================
|
|
5849
|
-
// State
|
|
5850
|
-
// ============================================================================
|
|
5851
|
-
let doc = null;
|
|
5852
|
-
let win = null;
|
|
5853
|
-
let config$1 = null;
|
|
5854
|
-
const regex = new RegExp(VIEWPORT_UNIT_REGEX.source, VIEWPORT_UNIT_REGEX.flags);
|
|
5855
|
-
const elementsWithViewportUnits = new Set();
|
|
5856
|
-
let originalValues = new WeakMap();
|
|
5857
|
-
let running$2 = false;
|
|
5858
|
-
function start$3(iframe, cfg) {
|
|
5859
|
-
if (running$2) {
|
|
5860
|
-
logger$1.warn('Replacer is already running. Call stop() first.');
|
|
5861
|
-
return;
|
|
5862
|
-
}
|
|
5863
|
-
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
5864
|
-
throw new Error('Iframe document or window not accessible');
|
|
5865
|
-
}
|
|
5866
|
-
doc = iframe.contentDocument;
|
|
5867
|
-
win = iframe.contentWindow;
|
|
5868
|
-
config$1 = cfg;
|
|
5869
|
-
running$2 = true;
|
|
5870
|
-
logger$1.configure({ enabled: !!cfg?.debug });
|
|
5871
|
-
// Initialize enforcer
|
|
5872
|
-
start$4(doc, win, cfg, { debug: !!cfg?.debug });
|
|
5873
|
-
logger$1.log('Viewport replacer started');
|
|
5874
|
-
}
|
|
5875
|
-
function stop$3() {
|
|
5876
|
-
if (!running$2) {
|
|
5877
|
-
return;
|
|
5878
|
-
}
|
|
5879
|
-
// Stop enforcer
|
|
5880
|
-
stop$4();
|
|
5881
|
-
doc = null;
|
|
5882
|
-
win = null;
|
|
5883
|
-
config$1 = null;
|
|
5884
|
-
elementsWithViewportUnits.clear();
|
|
5885
|
-
originalValues = new WeakMap();
|
|
5886
|
-
running$2 = false;
|
|
5887
|
-
logger$1.log('Viewport replacer stopped');
|
|
5888
|
-
}
|
|
5889
|
-
async function run() {
|
|
5890
|
-
if (!running$2 || !doc) {
|
|
5891
|
-
logger$1.warn('Replacer is not running. Call start() first.');
|
|
5892
|
-
return { height: 1000, width: 1000 };
|
|
5893
|
-
}
|
|
5894
|
-
try {
|
|
5895
|
-
logger$1.log('Starting viewport units replacement...');
|
|
5896
|
-
processInlineStyles();
|
|
5897
|
-
processStyleTags();
|
|
5898
|
-
processStylesheets();
|
|
5899
|
-
await processLinkedStylesheets();
|
|
5900
|
-
// Wait for stylesheets to be fully applied
|
|
5901
|
-
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
5902
|
-
// Enforce computed styles to inline with !important
|
|
5903
|
-
enforceComputedStylesToInline();
|
|
5904
|
-
// Setup MutationObserver to handle dynamically added elements (e.g., dialogs)
|
|
5905
|
-
// setupMutationObserver();
|
|
5906
|
-
return await new Promise((resolve) => {
|
|
5907
|
-
requestAnimationFrame(() => {
|
|
5908
|
-
const height = getFinalHeight();
|
|
5909
|
-
const width = getFinalWidth();
|
|
5910
|
-
logger$1.log('Calculated dimensions:', { height, width });
|
|
5911
|
-
resolve({ height, width });
|
|
5912
|
-
});
|
|
5913
|
-
});
|
|
5914
|
-
}
|
|
5915
|
-
catch (err) {
|
|
5916
|
-
logger$1.error('Critical error:', err);
|
|
5917
|
-
return {
|
|
5918
|
-
height: doc.body?.scrollHeight || 1000,
|
|
5919
|
-
width: doc.body?.scrollWidth || 1000,
|
|
5920
|
-
};
|
|
5921
|
-
}
|
|
4420
|
+
logger$5.log(`Enforced ${totalCount} computed styles for ${elementsWithViewportUnits$1.size} elements`);
|
|
4421
|
+
return totalCount;
|
|
5922
4422
|
}
|
|
5923
|
-
|
|
5924
|
-
|
|
5925
|
-
|
|
4423
|
+
|
|
4424
|
+
/**
|
|
4425
|
+
* Core viewport unit replacement logic.
|
|
4426
|
+
* Converts vh/vw/svh/dvh/% to pixel values across all CSS in the iframe.
|
|
4427
|
+
*/
|
|
4428
|
+
const logger$4 = createLogger({ enabled: false, prefix: 'ViewportUnitReplacer' });
|
|
4429
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
4430
|
+
const HEIGHT_RELATED_PROPERTIES = ['height', 'min-height', 'max-height', 'top', 'bottom'];
|
|
4431
|
+
// ─── Per-run tracking state (reset on each process() call) ───────────────────
|
|
4432
|
+
let elementsWithViewportUnits = new Set();
|
|
4433
|
+
let originalValues = new WeakMap();
|
|
4434
|
+
// ─── Regex ────────────────────────────────────────────────────────────────────
|
|
4435
|
+
/** Fresh instance every call — avoids shared lastIndex state with the g flag. */
|
|
4436
|
+
function createRegex() {
|
|
4437
|
+
return /([-.\\d]+)(vh|svh|lvh|dvh|vw|svw|lvw|dvw)/gi;
|
|
4438
|
+
}
|
|
4439
|
+
// ─── Unit conversion ─────────────────────────────────────────────────────────
|
|
5926
4440
|
function px(value) {
|
|
5927
4441
|
return `${value.toFixed(2)}px`;
|
|
5928
4442
|
}
|
|
5929
|
-
function
|
|
5930
|
-
if (!config$1) {
|
|
5931
|
-
throw new Error('Config is not initialized');
|
|
5932
|
-
}
|
|
4443
|
+
function getUnitMap(ctx) {
|
|
5933
4444
|
return {
|
|
5934
|
-
vh:
|
|
5935
|
-
svh:
|
|
5936
|
-
lvh:
|
|
5937
|
-
dvh:
|
|
5938
|
-
vw:
|
|
5939
|
-
svw:
|
|
5940
|
-
lvw:
|
|
5941
|
-
dvw:
|
|
4445
|
+
vh: ctx.targetHeight,
|
|
4446
|
+
svh: ctx.targetHeight,
|
|
4447
|
+
lvh: ctx.targetHeight,
|
|
4448
|
+
dvh: ctx.targetHeight,
|
|
4449
|
+
vw: ctx.targetWidth,
|
|
4450
|
+
svw: ctx.targetWidth,
|
|
4451
|
+
lvw: ctx.targetWidth,
|
|
4452
|
+
dvw: ctx.targetWidth,
|
|
5942
4453
|
};
|
|
5943
4454
|
}
|
|
5944
|
-
function
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
if (unitLower === '%') {
|
|
5950
|
-
return (value / 100) * config$1.targetHeight;
|
|
5951
|
-
}
|
|
5952
|
-
const unitMap = getViewportUnitMap();
|
|
5953
|
-
return (value / 100) * (unitMap[unitLower] || 0);
|
|
4455
|
+
function toPx(value, unit, ctx) {
|
|
4456
|
+
const u = unit.toLowerCase();
|
|
4457
|
+
if (u === '%')
|
|
4458
|
+
return (value / 100) * ctx.targetHeight;
|
|
4459
|
+
return (value / 100) * (getUnitMap(ctx)[u] ?? 0);
|
|
5954
4460
|
}
|
|
5955
|
-
function convert(value, unit) {
|
|
4461
|
+
function convert(value, unit, ctx) {
|
|
5956
4462
|
const num = parseFloat(value);
|
|
5957
|
-
|
|
5958
|
-
return value;
|
|
5959
|
-
return px(calculateExpectedPx(num, unit));
|
|
4463
|
+
return isNaN(num) ? value : px(toPx(num, unit, ctx));
|
|
5960
4464
|
}
|
|
5961
|
-
function
|
|
5962
|
-
return HEIGHT_RELATED_PROPERTIES.includes(
|
|
4465
|
+
function isHeightRelated(prop) {
|
|
4466
|
+
return HEIGHT_RELATED_PROPERTIES.includes(prop);
|
|
5963
4467
|
}
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
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.
|
|
4471
|
+
*/
|
|
4472
|
+
function extractProperty(cssText, matchOffset) {
|
|
4473
|
+
const before = cssText.substring(0, matchOffset);
|
|
4474
|
+
const m = before.match(/([a-z-]+)\s*:\s*[^;{}]*$/i);
|
|
4475
|
+
return m ? m[1].toLowerCase() : '';
|
|
5968
4476
|
}
|
|
5969
|
-
function replaceInText(cssText) {
|
|
5970
|
-
return cssText.replace(
|
|
5971
|
-
// For percentage, only convert if it's a height-related property
|
|
4477
|
+
function replaceInText(cssText, ctx) {
|
|
4478
|
+
return cssText.replace(createRegex(), (match, value, unit, offset) => {
|
|
5972
4479
|
if (unit === '%') {
|
|
5973
|
-
|
|
5974
|
-
// Only convert percentage for height-related properties
|
|
5975
|
-
if (isHeightRelatedProperty(propertyName)) {
|
|
5976
|
-
return convert(value, unit);
|
|
5977
|
-
}
|
|
5978
|
-
// For width or other properties, keep original
|
|
5979
|
-
return match;
|
|
4480
|
+
return isHeightRelated(extractProperty(cssText, offset)) ? convert(value, unit, ctx) : match;
|
|
5980
4481
|
}
|
|
5981
|
-
return convert(value, unit);
|
|
4482
|
+
return convert(value, unit, ctx);
|
|
5982
4483
|
});
|
|
5983
4484
|
}
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
return;
|
|
4485
|
+
// ─── Element tracking ─────────────────────────────────────────────────────────
|
|
4486
|
+
function trackSelector(selector, propOriginals, ctx) {
|
|
5987
4487
|
try {
|
|
5988
|
-
|
|
5989
|
-
elements.forEach((el) => {
|
|
4488
|
+
ctx.doc.querySelectorAll(selector).forEach((el) => {
|
|
5990
4489
|
elementsWithViewportUnits.add(el);
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
originalValues.set(el, elementOriginals);
|
|
4490
|
+
let originals = originalValues.get(el);
|
|
4491
|
+
if (!originals) {
|
|
4492
|
+
originals = new Map();
|
|
4493
|
+
originalValues.set(el, originals);
|
|
5996
4494
|
}
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
elementOriginals.set(prop, value);
|
|
6001
|
-
}
|
|
4495
|
+
propOriginals.forEach((v, k) => {
|
|
4496
|
+
if (!originals.has(k))
|
|
4497
|
+
originals.set(k, v);
|
|
6002
4498
|
});
|
|
6003
|
-
|
|
6004
|
-
trackElement(el, propertyOriginalValues);
|
|
4499
|
+
trackElement(el, propOriginals);
|
|
6005
4500
|
});
|
|
6006
4501
|
}
|
|
6007
|
-
catch
|
|
6008
|
-
|
|
6009
|
-
logger$1.warn('Invalid selector, skipping:', selector, error);
|
|
4502
|
+
catch {
|
|
4503
|
+
logger$4.warn('Invalid selector, skipping:', selector);
|
|
6010
4504
|
}
|
|
6011
4505
|
}
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
return;
|
|
6015
|
-
void doc.body.offsetHeight;
|
|
6016
|
-
}
|
|
6017
|
-
function getFinalHeight() {
|
|
6018
|
-
if (!doc)
|
|
6019
|
-
return 1000;
|
|
6020
|
-
triggerReflow();
|
|
6021
|
-
return Math.max(doc.body?.scrollHeight || 0, doc.body?.offsetHeight || 0, doc.documentElement?.scrollHeight || 0, doc.documentElement?.offsetHeight || 0, doc.documentElement?.clientHeight || 0);
|
|
6022
|
-
}
|
|
6023
|
-
function getFinalWidth() {
|
|
6024
|
-
if (!doc)
|
|
6025
|
-
return 1000;
|
|
6026
|
-
return Math.max(doc.body?.scrollWidth || 0, doc.body?.offsetWidth || 0, doc.documentElement?.scrollWidth || 0, doc.documentElement?.offsetWidth || 0, doc.documentElement?.clientWidth || 0);
|
|
6027
|
-
}
|
|
6028
|
-
// ============================================================================
|
|
6029
|
-
// Processing Functions
|
|
6030
|
-
// ============================================================================
|
|
6031
|
-
function processInlineStyles() {
|
|
6032
|
-
if (!doc)
|
|
6033
|
-
return 0;
|
|
4506
|
+
// ─── CSS processing ───────────────────────────────────────────────────────────
|
|
4507
|
+
function processInlineStyles(ctx) {
|
|
6034
4508
|
let count = 0;
|
|
6035
|
-
doc.querySelectorAll('[style]').forEach((el) => {
|
|
4509
|
+
ctx.doc.querySelectorAll('[style]').forEach((el) => {
|
|
6036
4510
|
const style = el.getAttribute('style');
|
|
6037
|
-
if (style &&
|
|
6038
|
-
regex.lastIndex = 0;
|
|
6039
|
-
// Track this element before replacing
|
|
4511
|
+
if (style && createRegex().test(style)) {
|
|
6040
4512
|
elementsWithViewportUnits.add(el);
|
|
6041
|
-
el.setAttribute('style', replaceInText(style));
|
|
4513
|
+
el.setAttribute('style', replaceInText(style, ctx));
|
|
6042
4514
|
count++;
|
|
6043
4515
|
}
|
|
6044
4516
|
});
|
|
6045
|
-
logger$
|
|
4517
|
+
logger$4.log(`Replaced ${count} inline style elements`);
|
|
6046
4518
|
return count;
|
|
6047
4519
|
}
|
|
6048
|
-
function processStyleTags() {
|
|
6049
|
-
if (!doc)
|
|
6050
|
-
return 0;
|
|
4520
|
+
function processStyleTags(ctx) {
|
|
6051
4521
|
let count = 0;
|
|
6052
|
-
doc.querySelectorAll('style').forEach((tag) => {
|
|
4522
|
+
ctx.doc.querySelectorAll('style').forEach((tag) => {
|
|
6053
4523
|
const css = tag.textContent || '';
|
|
6054
|
-
if (
|
|
6055
|
-
|
|
6056
|
-
tag.textContent = replaceInText(css);
|
|
4524
|
+
if (createRegex().test(css)) {
|
|
4525
|
+
tag.textContent = replaceInText(css, ctx);
|
|
6057
4526
|
count++;
|
|
6058
4527
|
}
|
|
6059
4528
|
});
|
|
6060
|
-
logger$
|
|
4529
|
+
logger$4.log(`Replaced ${count} <style> tags`);
|
|
6061
4530
|
return count;
|
|
6062
4531
|
}
|
|
6063
|
-
function processRule(rule) {
|
|
4532
|
+
function processRule(rule, ctx) {
|
|
6064
4533
|
let count = 0;
|
|
6065
4534
|
if ('style' in rule && rule.style) {
|
|
6066
4535
|
const cssRule = rule;
|
|
6067
4536
|
const style = cssRule.style;
|
|
6068
|
-
let
|
|
6069
|
-
const
|
|
4537
|
+
let hasVp = false;
|
|
4538
|
+
const propOriginals = new Map();
|
|
6070
4539
|
for (let i = 0; i < style.length; i++) {
|
|
6071
4540
|
const prop = style[i];
|
|
6072
4541
|
const value = style.getPropertyValue(prop);
|
|
6073
|
-
if (value &&
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
propertyOriginalValues.set(prop, value);
|
|
6078
|
-
style.setProperty(prop, replaceInText(value), style.getPropertyPriority(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));
|
|
6079
4546
|
count++;
|
|
6080
4547
|
}
|
|
6081
4548
|
}
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
trackOriginalValuesForSelector(cssRule.selectorText, propertyOriginalValues);
|
|
6085
|
-
}
|
|
4549
|
+
if (hasVp && cssRule.selectorText)
|
|
4550
|
+
trackSelector(cssRule.selectorText, propOriginals, ctx);
|
|
6086
4551
|
}
|
|
6087
4552
|
if ('cssRules' in rule) {
|
|
6088
|
-
const
|
|
6089
|
-
|
|
6090
|
-
count += processRule(r);
|
|
4553
|
+
for (const r of Array.from(rule.cssRules || [])) {
|
|
4554
|
+
count += processRule(r, ctx);
|
|
6091
4555
|
}
|
|
6092
4556
|
}
|
|
6093
4557
|
return count;
|
|
6094
4558
|
}
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
return 0;
|
|
6098
|
-
const windowOrigin = win.location.origin;
|
|
4559
|
+
/** Processes only inline <style> sheets. Linked sheets are handled by processLinkedStylesheets. */
|
|
4560
|
+
function processStylesheets(ctx) {
|
|
6099
4561
|
let total = 0;
|
|
6100
|
-
Array.from(doc.styleSheets).forEach((sheet) => {
|
|
4562
|
+
Array.from(ctx.doc.styleSheets).forEach((sheet) => {
|
|
4563
|
+
if (sheet.href)
|
|
4564
|
+
return; // deferred to processLinkedStylesheets
|
|
6101
4565
|
try {
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
logger$1.log('Skipping external CSS:', sheet.href);
|
|
6105
|
-
return;
|
|
6106
|
-
}
|
|
6107
|
-
const rules = sheet.cssRules || sheet.rules;
|
|
6108
|
-
if (!rules)
|
|
6109
|
-
return;
|
|
6110
|
-
for (const rule of Array.from(rules)) {
|
|
6111
|
-
total += processRule(rule);
|
|
4566
|
+
for (const rule of Array.from(sheet.cssRules || [])) {
|
|
4567
|
+
total += processRule(rule, ctx);
|
|
6112
4568
|
}
|
|
6113
4569
|
}
|
|
6114
4570
|
catch (e) {
|
|
6115
|
-
logger$
|
|
4571
|
+
logger$4.warn('Cannot read stylesheet (CORS?):', e.message);
|
|
6116
4572
|
}
|
|
6117
4573
|
});
|
|
6118
|
-
logger$
|
|
4574
|
+
logger$4.log(`Replaced ${total} rules in inline stylesheets`);
|
|
6119
4575
|
return total;
|
|
6120
4576
|
}
|
|
6121
|
-
async function processLinkedStylesheets() {
|
|
6122
|
-
|
|
6123
|
-
return 0;
|
|
6124
|
-
const links = doc.querySelectorAll('link[rel="stylesheet"]');
|
|
4577
|
+
async function processLinkedStylesheets(ctx) {
|
|
4578
|
+
const links = ctx.doc.querySelectorAll('link[rel="stylesheet"]');
|
|
6125
4579
|
let count = 0;
|
|
6126
4580
|
for (const link of Array.from(links)) {
|
|
6127
|
-
|
|
6128
|
-
|
|
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);
|
|
6129
4584
|
continue;
|
|
6130
4585
|
}
|
|
6131
4586
|
try {
|
|
6132
4587
|
const res = await fetch(link.href);
|
|
6133
4588
|
let css = await res.text();
|
|
6134
|
-
if (
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
const style = doc.createElement('style');
|
|
4589
|
+
if (createRegex().test(css)) {
|
|
4590
|
+
css = replaceInText(css, ctx);
|
|
4591
|
+
const style = ctx.doc.createElement('style');
|
|
6138
4592
|
style.textContent = css;
|
|
6139
4593
|
style.dataset.originalHref = link.href;
|
|
6140
4594
|
link.parentNode?.insertBefore(style, link);
|
|
@@ -6143,17 +4597,463 @@ async function processLinkedStylesheets() {
|
|
|
6143
4597
|
}
|
|
6144
4598
|
}
|
|
6145
4599
|
catch (e) {
|
|
6146
|
-
logger$
|
|
4600
|
+
logger$4.warn('Cannot load CSS:', link.href, e);
|
|
6147
4601
|
}
|
|
6148
4602
|
}
|
|
6149
|
-
logger$
|
|
4603
|
+
logger$4.log(`Replaced ${count} linked CSS files`);
|
|
6150
4604
|
return count;
|
|
6151
4605
|
}
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
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
|
+
}
|
|
4622
|
+
|
|
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
|
+
/**
|
|
4634
|
+
* GemPages v7 Slider Fix
|
|
4635
|
+
*
|
|
4636
|
+
* At DOM snapshot time the slider library has already computed pixel values on each
|
|
4637
|
+
* `.gem-slider-item` based on the original viewport width:
|
|
4638
|
+
* - `min-width` / `max-width` are fixed px (e.g. 2288px or 278px)
|
|
4639
|
+
* - `transform: translate3d(X, 0, 0)` offsets are derived from those widths
|
|
4640
|
+
*
|
|
4641
|
+
* Since we capture HTML+CSS without scripts, the library cannot re-initialize,
|
|
4642
|
+
* so we fix the widths and rescale the transforms manually.
|
|
4643
|
+
*
|
|
4644
|
+
* Two slider variants:
|
|
4645
|
+
*
|
|
4646
|
+
* 1. Full-width (1 item per view):
|
|
4647
|
+
* min-width = originalViewportWidth → newItemWidth = targetWidth
|
|
4648
|
+
*
|
|
4649
|
+
* 2. Multi-item (N items per view):
|
|
4650
|
+
* CSS var `--minw: calc(100% / N - Gpx)` encodes the formula.
|
|
4651
|
+
* newItemWidth = targetWidth / N - G
|
|
4652
|
+
*
|
|
4653
|
+
* In both cases: scale = newItemWidth / originalItemWidth
|
|
4654
|
+
* Transforms are rescaled proportionally (only when X ≠ 0).
|
|
4655
|
+
*/
|
|
4656
|
+
const SLIDER_ITEM_SELECTOR = '.gem-slider-item';
|
|
4657
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
4658
|
+
function parseTranslate3d(transform) {
|
|
4659
|
+
const match = transform.match(/translate3d\(\s*([-\d.]+)px\s*,\s*([-\d.]+)px\s*,\s*([-\d.]+)px\s*\)/);
|
|
4660
|
+
if (!match)
|
|
4661
|
+
return null;
|
|
4662
|
+
return { x: parseFloat(match[1]), y: parseFloat(match[2]), z: parseFloat(match[3]) };
|
|
4663
|
+
}
|
|
4664
|
+
/**
|
|
4665
|
+
* Parse `calc(100% / N - Gpx)` and evaluate against containerWidth.
|
|
4666
|
+
* Returns null if the format doesn't match.
|
|
4667
|
+
*/
|
|
4668
|
+
function parseCalcFraction(cssValue, containerWidth) {
|
|
4669
|
+
const match = cssValue.match(/calc\(\s*100%\s*\/\s*([\d.]+)\s*-\s*([\d.]+)px\s*\)/);
|
|
4670
|
+
if (!match)
|
|
4671
|
+
return null;
|
|
4672
|
+
const itemsPerRow = parseFloat(match[1]);
|
|
4673
|
+
const gap = parseFloat(match[2]);
|
|
4674
|
+
if (!itemsPerRow)
|
|
4675
|
+
return null;
|
|
4676
|
+
return containerWidth / itemsPerRow - gap;
|
|
4677
|
+
}
|
|
4678
|
+
/**
|
|
4679
|
+
* Determine the correct item width at the new targetWidth.
|
|
4680
|
+
*
|
|
4681
|
+
* Priority:
|
|
4682
|
+
* 1. `--minw` CSS custom property → extract formula and re-evaluate
|
|
4683
|
+
* 2. `--maxw` CSS custom property → same
|
|
4684
|
+
* 3. Fallback: targetWidth (full-width single-item slider)
|
|
4685
|
+
*/
|
|
4686
|
+
function resolveNewItemWidth(item, targetWidth) {
|
|
4687
|
+
for (const varName of ['--minw', '--maxw']) {
|
|
4688
|
+
const cssVar = item.style.getPropertyValue(varName).trim();
|
|
4689
|
+
if (!cssVar)
|
|
4690
|
+
continue;
|
|
4691
|
+
const calculated = parseCalcFraction(cssVar, targetWidth);
|
|
4692
|
+
if (calculated !== null && calculated > 0)
|
|
4693
|
+
return calculated;
|
|
4694
|
+
}
|
|
4695
|
+
return targetWidth;
|
|
4696
|
+
}
|
|
4697
|
+
function getDeviceType(deviceType) {
|
|
4698
|
+
switch (deviceType) {
|
|
4699
|
+
case EDeviceType.Mobile:
|
|
4700
|
+
return '-mobile';
|
|
4701
|
+
case EDeviceType.Tablet:
|
|
4702
|
+
return '-tablet';
|
|
4703
|
+
default:
|
|
4704
|
+
return '';
|
|
4705
|
+
}
|
|
4706
|
+
}
|
|
4707
|
+
function getMinWByDeviceType(deviceType) {
|
|
4708
|
+
return `--minw${getDeviceType(deviceType)}`;
|
|
4709
|
+
}
|
|
4710
|
+
function getMaxWByDeviceType(deviceType) {
|
|
4711
|
+
return `--maxw${getDeviceType(deviceType)}`;
|
|
4712
|
+
}
|
|
4713
|
+
// ─── Main fix ─────────────────────────────────────────────────────────────────
|
|
4714
|
+
function afterProcess$1({ doc, targetWidth, deviceType }) {
|
|
4715
|
+
doc.querySelectorAll(SLIDER_ITEM_SELECTOR).forEach((item) => {
|
|
4716
|
+
const originalWidth = parseFloat(item.style.minWidth) || parseFloat(item.style.maxWidth) || 0;
|
|
4717
|
+
if (!originalWidth)
|
|
4718
|
+
return;
|
|
4719
|
+
const newItemWidth = resolveNewItemWidth(item, targetWidth);
|
|
4720
|
+
if (newItemWidth === originalWidth)
|
|
4721
|
+
return;
|
|
4722
|
+
const minWVarName = getMinWByDeviceType(deviceType);
|
|
4723
|
+
const maxWVarName = getMaxWByDeviceType(deviceType);
|
|
4724
|
+
const newMinWidthByVar = `var(${minWVarName}, ${newItemWidth.toFixed(2)}px)`;
|
|
4725
|
+
const newMaxWidthByVar = `var(${maxWVarName}, ${newItemWidth.toFixed(2)}px)`;
|
|
4726
|
+
item.style.setProperty('min-width', newMinWidthByVar, 'important');
|
|
4727
|
+
item.style.setProperty('max-width', newMaxWidthByVar, 'important');
|
|
4728
|
+
const translate = parseTranslate3d(item.style.transform);
|
|
4729
|
+
const translateX = 0 - (translate?.x ?? 0);
|
|
4730
|
+
if (translate && translateX !== 0 && translateX > targetWidth) {
|
|
4731
|
+
const newX = `calc(1px - ${newMinWidthByVar})`;
|
|
4732
|
+
item.style.setProperty('transform', `translate3d(${newX}, ${translate.y}px, ${translate.z}px)`, 'important');
|
|
4733
|
+
}
|
|
4734
|
+
});
|
|
4735
|
+
}
|
|
4736
|
+
|
|
4737
|
+
register$1({
|
|
4738
|
+
name: 'gp-v7-slider',
|
|
4739
|
+
description: 'GemPages v7 slider: rescale .gem-slider-item min/max-width and translate3d X to match targetWidth',
|
|
4740
|
+
shouldApply: ({ doc }) => !!doc.querySelector('.gem-slider-item'),
|
|
4741
|
+
afterProcess: afterProcess$1,
|
|
4742
|
+
});
|
|
4743
|
+
|
|
4744
|
+
const HERO_BANNER_SELECTOR = '#MainContent .hero-wrapper .hero';
|
|
4745
|
+
const shouldApply = ({ doc }) => !!doc.querySelector(HERO_BANNER_SELECTOR);
|
|
4746
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
4747
|
+
/** Parse a raw CSS value like "65svh" → 65. Returns null if not svh. */
|
|
4748
|
+
function parseSvhPct(value) {
|
|
4749
|
+
const match = value.trim().match(/^([\d.]+)svh$/i);
|
|
4750
|
+
return match ? parseFloat(match[1]) : null;
|
|
4751
|
+
}
|
|
4752
|
+
/**
|
|
4753
|
+
* Get an svh percentage from a CSS property on an element.
|
|
4754
|
+
* If the inline value is a `var(--xxx)` reference, resolve it via getComputedStyle.
|
|
4755
|
+
*/
|
|
4756
|
+
function resolveSvhPct(hero, cssProp, win) {
|
|
4757
|
+
let value = hero.style.getPropertyValue(cssProp).trim();
|
|
4758
|
+
// Inline value is a var() reference → resolve via computed style
|
|
4759
|
+
if (value.startsWith('var(')) {
|
|
4760
|
+
const varName = value.match(/var\(\s*(--[\w-]+)/)?.[1];
|
|
4761
|
+
if (varName) {
|
|
4762
|
+
value = win.getComputedStyle(hero).getPropertyValue(varName).trim();
|
|
4763
|
+
}
|
|
4764
|
+
}
|
|
4765
|
+
return parseSvhPct(value);
|
|
4766
|
+
}
|
|
4767
|
+
function applyHeight(hero, px) {
|
|
4768
|
+
// hero.style.setProperty('height', px, 'important');
|
|
4769
|
+
hero.style.setProperty('min-height', px, 'important');
|
|
4770
|
+
}
|
|
4771
|
+
// ─── Main fix ─────────────────────────────────────────────────────────────────
|
|
4772
|
+
/**
|
|
4773
|
+
* Hero banners that use `svh` for height are sized against the browser viewport
|
|
4774
|
+
* (`win.innerHeight`), not against our `targetHeight`. This fix converts the svh
|
|
4775
|
+
* value to the correct pixel value based on `targetHeight`.
|
|
4776
|
+
*
|
|
4777
|
+
* Two cases:
|
|
4778
|
+
* 1. Inline style still contains a raw `svh` value → direct conversion.
|
|
4779
|
+
* 2. Cross-origin CSS (not processable by viewport-unit-replacer); the browser
|
|
4780
|
+
* has already resolved `svh` to px using `win.innerHeight` → rescale by ratio.
|
|
4781
|
+
*/
|
|
4782
|
+
function afterProcess({ doc, win, targetHeight }) {
|
|
4783
|
+
const browserViewportHeight = win.innerHeight || doc.documentElement.clientHeight;
|
|
4784
|
+
try {
|
|
4785
|
+
const heroBanners = doc.querySelectorAll(HERO_BANNER_SELECTOR);
|
|
4786
|
+
const listHero = Array.from(heroBanners);
|
|
4787
|
+
listHero.forEach((hero) => {
|
|
4788
|
+
// Case 1: inline style has a raw svh value or a var() reference resolving to svh
|
|
4789
|
+
const svhPct = resolveSvhPct(hero, '--hero-min-height', win);
|
|
4790
|
+
if (svhPct !== null) {
|
|
4791
|
+
const newHeight = `${((svhPct / 100) * targetHeight).toFixed(2)}px`;
|
|
4792
|
+
applyHeight(hero, newHeight);
|
|
4793
|
+
return;
|
|
4794
|
+
}
|
|
4795
|
+
// Case 2: browser already resolved svh → px via win.innerHeight, rescale
|
|
4796
|
+
if (!browserViewportHeight || browserViewportHeight === targetHeight)
|
|
4797
|
+
return;
|
|
4798
|
+
const browserMinHeight = parseFloat(win.getComputedStyle(hero).minHeight);
|
|
4799
|
+
if (!browserMinHeight || isNaN(browserMinHeight))
|
|
4800
|
+
return;
|
|
4801
|
+
applyHeight(hero, `${((browserMinHeight / browserViewportHeight) * targetHeight).toFixed(2)}px`);
|
|
4802
|
+
});
|
|
4803
|
+
}
|
|
4804
|
+
catch (error) {
|
|
4805
|
+
console.error(`Hero banner: afterProcess:`, error);
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
|
|
4809
|
+
register$1({
|
|
4810
|
+
name: 'theme-dawn-hero-banner',
|
|
4811
|
+
description: 'Shopify hero banner: height image is svh',
|
|
4812
|
+
shouldApply,
|
|
4813
|
+
afterProcess,
|
|
4814
|
+
});
|
|
4815
|
+
|
|
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
|
+
/**
|
|
4834
|
+
* Default iframe dimension calculation.
|
|
4835
|
+
* Used as fallback when no fix overrides getDimensions().
|
|
4836
|
+
*/
|
|
4837
|
+
function getFinalHeight(doc, win) {
|
|
4838
|
+
void doc.body.offsetHeight; // trigger reflow
|
|
4839
|
+
const bodyMinHeight = parseFloat(win.getComputedStyle(doc.body).minHeight) || 0;
|
|
4840
|
+
const htmlMinHeight = parseFloat(win.getComputedStyle(doc.documentElement).minHeight) || 0;
|
|
4841
|
+
return Math.max(doc.body?.scrollHeight || 0, doc.body?.offsetHeight || 0, doc.documentElement?.scrollHeight || 0, doc.documentElement?.offsetHeight || 0, doc.documentElement?.clientHeight || 0, bodyMinHeight, htmlMinHeight);
|
|
4842
|
+
}
|
|
4843
|
+
function getFinalWidth(doc) {
|
|
4844
|
+
return Math.max(doc.body?.scrollWidth || 0, doc.body?.offsetWidth || 0, doc.documentElement?.scrollWidth || 0, doc.documentElement?.offsetWidth || 0, doc.documentElement?.clientWidth || 0);
|
|
4845
|
+
}
|
|
4846
|
+
|
|
4847
|
+
/**
|
|
4848
|
+
* Viewport fix pipeline runner.
|
|
4849
|
+
*
|
|
4850
|
+
* Executes the 4-phase pipeline for a given context:
|
|
4851
|
+
* Phase 1: beforeProcess (global → shop)
|
|
4852
|
+
* Phase 2: process (global fixes)
|
|
4853
|
+
* Phase 3: afterProcess (shop → global)
|
|
4854
|
+
* Phase 4: getDimensions (shop → global → default)
|
|
4855
|
+
*/
|
|
4856
|
+
const logger$2 = createLogger({ enabled: false, prefix: 'ViewportReplacer' });
|
|
4857
|
+
function configure(debug) {
|
|
4858
|
+
logger$2.configure({ enabled: debug });
|
|
4859
|
+
}
|
|
4860
|
+
async function run$1(ctx, activeGlobal, shopFix) {
|
|
4861
|
+
// ── Phase 1: beforeProcess ────────────────────────────────────────────────
|
|
4862
|
+
for (const fix of activeGlobal) {
|
|
4863
|
+
if (fix.beforeProcess) {
|
|
4864
|
+
logger$2.log(`[beforeProcess] ${fix.name}`);
|
|
4865
|
+
await fix.beforeProcess(ctx);
|
|
4866
|
+
}
|
|
4867
|
+
}
|
|
4868
|
+
if (shopFix?.beforeProcess) {
|
|
4869
|
+
logger$2.log('[beforeProcess] shop');
|
|
4870
|
+
await shopFix.beforeProcess(ctx);
|
|
4871
|
+
}
|
|
4872
|
+
// ── Phase 2: process ──────────────────────────────────────────────────────
|
|
4873
|
+
for (const fix of activeGlobal) {
|
|
4874
|
+
if (fix.process) {
|
|
4875
|
+
logger$2.log(`[process] ${fix.name}`);
|
|
4876
|
+
await fix.process(ctx);
|
|
4877
|
+
}
|
|
4878
|
+
}
|
|
4879
|
+
// ── Phase 3: afterProcess ─────────────────────────────────────────────────
|
|
4880
|
+
if (shopFix?.afterProcess) {
|
|
4881
|
+
logger$2.log('[afterProcess] shop');
|
|
4882
|
+
await shopFix.afterProcess(ctx);
|
|
4883
|
+
}
|
|
4884
|
+
for (const fix of activeGlobal) {
|
|
4885
|
+
if (fix.afterProcess) {
|
|
4886
|
+
logger$2.log(`[afterProcess] ${fix.name}`);
|
|
4887
|
+
await fix.afterProcess(ctx);
|
|
4888
|
+
}
|
|
4889
|
+
}
|
|
4890
|
+
// ── Phase 4: getDimensions ────────────────────────────────────────────────
|
|
4891
|
+
return new Promise((resolve) => {
|
|
4892
|
+
requestAnimationFrame(() => {
|
|
4893
|
+
let dimensions = null;
|
|
4894
|
+
// Priority: shop → global → default
|
|
4895
|
+
if (shopFix?.getDimensions) {
|
|
4896
|
+
dimensions = shopFix.getDimensions(ctx);
|
|
4897
|
+
if (dimensions)
|
|
4898
|
+
logger$2.log('Dimensions from shop fix:', dimensions);
|
|
4899
|
+
}
|
|
4900
|
+
if (!dimensions) {
|
|
4901
|
+
for (const fix of activeGlobal) {
|
|
4902
|
+
if (fix.getDimensions) {
|
|
4903
|
+
dimensions = fix.getDimensions(ctx);
|
|
4904
|
+
if (dimensions) {
|
|
4905
|
+
logger$2.log(`Dimensions from global fix [${fix.name}]:`, dimensions);
|
|
4906
|
+
break;
|
|
4907
|
+
}
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
if (!dimensions) {
|
|
4912
|
+
dimensions = { height: getFinalHeight(ctx.doc, ctx.win), width: getFinalWidth(ctx.doc) };
|
|
4913
|
+
}
|
|
4914
|
+
logger$2.log('Final dimensions:', dimensions);
|
|
4915
|
+
resolve(dimensions);
|
|
4916
|
+
});
|
|
4917
|
+
});
|
|
4918
|
+
}
|
|
4919
|
+
|
|
4920
|
+
const registry = new Map();
|
|
4921
|
+
/**
|
|
4922
|
+
* Register a viewport fix for a specific shop.
|
|
4923
|
+
* Accepts a numeric shop ID or a myshopify domain string.
|
|
4924
|
+
*
|
|
4925
|
+
* @example
|
|
4926
|
+
* register(1234, { description: 'Fix for My Shop', extraIgnoreSelectors: ['.hero'] });
|
|
4927
|
+
* register('my-shop.myshopify.com', { afterProcess: ({ doc }) => { ... } });
|
|
4928
|
+
*/
|
|
4929
|
+
function register(shopId, fix) {
|
|
4930
|
+
if (registry.has(shopId)) {
|
|
4931
|
+
console.warn(`[ViewportShopFixes] Fix for shop "${shopId}" already registered — overwriting.`);
|
|
4932
|
+
}
|
|
4933
|
+
registry.set(shopId, fix);
|
|
4934
|
+
}
|
|
4935
|
+
function get(shopId) {
|
|
4936
|
+
return registry.get(shopId) ?? null;
|
|
4937
|
+
}
|
|
4938
|
+
|
|
4939
|
+
/**
|
|
4940
|
+
* Shop 566240210141053597
|
|
4941
|
+
*
|
|
4942
|
+
* Known issues:
|
|
4943
|
+
* - The hero section uses `height: 100vh` with a sticky internal element that
|
|
4944
|
+
* overflows the layout after viewport unit conversion → clamp it manually.
|
|
4945
|
+
* - The mega-menu drawer holds `min-height: 100vh` which inflates the total
|
|
4946
|
+
* page height calculation → exclude it from dimension measurement.
|
|
4947
|
+
*/
|
|
4948
|
+
const HERO_SELECTOR = '#shopify-section-hero';
|
|
4949
|
+
const MEGA_MENU_SELECTOR = '.mega-menu__drawer';
|
|
4950
|
+
// ─── beforeProcess ────────────────────────────────────────────────────────────
|
|
4951
|
+
/**
|
|
4952
|
+
* Hide the mega-menu drawer before processing so it doesn't affect layout.
|
|
4953
|
+
* It will be restored in afterProcess.
|
|
4954
|
+
*/
|
|
4955
|
+
function hideMegaMenuDrawer({ doc }) {
|
|
4956
|
+
const drawer = doc.querySelector(MEGA_MENU_SELECTOR);
|
|
4957
|
+
if (!drawer)
|
|
4958
|
+
return;
|
|
4959
|
+
drawer.dataset.originalDisplay = drawer.style.display;
|
|
4960
|
+
drawer.style.setProperty('display', 'none', 'important');
|
|
4961
|
+
}
|
|
4962
|
+
// ─── afterProcess ─────────────────────────────────────────────────────────────
|
|
4963
|
+
/**
|
|
4964
|
+
* Restore mega-menu and clamp hero height to prevent overflow.
|
|
4965
|
+
*/
|
|
4966
|
+
function restoreAndFixLayout({ doc, targetHeight }) {
|
|
4967
|
+
// Restore mega-menu
|
|
4968
|
+
const drawer = doc.querySelector(MEGA_MENU_SELECTOR);
|
|
4969
|
+
if (drawer) {
|
|
4970
|
+
const original = drawer.dataset.originalDisplay ?? '';
|
|
4971
|
+
drawer.style.removeProperty('display');
|
|
4972
|
+
if (original)
|
|
4973
|
+
drawer.style.display = original;
|
|
4974
|
+
delete drawer.dataset.originalDisplay;
|
|
4975
|
+
}
|
|
4976
|
+
// Clamp hero height to targetHeight
|
|
4977
|
+
const hero = doc.querySelector(HERO_SELECTOR);
|
|
4978
|
+
if (hero) {
|
|
4979
|
+
hero.style.setProperty('height', `${targetHeight}px`, 'important');
|
|
4980
|
+
hero.style.setProperty('max-height', `${targetHeight}px`, 'important');
|
|
4981
|
+
}
|
|
4982
|
+
}
|
|
4983
|
+
|
|
4984
|
+
register(`566240210141053597`, {
|
|
4985
|
+
description: 'Hero 100vh overflow + mega-menu drawer inflates page height',
|
|
4986
|
+
extraIgnoreSelectors: ['.mega-menu__drawer'],
|
|
4987
|
+
beforeProcess: hideMegaMenuDrawer,
|
|
4988
|
+
afterProcess: restoreAndFixLayout,
|
|
4989
|
+
});
|
|
4990
|
+
|
|
4991
|
+
const logger$1 = createLogger({ enabled: false, prefix: 'ViewportReplacer' });
|
|
4992
|
+
// ─── State ────────────────────────────────────────────────────────────────────
|
|
4993
|
+
let doc = null;
|
|
4994
|
+
let win = null;
|
|
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.');
|
|
5002
|
+
return;
|
|
5003
|
+
}
|
|
5004
|
+
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
5005
|
+
throw new Error('Iframe document or window not accessible');
|
|
5006
|
+
}
|
|
5007
|
+
doc = iframe.contentDocument;
|
|
5008
|
+
win = iframe.contentWindow;
|
|
5009
|
+
config$1 = cfg;
|
|
5010
|
+
running$2 = true;
|
|
5011
|
+
shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
|
|
5012
|
+
if (shopFix) {
|
|
5013
|
+
logger$1.log(`Shop fix loaded for "${cfg.shopId}":`, shopFix.description ?? '(no description)');
|
|
5014
|
+
}
|
|
5015
|
+
logger$1.configure({ enabled: !!cfg.debug });
|
|
5016
|
+
configure(!!cfg.debug);
|
|
5017
|
+
start$4(doc, win, cfg, { debug: !!cfg.debug });
|
|
5018
|
+
attach(cfg.debug);
|
|
5019
|
+
logger$1.log('Started');
|
|
5020
|
+
}
|
|
5021
|
+
function stop$3() {
|
|
5022
|
+
if (!running$2)
|
|
5023
|
+
return;
|
|
5024
|
+
stop$4();
|
|
5025
|
+
detach();
|
|
5026
|
+
doc = null;
|
|
5027
|
+
win = null;
|
|
5028
|
+
config$1 = null;
|
|
5029
|
+
shopFix = null;
|
|
5030
|
+
running$2 = false;
|
|
5031
|
+
logger$1.log('Stopped');
|
|
5032
|
+
}
|
|
5033
|
+
async function run() {
|
|
5034
|
+
if (!running$2 || !doc || !win || !config$1) {
|
|
5035
|
+
logger$1.warn('Not running. Call start() first.');
|
|
5036
|
+
return { height: 1000, width: 1000 };
|
|
5037
|
+
}
|
|
5038
|
+
const ctx = {
|
|
5039
|
+
doc,
|
|
5040
|
+
win,
|
|
5041
|
+
deviceType: config$1.deviceType,
|
|
5042
|
+
targetWidth: config$1.targetWidth,
|
|
5043
|
+
targetHeight: config$1.targetHeight,
|
|
5044
|
+
debug: config$1.debug,
|
|
5045
|
+
};
|
|
5046
|
+
const activeGlobal = getActiveFixes(ctx);
|
|
5047
|
+
if (activeGlobal.length > 0) {
|
|
5048
|
+
logger$1.log(`Active global fixes: ${activeGlobal.map((f) => f.name).join(', ')}`);
|
|
5049
|
+
}
|
|
5050
|
+
try {
|
|
5051
|
+
return await run$1(ctx, activeGlobal, shopFix);
|
|
5052
|
+
}
|
|
5053
|
+
catch (err) {
|
|
5054
|
+
logger$1.error('Critical error:', err);
|
|
5055
|
+
return { height: doc.body?.scrollHeight || 1000, width: doc.body?.scrollWidth || 1000 };
|
|
5056
|
+
}
|
|
6157
5057
|
}
|
|
6158
5058
|
|
|
6159
5059
|
const logger = createLogger({
|
|
@@ -6215,9 +5115,8 @@ async function initialize() {
|
|
|
6215
5115
|
}
|
|
6216
5116
|
}
|
|
6217
5117
|
async function process() {
|
|
6218
|
-
if (!iframe || !config)
|
|
5118
|
+
if (!iframe || !config)
|
|
6219
5119
|
return;
|
|
6220
|
-
}
|
|
6221
5120
|
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
6222
5121
|
logger.error('Cannot access iframe document');
|
|
6223
5122
|
config.onError?.(new Error('Cannot access iframe document'));
|
|
@@ -6225,11 +5124,8 @@ async function process() {
|
|
|
6225
5124
|
}
|
|
6226
5125
|
try {
|
|
6227
5126
|
logger.log('Processing viewport units...');
|
|
6228
|
-
// Start viewport replacer
|
|
6229
5127
|
start$3(iframe, config);
|
|
6230
|
-
// Setup navigation blocker
|
|
6231
5128
|
start$5(iframe, { debug: config.debug });
|
|
6232
|
-
// Run viewport replacement
|
|
6233
5129
|
const result = await run();
|
|
6234
5130
|
logger.log('Process completed:', result);
|
|
6235
5131
|
config.onSuccess?.(result);
|
|
@@ -6266,91 +5162,30 @@ function enableNavigationBlocking$2() {
|
|
|
6266
5162
|
|
|
6267
5163
|
/**
|
|
6268
5164
|
* Iframe Helper Starter Module
|
|
6269
|
-
* Manages iframe helper initialization with event listeners
|
|
6270
5165
|
* @module start
|
|
6271
5166
|
*/
|
|
6272
5167
|
// ============================================================================
|
|
6273
5168
|
// State
|
|
6274
5169
|
// ============================================================================
|
|
6275
5170
|
let running = false;
|
|
6276
|
-
let eventListenersAttached = false;
|
|
6277
|
-
// Event listener references for cleanup
|
|
6278
|
-
let dimensionsListener = null;
|
|
6279
|
-
let navigationListener = null;
|
|
6280
|
-
let formSubmitListener = null;
|
|
6281
|
-
// ============================================================================
|
|
6282
|
-
// Helper Functions
|
|
6283
|
-
// ============================================================================
|
|
6284
|
-
function attachEventListeners() {
|
|
6285
|
-
if (eventListenersAttached) {
|
|
6286
|
-
return;
|
|
6287
|
-
}
|
|
6288
|
-
dimensionsListener = ((e) => {
|
|
6289
|
-
// console.log('[IframeHelper] Iframe dimensions finalized:', ev.detail);
|
|
6290
|
-
});
|
|
6291
|
-
navigationListener = ((e) => {
|
|
6292
|
-
// console.warn('[IframeHelper] Iframe tried to navigate to:', ev.detail.url);
|
|
6293
|
-
});
|
|
6294
|
-
formSubmitListener = ((e) => {
|
|
6295
|
-
// console.log('[IframeHelper] Iframe form submitted:', ev.detail.data);
|
|
6296
|
-
});
|
|
6297
|
-
window.addEventListener('iframe-dimensions-applied', dimensionsListener);
|
|
6298
|
-
window.addEventListener('iframe-navigation-blocked', navigationListener);
|
|
6299
|
-
window.addEventListener('iframe-form-submit', formSubmitListener);
|
|
6300
|
-
eventListenersAttached = true;
|
|
6301
|
-
}
|
|
6302
|
-
function removeEventListeners() {
|
|
6303
|
-
if (!eventListenersAttached) {
|
|
6304
|
-
return;
|
|
6305
|
-
}
|
|
6306
|
-
if (dimensionsListener) {
|
|
6307
|
-
window.removeEventListener('iframe-dimensions-applied', dimensionsListener);
|
|
6308
|
-
dimensionsListener = null;
|
|
6309
|
-
}
|
|
6310
|
-
if (navigationListener) {
|
|
6311
|
-
window.removeEventListener('iframe-navigation-blocked', navigationListener);
|
|
6312
|
-
navigationListener = null;
|
|
6313
|
-
}
|
|
6314
|
-
if (formSubmitListener) {
|
|
6315
|
-
window.removeEventListener('iframe-form-submit', formSubmitListener);
|
|
6316
|
-
formSubmitListener = null;
|
|
6317
|
-
}
|
|
6318
|
-
eventListenersAttached = false;
|
|
6319
|
-
}
|
|
6320
5171
|
// ============================================================================
|
|
6321
5172
|
// Public API
|
|
6322
5173
|
// ============================================================================
|
|
6323
|
-
/**
|
|
6324
|
-
* Start iframe helper with configuration
|
|
6325
|
-
* Initializes IframeFixer and attaches event listeners
|
|
6326
|
-
*/
|
|
6327
5174
|
function start$1(config) {
|
|
6328
5175
|
if (running) {
|
|
6329
5176
|
console.warn('[IframeHelperStarter] Already running. Call stop() first.');
|
|
6330
5177
|
return;
|
|
6331
5178
|
}
|
|
6332
|
-
// Attach global event listeners
|
|
6333
|
-
attachEventListeners();
|
|
6334
|
-
// Start iframe fixer
|
|
6335
5179
|
start$2(config);
|
|
6336
5180
|
running = true;
|
|
6337
5181
|
}
|
|
6338
|
-
/**
|
|
6339
|
-
* Stop iframe helper and cleanup
|
|
6340
|
-
*/
|
|
6341
5182
|
function stop$1() {
|
|
6342
5183
|
if (!running) {
|
|
6343
5184
|
return;
|
|
6344
5185
|
}
|
|
6345
|
-
// Stop iframe fixer
|
|
6346
5186
|
stop$2();
|
|
6347
|
-
// Remove event listeners
|
|
6348
|
-
removeEventListeners();
|
|
6349
5187
|
running = false;
|
|
6350
5188
|
}
|
|
6351
|
-
/**
|
|
6352
|
-
* Enable navigation blocking
|
|
6353
|
-
*/
|
|
6354
5189
|
function enableNavigationBlocking$1() {
|
|
6355
5190
|
if (!running) {
|
|
6356
5191
|
console.warn('[IframeHelperStarter] Not running. Call start() first.');
|
|
@@ -6374,11 +5209,12 @@ function useVizLiveRender() {
|
|
|
6374
5209
|
const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
|
|
6375
5210
|
const wrapperWidth = useHeatmapVizRectContext((s) => s.wrapperWidth);
|
|
6376
5211
|
const setIsRenderViz = useHeatmapVizContext((s) => s.setIsRenderViz);
|
|
6377
|
-
const
|
|
6378
|
-
const
|
|
6379
|
-
const
|
|
6380
|
-
const renderMode = useHeatmapLiveStore((
|
|
6381
|
-
const storefrontPassword = useHeatmapLiveStore((
|
|
5212
|
+
const htmlContent = useHeatmapLiveStore((s) => s.htmlContent);
|
|
5213
|
+
const targetUrl = useHeatmapLiveStore((s) => s.targetUrl);
|
|
5214
|
+
const deviceType = useHeatmapSettingContext((s) => s.deviceType);
|
|
5215
|
+
const renderMode = useHeatmapLiveStore((s) => s.renderMode);
|
|
5216
|
+
const storefrontPassword = useHeatmapLiveStore((s) => s.storefrontPassword);
|
|
5217
|
+
useHeatmapWidthByDevice();
|
|
6382
5218
|
const { iframeRef, isReady } = useVizLiveIframeMsg();
|
|
6383
5219
|
// Handle iframe rendering based on mode
|
|
6384
5220
|
useEffect(() => {
|
|
@@ -6419,14 +5255,14 @@ function useVizLiveRender() {
|
|
|
6419
5255
|
if (!iframe || !hasContent)
|
|
6420
5256
|
return;
|
|
6421
5257
|
setIsRenderViz(true);
|
|
6422
|
-
initIframeHelper$1(iframe, { width: wrapperWidth, height: wrapperHeight }, (height) => {
|
|
5258
|
+
initIframeHelper$1(iframe, deviceType, { width: wrapperWidth, height: wrapperHeight }, (height) => {
|
|
6423
5259
|
height && setIframeHeight(height);
|
|
6424
5260
|
setIsRenderViz(true);
|
|
6425
5261
|
});
|
|
6426
5262
|
return () => { };
|
|
6427
5263
|
}, [
|
|
6428
5264
|
isReady,
|
|
6429
|
-
|
|
5265
|
+
deviceType,
|
|
6430
5266
|
wrapperHeight,
|
|
6431
5267
|
wrapperWidth,
|
|
6432
5268
|
renderMode,
|
|
@@ -6452,9 +5288,10 @@ function buildPortalUrl(targetUrl, storefrontPassword) {
|
|
|
6452
5288
|
const portalServiceUrl = getPortalServiceUrl();
|
|
6453
5289
|
return `${portalServiceUrl}/?${params.toString()}`;
|
|
6454
5290
|
}
|
|
6455
|
-
function initIframeHelper$1(iframe, rect, onSuccess) {
|
|
5291
|
+
function initIframeHelper$1(iframe, deviceType = EDeviceType.Desktop, rect, onSuccess) {
|
|
6456
5292
|
stop();
|
|
6457
5293
|
start({
|
|
5294
|
+
deviceType: deviceType,
|
|
6458
5295
|
targetWidth: rect.width,
|
|
6459
5296
|
targetHeight: rect.height,
|
|
6460
5297
|
iframe: iframe,
|
|
@@ -6677,24 +5514,17 @@ class AttentionMapRenderer {
|
|
|
6677
5514
|
|
|
6678
5515
|
class GXVisualizer extends Visualizer {
|
|
6679
5516
|
attentionMap;
|
|
6680
|
-
originalHtml;
|
|
6681
5517
|
originalClearmap;
|
|
6682
5518
|
originalSetup;
|
|
6683
5519
|
constructor() {
|
|
6684
5520
|
super();
|
|
6685
5521
|
this.attentionMap = new AttentionMapRenderer(null);
|
|
6686
5522
|
// Save references to base implementations before overriding
|
|
6687
|
-
this.originalHtml = this.html;
|
|
6688
|
-
this.originalClearmap = this.clearmap;
|
|
6689
5523
|
this.originalSetup = this.setup;
|
|
6690
|
-
this.
|
|
5524
|
+
this.originalClearmap = this.clearmap;
|
|
6691
5525
|
this.clearmap = this.clearmapOverride;
|
|
6692
5526
|
this.setup = this.setupOverride;
|
|
6693
5527
|
}
|
|
6694
|
-
htmlOverride = async (decoded, target, portalCanvasId, hash, useproxy, logerror, shortCircuitStrategy) => {
|
|
6695
|
-
await this.originalHtml(decoded, target, portalCanvasId, hash, useproxy, logerror, shortCircuitStrategy);
|
|
6696
|
-
return this;
|
|
6697
|
-
};
|
|
6698
5528
|
setupOverride = async (target, options) => {
|
|
6699
5529
|
// Clear existing custom renderers before re-initializing (null-safe)
|
|
6700
5530
|
this.attentionMap?.clear();
|
|
@@ -6728,8 +5558,13 @@ const useHeatmapRender = () => {
|
|
|
6728
5558
|
const setVizRef = useHeatmapVizRectContext((s) => s.setVizRef);
|
|
6729
5559
|
const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
|
|
6730
5560
|
const setIsRenderViz = useHeatmapVizContext((s) => s.setIsRenderViz);
|
|
5561
|
+
const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
|
|
5562
|
+
const contentWidth = useHeatmapWidthByDevice();
|
|
5563
|
+
const deviceType = useHeatmapSettingContext((s) => s.deviceType);
|
|
6731
5564
|
const iframeRef = useRef(null);
|
|
6732
5565
|
const renderHeatmap = useCallback(async (payloads) => {
|
|
5566
|
+
if (contentWidth === 0 || wrapperHeight === 0)
|
|
5567
|
+
return;
|
|
6733
5568
|
if (!payloads || payloads.length === 0)
|
|
6734
5569
|
return;
|
|
6735
5570
|
const visualizer = vizRef ?? new GXVisualizer();
|
|
@@ -6740,12 +5575,13 @@ const useHeatmapRender = () => {
|
|
|
6740
5575
|
if (!iframe?.contentWindow)
|
|
6741
5576
|
return;
|
|
6742
5577
|
await visualizer.html(payloads, iframe.contentWindow, viewId);
|
|
6743
|
-
|
|
5578
|
+
const size = { width: contentWidth, height: wrapperHeight };
|
|
5579
|
+
initIframeHelper(iframe, deviceType, size, (height) => {
|
|
6744
5580
|
height && setIframeHeight(height);
|
|
6745
5581
|
setIsRenderViz(true);
|
|
6746
5582
|
});
|
|
6747
5583
|
// setIsRenderViz(true);
|
|
6748
|
-
}, []);
|
|
5584
|
+
}, [wrapperHeight, contentWidth, deviceType]);
|
|
6749
5585
|
useEffect(() => {
|
|
6750
5586
|
if (!data || data.length === 0)
|
|
6751
5587
|
return;
|
|
@@ -6754,23 +5590,23 @@ const useHeatmapRender = () => {
|
|
|
6754
5590
|
return () => {
|
|
6755
5591
|
setVizRef(null);
|
|
6756
5592
|
};
|
|
6757
|
-
}, [data]);
|
|
5593
|
+
}, [data, renderHeatmap, setVizRef]);
|
|
6758
5594
|
return {
|
|
6759
5595
|
iframeRef,
|
|
6760
5596
|
};
|
|
6761
5597
|
};
|
|
6762
|
-
function initIframeHelper(iframe,
|
|
6763
|
-
// size: { width: number; height: number },
|
|
6764
|
-
payloads, onSuccess) {
|
|
6765
|
-
const { size } = findLastSizeOfDom(payloads);
|
|
5598
|
+
function initIframeHelper(iframe, deviceType = EDeviceType.Desktop, size, onSuccess) {
|
|
6766
5599
|
const docWidth = size.width ?? 0;
|
|
6767
5600
|
const docHeight = size.height ?? 0;
|
|
5601
|
+
if (docHeight === 0)
|
|
5602
|
+
return;
|
|
6768
5603
|
stop();
|
|
6769
5604
|
start({
|
|
5605
|
+
deviceType: deviceType,
|
|
6770
5606
|
targetWidth: docWidth,
|
|
6771
5607
|
targetHeight: docHeight,
|
|
6772
5608
|
iframe: iframe,
|
|
6773
|
-
debug:
|
|
5609
|
+
debug: true,
|
|
6774
5610
|
onSuccess: (data) => {
|
|
6775
5611
|
iframe.style.height = `${data.height}px`;
|
|
6776
5612
|
onSuccess(data.height);
|
|
@@ -6779,16 +5615,6 @@ payloads, onSuccess) {
|
|
|
6779
5615
|
// fixer.recalculate();
|
|
6780
5616
|
}
|
|
6781
5617
|
|
|
6782
|
-
function isMobileDevice(userAgent) {
|
|
6783
|
-
if (!userAgent)
|
|
6784
|
-
return false;
|
|
6785
|
-
return /android|webos|iphone|ipad|ipod|blackberry|windows phone|opera mini|iemobile|mobile|silk|fennec|bada|tizen|symbian|nokia|palmsource|meego|sailfish|kindle|playbook|bb10|rim/i.test(userAgent);
|
|
6786
|
-
}
|
|
6787
|
-
|
|
6788
|
-
function sortEvents(a, b) {
|
|
6789
|
-
return a.time - b.time;
|
|
6790
|
-
}
|
|
6791
|
-
|
|
6792
5618
|
const useReplayRender = () => {
|
|
6793
5619
|
const data = useHeatmapDataContext((s) => s.data);
|
|
6794
5620
|
const setIsRenderViz = useHeatmapVizContext((s) => s.setIsRenderViz);
|
|
@@ -7190,30 +6016,6 @@ const useHeatmapScale = (props) => {
|
|
|
7190
6016
|
handleScroll,
|
|
7191
6017
|
};
|
|
7192
6018
|
};
|
|
7193
|
-
const useIframeHeight = (props) => {
|
|
7194
|
-
const { iframeRef } = props;
|
|
7195
|
-
const iframeWidth = useHeatmapWidthByDevice();
|
|
7196
|
-
const wrapperHeight = useHeatmapVizRectContext((s) => s.wrapperHeight);
|
|
7197
|
-
const setIframeHeight = useHeatmapVizRectContext((s) => s.setIframeHeight);
|
|
7198
|
-
const isRenderViz = useHeatmapVizContext((s) => s.isRenderViz);
|
|
7199
|
-
useIframeHeightProcessor({
|
|
7200
|
-
iframeRef: iframeRef,
|
|
7201
|
-
iframeWidth: iframeWidth,
|
|
7202
|
-
defaultHeight: wrapperHeight,
|
|
7203
|
-
deviceType: 1,
|
|
7204
|
-
autoProcess: true,
|
|
7205
|
-
watchHeightChanges: true,
|
|
7206
|
-
autoApplyHeight: false,
|
|
7207
|
-
shouldProcess: isRenderViz && !!wrapperHeight,
|
|
7208
|
-
onHeightChange: (height) => {
|
|
7209
|
-
setIframeHeight(height);
|
|
7210
|
-
},
|
|
7211
|
-
onProcessComplete: (result) => {
|
|
7212
|
-
console.trace(`🚀 🐥 ~ VizDomRenderer ~ result:`, result);
|
|
7213
|
-
setIframeHeight(result.height);
|
|
7214
|
-
},
|
|
7215
|
-
});
|
|
7216
|
-
};
|
|
7217
6019
|
|
|
7218
6020
|
const useWrapperRefHeight = (props) => {
|
|
7219
6021
|
const setWrapperHeight = useHeatmapVizRectContext((s) => s.setWrapperHeight);
|
|
@@ -7413,10 +6215,10 @@ const useScrollmapZones = (options) => {
|
|
|
7413
6215
|
const newZones = createZones(scrollmap);
|
|
7414
6216
|
setZones(newZones);
|
|
7415
6217
|
setIsReady(true);
|
|
7416
|
-
logger$
|
|
6218
|
+
logger$9.log(`[useScrollmap] Created ${newZones.length} zones in ${mode} mode`);
|
|
7417
6219
|
}
|
|
7418
6220
|
catch (error) {
|
|
7419
|
-
logger$
|
|
6221
|
+
logger$9.error('[useScrollmap] Error:', error);
|
|
7420
6222
|
setIsReady(false);
|
|
7421
6223
|
}
|
|
7422
6224
|
}, [enabled, scrollmap, mode, createZones]);
|
|
@@ -9109,4 +7911,4 @@ const HeatmapLayout = ({ data, clickmap, clickAreas, scrollmap, attentionMap, co
|
|
|
9109
7911
|
}
|
|
9110
7912
|
};
|
|
9111
7913
|
|
|
9112
|
-
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, useHeatmapLiveStore, useHeatmapRenderByMode, useHeatmapScale, useHeatmapScroll, useHeatmapScrollContext, useHeatmapSettingContext, useHeatmapVizContext, useHeatmapVizRectContext, useHeatmapWidthByDevice, useHoveredElement,
|
|
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, useHeatmapLiveStore, useHeatmapRenderByMode, useHeatmapScale, useHeatmapScroll, useHeatmapScrollContext, useHeatmapSettingContext, useHeatmapVizContext, useHeatmapVizRectContext, useHeatmapWidthByDevice, useHoveredElement, useMeasureFunction, useRegisterConfig, useRegisterControl, useRegisterData, useRegisterHeatmap, useRenderCount, useScrollmapZones, useTrackHookCall, useViewIdContext, useVizLiveRender, useWhyDidYouUpdate, useWrapperRefHeight, useZonePositions, withPerformanceTracking };
|