interestfor 1.0.9 → 1.0.11
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/README.md +19 -5
- package/package.json +1 -1
- package/src/interestfor.js +191 -39
- package/src/interestfor.min.js +1 -1
- package/test/basic_test.html +60 -17
- package/test/test.html +839 -284
package/README.md
CHANGED
|
@@ -202,15 +202,29 @@ native feature:
|
|
|
202
202
|
- The polyfill installs a `MutationObserver` on the document to keep interest
|
|
203
203
|
buttons up to date, and prepends a `<style>` element to `<head>` containing
|
|
204
204
|
the default styles for interest invokers and interest buttons.
|
|
205
|
+
- Accessibility mappings (`aria-labelledby`, `aria-describedby`, `aria-details`,
|
|
206
|
+
`aria-expanded`, and `role="tooltip"`) are set up on a best-effort basis by
|
|
207
|
+
inspecting the DOM. Because JavaScript does not have access to the browser's
|
|
208
|
+
accessibility tree or computed roles/names, the polyfill cannot match the
|
|
209
|
+
native feature in all cases (for example, when accessible names depend on CSS,
|
|
210
|
+
shadow DOM boundaries, or targets without an `id`, or when plain vs. rich
|
|
211
|
+
hint classification depends on computed roles). Native browser support handles
|
|
212
|
+
these accessibility mappings directly in the accessibility tree without
|
|
213
|
+
mutating DOM attributes.
|
|
214
|
+
- On iOS (detected via user-agent sniffing for `iPad`, `iPhone`, or `iPod`),
|
|
215
|
+
long-pressing a `<button interestfor>` shows interest when the finger is
|
|
216
|
+
released (`touchend`) after holding for at least 500ms, rather than while the
|
|
217
|
+
finger is still held down. Unlike Android (which fires `pointercancel` and
|
|
218
|
+
`touchcancel` after a ~500ms hold), iOS WebKit does not cancel the touch
|
|
219
|
+
stream and fires `pointerup` on finger release, which would otherwise trigger
|
|
220
|
+
native popover light-dismiss on a popover opened after `pointerdown`.
|
|
205
221
|
|
|
206
222
|
|
|
207
223
|
## Tests
|
|
208
224
|
|
|
209
|
-
The `test/test.html` file
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
polyfill (optionally minified) or the native feature. You can run tests directly
|
|
213
|
-
from this repo,
|
|
225
|
+
The `test/test.html` file contains an automated test suite that runs on page
|
|
226
|
+
load and tests the polyfill (either `src/interestfor.js` or
|
|
227
|
+
`src/interestfor.min.js`). You can run the tests directly from this repo,
|
|
214
228
|
[here](https://mfreed7.github.io/interestfor/test/test.html).
|
|
215
229
|
|
|
216
230
|
## Browser Compatibility
|
package/package.json
CHANGED
package/src/interestfor.js
CHANGED
|
@@ -59,8 +59,7 @@
|
|
|
59
59
|
capture: true,
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
|
-
|
|
63
|
-
if(!window.InterestEvent) {
|
|
62
|
+
if (!window.InterestEvent || window.interestForUsePolyfillAlways) {
|
|
64
63
|
window.InterestEvent = class InterestEvent extends Event {
|
|
65
64
|
#source;
|
|
66
65
|
constructor(type, eventInit = {}) {
|
|
@@ -561,12 +560,111 @@
|
|
|
561
560
|
return true;
|
|
562
561
|
}
|
|
563
562
|
|
|
563
|
+
// Best-effort approximation of the Accessible Name Computation algorithm.
|
|
564
|
+
// Because JavaScript cannot query the browser's actual accessibility tree,
|
|
565
|
+
// this only inspects common DOM attributes (`aria-labelledby`, `aria-label`,
|
|
566
|
+
// `alt`, `title`), `<label>` elements, and subtree text nodes. It will miss
|
|
567
|
+
// names or visibility derived from CSS (e.g. `display: none` or `::before`
|
|
568
|
+
// `content`), `ElementInternals`, `ariaLabelledByElements`, or other
|
|
569
|
+
// browser-internal accessibility heuristics.
|
|
570
|
+
function normalizeText(str) {
|
|
571
|
+
return str ? str.replace(/\s+/g, " ").trim() : "";
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function getSubtreeText(node, isRoot = false) {
|
|
575
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
576
|
+
return node.data;
|
|
577
|
+
}
|
|
578
|
+
if (node.nodeType !== Node.ELEMENT_NODE) {
|
|
579
|
+
return "";
|
|
580
|
+
}
|
|
581
|
+
if (
|
|
582
|
+
!isRoot &&
|
|
583
|
+
(node.hasAttribute("hidden") ||
|
|
584
|
+
node.getAttribute("aria-hidden") === "true" ||
|
|
585
|
+
node.localName === "script" ||
|
|
586
|
+
node.localName === "style")
|
|
587
|
+
) {
|
|
588
|
+
return "";
|
|
589
|
+
}
|
|
590
|
+
const ariaLabel = node.getAttribute("aria-label");
|
|
591
|
+
if (ariaLabel) {
|
|
592
|
+
return ariaLabel;
|
|
593
|
+
}
|
|
594
|
+
if (node.localName === "img" || node.localName === "area") {
|
|
595
|
+
return node.getAttribute("alt") || "";
|
|
596
|
+
}
|
|
597
|
+
let text = "";
|
|
598
|
+
for (const child of node.childNodes) {
|
|
599
|
+
text += getSubtreeText(child);
|
|
600
|
+
}
|
|
601
|
+
return text;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
function getAccessibleName(el) {
|
|
605
|
+
const labelledBy = el.getAttribute("aria-labelledby");
|
|
606
|
+
if (labelledBy) {
|
|
607
|
+
const root = getRootNode(el);
|
|
608
|
+
if (typeof root.getElementById === "function") {
|
|
609
|
+
const parts = [];
|
|
610
|
+
for (const id of labelledBy.trim().split(/\s+/)) {
|
|
611
|
+
const ref = id ? root.getElementById(id) : null;
|
|
612
|
+
if (ref) {
|
|
613
|
+
parts.push(normalizeText(getSubtreeText(ref, true)));
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
const text = normalizeText(parts.join(" "));
|
|
617
|
+
if (text) {
|
|
618
|
+
return text;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
const ariaLabel = normalizeText(el.getAttribute("aria-label"));
|
|
623
|
+
if (ariaLabel) {
|
|
624
|
+
return ariaLabel;
|
|
625
|
+
}
|
|
626
|
+
if (el.labels?.length) {
|
|
627
|
+
const labelText = normalizeText(
|
|
628
|
+
[...el.labels].map((l) => getSubtreeText(l, true)).join(" ")
|
|
629
|
+
);
|
|
630
|
+
if (labelText) {
|
|
631
|
+
return labelText;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
const subtreeText = normalizeText(getSubtreeText(el, true));
|
|
635
|
+
if (subtreeText) {
|
|
636
|
+
return subtreeText;
|
|
637
|
+
}
|
|
638
|
+
return normalizeText(el.getAttribute("title"));
|
|
639
|
+
}
|
|
640
|
+
|
|
564
641
|
function setupAccessibility(invoker, target) {
|
|
642
|
+
if (!target.id) {
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
565
645
|
if (isPlainHint(target)) {
|
|
566
|
-
invoker.
|
|
646
|
+
const labelledBy = invoker.getAttribute("aria-labelledby") || "";
|
|
647
|
+
if (labelledBy.trim().split(/\s+/).includes(target.id)) {
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
const name = getAccessibleName(invoker);
|
|
651
|
+
const hintText = normalizeText(getSubtreeText(target, true));
|
|
652
|
+
if (!name) {
|
|
653
|
+
if (hintText) {
|
|
654
|
+
invoker.setAttribute("aria-labelledby", target.id);
|
|
655
|
+
}
|
|
656
|
+
} else if (
|
|
657
|
+
hintText &&
|
|
658
|
+
hintText !== name &&
|
|
659
|
+
!invoker.hasAttribute("aria-describedby")
|
|
660
|
+
) {
|
|
661
|
+
invoker.setAttribute("aria-describedby", target.id);
|
|
662
|
+
}
|
|
567
663
|
} else {
|
|
568
664
|
// Rich hint
|
|
569
|
-
invoker.
|
|
665
|
+
if (!invoker.hasAttribute("aria-details")) {
|
|
666
|
+
invoker.setAttribute("aria-details", target.id);
|
|
667
|
+
}
|
|
570
668
|
invoker.setAttribute("aria-expanded", "false");
|
|
571
669
|
if (!target.hasAttribute("role")) {
|
|
572
670
|
target.setAttribute("role", "tooltip");
|
|
@@ -575,23 +673,26 @@
|
|
|
575
673
|
}
|
|
576
674
|
|
|
577
675
|
function initializeDataField(el) {
|
|
578
|
-
if (el[dataField])
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
676
|
+
if (!el[dataField]) {
|
|
677
|
+
el[dataField] = {
|
|
678
|
+
state: InterestState.NoInterest,
|
|
679
|
+
target: null,
|
|
680
|
+
a11yTarget: null,
|
|
681
|
+
gainedTimer: null,
|
|
682
|
+
lostTimer: null,
|
|
683
|
+
longPressTimer: null,
|
|
684
|
+
suppressNextFocusInterest: false,
|
|
685
|
+
clearGainedTask() {
|
|
686
|
+
clearTimeout(this.gainedTimer);
|
|
687
|
+
},
|
|
688
|
+
clearLostTask() {
|
|
689
|
+
clearTimeout(this.lostTimer);
|
|
690
|
+
},
|
|
691
|
+
};
|
|
692
|
+
}
|
|
593
693
|
const target = GetInterestForTarget(el);
|
|
594
|
-
if (target) {
|
|
694
|
+
if (target && el[dataField].a11yTarget !== target) {
|
|
695
|
+
el[dataField].a11yTarget = target;
|
|
595
696
|
setupAccessibility(el, target);
|
|
596
697
|
}
|
|
597
698
|
}
|
|
@@ -764,20 +865,24 @@
|
|
|
764
865
|
const updates = [];
|
|
765
866
|
for (const invoker of invokers) {
|
|
766
867
|
let content = null;
|
|
767
|
-
|
|
868
|
+
const target = GetInterestForTarget(invoker);
|
|
869
|
+
if (target) {
|
|
870
|
+
invokersMissingTarget.delete(invoker);
|
|
768
871
|
if (wantsInterestButton(invoker)) {
|
|
769
|
-
invokersMissingTarget.delete(invoker);
|
|
770
872
|
content = getInterestButtonContent(invoker);
|
|
771
|
-
} else {
|
|
772
|
-
// The target might be added (or become valid) later.
|
|
773
|
-
invokersMissingTarget.add(invoker);
|
|
774
873
|
}
|
|
874
|
+
} else if (invoker.isConnected && invoker.hasAttribute(attributeName)) {
|
|
875
|
+
// The target might be added (or become valid) later.
|
|
876
|
+
invokersMissingTarget.add(invoker);
|
|
775
877
|
} else {
|
|
776
878
|
invokersMissingTarget.delete(invoker);
|
|
777
879
|
}
|
|
778
|
-
updates.push([invoker, content]);
|
|
880
|
+
updates.push([invoker, target, content]);
|
|
779
881
|
}
|
|
780
|
-
for (const [invoker, content] of updates) {
|
|
882
|
+
for (const [invoker, target, content] of updates) {
|
|
883
|
+
if (target) {
|
|
884
|
+
initializeDataField(invoker);
|
|
885
|
+
}
|
|
781
886
|
setInterestButton(invoker, content);
|
|
782
887
|
}
|
|
783
888
|
}
|
|
@@ -879,11 +984,19 @@
|
|
|
879
984
|
HandleInterestHoverOrFocus(el, source);
|
|
880
985
|
}
|
|
881
986
|
};
|
|
987
|
+
const clearTouch = (e) => {
|
|
988
|
+
if (e.pointerType !== "touch") {
|
|
989
|
+
touchInProgress = false;
|
|
990
|
+
}
|
|
991
|
+
};
|
|
992
|
+
document.body.addEventListener("pointerover", clearTouch);
|
|
993
|
+
document.body.addEventListener("pointerdown", clearTouch);
|
|
882
994
|
document.body.addEventListener("mouseover", (e) => handler(e, Source.Hover));
|
|
883
995
|
document.body.addEventListener("mouseout", (e) => handler(e, Source.DeHover));
|
|
884
996
|
document.body.addEventListener("focusin", (e) => handler(e, Source.Focus));
|
|
885
997
|
document.body.addEventListener("focusout", (e) => handler(e, Source.Blur));
|
|
886
998
|
document.body.addEventListener("keydown", (e) => {
|
|
999
|
+
touchInProgress = false;
|
|
887
1000
|
if (e.key === "Escape" && !e.defaultPrevented) {
|
|
888
1001
|
// Lose interest in all invokers, most recent first. These
|
|
889
1002
|
// `loseinterest` events are not cancelable.
|
|
@@ -899,20 +1012,37 @@
|
|
|
899
1012
|
});
|
|
900
1013
|
// Touch support
|
|
901
1014
|
const longPressTime = 500;
|
|
1015
|
+
// WebKit (iOS) long-press workaround:
|
|
1016
|
+
// On Android, holding for ~500ms fires `pointercancel` and `touchcancel`,
|
|
1017
|
+
// so the popover can open immediately when `longPressTimer` fires while the
|
|
1018
|
+
// finger is still down. On iOS WebKit, holding a button with
|
|
1019
|
+
// `user-select: none` does not cancel the touch stream; when the finger is
|
|
1020
|
+
// later lifted, iOS fires `pointerup` (which triggers WebKit's native
|
|
1021
|
+
// popover light-dismiss because the popover was not open at `pointerdown`)
|
|
1022
|
+
// followed by `touchend` and synthesized mouse/`click` events.
|
|
1023
|
+
// On iOS only, record that the 500ms hold succeeded (`longPressActive`),
|
|
1024
|
+
// and on `touchend` (which fires after `pointerup`), call `preventDefault()`
|
|
1025
|
+
// to suppress the synthesized `click` and open the popover then.
|
|
1026
|
+
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
902
1027
|
document.body.addEventListener("touchstart", (e) => {
|
|
903
1028
|
touchInProgress = true;
|
|
904
1029
|
const invoker = e.target.closest("button[interestfor]");
|
|
905
1030
|
if (invoker) {
|
|
906
1031
|
initializeDataField(invoker);
|
|
1032
|
+
invoker[dataField].longPressActive = false;
|
|
907
1033
|
invoker[dataField].longPressTimer = setTimeout(() => {
|
|
908
1034
|
// Long-press shows interest immediately, and that interest is not
|
|
909
1035
|
// lost by de-hovering or blurring the invoker.
|
|
910
1036
|
if (invoker[dataField].state === InterestState.NoInterest) {
|
|
911
|
-
|
|
912
|
-
invoker
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
1037
|
+
if (isIOS) {
|
|
1038
|
+
invoker[dataField].longPressActive = true;
|
|
1039
|
+
} else {
|
|
1040
|
+
GainOrLoseInterest(
|
|
1041
|
+
invoker,
|
|
1042
|
+
GetInterestForTarget(invoker),
|
|
1043
|
+
InterestState.ExplicitInterest
|
|
1044
|
+
);
|
|
1045
|
+
}
|
|
916
1046
|
}
|
|
917
1047
|
invoker[dataField].longPressTimer = null;
|
|
918
1048
|
}, longPressTime);
|
|
@@ -920,24 +1050,45 @@
|
|
|
920
1050
|
});
|
|
921
1051
|
const cancelLongPress = (e) => {
|
|
922
1052
|
const invoker = e.target.closest("button[interestfor]");
|
|
923
|
-
if (invoker && invoker[dataField]
|
|
1053
|
+
if (invoker && invoker[dataField]) {
|
|
924
1054
|
clearTimeout(invoker[dataField].longPressTimer);
|
|
925
1055
|
invoker[dataField].longPressTimer = null;
|
|
1056
|
+
invoker[dataField].longPressActive = false;
|
|
926
1057
|
}
|
|
927
1058
|
};
|
|
928
|
-
document.body.addEventListener("touchend", (e) => {
|
|
929
|
-
cancelLongPress(e);
|
|
930
|
-
touchInProgress = false;
|
|
931
|
-
});
|
|
932
1059
|
document.body.addEventListener("touchmove", cancelLongPress);
|
|
1060
|
+
document.body.addEventListener(
|
|
1061
|
+
"touchend",
|
|
1062
|
+
(e) => {
|
|
1063
|
+
const invoker = e.target.closest("button[interestfor]");
|
|
1064
|
+
const longPressActive = invoker?.[dataField]?.longPressActive;
|
|
1065
|
+
cancelLongPress(e);
|
|
1066
|
+
if (longPressActive) {
|
|
1067
|
+
if (e.cancelable) {
|
|
1068
|
+
e.preventDefault();
|
|
1069
|
+
}
|
|
1070
|
+
if (invoker[dataField].state === InterestState.NoInterest) {
|
|
1071
|
+
GainOrLoseInterest(
|
|
1072
|
+
invoker,
|
|
1073
|
+
GetInterestForTarget(invoker),
|
|
1074
|
+
InterestState.ExplicitInterest
|
|
1075
|
+
);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
},
|
|
1079
|
+
{ passive: false }
|
|
1080
|
+
);
|
|
933
1081
|
}
|
|
934
1082
|
|
|
935
1083
|
// CSS registration
|
|
936
1084
|
function registerCustomProperties() {
|
|
937
1085
|
const style = document.createElement("style");
|
|
1086
|
+
// `@property` syntax can't express "one or two of `normal | <time>`", so
|
|
1087
|
+
// the shorthand uses the universal syntax. It is still registered, so that
|
|
1088
|
+
// it doesn't inherit.
|
|
938
1089
|
style.textContent = `@property ${interestDelayStartProp} {syntax: "normal | <time>"; inherits: false; initial-value: normal;}
|
|
939
1090
|
@property ${interestDelayEndProp} {syntax: "normal | <time>"; inherits: false; initial-value: normal;}
|
|
940
|
-
@property ${interestDelayProp} {syntax: "
|
|
1091
|
+
@property ${interestDelayProp} {syntax: "*"; inherits: false;}
|
|
941
1092
|
@property ${interestButtonContentProp} {syntax: "*"; inherits: false;}`;
|
|
942
1093
|
document.head.appendChild(style);
|
|
943
1094
|
// Equivalents of the UA stylesheet rules for interest invokers. These are
|
|
@@ -1007,7 +1158,8 @@
|
|
|
1007
1158
|
].forEach((iface) => {
|
|
1008
1159
|
if (
|
|
1009
1160
|
iface &&
|
|
1010
|
-
!Object.prototype.hasOwnProperty.call(iface.prototype, "interestForElement")
|
|
1161
|
+
(!Object.prototype.hasOwnProperty.call(iface.prototype, "interestForElement") ||
|
|
1162
|
+
window.interestForUsePolyfillAlways)
|
|
1011
1163
|
) {
|
|
1012
1164
|
Object.defineProperty(iface.prototype, "interestForElement", descriptor);
|
|
1013
1165
|
}
|
package/src/interestfor.min.js
CHANGED
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
// LICENSE file in the root directory of this source tree.
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
!function(){const e="interestfor",t="interest",n="loseinterest",r="--interest-delay-start",o="--interest-delay-end",s="--interest-delay",i="--interest-button-content",a="--interest-button-polyfill-content",l="interest-button",c="__interestForData",u="__interestForTargetData",d="__interestForButton",f="__interestForButtonInvoker",m="__interestForExplicitTarget",p="http://www.w3.org/1999/xlink",h=new Set,b=new Set,y=new Set;let g=!1;if(window.interestForPolyfillInstalled)return;window.interestForPolyfillInstalled=!0;const w=HTMLButtonElement.prototype.hasOwnProperty("interestForElement");if(w&&!window.interestForUsePolyfillAlways)return;if(w){const e=e=>{e.isTrusted&&(e.preventDefault(),e.stopImmediatePropagation())};document.body.addEventListener(t,e,{capture:!0}),document.body.addEventListener(n,e,{capture:!0})}window.InterestEvent||(window.InterestEvent=class extends Event{#e;constructor(e,t={}){super(e,t);const{source:n}=t;if(null!=n&&!(n instanceof Element))throw new TypeError("source must be an element");this.#e=n}get[Symbol.toStringTag](){return"InterestEvent"}get source(){const e=this.#e;if(!e)return null;const t=S(e);return t!==S(this.target||document)?t.host:e}});const E="none",v="full",T="explicit",L="hover",A="dehover",x="focus",k="blur";function S(e){return e&&"function"==typeof e.getRootNode?e.getRootNode():e&&e.parentNode?S(e.parentNode):e}function N(e,r,o,s={}){if(!e||!r)return!1;if(!e.isConnected||I(e)!==r||o===E&&F(r)!==e)return!1;if(o!==E){q(e),e[c].state!==E&&e[c].target!==r&&H(e);const n=F(r);if(n){if(n===e)return o===T&&(n[c].state=T),n[c].clearLostTask(),!1;if(!N(n,r,E))return!1;if(!e.isConnected||I(e)!==r)return!1}return function(e,n,r){const o=e[c];switch(r){case v:case T:if(o.state!==E)throw new Error("Invalid state");if(!n.dispatchEvent(new InterestEvent(t,{source:e,cancelable:!0})))return!1;if(o.state=r,o.target=n,o.clearGainedTask(),n[u]||(n[u]={}),n[u].invoker=e,n.hasAttribute("popover")&&(n.addEventListener("beforetoggle",M),n[u].shownByInterest=!1,!$(n))){try{n.showPopover({source:e})}catch{}n[u].shownByInterest=$(n)}if(h.add(e),e.classList.add("interest-source"),n.classList.add("interest-target"),G(n)||e.setAttribute("aria-expanded","true"),"none"===getComputedStyle(e).anchorName&&"auto"===getComputedStyle(n).positionAnchor){const t=`--interest-anchor-${Math.random().toString(36).substring(2)}`;e.style.anchorName=t,n.style.positionAnchor=t,o.anchorName=t}break;default:throw new Error("Invalid state")}return!0}(e,r,o)}return function(e,{force:t=!1,closePopovers:r=!0}={}){const o=e[c];if(clearTimeout(o.gainedTimer),clearTimeout(o.lostTimer),o.state===E)return!0;const s=o.target,i=s.dispatchEvent(new InterestEvent(n,{source:e,cancelable:!t}));if(!i)return!1;const a=s[u],l=r&&a?.invoker===e&&a.shownByInterest;H(e),l&&$(s)&&function(e,t){const n=e[c],r=t.contains(document.activeElement);r&&(n.suppressNextFocusInterest=!0);try{t.hidePopover()}catch{}r&&(n.suppressNextFocusInterest=!1)}(e,s);return!0}(e,s)}function P(e){const t=1e3*V(e,o);if(!_(t))return;const n=e[c];n.clearLostTask();const r=n.target;n.lostTimer=setTimeout(()=>{N(e,r,E)},t)}function F(e){const t=e[u]?.invoker||null;if(!t)return null;const n=t[c];return n&&n.state!==E&&n.target===e&&I(t)===e?t:null}function I(t){if(!t.hasAttribute(e)||!t.isConnected||!function(e){if(e instanceof HTMLButtonElement)return!e.matches(":disabled");if(e instanceof HTMLAnchorElement||e instanceof HTMLAreaElement)return e.hasAttribute("href");if(window.SVGAElement&&e instanceof SVGAElement)return e.hasAttribute("href")||e.hasAttributeNS(p,"href");return!1}(t))return null;const n=C(t);return n&&n.isConnected?n:null}function C(t){const n=t.getAttribute(e);if(null===n)return null;const r=t[m];if(r&&""===n)return function(e,t){const n=S(e);let r=S(t);for(;r;){if(r===n)return!0;r=r instanceof ShadowRoot?S(r.host):null}return!1}(r,t)?r:null;if(""===n)return null;const o=S(t);return"function"==typeof o.getElementById?o.getElementById(n):null}function $(e){try{return e.matches(":popover-open")}catch{return!1}}function M(e){if("closed"!==e.newState)return;const t=e.currentTarget,n=F(t);if(n){if(t.contains(document.activeElement)){const e=n[c];e.suppressNextFocusInterest=!0,setTimeout(()=>{e.suppressNextFocusInterest=!1},0)}N(n,t,E,{closePopovers:!1})}}function _(e){return e>=0&&e<=2147483647}function B(e){const t=String(e).trim(),n=t.match(/^([\d.]+(?:e[+-]?\d+)?)s$/i);if(n)return parseFloat(n[1]);const r=t.match(/^([\d.]+(?:e[+-]?\d+)?)ms$/i);return r?parseFloat(r[1])/1e3:/\b(infinity|nan)\b/i.test(t)?1/0:parseFloat(t)||0}function V(e,t){const n=getComputedStyle(e),o=n.getPropertyValue(t).trim();if("normal"!==o.toLowerCase())return B(o);const i=n.getPropertyValue(s).trim();if(i&&"normal"!==i.toLowerCase()){const e=i.split(/\s+/).filter(e=>e.length>0);if(e.length>0){const n=e[0],o=e.length>1?e[1]:n;let s;if(s=t===r?n:o,"normal"!==s.toLowerCase())return B(s)}}return t===r?.25:.15}function H(e){const t=e[c];if(!t)return;if(clearTimeout(t.gainedTimer),clearTimeout(t.lostTimer),t.state===E)return;const n=t.target;h.delete(e),e.classList.remove("interest-source"),n&&(n[u]?.invoker===e&&(n.removeEventListener("beforetoggle",M),n[u]=null,n.classList.remove("interest-target")),G(n)||e.setAttribute("aria-expanded","false")),t.anchorName&&(e.style.anchorName="",n&&(n.style.positionAnchor=""),t.anchorName=null),t.state=E,t.target=null}const O=["a[href]","area[href]","input:not([disabled])","select:not([disabled])","textarea:not([disabled])","button:not([disabled])","iframe","object","embed","[contenteditable]",'[tabindex]:not([tabindex="-1"])'].join(",");function G(e){if("hint"!==e.getAttribute("popover")?.toLowerCase())return!1;if(e.querySelector(O))return!1;if(e.querySelector("h1,h2,h3,h4,h5,h6,ul,ol,li,table,nav,header,footer,main,aside,article,section,form,blockquote,details,summary,dialog"))return!1;const t=e.querySelectorAll("[role]");for(const e of t){const t=e.getAttribute("role").toLowerCase();if(!["presentation","none","generic","image"].includes(t))return!1}return!0}function q(e){if(e[c])return;e[c]={state:E,target:null,gainedTimer:null,lostTimer:null,longPressTimer:null,suppressNextFocusInterest:!1,clearGainedTask(){clearTimeout(this.gainedTimer)},clearLostTask(){clearTimeout(this.lostTimer)}};const t=I(e);t&&function(e,t){G(t)?e.setAttribute("aria-describedby",t.id):(e.setAttribute("aria-details",t.id),e.setAttribute("aria-expanded","false"),t.hasAttribute("role")||t.setAttribute("role","tooltip"))}(e,t)}function D(e){if(e[f])return e[f];if(e.assignedSlot)return e.assignedSlot;if(e.parentElement)return e.parentElement;const t=e.parentNode;return t instanceof ShadowRoot?t.host:null}function z(e){const t=new Set;if(0===h.size)return t;const n=e=>{const r=F(e);r&&!t.has(r)&&(t.add(r),n(r));const o=D(e);o&&!t.has(o)&&n(o)};return n(e),t}function j(e,t){if(g)return;if(!e.isConnected)return;const n=I(e);n&&q(e);const o=e[c];if(t===L||t===x){let s=!1;o&&(o.clearLostTask(),s=t===x&&o.suppressNextFocusInterest,o.suppressNextFocusInterest=!1);for(const t of z(e))t[c].clearLostTask();n&&!s&&o.state===E&&function(e,t){const n=I(e);if(!n)return;const o=1e3*V(e,r);_(o)&&(e[c].clearGainedTask(),e[c].gainedTimer=setTimeout(()=>{N(e,n,t)},o))}(e,v)}else if(o&&(o.clearGainedTask(),o.state===v&&P(e)),t===k||!e.matches(":hover"))for(const t of z(e))P(t)}function R(e){return e instanceof HTMLElement&&"area"!==e.localName&&!!e.parentNode&&!!I(e)}function U(e){const t=getComputedStyle(e).getPropertyValue(i).trim();return t&&"none"!==t&&"normal"!==t?t:null}function J(){const e=this[f];e&&N(e,I(e),T)}function K(e,t){let n=e[d];t?(n||(n=e.ownerDocument.createElement("span"),n.className=l,n.setAttribute("aria-hidden","true"),n[f]=e,n.addEventListener("click",J),e[d]=n,b.add(e)),n.style.getPropertyValue(a)!==t&&n.style.setProperty(a,t),e.nextSibling!==n&&e.after(n)):n&&(n.remove(),e[d]=null,b.delete(e))}function Q(t){const n=[];for(const r of t){let t=null;r.isConnected&&r.hasAttribute(e)?R(r)?(y.delete(r),t=U(r)):y.add(r):y.delete(r),n.push([r,t])}for(const[e,t]of n)K(e,t)}function W(t){const n=new Set;let r=!1;const o=t=>{if(t.nodeType===Node.ELEMENT_NODE&&!t[f]){t.hasAttribute(e)&&n.add(t);for(const r of t.querySelectorAll(`[${e}]`))n.add(r)}};for(const s of t){if("childList"===s.type){for(const e of s.addedNodes)e.nodeType!==Node.ELEMENT_NODE||e[f]||(r=!0,o(e));continue}const t=s.target;switch(s.attributeName){case e:null!==s.oldValue&&H(t),""!==t.getAttribute(e)&&(t[m]=null),n.add(t);break;case"id":r=!0;break;default:o(t)}}for(const e of[...h]){const t=e[c].target;e.isConnected&&t&&t.isConnected||H(e)}if(r)for(const e of y)n.add(e);for(const e of[...b])n.has(e)||(R(e)?e.nextSibling!==e[d]&&e.after(e[d]):K(e,null));Q(n)}function X(){!function(){const t=document.createElement("style");t.textContent=`@property ${r} {syntax: "normal | <time>"; inherits: false; initial-value: normal;}\n @property ${o} {syntax: "normal | <time>"; inherits: false; initial-value: normal;}\n @property ${s} {syntax: "[ normal | <time> ]{1,2}"; inherits: false; initial-value: normal;}\n @property ${i} {syntax: "*"; inherits: false;}`,document.head.appendChild(t);const n=`span.${l}[aria-hidden]`,u=document.createElement("style");u.textContent=`:where(button[${e}]) {\n -webkit-user-select: none;\n user-select: none;\n }\n :where(${n}) {\n display: inline-block;\n vertical-align: middle;\n color: inherit;\n background-color: transparent;\n box-sizing: border-box;\n min-inline-size: 24px;\n min-block-size: 24px;\n min-block-size: max(24px, 1lh);\n align-content: center;\n text-align: center;\n -webkit-user-select: none;\n user-select: none;\n cursor: help;\n }\n :where(${n}:hover) {\n background-color: color-mix(in oklab, currentColor 10%, transparent);\n }\n :where(${n}:active) {\n background-color: color-mix(in oklab, currentColor 20%, transparent);\n }\n :where(${n})::before {\n content: var(${a});\n }`,document.head.prepend(u),document[c]={globalPropsStyle:t,uaStyle:u}}(),function(){const e=(e,t)=>{const n=e.composedPath(),r=n.length?n[0]:e.target;if(r instanceof Element)for(let e=r;e;e=D(e))j(e,t)};document.body.addEventListener("mouseover",t=>e(t,L)),document.body.addEventListener("mouseout",t=>e(t,A)),document.body.addEventListener("focusin",t=>e(t,x)),document.body.addEventListener("focusout",t=>e(t,k)),document.body.addEventListener("keydown",e=>{"Escape"!==e.key||e.defaultPrevented||[...h].reverse().forEach(e=>{N(e,e[c].target,E,{force:!0})})}),document.body.addEventListener("touchstart",e=>{g=!0;const t=e.target.closest("button[interestfor]");t&&(q(t),t[c].longPressTimer=setTimeout(()=>{t[c].state===E&&N(t,I(t),T),t[c].longPressTimer=null},500))});const t=e=>{const t=e.target.closest("button[interestfor]");t&&t[c]?.longPressTimer&&(clearTimeout(t[c].longPressTimer),t[c].longPressTimer=null)};document.body.addEventListener("touchend",e=>{t(e),g=!1}),document.body.addEventListener("touchmove",t)}(),new MutationObserver(W).observe(document,{childList:!0,subtree:!0,attributes:!0,attributeOldValue:!0,attributeFilter:[e,"id","href","disabled"]}),Q(document.querySelectorAll(`[${e}]`)),console.log(`interestfor polyfill installed (native: ${w}).`)}!function(){const t={configurable:!0,enumerable:!0,get(){return C(this)},set(t){if(null==t)this[m]=null,this.removeAttribute(e);else{if(!(t instanceof Element))throw new TypeError("Failed to set the 'interestForElement' property: The provided value is not of type 'Element'.");this[m]=t,this.setAttribute(e,"")}}};[window.HTMLButtonElement,window.HTMLAnchorElement,window.HTMLAreaElement,window.SVGAElement].forEach(e=>{e&&!Object.prototype.hasOwnProperty.call(e.prototype,"interestForElement")&&Object.defineProperty(e.prototype,"interestForElement",t)})}(),"complete"===document.readyState?X():window.addEventListener("load",X)}();
|
|
8
|
+
!function(){const e="interestfor",t="interest",n="loseinterest",r="--interest-delay-start",o="--interest-delay-end",s="--interest-delay",i="--interest-button-content",a="--interest-button-polyfill-content",l="interest-button",c="__interestForData",u="__interestForTargetData",d="__interestForButton",f="__interestForButtonInvoker",m="__interestForExplicitTarget",p="http://www.w3.org/1999/xlink",h=new Set,b=new Set,g=new Set;let y=!1;if(window.interestForPolyfillInstalled)return;window.interestForPolyfillInstalled=!0;const E=HTMLButtonElement.prototype.hasOwnProperty("interestForElement");if(E&&!window.interestForUsePolyfillAlways)return;if(E){const e=e=>{e.isTrusted&&(e.preventDefault(),e.stopImmediatePropagation())};document.body.addEventListener(t,e,{capture:!0}),document.body.addEventListener(n,e,{capture:!0})}window.InterestEvent&&!window.interestForUsePolyfillAlways||(window.InterestEvent=class extends Event{#e;constructor(e,t={}){super(e,t);const{source:n}=t;if(null!=n&&!(n instanceof Element))throw new TypeError("source must be an element");this.#e=n}get[Symbol.toStringTag](){return"InterestEvent"}get source(){const e=this.#e;if(!e)return null;const t=P(e);return t!==P(this.target||document)?t.host:e}});const w="none",v="full",T="explicit",A="hover",L="dehover",N="focus",x="blur";function P(e){return e&&"function"==typeof e.getRootNode?e.getRootNode():e&&e.parentNode?P(e.parentNode):e}function k(e,r,o,s={}){if(!e||!r)return!1;if(!e.isConnected||I(e)!==r||o===w&&F(r)!==e)return!1;if(o!==w){z(e),e[c].state!==w&&e[c].target!==r&&D(e);const n=F(r);if(n){if(n===e)return o===T&&(n[c].state=T),n[c].clearLostTask(),!1;if(!k(n,r,w))return!1;if(!e.isConnected||I(e)!==r)return!1}return function(e,n,r){const o=e[c];switch(r){case v:case T:if(o.state!==w)throw new Error("Invalid state");if(!n.dispatchEvent(new InterestEvent(t,{source:e,cancelable:!0})))return!1;if(o.state=r,o.target=n,o.clearGainedTask(),n[u]||(n[u]={}),n[u].invoker=e,n.hasAttribute("popover")&&(n.addEventListener("beforetoggle",_),n[u].shownByInterest=!1,!$(n))){try{n.showPopover({source:e})}catch{}n[u].shownByInterest=$(n)}if(h.add(e),e.classList.add("interest-source"),n.classList.add("interest-target"),H(n)||e.setAttribute("aria-expanded","true"),"none"===getComputedStyle(e).anchorName&&"auto"===getComputedStyle(n).positionAnchor){const t=`--interest-anchor-${Math.random().toString(36).substring(2)}`;e.style.anchorName=t,n.style.positionAnchor=t,o.anchorName=t}break;default:throw new Error("Invalid state")}return!0}(e,r,o)}return function(e,{force:t=!1,closePopovers:r=!0}={}){const o=e[c];if(clearTimeout(o.gainedTimer),clearTimeout(o.lostTimer),o.state===w)return!0;const s=o.target,i=s.dispatchEvent(new InterestEvent(n,{source:e,cancelable:!t}));if(!i)return!1;const a=s[u],l=r&&a?.invoker===e&&a.shownByInterest;D(e),l&&$(s)&&function(e,t){const n=e[c],r=t.contains(document.activeElement);r&&(n.suppressNextFocusInterest=!0);try{t.hidePopover()}catch{}r&&(n.suppressNextFocusInterest=!1)}(e,s);return!0}(e,s)}function S(e){const t=1e3*O(e,o);if(!M(t))return;const n=e[c];n.clearLostTask();const r=n.target;n.lostTimer=setTimeout(()=>{k(e,r,w)},t)}function F(e){const t=e[u]?.invoker||null;if(!t)return null;const n=t[c];return n&&n.state!==w&&n.target===e&&I(t)===e?t:null}function I(t){if(!t.hasAttribute(e)||!t.isConnected||!function(e){if(e instanceof HTMLButtonElement)return!e.matches(":disabled");if(e instanceof HTMLAnchorElement||e instanceof HTMLAreaElement)return e.hasAttribute("href");if(window.SVGAElement&&e instanceof SVGAElement)return e.hasAttribute("href")||e.hasAttributeNS(p,"href");return!1}(t))return null;const n=C(t);return n&&n.isConnected?n:null}function C(t){const n=t.getAttribute(e);if(null===n)return null;const r=t[m];if(r&&""===n)return function(e,t){const n=P(e);let r=P(t);for(;r;){if(r===n)return!0;r=r instanceof ShadowRoot?P(r.host):null}return!1}(r,t)?r:null;if(""===n)return null;const o=P(t);return"function"==typeof o.getElementById?o.getElementById(n):null}function $(e){try{return e.matches(":popover-open")}catch{return!1}}function _(e){if("closed"!==e.newState)return;const t=e.currentTarget,n=F(t);if(n){if(t.contains(document.activeElement)){const e=n[c];e.suppressNextFocusInterest=!0,setTimeout(()=>{e.suppressNextFocusInterest=!1},0)}k(n,t,w,{closePopovers:!1})}}function M(e){return e>=0&&e<=2147483647}function B(e){const t=String(e).trim(),n=t.match(/^([\d.]+(?:e[+-]?\d+)?)s$/i);if(n)return parseFloat(n[1]);const r=t.match(/^([\d.]+(?:e[+-]?\d+)?)ms$/i);return r?parseFloat(r[1])/1e3:/\b(infinity|nan)\b/i.test(t)?1/0:parseFloat(t)||0}function O(e,t){const n=getComputedStyle(e),o=n.getPropertyValue(t).trim();if("normal"!==o.toLowerCase())return B(o);const i=n.getPropertyValue(s).trim();if(i&&"normal"!==i.toLowerCase()){const e=i.split(/\s+/).filter(e=>e.length>0);if(e.length>0){const n=e[0],o=e.length>1?e[1]:n;let s;if(s=t===r?n:o,"normal"!==s.toLowerCase())return B(s)}}return t===r?.25:.15}function D(e){const t=e[c];if(!t)return;if(clearTimeout(t.gainedTimer),clearTimeout(t.lostTimer),t.state===w)return;const n=t.target;h.delete(e),e.classList.remove("interest-source"),n&&(n[u]?.invoker===e&&(n.removeEventListener("beforetoggle",_),n[u]=null,n.classList.remove("interest-target")),H(n)||e.setAttribute("aria-expanded","false")),t.anchorName&&(e.style.anchorName="",n&&(n.style.positionAnchor=""),t.anchorName=null),t.state=w,t.target=null}const V=["a[href]","area[href]","input:not([disabled])","select:not([disabled])","textarea:not([disabled])","button:not([disabled])","iframe","object","embed","[contenteditable]",'[tabindex]:not([tabindex="-1"])'].join(",");function H(e){if("hint"!==e.getAttribute("popover")?.toLowerCase())return!1;if(e.querySelector(V))return!1;if(e.querySelector("h1,h2,h3,h4,h5,h6,ul,ol,li,table,nav,header,footer,main,aside,article,section,form,blockquote,details,summary,dialog"))return!1;const t=e.querySelectorAll("[role]");for(const e of t){const t=e.getAttribute("role").toLowerCase();if(!["presentation","none","generic","image"].includes(t))return!1}return!0}function G(e){return e?e.replace(/\s+/g," ").trim():""}function j(e,t=!1){if(e.nodeType===Node.TEXT_NODE)return e.data;if(e.nodeType!==Node.ELEMENT_NODE)return"";if(!t&&(e.hasAttribute("hidden")||"true"===e.getAttribute("aria-hidden")||"script"===e.localName||"style"===e.localName))return"";const n=e.getAttribute("aria-label");if(n)return n;if("img"===e.localName||"area"===e.localName)return e.getAttribute("alt")||"";let r="";for(const t of e.childNodes)r+=j(t);return r}function q(e,t){if(t.id)if(H(t)){if((e.getAttribute("aria-labelledby")||"").trim().split(/\s+/).includes(t.id))return;const n=function(e){const t=e.getAttribute("aria-labelledby");if(t){const n=P(e);if("function"==typeof n.getElementById){const e=[];for(const r of t.trim().split(/\s+/)){const t=r?n.getElementById(r):null;t&&e.push(G(j(t,!0)))}const r=G(e.join(" "));if(r)return r}}const n=G(e.getAttribute("aria-label"));if(n)return n;if(e.labels?.length){const t=G([...e.labels].map(e=>j(e,!0)).join(" "));if(t)return t}return G(j(e,!0))||G(e.getAttribute("title"))}(e),r=G(j(t,!0));n?r&&r!==n&&!e.hasAttribute("aria-describedby")&&e.setAttribute("aria-describedby",t.id):r&&e.setAttribute("aria-labelledby",t.id)}else e.hasAttribute("aria-details")||e.setAttribute("aria-details",t.id),e.setAttribute("aria-expanded","false"),t.hasAttribute("role")||t.setAttribute("role","tooltip")}function z(e){e[c]||(e[c]={state:w,target:null,a11yTarget:null,gainedTimer:null,lostTimer:null,longPressTimer:null,suppressNextFocusInterest:!1,clearGainedTask(){clearTimeout(this.gainedTimer)},clearLostTask(){clearTimeout(this.lostTimer)}});const t=I(e);t&&e[c].a11yTarget!==t&&(e[c].a11yTarget=t,q(e,t))}function R(e){if(e[f])return e[f];if(e.assignedSlot)return e.assignedSlot;if(e.parentElement)return e.parentElement;const t=e.parentNode;return t instanceof ShadowRoot?t.host:null}function U(e){const t=new Set;if(0===h.size)return t;const n=e=>{const r=F(e);r&&!t.has(r)&&(t.add(r),n(r));const o=R(e);o&&!t.has(o)&&n(o)};return n(e),t}function X(e,t){if(y)return;if(!e.isConnected)return;const n=I(e);n&&z(e);const o=e[c];if(t===A||t===N){let s=!1;o&&(o.clearLostTask(),s=t===N&&o.suppressNextFocusInterest,o.suppressNextFocusInterest=!1);for(const t of U(e))t[c].clearLostTask();n&&!s&&o.state===w&&function(e,t){const n=I(e);if(!n)return;const o=1e3*O(e,r);M(o)&&(e[c].clearGainedTask(),e[c].gainedTimer=setTimeout(()=>{k(e,n,t)},o))}(e,v)}else if(o&&(o.clearGainedTask(),o.state===v&&S(e)),t===x||!e.matches(":hover"))for(const t of U(e))S(t)}function J(e){return e instanceof HTMLElement&&"area"!==e.localName&&!!e.parentNode&&!!I(e)}function K(e){const t=getComputedStyle(e).getPropertyValue(i).trim();return t&&"none"!==t&&"normal"!==t?t:null}function Q(){const e=this[f];e&&k(e,I(e),T)}function W(e,t){let n=e[d];t?(n||(n=e.ownerDocument.createElement("span"),n.className=l,n.setAttribute("aria-hidden","true"),n[f]=e,n.addEventListener("click",Q),e[d]=n,b.add(e)),n.style.getPropertyValue(a)!==t&&n.style.setProperty(a,t),e.nextSibling!==n&&e.after(n)):n&&(n.remove(),e[d]=null,b.delete(e))}function Y(t){const n=[];for(const r of t){let t=null;const o=I(r);o?(g.delete(r),J(r)&&(t=K(r))):r.isConnected&&r.hasAttribute(e)?g.add(r):g.delete(r),n.push([r,o,t])}for(const[e,t,r]of n)t&&z(e),W(e,r)}function Z(t){const n=new Set;let r=!1;const o=t=>{if(t.nodeType===Node.ELEMENT_NODE&&!t[f]){t.hasAttribute(e)&&n.add(t);for(const r of t.querySelectorAll(`[${e}]`))n.add(r)}};for(const s of t){if("childList"===s.type){for(const e of s.addedNodes)e.nodeType!==Node.ELEMENT_NODE||e[f]||(r=!0,o(e));continue}const t=s.target;switch(s.attributeName){case e:null!==s.oldValue&&D(t),""!==t.getAttribute(e)&&(t[m]=null),n.add(t);break;case"id":r=!0;break;default:o(t)}}for(const e of[...h]){const t=e[c].target;e.isConnected&&t&&t.isConnected||D(e)}if(r)for(const e of g)n.add(e);for(const e of[...b])n.has(e)||(J(e)?e.nextSibling!==e[d]&&e.after(e[d]):W(e,null));Y(n)}function ee(){!function(){const t=document.createElement("style");t.textContent=`@property ${r} {syntax: "normal | <time>"; inherits: false; initial-value: normal;}\n @property ${o} {syntax: "normal | <time>"; inherits: false; initial-value: normal;}\n @property ${s} {syntax: "*"; inherits: false;}\n @property ${i} {syntax: "*"; inherits: false;}`,document.head.appendChild(t);const n=`span.${l}[aria-hidden]`,u=document.createElement("style");u.textContent=`:where(button[${e}]) {\n -webkit-user-select: none;\n user-select: none;\n }\n :where(${n}) {\n display: inline-block;\n vertical-align: middle;\n color: inherit;\n background-color: transparent;\n box-sizing: border-box;\n min-inline-size: 24px;\n min-block-size: 24px;\n min-block-size: max(24px, 1lh);\n align-content: center;\n text-align: center;\n -webkit-user-select: none;\n user-select: none;\n cursor: help;\n }\n :where(${n}:hover) {\n background-color: color-mix(in oklab, currentColor 10%, transparent);\n }\n :where(${n}:active) {\n background-color: color-mix(in oklab, currentColor 20%, transparent);\n }\n :where(${n})::before {\n content: var(${a});\n }`,document.head.prepend(u),document[c]={globalPropsStyle:t,uaStyle:u}}(),function(){const e=(e,t)=>{const n=e.composedPath(),r=n.length?n[0]:e.target;if(r instanceof Element)for(let e=r;e;e=R(e))X(e,t)},t=e=>{"touch"!==e.pointerType&&(y=!1)};document.body.addEventListener("pointerover",t),document.body.addEventListener("pointerdown",t),document.body.addEventListener("mouseover",t=>e(t,A)),document.body.addEventListener("mouseout",t=>e(t,L)),document.body.addEventListener("focusin",t=>e(t,N)),document.body.addEventListener("focusout",t=>e(t,x)),document.body.addEventListener("keydown",e=>{y=!1,"Escape"!==e.key||e.defaultPrevented||[...h].reverse().forEach(e=>{k(e,e[c].target,w,{force:!0})})});const n=/iPad|iPhone|iPod/.test(navigator.userAgent);document.body.addEventListener("touchstart",e=>{y=!0;const t=e.target.closest("button[interestfor]");t&&(z(t),t[c].longPressActive=!1,t[c].longPressTimer=setTimeout(()=>{t[c].state===w&&(n?t[c].longPressActive=!0:k(t,I(t),T)),t[c].longPressTimer=null},500))});const r=e=>{const t=e.target.closest("button[interestfor]");t&&t[c]&&(clearTimeout(t[c].longPressTimer),t[c].longPressTimer=null,t[c].longPressActive=!1)};document.body.addEventListener("touchmove",r),document.body.addEventListener("touchend",e=>{const t=e.target.closest("button[interestfor]"),n=t?.[c]?.longPressActive;r(e),n&&(e.cancelable&&e.preventDefault(),t[c].state===w&&k(t,I(t),T))},{passive:!1})}(),new MutationObserver(Z).observe(document,{childList:!0,subtree:!0,attributes:!0,attributeOldValue:!0,attributeFilter:[e,"id","href","disabled"]}),Y(document.querySelectorAll(`[${e}]`)),console.log(`interestfor polyfill installed (native: ${E}).`)}!function(){const t={configurable:!0,enumerable:!0,get(){return C(this)},set(t){if(null==t)this[m]=null,this.removeAttribute(e);else{if(!(t instanceof Element))throw new TypeError("Failed to set the 'interestForElement' property: The provided value is not of type 'Element'.");this[m]=t,this.setAttribute(e,"")}}};[window.HTMLButtonElement,window.HTMLAnchorElement,window.HTMLAreaElement,window.SVGAElement].forEach(e=>{!e||Object.prototype.hasOwnProperty.call(e.prototype,"interestForElement")&&!window.interestForUsePolyfillAlways||Object.defineProperty(e.prototype,"interestForElement",t)})}(),"complete"===document.readyState?ee():window.addEventListener("load",ee)}();
|
package/test/basic_test.html
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
+
<meta charset="utf-8">
|
|
3
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.4">
|
|
2
4
|
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
</p>
|
|
12
|
-
<div popover id=bar>Popover shown by the interest button</div>
|
|
5
|
+
<div>
|
|
6
|
+
<a interestfor=foo href=bar>Link - hover me</a>
|
|
7
|
+
</div>
|
|
8
|
+
<div>
|
|
9
|
+
<button interestfor=foo commandfor=bar command=toggle-popover>Button - hover me</button>
|
|
10
|
+
</div>
|
|
11
|
+
<div popover id=foo>Hovercard</div>
|
|
12
|
+
<div popover id=bar>Button action</div>
|
|
13
13
|
|
|
14
14
|
<style>
|
|
15
|
+
body {
|
|
16
|
+
padding: 20px 0 0 20px;
|
|
17
|
+
}
|
|
15
18
|
[interestfor] {
|
|
16
|
-
interest-delay: 600ms
|
|
17
|
-
|
|
19
|
+
--interest-delay: 600ms 500ms;
|
|
20
|
+
interest-delay: var(--interest-delay);
|
|
18
21
|
}
|
|
19
22
|
:is([interestfor]:interest-source),
|
|
20
23
|
[interestfor].interest-source {
|
|
@@ -26,13 +29,53 @@
|
|
|
26
29
|
}
|
|
27
30
|
[popover] {
|
|
28
31
|
position-area: right center;
|
|
32
|
+
margin-left:30px;
|
|
29
33
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
#bar {
|
|
35
|
+
position-area: bottom center;
|
|
36
|
+
margin: 10px 0 0 0;
|
|
33
37
|
}
|
|
38
|
+
div { margin: 10px; padding: 7.5px 0; }
|
|
34
39
|
/* Polyfilled ::interest-button */
|
|
35
|
-
|
|
36
|
-
--interest-button-content: "
|
|
40
|
+
[interestfor] {
|
|
41
|
+
--interest-button-content: "\24D8";
|
|
42
|
+
}
|
|
43
|
+
/* Native ::interest-button */
|
|
44
|
+
[interestfor]::interest-button {
|
|
45
|
+
content: var(--interest-button-content);
|
|
37
46
|
}
|
|
38
47
|
</style>
|
|
48
|
+
|
|
49
|
+
<div>
|
|
50
|
+
<label>Mode:
|
|
51
|
+
<select id="mode">
|
|
52
|
+
<option value="polyfill">Use polyfill</option>
|
|
53
|
+
<option value="native">Native</option>
|
|
54
|
+
</select>
|
|
55
|
+
</label>
|
|
56
|
+
</div>
|
|
57
|
+
<div id="nav_msg"></div>
|
|
58
|
+
<script>
|
|
59
|
+
let navTimer;
|
|
60
|
+
document.querySelector("a[interestfor]").addEventListener("click", (e) => {
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
const msg = document.getElementById("nav_msg");
|
|
63
|
+
msg.textContent = "would have navigated";
|
|
64
|
+
clearTimeout(navTimer);
|
|
65
|
+
navTimer = setTimeout(() => {
|
|
66
|
+
msg.textContent = "";
|
|
67
|
+
}, 1000);
|
|
68
|
+
});
|
|
69
|
+
const mode = new URLSearchParams(location.search).get("mode") || "polyfill";
|
|
70
|
+
const select = document.getElementById("mode");
|
|
71
|
+
select.value = mode;
|
|
72
|
+
select.addEventListener("change", () => {
|
|
73
|
+
location.search = `?mode=${select.value}`;
|
|
74
|
+
});
|
|
75
|
+
if (mode === "polyfill") {
|
|
76
|
+
window.interestForUsePolyfillAlways = true;
|
|
77
|
+
const s = document.createElement("script");
|
|
78
|
+
s.src = `../src/interestfor.js?v=${Date.now()}`;
|
|
79
|
+
document.head.appendChild(s);
|
|
80
|
+
}
|
|
81
|
+
</script>
|