easter-egg-quest 1.0.16 → 1.0.18
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.
|
@@ -82,19 +82,14 @@ const DEFAULT_SCRIPT = {
|
|
|
82
82
|
],
|
|
83
83
|
stage3Success: [
|
|
84
84
|
"rhythm was the answer",
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"the third egg appears",
|
|
88
|
-
"for those who breathe"
|
|
85
|
+
"you found the third egg",
|
|
86
|
+
"nice work"
|
|
89
87
|
],
|
|
90
88
|
// ── Finale ────────────────────────────────────────────────────────────
|
|
91
89
|
finale: [
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"motion",
|
|
96
|
-
"rhythm",
|
|
97
|
-
"this is where life appears"
|
|
90
|
+
"all three eggs found",
|
|
91
|
+
"stillness, motion, rhythm",
|
|
92
|
+
"that's the whole set"
|
|
98
93
|
],
|
|
99
94
|
// ── Results / Share ───────────────────────────────────────────────────
|
|
100
95
|
results: [
|
|
@@ -520,7 +515,25 @@ function isElementVisible(el) {
|
|
|
520
515
|
if (rect.width === 0 || rect.height === 0) return false;
|
|
521
516
|
const style = getComputedStyle(el);
|
|
522
517
|
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0") return false;
|
|
523
|
-
|
|
518
|
+
const inViewport = rect.top < window.innerHeight && rect.bottom > 0 && rect.left < window.innerWidth && rect.right > 0;
|
|
519
|
+
if (!inViewport) return false;
|
|
520
|
+
let parent = el.parentElement;
|
|
521
|
+
while (parent && parent !== document.body) {
|
|
522
|
+
const parentStyle = getComputedStyle(parent);
|
|
523
|
+
const overflowClips = [
|
|
524
|
+
parentStyle.overflow,
|
|
525
|
+
parentStyle.overflowX,
|
|
526
|
+
parentStyle.overflowY
|
|
527
|
+
].some((value) => ["auto", "scroll", "hidden", "clip"].includes(value));
|
|
528
|
+
if (overflowClips) {
|
|
529
|
+
const parentRect = parent.getBoundingClientRect();
|
|
530
|
+
if (rect.bottom <= parentRect.top || rect.top >= parentRect.bottom || rect.right <= parentRect.left || rect.left >= parentRect.right) {
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
parent = parent.parentElement;
|
|
535
|
+
}
|
|
536
|
+
return true;
|
|
524
537
|
}
|
|
525
538
|
function isDangerousElement(el) {
|
|
526
539
|
const text = (el.textContent ?? "").toLowerCase().trim();
|
|
@@ -528,26 +541,6 @@ function isDangerousElement(el) {
|
|
|
528
541
|
const combined = `${text} ${ariaLabel}`;
|
|
529
542
|
return DANGEROUS_KEYWORDS.some((kw) => combined.includes(kw));
|
|
530
543
|
}
|
|
531
|
-
function findEligibleEntryElements(containerSelector, excludeSelectors = []) {
|
|
532
|
-
const container = containerSelector ? document.querySelector(containerSelector) ?? document.body : document.body;
|
|
533
|
-
const candidates = container.querySelectorAll(
|
|
534
|
-
'a, button, [role="button"], nav a, nav button, .cta, [data-easter-entry]'
|
|
535
|
-
);
|
|
536
|
-
const excludeSet = /* @__PURE__ */ new Set();
|
|
537
|
-
for (const sel of excludeSelectors) {
|
|
538
|
-
document.querySelectorAll(sel).forEach((el) => excludeSet.add(el));
|
|
539
|
-
}
|
|
540
|
-
const eligible = [];
|
|
541
|
-
candidates.forEach((el) => {
|
|
542
|
-
if (excludeSet.has(el)) return;
|
|
543
|
-
if (!isElementVisible(el)) return;
|
|
544
|
-
if (isDangerousElement(el)) return;
|
|
545
|
-
const rect = el.getBoundingClientRect();
|
|
546
|
-
if (rect.width < 30 || rect.height < 20) return;
|
|
547
|
-
eligible.push(el);
|
|
548
|
-
});
|
|
549
|
-
return eligible;
|
|
550
|
-
}
|
|
551
544
|
function pickRandom(arr) {
|
|
552
545
|
if (arr.length === 0) return void 0;
|
|
553
546
|
return arr[Math.floor(Math.random() * arr.length)];
|
|
@@ -577,6 +570,11 @@ class HiddenEntry {
|
|
|
577
570
|
this._intersectionObserver = null;
|
|
578
571
|
this._mutationDebounce = null;
|
|
579
572
|
this._navigationHandler = null;
|
|
573
|
+
this._bootstrapObserver = null;
|
|
574
|
+
this._retryTimer = null;
|
|
575
|
+
this._fallbackTimer = null;
|
|
576
|
+
this._retryCount = 0;
|
|
577
|
+
this._historyPatched = false;
|
|
580
578
|
this.config = config;
|
|
581
579
|
this.script = script;
|
|
582
580
|
this.onFound = onFound;
|
|
@@ -586,16 +584,10 @@ class HiddenEntry {
|
|
|
586
584
|
this._createFallbackEntry();
|
|
587
585
|
return;
|
|
588
586
|
}
|
|
589
|
-
const eligible = findEligibleEntryElements(
|
|
590
|
-
this.config.hiddenEntry.selector,
|
|
591
|
-
this.config.hiddenEntry.excludeSelectors
|
|
592
|
-
);
|
|
593
|
-
if (eligible.length === 0) {
|
|
594
|
-
this._createFallbackEntry();
|
|
595
|
-
return;
|
|
596
|
-
}
|
|
597
|
-
this._injectIntoExisting(eligible);
|
|
598
587
|
this._startHintEscalation();
|
|
588
|
+
this._startBootstrapWatch();
|
|
589
|
+
this._scheduleFallback();
|
|
590
|
+
this._attemptInjection(0);
|
|
599
591
|
}
|
|
600
592
|
cleanup() {
|
|
601
593
|
var _a2, _b2, _c, _d;
|
|
@@ -611,6 +603,7 @@ class HiddenEntry {
|
|
|
611
603
|
this.targetElement.classList.remove("eeq-entry-target");
|
|
612
604
|
}
|
|
613
605
|
this._stopWatchdog();
|
|
606
|
+
this._stopBootstrapWatch();
|
|
614
607
|
(_a2 = this._injectedElement) == null ? void 0 : _a2.remove();
|
|
615
608
|
this._injectedElement = null;
|
|
616
609
|
(_b2 = this.hintContainer) == null ? void 0 : _b2.remove();
|
|
@@ -623,17 +616,11 @@ class HiddenEntry {
|
|
|
623
616
|
this._attachToElement(this.targetElement);
|
|
624
617
|
}
|
|
625
618
|
// ─── Inject trigger text inside an existing element ─────────────────
|
|
626
|
-
_injectIntoExisting(
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
).filter((el) => {
|
|
632
|
-
var _a2;
|
|
633
|
-
const text = ((_a2 = el.textContent) == null ? void 0 : _a2.trim()) ?? "";
|
|
634
|
-
if (text.length < 2 || el.closest("[data-eeq]")) return false;
|
|
635
|
-
return isElementVisible(el);
|
|
636
|
-
});
|
|
619
|
+
_injectIntoExisting() {
|
|
620
|
+
var _a2;
|
|
621
|
+
const root = this._getSearchRoot();
|
|
622
|
+
const candidates = this._findTextCandidates(root);
|
|
623
|
+
if (candidates.length === 0) return false;
|
|
637
624
|
const sorted = candidates.sort((a, b) => {
|
|
638
625
|
const aNav = a.closest("nav") !== null || a.closest("header") !== null ? 1 : 0;
|
|
639
626
|
const bNav = b.closest("nav") !== null || b.closest("header") !== null ? 1 : 0;
|
|
@@ -644,8 +631,8 @@ class HiddenEntry {
|
|
|
644
631
|
});
|
|
645
632
|
const prints = sorted.map(
|
|
646
633
|
(el) => {
|
|
647
|
-
var
|
|
648
|
-
return `${el.tagName}:${(((
|
|
634
|
+
var _a3;
|
|
635
|
+
return `${el.tagName}:${(((_a3 = el.textContent) == null ? void 0 : _a3.trim()) ?? "").slice(0, 30)}`;
|
|
649
636
|
}
|
|
650
637
|
);
|
|
651
638
|
const HISTORY_KEY = "eeq_trigger_history";
|
|
@@ -677,8 +664,8 @@ class HiddenEntry {
|
|
|
677
664
|
];
|
|
678
665
|
const rotatedPrints = rotated.map(
|
|
679
666
|
(el) => {
|
|
680
|
-
var
|
|
681
|
-
return `${el.tagName}:${(((
|
|
667
|
+
var _a3;
|
|
668
|
+
return `${el.tagName}:${(((_a3 = el.textContent) == null ? void 0 : _a3.trim()) ?? "").slice(0, 30)}`;
|
|
682
669
|
}
|
|
683
670
|
);
|
|
684
671
|
const unused = rotated.filter((_, i) => !usedSet.has(rotatedPrints[i]));
|
|
@@ -692,6 +679,7 @@ class HiddenEntry {
|
|
|
692
679
|
const isInline = host.tagName === "A" || host.tagName === "BUTTON" || host.tagName === "LI" || host.closest("nav") !== null;
|
|
693
680
|
const span = document.createElement("span");
|
|
694
681
|
span.textContent = isInline ? " · start hunt" : " start hunt";
|
|
682
|
+
span.setAttribute("data-eeq", "trigger");
|
|
695
683
|
span.style.cssText = `
|
|
696
684
|
font: inherit;
|
|
697
685
|
color: inherit;
|
|
@@ -719,10 +707,161 @@ class HiddenEntry {
|
|
|
719
707
|
this._injectedElement = span;
|
|
720
708
|
this.targetElement = span;
|
|
721
709
|
this._attachToElement(span);
|
|
710
|
+
this._retryCount = 0;
|
|
711
|
+
this._clearRetryTimer();
|
|
712
|
+
this._clearFallbackTimer();
|
|
713
|
+
(_a2 = this.fallbackButton) == null ? void 0 : _a2.remove();
|
|
714
|
+
this.fallbackButton = null;
|
|
715
|
+
this._stopBootstrapWatch();
|
|
722
716
|
this._startWatchdog();
|
|
723
|
-
return;
|
|
717
|
+
return true;
|
|
718
|
+
}
|
|
719
|
+
return false;
|
|
720
|
+
}
|
|
721
|
+
_attemptInjection(delayMs) {
|
|
722
|
+
this._clearRetryTimer();
|
|
723
|
+
this._retryTimer = setTimeout(() => {
|
|
724
|
+
if (this._destroyed || this._injectedElement) return;
|
|
725
|
+
const ok = this._injectIntoExisting();
|
|
726
|
+
if (!ok) this._scheduleNextRetry();
|
|
727
|
+
}, delayMs);
|
|
728
|
+
}
|
|
729
|
+
_scheduleNextRetry() {
|
|
730
|
+
if (this._destroyed || this._injectedElement) return;
|
|
731
|
+
const delays = [300, 900, 1800, 3200, 5e3, 8e3];
|
|
732
|
+
const nextDelay = delays[Math.min(this._retryCount, delays.length - 1)];
|
|
733
|
+
this._retryCount += 1;
|
|
734
|
+
this._attemptInjection(nextDelay);
|
|
735
|
+
}
|
|
736
|
+
_scheduleFallback() {
|
|
737
|
+
if (this.fallbackButton || this._fallbackTimer) return;
|
|
738
|
+
this._fallbackTimer = setTimeout(() => {
|
|
739
|
+
if (this._destroyed || this._injectedElement || this.fallbackButton) return;
|
|
740
|
+
this._createFallbackEntry();
|
|
741
|
+
}, 1e4);
|
|
742
|
+
}
|
|
743
|
+
_clearRetryTimer() {
|
|
744
|
+
if (this._retryTimer) {
|
|
745
|
+
clearTimeout(this._retryTimer);
|
|
746
|
+
this._retryTimer = null;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
_clearFallbackTimer() {
|
|
750
|
+
if (this._fallbackTimer) {
|
|
751
|
+
clearTimeout(this._fallbackTimer);
|
|
752
|
+
this._fallbackTimer = null;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
_getSearchRoot() {
|
|
756
|
+
if (!this.config.hiddenEntry.selector) return document.body;
|
|
757
|
+
return document.querySelector(this.config.hiddenEntry.selector) ?? document.body;
|
|
758
|
+
}
|
|
759
|
+
_findTextCandidates(root) {
|
|
760
|
+
var _a2;
|
|
761
|
+
const selector = [
|
|
762
|
+
"p",
|
|
763
|
+
"li",
|
|
764
|
+
"figcaption",
|
|
765
|
+
"blockquote",
|
|
766
|
+
"caption",
|
|
767
|
+
"label",
|
|
768
|
+
"td",
|
|
769
|
+
"th",
|
|
770
|
+
"h1",
|
|
771
|
+
"h2",
|
|
772
|
+
"h3",
|
|
773
|
+
"h4",
|
|
774
|
+
"h5",
|
|
775
|
+
"h6",
|
|
776
|
+
"a",
|
|
777
|
+
"button",
|
|
778
|
+
'[role="button"]',
|
|
779
|
+
'[role="link"]',
|
|
780
|
+
"div",
|
|
781
|
+
"span",
|
|
782
|
+
"article",
|
|
783
|
+
"section",
|
|
784
|
+
"summary",
|
|
785
|
+
"[data-easter-entry]",
|
|
786
|
+
"[mat-button]",
|
|
787
|
+
"[mat-list-item]",
|
|
788
|
+
".mat-mdc-button",
|
|
789
|
+
".mat-mdc-list-item",
|
|
790
|
+
".ag-cell",
|
|
791
|
+
".ag-header-cell"
|
|
792
|
+
].join(", ");
|
|
793
|
+
const excludeSet = /* @__PURE__ */ new Set();
|
|
794
|
+
for (const sel of this.config.hiddenEntry.excludeSelectors) {
|
|
795
|
+
(_a2 = root.querySelectorAll) == null ? void 0 : _a2.call(root, sel).forEach((el) => excludeSet.add(el));
|
|
796
|
+
}
|
|
797
|
+
return Array.from(root.querySelectorAll(selector)).filter((el) => {
|
|
798
|
+
var _a3, _b2;
|
|
799
|
+
if (!(el instanceof HTMLElement)) return false;
|
|
800
|
+
if (excludeSet.has(el)) return false;
|
|
801
|
+
if (el.closest("[data-eeq]")) return false;
|
|
802
|
+
if (el.closest("script, style, noscript, svg, canvas, form")) return false;
|
|
803
|
+
if (isDangerousElement(el)) return false;
|
|
804
|
+
if (!isElementVisible(el)) return false;
|
|
805
|
+
const text = ((_a3 = el.innerText) == null ? void 0 : _a3.trim()) || ((_b2 = el.textContent) == null ? void 0 : _b2.trim()) || "";
|
|
806
|
+
if (text.length < 6 || text.length > 220) return false;
|
|
807
|
+
const childElementCount = el.children.length;
|
|
808
|
+
if (childElementCount > 12) return false;
|
|
809
|
+
const rect = el.getBoundingClientRect();
|
|
810
|
+
if (rect.width < 18 || rect.height < 12) return false;
|
|
811
|
+
return true;
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
_startBootstrapWatch() {
|
|
815
|
+
this._stopBootstrapWatch();
|
|
816
|
+
const root = this._getSearchRoot();
|
|
817
|
+
const observerTarget = root instanceof HTMLElement ? root : document.body;
|
|
818
|
+
this._bootstrapObserver = new MutationObserver(() => {
|
|
819
|
+
if (this._destroyed || this._injectedElement) return;
|
|
820
|
+
if (this._mutationDebounce) clearTimeout(this._mutationDebounce);
|
|
821
|
+
this._mutationDebounce = setTimeout(() => {
|
|
822
|
+
if (this._destroyed || this._injectedElement) return;
|
|
823
|
+
this._attemptInjection(150);
|
|
824
|
+
}, 250);
|
|
825
|
+
});
|
|
826
|
+
this._bootstrapObserver.observe(observerTarget, { childList: true, subtree: true });
|
|
827
|
+
this._navigationHandler = () => {
|
|
828
|
+
if (this._destroyed || this._injectedElement) return;
|
|
829
|
+
this._attemptInjection(700);
|
|
830
|
+
};
|
|
831
|
+
window.addEventListener("popstate", this._navigationHandler);
|
|
832
|
+
window.addEventListener("hashchange", this._navigationHandler);
|
|
833
|
+
if (!this._historyPatched && typeof window.history !== "undefined") {
|
|
834
|
+
this._historyPatched = true;
|
|
835
|
+
const patchHistoryMethod = (method) => {
|
|
836
|
+
const original = window.history[method].bind(window.history);
|
|
837
|
+
window.history[method] = (...args) => {
|
|
838
|
+
const result = original(...args);
|
|
839
|
+
window.dispatchEvent(new Event("eeq:navigation"));
|
|
840
|
+
return result;
|
|
841
|
+
};
|
|
842
|
+
};
|
|
843
|
+
patchHistoryMethod("pushState");
|
|
844
|
+
patchHistoryMethod("replaceState");
|
|
845
|
+
}
|
|
846
|
+
window.addEventListener("eeq:navigation", this._navigationHandler);
|
|
847
|
+
}
|
|
848
|
+
_stopBootstrapWatch() {
|
|
849
|
+
if (this._bootstrapObserver) {
|
|
850
|
+
this._bootstrapObserver.disconnect();
|
|
851
|
+
this._bootstrapObserver = null;
|
|
852
|
+
}
|
|
853
|
+
this._clearRetryTimer();
|
|
854
|
+
this._clearFallbackTimer();
|
|
855
|
+
if (this._mutationDebounce) {
|
|
856
|
+
clearTimeout(this._mutationDebounce);
|
|
857
|
+
this._mutationDebounce = null;
|
|
858
|
+
}
|
|
859
|
+
if (this._navigationHandler) {
|
|
860
|
+
window.removeEventListener("popstate", this._navigationHandler);
|
|
861
|
+
window.removeEventListener("hashchange", this._navigationHandler);
|
|
862
|
+
window.removeEventListener("eeq:navigation", this._navigationHandler);
|
|
863
|
+
this._navigationHandler = null;
|
|
724
864
|
}
|
|
725
|
-
this._createFallbackEntry();
|
|
726
865
|
}
|
|
727
866
|
/**
|
|
728
867
|
* Watch for the injected trigger element being removed from the DOM
|
|
@@ -769,6 +908,7 @@ class HiddenEntry {
|
|
|
769
908
|
};
|
|
770
909
|
window.addEventListener("popstate", this._navigationHandler);
|
|
771
910
|
window.addEventListener("hashchange", this._navigationHandler);
|
|
911
|
+
window.addEventListener("eeq:navigation", this._navigationHandler);
|
|
772
912
|
}
|
|
773
913
|
/**
|
|
774
914
|
* Walk up the DOM to find a stable ancestor that won't be replaced
|
|
@@ -803,6 +943,7 @@ class HiddenEntry {
|
|
|
803
943
|
if (this._navigationHandler) {
|
|
804
944
|
window.removeEventListener("popstate", this._navigationHandler);
|
|
805
945
|
window.removeEventListener("hashchange", this._navigationHandler);
|
|
946
|
+
window.removeEventListener("eeq:navigation", this._navigationHandler);
|
|
806
947
|
this._navigationHandler = null;
|
|
807
948
|
}
|
|
808
949
|
}
|
|
@@ -817,13 +958,12 @@ class HiddenEntry {
|
|
|
817
958
|
}
|
|
818
959
|
this._injectedElement = null;
|
|
819
960
|
this.targetElement = null;
|
|
961
|
+
this._startBootstrapWatch();
|
|
962
|
+
this._scheduleFallback();
|
|
820
963
|
setTimeout(() => {
|
|
821
964
|
if (this._destroyed) return;
|
|
822
|
-
const
|
|
823
|
-
|
|
824
|
-
this.config.hiddenEntry.excludeSelectors
|
|
825
|
-
);
|
|
826
|
-
this._injectIntoExisting(eligible);
|
|
965
|
+
const ok = this._injectIntoExisting();
|
|
966
|
+
if (!ok) this._scheduleNextRetry();
|
|
827
967
|
}, 1200);
|
|
828
968
|
}
|
|
829
969
|
/**
|
|
@@ -832,12 +972,22 @@ class HiddenEntry {
|
|
|
832
972
|
* Returns true if inserted without layout shift.
|
|
833
973
|
*/
|
|
834
974
|
_tryInsertBetweenWords(host, span) {
|
|
835
|
-
var _a2;
|
|
836
975
|
const textNodes = [];
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
976
|
+
const walker = document.createTreeWalker(host, NodeFilter.SHOW_TEXT, {
|
|
977
|
+
acceptNode: (node) => {
|
|
978
|
+
var _a2;
|
|
979
|
+
const text2 = ((_a2 = node.textContent) == null ? void 0 : _a2.trim()) ?? "";
|
|
980
|
+
if (text2.length <= 5) return NodeFilter.FILTER_REJECT;
|
|
981
|
+
const parent = node.parentElement;
|
|
982
|
+
if (!parent) return NodeFilter.FILTER_REJECT;
|
|
983
|
+
if (parent.closest("[data-eeq], script, style, noscript")) return NodeFilter.FILTER_REJECT;
|
|
984
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
840
985
|
}
|
|
986
|
+
});
|
|
987
|
+
let current = walker.nextNode();
|
|
988
|
+
while (current) {
|
|
989
|
+
textNodes.push(current);
|
|
990
|
+
current = walker.nextNode();
|
|
841
991
|
}
|
|
842
992
|
if (!textNodes.length) return false;
|
|
843
993
|
const slotSeed = Math.floor(Date.now() / (1e3 * 60 * 2));
|
|
@@ -854,13 +1004,13 @@ class HiddenEntry {
|
|
|
854
1004
|
const splitAt = spacePositions[Math.min(idx, spacePositions.length - 1)];
|
|
855
1005
|
const before = text.slice(0, splitAt);
|
|
856
1006
|
const after = text.slice(splitAt);
|
|
857
|
-
const
|
|
1007
|
+
const rectBefore = host.getBoundingClientRect();
|
|
858
1008
|
const afterNode = document.createTextNode(after);
|
|
859
1009
|
textNode.textContent = before;
|
|
860
1010
|
host.insertBefore(afterNode, textNode.nextSibling);
|
|
861
1011
|
host.insertBefore(span, afterNode);
|
|
862
|
-
const
|
|
863
|
-
if (Math.abs(
|
|
1012
|
+
const rectAfter = host.getBoundingClientRect();
|
|
1013
|
+
if (Math.abs(rectAfter.height - rectBefore.height) > 8 || Math.abs(rectAfter.width - rectBefore.width) > 24) {
|
|
864
1014
|
host.removeChild(span);
|
|
865
1015
|
host.removeChild(afterNode);
|
|
866
1016
|
textNode.textContent = text;
|
|
@@ -1105,6 +1255,7 @@ class HiddenEntry {
|
|
|
1105
1255
|
document.head.appendChild(this.shimmerStyle);
|
|
1106
1256
|
}
|
|
1107
1257
|
_createFallbackEntry() {
|
|
1258
|
+
if (this.fallbackButton) return;
|
|
1108
1259
|
this.fallbackButton = document.createElement("button");
|
|
1109
1260
|
this.fallbackButton.textContent = "·";
|
|
1110
1261
|
this.fallbackButton.setAttribute("aria-label", "Hidden game entry");
|
|
@@ -3568,16 +3719,16 @@ const _ResultsRenderer = class _ResultsRenderer {
|
|
|
3568
3719
|
inner.appendChild(badgesDiv);
|
|
3569
3720
|
const invite = document.createElement("div");
|
|
3570
3721
|
invite.className = "eeq-share-invite";
|
|
3571
|
-
invite.textContent = "share your result
|
|
3722
|
+
invite.textContent = "share or copy your result";
|
|
3572
3723
|
inner.appendChild(invite);
|
|
3573
3724
|
const actions = document.createElement("div");
|
|
3574
3725
|
actions.className = "eeq-results-actions";
|
|
3575
3726
|
const shareBtn = document.createElement("button");
|
|
3576
3727
|
shareBtn.className = "eeq-btn eeq-btn-share";
|
|
3577
|
-
shareBtn.title = "share result";
|
|
3728
|
+
shareBtn.title = "share or copy result";
|
|
3578
3729
|
shareBtn.innerHTML = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4.5 10.5a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm7-4a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4z" stroke="currentColor" stroke-width="1.2"/><path d="M6.3 9.2l3.4 1.6M6.3 7.8l3.4-1.6" stroke="currentColor" stroke-width="1.2"/></svg>';
|
|
3579
3730
|
const shareLabel = document.createElement("span");
|
|
3580
|
-
shareLabel.textContent = "share";
|
|
3731
|
+
shareLabel.textContent = "share / copy";
|
|
3581
3732
|
shareBtn.appendChild(shareLabel);
|
|
3582
3733
|
actions.appendChild(shareBtn);
|
|
3583
3734
|
const finishBtn = document.createElement("button");
|
|
@@ -3811,6 +3962,7 @@ const _ResultsRenderer = class _ResultsRenderer {
|
|
|
3811
3962
|
_copyShareImage(s) {
|
|
3812
3963
|
var _a2;
|
|
3813
3964
|
const canvas = this._renderCard(s);
|
|
3965
|
+
const shareText = this._buildShareText(s);
|
|
3814
3966
|
const dataUrl = canvas.toDataURL("image/png");
|
|
3815
3967
|
const byteString = atob(dataUrl.split(",")[1]);
|
|
3816
3968
|
const ab = new ArrayBuffer(byteString.length);
|
|
@@ -3824,17 +3976,35 @@ const _ResultsRenderer = class _ResultsRenderer {
|
|
|
3824
3976
|
navigator.share({
|
|
3825
3977
|
files: [file],
|
|
3826
3978
|
title: "Easter Egg Quest",
|
|
3827
|
-
text:
|
|
3979
|
+
text: shareText
|
|
3828
3980
|
}).catch(() => {
|
|
3829
3981
|
});
|
|
3830
3982
|
return;
|
|
3831
3983
|
}
|
|
3984
|
+
navigator.share({
|
|
3985
|
+
title: "Easter Egg Quest",
|
|
3986
|
+
text: shareText
|
|
3987
|
+
}).catch(() => {
|
|
3988
|
+
});
|
|
3989
|
+
return;
|
|
3832
3990
|
}
|
|
3833
3991
|
if (navigator.clipboard && typeof ClipboardItem !== "undefined") {
|
|
3834
3992
|
navigator.clipboard.write([
|
|
3835
3993
|
new ClipboardItem({ "image/png": blob })
|
|
3836
3994
|
]).then(() => {
|
|
3837
|
-
this._flashButton(".eeq-btn-share", "copied
|
|
3995
|
+
this._flashButton(".eeq-btn-share", "image copied");
|
|
3996
|
+
}).catch(() => {
|
|
3997
|
+
this._copyShareText(shareText, blob);
|
|
3998
|
+
});
|
|
3999
|
+
return;
|
|
4000
|
+
}
|
|
4001
|
+
this._copyShareText(shareText, blob);
|
|
4002
|
+
}
|
|
4003
|
+
_copyShareText(text, blob) {
|
|
4004
|
+
var _a2;
|
|
4005
|
+
if ((_a2 = navigator.clipboard) == null ? void 0 : _a2.writeText) {
|
|
4006
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
4007
|
+
this._flashButton(".eeq-btn-share", "text copied");
|
|
3838
4008
|
}).catch(() => {
|
|
3839
4009
|
this._downloadBlob(blob);
|
|
3840
4010
|
});
|
|
@@ -3842,6 +4012,11 @@ const _ResultsRenderer = class _ResultsRenderer {
|
|
|
3842
4012
|
}
|
|
3843
4013
|
this._downloadBlob(blob);
|
|
3844
4014
|
}
|
|
4015
|
+
_buildShareText(s) {
|
|
4016
|
+
const time = formatTime(s.totalTime);
|
|
4017
|
+
const eggs = `${s.eggsFound}/3 eggs`;
|
|
4018
|
+
return `Easter Egg Quest: ${s.behaviorProfile.title} • ${time} • ${eggs}`;
|
|
4019
|
+
}
|
|
3845
4020
|
_downloadBlob(blob) {
|
|
3846
4021
|
const url = URL.createObjectURL(blob);
|
|
3847
4022
|
const a = document.createElement("a");
|
|
@@ -3921,10 +4096,10 @@ const _ResultsRenderer = class _ResultsRenderer {
|
|
|
3921
4096
|
ctx.fillText(labels.join(" · "), W / 2, divY + 92);
|
|
3922
4097
|
ctx.font = "14px Georgia, serif";
|
|
3923
4098
|
ctx.fillStyle = "rgba(232,224,214,0.55)";
|
|
3924
|
-
ctx.fillText("
|
|
4099
|
+
ctx.fillText("All three eggs found", W / 2, divY + 130);
|
|
3925
4100
|
ctx.font = "11px Georgia, serif";
|
|
3926
4101
|
ctx.fillStyle = "rgba(232,224,214,0.3)";
|
|
3927
|
-
ctx.fillText("
|
|
4102
|
+
ctx.fillText("Share or copy your result", W / 2, divY + 150);
|
|
3928
4103
|
ctx.font = "9px Georgia, serif";
|
|
3929
4104
|
ctx.fillStyle = "rgba(232,224,214,0.12)";
|
|
3930
4105
|
ctx.fillText("easter egg quest", W / 2, H - 16);
|