@magicfeedback/popup-sdk 1.7.2 → 1.8.0

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.
@@ -538,7 +538,27 @@ declare class DeepdotsPopups {
538
538
  private showDefinition;
539
539
  private shouldShow;
540
540
  private matchesSegmentsLang;
541
+ /** `segments.path`: rutas donde el popup PUEDE mostrarse. Sin lista, en todas. */
541
542
  private matchesSegmentsPath;
543
+ /**
544
+ * `segments.excludedPaths`: rutas donde el popup NO debe mostrarse. Gana sobre
545
+ * `segments.path` (`path: ['/']` + `excludedPaths: ['/cart']` = en todas menos el
546
+ * carrito) y se aplica también cuando no hay `path` (= en todas menos las excluidas).
547
+ */
548
+ private isPathExcluded;
549
+ /**
550
+ * Compara UN candidato de `segments.path`/`segments.excludedPaths` con la ruta
551
+ * actual. Mismas reglas para incluir y para excluir:
552
+ * - URL absoluta → href completo exacto
553
+ * - empieza por / → subcadena del href (así entran las rutas con hash: `/#/home`)
554
+ * - resto → pathname exacto
555
+ * Ignora entradas que no sean string: el backend puede colar un `null` en la lista
556
+ * y no puede tumbar la evaluación del trigger entero (mismo fallo que hubo con
557
+ * `segments.lang`).
558
+ */
559
+ private matchesPathCandidate;
560
+ /** href + pathname normalizados de la ruta a evaluar, o null si no hay `window.location`. */
561
+ private resolveCurrentLocation;
542
562
  private evaluateCooldown;
543
563
  private evaluateLegacyCondition;
544
564
  private hasCooldownElapsed;
@@ -538,7 +538,27 @@ declare class DeepdotsPopups {
538
538
  private showDefinition;
539
539
  private shouldShow;
540
540
  private matchesSegmentsLang;
541
+ /** `segments.path`: rutas donde el popup PUEDE mostrarse. Sin lista, en todas. */
541
542
  private matchesSegmentsPath;
543
+ /**
544
+ * `segments.excludedPaths`: rutas donde el popup NO debe mostrarse. Gana sobre
545
+ * `segments.path` (`path: ['/']` + `excludedPaths: ['/cart']` = en todas menos el
546
+ * carrito) y se aplica también cuando no hay `path` (= en todas menos las excluidas).
547
+ */
548
+ private isPathExcluded;
549
+ /**
550
+ * Compara UN candidato de `segments.path`/`segments.excludedPaths` con la ruta
551
+ * actual. Mismas reglas para incluir y para excluir:
552
+ * - URL absoluta → href completo exacto
553
+ * - empieza por / → subcadena del href (así entran las rutas con hash: `/#/home`)
554
+ * - resto → pathname exacto
555
+ * Ignora entradas que no sean string: el backend puede colar un `null` en la lista
556
+ * y no puede tumbar la evaluación del trigger entero (mismo fallo que hubo con
557
+ * `segments.lang`).
558
+ */
559
+ private matchesPathCandidate;
560
+ /** href + pathname normalizados de la ruta a evaluar, o null si no hay `window.location`. */
561
+ private resolveCurrentLocation;
542
562
  private evaluateCooldown;
543
563
  private evaluateLegacyCondition;
544
564
  private hasCooldownElapsed;
@@ -5508,6 +5508,9 @@ var DeepdotsPopups = class {
5508
5508
  this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
5509
5509
  }
5510
5510
  shouldShow(def, pathUrl, skipPathCheck = false) {
5511
+ if (this.isPathExcluded(def, pathUrl)) {
5512
+ return false;
5513
+ }
5511
5514
  if (!skipPathCheck && !this.matchesSegmentsPath(def, pathUrl)) {
5512
5515
  return false;
5513
5516
  }
@@ -5538,40 +5541,85 @@ var DeepdotsPopups = class {
5538
5541
  }
5539
5542
  return matches;
5540
5543
  }
5544
+ /** `segments.path`: rutas donde el popup PUEDE mostrarse. Sin lista, en todas. */
5541
5545
  matchesSegmentsPath(def, pathUrl) {
5542
5546
  const paths = def.segments?.path;
5543
- if (!paths || paths.length === 0) return true;
5544
- if (typeof window === "undefined" || !window.location) {
5547
+ if (!Array.isArray(paths) || paths.length === 0) return true;
5548
+ const location = this.resolveCurrentLocation(pathUrl);
5549
+ if (!location) {
5545
5550
  this.debug("No window.location available for path comparison", { popupId: def.id, paths });
5546
5551
  return true;
5547
5552
  }
5548
- const normalizedHref = this.normalizeUrl(pathUrl || window.location.href || "");
5549
- const currentUrl = this.safeParseUrl(normalizedHref);
5550
- const normalizedPath = this.normalizeUrl(currentUrl?.pathname || window.location.pathname || "");
5551
5553
  const matches = paths.some((rawCandidate) => {
5552
- const candidate = this.normalizeUrl(rawCandidate);
5553
- let match = false;
5554
- if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
5555
- match = normalizedHref === candidate;
5556
- } else if (candidate.startsWith("/")) {
5557
- match = normalizedHref.includes(candidate);
5558
- } else {
5559
- match = normalizedPath === candidate;
5560
- }
5554
+ const match = this.matchesPathCandidate(rawCandidate, location);
5561
5555
  this.debug("Path comparison", {
5562
5556
  popupId: def.id,
5563
- candidate,
5564
- currentPath: normalizedPath,
5565
- currentHref: normalizedHref,
5557
+ candidate: rawCandidate,
5558
+ currentPath: location.path,
5559
+ currentHref: location.href,
5566
5560
  match
5567
5561
  });
5568
5562
  return match;
5569
5563
  });
5570
5564
  if (!matches) {
5571
- this.debug("No path match for popup", { popupId: def.id, paths, currentPath: normalizedPath });
5565
+ this.debug("No path match for popup", { popupId: def.id, paths, currentPath: location.path });
5572
5566
  }
5573
5567
  return matches;
5574
5568
  }
5569
+ /**
5570
+ * `segments.excludedPaths`: rutas donde el popup NO debe mostrarse. Gana sobre
5571
+ * `segments.path` (`path: ['/']` + `excludedPaths: ['/cart']` = en todas menos el
5572
+ * carrito) y se aplica también cuando no hay `path` (= en todas menos las excluidas).
5573
+ */
5574
+ isPathExcluded(def, pathUrl) {
5575
+ const excluded = def.segments?.excludedPaths;
5576
+ if (!Array.isArray(excluded) || excluded.length === 0) return false;
5577
+ const location = this.resolveCurrentLocation(pathUrl);
5578
+ if (!location) {
5579
+ this.debug("No window.location available for excluded path comparison", { popupId: def.id, excluded });
5580
+ return false;
5581
+ }
5582
+ const hit = excluded.find((rawCandidate) => this.matchesPathCandidate(rawCandidate, location));
5583
+ if (hit !== void 0) {
5584
+ this.debug("Popup excluded by path", {
5585
+ popupId: def.id,
5586
+ candidate: hit,
5587
+ currentPath: location.path,
5588
+ currentHref: location.href
5589
+ });
5590
+ return true;
5591
+ }
5592
+ return false;
5593
+ }
5594
+ /**
5595
+ * Compara UN candidato de `segments.path`/`segments.excludedPaths` con la ruta
5596
+ * actual. Mismas reglas para incluir y para excluir:
5597
+ * - URL absoluta → href completo exacto
5598
+ * - empieza por / → subcadena del href (así entran las rutas con hash: `/#/home`)
5599
+ * - resto → pathname exacto
5600
+ * Ignora entradas que no sean string: el backend puede colar un `null` en la lista
5601
+ * y no puede tumbar la evaluación del trigger entero (mismo fallo que hubo con
5602
+ * `segments.lang`).
5603
+ */
5604
+ matchesPathCandidate(rawCandidate, location) {
5605
+ if (typeof rawCandidate !== "string") return false;
5606
+ const candidate = this.normalizeUrl(rawCandidate);
5607
+ if (!candidate) return false;
5608
+ if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
5609
+ return location.href === candidate;
5610
+ }
5611
+ if (candidate.startsWith("/")) {
5612
+ return location.href.includes(candidate);
5613
+ }
5614
+ return location.path === candidate;
5615
+ }
5616
+ /** href + pathname normalizados de la ruta a evaluar, o null si no hay `window.location`. */
5617
+ resolveCurrentLocation(pathUrl) {
5618
+ if (typeof window === "undefined" || !window.location) return null;
5619
+ const href = this.normalizeUrl(pathUrl || window.location.href || "");
5620
+ const parsed = this.safeParseUrl(href);
5621
+ return { href, path: this.normalizeUrl(parsed?.pathname || window.location.pathname || "") };
5622
+ }
5575
5623
  evaluateCooldown(def, condition) {
5576
5624
  switch (condition.answered) {
5577
5625
  case "SHOWED":