easter-egg-quest 1.0.25 → 1.0.27
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.
|
@@ -567,6 +567,8 @@ class HiddenEntry {
|
|
|
567
567
|
this.clickHandler = null;
|
|
568
568
|
this.fallbackButton = null;
|
|
569
569
|
this._injectedElement = null;
|
|
570
|
+
this._replacedTextNode = null;
|
|
571
|
+
this._replacedTextContent = "";
|
|
570
572
|
this._destroyed = false;
|
|
571
573
|
this._hintVisibleElapsed = 0;
|
|
572
574
|
this._hintVisibleStart = 0;
|
|
@@ -610,6 +612,7 @@ class HiddenEntry {
|
|
|
610
612
|
}
|
|
611
613
|
this._stopWatchdog();
|
|
612
614
|
this._stopBootstrapWatch();
|
|
615
|
+
this._restoreReplacedText();
|
|
613
616
|
(_a2 = this._injectedElement) == null ? void 0 : _a2.remove();
|
|
614
617
|
this._injectedElement = null;
|
|
615
618
|
(_b2 = this.hintContainer) == null ? void 0 : _b2.remove();
|
|
@@ -680,31 +683,8 @@ class HiddenEntry {
|
|
|
680
683
|
for (const candidate of ordered) {
|
|
681
684
|
const host = candidate;
|
|
682
685
|
if (!this._canHostInjectedTrigger(host)) continue;
|
|
683
|
-
const
|
|
684
|
-
|
|
685
|
-
span.textContent = isInline ? " · start hunt" : " start hunt";
|
|
686
|
-
span.setAttribute("data-eeq", "trigger");
|
|
687
|
-
span.classList.add("eeq-inline-trigger");
|
|
688
|
-
span.style.cssText = `
|
|
689
|
-
font: inherit;
|
|
690
|
-
color: inherit;
|
|
691
|
-
letter-spacing: inherit;
|
|
692
|
-
cursor: pointer;
|
|
693
|
-
white-space: nowrap;
|
|
694
|
-
transition: filter 0.18s ease, opacity 0.18s ease, text-shadow 0.18s ease;
|
|
695
|
-
`;
|
|
696
|
-
const inserted = !isInline && this._tryInsertBetweenWords(host, span);
|
|
697
|
-
if (!inserted) {
|
|
698
|
-
const heightBefore = host.getBoundingClientRect().height;
|
|
699
|
-
const widthBefore = host.getBoundingClientRect().width;
|
|
700
|
-
host.appendChild(span);
|
|
701
|
-
const heightAfter = host.getBoundingClientRect().height;
|
|
702
|
-
const widthAfter = host.getBoundingClientRect().width;
|
|
703
|
-
if (Math.abs(heightAfter - heightBefore) > 2 || Math.abs(widthAfter - widthBefore) > 24 || this._isTriggerClipped(host, span)) {
|
|
704
|
-
host.removeChild(span);
|
|
705
|
-
continue;
|
|
706
|
-
}
|
|
707
|
-
}
|
|
686
|
+
const span = this._replaceTextCandidate(host);
|
|
687
|
+
if (!span) continue;
|
|
708
688
|
const idx = sorted.indexOf(candidate);
|
|
709
689
|
if (idx >= 0) {
|
|
710
690
|
usedSet.add(prints[idx]);
|
|
@@ -1009,6 +989,7 @@ class HiddenEntry {
|
|
|
1009
989
|
if (this._injectedElement && document.body.contains(this._injectedElement)) {
|
|
1010
990
|
this._injectedElement.remove();
|
|
1011
991
|
}
|
|
992
|
+
this._restoreReplacedText();
|
|
1012
993
|
this._injectedElement = null;
|
|
1013
994
|
this.targetElement = null;
|
|
1014
995
|
this._startBootstrapWatch();
|
|
@@ -1067,6 +1048,7 @@ class HiddenEntry {
|
|
|
1067
1048
|
const after = text.slice(splitAt);
|
|
1068
1049
|
const rectBefore = host.getBoundingClientRect();
|
|
1069
1050
|
const afterNode = document.createTextNode(after);
|
|
1051
|
+
this._applyTriggerTypography(span, parent);
|
|
1070
1052
|
textNode.textContent = before;
|
|
1071
1053
|
parent.insertBefore(span, textNode.nextSibling);
|
|
1072
1054
|
parent.insertBefore(afterNode, span.nextSibling);
|
|
@@ -1088,6 +1070,104 @@ class HiddenEntry {
|
|
|
1088
1070
|
}
|
|
1089
1071
|
return arr;
|
|
1090
1072
|
}
|
|
1073
|
+
_replaceTextCandidate(host) {
|
|
1074
|
+
const target = this._findReplacementTextTarget(host);
|
|
1075
|
+
if (!target) return null;
|
|
1076
|
+
const span = document.createElement("span");
|
|
1077
|
+
span.textContent = "start hunt";
|
|
1078
|
+
span.setAttribute("data-eeq", "trigger");
|
|
1079
|
+
span.classList.add("eeq-inline-trigger");
|
|
1080
|
+
this._applyTriggerTypography(span, target.parent);
|
|
1081
|
+
const rectBefore = host.getBoundingClientRect();
|
|
1082
|
+
target.textNode.textContent = "";
|
|
1083
|
+
target.parent.insertBefore(span, target.textNode.nextSibling);
|
|
1084
|
+
const rectAfter = host.getBoundingClientRect();
|
|
1085
|
+
const invalid = Math.abs(rectAfter.height - rectBefore.height) > 6 || Math.abs(rectAfter.width - rectBefore.width) > 20 || this._isTriggerClipped(host, span);
|
|
1086
|
+
if (invalid) {
|
|
1087
|
+
span.remove();
|
|
1088
|
+
target.textNode.textContent = target.text;
|
|
1089
|
+
return null;
|
|
1090
|
+
}
|
|
1091
|
+
this._replacedTextNode = target.textNode;
|
|
1092
|
+
this._replacedTextContent = target.text;
|
|
1093
|
+
return span;
|
|
1094
|
+
}
|
|
1095
|
+
_findReplacementTextTarget(host) {
|
|
1096
|
+
const triggerLength = "start hunt".length;
|
|
1097
|
+
const minReplaceLength = 5;
|
|
1098
|
+
const textTargets = [];
|
|
1099
|
+
const walker = document.createTreeWalker(host, NodeFilter.SHOW_TEXT, {
|
|
1100
|
+
acceptNode: (node) => {
|
|
1101
|
+
const parent = node.parentElement;
|
|
1102
|
+
const text = this._normalizeComparableText(node.textContent ?? "");
|
|
1103
|
+
if (!parent || text.length === 0) return NodeFilter.FILTER_REJECT;
|
|
1104
|
+
if (parent.closest("[data-eeq], script, style, noscript")) return NodeFilter.FILTER_REJECT;
|
|
1105
|
+
if (this._isIconLikeTarget(parent)) return NodeFilter.FILTER_REJECT;
|
|
1106
|
+
if (!isElementVisible(parent)) return NodeFilter.FILTER_REJECT;
|
|
1107
|
+
if (text.length < minReplaceLength) return NodeFilter.FILTER_REJECT;
|
|
1108
|
+
if (Math.abs(text.length - triggerLength) > 10) return NodeFilter.FILTER_REJECT;
|
|
1109
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
1110
|
+
}
|
|
1111
|
+
});
|
|
1112
|
+
let current = walker.nextNode();
|
|
1113
|
+
while (current) {
|
|
1114
|
+
const textNode = current;
|
|
1115
|
+
const parent = textNode.parentElement;
|
|
1116
|
+
const text = textNode.textContent ?? "";
|
|
1117
|
+
if (parent) {
|
|
1118
|
+
textTargets.push({ textNode, parent, text });
|
|
1119
|
+
}
|
|
1120
|
+
current = walker.nextNode();
|
|
1121
|
+
}
|
|
1122
|
+
if (!textTargets.length) return null;
|
|
1123
|
+
const shuffled = this._shuffleTextTargets(textTargets);
|
|
1124
|
+
return shuffled[0] ?? null;
|
|
1125
|
+
}
|
|
1126
|
+
_shuffleTextTargets(values) {
|
|
1127
|
+
const arr = [...values];
|
|
1128
|
+
for (let i = arr.length - 1; i > 0; i--) {
|
|
1129
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
1130
|
+
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
1131
|
+
}
|
|
1132
|
+
return arr;
|
|
1133
|
+
}
|
|
1134
|
+
_normalizeComparableText(text) {
|
|
1135
|
+
return text.replace(/\s+/g, " ").trim();
|
|
1136
|
+
}
|
|
1137
|
+
_isIconLikeTarget(parent) {
|
|
1138
|
+
const tag = parent.tagName.toLowerCase();
|
|
1139
|
+
const className = parent.className.toString().toLowerCase();
|
|
1140
|
+
const role = (parent.getAttribute("role") ?? "").toLowerCase();
|
|
1141
|
+
const ariaHidden = parent.getAttribute("aria-hidden");
|
|
1142
|
+
if (tag === "mat-icon" || tag === "svg" || tag === "i") return true;
|
|
1143
|
+
if (className.includes("icon") || className.includes("mat-icon")) return true;
|
|
1144
|
+
if (role === "img" || ariaHidden === "true") return true;
|
|
1145
|
+
if (parent.querySelector("svg, mat-icon")) return true;
|
|
1146
|
+
return false;
|
|
1147
|
+
}
|
|
1148
|
+
_restoreReplacedText() {
|
|
1149
|
+
if (this._replacedTextNode) {
|
|
1150
|
+
this._replacedTextNode.textContent = this._replacedTextContent;
|
|
1151
|
+
}
|
|
1152
|
+
this._replacedTextNode = null;
|
|
1153
|
+
this._replacedTextContent = "";
|
|
1154
|
+
}
|
|
1155
|
+
_applyTriggerTypography(span, source) {
|
|
1156
|
+
const style = getComputedStyle(source);
|
|
1157
|
+
span.style.cssText = `
|
|
1158
|
+
font-family: ${style.fontFamily};
|
|
1159
|
+
font-size: ${style.fontSize};
|
|
1160
|
+
font-weight: ${style.fontWeight};
|
|
1161
|
+
font-style: ${style.fontStyle};
|
|
1162
|
+
line-height: ${style.lineHeight};
|
|
1163
|
+
letter-spacing: ${style.letterSpacing};
|
|
1164
|
+
text-transform: ${style.textTransform};
|
|
1165
|
+
color: ${style.color};
|
|
1166
|
+
cursor: pointer;
|
|
1167
|
+
white-space: nowrap;
|
|
1168
|
+
transition: color 0.18s ease;
|
|
1169
|
+
`;
|
|
1170
|
+
}
|
|
1091
1171
|
// ─── Shared ───────────────────────────────────────────────────────────
|
|
1092
1172
|
_attachToElement(el) {
|
|
1093
1173
|
this.clickHandler = (e) => {
|
|
@@ -1279,9 +1359,7 @@ class HiddenEntry {
|
|
|
1279
1359
|
animation: eeq-shimmer 3s ease-in-out infinite !important;
|
|
1280
1360
|
}
|
|
1281
1361
|
.eeq-inline-trigger:hover {
|
|
1282
|
-
|
|
1283
|
-
opacity: 1;
|
|
1284
|
-
text-shadow: 0 0 10px rgba(255, 248, 220, 0.35);
|
|
1362
|
+
color: ${this.config.theme.accent};
|
|
1285
1363
|
}
|
|
1286
1364
|
@keyframes eeq-shimmer {
|
|
1287
1365
|
0%, 100% { opacity: 1; }
|