@gemx-dev/heatmap-react 3.5.92-dev.34 → 3.5.92-dev.36
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/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
- package/dist/esm/hooks/viz-render/useHeatmapIframeProcessor.d.ts.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +549 -562
- package/dist/esm/index.mjs +549 -562
- package/dist/esm/libs/iframe-processor/index.d.ts +1 -0
- package/dist/esm/libs/iframe-processor/index.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/lifecycle.d.ts +3 -3
- package/dist/esm/libs/iframe-processor/lifecycle.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/orchestrator.d.ts +2 -2
- package/dist/esm/libs/iframe-processor/orchestrator.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/height-observer/index.d.ts +1 -1
- package/dist/esm/libs/iframe-processor/processors/height-observer/index.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/height-observer/listeners.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/navigation/index.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/fixes.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/viewport/index.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts +8 -8
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts +1 -1
- package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts.map +1 -1
- package/dist/esm/libs/iframe-processor/shared/iframe-types.d.ts +4 -4
- package/dist/esm/libs/iframe-processor/shared/iframe-types.d.ts.map +1 -1
- package/dist/esm/libs/visualizer/GXVisualizer.d.ts +3 -3
- package/dist/esm/libs/visualizer/GXVisualizer.d.ts.map +1 -1
- package/dist/esm/libs/visualizer/index.d.ts +1 -1
- package/dist/esm/libs/visualizer/index.d.ts.map +1 -1
- package/dist/esm/libs/visualizer/renderers/ScrollBucketRenderer.d.ts +3 -22
- package/dist/esm/libs/visualizer/renderers/ScrollBucketRenderer.d.ts.map +1 -1
- package/dist/esm/libs/visualizer/renderers/index.d.ts +1 -1
- package/dist/esm/libs/visualizer/renderers/index.d.ts.map +1 -1
- package/dist/esm/types/viz-scrollmap.d.ts +8 -0
- package/dist/esm/types/viz-scrollmap.d.ts.map +1 -1
- package/dist/esm/utils/index.d.ts +1 -0
- package/dist/esm/utils/index.d.ts.map +1 -1
- package/dist/esm/utils/scrollmap.d.ts +11 -0
- package/dist/esm/utils/scrollmap.d.ts.map +1 -0
- package/dist/umd/hooks/viz-canvas/useScrollmap.d.ts.map +1 -1
- package/dist/umd/hooks/viz-render/useHeatmapIframeProcessor.d.ts.map +1 -1
- package/dist/umd/index.d.ts +1 -1
- package/dist/umd/index.d.ts.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/libs/iframe-processor/index.d.ts +1 -0
- package/dist/umd/libs/iframe-processor/index.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/lifecycle.d.ts +3 -3
- package/dist/umd/libs/iframe-processor/lifecycle.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/orchestrator.d.ts +2 -2
- package/dist/umd/libs/iframe-processor/orchestrator.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/height-observer/index.d.ts +1 -1
- package/dist/umd/libs/iframe-processor/processors/height-observer/index.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/height-observer/listeners.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/navigation/index.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/fixes.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/viewport/index.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts +8 -8
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts +1 -1
- package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts.map +1 -1
- package/dist/umd/libs/iframe-processor/shared/iframe-types.d.ts +4 -4
- package/dist/umd/libs/iframe-processor/shared/iframe-types.d.ts.map +1 -1
- package/dist/umd/libs/visualizer/GXVisualizer.d.ts +3 -3
- package/dist/umd/libs/visualizer/GXVisualizer.d.ts.map +1 -1
- package/dist/umd/libs/visualizer/index.d.ts +1 -1
- package/dist/umd/libs/visualizer/index.d.ts.map +1 -1
- package/dist/umd/libs/visualizer/renderers/ScrollBucketRenderer.d.ts +3 -22
- package/dist/umd/libs/visualizer/renderers/ScrollBucketRenderer.d.ts.map +1 -1
- package/dist/umd/libs/visualizer/renderers/index.d.ts +1 -1
- package/dist/umd/libs/visualizer/renderers/index.d.ts.map +1 -1
- package/dist/umd/types/viz-scrollmap.d.ts +8 -0
- package/dist/umd/types/viz-scrollmap.d.ts.map +1 -1
- package/dist/umd/utils/index.d.ts +1 -0
- package/dist/umd/utils/index.d.ts.map +1 -1
- package/dist/umd/utils/scrollmap.d.ts +11 -0
- package/dist/umd/utils/scrollmap.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/esm/index.mjs
CHANGED
|
@@ -1971,6 +1971,21 @@ function createObservable(initialValue) {
|
|
|
1971
1971
|
return observable;
|
|
1972
1972
|
}
|
|
1973
1973
|
|
|
1974
|
+
/**
|
|
1975
|
+
* Given a list of items where each item represents the START of a bucket,
|
|
1976
|
+
* returns each item enriched with `startY` (= position) and `endY` (= next position, or 100 for the last bucket).
|
|
1977
|
+
*
|
|
1978
|
+
* Works for any scroll data shape (depth, attention, revenue).
|
|
1979
|
+
*/
|
|
1980
|
+
function buildBuckets(items, getPosition) {
|
|
1981
|
+
const sorted = [...items].sort((a, b) => getPosition(a) - getPosition(b));
|
|
1982
|
+
return sorted.map((item, i) => ({
|
|
1983
|
+
...item,
|
|
1984
|
+
startY: getPosition(item),
|
|
1985
|
+
endY: sorted[i + 1] !== undefined ? getPosition(sorted[i + 1]) : 100,
|
|
1986
|
+
}));
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1974
1989
|
function sortEvents(a, b) {
|
|
1975
1990
|
return a.time - b.time;
|
|
1976
1991
|
}
|
|
@@ -3550,10 +3565,11 @@ const useScrollmap = () => {
|
|
|
3550
3565
|
const renderScrollBucket = useCallback(() => {
|
|
3551
3566
|
if (!vizRef || !scrollmap || scrollmap.length === 0 || !isDomLoaded)
|
|
3552
3567
|
return;
|
|
3553
|
-
const bucketData = scrollmap.map((
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3568
|
+
const bucketData = buildBuckets(scrollmap, (p) => p.scrollReachY).map((b) => ({
|
|
3569
|
+
startY: b.startY,
|
|
3570
|
+
endY: b.endY,
|
|
3571
|
+
value: b.cumulativeSum,
|
|
3572
|
+
percent: b.percUsers,
|
|
3557
3573
|
}));
|
|
3558
3574
|
try {
|
|
3559
3575
|
requestIdleCallback(() => vizRef?.scrollBucket?.(bucketData), { timeout: 300 });
|
|
@@ -4324,206 +4340,207 @@ function setup(doc, onChange) {
|
|
|
4324
4340
|
// cspell:ignore cooldown
|
|
4325
4341
|
/**
|
|
4326
4342
|
* Height Observer Processor
|
|
4327
|
-
* Background observer — watches for iframe content height
|
|
4343
|
+
* Background observer — watches for iframe content height changectx.
|
|
4328
4344
|
*/
|
|
4329
4345
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
4330
|
-
function readCurrentHeight(
|
|
4331
|
-
if (!
|
|
4346
|
+
function readCurrentHeight(ctx) {
|
|
4347
|
+
if (!ctx.iframe?.contentDocument || !ctx.iframe?.contentWindow)
|
|
4332
4348
|
return 0;
|
|
4333
|
-
const height = getFinalHeight(
|
|
4334
|
-
|
|
4349
|
+
const height = getFinalHeight(ctx.iframe.contentDocument, false);
|
|
4350
|
+
ctx.logger.log('Height:', height);
|
|
4335
4351
|
return height;
|
|
4336
4352
|
}
|
|
4337
|
-
function isBlocked(
|
|
4338
|
-
return
|
|
4353
|
+
function isBlocked(ctx) {
|
|
4354
|
+
return ctx.isProcessing || ctx.isCoolingDown || ctx.throttleTimeout !== null;
|
|
4339
4355
|
}
|
|
4340
|
-
function hasHeightChanged(
|
|
4341
|
-
return height !==
|
|
4356
|
+
function hasHeightChanged(ctx, height) {
|
|
4357
|
+
return height !== ctx.lastHeight;
|
|
4342
4358
|
}
|
|
4343
4359
|
// ── Cooldown ──────────────────────────────────────────────────────────────────
|
|
4344
|
-
function startCooldown(
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4360
|
+
function startCooldown(ctx) {
|
|
4361
|
+
const cooldownMs = ctx.cooldownMs;
|
|
4362
|
+
ctx.isCoolingDown = true;
|
|
4363
|
+
ctx.cooldownTimeout = setTimeout(() => {
|
|
4364
|
+
ctx.cooldownTimeout = null;
|
|
4365
|
+
ctx.isCoolingDown = false;
|
|
4366
|
+
}, cooldownMs);
|
|
4350
4367
|
}
|
|
4351
|
-
function stopCooldown(
|
|
4352
|
-
if (
|
|
4353
|
-
clearTimeout(
|
|
4354
|
-
|
|
4368
|
+
function stopCooldown(ctx) {
|
|
4369
|
+
if (ctx.cooldownTimeout) {
|
|
4370
|
+
clearTimeout(ctx.cooldownTimeout);
|
|
4371
|
+
ctx.cooldownTimeout = null;
|
|
4355
4372
|
}
|
|
4356
|
-
|
|
4373
|
+
ctx.isCoolingDown = false;
|
|
4357
4374
|
}
|
|
4358
4375
|
// ── Debounce ──────────────────────────────────────────────────────────────────
|
|
4359
|
-
function cancelPendingDebounce(
|
|
4360
|
-
if (
|
|
4361
|
-
clearTimeout(
|
|
4362
|
-
|
|
4376
|
+
function cancelPendingDebounce(ctx) {
|
|
4377
|
+
if (ctx.debounceTimeout) {
|
|
4378
|
+
clearTimeout(ctx.debounceTimeout);
|
|
4379
|
+
ctx.debounceTimeout = null;
|
|
4363
4380
|
}
|
|
4364
4381
|
}
|
|
4365
|
-
function processCurrentHeightIfChanged(
|
|
4366
|
-
const height = readCurrentHeight(
|
|
4367
|
-
if (hasHeightChanged(
|
|
4368
|
-
processHeightChange(
|
|
4382
|
+
function processCurrentHeightIfChanged(ctx) {
|
|
4383
|
+
const height = readCurrentHeight(ctx);
|
|
4384
|
+
if (hasHeightChanged(ctx, height)) {
|
|
4385
|
+
processHeightChange(ctx, height);
|
|
4369
4386
|
}
|
|
4370
4387
|
}
|
|
4371
|
-
function scheduleDebounce(
|
|
4372
|
-
cancelPendingDebounce(
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
processCurrentHeightIfChanged(
|
|
4376
|
-
},
|
|
4388
|
+
function scheduleDebounce(ctx) {
|
|
4389
|
+
cancelPendingDebounce(ctx);
|
|
4390
|
+
ctx.debounceTimeout = setTimeout(() => {
|
|
4391
|
+
ctx.debounceTimeout = null;
|
|
4392
|
+
processCurrentHeightIfChanged(ctx);
|
|
4393
|
+
}, ctx.debounceMs);
|
|
4377
4394
|
}
|
|
4378
4395
|
// ── Throttle ──────────────────────────────────────────────────────────────────
|
|
4379
|
-
function scheduleThrottledCheck(
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
const height = readCurrentHeight(
|
|
4383
|
-
if (!hasHeightChanged(
|
|
4384
|
-
cancelPendingDebounce(
|
|
4396
|
+
function scheduleThrottledCheck(ctx) {
|
|
4397
|
+
ctx.throttleTimeout = setTimeout(() => {
|
|
4398
|
+
ctx.throttleTimeout = null;
|
|
4399
|
+
const height = readCurrentHeight(ctx);
|
|
4400
|
+
if (!hasHeightChanged(ctx, height)) {
|
|
4401
|
+
cancelPendingDebounce(ctx);
|
|
4385
4402
|
return;
|
|
4386
4403
|
}
|
|
4387
|
-
|
|
4388
|
-
scheduleDebounce(
|
|
4389
|
-
},
|
|
4404
|
+
ctx.logger.log(`Height changed: ${ctx.lastHeight}px -> ${height}px`);
|
|
4405
|
+
scheduleDebounce(ctx);
|
|
4406
|
+
}, ctx.throttleMs);
|
|
4390
4407
|
}
|
|
4391
4408
|
// ── Core ──────────────────────────────────────────────────────────────────────
|
|
4392
|
-
async function processHeightChange(
|
|
4393
|
-
if (!
|
|
4409
|
+
async function processHeightChange(ctx, newHeight) {
|
|
4410
|
+
if (!ctx.iframe || !ctx.config)
|
|
4394
4411
|
return;
|
|
4395
|
-
|
|
4396
|
-
|
|
4412
|
+
ctx.isProcessing = true;
|
|
4413
|
+
ctx.logger.log(`Processing height change: ${newHeight}px`);
|
|
4397
4414
|
try {
|
|
4398
4415
|
const result = {
|
|
4399
4416
|
height: newHeight,
|
|
4400
|
-
width:
|
|
4417
|
+
width: ctx.iframe.contentWindow?.innerWidth ?? 0,
|
|
4401
4418
|
};
|
|
4402
|
-
|
|
4403
|
-
|
|
4419
|
+
ctx.lastHeight = newHeight;
|
|
4420
|
+
ctx.config.onHeightChange?.(result);
|
|
4404
4421
|
window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', { detail: result }));
|
|
4405
4422
|
}
|
|
4406
4423
|
catch (error) {
|
|
4407
|
-
|
|
4408
|
-
|
|
4424
|
+
ctx.logger.error('Failed to process height change:', error);
|
|
4425
|
+
ctx.config.onError?.(error);
|
|
4409
4426
|
}
|
|
4410
4427
|
finally {
|
|
4411
|
-
|
|
4412
|
-
if (
|
|
4413
|
-
startCooldown(
|
|
4428
|
+
ctx.isProcessing = false;
|
|
4429
|
+
if (ctx.cooldownMs > 0)
|
|
4430
|
+
startCooldown(ctx);
|
|
4414
4431
|
}
|
|
4415
4432
|
}
|
|
4416
|
-
function handleHeightChange(
|
|
4417
|
-
if (!
|
|
4433
|
+
function handleHeightChange(ctx) {
|
|
4434
|
+
if (!ctx.running || isBlocked(ctx))
|
|
4418
4435
|
return;
|
|
4419
|
-
scheduleThrottledCheck(
|
|
4436
|
+
scheduleThrottledCheck(ctx);
|
|
4420
4437
|
}
|
|
4421
|
-
function attachObserver(
|
|
4422
|
-
if (!
|
|
4423
|
-
|
|
4438
|
+
function attachObserver(ctx) {
|
|
4439
|
+
if (!ctx.iframe?.contentDocument?.body) {
|
|
4440
|
+
ctx.logger.warn('Cannot observe height changes: iframe body not found');
|
|
4424
4441
|
return;
|
|
4425
4442
|
}
|
|
4426
|
-
|
|
4427
|
-
const height = readCurrentHeight(
|
|
4428
|
-
|
|
4429
|
-
if (hasHeightChanged(
|
|
4430
|
-
processHeightChange(
|
|
4443
|
+
ctx.observerCleanup?.();
|
|
4444
|
+
const height = readCurrentHeight(ctx);
|
|
4445
|
+
ctx.logger.log('Initial height:', height);
|
|
4446
|
+
if (hasHeightChanged(ctx, height)) {
|
|
4447
|
+
processHeightChange(ctx, height);
|
|
4431
4448
|
}
|
|
4432
4449
|
else {
|
|
4433
|
-
|
|
4450
|
+
ctx.lastHeight = height;
|
|
4434
4451
|
}
|
|
4435
|
-
|
|
4452
|
+
ctx.observerCleanup = setup(ctx.iframe.contentDocument, () => handleHeightChange(ctx));
|
|
4436
4453
|
}
|
|
4437
|
-
function detachObserver(
|
|
4438
|
-
|
|
4439
|
-
|
|
4454
|
+
function detachObserver(ctx) {
|
|
4455
|
+
ctx.observerCleanup?.();
|
|
4456
|
+
ctx.observerCleanup = null;
|
|
4440
4457
|
}
|
|
4441
|
-
function clearAllTimers(
|
|
4442
|
-
if (
|
|
4443
|
-
clearTimeout(
|
|
4444
|
-
|
|
4458
|
+
function clearAllTimers(ctx) {
|
|
4459
|
+
if (ctx.throttleTimeout) {
|
|
4460
|
+
clearTimeout(ctx.throttleTimeout);
|
|
4461
|
+
ctx.throttleTimeout = null;
|
|
4445
4462
|
}
|
|
4446
|
-
if (
|
|
4447
|
-
clearTimeout(
|
|
4448
|
-
|
|
4463
|
+
if (ctx.debounceTimeout) {
|
|
4464
|
+
clearTimeout(ctx.debounceTimeout);
|
|
4465
|
+
ctx.debounceTimeout = null;
|
|
4449
4466
|
}
|
|
4450
|
-
if (
|
|
4451
|
-
clearTimeout(
|
|
4452
|
-
|
|
4467
|
+
if (ctx.startDelayTimeout) {
|
|
4468
|
+
clearTimeout(ctx.startDelayTimeout);
|
|
4469
|
+
ctx.startDelayTimeout = null;
|
|
4453
4470
|
}
|
|
4454
|
-
stopCooldown(
|
|
4471
|
+
stopCooldown(ctx);
|
|
4455
4472
|
}
|
|
4456
4473
|
// ── Lifecycle ─────────────────────────────────────────────────────────────────
|
|
4457
|
-
function observeImmediately(
|
|
4458
|
-
attachObserver(
|
|
4459
|
-
|
|
4460
|
-
}
|
|
4461
|
-
function observeAfterDelay(
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
if (!
|
|
4466
|
-
return;
|
|
4467
|
-
attachObserver(
|
|
4468
|
-
|
|
4474
|
+
function observeImmediately(ctx) {
|
|
4475
|
+
attachObserver(ctx);
|
|
4476
|
+
ctx.logger.log('Height observer started');
|
|
4477
|
+
}
|
|
4478
|
+
function observeAfterDelay(ctx, delayMs) {
|
|
4479
|
+
ctx.logger.log(`Height observer will start in ${delayMs}ms`);
|
|
4480
|
+
ctx.startDelayTimeout = setTimeout(() => {
|
|
4481
|
+
ctx.startDelayTimeout = null;
|
|
4482
|
+
if (!ctx.running)
|
|
4483
|
+
return;
|
|
4484
|
+
attachObserver(ctx);
|
|
4485
|
+
ctx.logger.log('Height observer started (after delay)');
|
|
4469
4486
|
}, delayMs);
|
|
4470
4487
|
}
|
|
4471
|
-
function start$5(
|
|
4472
|
-
if (
|
|
4473
|
-
|
|
4488
|
+
function start$5(ctx, iframe, cfg) {
|
|
4489
|
+
if (ctx.running) {
|
|
4490
|
+
ctx.logger.warn('Observer is already running. Call stop() first.');
|
|
4474
4491
|
return;
|
|
4475
4492
|
}
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4493
|
+
ctx.iframe = iframe;
|
|
4494
|
+
ctx.config = cfg;
|
|
4495
|
+
ctx.throttleMs = cfg.throttleMs ?? 25;
|
|
4496
|
+
ctx.debounceMs = cfg.debounceMs ?? 500;
|
|
4497
|
+
ctx.cooldownMs = cfg.cooldownMs ?? 0;
|
|
4498
|
+
ctx.running = true;
|
|
4482
4499
|
const startDelayMs = cfg.startDelayMs ?? 0;
|
|
4483
4500
|
if (startDelayMs > 0) {
|
|
4484
|
-
observeAfterDelay(
|
|
4501
|
+
observeAfterDelay(ctx, startDelayMs);
|
|
4485
4502
|
}
|
|
4486
4503
|
else {
|
|
4487
|
-
observeImmediately(
|
|
4504
|
+
observeImmediately(ctx);
|
|
4488
4505
|
}
|
|
4489
4506
|
}
|
|
4490
|
-
function stop$5(
|
|
4491
|
-
if (!
|
|
4507
|
+
function stop$5(ctx) {
|
|
4508
|
+
if (!ctx.running)
|
|
4492
4509
|
return;
|
|
4493
|
-
detachObserver(
|
|
4494
|
-
clearAllTimers(
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
}
|
|
4503
|
-
function clear(
|
|
4504
|
-
detachObserver(
|
|
4505
|
-
clearAllTimers(
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
}
|
|
4509
|
-
function updateConfig$3(
|
|
4510
|
-
if (!
|
|
4511
|
-
|
|
4510
|
+
detachObserver(ctx);
|
|
4511
|
+
clearAllTimers(ctx);
|
|
4512
|
+
ctx.iframe = null;
|
|
4513
|
+
ctx.config = null;
|
|
4514
|
+
ctx.lastHeight = 0;
|
|
4515
|
+
ctx.isProcessing = false;
|
|
4516
|
+
ctx.isCoolingDown = false;
|
|
4517
|
+
ctx.running = false;
|
|
4518
|
+
ctx.logger.log('Height observer stopped');
|
|
4519
|
+
}
|
|
4520
|
+
function clear(ctx) {
|
|
4521
|
+
detachObserver(ctx);
|
|
4522
|
+
clearAllTimers(ctx);
|
|
4523
|
+
ctx.lastHeight = 0;
|
|
4524
|
+
ctx.isProcessing = false;
|
|
4525
|
+
}
|
|
4526
|
+
function updateConfig$3(ctx, cfg) {
|
|
4527
|
+
if (!ctx.running || !ctx.config) {
|
|
4528
|
+
ctx.logger.warn('Observer is not running.');
|
|
4512
4529
|
return;
|
|
4513
4530
|
}
|
|
4514
|
-
|
|
4531
|
+
ctx.config = { ...ctx.config, ...cfg };
|
|
4515
4532
|
if (cfg.throttleMs !== undefined)
|
|
4516
|
-
|
|
4533
|
+
ctx.throttleMs = cfg.throttleMs;
|
|
4517
4534
|
if (cfg.debounceMs !== undefined)
|
|
4518
|
-
|
|
4535
|
+
ctx.debounceMs = cfg.debounceMs;
|
|
4519
4536
|
if (cfg.cooldownMs !== undefined)
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4537
|
+
ctx.cooldownMs = cfg.cooldownMs;
|
|
4538
|
+
ctx.logger.configure({ enabled: !!ctx.config.debug });
|
|
4539
|
+
ctx.logger.log('Config updated');
|
|
4523
4540
|
}
|
|
4524
4541
|
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
4525
4542
|
function createHeightObserver() {
|
|
4526
|
-
const
|
|
4543
|
+
const ctx = {
|
|
4527
4544
|
logger: createLogger({ enabled: true, prefix: 'IframeHeightObserver' }),
|
|
4528
4545
|
iframe: null,
|
|
4529
4546
|
config: null,
|
|
@@ -4541,18 +4558,18 @@ function createHeightObserver() {
|
|
|
4541
4558
|
running: false,
|
|
4542
4559
|
};
|
|
4543
4560
|
return {
|
|
4544
|
-
start: (iframe, cfg) => start$5(
|
|
4545
|
-
stop: () => stop$5(
|
|
4546
|
-
observe: () => attachObserver(
|
|
4547
|
-
clear: () => clear(
|
|
4548
|
-
updateConfig: (cfg) => updateConfig$3(
|
|
4549
|
-
getCurrentHeight: () =>
|
|
4550
|
-
isRunning: () =>
|
|
4561
|
+
start: (iframe, cfg) => start$5(ctx, iframe, cfg),
|
|
4562
|
+
stop: () => stop$5(ctx),
|
|
4563
|
+
observe: () => attachObserver(ctx),
|
|
4564
|
+
clear: () => clear(ctx),
|
|
4565
|
+
updateConfig: (cfg) => updateConfig$3(ctx, cfg),
|
|
4566
|
+
getCurrentHeight: () => ctx.lastHeight,
|
|
4567
|
+
isRunning: () => ctx.running,
|
|
4551
4568
|
getStateInfo: () => ({
|
|
4552
|
-
isRunning:
|
|
4553
|
-
lastHeight:
|
|
4554
|
-
isProcessing:
|
|
4555
|
-
hasObservers: !!
|
|
4569
|
+
isRunning: ctx.running,
|
|
4570
|
+
lastHeight: ctx.lastHeight,
|
|
4571
|
+
isProcessing: ctx.isProcessing,
|
|
4572
|
+
hasObservers: !!ctx.observerCleanup,
|
|
4556
4573
|
}),
|
|
4557
4574
|
};
|
|
4558
4575
|
}
|
|
@@ -4565,27 +4582,27 @@ function createHeightObserver() {
|
|
|
4565
4582
|
* - Dispatch navigation events to the parent window
|
|
4566
4583
|
*/
|
|
4567
4584
|
// ── Module-level functions ────────────────────────────────────────────────────
|
|
4568
|
-
function attach$1(
|
|
4569
|
-
|
|
4570
|
-
|
|
4585
|
+
function attach$1(ctx, debug) {
|
|
4586
|
+
ctx.logger.configure({ enabled: !!debug });
|
|
4587
|
+
ctx.navigationBlockedListener = (e) => {
|
|
4571
4588
|
const ev = e;
|
|
4572
|
-
|
|
4589
|
+
ctx.logger.log('Navigation blocked:', ev.detail.url);
|
|
4573
4590
|
};
|
|
4574
|
-
|
|
4591
|
+
ctx.formSubmitWindowListener = (e) => {
|
|
4575
4592
|
const ev = e;
|
|
4576
|
-
|
|
4593
|
+
ctx.logger.log('Form submitted:', ev.detail.data);
|
|
4577
4594
|
};
|
|
4578
|
-
window.addEventListener('iframe-navigation-blocked',
|
|
4579
|
-
window.addEventListener('iframe-form-submit',
|
|
4595
|
+
window.addEventListener('iframe-navigation-blocked', ctx.navigationBlockedListener);
|
|
4596
|
+
window.addEventListener('iframe-form-submit', ctx.formSubmitWindowListener);
|
|
4580
4597
|
}
|
|
4581
|
-
function detach$1(
|
|
4582
|
-
if (
|
|
4583
|
-
window.removeEventListener('iframe-navigation-blocked',
|
|
4584
|
-
|
|
4598
|
+
function detach$1(ctx) {
|
|
4599
|
+
if (ctx.navigationBlockedListener) {
|
|
4600
|
+
window.removeEventListener('iframe-navigation-blocked', ctx.navigationBlockedListener);
|
|
4601
|
+
ctx.navigationBlockedListener = null;
|
|
4585
4602
|
}
|
|
4586
|
-
if (
|
|
4587
|
-
window.removeEventListener('iframe-form-submit',
|
|
4588
|
-
|
|
4603
|
+
if (ctx.formSubmitWindowListener) {
|
|
4604
|
+
window.removeEventListener('iframe-form-submit', ctx.formSubmitWindowListener);
|
|
4605
|
+
ctx.formSubmitWindowListener = null;
|
|
4589
4606
|
}
|
|
4590
4607
|
}
|
|
4591
4608
|
function dispatchBlocked(url, showMessage) {
|
|
@@ -4598,14 +4615,14 @@ function dispatchFormSubmit(form, data) {
|
|
|
4598
4615
|
}
|
|
4599
4616
|
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
4600
4617
|
function createNavigationListeners() {
|
|
4601
|
-
const
|
|
4618
|
+
const ctx = {
|
|
4602
4619
|
logger: createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' }),
|
|
4603
4620
|
navigationBlockedListener: null,
|
|
4604
4621
|
formSubmitWindowListener: null,
|
|
4605
4622
|
};
|
|
4606
4623
|
return {
|
|
4607
|
-
attach: (debug) => attach$1(
|
|
4608
|
-
detach: () => detach$1(
|
|
4624
|
+
attach: (debug) => attach$1(ctx, debug),
|
|
4625
|
+
detach: () => detach$1(ctx),
|
|
4609
4626
|
dispatchBlocked,
|
|
4610
4627
|
dispatchFormSubmit,
|
|
4611
4628
|
};
|
|
@@ -4739,9 +4756,9 @@ function setupDOMMonitor(doc) {
|
|
|
4739
4756
|
* Continuous guard — blocks all navigation attempts within the iframe.
|
|
4740
4757
|
*/
|
|
4741
4758
|
// ── Module-level functions ────────────────────────────────────────────────────
|
|
4742
|
-
function start$4(
|
|
4743
|
-
if (
|
|
4744
|
-
|
|
4759
|
+
function start$4(ctx, iframe, cfg) {
|
|
4760
|
+
if (ctx.running) {
|
|
4761
|
+
ctx.logger.warn('Blocker is already running. Call stop() first.');
|
|
4745
4762
|
return;
|
|
4746
4763
|
}
|
|
4747
4764
|
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
@@ -4750,65 +4767,67 @@ function start$4(s, iframe, cfg) {
|
|
|
4750
4767
|
const doc = iframe.contentDocument;
|
|
4751
4768
|
const win = iframe.contentWindow;
|
|
4752
4769
|
const originalOpen = win.open.bind(win);
|
|
4753
|
-
|
|
4770
|
+
ctx.logger.configure({ enabled: !!cfg?.debug });
|
|
4754
4771
|
configure$1(!!cfg?.debug);
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4772
|
+
const isEnabledFn = () => ctx.isEnabled;
|
|
4773
|
+
const dispatchBlocked = (url) => ctx.listeners.dispatchBlocked(url, ctx.showMessage);
|
|
4774
|
+
const dispatchFormSubmit = ctx.listeners.dispatchFormSubmit;
|
|
4775
|
+
const linkBlocker = setupLinkBlocker(doc, isEnabledFn, dispatchBlocked);
|
|
4776
|
+
const formBlocker = setupFormBlocker(doc, isEnabledFn, dispatchBlocked, dispatchFormSubmit);
|
|
4777
|
+
const windowOpenBlocker = setupWindowOpenBlocker(win, originalOpen, isEnabledFn, dispatchBlocked);
|
|
4778
|
+
const unloadBlocker = setupUnloadBlocker(win, isEnabledFn);
|
|
4779
|
+
const domMonitor = setupDOMMonitor(doc);
|
|
4780
|
+
ctx.cleanups = [linkBlocker, formBlocker, windowOpenBlocker, unloadBlocker, domMonitor];
|
|
4781
|
+
ctx.listeners.attach(cfg?.debug);
|
|
4782
|
+
ctx.running = true;
|
|
4783
|
+
ctx.logger.log('Started');
|
|
4784
|
+
}
|
|
4785
|
+
function stop$4(ctx) {
|
|
4786
|
+
if (!ctx.running)
|
|
4768
4787
|
return;
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
}
|
|
4777
|
-
function enable(
|
|
4778
|
-
if (!
|
|
4779
|
-
|
|
4788
|
+
ctx.cleanups.forEach((fn) => fn());
|
|
4789
|
+
ctx.cleanups = [];
|
|
4790
|
+
ctx.listeners.detach();
|
|
4791
|
+
ctx.isEnabled = false;
|
|
4792
|
+
ctx.showMessage = false;
|
|
4793
|
+
ctx.running = false;
|
|
4794
|
+
ctx.logger.log('Stopped');
|
|
4795
|
+
}
|
|
4796
|
+
function enable(ctx) {
|
|
4797
|
+
if (!ctx.running) {
|
|
4798
|
+
ctx.logger.warn('Blocker is not running.');
|
|
4780
4799
|
return;
|
|
4781
4800
|
}
|
|
4782
|
-
|
|
4783
|
-
|
|
4801
|
+
ctx.isEnabled = true;
|
|
4802
|
+
ctx.logger.log('Navigation blocking enabled');
|
|
4784
4803
|
}
|
|
4785
|
-
function disable(
|
|
4786
|
-
if (!
|
|
4787
|
-
|
|
4804
|
+
function disable(ctx) {
|
|
4805
|
+
if (!ctx.running) {
|
|
4806
|
+
ctx.logger.warn('Blocker is not running.');
|
|
4788
4807
|
return;
|
|
4789
4808
|
}
|
|
4790
|
-
|
|
4791
|
-
|
|
4809
|
+
ctx.isEnabled = false;
|
|
4810
|
+
ctx.logger.log('Navigation blocking disabled');
|
|
4792
4811
|
}
|
|
4793
|
-
function enableMessage(
|
|
4794
|
-
if (!
|
|
4795
|
-
|
|
4812
|
+
function enableMessage(ctx) {
|
|
4813
|
+
if (!ctx.running) {
|
|
4814
|
+
ctx.logger.warn('Blocker is not running.');
|
|
4796
4815
|
return;
|
|
4797
4816
|
}
|
|
4798
|
-
|
|
4799
|
-
|
|
4817
|
+
ctx.showMessage = true;
|
|
4818
|
+
ctx.logger.log('Navigation blocking message enabled');
|
|
4800
4819
|
}
|
|
4801
|
-
function disableMessage(
|
|
4802
|
-
if (!
|
|
4803
|
-
|
|
4820
|
+
function disableMessage(ctx) {
|
|
4821
|
+
if (!ctx.running) {
|
|
4822
|
+
ctx.logger.warn('Blocker is not running.');
|
|
4804
4823
|
return;
|
|
4805
4824
|
}
|
|
4806
|
-
|
|
4807
|
-
|
|
4825
|
+
ctx.showMessage = false;
|
|
4826
|
+
ctx.logger.log('Navigation blocking message disabled');
|
|
4808
4827
|
}
|
|
4809
4828
|
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
4810
4829
|
function createNavigationBlocker() {
|
|
4811
|
-
const
|
|
4830
|
+
const ctx = {
|
|
4812
4831
|
logger: createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' }),
|
|
4813
4832
|
listeners: createNavigationListeners(),
|
|
4814
4833
|
isEnabled: false,
|
|
@@ -4817,42 +4836,42 @@ function createNavigationBlocker() {
|
|
|
4817
4836
|
cleanups: [],
|
|
4818
4837
|
};
|
|
4819
4838
|
return {
|
|
4820
|
-
start: (iframe, cfg) => start$4(
|
|
4821
|
-
stop: () => stop$4(
|
|
4822
|
-
enable: () => enable(
|
|
4823
|
-
disable: () => disable(
|
|
4824
|
-
enableMessage: () => enableMessage(
|
|
4825
|
-
disableMessage: () => disableMessage(
|
|
4826
|
-
isRunning: () =>
|
|
4827
|
-
isBlockingEnabled: () =>
|
|
4828
|
-
getStateInfo: () => ({ isRunning:
|
|
4839
|
+
start: (iframe, cfg) => start$4(ctx, iframe, cfg),
|
|
4840
|
+
stop: () => stop$4(ctx),
|
|
4841
|
+
enable: () => enable(ctx),
|
|
4842
|
+
disable: () => disable(ctx),
|
|
4843
|
+
enableMessage: () => enableMessage(ctx),
|
|
4844
|
+
disableMessage: () => disableMessage(ctx),
|
|
4845
|
+
isRunning: () => ctx.running,
|
|
4846
|
+
isBlockingEnabled: () => ctx.isEnabled,
|
|
4847
|
+
getStateInfo: () => ({ isRunning: ctx.running, isEnabled: ctx.isEnabled, showMessage: ctx.showMessage }),
|
|
4829
4848
|
};
|
|
4830
4849
|
}
|
|
4831
4850
|
|
|
4832
4851
|
// ── Module-level functions ────────────────────────────────────────────────────
|
|
4833
|
-
function attach(
|
|
4834
|
-
|
|
4835
|
-
|
|
4852
|
+
function attach(ctx, debug) {
|
|
4853
|
+
ctx.logger.configure({ enabled: !!debug });
|
|
4854
|
+
ctx.dimensionsListener = (_e) => {
|
|
4836
4855
|
// const ev = e as CustomEvent<IframeDimensionsDetail>;
|
|
4837
|
-
//
|
|
4856
|
+
// ctx.logger.log('Dimensions applied:', ev.detail);
|
|
4838
4857
|
};
|
|
4839
|
-
window.addEventListener('iframe-dimensions-applied',
|
|
4858
|
+
window.addEventListener('iframe-dimensions-applied', ctx.dimensionsListener);
|
|
4840
4859
|
}
|
|
4841
|
-
function detach(
|
|
4842
|
-
if (
|
|
4843
|
-
window.removeEventListener('iframe-dimensions-applied',
|
|
4844
|
-
|
|
4860
|
+
function detach(ctx) {
|
|
4861
|
+
if (ctx.dimensionsListener) {
|
|
4862
|
+
window.removeEventListener('iframe-dimensions-applied', ctx.dimensionsListener);
|
|
4863
|
+
ctx.dimensionsListener = null;
|
|
4845
4864
|
}
|
|
4846
4865
|
}
|
|
4847
4866
|
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
4848
4867
|
function createViewportListeners() {
|
|
4849
|
-
const
|
|
4868
|
+
const ctx = {
|
|
4850
4869
|
logger: createLogger({ enabled: false, prefix: 'ViewportReplacer' }),
|
|
4851
4870
|
dimensionsListener: null,
|
|
4852
4871
|
};
|
|
4853
4872
|
return {
|
|
4854
|
-
attach: (debug) => attach(
|
|
4855
|
-
detach: () => detach(
|
|
4873
|
+
attach: (debug) => attach(ctx, debug),
|
|
4874
|
+
detach: () => detach(ctx),
|
|
4856
4875
|
};
|
|
4857
4876
|
}
|
|
4858
4877
|
|
|
@@ -4896,33 +4915,33 @@ const CRITICAL_PROPERTIES = [
|
|
|
4896
4915
|
];
|
|
4897
4916
|
|
|
4898
4917
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
4899
|
-
function getViewportUnitMap(
|
|
4900
|
-
if (!
|
|
4918
|
+
function getViewportUnitMap(ctx) {
|
|
4919
|
+
if (!ctx.config)
|
|
4901
4920
|
throw new Error('Config is not initialized');
|
|
4902
4921
|
return {
|
|
4903
|
-
vh:
|
|
4904
|
-
svh:
|
|
4905
|
-
lvh:
|
|
4906
|
-
dvh:
|
|
4907
|
-
vw:
|
|
4908
|
-
svw:
|
|
4909
|
-
lvw:
|
|
4910
|
-
dvw:
|
|
4911
|
-
};
|
|
4912
|
-
}
|
|
4913
|
-
function calculateExpectedPx(
|
|
4914
|
-
if (!
|
|
4922
|
+
vh: ctx.config.targetHeight,
|
|
4923
|
+
svh: ctx.config.targetHeight,
|
|
4924
|
+
lvh: ctx.config.targetHeight,
|
|
4925
|
+
dvh: ctx.config.targetHeight,
|
|
4926
|
+
vw: ctx.config.targetWidth,
|
|
4927
|
+
svw: ctx.config.targetWidth,
|
|
4928
|
+
lvw: ctx.config.targetWidth,
|
|
4929
|
+
dvw: ctx.config.targetWidth,
|
|
4930
|
+
};
|
|
4931
|
+
}
|
|
4932
|
+
function calculateExpectedPx(ctx, value, unit) {
|
|
4933
|
+
if (!ctx.config)
|
|
4915
4934
|
throw new Error('Config is not initialized');
|
|
4916
4935
|
const unitLower = unit.toLowerCase();
|
|
4917
4936
|
if (unitLower === '%')
|
|
4918
|
-
return (value / 100) *
|
|
4919
|
-
return (value / 100) * (getViewportUnitMap(
|
|
4937
|
+
return (value / 100) * ctx.config.targetHeight;
|
|
4938
|
+
return (value / 100) * (getViewportUnitMap(ctx)[unitLower] || 0);
|
|
4920
4939
|
}
|
|
4921
4940
|
function isDefaultCssValue(value) {
|
|
4922
4941
|
return DEFAULT_CSS_VALUES.includes(value);
|
|
4923
4942
|
}
|
|
4924
|
-
function shouldReplaceValue(
|
|
4925
|
-
if (!
|
|
4943
|
+
function shouldReplaceValue(ctx, computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
|
|
4944
|
+
if (!ctx.config)
|
|
4926
4945
|
return false;
|
|
4927
4946
|
const computedPx = parseFloat(computedValue);
|
|
4928
4947
|
if (isNaN(computedPx))
|
|
@@ -4935,86 +4954,86 @@ function shouldReplaceValue(s, computedValue, originalValue, tolerance = DEFAULT
|
|
|
4935
4954
|
const num = parseFloat(value);
|
|
4936
4955
|
if (isNaN(num))
|
|
4937
4956
|
return false;
|
|
4938
|
-
const expectedPx = calculateExpectedPx(
|
|
4957
|
+
const expectedPx = calculateExpectedPx(ctx, num, unit);
|
|
4939
4958
|
const diff = Math.abs(computedPx - expectedPx);
|
|
4940
4959
|
if (diff <= tolerance) {
|
|
4941
|
-
|
|
4960
|
+
ctx.logger.log(`OK to replace: computed=${computedValue} matches expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
|
|
4942
4961
|
return true;
|
|
4943
4962
|
}
|
|
4944
|
-
|
|
4963
|
+
ctx.logger.log(`Skip replace: computed=${computedValue} differs from expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
|
|
4945
4964
|
return false;
|
|
4946
4965
|
}
|
|
4947
|
-
function applyPropertyWithVerification(
|
|
4948
|
-
if (originalValue && shouldReplaceValue(
|
|
4966
|
+
function applyPropertyWithVerification(ctx, element, prop, computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
|
|
4967
|
+
if (originalValue && shouldReplaceValue(ctx, computedValue, originalValue, tolerance)) {
|
|
4949
4968
|
element.style.setProperty(prop, computedValue, 'important');
|
|
4950
4969
|
return true;
|
|
4951
4970
|
}
|
|
4952
|
-
|
|
4971
|
+
if (!originalValue) {
|
|
4953
4972
|
element.style.setProperty(prop, computedValue, 'important');
|
|
4954
4973
|
return true;
|
|
4955
4974
|
}
|
|
4956
4975
|
return false;
|
|
4957
4976
|
}
|
|
4958
4977
|
// ── Exported module-level functions ───────────────────────────────────────────
|
|
4959
|
-
function start$3(
|
|
4960
|
-
if (
|
|
4961
|
-
|
|
4978
|
+
function start$3(ctx, d, w, cfg, options = {}) {
|
|
4979
|
+
if (ctx.running) {
|
|
4980
|
+
ctx.logger.warn('Enforcer is already running. Call stop() first.');
|
|
4962
4981
|
return;
|
|
4963
4982
|
}
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4983
|
+
ctx.doc = d;
|
|
4984
|
+
ctx.win = w;
|
|
4985
|
+
ctx.config = cfg;
|
|
4986
|
+
ctx.running = true;
|
|
4987
|
+
ctx.logger.configure({ enabled: !!options.debug });
|
|
4988
|
+
ctx.logger.log('Started');
|
|
4970
4989
|
}
|
|
4971
|
-
function stop$3(
|
|
4972
|
-
if (!
|
|
4990
|
+
function stop$3(ctx) {
|
|
4991
|
+
if (!ctx.running)
|
|
4973
4992
|
return;
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
}
|
|
4982
|
-
function reset(
|
|
4983
|
-
if (!
|
|
4984
|
-
|
|
4993
|
+
ctx.doc = null;
|
|
4994
|
+
ctx.win = null;
|
|
4995
|
+
ctx.config = null;
|
|
4996
|
+
ctx.elementsWithViewportUnits.clear();
|
|
4997
|
+
ctx.originalValues = new WeakMap();
|
|
4998
|
+
ctx.running = false;
|
|
4999
|
+
ctx.logger.log('Stopped');
|
|
5000
|
+
}
|
|
5001
|
+
function reset(ctx) {
|
|
5002
|
+
if (!ctx.running) {
|
|
5003
|
+
ctx.logger.warn('Enforcer is not running. Call start() first.');
|
|
4985
5004
|
return;
|
|
4986
5005
|
}
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
5006
|
+
ctx.elementsWithViewportUnits.clear();
|
|
5007
|
+
ctx.originalValues = new WeakMap();
|
|
5008
|
+
ctx.logger.log('Reset');
|
|
4990
5009
|
}
|
|
4991
|
-
function trackElement(
|
|
4992
|
-
if (!
|
|
4993
|
-
|
|
5010
|
+
function trackElement(ctx, element, propertyOriginalValues) {
|
|
5011
|
+
if (!ctx.running) {
|
|
5012
|
+
ctx.logger.warn('Enforcer is not running. Call start() first.');
|
|
4994
5013
|
return;
|
|
4995
5014
|
}
|
|
4996
|
-
|
|
4997
|
-
let elementOriginals =
|
|
5015
|
+
ctx.elementsWithViewportUnits.add(element);
|
|
5016
|
+
let elementOriginals = ctx.originalValues.get(element);
|
|
4998
5017
|
if (!elementOriginals) {
|
|
4999
5018
|
elementOriginals = new Map();
|
|
5000
|
-
|
|
5019
|
+
ctx.originalValues.set(element, elementOriginals);
|
|
5001
5020
|
}
|
|
5002
5021
|
propertyOriginalValues.forEach((value, prop) => {
|
|
5003
5022
|
if (!elementOriginals.has(prop))
|
|
5004
5023
|
elementOriginals.set(prop, value);
|
|
5005
5024
|
});
|
|
5006
5025
|
}
|
|
5007
|
-
function processElement(
|
|
5008
|
-
if (!
|
|
5009
|
-
|
|
5026
|
+
function processElement(ctx, element, options = {}) {
|
|
5027
|
+
if (!ctx.running || !ctx.doc || !ctx.win || !ctx.config) {
|
|
5028
|
+
ctx.logger.warn('Enforcer is not running.');
|
|
5010
5029
|
return 0;
|
|
5011
5030
|
}
|
|
5012
|
-
if (!
|
|
5031
|
+
if (!ctx.elementsWithViewportUnits.has(element))
|
|
5013
5032
|
return 0;
|
|
5014
5033
|
const htmlElement = element;
|
|
5015
|
-
const computed =
|
|
5034
|
+
const computed = ctx.win.getComputedStyle(htmlElement);
|
|
5016
5035
|
const inlineStyle = htmlElement.style;
|
|
5017
|
-
const elementOriginals =
|
|
5036
|
+
const elementOriginals = ctx.originalValues.get(element);
|
|
5018
5037
|
const tolerance = options.tolerance ?? DEFAULT_TOLERANCE_PX;
|
|
5019
5038
|
let count = 0;
|
|
5020
5039
|
CRITICAL_PROPERTIES.forEach((prop) => {
|
|
@@ -5022,31 +5041,31 @@ function processElement(s, element, options = {}) {
|
|
|
5022
5041
|
const inlineValue = inlineStyle.getPropertyValue(prop);
|
|
5023
5042
|
if (computedValue && (!inlineValue || inlineValue !== computedValue) && !isDefaultCssValue(computedValue)) {
|
|
5024
5043
|
const originalValue = elementOriginals?.get(prop) || '';
|
|
5025
|
-
if (applyPropertyWithVerification(
|
|
5044
|
+
if (applyPropertyWithVerification(ctx, htmlElement, prop, computedValue, originalValue, tolerance))
|
|
5026
5045
|
count++;
|
|
5027
5046
|
}
|
|
5028
5047
|
});
|
|
5029
5048
|
return count;
|
|
5030
5049
|
}
|
|
5031
|
-
function processAll(
|
|
5032
|
-
if (!
|
|
5033
|
-
|
|
5050
|
+
function processAll(ctx, options = {}) {
|
|
5051
|
+
if (!ctx.running || !ctx.doc || !ctx.win || !ctx.config) {
|
|
5052
|
+
ctx.logger.warn('Enforcer is not running.');
|
|
5034
5053
|
return 0;
|
|
5035
5054
|
}
|
|
5036
5055
|
let totalCount = 0;
|
|
5037
|
-
|
|
5038
|
-
totalCount += processElement(
|
|
5056
|
+
ctx.elementsWithViewportUnits.forEach((element) => {
|
|
5057
|
+
totalCount += processElement(ctx, element, options);
|
|
5039
5058
|
});
|
|
5040
|
-
|
|
5059
|
+
ctx.logger.log(`Enforced ${totalCount} computed styles for ${ctx.elementsWithViewportUnits.size} elements`);
|
|
5041
5060
|
return totalCount;
|
|
5042
5061
|
}
|
|
5043
|
-
function updateConfig$2(
|
|
5044
|
-
if (!
|
|
5045
|
-
|
|
5062
|
+
function updateConfig$2(ctx, cfg) {
|
|
5063
|
+
if (!ctx.running || !ctx.config) {
|
|
5064
|
+
ctx.logger.warn('Enforcer is not running.');
|
|
5046
5065
|
return;
|
|
5047
5066
|
}
|
|
5048
|
-
|
|
5049
|
-
|
|
5067
|
+
ctx.config = { ...ctx.config, ...cfg };
|
|
5068
|
+
ctx.logger.log('Config updated:', cfg);
|
|
5050
5069
|
}
|
|
5051
5070
|
|
|
5052
5071
|
/**
|
|
@@ -5055,7 +5074,7 @@ function updateConfig$2(s, cfg) {
|
|
|
5055
5074
|
*/
|
|
5056
5075
|
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
5057
5076
|
function createEnforcer() {
|
|
5058
|
-
const
|
|
5077
|
+
const ctx = {
|
|
5059
5078
|
logger: createLogger({ enabled: false, prefix: 'ComputedStyleEnforcer' }),
|
|
5060
5079
|
doc: null,
|
|
5061
5080
|
win: null,
|
|
@@ -5065,19 +5084,19 @@ function createEnforcer() {
|
|
|
5065
5084
|
running: false,
|
|
5066
5085
|
};
|
|
5067
5086
|
return {
|
|
5068
|
-
start: (d, w, cfg, options) => start$3(
|
|
5069
|
-
stop: () => stop$3(
|
|
5070
|
-
reset: () => reset(
|
|
5071
|
-
trackElement: (element, propertyOriginalValues) => trackElement(
|
|
5072
|
-
processElement: (element, options) => processElement(
|
|
5073
|
-
processAll: (options) => processAll(
|
|
5074
|
-
updateConfig: (cfg) => updateConfig$2(
|
|
5087
|
+
start: (d, w, cfg, options) => start$3(ctx, d, w, cfg, options),
|
|
5088
|
+
stop: () => stop$3(ctx),
|
|
5089
|
+
reset: () => reset(ctx),
|
|
5090
|
+
trackElement: (element, propertyOriginalValues) => trackElement(ctx, element, propertyOriginalValues),
|
|
5091
|
+
processElement: (element, options) => processElement(ctx, element, options),
|
|
5092
|
+
processAll: (options) => processAll(ctx, options),
|
|
5093
|
+
updateConfig: (cfg) => updateConfig$2(ctx, cfg),
|
|
5075
5094
|
getStateInfo: () => ({
|
|
5076
|
-
isRunning:
|
|
5077
|
-
trackedElementsCount:
|
|
5078
|
-
hasConfig: !!
|
|
5095
|
+
isRunning: ctx.running,
|
|
5096
|
+
trackedElementsCount: ctx.elementsWithViewportUnits.size,
|
|
5097
|
+
hasConfig: !!ctx.config,
|
|
5079
5098
|
}),
|
|
5080
|
-
isRunning: () =>
|
|
5099
|
+
isRunning: () => ctx.running,
|
|
5081
5100
|
};
|
|
5082
5101
|
}
|
|
5083
5102
|
|
|
@@ -5446,82 +5465,83 @@ register(`566240210141053597`, {
|
|
|
5446
5465
|
});
|
|
5447
5466
|
|
|
5448
5467
|
// ── Module-level functions ────────────────────────────────────────────────────
|
|
5449
|
-
function start$2(
|
|
5450
|
-
if (
|
|
5451
|
-
|
|
5468
|
+
function start$2(ctx, iframe, cfg) {
|
|
5469
|
+
if (ctx.running) {
|
|
5470
|
+
ctx.logger.warn('Already running. Call stop() first.');
|
|
5452
5471
|
return;
|
|
5453
5472
|
}
|
|
5454
5473
|
if (!iframe.contentDocument || !iframe.contentWindow) {
|
|
5455
5474
|
throw new Error('Iframe document or window not accessible');
|
|
5456
5475
|
}
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
if (
|
|
5463
|
-
|
|
5464
|
-
|
|
5476
|
+
ctx.doc = iframe.contentDocument;
|
|
5477
|
+
ctx.win = iframe.contentWindow;
|
|
5478
|
+
ctx.config = cfg;
|
|
5479
|
+
ctx.running = true;
|
|
5480
|
+
ctx.shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
|
|
5481
|
+
if (ctx.shopFix) {
|
|
5482
|
+
ctx.logger.log(`Shop fix loaded for "${cfg.shopId}":`, ctx.shopFix.description ?? '(no description)');
|
|
5483
|
+
}
|
|
5484
|
+
ctx.logger.configure({ enabled: !!cfg.debug });
|
|
5465
5485
|
configure(!!cfg.debug);
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5486
|
+
ctx.enforcer.start(ctx.doc, ctx.win, cfg, { debug: !!cfg.debug });
|
|
5487
|
+
ctx.listeners.attach(cfg.debug);
|
|
5488
|
+
ctx.logger.log('Started');
|
|
5469
5489
|
}
|
|
5470
|
-
function stop$2(
|
|
5471
|
-
if (!
|
|
5490
|
+
function stop$2(ctx) {
|
|
5491
|
+
if (!ctx.running)
|
|
5472
5492
|
return;
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
}
|
|
5482
|
-
async function run(
|
|
5483
|
-
if (!
|
|
5484
|
-
|
|
5493
|
+
ctx.enforcer.stop();
|
|
5494
|
+
ctx.listeners.detach();
|
|
5495
|
+
ctx.doc = null;
|
|
5496
|
+
ctx.win = null;
|
|
5497
|
+
ctx.config = null;
|
|
5498
|
+
ctx.shopFix = null;
|
|
5499
|
+
ctx.running = false;
|
|
5500
|
+
ctx.logger.log('Stopped');
|
|
5501
|
+
}
|
|
5502
|
+
async function run(ctx) {
|
|
5503
|
+
if (!ctx.running || !ctx.doc || !ctx.win || !ctx.config) {
|
|
5504
|
+
ctx.logger.warn('Not running. Call start() first.');
|
|
5485
5505
|
return { height: 1000, width: 1000 };
|
|
5486
5506
|
}
|
|
5487
|
-
const
|
|
5488
|
-
doc:
|
|
5489
|
-
win:
|
|
5490
|
-
deviceType:
|
|
5491
|
-
targetWidth:
|
|
5492
|
-
targetHeight:
|
|
5493
|
-
debug:
|
|
5494
|
-
enforcer:
|
|
5495
|
-
};
|
|
5496
|
-
const activeGlobal = getActiveFixes(
|
|
5507
|
+
const pipelineCtx = {
|
|
5508
|
+
doc: ctx.doc,
|
|
5509
|
+
win: ctx.win,
|
|
5510
|
+
deviceType: ctx.config.deviceType,
|
|
5511
|
+
targetWidth: ctx.config.targetWidth,
|
|
5512
|
+
targetHeight: ctx.config.targetHeight,
|
|
5513
|
+
debug: ctx.config.debug,
|
|
5514
|
+
enforcer: ctx.enforcer,
|
|
5515
|
+
};
|
|
5516
|
+
const activeGlobal = getActiveFixes(pipelineCtx);
|
|
5497
5517
|
if (activeGlobal.length > 0)
|
|
5498
|
-
|
|
5518
|
+
ctx.logger.log(`Active global fixes: ${activeGlobal.map((f) => f.name).join(', ')}`);
|
|
5499
5519
|
const tRun = perf$3.mark('viewport.run');
|
|
5500
5520
|
try {
|
|
5501
|
-
const result = await run$1(
|
|
5521
|
+
const result = await run$1(pipelineCtx, activeGlobal, ctx.shopFix);
|
|
5502
5522
|
perf$3.measure('viewport.run', tRun);
|
|
5503
5523
|
return result;
|
|
5504
5524
|
}
|
|
5505
5525
|
catch (err) {
|
|
5506
5526
|
perf$3.measure('viewport.run', tRun);
|
|
5507
|
-
|
|
5508
|
-
return { height:
|
|
5527
|
+
ctx.logger.error('Critical error:', err);
|
|
5528
|
+
return { height: ctx.doc.body?.scrollHeight || 1000, width: ctx.doc.body?.scrollWidth || 1000 };
|
|
5509
5529
|
}
|
|
5510
5530
|
}
|
|
5511
|
-
function updateConfig$1(
|
|
5512
|
-
if (!
|
|
5513
|
-
|
|
5531
|
+
function updateConfig$1(ctx, cfg) {
|
|
5532
|
+
if (!ctx.running || !ctx.config) {
|
|
5533
|
+
ctx.logger.warn('Not running. Call start() first.');
|
|
5514
5534
|
return;
|
|
5515
5535
|
}
|
|
5516
|
-
|
|
5536
|
+
ctx.config = { ...ctx.config, ...cfg };
|
|
5517
5537
|
if (cfg.shopId !== undefined)
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5538
|
+
ctx.shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
|
|
5539
|
+
ctx.enforcer.updateConfig(cfg);
|
|
5540
|
+
ctx.logger.log('Config updated');
|
|
5521
5541
|
}
|
|
5522
5542
|
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
5523
5543
|
function createViewportProcessor() {
|
|
5524
|
-
const
|
|
5544
|
+
const ctx = {
|
|
5525
5545
|
logger: createLogger({ enabled: false, prefix: 'ViewportReplacer' }),
|
|
5526
5546
|
enforcer: createEnforcer(),
|
|
5527
5547
|
listeners: createViewportListeners(),
|
|
@@ -5532,11 +5552,11 @@ function createViewportProcessor() {
|
|
|
5532
5552
|
running: false,
|
|
5533
5553
|
};
|
|
5534
5554
|
return {
|
|
5535
|
-
start: (iframe, cfg) => start$2(
|
|
5536
|
-
stop: () => stop$2(
|
|
5537
|
-
run: () => run(
|
|
5538
|
-
updateConfig: (cfg) => updateConfig$1(
|
|
5539
|
-
isRunning: () =>
|
|
5555
|
+
start: (iframe, cfg) => start$2(ctx, iframe, cfg),
|
|
5556
|
+
stop: () => stop$2(ctx),
|
|
5557
|
+
run: () => run(ctx),
|
|
5558
|
+
updateConfig: (cfg) => updateConfig$1(ctx, cfg),
|
|
5559
|
+
isRunning: () => ctx.running,
|
|
5540
5560
|
};
|
|
5541
5561
|
}
|
|
5542
5562
|
|
|
@@ -5544,117 +5564,117 @@ function createViewportProcessor() {
|
|
|
5544
5564
|
function dispatchDimensionsEvent(dimensions) {
|
|
5545
5565
|
window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', { detail: dimensions }));
|
|
5546
5566
|
}
|
|
5547
|
-
async function process(
|
|
5548
|
-
if (!
|
|
5567
|
+
async function process(ctx) {
|
|
5568
|
+
if (!ctx.iframe || !ctx.config)
|
|
5549
5569
|
return;
|
|
5550
|
-
if (!
|
|
5551
|
-
|
|
5552
|
-
|
|
5570
|
+
if (!ctx.iframe.contentDocument || !ctx.iframe.contentWindow) {
|
|
5571
|
+
ctx.logger.error('Cannot access iframe document');
|
|
5572
|
+
ctx.config.onError?.(new Error('Cannot access iframe document'));
|
|
5553
5573
|
return;
|
|
5554
5574
|
}
|
|
5555
5575
|
const sessionId = `render-${Date.now()}`;
|
|
5556
5576
|
perf$3.startSession(sessionId);
|
|
5557
5577
|
const t0 = perf$3.mark('orchestrator.process');
|
|
5558
5578
|
try {
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
const result = await
|
|
5579
|
+
ctx.logger.groupCollapsed('Processing...');
|
|
5580
|
+
ctx.viewportReplacer.start(ctx.iframe, ctx.config);
|
|
5581
|
+
ctx.navigationBlocker.start(ctx.iframe, { debug: ctx.config.debug });
|
|
5582
|
+
const result = await ctx.viewportReplacer.run();
|
|
5563
5583
|
perf$3.measure('orchestrator.process', t0);
|
|
5564
5584
|
perf$3.endSession();
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5585
|
+
ctx.logger.groupEnd();
|
|
5586
|
+
ctx.logger.log('Process completed:', result);
|
|
5587
|
+
ctx.config.onSuccess?.(result);
|
|
5568
5588
|
dispatchDimensionsEvent(result);
|
|
5569
5589
|
}
|
|
5570
5590
|
catch (error) {
|
|
5571
5591
|
perf$3.measure('orchestrator.process', t0);
|
|
5572
5592
|
perf$3.endSession();
|
|
5573
|
-
|
|
5574
|
-
|
|
5593
|
+
ctx.logger.error('Failed to process:', error);
|
|
5594
|
+
ctx.config.onError?.(error);
|
|
5575
5595
|
}
|
|
5576
5596
|
}
|
|
5577
|
-
async function initialize(
|
|
5578
|
-
if (!
|
|
5579
|
-
|
|
5580
|
-
|
|
5597
|
+
async function initialize(ctx) {
|
|
5598
|
+
if (!ctx.iframe || !ctx.config) {
|
|
5599
|
+
ctx.logger.error('iframe not found');
|
|
5600
|
+
ctx.config?.onError?.(new Error('iframe not found'));
|
|
5581
5601
|
return;
|
|
5582
5602
|
}
|
|
5583
|
-
if (
|
|
5584
|
-
await process(
|
|
5603
|
+
if (ctx.iframe.contentDocument?.readyState === 'complete') {
|
|
5604
|
+
await process(ctx);
|
|
5585
5605
|
}
|
|
5586
5606
|
else {
|
|
5587
|
-
|
|
5588
|
-
|
|
5607
|
+
ctx.loadListener = () => process(ctx);
|
|
5608
|
+
ctx.iframe.addEventListener('load', ctx.loadListener);
|
|
5589
5609
|
}
|
|
5590
5610
|
}
|
|
5591
|
-
function start$1(
|
|
5592
|
-
if (
|
|
5593
|
-
|
|
5611
|
+
function start$1(ctx, cfg) {
|
|
5612
|
+
if (ctx.running) {
|
|
5613
|
+
ctx.logger.warn('Fixer is already running. Call stop() first.');
|
|
5594
5614
|
return;
|
|
5595
5615
|
}
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
initialize(
|
|
5616
|
+
ctx.iframe = cfg.iframe;
|
|
5617
|
+
ctx.config = cfg;
|
|
5618
|
+
ctx.running = true;
|
|
5619
|
+
ctx.logger.configure({ enabled: !!cfg.debug });
|
|
5620
|
+
ctx.logger.log('Started');
|
|
5621
|
+
initialize(ctx);
|
|
5602
5622
|
}
|
|
5603
|
-
function stop$1(
|
|
5604
|
-
if (!
|
|
5623
|
+
function stop$1(ctx) {
|
|
5624
|
+
if (!ctx.running)
|
|
5605
5625
|
return;
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
if (
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
}
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
}
|
|
5618
|
-
function startHeightObserver(
|
|
5619
|
-
if (!
|
|
5626
|
+
ctx.viewportReplacer.stop();
|
|
5627
|
+
ctx.heightObserver.stop();
|
|
5628
|
+
ctx.navigationBlocker.stop();
|
|
5629
|
+
if (ctx.iframe && ctx.loadListener) {
|
|
5630
|
+
ctx.iframe.removeEventListener('load', ctx.loadListener);
|
|
5631
|
+
ctx.loadListener = null;
|
|
5632
|
+
}
|
|
5633
|
+
ctx.iframe = null;
|
|
5634
|
+
ctx.config = null;
|
|
5635
|
+
ctx.running = false;
|
|
5636
|
+
ctx.logger.log('Stopped');
|
|
5637
|
+
}
|
|
5638
|
+
function startHeightObserver(ctx, config) {
|
|
5639
|
+
if (!ctx.iframe || !ctx.config)
|
|
5620
5640
|
return;
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
iframe:
|
|
5624
|
-
debug:
|
|
5641
|
+
ctx.heightObserver.stop();
|
|
5642
|
+
ctx.heightObserver.start(ctx.iframe, {
|
|
5643
|
+
iframe: ctx.iframe,
|
|
5644
|
+
debug: ctx.config.debug,
|
|
5625
5645
|
throttleMs: 25,
|
|
5626
5646
|
debounceMs: 500,
|
|
5627
5647
|
cooldownMs: 1000,
|
|
5628
|
-
startDelayMs:
|
|
5648
|
+
startDelayMs: ctx.config.heightObserverStartDelayMs,
|
|
5629
5649
|
onHeightChange: (result) => {
|
|
5630
|
-
|
|
5650
|
+
config?.onHeightChange?.(result);
|
|
5631
5651
|
dispatchDimensionsEvent(result);
|
|
5632
5652
|
},
|
|
5633
5653
|
onError: (error) => {
|
|
5634
|
-
|
|
5654
|
+
(config?.onError ?? ctx.config?.onError)?.(error);
|
|
5635
5655
|
},
|
|
5636
5656
|
});
|
|
5637
5657
|
}
|
|
5638
|
-
async function recalculate$1(
|
|
5639
|
-
if (!
|
|
5640
|
-
|
|
5658
|
+
async function recalculate$1(ctx) {
|
|
5659
|
+
if (!ctx.running) {
|
|
5660
|
+
ctx.logger.warn('Fixer is not running.');
|
|
5641
5661
|
return;
|
|
5642
5662
|
}
|
|
5643
|
-
|
|
5644
|
-
await process(
|
|
5663
|
+
ctx.logger.log('Recalculating...');
|
|
5664
|
+
await process(ctx);
|
|
5645
5665
|
}
|
|
5646
|
-
function updateConfig(
|
|
5647
|
-
if (!
|
|
5648
|
-
|
|
5666
|
+
function updateConfig(ctx, cfg) {
|
|
5667
|
+
if (!ctx.running || !ctx.config) {
|
|
5668
|
+
ctx.logger.warn('Fixer is not running.');
|
|
5649
5669
|
return;
|
|
5650
5670
|
}
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5671
|
+
ctx.config = { ...ctx.config, ...cfg };
|
|
5672
|
+
ctx.viewportReplacer.updateConfig(cfg);
|
|
5673
|
+
ctx.logger.log('Config updated');
|
|
5654
5674
|
}
|
|
5655
5675
|
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
5656
5676
|
function createOrchestrator() {
|
|
5657
|
-
const
|
|
5677
|
+
const ctx = {
|
|
5658
5678
|
logger: createLogger({ enabled: false, prefix: 'IframeFixer' }),
|
|
5659
5679
|
viewportReplacer: createViewportProcessor(),
|
|
5660
5680
|
navigationBlocker: createNavigationBlocker(),
|
|
@@ -5665,23 +5685,23 @@ function createOrchestrator() {
|
|
|
5665
5685
|
loadListener: null,
|
|
5666
5686
|
};
|
|
5667
5687
|
return {
|
|
5668
|
-
start: (cfg) => start$1(
|
|
5669
|
-
stop: () => stop$1(
|
|
5670
|
-
recalculate: () => recalculate$1(
|
|
5671
|
-
updateConfig: (cfg) => updateConfig(
|
|
5672
|
-
enableNavigationBlocking: () =>
|
|
5673
|
-
enableNavigationBlockingMessage: () =>
|
|
5674
|
-
disableNavigationBlocking: () =>
|
|
5675
|
-
disableNavigationBlockingMessage: () =>
|
|
5676
|
-
startHeightObserver: () => startHeightObserver(
|
|
5677
|
-
isRunning: () =>
|
|
5688
|
+
start: (cfg) => start$1(ctx, cfg),
|
|
5689
|
+
stop: () => stop$1(ctx),
|
|
5690
|
+
recalculate: () => recalculate$1(ctx),
|
|
5691
|
+
updateConfig: (cfg) => updateConfig(ctx, cfg),
|
|
5692
|
+
enableNavigationBlocking: () => ctx.navigationBlocker.enable(),
|
|
5693
|
+
enableNavigationBlockingMessage: () => ctx.navigationBlocker.enableMessage(),
|
|
5694
|
+
disableNavigationBlocking: () => ctx.navigationBlocker.disable(),
|
|
5695
|
+
disableNavigationBlockingMessage: () => ctx.navigationBlocker.disableMessage(),
|
|
5696
|
+
startHeightObserver: (config) => startHeightObserver(ctx, config),
|
|
5697
|
+
isRunning: () => ctx.running,
|
|
5678
5698
|
getStateInfo: () => ({
|
|
5679
|
-
isRunning:
|
|
5680
|
-
hasIframe: !!
|
|
5681
|
-
hasConfig: !!
|
|
5682
|
-
hasNavigationBlocker:
|
|
5683
|
-
hasHeightObserver:
|
|
5684
|
-
viewportReplacerRunning:
|
|
5699
|
+
isRunning: ctx.running,
|
|
5700
|
+
hasIframe: !!ctx.iframe,
|
|
5701
|
+
hasConfig: !!ctx.config,
|
|
5702
|
+
hasNavigationBlocker: ctx.navigationBlocker.isRunning(),
|
|
5703
|
+
hasHeightObserver: ctx.heightObserver.isRunning(),
|
|
5704
|
+
viewportReplacerRunning: ctx.viewportReplacer.isRunning(),
|
|
5685
5705
|
}),
|
|
5686
5706
|
};
|
|
5687
5707
|
}
|
|
@@ -5690,50 +5710,50 @@ function createOrchestrator() {
|
|
|
5690
5710
|
* Iframe Helper — factory entry point.
|
|
5691
5711
|
*
|
|
5692
5712
|
* Each call to `createIframeHelper()` returns a fully isolated instance
|
|
5693
|
-
* with its own processor
|
|
5713
|
+
* with its own processor ctx. Use one instance per iframe.
|
|
5694
5714
|
*/
|
|
5695
5715
|
// ── Module-level functions ────────────────────────────────────────────────────
|
|
5696
|
-
function start(
|
|
5697
|
-
if (
|
|
5716
|
+
function start(ctx, config) {
|
|
5717
|
+
if (ctx.running) {
|
|
5698
5718
|
console.warn('[IframeHelper] Already running. Call stop() first.');
|
|
5699
5719
|
return;
|
|
5700
5720
|
}
|
|
5701
|
-
|
|
5702
|
-
|
|
5721
|
+
ctx.fixer.start(config);
|
|
5722
|
+
ctx.running = true;
|
|
5703
5723
|
}
|
|
5704
|
-
function stop(
|
|
5705
|
-
if (!
|
|
5724
|
+
function stop(ctx) {
|
|
5725
|
+
if (!ctx.running)
|
|
5706
5726
|
return;
|
|
5707
|
-
|
|
5708
|
-
|
|
5727
|
+
ctx.fixer.stop();
|
|
5728
|
+
ctx.running = false;
|
|
5709
5729
|
}
|
|
5710
|
-
async function recalculate(
|
|
5711
|
-
if (!
|
|
5730
|
+
async function recalculate(ctx) {
|
|
5731
|
+
if (!ctx.running) {
|
|
5712
5732
|
console.warn('[IframeHelper] Not running. Call start() first.');
|
|
5713
5733
|
return;
|
|
5714
5734
|
}
|
|
5715
|
-
await
|
|
5735
|
+
await ctx.fixer.recalculate();
|
|
5716
5736
|
}
|
|
5717
|
-
function enableNavigationBlocking(
|
|
5718
|
-
if (!
|
|
5737
|
+
function enableNavigationBlocking(ctx) {
|
|
5738
|
+
if (!ctx.running) {
|
|
5719
5739
|
console.warn('[IframeHelper] Not running. Call start() first.');
|
|
5720
5740
|
return;
|
|
5721
5741
|
}
|
|
5722
|
-
|
|
5742
|
+
ctx.fixer.enableNavigationBlocking();
|
|
5723
5743
|
}
|
|
5724
5744
|
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
5725
5745
|
function createIframeHelper() {
|
|
5726
|
-
const
|
|
5746
|
+
const ctx = {
|
|
5727
5747
|
fixer: createOrchestrator(),
|
|
5728
5748
|
running: false,
|
|
5729
5749
|
};
|
|
5730
5750
|
return {
|
|
5731
|
-
start: (config) => start(
|
|
5732
|
-
stop: () => stop(
|
|
5733
|
-
recalculate: () => recalculate(
|
|
5734
|
-
enableNavigationBlocking: () => enableNavigationBlocking(
|
|
5735
|
-
startHeightObserver: () =>
|
|
5736
|
-
isRunning: () =>
|
|
5751
|
+
start: (config) => start(ctx, config),
|
|
5752
|
+
stop: () => stop(ctx),
|
|
5753
|
+
recalculate: () => recalculate(ctx),
|
|
5754
|
+
enableNavigationBlocking: () => enableNavigationBlocking(ctx),
|
|
5755
|
+
startHeightObserver: (config) => ctx.fixer.startHeightObserver(config),
|
|
5756
|
+
isRunning: () => ctx.running,
|
|
5737
5757
|
};
|
|
5738
5758
|
}
|
|
5739
5759
|
|
|
@@ -6168,6 +6188,7 @@ class ScrollBucketRenderer {
|
|
|
6168
6188
|
this.redrawTimeout = setTimeout(() => this.draw(this.lastData), REDRAW_INTERVAL);
|
|
6169
6189
|
};
|
|
6170
6190
|
attachDimensionsListener = () => {
|
|
6191
|
+
this.detachDimensionsListener();
|
|
6171
6192
|
this.dimensionsListener = () => this.redraw();
|
|
6172
6193
|
window.addEventListener('iframe-dimensions-applied', this.dimensionsListener);
|
|
6173
6194
|
};
|
|
@@ -6212,6 +6233,7 @@ class ScrollBucketRenderer {
|
|
|
6212
6233
|
const doc = this.heatmap.state.window.document;
|
|
6213
6234
|
const body = doc.body;
|
|
6214
6235
|
const de = doc.documentElement;
|
|
6236
|
+
// Same formula as HeatmapHelper.scroll() — self-contained, no external dependency
|
|
6215
6237
|
const height = Math.max(body.scrollHeight, body.offsetHeight, de.clientHeight, de.scrollHeight, de.offsetHeight);
|
|
6216
6238
|
// Same canvas setup as HeatmapHelper.scroll(): full content height, top=0
|
|
6217
6239
|
canvas.height = Math.min(height, CANVAS_MAX_HEIGHT);
|
|
@@ -6220,59 +6242,39 @@ class ScrollBucketRenderer {
|
|
|
6220
6242
|
return;
|
|
6221
6243
|
const buckets = this.mapToBuckets(data);
|
|
6222
6244
|
const maxPercent = buckets.length > 0 ? Math.max(...buckets.map((b) => b.percent)) : 0;
|
|
6223
|
-
//
|
|
6224
|
-
|
|
6225
|
-
const
|
|
6226
|
-
if (buckets.length
|
|
6227
|
-
//
|
|
6228
|
-
gradient.addColorStop(0, coldColor);
|
|
6229
|
-
gradient.addColorStop(1, coldColor);
|
|
6230
|
-
}
|
|
6231
|
-
else {
|
|
6245
|
+
// Build a per-percentage-point hue array (same pattern as AttentionMapRenderer)
|
|
6246
|
+
// Cold hue (240 = blue) is the baseline when there is no data
|
|
6247
|
+
const hueStops = new Array(101).fill(240);
|
|
6248
|
+
if (buckets.length > 0 && maxPercent > 0) {
|
|
6249
|
+
// Pass 1: fill each bucket's pure color (exclusive of shared boundary point)
|
|
6232
6250
|
for (const bucket of buckets) {
|
|
6233
|
-
const stopMid = (bucket.startY + bucket.endY) / 2 / 100;
|
|
6234
|
-
// Same hue direction as HeatmapHelper.scroll() (MaxHue = 240):
|
|
6235
6251
|
// high percent → hue 0 (red/hot), low percent → hue 240 (blue/cold)
|
|
6236
|
-
const hue = (1 - bucket.percent / maxPercent) * 240;
|
|
6237
|
-
|
|
6238
|
-
|
|
6252
|
+
const hue = Math.round((1 - bucket.percent / maxPercent) * 240);
|
|
6253
|
+
for (let i = bucket.startY; i < bucket.endY; i++) {
|
|
6254
|
+
hueStops[i] = hue;
|
|
6255
|
+
}
|
|
6239
6256
|
}
|
|
6257
|
+
// Set last point of final bucket
|
|
6258
|
+
const last = buckets[buckets.length - 1];
|
|
6259
|
+
hueStops[last.endY] = Math.round((1 - last.percent / maxPercent) * 240);
|
|
6260
|
+
// Pass 2: center transitions at bucket boundaries (average of two adjacent hues)
|
|
6261
|
+
for (let b = 0; b < buckets.length - 1; b++) {
|
|
6262
|
+
const boundary = buckets[b].endY; // = buckets[b+1].startY
|
|
6263
|
+
const hueA = Math.round((1 - buckets[b].percent / maxPercent) * 240);
|
|
6264
|
+
const hueB = Math.round((1 - buckets[b + 1].percent / maxPercent) * 240);
|
|
6265
|
+
hueStops[boundary] = Math.round((hueA + hueB) / 2);
|
|
6266
|
+
}
|
|
6267
|
+
}
|
|
6268
|
+
const gradient = context.createLinearGradient(0, 0, 0, canvas.height);
|
|
6269
|
+
for (let i = 0; i <= 100; i++) {
|
|
6270
|
+
gradient.addColorStop(i / 100, `hsla(${hueStops[i]}, 100%, 50%, 0.6)`);
|
|
6240
6271
|
}
|
|
6241
6272
|
context.fillStyle = gradient;
|
|
6242
6273
|
context.fillRect(0, 0, canvas.width, canvas.height);
|
|
6243
6274
|
};
|
|
6244
|
-
/**
|
|
6245
|
-
* Convert flat position markers → structured buckets with startY/endY.
|
|
6246
|
-
*
|
|
6247
|
-
* Input positions: [0, 5, 10, 15, ..., 95]
|
|
6248
|
-
* position=0 → { startY: 0, endY: 5 } (special start marker)
|
|
6249
|
-
* position=10 → { startY: 5, endY: 10 }
|
|
6250
|
-
* position=15 → { startY: 10, endY: 15 }
|
|
6251
|
-
*/
|
|
6252
6275
|
mapToBuckets = (data) => {
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
for (let i = 0; i < sorted.length; i++) {
|
|
6256
|
-
const current = sorted[i];
|
|
6257
|
-
let startY;
|
|
6258
|
-
let endY;
|
|
6259
|
-
if (current.position === 0) {
|
|
6260
|
-
// position=0 is the start marker → range 0 to next position
|
|
6261
|
-
const next = sorted[i + 1];
|
|
6262
|
-
if (!next)
|
|
6263
|
-
continue;
|
|
6264
|
-
startY = 0;
|
|
6265
|
-
endY = next.position;
|
|
6266
|
-
}
|
|
6267
|
-
else {
|
|
6268
|
-
// Each non-zero position is the END of its bucket; start = previous position
|
|
6269
|
-
const prev = sorted[i - 1];
|
|
6270
|
-
startY = prev ? prev.position : 0;
|
|
6271
|
-
endY = current.position;
|
|
6272
|
-
}
|
|
6273
|
-
buckets.push({ startY, endY, value: current.value, percent: current.percent });
|
|
6274
|
-
}
|
|
6275
|
-
return buckets;
|
|
6276
|
+
// Implement
|
|
6277
|
+
return data;
|
|
6276
6278
|
};
|
|
6277
6279
|
}
|
|
6278
6280
|
|
|
@@ -6750,11 +6752,7 @@ const useHeatmapIframeProcessor = () => {
|
|
|
6750
6752
|
const reset = useCallback(() => {
|
|
6751
6753
|
pendingRef.current = null;
|
|
6752
6754
|
}, []);
|
|
6753
|
-
const
|
|
6754
|
-
if (viewport.width === 0 || viewport.height === 0) {
|
|
6755
|
-
pendingRef.current = { iframe, t0, abort };
|
|
6756
|
-
return;
|
|
6757
|
-
}
|
|
6755
|
+
const callStartIframe = useCallback((iframe, t0, abort) => {
|
|
6758
6756
|
startIframe({
|
|
6759
6757
|
helperRef,
|
|
6760
6758
|
iframe,
|
|
@@ -6762,16 +6760,30 @@ const useHeatmapIframeProcessor = () => {
|
|
|
6762
6760
|
deviceType,
|
|
6763
6761
|
size: viewport,
|
|
6764
6762
|
t0,
|
|
6765
|
-
onSuccess: (
|
|
6763
|
+
onSuccess: (data) => {
|
|
6766
6764
|
if (abort.signal.aborted)
|
|
6767
6765
|
return;
|
|
6768
|
-
if (height)
|
|
6769
|
-
setIframeHeight(height);
|
|
6766
|
+
if (data.height)
|
|
6767
|
+
setIframeHeight(data.height);
|
|
6770
6768
|
setIsDomLoaded(true);
|
|
6771
|
-
helperRef.current?.startHeightObserver(
|
|
6769
|
+
helperRef.current?.startHeightObserver({
|
|
6770
|
+
onHeightChange: (data) => {
|
|
6771
|
+
if (abort.signal.aborted)
|
|
6772
|
+
return;
|
|
6773
|
+
if (data.height)
|
|
6774
|
+
setIframeHeight(data.height);
|
|
6775
|
+
},
|
|
6776
|
+
});
|
|
6772
6777
|
},
|
|
6773
6778
|
});
|
|
6774
|
-
}, [deviceType]);
|
|
6779
|
+
}, [deviceType, shopId, viewport, setIframeHeight, setIsDomLoaded]);
|
|
6780
|
+
const run = useCallback((iframe, t0, abort) => {
|
|
6781
|
+
if (viewport.width === 0 || viewport.height === 0) {
|
|
6782
|
+
pendingRef.current = { iframe, t0, abort };
|
|
6783
|
+
return;
|
|
6784
|
+
}
|
|
6785
|
+
callStartIframe(iframe, t0, abort);
|
|
6786
|
+
}, [callStartIframe, viewport]);
|
|
6775
6787
|
// Retry when dims become available
|
|
6776
6788
|
useEffect(() => {
|
|
6777
6789
|
if (viewport.width === 0 || viewport.height === 0)
|
|
@@ -6782,29 +6794,8 @@ const useHeatmapIframeProcessor = () => {
|
|
|
6782
6794
|
pendingRef.current = null;
|
|
6783
6795
|
if (abort.signal.aborted)
|
|
6784
6796
|
return;
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
iframe,
|
|
6788
|
-
shopId,
|
|
6789
|
-
deviceType,
|
|
6790
|
-
size: viewport,
|
|
6791
|
-
t0,
|
|
6792
|
-
onSuccess: (height) => {
|
|
6793
|
-
if (abort.signal.aborted)
|
|
6794
|
-
return;
|
|
6795
|
-
if (height)
|
|
6796
|
-
setIframeHeight(height);
|
|
6797
|
-
setIsDomLoaded(true);
|
|
6798
|
-
helperRef.current?.startHeightObserver();
|
|
6799
|
-
},
|
|
6800
|
-
onHeightChange: (height) => {
|
|
6801
|
-
if (abort.signal.aborted)
|
|
6802
|
-
return;
|
|
6803
|
-
if (height)
|
|
6804
|
-
setIframeHeight(height);
|
|
6805
|
-
},
|
|
6806
|
-
});
|
|
6807
|
-
}, [viewport]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
6797
|
+
callStartIframe(iframe, t0, abort);
|
|
6798
|
+
}, [viewport, callStartIframe]);
|
|
6808
6799
|
useEffect(() => {
|
|
6809
6800
|
return () => {
|
|
6810
6801
|
helperRef.current?.stop();
|
|
@@ -6814,7 +6805,7 @@ const useHeatmapIframeProcessor = () => {
|
|
|
6814
6805
|
return { run, reset };
|
|
6815
6806
|
};
|
|
6816
6807
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
6817
|
-
function startIframe({ helperRef, iframe, shopId, deviceType = EDeviceType.Desktop, size, t0, onSuccess,
|
|
6808
|
+
function startIframe({ helperRef, iframe, shopId, deviceType = EDeviceType.Desktop, size, t0, onSuccess, }) {
|
|
6818
6809
|
const docWidth = size.width ?? 0;
|
|
6819
6810
|
const docHeight = size.height ?? 0;
|
|
6820
6811
|
if (docHeight === 0)
|
|
@@ -6835,11 +6826,7 @@ function startIframe({ helperRef, iframe, shopId, deviceType = EDeviceType.Deskt
|
|
|
6835
6826
|
perf$1.measure('IframeHelper processing', tHelper);
|
|
6836
6827
|
perf$1.measure('Total render', t0);
|
|
6837
6828
|
iframe.style.height = `${data.height}px`;
|
|
6838
|
-
onSuccess(data
|
|
6839
|
-
},
|
|
6840
|
-
onHeightChange: (data) => {
|
|
6841
|
-
iframe.style.height = `${data.height}px`;
|
|
6842
|
-
onHeightChange?.(data.height);
|
|
6829
|
+
onSuccess(data);
|
|
6843
6830
|
},
|
|
6844
6831
|
});
|
|
6845
6832
|
}
|
|
@@ -9037,4 +9024,4 @@ const HeatmapLayout = ({ shopId, data, clickmap, clickAreas, scrollmap, attentio
|
|
|
9037
9024
|
}
|
|
9038
9025
|
};
|
|
9039
9026
|
|
|
9040
|
-
export { BACKDROP_CONFIG, DEFAULT_SIDEBAR_WIDTH, DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO, EClickMode, EClickRankType, EClickType, EDeviceType, EHeatmapDataSource, EHeatmapMode, EHeatmapType, ELM_CALLOUT_CONFIG, EScrollType, GraphView, HEATMAP_CONFIG, HEATMAP_IFRAME, HEATMAP_STYLE, HeatmapLayout, ViewIdContext, Z_INDEX$1 as Z_INDEX, compareViewPerformance, convertViewportToIframeCoords, createStorePerformanceTracker, createViewContextHook, decodeArrayClarity, decodeClarity, downloadPerformanceReport, getCompareViewId, getElementAtPoint, getElementHash, getMetricsByViewId, getPerformanceReportJSON, getScrollGradientColor, isElmInDataInfo, performanceLogger, printPerformanceSummary, scrollToElementIfNeeded, sendPerformanceReport, serializeAreas, trackStoreAction, useAreaCreation, useAreaEditMode, useAreaFilterVisible, useAreaHydration, useAreaInteraction, useAreaPositionsUpdater, useAreaRectSync, useAreaRendererContainer, useAreaTopAutoDetect, useClickedElement, useDebounceCallback, useElementCalloutVisible, useHeatmapAreaClickContext, useHeatmapCanvas, useHeatmapClickContext, useHeatmapCompareStore, useHeatmapConfigStore, useHeatmapCopyView, useHeatmapDataContext, useHeatmapEffects, useHeatmapElementPosition, useHeatmapHoverContext, useHeatmapLiveContext, useHeatmapRenderByMode, useHeatmapScale, useHeatmapScroll, useHeatmapScrollContext, useHeatmapSettingContext, useHeatmapViewportByDevice, useHeatmapVizContext, useHeatmapVizRectContext, useHoveredElement, useMeasureFunction, useRegisterConfig, useRegisterControl, useRegisterData, useRegisterHeatmap, useRenderCount, useScrollmapZones, useTrackHookCall, useViewIdContext, useVizLiveRender, useWhyDidYouUpdate, useWrapperRefHeight, useZonePositions, withPerformanceTracking };
|
|
9027
|
+
export { BACKDROP_CONFIG, DEFAULT_SIDEBAR_WIDTH, DEFAULT_VIEW_ID, DEFAULT_ZOOM_RATIO, EClickMode, EClickRankType, EClickType, EDeviceType, EHeatmapDataSource, EHeatmapMode, EHeatmapType, ELM_CALLOUT_CONFIG, EScrollType, GraphView, HEATMAP_CONFIG, HEATMAP_IFRAME, HEATMAP_STYLE, HeatmapLayout, ViewIdContext, Z_INDEX$1 as Z_INDEX, buildBuckets, compareViewPerformance, convertViewportToIframeCoords, createStorePerformanceTracker, createViewContextHook, decodeArrayClarity, decodeClarity, downloadPerformanceReport, getCompareViewId, getElementAtPoint, getElementHash, getMetricsByViewId, getPerformanceReportJSON, getScrollGradientColor, isElmInDataInfo, performanceLogger, printPerformanceSummary, scrollToElementIfNeeded, sendPerformanceReport, serializeAreas, trackStoreAction, useAreaCreation, useAreaEditMode, useAreaFilterVisible, useAreaHydration, useAreaInteraction, useAreaPositionsUpdater, useAreaRectSync, useAreaRendererContainer, useAreaTopAutoDetect, useClickedElement, useDebounceCallback, useElementCalloutVisible, useHeatmapAreaClickContext, useHeatmapCanvas, useHeatmapClickContext, useHeatmapCompareStore, useHeatmapConfigStore, useHeatmapCopyView, useHeatmapDataContext, useHeatmapEffects, useHeatmapElementPosition, useHeatmapHoverContext, useHeatmapLiveContext, useHeatmapRenderByMode, useHeatmapScale, useHeatmapScroll, useHeatmapScrollContext, useHeatmapSettingContext, useHeatmapViewportByDevice, useHeatmapVizContext, useHeatmapVizRectContext, useHoveredElement, useMeasureFunction, useRegisterConfig, useRegisterControl, useRegisterData, useRegisterHeatmap, useRenderCount, useScrollmapZones, useTrackHookCall, useViewIdContext, useVizLiveRender, useWhyDidYouUpdate, useWrapperRefHeight, useZonePositions, withPerformanceTracking };
|