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