@shopgate/tracking-core 7.30.0-alpha.7 → 7.30.0-alpha.8
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/core/AppHandler.js +121 -19
- package/core/Core.js +337 -82
- package/helpers/events.js +46 -7
- package/helpers/formatHelpers.js +324 -49
- package/helpers/helper.js +247 -36
- package/helpers/optOut.js +114 -13
- package/helpers/urlMapping.js +110 -14
- package/package.json +3 -3
- package/plugins/Base.js +94 -17
- package/plugins/trackers/FbPixel.js +186 -17
- package/plugins/trackers/GaBase.js +250 -31
- package/plugins/trackers/GaClassic.js +93 -13
- package/plugins/trackers/GaUniversal.js +162 -16
- package/plugins/trackers/Unified.js +67 -11
- package/typedef.js +51 -17
package/helpers/helper.js
CHANGED
|
@@ -1,75 +1,286 @@
|
|
|
1
|
-
|
|
1
|
+
import "core-js/modules/es.string.replace.js";
|
|
2
|
+
import DataRequest from '@shopgate/pwa-core/classes/DataRequest';
|
|
3
|
+
import { logger } from '@shopgate/pwa-core/helpers';
|
|
4
|
+
import * as _SGAction from '@shopgate/pwa-core/commands/unifiedTracking';
|
|
5
|
+
export { _SGAction as SGAction };
|
|
6
|
+
/**
|
|
2
7
|
* Decodes a hexadecimal encoded binary string
|
|
3
8
|
* @param {string} str The string that shall be decoded
|
|
4
9
|
* @see http://locutus.io/php/strings/hex2bin/
|
|
5
10
|
* @returns {string|boolean} Hexadecimal representation of data. FALSE if decoding failed.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
*/
|
|
12
|
+
export const hex2bin = str => {
|
|
13
|
+
const s = `${str}`;
|
|
14
|
+
const ret = [];
|
|
15
|
+
let i = 0;
|
|
16
|
+
let l;
|
|
17
|
+
for (l = s.length; i < l; i += 2) {
|
|
18
|
+
const c = parseInt(s.substr(i, 1), 16);
|
|
19
|
+
const k = parseInt(s.substr(i + 1, 1), 16);
|
|
20
|
+
|
|
21
|
+
// eslint-disable-next-line no-restricted-globals
|
|
22
|
+
if (isNaN(c) || isNaN(k)) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// eslint-disable-next-line no-bitwise
|
|
27
|
+
ret.push(c << 4 | k);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// eslint-disable-next-line prefer-spread
|
|
31
|
+
return String.fromCharCode.apply(String, ret);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
10
35
|
* Sends a DataRequest
|
|
11
36
|
* @param {string} url Url for the request
|
|
12
|
-
*/
|
|
37
|
+
*/
|
|
38
|
+
export function sendDataRequest(url) {
|
|
39
|
+
new DataRequest(url).dispatch().then(result => logger.info(url, result)).catch(err => err && logger.error(err));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
13
43
|
* Object representation of URI(RFC2396) string
|
|
14
44
|
* Made for general purpose. Feel free to extend it for your needs.
|
|
15
|
-
*/
|
|
45
|
+
*/
|
|
46
|
+
export class SGLink {
|
|
47
|
+
/**
|
|
16
48
|
* Constructor
|
|
17
49
|
* @param {string} url Url to creating SGLink from
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
50
|
+
*/
|
|
51
|
+
constructor(url) {
|
|
52
|
+
// Complete url string
|
|
53
|
+
this.url = '';
|
|
54
|
+
// Any scheme we support (ex. https|shopgate-{$number}|sgapi)
|
|
55
|
+
this.scheme = '';
|
|
56
|
+
this.authority = '';
|
|
57
|
+
this.path = '';
|
|
58
|
+
this.splittedPath = [];
|
|
59
|
+
this.query = '';
|
|
60
|
+
// Endpoint - safe for shopgate (ex. no endpoint is converted to "index")
|
|
61
|
+
this.action = '';
|
|
62
|
+
this.params = {};
|
|
63
|
+
this.isDeepLink = false;
|
|
64
|
+
/**
|
|
65
|
+
* Converts the object to relative url
|
|
66
|
+
* @param {boolean} [leadingSlash=true] Tells if the url shall start with a leading slash
|
|
67
|
+
* @return {string}
|
|
68
|
+
*/
|
|
69
|
+
this.toRelativeString = (leadingSlash = true) => {
|
|
70
|
+
let outputUrl = '';
|
|
71
|
+
if (leadingSlash && this.path[0] !== '/') {
|
|
72
|
+
outputUrl = '/';
|
|
73
|
+
}
|
|
74
|
+
if (this.path) {
|
|
75
|
+
outputUrl += SGLink.encodeURISafe(this.path);
|
|
76
|
+
}
|
|
77
|
+
if (this.query) {
|
|
78
|
+
// .query is always encoded
|
|
79
|
+
outputUrl += `?${this.query}`;
|
|
80
|
+
}
|
|
81
|
+
return outputUrl;
|
|
82
|
+
};
|
|
83
|
+
this.url = url;
|
|
84
|
+
this.parseUrl(url);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
27
88
|
* Encode the url with encodeURIComponent and
|
|
28
89
|
* takes care of double encoding
|
|
29
90
|
*
|
|
30
91
|
* @param {string} string - string to be encoded
|
|
31
92
|
* @return {string}
|
|
32
|
-
*/
|
|
93
|
+
*/
|
|
94
|
+
static encodeURIComponentSafe(string) {
|
|
95
|
+
const decoded = decodeURIComponent(string);
|
|
96
|
+
if (decoded !== string) {
|
|
97
|
+
return string;
|
|
98
|
+
}
|
|
99
|
+
return encodeURIComponent(string);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Encode the url and takes care of double encoding
|
|
104
|
+
* @param {string} string String to be encoded
|
|
105
|
+
* @returns {string} encoded string
|
|
106
|
+
*/
|
|
107
|
+
static encodeURISafe(string) {
|
|
108
|
+
const decoded = decodeURI(string);
|
|
109
|
+
if (decoded !== string) {
|
|
110
|
+
return string;
|
|
111
|
+
}
|
|
112
|
+
return encodeURI(string);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
33
116
|
* Parses url and extracts path, query, action, splittedPath, ...
|
|
34
117
|
*
|
|
35
118
|
* @param {string} incomingUrl The url that shall be parsed.
|
|
36
|
-
*/
|
|
37
|
-
|
|
119
|
+
*/
|
|
120
|
+
parseUrl(incomingUrl) {
|
|
121
|
+
let urlToSanitize = incomingUrl;
|
|
122
|
+
if (!urlToSanitize) {
|
|
123
|
+
urlToSanitize = '';
|
|
124
|
+
}
|
|
125
|
+
const commonSchemas = ['http', 'https', 'tel', 'mailto'];
|
|
126
|
+
|
|
127
|
+
// Based on the regex in RFC2396 Appendix B.
|
|
128
|
+
const parser = /^(?:([^:/?#]+):)?(?:\/\/([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/;
|
|
129
|
+
const result = urlToSanitize.match(parser);
|
|
130
|
+
if (!this.isDeepLink && result[1] && commonSchemas.indexOf(result[1]) === -1) {
|
|
131
|
+
this.isDeepLink = true;
|
|
132
|
+
const scheme = `${result[1]}://`;
|
|
133
|
+
|
|
134
|
+
/**
|
|
38
135
|
* Add slash so that we can parse the attributes properly
|
|
39
136
|
* (for shopgate-standalone://cart we would get e.g. "authority: cart" which is wrong)
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
|
-
this.
|
|
137
|
+
*/
|
|
138
|
+
urlToSanitize = urlToSanitize.replace(scheme, `${scheme}/`);
|
|
139
|
+
this.parseUrl(urlToSanitize);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
this.scheme = result[1] || '';
|
|
143
|
+
this.authority = result[2] || '';
|
|
144
|
+
this.path = result[3] || '';
|
|
145
|
+
this.query = result[4] || '';
|
|
146
|
+
this.action = ''; // Endpoint - safe for shopgate (ex. no endpoint is converted to "index")
|
|
147
|
+
|
|
148
|
+
if (this.query) {
|
|
149
|
+
const queryParts = this.query.split('&');
|
|
150
|
+
const queryPartsLength = queryParts.length;
|
|
151
|
+
|
|
152
|
+
// Clearing params
|
|
153
|
+
this.setParams({});
|
|
154
|
+
for (let i = 0; i < queryPartsLength; i += 1) {
|
|
155
|
+
const queryPair = queryParts[i].split('=');
|
|
156
|
+
this.setParam(queryPair[0], queryPair[1]);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (this.path) {
|
|
160
|
+
const pathSplitted = this.path.replace('/php/shopgate', '').split('/');
|
|
161
|
+
this.action = pathSplitted[0] || '';
|
|
162
|
+
this.splittedPath = pathSplitted;
|
|
163
|
+
if (pathSplitted[0] === '/' || pathSplitted[0] === '') {
|
|
164
|
+
this.action = pathSplitted[1] || '';
|
|
165
|
+
this.splittedPath.shift();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
43
171
|
* Gets a param
|
|
44
172
|
* @param {string} name name of param
|
|
45
173
|
* @return {string|undefined}
|
|
46
|
-
*/
|
|
174
|
+
*/
|
|
175
|
+
getParam(name) {
|
|
176
|
+
if (!(name in this.params)) {
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
return this.params[name];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
47
183
|
* Sets param.
|
|
48
184
|
* @param {string} name Name of param
|
|
49
185
|
* @param {string} [value] Value of param - if empty, the parameter will be deleted from the query
|
|
50
|
-
*/
|
|
186
|
+
*/
|
|
187
|
+
setParam(name, value) {
|
|
188
|
+
if (typeof value === 'undefined') {
|
|
189
|
+
this.deleteParam(name);
|
|
190
|
+
} else {
|
|
191
|
+
this.params[name] = value;
|
|
192
|
+
this.setParams();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
51
197
|
* Sets params array
|
|
52
198
|
*
|
|
53
199
|
* @param {Object} [newParams] New Params to be set
|
|
54
|
-
*/
|
|
200
|
+
*/
|
|
201
|
+
setParams(newParams) {
|
|
202
|
+
const newQueryArr = [];
|
|
203
|
+
if (typeof newParams !== 'undefined') {
|
|
204
|
+
this.params = newParams;
|
|
205
|
+
}
|
|
206
|
+
Object.keys(this.params).forEach(keyName => {
|
|
207
|
+
newQueryArr.push(`${keyName}=${SGLink.encodeURIComponentSafe(this.params[keyName])}`);
|
|
208
|
+
});
|
|
209
|
+
this.query = newQueryArr.join('&');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
55
213
|
* Safely deletes the param.
|
|
56
214
|
*
|
|
57
215
|
* @param {string} name name of param
|
|
58
216
|
* @returns {boolean}
|
|
59
|
-
*/
|
|
217
|
+
*/
|
|
218
|
+
deleteParam(name) {
|
|
219
|
+
if (!(name in this.params)) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
delete this.params[name];
|
|
223
|
+
this.setParams(this.params);
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
60
228
|
* Converts the object to string
|
|
61
229
|
*
|
|
62
230
|
* @return {string}
|
|
63
|
-
*/
|
|
64
|
-
|
|
65
|
-
outputUrl
|
|
231
|
+
*/
|
|
232
|
+
toString() {
|
|
233
|
+
let outputUrl = '';
|
|
234
|
+
const notNavigatorSchema = ['mailto', 'tel'].indexOf(this.scheme) > -1;
|
|
235
|
+
if (this.scheme) {
|
|
236
|
+
outputUrl += this.scheme;
|
|
237
|
+
|
|
238
|
+
// The sgapi-links don't need further scheme parsing since the scheme is 'sgapi:'
|
|
239
|
+
if (this.scheme !== 'sgapi') {
|
|
240
|
+
if (notNavigatorSchema) {
|
|
241
|
+
if (this.scheme.indexOf(':') === -1) {
|
|
242
|
+
outputUrl += ':';
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
if (this.scheme.indexOf(':/') === -1) {
|
|
246
|
+
// If the scheme already contains :/ we don't want to add it again
|
|
247
|
+
outputUrl += ':/';
|
|
248
|
+
this.scheme = outputUrl;
|
|
249
|
+
}
|
|
250
|
+
if (!this.isDeepLink) {
|
|
251
|
+
outputUrl += '/';
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
} else if (this.scheme.indexOf(':') === -1) {
|
|
255
|
+
outputUrl += ':';
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (this.authority) {
|
|
259
|
+
outputUrl += this.authority;
|
|
260
|
+
}
|
|
261
|
+
outputUrl += this.toRelativeString(false);
|
|
262
|
+
return outputUrl;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
66
265
|
* Sets utm param from event.
|
|
67
266
|
* @param {Object} data event data
|
|
68
267
|
* @param {Object} raw event raw data
|
|
69
|
-
*/
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
268
|
+
*/
|
|
269
|
+
setUtmParams(data, raw) {
|
|
270
|
+
// Add fake params, only if it didn't come from branch.io
|
|
271
|
+
if (raw.type !== 'branchio') {
|
|
272
|
+
this.setParam('utm_source', 'shopgate');
|
|
273
|
+
this.setParam('utm_medium', raw.type);
|
|
274
|
+
}
|
|
275
|
+
if (raw.type === 'push_message') {
|
|
276
|
+
const campaigns = ['cart_reminder', 'inactive_app_user'];
|
|
277
|
+
const notificationId = raw.notificationId || 'not-provided';
|
|
278
|
+
const campaignName = this.getParam('utm_campaign');
|
|
279
|
+
if (campaigns.indexOf(campaignName) !== -1) {
|
|
280
|
+
// Set utm_content to distinguish the cart reminders from "normal" push messages
|
|
281
|
+
this.setParam('utm_content', campaignName);
|
|
282
|
+
}
|
|
283
|
+
this.setParam('utm_campaign', `push-${notificationId}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
package/helpers/optOut.js
CHANGED
|
@@ -1,44 +1,140 @@
|
|
|
1
|
-
|
|
1
|
+
const disableStr = 'sg-tracking-disabled';
|
|
2
|
+
|
|
3
|
+
/**
|
|
2
4
|
* Sets opt out state to localStorage
|
|
3
5
|
* @param {boolean} optOutState true - user opted out of tracking, false - user did not opted out
|
|
4
6
|
* @private
|
|
5
7
|
* @returns {boolean|null} Info about the success
|
|
6
|
-
*/
|
|
8
|
+
*/
|
|
9
|
+
function setLocalStorage(optOutState) {
|
|
10
|
+
if (!(localStorage && localStorage.setItem)) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
if (typeof optOutState !== 'boolean') {
|
|
14
|
+
console.warn('setCookie for outOut invalid param optOutState. Param must be boolean');
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
localStorage.setItem(disableStr, optOutState);
|
|
19
|
+
} catch (e) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return optOutState;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
7
26
|
* Gets optOut state from localStorage
|
|
8
27
|
* @private
|
|
9
28
|
* @returns {boolean|null} Opt out state in the localstorage
|
|
10
|
-
*/
|
|
29
|
+
*/
|
|
30
|
+
function getLocalStorage() {
|
|
31
|
+
if (!(localStorage && localStorage.getItem)) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
let state = localStorage.getItem(disableStr);
|
|
35
|
+
if (state === 'false') {
|
|
36
|
+
state = false;
|
|
37
|
+
} else if (state === 'true') {
|
|
38
|
+
state = true;
|
|
39
|
+
}
|
|
40
|
+
return state;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
11
44
|
* Sets opt out cookie
|
|
12
45
|
* @param {boolean} optOutState true - user opted out of tracking, false - user did not opted out
|
|
13
46
|
* @private
|
|
14
47
|
* @returns {boolean} Info about the success
|
|
15
|
-
*/
|
|
48
|
+
*/
|
|
49
|
+
function setCookie(optOutState) {
|
|
50
|
+
switch (optOutState) {
|
|
51
|
+
case true:
|
|
52
|
+
document.cookie = `${disableStr}=true; expires=Thu, 18 Jan 2038 03:13:59 UTC; path=/`;
|
|
53
|
+
window[disableStr] = true;
|
|
54
|
+
break;
|
|
55
|
+
case false:
|
|
56
|
+
document.cookie = `${disableStr}=false; expires=Thu, 01 Jan 1970 00:00:01 UTC; path=/`;
|
|
57
|
+
window[disableStr] = false;
|
|
58
|
+
break;
|
|
59
|
+
default:
|
|
60
|
+
console.warn('setCookie for outOut invalid param optOutState. Param must be boolean');
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
16
67
|
* Set global + storages
|
|
17
68
|
* @param {boolean} optOutParam If false -> revert the opt out (enable tracking)
|
|
18
69
|
* @private
|
|
19
70
|
* @returns {boolean} optOut State which was set
|
|
20
|
-
*/
|
|
71
|
+
*/
|
|
72
|
+
function setOptOut(optOutParam) {
|
|
73
|
+
window[disableStr] = optOutParam;
|
|
74
|
+
setCookie(optOutParam);
|
|
75
|
+
setLocalStorage(optOutParam);
|
|
76
|
+
return optOutParam;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
21
80
|
* Global helper for the opt out mechanism for all tracking tools
|
|
22
81
|
* Sets information to container and inform whoever should
|
|
23
82
|
* be informed (GA)
|
|
24
83
|
*
|
|
25
84
|
* @param {boolean} [optOutParam = true] If false -> revert the opt out (enable tracking)
|
|
26
85
|
* @returns {boolean} - state which was set
|
|
27
|
-
*/
|
|
86
|
+
*/
|
|
87
|
+
function optOut(optOutParam) {
|
|
88
|
+
let out = optOutParam;
|
|
89
|
+
if (typeof optOutParam === 'undefined') {
|
|
90
|
+
out = true;
|
|
91
|
+
}
|
|
92
|
+
setOptOut(out);
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
28
97
|
* Gets optout state from cookie
|
|
29
98
|
* @private
|
|
30
99
|
* @returns {boolean|null} OptOut state from the cookie
|
|
31
|
-
*/
|
|
100
|
+
*/
|
|
101
|
+
function getCookie() {
|
|
102
|
+
if (document.cookie.indexOf(`${disableStr}=true`) > -1) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
if (document.cookie.indexOf(`${disableStr}=false`) > -1) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
32
112
|
* Check if the opt-out state is set
|
|
33
113
|
*
|
|
34
114
|
* Cookie is privileged.
|
|
35
115
|
*
|
|
36
116
|
* @returns {boolean} Information if the user opt out
|
|
37
|
-
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
117
|
+
*/
|
|
118
|
+
function isOptOut() {
|
|
119
|
+
// Check cookie first
|
|
120
|
+
let optOutState = getCookie();
|
|
121
|
+
|
|
122
|
+
// No cookie info, check localStorage
|
|
123
|
+
if (optOutState === null) {
|
|
124
|
+
optOutState = getLocalStorage();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// No localStorage, we get default value
|
|
128
|
+
if (optOutState === null || typeof optOutState === 'undefined') {
|
|
129
|
+
optOutState = false;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Set global for the environment
|
|
133
|
+
window[disableStr] = optOutState;
|
|
134
|
+
return optOutState;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
42
138
|
* Inits cookie and synchronizes localStorage
|
|
43
139
|
* with information stored in cookie (if needed)
|
|
44
140
|
*
|
|
@@ -46,4 +142,9 @@ window[disableStr]=optOutState;return optOutState;}/**
|
|
|
46
142
|
* not be removed, since localStorage may be purged
|
|
47
143
|
* from time to time (depends on multiple factors
|
|
48
144
|
* like memory usage and etc.).
|
|
49
|
-
*/
|
|
145
|
+
*/
|
|
146
|
+
function init() {
|
|
147
|
+
setOptOut(isOptOut());
|
|
148
|
+
}
|
|
149
|
+
init();
|
|
150
|
+
export { isOptOut, optOut };
|
package/helpers/urlMapping.js
CHANGED
|
@@ -1,27 +1,123 @@
|
|
|
1
|
+
import "core-js/modules/es.string.replace.js";
|
|
1
2
|
/**
|
|
2
3
|
* Data modifier for urls
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* eslint-disable camelcase */
|
|
7
|
+
|
|
8
|
+
// Contains a list of url parameter names that will be removed from the url
|
|
9
|
+
const urlParameterBlacklist = [
|
|
10
|
+
// Tracking parameters that come after switching from http to https
|
|
11
|
+
'SWITCHTOKEN', 'preview', 'emos_sid', 'emos_vid', '_ga', '__utma', '__utmb', '__utmc', '__utmx', '__utmz', '__utmv', '__utmk',
|
|
12
|
+
// Ga parameter for external payment methods
|
|
13
|
+
'utm_nooverride'];
|
|
14
|
+
|
|
15
|
+
/**
|
|
7
16
|
* Returns a path with optional parameters
|
|
8
17
|
* @param {string} pageName Name of the page.
|
|
9
18
|
* @param {string[]} path Path splitted by '/'.
|
|
10
19
|
* @returns {string}
|
|
11
|
-
*/
|
|
20
|
+
*/
|
|
21
|
+
const pathWithParameters = (pageName, path) => {
|
|
22
|
+
if (path.length === 0) {
|
|
23
|
+
return pageName;
|
|
24
|
+
}
|
|
25
|
+
return `${pageName}/${path.join('/')}`;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Mapping function, returns an array.
|
|
12
29
|
// The first value will be for shopgate account, second for merchant
|
|
13
|
-
|
|
30
|
+
const mapping = {
|
|
31
|
+
'': () => 'index',
|
|
32
|
+
favourite_list(path, data) {
|
|
33
|
+
let isEmpty = true;
|
|
34
|
+
if (typeof data.favouriteList.products !== 'undefined' && data.favouriteList.products.length) {
|
|
35
|
+
isEmpty = false;
|
|
36
|
+
}
|
|
37
|
+
return isEmpty ? 'favourite_list_empty' : 'favourite_list';
|
|
38
|
+
},
|
|
39
|
+
cart(path, data) {
|
|
40
|
+
const isEmpty = data.cart.productsCount === 0;
|
|
41
|
+
return isEmpty ? 'cart_empty' : 'cart';
|
|
42
|
+
},
|
|
43
|
+
payment_success: path => {
|
|
44
|
+
if (path.length >= 2) {
|
|
45
|
+
return `checkout_success/${path[1]}`;
|
|
46
|
+
}
|
|
47
|
+
if (path.length === 1) {
|
|
48
|
+
return `checkout_success/${path[0]}`;
|
|
49
|
+
}
|
|
50
|
+
return 'checkout_success';
|
|
51
|
+
},
|
|
52
|
+
checkout_payment: path => pathWithParameters('checkout_payment_and_shipping', path),
|
|
53
|
+
checkout: () => 'checkout',
|
|
54
|
+
payment_failure: path => pathWithParameters('payment_failure', path)
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
14
58
|
* Maps an internal url to an external url that we can send to tracking providers
|
|
15
59
|
*
|
|
16
60
|
* @param {string} url internal url
|
|
17
61
|
* @param {Object} [data] sgData object
|
|
18
62
|
*
|
|
19
63
|
* @returns {Object} external url
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
64
|
+
*/
|
|
65
|
+
function sgTrackingUrlMapper(url, data) {
|
|
66
|
+
// In our development system urls start with /php/shopgate/ always
|
|
67
|
+
const developmentPath = '/php/shopgate/';
|
|
68
|
+
const appRegex = /sg_app_resources\/[0-9]*\//;
|
|
69
|
+
|
|
70
|
+
// Build regex that will remove all blacklisted parameters
|
|
71
|
+
let regex = '';
|
|
72
|
+
urlParameterBlacklist.forEach(entry => {
|
|
73
|
+
regex += `((\\?|^){0,1}(${entry}=.*?(&|$)))`;
|
|
74
|
+
regex += '|';
|
|
75
|
+
});
|
|
76
|
+
const params = url.indexOf('?') !== -1 ? url.split('?')[1] : '';
|
|
77
|
+
let urlParams = params.replace(new RegExp(regex, 'g'), '');
|
|
78
|
+
urlParams = urlParams === '' ? '' : `?${urlParams.replace(/&$/, '')}`;
|
|
79
|
+
|
|
80
|
+
// Get rid of hash and app urls
|
|
81
|
+
let urlPath = url.split('?')[0].split('#')[0].replace(appRegex, '');
|
|
82
|
+
|
|
83
|
+
// Get path from url
|
|
84
|
+
if (url.indexOf(developmentPath) !== -1) {
|
|
85
|
+
urlPath = urlPath.substring(urlPath.indexOf(developmentPath) + developmentPath.length);
|
|
86
|
+
} else if (urlPath.indexOf('http') !== -1) {
|
|
87
|
+
urlPath = urlPath.substring(urlPath.indexOf('/', urlPath.indexOf('//') + 2) + 1);
|
|
88
|
+
} else {
|
|
89
|
+
urlPath = urlPath.substring(1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Get action from path
|
|
93
|
+
const action = urlPath.substring(0, urlPath.indexOf('/') !== -1 ? urlPath.indexOf('/') : undefined);
|
|
94
|
+
|
|
95
|
+
// If no mapping function is available for the action, continue
|
|
96
|
+
if (typeof mapping[action] === 'undefined') {
|
|
97
|
+
return {
|
|
98
|
+
public: urlPath + urlParams,
|
|
99
|
+
private: action
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Call mapping function and return its result
|
|
104
|
+
const pathWithoutAction = urlPath.substring(action.length + 1);
|
|
105
|
+
let pathWithoutActionArray = [];
|
|
106
|
+
if (pathWithoutAction.length !== 0) {
|
|
107
|
+
pathWithoutActionArray = pathWithoutAction.split('/');
|
|
108
|
+
}
|
|
109
|
+
const mappedUrls = mapping[action](pathWithoutActionArray, data || {});
|
|
110
|
+
if (Array.isArray(mappedUrls)) {
|
|
111
|
+
return {
|
|
112
|
+
public: mappedUrls[1] + urlParams,
|
|
113
|
+
private: mappedUrls[0]
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
public: mappedUrls + urlParams,
|
|
118
|
+
private: mappedUrls
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
export default sgTrackingUrlMapper;
|
|
122
|
+
|
|
123
|
+
/* eslint-enable camelcase */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shopgate/tracking-core",
|
|
3
|
-
"version": "7.30.0-alpha.
|
|
3
|
+
"version": "7.30.0-alpha.8",
|
|
4
4
|
"description": "Tracking core library for the Shopgate Connect PWA.",
|
|
5
5
|
"author": "Shopgate <support@shopgate.com>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"connect"
|
|
17
17
|
],
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@shopgate/eslint-config": "7.30.0-alpha.
|
|
20
|
-
"@shopgate/pwa-core": "7.30.0-alpha.
|
|
19
|
+
"@shopgate/eslint-config": "7.30.0-alpha.8",
|
|
20
|
+
"@shopgate/pwa-core": "7.30.0-alpha.8",
|
|
21
21
|
"chai": "^3.5.0",
|
|
22
22
|
"jsdom": "^10.0.0",
|
|
23
23
|
"mocha": "^3.1.0",
|