easter-egg-quest 1.0.23 → 1.0.25

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.
@@ -662,12 +662,9 @@ class HiddenEntry {
662
662
  const navEls = sorted.filter(
663
663
  (el) => el.closest("nav") !== null || el.closest("header") !== null
664
664
  );
665
- const offset = bodyEls.length > 1 ? visitCount % bodyEls.length : 0;
666
- const rotated = [
667
- ...bodyEls.slice(offset),
668
- ...bodyEls.slice(0, offset),
669
- ...navEls
670
- ];
665
+ const rotated = this._shuffleCandidates(bodyEls, visitCount).concat(
666
+ this._shuffleCandidates(navEls, visitCount + 17)
667
+ );
671
668
  const rotatedPrints = rotated.map(
672
669
  (el) => {
673
670
  var _a3;
@@ -682,22 +679,28 @@ class HiddenEntry {
682
679
  const ordered = unused.length > 0 ? [...unused, ...rotated.filter((_, i) => usedSet.has(rotatedPrints[i]))] : rotated;
683
680
  for (const candidate of ordered) {
684
681
  const host = candidate;
682
+ if (!this._canHostInjectedTrigger(host)) continue;
685
683
  const isInline = host.tagName === "A" || host.tagName === "BUTTON" || host.tagName === "LI" || host.closest("nav") !== null;
686
684
  const span = document.createElement("span");
687
685
  span.textContent = isInline ? " · start hunt" : " start hunt";
688
686
  span.setAttribute("data-eeq", "trigger");
687
+ span.classList.add("eeq-inline-trigger");
689
688
  span.style.cssText = `
690
689
  font: inherit;
691
690
  color: inherit;
692
691
  letter-spacing: inherit;
693
692
  cursor: pointer;
693
+ white-space: nowrap;
694
+ transition: filter 0.18s ease, opacity 0.18s ease, text-shadow 0.18s ease;
694
695
  `;
695
696
  const inserted = !isInline && this._tryInsertBetweenWords(host, span);
696
697
  if (!inserted) {
697
698
  const heightBefore = host.getBoundingClientRect().height;
699
+ const widthBefore = host.getBoundingClientRect().width;
698
700
  host.appendChild(span);
699
701
  const heightAfter = host.getBoundingClientRect().height;
700
- if (Math.abs(heightAfter - heightBefore) > 2) {
702
+ const widthAfter = host.getBoundingClientRect().width;
703
+ if (Math.abs(heightAfter - heightBefore) > 2 || Math.abs(widthAfter - widthBefore) > 24 || this._isTriggerClipped(host, span)) {
701
704
  host.removeChild(span);
702
705
  continue;
703
706
  }
@@ -814,9 +817,53 @@ class HiddenEntry {
814
817
  if (childElementCount > 12) return false;
815
818
  const rect = el.getBoundingClientRect();
816
819
  if (rect.width < 18 || rect.height < 12) return false;
820
+ if (!this._canHostInjectedTrigger(el)) return false;
817
821
  return true;
818
822
  });
819
823
  }
824
+ _shuffleCandidates(candidates, seed) {
825
+ if (candidates.length < 2) return [...candidates];
826
+ const arr = [...candidates];
827
+ let state = (seed || 1) ^ Date.now() & 65535;
828
+ const rand = () => {
829
+ state ^= state << 13;
830
+ state ^= state >>> 17;
831
+ state ^= state << 5;
832
+ return (state >>> 0) % 1e4 / 1e4;
833
+ };
834
+ for (let i = arr.length - 1; i > 0; i--) {
835
+ const j = Math.floor(rand() * (i + 1));
836
+ [arr[i], arr[j]] = [arr[j], arr[i]];
837
+ }
838
+ return arr;
839
+ }
840
+ _canHostInjectedTrigger(host) {
841
+ const style = getComputedStyle(host);
842
+ const textOverflow = style.textOverflow;
843
+ const whiteSpace = style.whiteSpace;
844
+ const overflowX = style.overflowX;
845
+ const overflow = style.overflow;
846
+ if (textOverflow === "ellipsis") return false;
847
+ if (whiteSpace === "nowrap" && ["hidden", "clip"].includes(overflowX || overflow)) return false;
848
+ if (host.scrollWidth > host.clientWidth + 2 && host.clientWidth > 0) return false;
849
+ if (host.scrollHeight > host.clientHeight + 2 && host.clientHeight > 0 && whiteSpace === "nowrap") return false;
850
+ return true;
851
+ }
852
+ _isTriggerClipped(host, span) {
853
+ if (!document.body.contains(span)) return true;
854
+ const hostRect = host.getBoundingClientRect();
855
+ const spanRect = span.getBoundingClientRect();
856
+ const style = getComputedStyle(host);
857
+ const clipsHorizontally = ["hidden", "clip"].includes(style.overflowX || style.overflow);
858
+ const clipsVertically = ["hidden", "clip"].includes(style.overflowY || style.overflow);
859
+ if (host.scrollWidth > host.clientWidth + 2 && host.clientWidth > 0) return true;
860
+ if (style.textOverflow === "ellipsis") return true;
861
+ if (clipsHorizontally && spanRect.right > hostRect.right - 1) return true;
862
+ if (clipsHorizontally && spanRect.left < hostRect.left + 1) return true;
863
+ if (clipsVertically && spanRect.bottom > hostRect.bottom - 1) return true;
864
+ if (clipsVertically && spanRect.top < hostRect.top + 1) return true;
865
+ return false;
866
+ }
820
867
  _startBootstrapWatch() {
821
868
  this._stopBootstrapWatch();
822
869
  const root = this._getSearchRoot();
@@ -982,8 +1029,8 @@ class HiddenEntry {
982
1029
  const walker = document.createTreeWalker(host, NodeFilter.SHOW_TEXT, {
983
1030
  acceptNode: (node) => {
984
1031
  var _a2;
985
- const text2 = ((_a2 = node.textContent) == null ? void 0 : _a2.trim()) ?? "";
986
- if (text2.length <= 5) return NodeFilter.FILTER_REJECT;
1032
+ const text = ((_a2 = node.textContent) == null ? void 0 : _a2.trim()) ?? "";
1033
+ if (text.length <= 5) return NodeFilter.FILTER_REJECT;
987
1034
  const parent = node.parentElement;
988
1035
  if (!parent) return NodeFilter.FILTER_REJECT;
989
1036
  if (parent.closest("[data-eeq], script, style, noscript")) return NodeFilter.FILTER_REJECT;
@@ -996,33 +1043,50 @@ class HiddenEntry {
996
1043
  current = walker.nextNode();
997
1044
  }
998
1045
  if (!textNodes.length) return false;
999
- const slotSeed = Math.floor(Date.now() / (1e3 * 60 * 2));
1000
- const textNode = textNodes[slotSeed % textNodes.length];
1001
- const text = textNode.textContent ?? "";
1002
- const spacePositions = [];
1003
- for (let i = 1; i < text.length - 1; i++) {
1004
- if (text[i] === " ") spacePositions.push(i);
1005
- }
1006
- if (spacePositions.length < 2) return false;
1007
- const start = Math.floor(spacePositions.length * 0.25);
1008
- const end = Math.floor(spacePositions.length * 0.75);
1009
- const idx = start + slotSeed % Math.max(1, end - start);
1010
- const splitAt = spacePositions[Math.min(idx, spacePositions.length - 1)];
1011
- const before = text.slice(0, splitAt);
1012
- const after = text.slice(splitAt);
1013
- const rectBefore = host.getBoundingClientRect();
1014
- const afterNode = document.createTextNode(after);
1015
- textNode.textContent = before;
1016
- host.insertBefore(afterNode, textNode.nextSibling);
1017
- host.insertBefore(span, afterNode);
1018
- const rectAfter = host.getBoundingClientRect();
1019
- if (Math.abs(rectAfter.height - rectBefore.height) > 8 || Math.abs(rectAfter.width - rectBefore.width) > 24) {
1020
- host.removeChild(span);
1021
- host.removeChild(afterNode);
1022
- textNode.textContent = text;
1023
- return false;
1046
+ const textNodesOrdered = this._shuffleCandidates(
1047
+ textNodes.map((node) => node.parentElement).filter((el) => !!el),
1048
+ Date.now()
1049
+ );
1050
+ const uniqueTextNodes = textNodesOrdered.map((parent) => textNodes.find((node) => node.parentElement === parent)).filter((node) => !!node);
1051
+ for (const textNode of uniqueTextNodes) {
1052
+ const text = textNode.textContent ?? "";
1053
+ const parent = textNode.parentElement;
1054
+ if (!parent) continue;
1055
+ const spacePositions = [];
1056
+ for (let i = 1; i < text.length - 1; i++) {
1057
+ if (text[i] === " ") spacePositions.push(i);
1058
+ }
1059
+ if (spacePositions.length < 2) continue;
1060
+ const start = Math.floor(spacePositions.length * 0.2);
1061
+ const end = Math.ceil(spacePositions.length * 0.8);
1062
+ const candidateBreaks = this._shuffleNumbers(
1063
+ spacePositions.slice(start, Math.max(start + 1, end))
1064
+ );
1065
+ for (const splitAt of candidateBreaks) {
1066
+ const before = text.slice(0, splitAt);
1067
+ const after = text.slice(splitAt);
1068
+ const rectBefore = host.getBoundingClientRect();
1069
+ const afterNode = document.createTextNode(after);
1070
+ textNode.textContent = before;
1071
+ parent.insertBefore(span, textNode.nextSibling);
1072
+ parent.insertBefore(afterNode, span.nextSibling);
1073
+ const rectAfter = host.getBoundingClientRect();
1074
+ const invalid = Math.abs(rectAfter.height - rectBefore.height) > 8 || Math.abs(rectAfter.width - rectBefore.width) > 24 || this._isTriggerClipped(host, span);
1075
+ if (!invalid) return true;
1076
+ span.remove();
1077
+ afterNode.remove();
1078
+ textNode.textContent = text;
1079
+ }
1024
1080
  }
1025
- return true;
1081
+ return false;
1082
+ }
1083
+ _shuffleNumbers(values) {
1084
+ const arr = [...values];
1085
+ for (let i = arr.length - 1; i > 0; i--) {
1086
+ const j = Math.floor(Math.random() * (i + 1));
1087
+ [arr[i], arr[j]] = [arr[j], arr[i]];
1088
+ }
1089
+ return arr;
1026
1090
  }
1027
1091
  // ─── Shared ───────────────────────────────────────────────────────────
1028
1092
  _attachToElement(el) {
@@ -1214,6 +1278,11 @@ class HiddenEntry {
1214
1278
  .eeq-entry-target {
1215
1279
  animation: eeq-shimmer 3s ease-in-out infinite !important;
1216
1280
  }
1281
+ .eeq-inline-trigger:hover {
1282
+ filter: brightness(1.35);
1283
+ opacity: 1;
1284
+ text-shadow: 0 0 10px rgba(255, 248, 220, 0.35);
1285
+ }
1217
1286
  @keyframes eeq-shimmer {
1218
1287
  0%, 100% { opacity: 1; }
1219
1288
  50% { opacity: 0.55; }
@@ -3716,9 +3785,11 @@ const _ResultsRenderer = class _ResultsRenderer {
3716
3785
  panel.classList.add("eeq-results-visible");
3717
3786
  });
3718
3787
  });
3719
- (_a2 = this.shadow.querySelector(".eeq-btn-finish")) == null ? void 0 : _a2.addEventListener("click", () => {
3788
+ (_a2 = this.shadow.querySelector(".eeq-btn-finish")) == null ? void 0 : _a2.addEventListener("click", (event) => {
3720
3789
  var _a3;
3721
- return (_a3 = this._onFinish) == null ? void 0 : _a3.call(this);
3790
+ event.preventDefault();
3791
+ event.stopPropagation();
3792
+ (_a3 = this._onFinish) == null ? void 0 : _a3.call(this);
3722
3793
  });
3723
3794
  (_b2 = this.shadow.querySelector(".eeq-btn-share")) == null ? void 0 : _b2.addEventListener("click", () => this._copyShareImage(score));
3724
3795
  }
@@ -5714,7 +5785,7 @@ class GameController {
5714
5785
  () => {
5715
5786
  this.persistence.markCompleted();
5716
5787
  this.destroy();
5717
- window.location.reload();
5788
+ this._reloadPage();
5718
5789
  }
5719
5790
  );
5720
5791
  (_c = (_b2 = this.config.callbacks).onComplete) == null ? void 0 : _c.call(_b2, score);
@@ -5762,6 +5833,17 @@ class GameController {
5762
5833
  _wait(ms) {
5763
5834
  return new Promise((r) => setTimeout(r, ms));
5764
5835
  }
5836
+ _reloadPage() {
5837
+ try {
5838
+ window.location.reload();
5839
+ return;
5840
+ } catch {
5841
+ }
5842
+ try {
5843
+ window.location.assign(window.location.href);
5844
+ } catch {
5845
+ }
5846
+ }
5765
5847
  }
5766
5848
  let _instance = null;
5767
5849
  const EasterEggQuest = {