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