fck-honey 0.3.6 → 0.3.7

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 CHANGED
@@ -3,19 +3,26 @@ Open source lib for Merchants to detect if a customer has Honey browser extensio
3
3
 
4
4
  <img width="1307" height="561" alt="image" src="https://github.com/user-attachments/assets/33b2554b-fc90-4b4b-b917-4ed088664200" />
5
5
 
6
- ## Usage (Browser Global)
6
+ ## Easy install (no-JS)
7
+ This will automatically listen for Honey and show a default warning to the user to disable the extension as shown above). Install this at the very top of the `<head>` in your webpage to ensure it runs prior to Honey.
8
+ ```html
9
+ <script src="https://cdn.jsdelivr.net/npm/fck-honey@latest/dist/auto.min.js"></script>
10
+ ```
11
+
12
+ ## Custom Usage (Browser Global)
7
13
 
8
14
  ```html
9
15
  <script src="https://cdn.jsdelivr.net/npm/fck-honey@latest/dist/honey-detect.min.js"></script>
10
16
  <script>
11
- window.fckHoney.listen((warn) => {
17
+ window.fckHoney.listen((warn, el, vendor) => {
12
18
  // Decide how you want to handle this. Native warn function allows you to tell the user to disable Honey.
19
+ // vendor is "honey" or "Capital One Shopping"
13
20
  warn("You must disable the Honey extension to continue.");
14
21
  });
15
22
  </script>
16
23
  ```
17
24
 
18
- ## Usage (ESM)
25
+ ## Custom Usage (ESM)
19
26
 
20
27
  ```sh
21
28
  npm install fck-honey
@@ -24,8 +31,9 @@ npm install fck-honey
24
31
  ```js
25
32
  import { listen } from "fck-honey";
26
33
 
