saltfish 0.3.55 → 0.3.57
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/core/services/PlaylistOrchestrator.d.ts.map +1 -1
- package/dist/managers/CursorManager.d.ts +10 -1
- package/dist/managers/CursorManager.d.ts.map +1 -1
- package/dist/managers/TransitionManager.d.ts.map +1 -1
- package/dist/managers/TriggerManager.d.ts +8 -0
- package/dist/managers/TriggerManager.d.ts.map +1 -1
- package/dist/player.js +2 -2
- package/dist/player.min.js +2 -2
- package/dist/saltfish-playlist-player.es.js +237 -42
- package/dist/saltfish-playlist-player.umd.js +1 -1
- package/dist/types/index.d.ts +12 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/elementSizeValidator.d.ts +49 -0
- package/dist/utils/elementSizeValidator.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -2754,6 +2754,7 @@ class PlaylistOrchestrator {
|
|
|
2754
2754
|
}
|
|
2755
2755
|
const runId = this.managers.sessionManager.startNewRun();
|
|
2756
2756
|
log(`PlaylistOrchestrator: Starting playlist ${playlistId} with runId: ${runId}`);
|
|
2757
|
+
this.managers.triggerManager.markPlaylistAsTriggered(playlistId);
|
|
2757
2758
|
const userDataLoadedPromise = (_c = this.userManagementService) == null ? void 0 : _c.getUserDataLoadedPromise();
|
|
2758
2759
|
if (userDataLoadedPromise) {
|
|
2759
2760
|
log("[PlaylistOrchestrator.startPlaylist] Waiting for user data to load before checking A/B test assignments");
|
|
@@ -6685,6 +6686,121 @@ const THRESHOLDS = {
|
|
|
6685
6686
|
/** Minimum scroll distance in pixels to trigger scroll events */
|
|
6686
6687
|
SCROLL_THRESHOLD_PX: 10
|
|
6687
6688
|
};
|
|
6689
|
+
const DEFAULT_CONFIG = {
|
|
6690
|
+
tolerance: 0.3,
|
|
6691
|
+
// 30% size difference allowed (70% match required)
|
|
6692
|
+
minSize: 1
|
|
6693
|
+
// Minimum 1x1px (reject only zero-size elements)
|
|
6694
|
+
};
|
|
6695
|
+
function getBasicRejectionReason(element, config) {
|
|
6696
|
+
const rect = element.getBoundingClientRect();
|
|
6697
|
+
if (rect.width === 0 || rect.height === 0) {
|
|
6698
|
+
return "zero size";
|
|
6699
|
+
}
|
|
6700
|
+
if (rect.width < config.minSize || rect.height < config.minSize) {
|
|
6701
|
+
return `too small (${rect.width.toFixed(0)}x${rect.height.toFixed(0)})`;
|
|
6702
|
+
}
|
|
6703
|
+
return null;
|
|
6704
|
+
}
|
|
6705
|
+
function calculateSizeScore(element, expected) {
|
|
6706
|
+
const rect = element.getBoundingClientRect();
|
|
6707
|
+
const widthRatio = Math.min(rect.width, expected.width) / Math.max(rect.width, expected.width);
|
|
6708
|
+
const heightRatio = Math.min(rect.height, expected.height) / Math.max(rect.height, expected.height);
|
|
6709
|
+
return (widthRatio + heightRatio) / 2 * 100;
|
|
6710
|
+
}
|
|
6711
|
+
function findValidElement(selector, expectedSize, config = DEFAULT_CONFIG) {
|
|
6712
|
+
const elements = document.querySelectorAll(selector);
|
|
6713
|
+
if (elements.length === 0) {
|
|
6714
|
+
return null;
|
|
6715
|
+
}
|
|
6716
|
+
if (!expectedSize) {
|
|
6717
|
+
for (const element of elements) {
|
|
6718
|
+
const rejection = getBasicRejectionReason(element, config);
|
|
6719
|
+
if (!rejection) {
|
|
6720
|
+
return element;
|
|
6721
|
+
}
|
|
6722
|
+
}
|
|
6723
|
+
return elements[0];
|
|
6724
|
+
}
|
|
6725
|
+
const threshold = (1 - config.tolerance) * 100;
|
|
6726
|
+
const scored = [];
|
|
6727
|
+
for (const element of elements) {
|
|
6728
|
+
const rejection = getBasicRejectionReason(element, config);
|
|
6729
|
+
if (rejection) {
|
|
6730
|
+
scored.push({ element, score: -1, rejection });
|
|
6731
|
+
continue;
|
|
6732
|
+
}
|
|
6733
|
+
const score = calculateSizeScore(element, expectedSize);
|
|
6734
|
+
if (score < threshold) {
|
|
6735
|
+
const rect = element.getBoundingClientRect();
|
|
6736
|
+
scored.push({
|
|
6737
|
+
element,
|
|
6738
|
+
score,
|
|
6739
|
+
rejection: `size mismatch: expected ~${expectedSize.width.toFixed(0)}x${expectedSize.height.toFixed(0)}, got ${rect.width.toFixed(0)}x${rect.height.toFixed(0)}`
|
|
6740
|
+
});
|
|
6741
|
+
} else {
|
|
6742
|
+
scored.push({ element, score });
|
|
6743
|
+
}
|
|
6744
|
+
}
|
|
6745
|
+
log(`ElementValidator: ${scored.length} element(s) for '${selector}' (expected ~${expectedSize.width.toFixed(0)}x${expectedSize.height.toFixed(0)})`);
|
|
6746
|
+
for (let i = 0; i < scored.length; i++) {
|
|
6747
|
+
const s = scored[i];
|
|
6748
|
+
const rect = s.element.getBoundingClientRect();
|
|
6749
|
+
const status = s.rejection ? `REJECTED (${s.rejection})` : `OK (${s.score.toFixed(0)}%)`;
|
|
6750
|
+
log(` [${i}] ${rect.width.toFixed(0)}x${rect.height.toFixed(0)} - ${status}`);
|
|
6751
|
+
}
|
|
6752
|
+
const valid = scored.filter((s) => !s.rejection);
|
|
6753
|
+
if (valid.length === 0) {
|
|
6754
|
+
return null;
|
|
6755
|
+
}
|
|
6756
|
+
valid.sort((a, b) => b.score - a.score);
|
|
6757
|
+
log(`ElementValidator: Selected element with ${valid[0].score.toFixed(0)}% match`);
|
|
6758
|
+
return valid[0].element;
|
|
6759
|
+
}
|
|
6760
|
+
function findAllValidElements(selector, expectedSize, config = DEFAULT_CONFIG) {
|
|
6761
|
+
const elements = document.querySelectorAll(selector);
|
|
6762
|
+
if (elements.length === 0) {
|
|
6763
|
+
return [];
|
|
6764
|
+
}
|
|
6765
|
+
if (!expectedSize) {
|
|
6766
|
+
const valid2 = [];
|
|
6767
|
+
for (const element of elements) {
|
|
6768
|
+
const rejection = getBasicRejectionReason(element, config);
|
|
6769
|
+
if (!rejection) {
|
|
6770
|
+
valid2.push(element);
|
|
6771
|
+
}
|
|
6772
|
+
}
|
|
6773
|
+
return valid2.length > 0 ? valid2 : Array.from(elements);
|
|
6774
|
+
}
|
|
6775
|
+
const threshold = (1 - config.tolerance) * 100;
|
|
6776
|
+
const valid = [];
|
|
6777
|
+
for (const element of elements) {
|
|
6778
|
+
const rejection = getBasicRejectionReason(element, config);
|
|
6779
|
+
if (rejection) {
|
|
6780
|
+
continue;
|
|
6781
|
+
}
|
|
6782
|
+
const score = calculateSizeScore(element, expectedSize);
|
|
6783
|
+
if (score >= threshold) {
|
|
6784
|
+
valid.push(element);
|
|
6785
|
+
}
|
|
6786
|
+
}
|
|
6787
|
+
if (valid.length > 0) {
|
|
6788
|
+
log(`ElementValidator: Found ${valid.length} valid element(s) for '${selector}'`);
|
|
6789
|
+
}
|
|
6790
|
+
return valid;
|
|
6791
|
+
}
|
|
6792
|
+
function isElementValid(element, expectedSize, config = DEFAULT_CONFIG) {
|
|
6793
|
+
const rejection = getBasicRejectionReason(element, config);
|
|
6794
|
+
if (rejection) {
|
|
6795
|
+
return false;
|
|
6796
|
+
}
|
|
6797
|
+
if (!expectedSize) {
|
|
6798
|
+
return true;
|
|
6799
|
+
}
|
|
6800
|
+
const threshold = (1 - config.tolerance) * 100;
|
|
6801
|
+
const score = calculateSizeScore(element, expectedSize);
|
|
6802
|
+
return score >= threshold;
|
|
6803
|
+
}
|
|
6688
6804
|
class CursorManager {
|
|
6689
6805
|
constructor() {
|
|
6690
6806
|
__publicField(this, "cursor", null);
|
|
@@ -6858,40 +6974,61 @@ class CursorManager {
|
|
|
6858
6974
|
* Sets up a MutationObserver to wait for an element to appear in the DOM
|
|
6859
6975
|
* @param selector - CSS selector to wait for
|
|
6860
6976
|
* @param callback - Callback to execute when element is found
|
|
6977
|
+
* @param expectedSize - Optional expected size for validation
|
|
6861
6978
|
*/
|
|
6862
|
-
waitForElement(selector, callback) {
|
|
6979
|
+
waitForElement(selector, callback, expectedSize) {
|
|
6863
6980
|
if (this.targetMutationObserver) {
|
|
6864
6981
|
this.targetMutationObserver.disconnect();
|
|
6865
6982
|
this.targetMutationObserver = null;
|
|
6866
6983
|
}
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6984
|
+
const MAX_RETRIES = 10;
|
|
6985
|
+
let retryCount = 0;
|
|
6986
|
+
let periodicCheckId = null;
|
|
6987
|
+
const cleanupWatchers = () => {
|
|
6988
|
+
if (this.targetMutationObserver) {
|
|
6989
|
+
this.targetMutationObserver.disconnect();
|
|
6870
6990
|
this.targetMutationObserver = null;
|
|
6991
|
+
}
|
|
6992
|
+
if (periodicCheckId !== null) {
|
|
6993
|
+
clearInterval(periodicCheckId);
|
|
6994
|
+
periodicCheckId = null;
|
|
6995
|
+
}
|
|
6996
|
+
};
|
|
6997
|
+
const tryFindElement = async () => {
|
|
6998
|
+
retryCount++;
|
|
6999
|
+
if (retryCount > MAX_RETRIES) {
|
|
7000
|
+
console.warn(`CursorManager: Stopped waiting for element '${selector}' after ${MAX_RETRIES} attempts`);
|
|
7001
|
+
cleanupWatchers();
|
|
7002
|
+
return null;
|
|
7003
|
+
}
|
|
7004
|
+
return this.findElementAndScrollIntoView(selector, expectedSize);
|
|
7005
|
+
};
|
|
7006
|
+
this.targetMutationObserver = new MutationObserver(async () => {
|
|
7007
|
+
if (this.isAutoplayBlocked()) {
|
|
7008
|
+
cleanupWatchers();
|
|
6871
7009
|
return;
|
|
6872
7010
|
}
|
|
6873
|
-
const el = await
|
|
7011
|
+
const el = await tryFindElement();
|
|
6874
7012
|
if (el) {
|
|
6875
|
-
|
|
6876
|
-
this.targetMutationObserver = null;
|
|
7013
|
+
cleanupWatchers();
|
|
6877
7014
|
callback(el);
|
|
6878
7015
|
}
|
|
6879
7016
|
});
|
|
6880
7017
|
this.targetMutationObserver.observe(document.body, { childList: true, subtree: true });
|
|
6881
|
-
|
|
7018
|
+
periodicCheckId = setInterval(() => {
|
|
6882
7019
|
if (!this.targetMutationObserver || this.isAutoplayBlocked()) {
|
|
6883
|
-
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
7020
|
+
cleanupWatchers();
|
|
7021
|
+
return;
|
|
7022
|
+
}
|
|
7023
|
+
retryCount++;
|
|
7024
|
+
if (retryCount > MAX_RETRIES) {
|
|
7025
|
+
console.warn(`CursorManager: Stopped waiting for element '${selector}' after ${MAX_RETRIES} attempts`);
|
|
7026
|
+
cleanupWatchers();
|
|
6888
7027
|
return;
|
|
6889
7028
|
}
|
|
6890
|
-
const found = this.findElement(selector);
|
|
7029
|
+
const found = this.findElement(selector, expectedSize);
|
|
6891
7030
|
if (found) {
|
|
6892
|
-
|
|
6893
|
-
this.targetMutationObserver.disconnect();
|
|
6894
|
-
this.targetMutationObserver = null;
|
|
7031
|
+
cleanupWatchers();
|
|
6895
7032
|
callback(found);
|
|
6896
7033
|
}
|
|
6897
7034
|
}, 1e3);
|
|
@@ -6943,11 +7080,20 @@ class CursorManager {
|
|
|
6943
7080
|
}
|
|
6944
7081
|
/**
|
|
6945
7082
|
* Helper function to find an element in the document
|
|
6946
|
-
*
|
|
7083
|
+
* Uses size validation when expectedSize is provided
|
|
7084
|
+
* Falls back to viewport-based selection when no expectedSize or when validation passes
|
|
6947
7085
|
* @param selector - CSS selector
|
|
7086
|
+
* @param expectedSize - Optional expected size for validation
|
|
6948
7087
|
* @returns - The found element or null
|
|
6949
7088
|
*/
|
|
6950
|
-
findElement(selector) {
|
|
7089
|
+
findElement(selector, expectedSize) {
|
|
7090
|
+
if (expectedSize) {
|
|
7091
|
+
const validElement = findValidElement(selector, expectedSize);
|
|
7092
|
+
if (validElement) {
|
|
7093
|
+
return validElement;
|
|
7094
|
+
}
|
|
7095
|
+
return null;
|
|
7096
|
+
}
|
|
6951
7097
|
const elements = document.querySelectorAll(selector);
|
|
6952
7098
|
if (elements.length === 0) {
|
|
6953
7099
|
return null;
|
|
@@ -7087,10 +7233,11 @@ class CursorManager {
|
|
|
7087
7233
|
/**
|
|
7088
7234
|
* Finds an element and scrolls it into view if necessary
|
|
7089
7235
|
* @param selector - CSS selector
|
|
7236
|
+
* @param expectedSize - Optional expected size for validation
|
|
7090
7237
|
* @returns - Promise that resolves with the element or null
|
|
7091
7238
|
*/
|
|
7092
|
-
async findElementAndScrollIntoView(selector) {
|
|
7093
|
-
const element = this.findElement(selector);
|
|
7239
|
+
async findElementAndScrollIntoView(selector, expectedSize) {
|
|
7240
|
+
const element = this.findElement(selector, expectedSize);
|
|
7094
7241
|
if (!element) {
|
|
7095
7242
|
return null;
|
|
7096
7243
|
}
|
|
@@ -7099,10 +7246,29 @@ class CursorManager {
|
|
|
7099
7246
|
}
|
|
7100
7247
|
return element;
|
|
7101
7248
|
}
|
|
7249
|
+
/**
|
|
7250
|
+
* Cleans up any existing cursor elements from the DOM
|
|
7251
|
+
* This prevents duplicate elements when switching playlists
|
|
7252
|
+
*/
|
|
7253
|
+
cleanupExistingElements() {
|
|
7254
|
+
const existingCursors = document.querySelectorAll(".sf-cursor");
|
|
7255
|
+
existingCursors.forEach((el) => el.remove());
|
|
7256
|
+
const existingLabels = document.querySelectorAll(".sf-cursor-label");
|
|
7257
|
+
existingLabels.forEach((el) => el.remove());
|
|
7258
|
+
const existingSelections = document.querySelectorAll(".sf-selection");
|
|
7259
|
+
existingSelections.forEach((el) => el.remove());
|
|
7260
|
+
const existingFlashlights = document.querySelectorAll(".sf-flashlight-overlay");
|
|
7261
|
+
existingFlashlights.forEach((el) => el.remove());
|
|
7262
|
+
this.cursor = null;
|
|
7263
|
+
this.labelElement = null;
|
|
7264
|
+
this.selectionElement = null;
|
|
7265
|
+
this.flashlightOverlay = null;
|
|
7266
|
+
}
|
|
7102
7267
|
/**
|
|
7103
7268
|
* Creates the virtual cursor element
|
|
7104
7269
|
*/
|
|
7105
7270
|
create() {
|
|
7271
|
+
this.cleanupExistingElements();
|
|
7106
7272
|
this.injectCursorStyles();
|
|
7107
7273
|
this.cursor = document.createElement("div");
|
|
7108
7274
|
this.cursor.className = "sf-cursor";
|
|
@@ -7411,12 +7577,12 @@ class CursorManager {
|
|
|
7411
7577
|
if (this.isAutoplayBlocked()) {
|
|
7412
7578
|
return;
|
|
7413
7579
|
}
|
|
7414
|
-
const targetElement = await this.findElementAndScrollIntoView(animation.targetSelector);
|
|
7580
|
+
const targetElement = await this.findElementAndScrollIntoView(animation.targetSelector, animation.expectedSize);
|
|
7415
7581
|
if (!targetElement) {
|
|
7416
7582
|
console.warn("CursorManager: Target element not found in animate:", animation.targetSelector);
|
|
7417
7583
|
this.setShouldShowCursor(false);
|
|
7418
7584
|
this.hideCursorElements();
|
|
7419
|
-
this.waitForElement(animation.targetSelector, () => this.animate(animation));
|
|
7585
|
+
this.waitForElement(animation.targetSelector, () => this.animate(animation), animation.expectedSize);
|
|
7420
7586
|
return;
|
|
7421
7587
|
}
|
|
7422
7588
|
this.setShouldShowCursor(true);
|
|
@@ -9090,7 +9256,7 @@ class TransitionManager {
|
|
|
9090
9256
|
element.addEventListener("click", handler, { capture: true });
|
|
9091
9257
|
});
|
|
9092
9258
|
};
|
|
9093
|
-
const initialElements = document.querySelectorAll(selector);
|
|
9259
|
+
const initialElements = transition.expectedSize ? findAllValidElements(selector, transition.expectedSize) : Array.from(document.querySelectorAll(selector));
|
|
9094
9260
|
addClickHandlersToElements(initialElements);
|
|
9095
9261
|
mutationObserver = new MutationObserver((mutationsList) => {
|
|
9096
9262
|
for (const mutation of mutationsList) {
|
|
@@ -9099,12 +9265,17 @@ class TransitionManager {
|
|
|
9099
9265
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
9100
9266
|
const elementNode = node;
|
|
9101
9267
|
if (elementNode.matches(selector)) {
|
|
9102
|
-
|
|
9268
|
+
if (!transition.expectedSize || isElementValid(elementNode, transition.expectedSize)) {
|
|
9269
|
+
addClickHandlersToElements([elementNode]);
|
|
9270
|
+
}
|
|
9103
9271
|
}
|
|
9104
9272
|
const matchingDescendants = elementNode.querySelectorAll(selector);
|
|
9105
9273
|
if (matchingDescendants.length > 0) {
|
|
9106
|
-
|
|
9107
|
-
|
|
9274
|
+
const validDescendants = transition.expectedSize ? Array.from(matchingDescendants).filter((el) => isElementValid(el, transition.expectedSize)) : Array.from(matchingDescendants);
|
|
9275
|
+
if (validDescendants.length > 0) {
|
|
9276
|
+
log(`TransitionManager: Found ${validDescendants.length} valid descendants matching '${selector}'`);
|
|
9277
|
+
addClickHandlersToElements(validDescendants);
|
|
9278
|
+
}
|
|
9108
9279
|
}
|
|
9109
9280
|
}
|
|
9110
9281
|
});
|
|
@@ -9436,7 +9607,7 @@ class TransitionManager {
|
|
|
9436
9607
|
mutationObserver = null;
|
|
9437
9608
|
}
|
|
9438
9609
|
};
|
|
9439
|
-
const initialElement = document.querySelector(selector);
|
|
9610
|
+
const initialElement = transition.expectedSize ? findValidElement(selector, transition.expectedSize) : document.querySelector(selector);
|
|
9440
9611
|
if (initialElement) {
|
|
9441
9612
|
setupIntersectionObserver(initialElement);
|
|
9442
9613
|
} else {
|
|
@@ -9447,10 +9618,12 @@ class TransitionManager {
|
|
|
9447
9618
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
9448
9619
|
const elementNode = node;
|
|
9449
9620
|
if (elementNode.matches(selector)) {
|
|
9450
|
-
|
|
9451
|
-
|
|
9621
|
+
if (!transition.expectedSize || isElementValid(elementNode, transition.expectedSize)) {
|
|
9622
|
+
setupIntersectionObserver(elementNode);
|
|
9623
|
+
return;
|
|
9624
|
+
}
|
|
9452
9625
|
}
|
|
9453
|
-
const matchingDescendant = elementNode.querySelector(selector);
|
|
9626
|
+
const matchingDescendant = transition.expectedSize ? findValidElement(selector, transition.expectedSize) : elementNode.querySelector(selector);
|
|
9454
9627
|
if (matchingDescendant) {
|
|
9455
9628
|
setupIntersectionObserver(matchingDescendant);
|
|
9456
9629
|
return;
|
|
@@ -9471,7 +9644,7 @@ class TransitionManager {
|
|
|
9471
9644
|
}
|
|
9472
9645
|
return;
|
|
9473
9646
|
}
|
|
9474
|
-
const element = document.querySelector(selector);
|
|
9647
|
+
const element = transition.expectedSize ? findValidElement(selector, transition.expectedSize) : document.querySelector(selector);
|
|
9475
9648
|
if (element && element.offsetWidth > 0 && element.offsetHeight > 0) {
|
|
9476
9649
|
if (periodicCheck) {
|
|
9477
9650
|
clearInterval(periodicCheck);
|
|
@@ -9930,7 +10103,11 @@ class TriggerManager {
|
|
|
9930
10103
|
this.triggeredPlaylists.forEach((playlist) => {
|
|
9931
10104
|
var _a;
|
|
9932
10105
|
if ((_a = playlist.triggers) == null ? void 0 : _a.elementClicked) {
|
|
9933
|
-
this.setupElementClickListener(
|
|
10106
|
+
this.setupElementClickListener(
|
|
10107
|
+
playlist.id,
|
|
10108
|
+
playlist.triggers.elementClicked,
|
|
10109
|
+
playlist.triggers.elementClickedExpectedSize
|
|
10110
|
+
);
|
|
9934
10111
|
}
|
|
9935
10112
|
});
|
|
9936
10113
|
}
|
|
@@ -9938,10 +10115,11 @@ class TriggerManager {
|
|
|
9938
10115
|
* Sets up a click event listener for a specific playlist and selector
|
|
9939
10116
|
* @param playlistId - The playlist ID
|
|
9940
10117
|
* @param selector - CSS selector for the target element
|
|
10118
|
+
* @param expectedSize - Optional expected size for validation
|
|
9941
10119
|
*/
|
|
9942
|
-
setupElementClickListener(playlistId, selector) {
|
|
10120
|
+
setupElementClickListener(playlistId, selector, expectedSize) {
|
|
9943
10121
|
try {
|
|
9944
|
-
const element = document.querySelector(selector);
|
|
10122
|
+
const element = expectedSize ? findValidElement(selector, expectedSize) : document.querySelector(selector);
|
|
9945
10123
|
if (!element) {
|
|
9946
10124
|
log(`TriggerManager: Element not found for selector '${selector}' (playlist: ${playlistId})`);
|
|
9947
10125
|
return;
|
|
@@ -9990,7 +10168,11 @@ class TriggerManager {
|
|
|
9990
10168
|
this.triggeredPlaylists.forEach((playlist) => {
|
|
9991
10169
|
var _a;
|
|
9992
10170
|
if ((_a = playlist.triggers) == null ? void 0 : _a.elementVisible) {
|
|
9993
|
-
this.setupElementVisibleObserver(
|
|
10171
|
+
this.setupElementVisibleObserver(
|
|
10172
|
+
playlist.id,
|
|
10173
|
+
playlist.triggers.elementVisible,
|
|
10174
|
+
playlist.triggers.elementVisibleExpectedSize
|
|
10175
|
+
);
|
|
9994
10176
|
}
|
|
9995
10177
|
});
|
|
9996
10178
|
}
|
|
@@ -9998,8 +10180,9 @@ class TriggerManager {
|
|
|
9998
10180
|
* Sets up a visibility observer for a specific playlist and selector
|
|
9999
10181
|
* @param playlistId - The playlist ID
|
|
10000
10182
|
* @param selector - CSS selector for the target element
|
|
10183
|
+
* @param expectedSize - Optional expected size for validation
|
|
10001
10184
|
*/
|
|
10002
|
-
setupElementVisibleObserver(playlistId, selector) {
|
|
10185
|
+
setupElementVisibleObserver(playlistId, selector, expectedSize) {
|
|
10003
10186
|
try {
|
|
10004
10187
|
const observerId = `${playlistId}-${selector}`;
|
|
10005
10188
|
if (this.elementVisibleObservers.has(observerId)) {
|
|
@@ -10057,7 +10240,7 @@ class TriggerManager {
|
|
|
10057
10240
|
});
|
|
10058
10241
|
}
|
|
10059
10242
|
};
|
|
10060
|
-
const initialElement = document.querySelector(selector);
|
|
10243
|
+
const initialElement = expectedSize ? findValidElement(selector, expectedSize) : document.querySelector(selector);
|
|
10061
10244
|
if (initialElement) {
|
|
10062
10245
|
log(`TriggerManager: Found element matching '${selector}' immediately`);
|
|
10063
10246
|
setupIntersectionObserver(initialElement);
|
|
@@ -10070,10 +10253,12 @@ class TriggerManager {
|
|
|
10070
10253
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
10071
10254
|
const elementNode = node;
|
|
10072
10255
|
if (elementNode.matches(selector)) {
|
|
10073
|
-
|
|
10074
|
-
|
|
10256
|
+
if (!expectedSize || isElementValid(elementNode, expectedSize)) {
|
|
10257
|
+
log(`TriggerManager: Added node matches '${selector}'`);
|
|
10258
|
+
setupIntersectionObserver(elementNode);
|
|
10259
|
+
}
|
|
10075
10260
|
} else {
|
|
10076
|
-
const matchingDescendant = elementNode.querySelector(selector);
|
|
10261
|
+
const matchingDescendant = expectedSize ? findValidElement(selector, expectedSize) : elementNode.querySelector(selector);
|
|
10077
10262
|
if (matchingDescendant) {
|
|
10078
10263
|
log(`TriggerManager: Found descendant matching '${selector}'`);
|
|
10079
10264
|
setupIntersectionObserver(matchingDescendant);
|
|
@@ -10166,6 +10351,16 @@ class TriggerManager {
|
|
|
10166
10351
|
getTriggeredPlaylists() {
|
|
10167
10352
|
return Array.from(this.triggeredPlaylistsSet);
|
|
10168
10353
|
}
|
|
10354
|
+
/**
|
|
10355
|
+
* Marks a playlist as triggered to prevent re-triggering during URL changes
|
|
10356
|
+
* This should be called when a playlist is started programmatically
|
|
10357
|
+
* @param playlistId - The playlist ID to mark as triggered
|
|
10358
|
+
*/
|
|
10359
|
+
markPlaylistAsTriggered(playlistId) {
|
|
10360
|
+
if (!this.triggeredPlaylistsSet.has(playlistId)) {
|
|
10361
|
+
this.triggeredPlaylistsSet.add(playlistId);
|
|
10362
|
+
}
|
|
10363
|
+
}
|
|
10169
10364
|
/**
|
|
10170
10365
|
* Cleanup method to be called on destroy
|
|
10171
10366
|
*/
|
|
@@ -11977,7 +12172,7 @@ const SaltfishPlayer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
|
|
|
11977
12172
|
__proto__: null,
|
|
11978
12173
|
SaltfishPlayer
|
|
11979
12174
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
11980
|
-
const version = "0.3.
|
|
12175
|
+
const version = "0.3.57";
|
|
11981
12176
|
const packageJson = {
|
|
11982
12177
|
version
|
|
11983
12178
|
};
|