choreograph-create-pixel 1.2.0 β†’ 1.3.1

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
@@ -4,26 +4,32 @@ This library lets you apply best practises to [Create](https://www.lemonpi.io/)
4
4
 
5
5
  ## Features
6
6
 
7
- - [x] Supports scrapers and segments
8
- - [x] Supports user interaction triggers
9
- - [x] Supports dynamic page changes
7
+ - [x] Supports [scraper](#scraper-pixels), [segment](#segment-pixels) and [conversion](#conversion-pixels) (coming soon) pixels
8
+ - [x] Supports dynamic page content updates
9
+ - [x] Prevents scraping browser-translated content
10
10
  - [x] Continuous URL validation
11
- - [x] Prevents scraping browser-translated pages
12
- - [x] Console debugger
11
+ - [x] User interaction triggers
12
+ - [x] [Console debugger](#debugging)
13
13
 
14
- ## Pixel types
14
+ ### Scraper pixels
15
15
 
16
- ### Scrapers
16
+ <small>Type: `scraper`</small>
17
17
 
18
- Scraper pixels are used to scrape (read) data from websites, and store it as products within an advertiser's product store.
18
+ Scraper pixels are used to scrape (read) data from websites, and store that data as products within an advertiser's product store.
19
19
 
20
- ### Segments <small>(`viewed`, `basketed` and `purchased`)</small>
20
+ ### Segment pixels
21
21
 
22
- Products in ads are shown by recommendation logic. Segment pixels determine this recommendation on a consumer level, by storing a cookie at different moments during the consumer's journey. Segments can be triggered by page views, or other user interactions within a page.
22
+ <small>Types: `viewed`, `basketed` and `purchased`</small>
23
+
24
+ Products in ads are shown by recommendation. Segment pixels determine this recommendation on a consumer level, by storing a **cookie** at different moments or events during the consumer's journey.
25
+
26
+ ### Conversion pixels
27
+
28
+ _(coming soon)_
23
29
 
24
30
  ## Quickstart
25
31
 
26
- The following snippet of all possible pixel types could be embedded on every page of _example.com_, and would automatically determine which pixel to enable where, through URL validation.
32
+ The following theoretical snippet includes all pixel types, can be embedded on every page of _example.com_, and will automatically determine which pixel to enable and disable through continuous URL validation.
27
33
 
28
34
  ### ES module
29
35
 
@@ -35,9 +41,10 @@ new Pixel({
35
41
  advertiser: 0,
36
42
  type: "scraper",
37
43
 
38
- // Where should this pixel be enabled?
44
+ // Where on the website should this pixel be enabled?
39
45
  url: /example\.com\/products\/\d/,
40
46
 
47
+ // Functions here are continuously being evaluated for value changes
41
48
  scrape: {
42
49
  // Data layer example
43
50
  sku: () => window.dataLayer[0].product.sku,
@@ -66,13 +73,13 @@ new Pixel({
66
73
  type: "basketed",
67
74
  url: /example\.com/,
68
75
 
69
- // [Optional] When should this pixel be triggered?
70
- listener: {
76
+ // [Optional] Trigger by DOM events, rather than scrape content updates
77
+ trigger: {
71
78
  event: "click",
72
- elements: () => document.querySelectorAll("button.basket[data-sku]"),
79
+ elements: "button.basket[data-sku]",
73
80
  },
74
81
 
75
- // The "element" parameter can be used when using an event listener
82
+ // The "element" parameter only becomes available when using a trigger
76
83
  scrape: (element) => element.getAttribute("data-sku"),
77
84
  });
78
85
 
@@ -82,9 +89,9 @@ new Pixel({
82
89
  type: "purchased",
83
90
  url: /example\.com\/cart/,
84
91
 
85
- listener: {
92
+ trigger: {
86
93
  event: "click",
87
- elements: () => document.querySelectorAll("button.checkout"),
94
+ elements: "button.checkout",
88
95
  },
89
96
 
90
97
  // Segment pixels support multiple SKUs
@@ -92,11 +99,11 @@ new Pixel({
92
99
  });
93
100
  ```
94
101
 
95
- > ES modules require manual bundling and transpiling before they can be safely used as browser scripts.
102
+ > ES modules require manual bundling and transpiling before they can be safely embedded on websites.
96
103
 
97
104
  ### CDN library
98
105
 
99
- This implementation method allows for embeddeding on pages without the need for bundling or transpiling.
106
+ This alternative implementation method allows for direct embedding on pages without the need for bundling nor transpiling.
100
107
 
101
108
  ```html
102
109
  <script src="https://cdn.jsdelivr.net/npm/choreograph-create-pixel@1"></script>
@@ -117,43 +124,43 @@ Enable browser console debugging by adding `?pixel_debug` or `#pixel_debug` to t
117
124
 
118
125
  ## Configuration
119
126
 
120
- | Property | Type | Description | Default |
121
- | ------------------------------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
122
- | `advertiser` | Number | You can retrieve the advertiser ID from the URL in Create: _manage.lemonpi.io/r/AGENCY_ID/advertiser/`ADVERTISER_ID`_. | _Required_ |
123
- | `type` | String | Pixel type. One of: `"scraper"`, `"viewed"`, `"basketed"` or `"purchased"`. | _Required_ |
124
- | `url` | RegExp | Only enables the pixel on page URLs that are matched by this pattern. | _Required_ |
125
- | `scrape`<br>_(segments only)_ | String, Array or Function | Scrapes the product's SKU for segments. | _Required_ |
126
- | `scrape.*`<br>_(scrapers only)_ | String, Number, Boolean or Function | Scrapes arbitrary product data. `*` should always match with existing field names in the advertiser's product store. | _Required_ |
127
- | `listener` | Object | Use an event listener when you want to enable the pixel only after a specific DOM event, instead of on page change. | `undefined` |
128
- | `listener.event` | String | DOM event type. [List of supported values.](https://www.w3schools.com/jsref/dom_obj_event.asp) | _Required_ |
129
- | `listener.elements` | Function | This function should return DOM element(s) to apply the event listener to. | _Required_ |
130
- | `optional`<br>_(scrapers only)_ | Array | An array of field names (as used in `scrape.*`) that are allowed to have empty values. | `[]` |
131
- | `before` | Function | A custom function that's executed just before the pixel is executed. | `(data, callback) => { callback(data); }` |
132
- | `after` | Function | A custom function that's executed just after the pixel has been executed. | `(data) => {}` |
127
+ | Property | Type | Description | Default |
128
+ | ------------------------------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
129
+ | `advertiser` | Number | You can retrieve the advertiser ID from the URL in Create: _manage.lemonpi.io/r/AGENCY_ID/advertiser/`ADVERTISER_ID`_. | _Required_ |
130
+ | `type` | String | Pixel type. One of: `"scraper"`, `"viewed"`, `"basketed"` or `"purchased"`. | _Required_ |
131
+ | `url` | RegExp | Only enables the pixel on page URLs that are matched by this pattern. | _Required_ |
132
+ | `scrape`<br>_(segments only)_ | String, Array or Function | Scrapes the product's SKU for segments. | _Required_ |
133
+ | `scrape.*`<br>_(scrapers only)_ | String, Number, Boolean or Function | Scrapes arbitrary product data. `*` should always match with existing field names in the advertiser's product store. | _Required_ |
134
+ | `trigger` | Object | Adds an event listener to enable the pixel only on a specific DOM event, instead of on scrape content updates. | `undefined` |
135
+ | `trigger.event` | String | DOM event type. [List of supported values.](https://www.w3schools.com/jsref/dom_obj_event.asp) | _Required_ |
136
+ | `trigger.elements` | String, Function | This query selector string, or function returning DOM element(s), is used to apply the event listener to. | _Required_ |
137
+ | `optional`<br>_(scrapers only)_ | Array | An array of field names (as used in `scrape.*`) that are allowed to have empty values. | `[]` |
138
+ | `before` | Function | A custom function that's executed just before the pixel is executed. | `(scrapedData, callback) => { callback(scrapedData); }` |
139
+ | `after` | Function | A custom function that's executed just after the pixel has been executed. | `(scrapedData) => {}` |
133
140
 
134
141
  ## Static methods (helpers)
135
142
 
136
- ### `getUrl({ allowedQueryParameters, allowHash })`
143
+ ### `.getUrl({ allowedQueryParameters, allowHash })`
137
144
 
138
- Returns the bare page URL without query parameters or location hash. This is recommended to prevent scraping unwanted UTM tagging.
145
+ Returns the bare page URL without query parameters or location hash. This is highly recommended to exclude (UTM) tagging, or other unwanted side effects.
139
146
 
140
- | Property | Type | Description | Default |
141
- | ------------------------ | ------- | --------------------------------------------------------------- | ------- |
142
- | `allowedQueryParameters` | Array | Explicitly allow query parameters in the resulting URL. | `[]` |
143
- | `allowHash` | Boolean | Wether or not to include the location hash (`#foo`) of the URL. | `false` |
147
+ | Property | Type | Description | Default |
148
+ | ------------------------ | ------- | ----------------------------------------------------------------- | ------- |
149
+ | `allowedQueryParameters` | Array | Explicitly allow query parameters in the URL. | `[]` |
150
+ | `allowHash` | Boolean | Explicitly allow including the location hash (`#foo`) in the URL. | `false` |
144
151
 
145
- ### `getAllPathSegments()`
152
+ ### `.getAllPathSegments()`
146
153
 
147
154
  Retrieves all path segments from the URL as an array. E.g. _http://www.example.com/foo/bar_ returns `["foo", "bar"]`.
148
155
 
149
- ### `getPathSegment(index)`
156
+ ### `.getPathSegment(index)`
150
157
 
151
- Retrieves a specific segment from the URL. E.g. `getPathSegment(0)` with URL _http://www.example.com/foo/bar_ returns `"foo"`.
158
+ Retrieves a specific segment from the URL. E.g. `getPathSegment(0)` on _http://www.example.com/foo/bar_ returns `"foo"`.
152
159
 
153
- ### `getAllQueryParameters()`
160
+ ### `.getAllQueryParameters()`
154
161
 
155
162
  Retrieves all query string parameters from the URL as an object. E.g. _http://www.example.com/?foo=bar_ returns `{ foo: "bar" }`.
156
163
 
157
- ### `getQueryParameter(key)`
164
+ ### `.getQueryParameter(key)`
158
165
 
159
- Retrieves a specific query parameter from the URL. E.g. `getQueryParameter('foo')` with URL _http://www.example.com/?foo=bar_ returns `"bar"`.
166
+ Retrieves a specific query parameter from the URL. E.g. `getQueryParameter('foo')` on _http://www.example.com/?foo=bar_ returns `"bar"`.
@@ -1,24 +1,21 @@
1
- /*! choreograph-create-pixel v1.2.0 2022/10/10 */
1
+ /*! choreograph-create-pixel v1.3.1 2022/11/25 */
2
2
  'use strict';
3
3
 
4
- const CONFIG = {
5
- colors: { error: "red", warn: "orange", success: "green" },
6
- icons: {
7
- scraper: "πŸ“š",
8
- viewed: "πŸ‘€",
9
- basketed: "πŸ›’",
10
- purchased: "🧾",
11
- attribution: "πŸ”–",
12
- conversion: "πŸ’΅",
13
- },
14
- };
15
-
16
4
  class ChoreographCreatePixel {
17
5
  constructor(userConfig) {
18
6
  this.previouslyScrapedHash = null;
19
7
  this.logs = [];
20
8
 
21
9
  this.config = {
10
+ colors: { error: "red", warn: "orange", success: "green" },
11
+ icons: {
12
+ scraper: "πŸ“š",
13
+ viewed: "πŸ‘€",
14
+ basketed: "πŸ›’",
15
+ purchased: "🧾",
16
+ attribution: "πŸ”–",
17
+ conversion: "πŸ’΅",
18
+ },
22
19
  debug: /(pixel|lemonpi)_debug/i.test(location.href),
23
20
  before: (data, callback) => callback(data),
24
21
  after: () => {},
@@ -89,11 +86,11 @@ class ChoreographCreatePixel {
89
86
 
90
87
  const args = [
91
88
  `%cβΈ¬ create%c ${this.config.type} ${
92
- CONFIG.icons[this.config.type]
89
+ this.config.icons[this.config.type]
93
90
  } %c${message}`,
94
91
  "background:black;color:white;border-radius:3px;padding:3px 6px",
95
92
  "font-weight:bold",
96
- `color:${CONFIG.colors[level]}`,
93
+ `color:${this.config.colors[level]}`,
97
94
  ];
98
95
 
99
96
  if (data) args.push(data);
@@ -136,16 +133,20 @@ class ChoreographCreatePixel {
136
133
  "warn",
137
134
  "This page has been translated by the browser, and won't be scraped"
138
135
  );
139
- else if (this.config.listener) {
140
- const attribute = `create-${this.config.type}-${this.config.listener.event}`;
136
+ else if (this.config.trigger) {
137
+ const attribute = `create-${this.config.type}-${this.config.trigger.event}`;
141
138
 
142
139
  try {
143
- let elements = this.config.listener.elements();
140
+ let elements =
141
+ typeof this.config.trigger.elements === "string"
142
+ ? document.querySelectorAll(this.config.trigger.elements)
143
+ : this.config.trigger.elements();
144
+
144
145
  if (!elements.forEach) elements = [elements];
145
146
 
146
147
  elements.forEach((element) => {
147
148
  if (!element.hasAttribute(attribute)) {
148
- element.addEventListener(this.config.listener.event, () =>
149
+ element.addEventListener(this.config.trigger.event, () =>
149
150
  this.scrape(element)
150
151
  );
151
152
 
@@ -154,7 +155,7 @@ class ChoreographCreatePixel {
154
155
  });
155
156
  } catch (error) {
156
157
  this.log("error", error.message, {
157
- "listener.elements": this.config.listener.elements,
158
+ "trigger.elements": this.config.trigger.elements,
158
159
  });
159
160
  }
160
161
  } else {
@@ -1,22 +1,19 @@
1
- /*! choreograph-create-pixel v1.2.0 2022/10/10 */
2
- const CONFIG = {
3
- colors: { error: "red", warn: "orange", success: "green" },
4
- icons: {
5
- scraper: "πŸ“š",
6
- viewed: "πŸ‘€",
7
- basketed: "πŸ›’",
8
- purchased: "🧾",
9
- attribution: "πŸ”–",
10
- conversion: "πŸ’΅",
11
- },
12
- };
13
-
1
+ /*! choreograph-create-pixel v1.3.1 2022/11/25 */
14
2
  class ChoreographCreatePixel {
15
3
  constructor(userConfig) {
16
4
  this.previouslyScrapedHash = null;
17
5
  this.logs = [];
18
6
 
19
7
  this.config = {
8
+ colors: { error: "red", warn: "orange", success: "green" },
9
+ icons: {
10
+ scraper: "πŸ“š",
11
+ viewed: "πŸ‘€",
12
+ basketed: "πŸ›’",
13
+ purchased: "🧾",
14
+ attribution: "πŸ”–",
15
+ conversion: "πŸ’΅",
16
+ },
20
17
  debug: /(pixel|lemonpi)_debug/i.test(location.href),
21
18
  before: (data, callback) => callback(data),
22
19
  after: () => {},
@@ -87,11 +84,11 @@ class ChoreographCreatePixel {
87
84
 
88
85
  const args = [
89
86
  `%cβΈ¬ create%c ${this.config.type} ${
90
- CONFIG.icons[this.config.type]
87
+ this.config.icons[this.config.type]
91
88
  } %c${message}`,
92
89
  "background:black;color:white;border-radius:3px;padding:3px 6px",
93
90
  "font-weight:bold",
94
- `color:${CONFIG.colors[level]}`,
91
+ `color:${this.config.colors[level]}`,
95
92
  ];
96
93
 
97
94
  if (data) args.push(data);
@@ -134,16 +131,20 @@ class ChoreographCreatePixel {
134
131
  "warn",
135
132
  "This page has been translated by the browser, and won't be scraped"
136
133
  );
137
- else if (this.config.listener) {
138
- const attribute = `create-${this.config.type}-${this.config.listener.event}`;
134
+ else if (this.config.trigger) {
135
+ const attribute = `create-${this.config.type}-${this.config.trigger.event}`;
139
136
 
140
137
  try {
141
- let elements = this.config.listener.elements();
138
+ let elements =
139
+ typeof this.config.trigger.elements === "string"
140
+ ? document.querySelectorAll(this.config.trigger.elements)
141
+ : this.config.trigger.elements();
142
+
142
143
  if (!elements.forEach) elements = [elements];
143
144
 
144
145
  elements.forEach((element) => {
145
146
  if (!element.hasAttribute(attribute)) {
146
- element.addEventListener(this.config.listener.event, () =>
147
+ element.addEventListener(this.config.trigger.event, () =>
147
148
  this.scrape(element)
148
149
  );
149
150
 
@@ -152,7 +153,7 @@ class ChoreographCreatePixel {
152
153
  });
153
154
  } catch (error) {
154
155
  this.log("error", error.message, {
155
- "listener.elements": this.config.listener.elements,
156
+ "trigger.elements": this.config.trigger.elements,
156
157
  });
157
158
  }
158
159
  } else {
@@ -1,2 +1,2 @@
1
- /*! choreograph-create-pixel v1.2.0 2022/10/10 */
2
- var ChoreographCreatePixel=function(){"use strict";function e(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function t(t){for(var r=1;r<arguments.length;r++){var o=null!=arguments[r]?arguments[r]:{};r%2?e(Object(o),!0).forEach((function(e){n(t,e,o[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(o)):e(Object(o)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(o,e))}))}return t}function r(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}var o={colors:{error:"red",warn:"orange",success:"green"},icons:{scraper:"πŸ“š",viewed:"πŸ‘€",basketed:"πŸ›’",purchased:"🧾",attribution:"πŸ”–",conversion:"πŸ’΅"}},i=function(){function e(r){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.previouslyScrapedHash=null,this.logs=[],this.config=t({debug:/(pixel|lemonpi)_debug/i.test(location.href),before:function(e,t){return t(e)},after:function(){},optional:[]},r),this.validateConfig()&&this.cycle()}var i,c,s;return i=e,c=[{key:"log",value:function(e,t){var r,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if(this.config.debug&&!this.logs.includes(t)){var i=["%cβΈ¬ create%c ".concat(this.config.type," ").concat(o.icons[this.config.type]," %c").concat(t),"background:black;color:white;border-radius:3px;padding:3px 6px","font-weight:bold","color:".concat(o.colors[e])];n&&i.push(n),(r=console).info.apply(r,i),this.logs.push(t)}}},{key:"validateConfig",value:function(){if("number"!=typeof this.config.advertiser)this.log("error","Please use a number",{advertiser:this.config.advertiser});else if(["scraper","viewed","basketed","purchased"].includes(this.config.type))if(this.config.url instanceof RegExp){if(this.config.scrape)return!0;this.log("error","Please provide something to scrape",{scrape:this.config.scrape})}else this.log("error","Please use a regular expression",{url:this.config.url});else this.log("error","Please use scraper, viewed, basketed or purchased",{type:this.config.type})}},{key:"cycle",value:function(){var e=this;if(this.config.url.test(location.href))if("scraper"===this.config.type&&document.querySelector('html[class*="translated-"]'))this.log("warn","This page has been translated by the browser, and won't be scraped");else if(this.config.listener){var t="create-".concat(this.config.type,"-").concat(this.config.listener.event);try{var r=this.config.listener.elements();r.forEach||(r=[r]),r.forEach((function(r){r.hasAttribute(t)||(r.addEventListener(e.config.listener.event,(function(){return e.scrape(r)})),r.setAttribute(t,""))}))}catch(e){this.log("error",e.message,{"listener.elements":this.config.listener.elements})}}else this.scrape();else this.log("warn",'URL pattern does not match "'.concat(location.href,'"'),{url:this.config.url});setTimeout((function(){return e.cycle()}),750)}},{key:"scrape",value:function(e){var r,o=this,i=!1,c=function(t,r){var c=t;if("function"==typeof c)try{c=c(e)}catch(e){if(o.config.optional.includes(r))return null;o.log("attribution"===o.config.type?"warn":"error",e.message,n({},r?"scrape.".concat(r):"scrape",c)),i=!0}if("string"==typeof c&&(c=c.replace(/\s+/g," ").trim()),null==c||""===c){if(o.config.optional.includes(r))return null;o.log("attribution"===o.config.type?"warn":"error","Value is empty",n({},r?"scrape.".concat(r):"scrape",c)),i=!0}return c};"conversion"===this.config.type?"string"!=typeof(r={conversion:c(this.config.scrape),attribution:localStorage.getItem("create-attribution-id")}).attribution&&(this.log("warn","There's no attribution ID stored yet"),i=!0):r="scraper"!==this.config.type?c(this.config.scrape):Object.keys(this.config.scrape).reduce((function(e,r){return t(t({},e),{},n({},r,c(o.config.scrape[r],r)))}),{});var s=JSON.stringify(r);if(!i&&this.previouslyScrapedHash!==s){try{this.config.before(r,(function(e){if("attribution"===o.config.type){localStorage.setItem("create-attribution-id",r),o.log("success","Successful!",{attribution:r});try{o.config.after(r)}catch(e){o.log("error",e.message,{after:o.config.after})}}else Array.isArray(e)?e.forEach((function(e){return o.send(e)})):o.send(e)}))}catch(e){this.log("error",e.message,{before:this.config.before})}this.previouslyScrapedHash=s,this.logs.length=0}}},{key:"send",value:function(e){var r,n=this;switch(this.config.type){case"scraper":r="https://d.lemonpi.io/scrapes".concat(this.config.debug?"?validate=true":"");break;case"conversion":r="https://lemonpi.io/";break;default:r="https://d.lemonpi.io/a/".concat(this.config.advertiser,"/product/event?e=").concat(encodeURIComponent(JSON.stringify({"event-type":"product-".concat(this.config.type),sku:e})))}"scraper"===this.config.type||this.config.debug?fetch(r,"scraper"===this.config.type?{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({"advertiser-id":this.config.advertiser,sku:e.sku,fields:t(t({},e),{},{sku:void 0})})}:null).then((function(t){return t.json().then((function(r){if(t.ok){n.log("warn","Successful, with warnings. Details:",r);try{n.config.after(e)}catch(e){n.log("error",e.message,{after:n.config.after})}}else n.log("error","Failed: ".concat(t.status," (").concat(t.statusText,"). Details:"),r);n.logs.length=0})).catch((function(){if(t.ok){n.log("success","Successful!",["viewed","basketed","purchased"].includes(n.config.type)?{sku:e}:e);try{n.config.after(e)}catch(e){n.log("error",e.message,{after:n.config.after})}}else n.log("error","Failed: ".concat(t.status," (").concat(t.statusText,"). Details:"),t);n.logs.length=0}))})).catch((function(e){n.log("error","Failed: ".concat(e.message)),n.logs.length=0})):(new Image).src=r}}],s=[{key:"getUrl",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.allowedQueryParameters,r=void 0===t?[]:t,n=e.allowHash,o=void 0!==n&&n,i="".concat(location.protocol,"//").concat(location.host).concat(location.pathname),c=new URLSearchParams(location.search);return r.reduce((function(e,t){var r=e?"&":"?",n=encodeURI(t),o=c.get(t);return null!=o?(i+="".concat(r).concat(n).concat(""===o?"":"=".concat(encodeURI(o))),!0):e}),!1),o&&(i+=location.hash),i}},{key:"getAllPathSegments",value:function(){return location.pathname.split("/").filter((function(e){return e})).map((function(e){return decodeURI(e)}))}},{key:"getPathSegment",value:function(e){return this.getAllPathSegments()[e]}},{key:"getAllQueryParameters",value:function(){return location.search.replace(/^\?/,"").split("&").filter((function(e){return e})).reduce((function(e,r){return t(t({},e),{},n({},decodeURI(r.split("=")[0]),decodeURI(r.split("=")[1]||"")))}),{})}},{key:"getQueryParameter",value:function(e){return this.getAllQueryParameters()[e]}}],c&&r(i.prototype,c),s&&r(i,s),Object.defineProperty(i,"prototype",{writable:!1}),e}();return i}();
1
+ /*! choreograph-create-pixel v1.3.1 2022/11/25 */
2
+ var ChoreographCreatePixel=function(){"use strict";function e(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function t(t){for(var r=1;r<arguments.length;r++){var o=null!=arguments[r]?arguments[r]:{};r%2?e(Object(o),!0).forEach((function(e){n(t,e,o[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(o)):e(Object(o)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(o,e))}))}return t}function r(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}var o=function(){function e(r){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.previouslyScrapedHash=null,this.logs=[],this.config=t({colors:{error:"red",warn:"orange",success:"green"},icons:{scraper:"πŸ“š",viewed:"πŸ‘€",basketed:"πŸ›’",purchased:"🧾",attribution:"πŸ”–",conversion:"πŸ’΅"},debug:/(pixel|lemonpi)_debug/i.test(location.href),before:function(e,t){return t(e)},after:function(){},optional:[]},r),this.validateConfig()&&this.cycle()}var o,i,c;return o=e,i=[{key:"log",value:function(e,t){var r,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if(this.config.debug&&!this.logs.includes(t)){var o=["%cβΈ¬ create%c ".concat(this.config.type," ").concat(this.config.icons[this.config.type]," %c").concat(t),"background:black;color:white;border-radius:3px;padding:3px 6px","font-weight:bold","color:".concat(this.config.colors[e])];n&&o.push(n),(r=console).info.apply(r,o),this.logs.push(t)}}},{key:"validateConfig",value:function(){if("number"!=typeof this.config.advertiser)this.log("error","Please use a number",{advertiser:this.config.advertiser});else if(["scraper","viewed","basketed","purchased"].includes(this.config.type))if(this.config.url instanceof RegExp){if(this.config.scrape)return!0;this.log("error","Please provide something to scrape",{scrape:this.config.scrape})}else this.log("error","Please use a regular expression",{url:this.config.url});else this.log("error","Please use scraper, viewed, basketed or purchased",{type:this.config.type})}},{key:"cycle",value:function(){var e=this;if(this.config.url.test(location.href))if("scraper"===this.config.type&&document.querySelector('html[class*="translated-"]'))this.log("warn","This page has been translated by the browser, and won't be scraped");else if(this.config.trigger){var t="create-".concat(this.config.type,"-").concat(this.config.trigger.event);try{var r="string"==typeof this.config.trigger.elements?document.querySelectorAll(this.config.trigger.elements):this.config.trigger.elements();r.forEach||(r=[r]),r.forEach((function(r){r.hasAttribute(t)||(r.addEventListener(e.config.trigger.event,(function(){return e.scrape(r)})),r.setAttribute(t,""))}))}catch(e){this.log("error",e.message,{"trigger.elements":this.config.trigger.elements})}}else this.scrape();else this.log("warn",'URL pattern does not match "'.concat(location.href,'"'),{url:this.config.url});setTimeout((function(){return e.cycle()}),750)}},{key:"scrape",value:function(e){var r,o=this,i=!1,c=function(t,r){var c=t;if("function"==typeof c)try{c=c(e)}catch(e){if(o.config.optional.includes(r))return null;o.log("attribution"===o.config.type?"warn":"error",e.message,n({},r?"scrape.".concat(r):"scrape",c)),i=!0}if("string"==typeof c&&(c=c.replace(/\s+/g," ").trim()),null==c||""===c){if(o.config.optional.includes(r))return null;o.log("attribution"===o.config.type?"warn":"error","Value is empty",n({},r?"scrape.".concat(r):"scrape",c)),i=!0}return c};"conversion"===this.config.type?"string"!=typeof(r={conversion:c(this.config.scrape),attribution:localStorage.getItem("create-attribution-id")}).attribution&&(this.log("warn","There's no attribution ID stored yet"),i=!0):r="scraper"!==this.config.type?c(this.config.scrape):Object.keys(this.config.scrape).reduce((function(e,r){return t(t({},e),{},n({},r,c(o.config.scrape[r],r)))}),{});var s=JSON.stringify(r);if(!i&&this.previouslyScrapedHash!==s){try{this.config.before(r,(function(e){if("attribution"===o.config.type){localStorage.setItem("create-attribution-id",r),o.log("success","Successful!",{attribution:r});try{o.config.after(r)}catch(e){o.log("error",e.message,{after:o.config.after})}}else Array.isArray(e)?e.forEach((function(e){return o.send(e)})):o.send(e)}))}catch(e){this.log("error",e.message,{before:this.config.before})}this.previouslyScrapedHash=s,this.logs.length=0}}},{key:"send",value:function(e){var r,n=this;switch(this.config.type){case"scraper":r="https://d.lemonpi.io/scrapes".concat(this.config.debug?"?validate=true":"");break;case"conversion":r="https://lemonpi.io/";break;default:r="https://d.lemonpi.io/a/".concat(this.config.advertiser,"/product/event?e=").concat(encodeURIComponent(JSON.stringify({"event-type":"product-".concat(this.config.type),sku:e})))}"scraper"===this.config.type||this.config.debug?fetch(r,"scraper"===this.config.type?{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({"advertiser-id":this.config.advertiser,sku:e.sku,fields:t(t({},e),{},{sku:void 0})})}:null).then((function(t){return t.json().then((function(r){if(t.ok){n.log("warn","Successful, with warnings. Details:",r);try{n.config.after(e)}catch(e){n.log("error",e.message,{after:n.config.after})}}else n.log("error","Failed: ".concat(t.status," (").concat(t.statusText,"). Details:"),r);n.logs.length=0})).catch((function(){if(t.ok){n.log("success","Successful!",["viewed","basketed","purchased"].includes(n.config.type)?{sku:e}:e);try{n.config.after(e)}catch(e){n.log("error",e.message,{after:n.config.after})}}else n.log("error","Failed: ".concat(t.status," (").concat(t.statusText,"). Details:"),t);n.logs.length=0}))})).catch((function(e){n.log("error","Failed: ".concat(e.message)),n.logs.length=0})):(new Image).src=r}}],c=[{key:"getUrl",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.allowedQueryParameters,r=void 0===t?[]:t,n=e.allowHash,o=void 0!==n&&n,i="".concat(location.protocol,"//").concat(location.host).concat(location.pathname),c=new URLSearchParams(location.search);return r.reduce((function(e,t){var r=e?"&":"?",n=encodeURI(t),o=c.get(t);return null!=o?(i+="".concat(r).concat(n).concat(""===o?"":"=".concat(encodeURI(o))),!0):e}),!1),o&&(i+=location.hash),i}},{key:"getAllPathSegments",value:function(){return location.pathname.split("/").filter((function(e){return e})).map((function(e){return decodeURI(e)}))}},{key:"getPathSegment",value:function(e){return this.getAllPathSegments()[e]}},{key:"getAllQueryParameters",value:function(){return location.search.replace(/^\?/,"").split("&").filter((function(e){return e})).reduce((function(e,r){return t(t({},e),{},n({},decodeURI(r.split("=")[0]),decodeURI(r.split("=")[1]||"")))}),{})}},{key:"getQueryParameter",value:function(e){return this.getAllQueryParameters()[e]}}],i&&r(o.prototype,i),c&&r(o,c),Object.defineProperty(o,"prototype",{writable:!1}),e}();return o}();
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "choreograph-create-pixel",
3
3
  "description": "This library lets you apply best practises to Choreograph Create pixel development and implementation.",
4
+ "version": "1.3.1",
4
5
  "keywords": [
5
6
  "wpp",
6
7
  "groupm",
@@ -8,7 +9,6 @@
8
9
  "odc",
9
10
  "opendc"
10
11
  ],
11
- "version": "1.2.0",
12
12
  "author": "Rick Stevens <rick.stevens@choreograph.com> (https://lemonpi.io)",
13
13
  "repository": "gitlab:GreenhouseGroup/lemonpi/solutions/choreograph-create-pixel",
14
14
  "homepage": "https://lemonpi.io",
@@ -28,15 +28,15 @@
28
28
  "prepublishOnly": "npm run build"
29
29
  },
30
30
  "devDependencies": {
31
- "@babel/core": "^7.19.3",
32
- "@babel/preset-env": "^7.19.3",
33
- "@rollup/plugin-babel": "^5.3.1",
34
- "@rollup/plugin-eslint": "^8.0.2",
35
- "eslint": "^8.24.0",
31
+ "@babel/core": "^7.20.2",
32
+ "@babel/preset-env": "^7.20.2",
33
+ "@rollup/plugin-babel": "^6.0.3",
34
+ "@rollup/plugin-eslint": "^9.0.1",
35
+ "eslint": "^8.28.0",
36
36
  "eslint-config-prettier": "^8.5.0",
37
37
  "eslint-plugin-prettier": "^4.2.1",
38
38
  "moment": "^2.29.4",
39
- "prettier": "^2.7.1",
39
+ "prettier": "^2.8.0",
40
40
  "rollup": "^2.79.1",
41
41
  "rollup-plugin-terser": "^7.0.2"
42
42
  }