27
- listen((warn) => {
34
+ listen((warn, el, vendor) => {
28
35
  // Decide how you want to handle this. Native warn function allows you to tell the user to disable Honey.
36
+ // vendor is "honey" or "Capital One Shopping"
29
37
  warn("You must disable the Honey extension to continue.");
30
38
  });
31
39
  ```
@@ -33,9 +41,10 @@ listen((warn) => {
33
41
  ## Advanced Options
34
42
 
35
43
  ```js
36
- window.fckHoney.listen((warn, el) => {
44
+ window.fckHoney.listen((warn, el, vendor) => {
37
45
  // removeHoney defaults to true (element is auto-removed).
38
46
  // Set removeHoney to false if you want to keep the Honey element for some reason.
47
+ // vendor is "honey" or "Capital One Shopping"
39
48
  }, { removeHoney: false });
40
49
  ```
41
50
 
package/dist/auto.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function() {
2
2
  // dist/bundle-tmp/version.js
3
- var VERSION = "0.3.6";
3
+ var VERSION = "0.3.7";
4
4
 
5
5
  // dist/bundle-tmp/core.js
6
6
  var __assign = function() {
@@ -17,7 +17,7 @@
17
17
  var version = VERSION;
18
18
  var DEFAULT_Z_NEAR_MAX = 214748e4;
19
19
  var UUIDISH_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
20
- var TARGET_SELECTOR = "div[id]";
20
+ var TARGET_SELECTOR = "div";
21
21
  var OVERLAY_STYLE_ID = "simple-overlay-styles";
22
22
  function showOverlay(message) {
23
23
  if (typeof document === "undefined")
@@ -54,17 +54,21 @@
54
54
  var inline = parseInt(el.style.zIndex, 10);
55
55
  return isFinite(inline) ? inline : null;
56
56
  }
57
- function looksLikeTargetDiv(el, zNearMax, uuidGate, debug) {
58
- if (!el.id) {
59
- if (debug)
60
- console.log("+++ reject: no id", el);
61
- return false;
62
- }
63
- if (uuidGate && !UUIDISH_RE.test(el.id)) {
64
- if (debug)
65
- console.log("+++ reject: uuid", el.id);
66
- return false;
57
+ function getDataGuidAttribute(el) {
58
+ for (var i = 0; i < el.attributes.length; i += 1) {
59
+ var attr = el.attributes[i];
60
+ if (!attr)
61
+ continue;
62
+ if (attr.name.indexOf("data-") === 0) {
63
+ var suffix = attr.name.slice(5);
64
+ if (UUIDISH_RE.test(suffix) && attr.value === "true") {
65
+ return attr.name;
66
+ }
67
+ }
67
68
  }
69
+ return null;
70
+ }
71
+ function hasNearMaxZIndex(el, zNearMax, debug) {
68
72
  var inlineZ = parseInt(el.style.zIndex, 10);
69
73
  if (!isFinite(inlineZ) || inlineZ < zNearMax) {
70
74
  var cs_1 = getComputedStyle(el);
@@ -84,8 +88,6 @@
84
88
  console.log("+++ reject: shadowRoot", el);
85
89
  return false;
86
90
  }
87
- if (debug)
88
- console.log("+++ match", el);
89
91
  return true;
90
92
  }
91
93
  var cs = getComputedStyle(el);
@@ -105,16 +107,62 @@
105
107
  console.log("+++ reject: shadowRoot", el);
106
108
  return false;
107
109
  }
108
- if (debug)
109
- console.log("+++ match", el);
110
110
  return true;
111
111
  }
112
+ var VENDOR_MATCHERS = [
113
+ {
114
+ name: "honey",
115
+ matches: function(el, uuidGate, debug) {
116
+ if (!el.id) {
117
+ if (debug)
118
+ console.log("+++ reject: no id", el);
119
+ return false;
120
+ }
121
+ if (uuidGate && !UUIDISH_RE.test(el.id)) {
122
+ if (debug)
123
+ console.log("+++ reject: uuid", el.id);
124
+ return false;
125
+ }
126
+ return true;
127
+ }
128
+ },
129
+ {
130
+ name: "Capital One Shopping",
131
+ matches: function(el, _uuidGate, debug) {
132
+ var dataGuid = getDataGuidAttribute(el);
133
+ if (!dataGuid) {
134
+ if (debug)
135
+ console.log("+++ reject: no data guid", el);
136
+ return false;
137
+ }
138
+ if (debug)
139
+ console.log("+++ match capitalone", dataGuid, el);
140
+ return true;
141
+ }
142
+ }
143
+ ];
144
+ function getVendorForDiv(el, zNearMax, uuidGate, debug) {
145
+ if (!hasNearMaxZIndex(el, zNearMax, debug))
146
+ return null;
147
+ for (var i = 0; i < VENDOR_MATCHERS.length; i += 1) {
148
+ var matcher = VENDOR_MATCHERS[i];
149
+ if (matcher.matches(el, uuidGate, debug)) {
150
+ if (debug)
151
+ console.log("+++ match", matcher.name, el);
152
+ return matcher.name;
153
+ }
154
+ }
155
+ if (debug)
156
+ console.log("+++ reject: no vendor match", el);
157
+ return null;
158
+ }
112
159
  function scanElement(el, seen, zNearMax, uuidGate, debug, handleMatch) {
113
160
  var _a;
114
161
  if (el instanceof HTMLDivElement && el.matches(TARGET_SELECTOR)) {
115
- if (seen.indexOf(el) === -1 && looksLikeTargetDiv(el, zNearMax, uuidGate, debug)) {
162
+ var vendor = getVendorForDiv(el, zNearMax, uuidGate, debug);
163
+ if (seen.indexOf(el) === -1 && vendor) {
116
164
  seen.push(el);
117
- handleMatch(el);
165
+ handleMatch(el, vendor);
118
166
  }
119
167
  }
120
168
  var divs = (_a = el.querySelectorAll) === null || _a === void 0 ? void 0 : _a.call(el, TARGET_SELECTOR);
@@ -122,9 +170,10 @@
122
170
  return;
123
171
  for (var i = 0; i < divs.length; i += 1) {
124
172
  var d = divs[i];
125
- if (seen.indexOf(d) === -1 && looksLikeTargetDiv(d, zNearMax, uuidGate, debug)) {
173
+ var vendor = getVendorForDiv(d, zNearMax, uuidGate, debug);
174
+ if (seen.indexOf(d) === -1 && vendor) {
126
175
  seen.push(d);
127
- handleMatch(d);
176
+ handleMatch(d, vendor);
128
177
  }
129
178
  }
130
179
  }
@@ -146,7 +195,7 @@
146
195
  });
147
196
  var matched = false;
148
197
  var unbindTimer;
149
- var handleMatch = function(el) {
198
+ var handleMatch = function(el, vendor) {
150
199
  matched = true;
151
200
  if (typeof unbindTimer === "number") {
152
201
  clearTimeout(unbindTimer);
@@ -155,9 +204,9 @@
155
204
  if (removeHoney && el.parentNode)
156
205
  el.parentNode.removeChild(el);
157
206
  if (removeHoney) {
158
- onMatch(warn);
207
+ onMatch(warn, void 0, vendor);
159
208
  } else {
160
- onMatch(warn, el);
209
+ onMatch(warn, el, vendor);
161
210
  }
162
211
  };
163
212
  var mo = new MutationObserver(function(mutations) {
@@ -219,13 +268,18 @@
219
268
  }
220
269
 
221
270
  // dist/bundle-tmp/auto.js
222
- var AUTO_MODAL_HTML = '<div class="modal" role="dialog" aria-modal="true" aria-labelledby="honey-modal-title"><h2 id="honey-modal-title">This site can\u2019t proceed with Honey enabled</h2><div style="display:flex;gap:8px;flex-wrap:wrap;margin:8px 0 12px 0;"><a href="https://help.joinhoney.com/article/26-how-do-i-uninstall-honey" target="_blank" rel="noopener noreferrer" style="display:block;padding:10px 12px;background:#e6eef7;color:#0b1b2b;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px;border-radius:6px;flex:1 1 220px;">Please disable it to continue your checkout.</a><a href="https://www.youtube.com/watch?v=wwB3FmbcC88" target="_blank" rel="noopener noreferrer" style="display:block;padding:10px 12px;background:#e6eef7;color:#0b1b2b;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px;border-radius:6px;flex:1 1 220px;">Here is why \uD83C\uDFA5</a></div></div>';
271
+ function buildAutoModalHtml(vendor) {
272
+ var query = encodeURIComponent("Why is the " + vendor + " browser extension shady, and how can i uninstall it?");
273
+ var helpUrl = "http://chatgpt.com/?q=" + query;
274
+ return '<div class="modal" role="dialog" aria-modal="true" aria-labelledby="honey-modal-title"><h2 id="honey-modal-title">This site can\u2019t proceed with ' + vendor + ' enabled</h2><div style="display:flex;gap:8px;flex-wrap:wrap;margin:8px 0 12px 0;"><a href="' + helpUrl + '" target="_blank" rel="noopener noreferrer" style="display:block;padding:10px 12px;background:#e6eef7;color:#0b1b2b;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px;border-radius:6px;flex:1 1 220px;">Please disable it to continue your checkout.</a><a href="https://www.youtube.com/watch?v=wwB3FmbcC88" target="_blank" rel="noopener noreferrer" style="display:block;padding:10px 12px;background:#e6eef7;color:#0b1b2b;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px;border-radius:6px;flex:1 1 220px;">Here is why \uD83C\uDFA5</a></div></div>';
275
+ }
223
276
  if (typeof window !== "undefined") {
224
277
  window.fckHoney = window.fckHoney || {};
225
278
  window.fckHoney.listen = listen;
226
279
  window.fckHoney.version = version;
227
- window.fckHoneyHandle = window.fckHoney.listen(function(warn, _el) {
228
- warn(AUTO_MODAL_HTML);
280
+ window.fckHoneyHandle = window.fckHoney.listen(function(warn, _el, vendor) {
281
+ var vendorLabel = vendor || "honey";
282
+ warn(buildAutoModalHtml(vendorLabel));
229
283
  });
230
284
  }
231
285
  })();
@@ -1,10 +1,24 @@
1
1
  import { listen, version } from "./core";
2
- var AUTO_MODAL_HTML = '<div class="modal" role="dialog" aria-modal="true" aria-labelledby="honey-modal-title"><h2 id="honey-modal-title">This site can’t proceed with Honey enabled</h2><div style="display:flex;gap:8px;flex-wrap:wrap;margin:8px 0 12px 0;"><a href="https://help.joinhoney.com/article/26-how-do-i-uninstall-honey" target="_blank" rel="noopener noreferrer" style="display:block;padding:10px 12px;background:#e6eef7;color:#0b1b2b;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px;border-radius:6px;flex:1 1 220px;">Please disable it to continue your checkout.</a><a href="https://www.youtube.com/watch?v=wwB3FmbcC88" target="_blank" rel="noopener noreferrer" style="display:block;padding:10px 12px;background:#e6eef7;color:#0b1b2b;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px;border-radius:6px;flex:1 1 220px;">Here is why 🎥</a></div></div>';
2
+ function buildAutoModalHtml(vendor) {
3
+ var query = encodeURIComponent("Why is the " + vendor + " browser extension shady, and how can i uninstall it?");
4
+ var helpUrl = "http://chatgpt.com/?q=" + query;
5
+ return ('<div class="modal" role="dialog" aria-modal="true" aria-labelledby="honey-modal-title">' +
6
+ '<h2 id="honey-modal-title">This site can’t proceed with ' +
7
+ vendor +
8
+ " enabled</h2>" +
9
+ '<div style="display:flex;gap:8px;flex-wrap:wrap;margin:8px 0 12px 0;">' +
10
+ '<a href="' +
11
+ helpUrl +
12
+ '" target="_blank" rel="noopener noreferrer" style="display:block;padding:10px 12px;background:#e6eef7;color:#0b1b2b;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px;border-radius:6px;flex:1 1 220px;">Please disable it to continue your checkout.</a>' +
13
+ '<a href="https://www.youtube.com/watch?v=wwB3FmbcC88" target="_blank" rel="noopener noreferrer" style="display:block;padding:10px 12px;background:#e6eef7;color:#0b1b2b;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px;border-radius:6px;flex:1 1 220px;">Here is why 🎥</a>' +
14
+ "</div></div>");
15
+ }
3
16
  if (typeof window !== "undefined") {
4
17
  window.fckHoney = window.fckHoney || {};
5
18
  window.fckHoney.listen = listen;
6
19
  window.fckHoney.version = version;
7
- window.fckHoneyHandle = window.fckHoney.listen(function (warn, _el) {
8
- warn(AUTO_MODAL_HTML);
20
+ window.fckHoneyHandle = window.fckHoney.listen(function (warn, _el, vendor) {
21
+ var vendorLabel = vendor || "honey";
22
+ warn(buildAutoModalHtml(vendorLabel));
9
23
  });
10
24
  }
@@ -13,7 +13,7 @@ import { VERSION } from "./version";
13
13
  export var version = VERSION;
14
14
  var DEFAULT_Z_NEAR_MAX = 2147480000;
15
15
  var UUIDISH_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
16
- var TARGET_SELECTOR = "div[id]";
16
+ var TARGET_SELECTOR = "div";
17
17
  var OVERLAY_STYLE_ID = "simple-overlay-styles";
18
18
  function showOverlay(message) {
19
19
  if (typeof document === "undefined")
@@ -51,17 +51,21 @@ function parseZIndex(cs, el) {
51
51
  var inline = parseInt(el.style.zIndex, 10);
52
52
  return isFinite(inline) ? inline : null;
53
53
  }
54
- function looksLikeTargetDiv(el, zNearMax, uuidGate, debug) {
55
- if (!el.id) {
56
- if (debug)
57
- console.log("+++ reject: no id", el);
58
- return false;
59
- }
60
- if (uuidGate && !UUIDISH_RE.test(el.id)) {
61
- if (debug)
62
- console.log("+++ reject: uuid", el.id);
63
- return false;
54
+ function getDataGuidAttribute(el) {
55
+ for (var i = 0; i < el.attributes.length; i += 1) {
56
+ var attr = el.attributes[i];
57
+ if (!attr)
58
+ continue;
59
+ if (attr.name.indexOf("data-") === 0) {
60
+ var suffix = attr.name.slice(5);
61
+ if (UUIDISH_RE.test(suffix) && attr.value === "true") {
62
+ return attr.name;
63
+ }
64
+ }
64
65
  }
66
+ return null;
67
+ }
68
+ function hasNearMaxZIndex(el, zNearMax, debug) {
65
69
  // Fast path: if inline z-index is missing or below threshold, skip expensive getComputedStyle
66
70
  var inlineZ = parseInt(el.style.zIndex, 10);
67
71
  if (!isFinite(inlineZ) || inlineZ < zNearMax) {
@@ -82,8 +86,6 @@ function looksLikeTargetDiv(el, zNearMax, uuidGate, debug) {
82
86
  console.log("+++ reject: shadowRoot", el);
83
87
  return false;
84
88
  }
85
- if (debug)
86
- console.log("+++ match", el);
87
89
  return true;
88
90
  }
89
91
  var cs = getComputedStyle(el);
@@ -103,16 +105,63 @@ function looksLikeTargetDiv(el, zNearMax, uuidGate, debug) {
103
105
  console.log("+++ reject: shadowRoot", el);
104
106
  return false;
105
107
  }
106
- if (debug)
107
- console.log("+++ match", el);
108
108
  return true;
109
109
  }
110
+ // Each matcher should only check vendor-specific flags; shared z-index gating happens earlier.
111
+ var VENDOR_MATCHERS = [
112
+ {
113
+ name: "honey",
114
+ matches: function (el, uuidGate, debug) {
115
+ if (!el.id) {
116
+ if (debug)
117
+ console.log("+++ reject: no id", el);
118
+ return false;
119
+ }
120
+ if (uuidGate && !UUIDISH_RE.test(el.id)) {
121
+ if (debug)
122
+ console.log("+++ reject: uuid", el.id);
123
+ return false;
124
+ }
125
+ return true;
126
+ }
127
+ },
128
+ {
129
+ name: "Capital One Shopping",
130
+ matches: function (el, _uuidGate, debug) {
131
+ var dataGuid = getDataGuidAttribute(el);
132
+ if (!dataGuid) {
133
+ if (debug)
134
+ console.log("+++ reject: no data guid", el);
135
+ return false;
136
+ }
137
+ if (debug)
138
+ console.log("+++ match capitalone", dataGuid, el);
139
+ return true;
140
+ }
141
+ }
142
+ ];
143
+ function getVendorForDiv(el, zNearMax, uuidGate, debug) {
144
+ if (!hasNearMaxZIndex(el, zNearMax, debug))
145
+ return null;
146
+ for (var i = 0; i < VENDOR_MATCHERS.length; i += 1) {
147
+ var matcher = VENDOR_MATCHERS[i];
148
+ if (matcher.matches(el, uuidGate, debug)) {
149
+ if (debug)
150
+ console.log("+++ match", matcher.name, el);
151
+ return matcher.name;
152
+ }
153
+ }
154
+ if (debug)
155
+ console.log("+++ reject: no vendor match", el);
156
+ return null;
157
+ }
110
158
  function scanElement(el, seen, zNearMax, uuidGate, debug, handleMatch) {
111
159
  var _a;
112
160
  if (el instanceof HTMLDivElement && el.matches(TARGET_SELECTOR)) {
113
- if (seen.indexOf(el) === -1 && looksLikeTargetDiv(el, zNearMax, uuidGate, debug)) {
161
+ var vendor = getVendorForDiv(el, zNearMax, uuidGate, debug);
162
+ if (seen.indexOf(el) === -1 && vendor) {
114
163
  seen.push(el);
115
- handleMatch(el);
164
+ handleMatch(el, vendor);
116
165
  }
117
166
  }
118
167
  var divs = (_a = el.querySelectorAll) === null || _a === void 0 ? void 0 : _a.call(el, TARGET_SELECTOR);
@@ -120,9 +169,10 @@ function scanElement(el, seen, zNearMax, uuidGate, debug, handleMatch) {
120
169
  return;
121
170
  for (var i = 0; i < divs.length; i += 1) {
122
171
  var d = divs[i];
123
- if (seen.indexOf(d) === -1 && looksLikeTargetDiv(d, zNearMax, uuidGate, debug)) {
172
+ var vendor = getVendorForDiv(d, zNearMax, uuidGate, debug);
173
+ if (seen.indexOf(d) === -1 && vendor) {
124
174
  seen.push(d);
125
- handleMatch(d);
175
+ handleMatch(d, vendor);
126
176
  }
127
177
  }
128
178
  }
@@ -139,7 +189,7 @@ export function startHoneyOverlayObserver(options) {
139
189
  var onMatch = (_e = options.onMatch) !== null && _e !== void 0 ? _e : (function () { });
140
190
  var matched = false;
141
191
  var unbindTimer;
142
- var handleMatch = function (el) {
192
+ var handleMatch = function (el, vendor) {
143
193
  matched = true;
144
194
  if (typeof unbindTimer === "number") {
145
195
  clearTimeout(unbindTimer);
@@ -148,10 +198,10 @@ export function startHoneyOverlayObserver(options) {
148
198
  if (removeHoney && el.parentNode)
149
199
  el.parentNode.removeChild(el);
150
200
  if (removeHoney) {
151
- onMatch(warn);
201
+ onMatch(warn, undefined, vendor);
152
202
  }
153
203
  else {
154
- onMatch(warn, el);
204
+ onMatch(warn, el, vendor);
155
205
  }
156
206
  };
157
207
  // Greedy, page-wide observer: Honey overlays can be inserted late, moved,
@@ -1,2 +1,2 @@
1
1
  // Auto-generated from package.json. Do not edit by hand.
2
- export var VERSION = "0.3.6";
2
+ export var VERSION = "0.3.7";
package/dist/esm/core.js CHANGED
@@ -13,7 +13,7 @@ import { VERSION } from "./version";
13
13
  export var version = VERSION;
14
14
  var DEFAULT_Z_NEAR_MAX = 2147480000;
15
15
  var UUIDISH_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
16
- var TARGET_SELECTOR = "div[id]";
16
+ var TARGET_SELECTOR = "div";
17
17
  var OVERLAY_STYLE_ID = "simple-overlay-styles";
18
18
  function showOverlay(message) {
19
19
  if (typeof document === "undefined")
@@ -51,17 +51,21 @@ function parseZIndex(cs, el) {
51
51
  var inline = parseInt(el.style.zIndex, 10);
52
52
  return isFinite(inline) ? inline : null;
53
53
  }
54
- function looksLikeTargetDiv(el, zNearMax, uuidGate, debug) {
55
- if (!el.id) {
56
- if (debug)
57
- console.log("+++ reject: no id", el);
58
- return false;
59
- }
60
- if (uuidGate && !UUIDISH_RE.test(el.id)) {
61
- if (debug)
62
- console.log("+++ reject: uuid", el.id);
63
- return false;
54
+ function getDataGuidAttribute(el) {
55
+ for (var i = 0; i < el.attributes.length; i += 1) {
56
+ var attr = el.attributes[i];
57
+ if (!attr)
58
+ continue;
59
+ if (attr.name.indexOf("data-") === 0) {
60
+ var suffix = attr.name.slice(5);
61
+ if (UUIDISH_RE.test(suffix) && attr.value === "true") {
62
+ return attr.name;
63
+ }
64
+ }
64
65
  }
66
+ return null;
67
+ }
68
+ function hasNearMaxZIndex(el, zNearMax, debug) {
65
69
  // Fast path: if inline z-index is missing or below threshold, skip expensive getComputedStyle
66
70
  var inlineZ = parseInt(el.style.zIndex, 10);
67
71
  if (!isFinite(inlineZ) || inlineZ < zNearMax) {
@@ -82,8 +86,6 @@ function looksLikeTargetDiv(el, zNearMax, uuidGate, debug) {
82
86
  console.log("+++ reject: shadowRoot", el);
83
87
  return false;
84
88
  }
85
- if (debug)
86
- console.log("+++ match", el);
87
89
  return true;
88
90
  }
89
91
  var cs = getComputedStyle(el);
@@ -103,16 +105,63 @@ function looksLikeTargetDiv(el, zNearMax, uuidGate, debug) {
103
105
  console.log("+++ reject: shadowRoot", el);
104
106
  return false;
105
107
  }
106
- if (debug)
107
- console.log("+++ match", el);
108
108
  return true;
109
109
  }
110
+ // Each matcher should only check vendor-specific flags; shared z-index gating happens earlier.
111
+ var VENDOR_MATCHERS = [
112
+ {
113
+ name: "honey",
114
+ matches: function (el, uuidGate, debug) {
115
+ if (!el.id) {
116
+ if (debug)
117
+ console.log("+++ reject: no id", el);
118
+ return false;
119
+ }
120
+ if (uuidGate && !UUIDISH_RE.test(el.id)) {
121
+ if (debug)
122
+ console.log("+++ reject: uuid", el.id);
123
+ return false;
124
+ }
125
+ return true;
126
+ }
127
+ },
128
+ {
129
+ name: "Capital One Shopping",
130
+ matches: function (el, _uuidGate, debug) {
131
+ var dataGuid = getDataGuidAttribute(el);
132
+ if (!dataGuid) {
133
+ if (debug)
134
+ console.log("+++ reject: no data guid", el);
135
+ return false;
136
+ }
137
+ if (debug)
138
+ console.log("+++ match capitalone", dataGuid, el);
139
+ return true;
140
+ }
141
+ }
142
+ ];
143
+ function getVendorForDiv(el, zNearMax, uuidGate, debug) {
144
+ if (!hasNearMaxZIndex(el, zNearMax, debug))
145
+ return null;
146
+ for (var i = 0; i < VENDOR_MATCHERS.length; i += 1) {
147
+ var matcher = VENDOR_MATCHERS[i];
148
+ if (matcher.matches(el, uuidGate, debug)) {
149
+ if (debug)
150
+ console.log("+++ match", matcher.name, el);
151
+ return matcher.name;
152
+ }
153
+ }
154
+ if (debug)
155
+ console.log("+++ reject: no vendor match", el);
156
+ return null;
157
+ }
110
158
  function scanElement(el, seen, zNearMax, uuidGate, debug, handleMatch) {
111
159
  var _a;
112
160
  if (el instanceof HTMLDivElement && el.matches(TARGET_SELECTOR)) {
113
- if (seen.indexOf(el) === -1 && looksLikeTargetDiv(el, zNearMax, uuidGate, debug)) {
161
+ var vendor = getVendorForDiv(el, zNearMax, uuidGate, debug);
162
+ if (seen.indexOf(el) === -1 && vendor) {
114
163
  seen.push(el);
115
- handleMatch(el);
164
+ handleMatch(el, vendor);
116
165
  }
117
166
  }
118
167
  var divs = (_a = el.querySelectorAll) === null || _a === void 0 ? void 0 : _a.call(el, TARGET_SELECTOR);
@@ -120,9 +169,10 @@ function scanElement(el, seen, zNearMax, uuidGate, debug, handleMatch) {
120
169
  return;
121
170
  for (var i = 0; i < divs.length; i += 1) {
122
171
  var d = divs[i];
123
- if (seen.indexOf(d) === -1 && looksLikeTargetDiv(d, zNearMax, uuidGate, debug)) {
172
+ var vendor = getVendorForDiv(d, zNearMax, uuidGate, debug);
173
+ if (seen.indexOf(d) === -1 && vendor) {
124
174
  seen.push(d);
125
- handleMatch(d);
175
+ handleMatch(d, vendor);
126
176
  }
127
177
  }
128
178
  }
@@ -139,7 +189,7 @@ export function startHoneyOverlayObserver(options) {
139
189
  var onMatch = (_e = options.onMatch) !== null && _e !== void 0 ? _e : (function () { });
140
190
  var matched = false;
141
191
  var unbindTimer;
142
- var handleMatch = function (el) {
192
+ var handleMatch = function (el, vendor) {
143
193
  matched = true;
144
194
  if (typeof unbindTimer === "number") {
145
195
  clearTimeout(unbindTimer);
@@ -148,10 +198,10 @@ export function startHoneyOverlayObserver(options) {
148
198
  if (removeHoney && el.parentNode)
149
199
  el.parentNode.removeChild(el);
150
200
  if (removeHoney) {
151
- onMatch(warn);
201
+ onMatch(warn, undefined, vendor);
152
202
  }
153
203
  else {
154
- onMatch(warn, el);
204
+ onMatch(warn, el, vendor);
155
205
  }
156
206
  };
157
207
  // Greedy, page-wide observer: Honey overlays can be inserted late, moved,
@@ -1,2 +1,2 @@
1
1
  // Auto-generated from package.json. Do not edit by hand.
2
- export var VERSION = "0.3.6";
2
+ export var VERSION = "0.3.7";
@@ -1,6 +1,6 @@
1
1
  (function() {
2
2
  // dist/bundle-tmp/version.js
3
- var VERSION = "0.3.6";
3
+ var VERSION = "0.3.7";
4
4
 
5
5
  // dist/bundle-tmp/core.js
6
6
  var __assign = function() {
@@ -17,7 +17,7 @@
17
17
  var version = VERSION;
18
18
  var DEFAULT_Z_NEAR_MAX = 214748e4;
19
19
  var UUIDISH_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
20
- var TARGET_SELECTOR = "div[id]";
20
+ var TARGET_SELECTOR = "div";
21
21
  var OVERLAY_STYLE_ID = "simple-overlay-styles";
22
22
  function showOverlay(message) {
23
23
  if (typeof document === "undefined")
@@ -54,17 +54,21 @@
54
54
  var inline = parseInt(el.style.zIndex, 10);
55
55
  return isFinite(inline) ? inline : null;
56
56
  }
57
- function looksLikeTargetDiv(el, zNearMax, uuidGate, debug) {
58
- if (!el.id) {
59
- if (debug)
60
- console.log("+++ reject: no id", el);
61
- return false;
62
- }
63
- if (uuidGate && !UUIDISH_RE.test(el.id)) {
64
- if (debug)
65
- console.log("+++ reject: uuid", el.id);
66
- return false;
57
+ function getDataGuidAttribute(el) {
58
+ for (var i = 0; i < el.attributes.length; i += 1) {
59
+ var attr = el.attributes[i];
60
+ if (!attr)
61
+ continue;
62
+ if (attr.name.indexOf("data-") === 0) {
63
+ var suffix = attr.name.slice(5);
64
+ if (UUIDISH_RE.test(suffix) && attr.value === "true") {
65
+ return attr.name;
66
+ }
67
+ }
67
68
  }
69
+ return null;
70
+ }
71
+ function hasNearMaxZIndex(el, zNearMax, debug) {
68
72
  var inlineZ = parseInt(el.style.zIndex, 10);
69
73
  if (!isFinite(inlineZ) || inlineZ < zNearMax) {
70
74
  var cs_1 = getComputedStyle(el);
@@ -84,8 +88,6 @@
84
88
  console.log("+++ reject: shadowRoot", el);
85
89
  return false;
86
90
  }
87
- if (debug)
88
- console.log("+++ match", el);
89
91
  return true;
90
92
  }
91
93
  var cs = getComputedStyle(el);
@@ -105,16 +107,62 @@
105
107
  console.log("+++ reject: shadowRoot", el);
106
108
  return false;
107
109
  }
108
- if (debug)
109
- console.log("+++ match", el);
110
110
  return true;
111
111
  }
112
+ var VENDOR_MATCHERS = [
113
+ {
114
+ name: "honey",
115
+ matches: function(el, uuidGate, debug) {
116
+ if (!el.id) {
117
+ if (debug)
118
+ console.log("+++ reject: no id", el);
119
+ return false;
120
+ }
121
+ if (uuidGate && !UUIDISH_RE.test(el.id)) {
122
+ if (debug)
123
+ console.log("+++ reject: uuid", el.id);
124
+ return false;
125
+ }
126
+ return true;
127
+ }
128
+ },
129
+ {
130
+ name: "Capital One Shopping",
131
+ matches: function(el, _uuidGate, debug) {
132
+ var dataGuid = getDataGuidAttribute(el);
133
+ if (!dataGuid) {
134
+ if (debug)
135
+ console.log("+++ reject: no data guid", el);
136
+ return false;
137
+ }
138
+ if (debug)
139
+ console.log("+++ match capitalone", dataGuid, el);
140
+ return true;
141
+ }
142
+ }
143
+ ];
144
+ function getVendorForDiv(el, zNearMax, uuidGate, debug) {
145
+ if (!hasNearMaxZIndex(el, zNearMax, debug))
146
+ return null;
147
+ for (var i = 0; i < VENDOR_MATCHERS.length; i += 1) {
148
+ var matcher = VENDOR_MATCHERS[i];
149
+ if (matcher.matches(el, uuidGate, debug)) {
150
+ if (debug)
151
+ console.log("+++ match", matcher.name, el);
152
+ return matcher.name;
153
+ }
154
+ }
155
+ if (debug)
156
+ console.log("+++ reject: no vendor match", el);
157
+ return null;
158
+ }
112
159
  function scanElement(el, seen, zNearMax, uuidGate, debug, handleMatch) {
113
160
  var _a;
114
161
  if (el instanceof HTMLDivElement && el.matches(TARGET_SELECTOR)) {
115
- if (seen.indexOf(el) === -1 && looksLikeTargetDiv(el, zNearMax, uuidGate, debug)) {
162
+ var vendor = getVendorForDiv(el, zNearMax, uuidGate, debug);
163
+ if (seen.indexOf(el) === -1 && vendor) {
116
164
  seen.push(el);
117
- handleMatch(el);
165
+ handleMatch(el, vendor);
118
166
  }
119
167
  }
120
168
  var divs = (_a = el.querySelectorAll) === null || _a === void 0 ? void 0 : _a.call(el, TARGET_SELECTOR);
@@ -122,9 +170,10 @@
122
170
  return;
123
171
  for (var i = 0; i < divs.length; i += 1) {
124
172
  var d = divs[i];
125
- if (seen.indexOf(d) === -1 && looksLikeTargetDiv(d, zNearMax, uuidGate, debug)) {
173
+ var vendor = getVendorForDiv(d, zNearMax, uuidGate, debug);
174
+ if (seen.indexOf(d) === -1 && vendor) {
126
175
  seen.push(d);
127
- handleMatch(d);
176
+ handleMatch(d, vendor);
128
177
  }
129
178
  }
130
179
  }
@@ -146,7 +195,7 @@
146
195
  });
147
196
  var matched = false;
148
197
  var unbindTimer;
149
- var handleMatch = function(el) {
198
+ var handleMatch = function(el, vendor) {
150
199
  matched = true;
151
200
  if (typeof unbindTimer === "number") {
152
201
  clearTimeout(unbindTimer);
@@ -155,9 +204,9 @@
155
204
  if (removeHoney && el.parentNode)
156
205
  el.parentNode.removeChild(el);
157
206
  if (removeHoney) {
158
- onMatch(warn);
207
+ onMatch(warn, void 0, vendor);
159
208
  } else {
160
- onMatch(warn, el);
209
+ onMatch(warn, el, vendor);
161
210
  }
162
211
  };
163
212
  var mo = new MutationObserver(function(mutations) {
@@ -1,6 +1,7 @@
1
- export declare const version = "0.3.6";
1
+ export declare const version = "0.3.7";
2
2
  export type WarnCallback = (message: string) => () => void;
3
- export type MatchCallback = (warn: WarnCallback, el?: HTMLDivElement) => void;
3
+ export type DetectedVendor = "honey" | "Capital One Shopping";
4
+ export type MatchCallback = (warn: WarnCallback, el?: HTMLDivElement, vendor?: DetectedVendor) => void;
4
5
  export interface ObserverOptions {
5
6
  onMatch?: MatchCallback;
6
7
  uuidGate?: boolean;
@@ -1 +1 @@
1
- export declare const VERSION = "0.3.6";
1
+ export declare const VERSION = "0.3.7";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fck-honey",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "Detects Honey browser extension overlays for merchants.",
5
5
  "license": "MIT",
6
6
  "main": "dist/honey-detect.js",