@miso.ai/client-sdk-ui 1.10.0-beta.8 → 1.10.0

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.
Files changed (51) hide show
  1. package/dist/cjs/actor/index.js +0 -7
  2. package/dist/cjs/actor/tracker.js +47 -97
  3. package/dist/cjs/actor/utils.js +3 -1
  4. package/dist/cjs/actor/view.js +12 -1
  5. package/dist/cjs/actor/views.js +24 -2
  6. package/dist/cjs/affiliation/index.js +26 -10
  7. package/dist/cjs/asset/svgs.js +14 -4
  8. package/dist/cjs/constants.js +3 -2
  9. package/dist/cjs/layout/affiliation/affiliation.js +263 -13
  10. package/dist/cjs/layout/input/option-list.js +34 -49
  11. package/dist/cjs/layout/list/collection.js +24 -45
  12. package/dist/cjs/layout/templates.js +54 -32
  13. package/dist/cjs/layout/text/typewriter/index.js +12 -7
  14. package/dist/cjs/layout/trackable.js +124 -0
  15. package/dist/cjs/util/bindings.js +58 -110
  16. package/dist/cjs/util/states.js +31 -24
  17. package/dist/cjs/util/trackers.js +75 -0
  18. package/dist/cjs/util/viewables.js +55 -0
  19. package/dist/cjs/version.js +1 -1
  20. package/dist/cjs/workflow/ask.js +1 -2
  21. package/dist/cjs/workflow/base.js +2 -7
  22. package/dist/cjs/workflow/recommendation.js +2 -0
  23. package/package.json +2 -2
  24. package/src/actor/index.js +0 -1
  25. package/src/actor/tracker.js +37 -88
  26. package/src/actor/utils.js +3 -1
  27. package/src/actor/view.js +14 -1
  28. package/src/actor/views.js +30 -1
  29. package/src/affiliation/index.js +25 -8
  30. package/src/asset/svgs.js +13 -2
  31. package/src/constants.js +7 -1
  32. package/src/layout/affiliation/affiliation.js +247 -14
  33. package/src/layout/input/option-list.js +35 -43
  34. package/src/layout/list/collection.js +22 -40
  35. package/src/layout/templates.js +25 -19
  36. package/src/layout/text/typewriter/index.js +8 -6
  37. package/src/layout/trackable.js +106 -0
  38. package/src/util/bindings.js +47 -103
  39. package/src/util/states.js +26 -20
  40. package/src/util/trackers.js +69 -0
  41. package/src/util/viewables.js +47 -0
  42. package/src/version.js +1 -1
  43. package/src/workflow/ask.js +1 -2
  44. package/src/workflow/base.js +3 -5
  45. package/src/workflow/recommendation.js +1 -0
  46. package/dist/cjs/actor/trackers.js +0 -51
  47. package/dist/cjs/layout/text/typewriter/progress.js +0 -45
  48. package/dist/cjs/util/tracker.js +0 -348
  49. package/src/actor/trackers.js +0 -45
  50. package/src/layout/text/typewriter/progress.js +0 -33
  51. package/src/util/tracker.js +0 -318
@@ -25,6 +25,8 @@ exports.titleBlock = titleBlock;
25
25
  exports.unimplemented = unimplemented;
26
26
  var _commons = require("@miso.ai/commons");
27
27
  var _constants = require("../constants.js");
28
+ const _excluded = ["classSuffix", "role"];
29
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
28
30
  function requiresImplementation() {
29
31
  for (var _len = arguments.length, names = new Array(_len), _key = 0; _key < _len; _key++) {
30
32
  names[_key] = arguments[_key];
@@ -61,8 +63,12 @@ function affiliation(layout, state, data, meta) {
61
63
  const {
62
64
  templates
63
65
  } = layout;
64
- const [openTag, closeTag] = tagPair(layout, data);
65
- return [openTag, (templates.infoBlock || templates.affiliationInfoBlock || affiliationInfoBlock)(layout, data, meta), (templates.imageBlock || imageBlock)(layout, data, meta), (templates.brandBlock || brandBlock)(layout, data, meta), closeTag].join('');
66
+ const [openTag, closeTag] = tagPair(layout, data, {
67
+ link: false
68
+ });
69
+ return [openTag, (templates.infoBlock || templates.affiliationInfoBlock || affiliationInfoBlock)(layout, data, meta), (templates.imageBlock || imageBlock)(layout, data, Object.assign({
70
+ brand: true
71
+ }, meta)), closeTag].join('');
66
72
  }
67
73
  function affiliationInfoBlock(layout, data, meta) {
68
74
  const {
@@ -156,7 +162,9 @@ function priceBlock(layout, data) {
156
162
  content += `<span class="${className}__item-price miso-price" data-currency="${currency}">${price}</span>`;
157
163
  // discount rate
158
164
  if (discount_rate_percent) {
159
- const text = (templates.discountRateText || discountRateText)(layout, data);
165
+ const text = (templates.discountRateText || discountRateText)(layout, Object.assign({}, data, {
166
+ discount_rate_percent
167
+ }));
160
168
  content += ` <span class="${className}__item-discount-rate">${text}</span>`;
161
169
  }
162
170
  return `<div class="${className}__item-price-container">${content}</div>`;
@@ -167,26 +175,28 @@ function discountRateText(layout, _ref9) {
167
175
  } = _ref9;
168
176
  return `(${discount_rate_percent}% off)`;
169
177
  }
170
- function imageBlock(_ref10, _ref11) {
171
- let {
172
- className
173
- } = _ref10;
174
- let {
178
+ function imageBlock(layout, data, meta) {
179
+ const {
180
+ className,
181
+ templates
182
+ } = layout;
183
+ const {
175
184
  cover_image
176
- } = _ref11;
185
+ } = data;
177
186
  if (!cover_image) {
178
187
  return '';
179
188
  }
180
189
  const img = `<img class="${className}__item-cover-image" src="${cover_image}">`;
181
- return `<div class="${className}__item-cover-image-container">${img}</div>`;
190
+ const brand = meta.brand ? (templates.brandBlock || brandBlock)(layout, data, meta) : '';
191
+ return `<div class="${className}__item-cover-image-container">${img}${brand}</div>`;
182
192
  }
183
- function indexBlock(_ref12, data, _ref13) {
193
+ function indexBlock(_ref10, data, _ref11) {
184
194
  let {
185
195
  className
186
- } = _ref12;
196
+ } = _ref10;
187
197
  let {
188
198
  index
189
- } = _ref13;
199
+ } = _ref11;
190
200
  return `<div class="${className}__item-index-container"><span class="${className}__item-index miso-citation-index" data-index="${index + 1}"></span></div>`;
191
201
  }
192
202
  function ctaBlock(layout, data, meta) {
@@ -194,38 +204,45 @@ function ctaBlock(layout, data, meta) {
194
204
  className,
195
205
  templates
196
206
  } = layout;
197
- let _cta = templates.cta || cta;
198
- if (typeof _cta === 'function') {
199
- _cta = _cta(layout, data, meta);
200
- }
201
- return _cta ? `<div class="${className}__item-cta-container">${_cta}</div>` : '';
207
+ const cta = helpers.asFunction(templates.cta)(layout, data, meta);
208
+ return cta ? `<div class="${className}__item-cta-container">${cta}</div>` : '';
202
209
  }
203
210
  function cta(layout, data, meta) {
204
211
  const {
205
- className,
206
212
  templates
207
213
  } = layout;
208
- let text = templates.ctaText;
209
- if (typeof text === 'function') {
210
- text = text(layout, data, meta);
214
+ const {
215
+ url
216
+ } = data;
217
+ if (!url) {
218
+ return '';
211
219
  }
212
- return text ? `<div class="${className}__item-cta">${text}</div>` : '';
220
+ const [openTag, closeTag] = tagPair(layout, {
221
+ url
222
+ }, {
223
+ classSuffix: 'item-cta',
224
+ role: 'cta'
225
+ });
226
+ const ctaText = helpers.asFunction(templates.ctaText)(layout, data, meta);
227
+ return ctaText ? `${openTag}${ctaText}${closeTag}` : '';
213
228
  }
214
229
 
215
230
  // helpers //
216
- function tagPair(_ref14, _ref15) {
231
+ function tagPair(_ref13, _ref14) {
217
232
  let {
218
233
  className,
219
234
  options = {}
220
- } = _ref14;
235
+ } = _ref13;
221
236
  let {
222
237
  product_id,
223
238
  url
224
- } = _ref15;
239
+ } = _ref14;
240
+ let _ref12 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
225
241
  let {
226
- classSuffix = 'item-body',
227
- role = 'item'
228
- } = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
242
+ classSuffix = 'item-body',
243
+ role = 'item'
244
+ } = _ref12,
245
+ meta = _objectWithoutPropertiesLoose(_ref12, _excluded);
229
246
  const {
230
247
  link = {}
231
248
  } = options;
@@ -233,8 +250,8 @@ function tagPair(_ref14, _ref15) {
233
250
  target = '_blank',
234
251
  rel = 'noopener'
235
252
  } = link; // TODO: other properties
236
- const tag = url ? 'a' : 'div';
237
- const urlAttrs = url ? `href="${url}" target="${target}" rel="${rel}"` : '';
253
+ const tag = meta.link !== false && url ? 'a' : 'div';
254
+ const urlAttrs = meta.link !== false && url ? `href="${url}" target="${target}" rel="${rel}"` : '';
238
255
  const productAttrs = product_id ? `${_constants.ATTR_DATA_MISO_PRODUCT_ID}="${product_id}"` : '';
239
256
  const roleAttrs = role ? `data-role="${role}"` : '';
240
257
  return [`<${tag} class="${className}__${classSuffix}" ${roleAttrs} ${productAttrs} ${urlAttrs}>`, `</${tag}>`];
@@ -258,8 +275,13 @@ function formatDate(date) {
258
275
  throw new Error(`Invalid date format: ${fn}`);
259
276
  }
260
277
  }
278
+ function asFunction() {
279
+ let template = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
280
+ return typeof template === 'function' ? template : () => template;
281
+ }
261
282
  const helpers = exports.helpers = Object.freeze({
262
283
  tagPair,
263
284
  formatDate,
264
- escapeHtml: _commons.escapeHtml
285
+ escapeHtml: _commons.escapeHtml,
286
+ asFunction
265
287
  });
@@ -7,10 +7,9 @@ exports.default = void 0;
7
7
  var _commons = require("@miso.ai/commons");
8
8
  var _constants = require("../../../constants.js");
9
9
  var _progressive = _interopRequireDefault(require("../../progressive.js"));
10
- var _progress = _interopRequireDefault(require("./progress.js"));
11
10
  var _plaintext = _interopRequireDefault(require("./plaintext.js"));
12
11
  var _utils = require("./utils.js");
13
- const _excluded = ["className", "tag", "format", "tooltip"];
12
+ const _excluded = ["className", "tag", "format", "tooltip", "speed", "acceleration", "nextCursorFn"];
14
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
14
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
16
15
  const TYPE = 'typewriter';
@@ -31,7 +30,10 @@ class TypewriterLayout extends _progressive.default {
31
30
  className = DEFAULT_CLASSNAME,
32
31
  tag = 'auto',
33
32
  format = 'markdown',
34
- tooltip = false
33
+ tooltip = false,
34
+ speed,
35
+ acceleration,
36
+ nextCursorFn
35
37
  } = _ref,
36
38
  options = _objectWithoutPropertiesLoose(_ref, _excluded);
37
39
  super(Object.assign({
@@ -43,7 +45,10 @@ class TypewriterLayout extends _progressive.default {
43
45
  className
44
46
  });
45
47
  this._prevState = undefined;
46
- this._progress = new _progress.default(options);
48
+ this._getNextCursor = typeof nextCursorFn === 'function' ? nextCursorFn : (0, _commons.pacer)({
49
+ speed,
50
+ acceleration
51
+ });
47
52
  this._readiness = new _commons.Resolution();
48
53
 
49
54
  // kick off sooner
@@ -86,7 +91,7 @@ class TypewriterLayout extends _progressive.default {
86
91
  onDebug
87
92
  });
88
93
  // capture citation link click if necessary
89
- this._unsubscribes.push(this._view.proxyElement.on('click', e => this._handleClick(e)));
94
+ this._unsubscribes.push(this._view.proxyElement.on('click', e => this._onClick(e)));
90
95
  }
91
96
  _getSource(index) {
92
97
  const {
@@ -154,7 +159,7 @@ class TypewriterLayout extends _progressive.default {
154
159
  // new typing streak
155
160
  result = this._renderer.clear(container, rendered);
156
161
  } else {
157
- const cursor = this._progress.get(rendered, state);
162
+ const cursor = this._getNextCursor(rendered.cursor, state.doneAt, rendered.timestamp, state.timestamp);
158
163
  result = this._renderer.update(container, rendered, Object.assign({}, state, {
159
164
  cursor
160
165
  }));
@@ -172,7 +177,7 @@ class TypewriterLayout extends _progressive.default {
172
177
  }
173
178
 
174
179
  // event //
175
- _handleClick(_ref5) {
180
+ _onClick(_ref5) {
176
181
  let {
177
182
  target
178
183
  } = _ref5;
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.TrackableMixin = void 0;
7
+ exports.makeTrackable = makeTrackable;
8
+ var _constants = require("../constants.js");
9
+ var _bindings = _interopRequireDefault(require("../util/bindings.js"));
10
+ var _viewables = _interopRequireDefault(require("../util/viewables.js"));
11
+ var _trackers = require("../util/trackers.js");
12
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
+ function makeTrackable(prototype) {
14
+ _mixin(prototype, TrackableMixin.prototype);
15
+ }
16
+ function _mixin(target, source) {
17
+ const descriptors = Object.getOwnPropertyDescriptors(source);
18
+ for (const key in descriptors) {
19
+ if (key === 'constructor') {
20
+ continue;
21
+ }
22
+ const {
23
+ value
24
+ } = descriptors[key];
25
+ if (target[key] === undefined && typeof value === 'function') {
26
+ target[key] = value;
27
+ }
28
+ // TODO: getter, setter
29
+ }
30
+ }
31
+ class TrackableMixin {
32
+ _initTrackable() {
33
+ this._bindings = new _bindings.default();
34
+ this._viewables = new _viewables.default();
35
+ }
36
+ _syncBindings(element, state) {
37
+ const values = this._getItems(state) || [];
38
+ const keys = values.map(value => this._getItemKey(value));
39
+ const elements = this._getItemElements(element);
40
+ const {
41
+ bounds,
42
+ unbounds
43
+ } = this._bindings.update(keys, values, elements);
44
+ this._onBindingsUpdate(bounds, unbounds);
45
+ }
46
+ _clearBindings() {
47
+ const {
48
+ bounds,
49
+ unbounds
50
+ } = this._bindings.clear();
51
+ this._onBindingsUpdate(bounds, unbounds);
52
+ }
53
+ _getItemKey(value) {
54
+ // TODO: ad-hoc!
55
+ return value.product_id || value.text || value.id || value;
56
+ }
57
+ _getItems(state) {
58
+ throw new Error(`Not implemented.`);
59
+ }
60
+ _getItemElements(element) {
61
+ throw new Error(`Not implemented.`);
62
+ }
63
+ _onBindingsUpdate(bounds, unbounds) {
64
+ this._trackImpressions(bounds);
65
+ this._untrackViewables(unbounds);
66
+ this._trackViewables(bounds);
67
+ }
68
+ _trackImpressions(entries) {
69
+ if (entries.length === 0) {
70
+ return;
71
+ }
72
+ const {
73
+ impression: options
74
+ } = this._view.tracker.options || {};
75
+ if (!options) {
76
+ return;
77
+ }
78
+ this._view.tracker.impression(entries.map(_ref => {
79
+ let {
80
+ value
81
+ } = _ref;
82
+ return value;
83
+ }));
84
+ }
85
+ _untrackViewables(entries) {
86
+ for (const {
87
+ element
88
+ } of entries) {
89
+ this._viewables.untrack(element);
90
+ }
91
+ }
92
+ _trackViewables(entries) {
93
+ if (entries.length === 0) {
94
+ return;
95
+ }
96
+ const {
97
+ viewable: options
98
+ } = this._view.tracker.options || {};
99
+ if (!options) {
100
+ return;
101
+ }
102
+ for (const {
103
+ value,
104
+ element
105
+ } of entries) {
106
+ (async () => (await this._viewables.track(element, options)) && this._view.tracker.viewable([value]))();
107
+ }
108
+ }
109
+ _trackClick(event, binding) {
110
+ const {
111
+ click: options
112
+ } = this._view.tracker.options || {};
113
+ if ((0, _trackers.validateClick)(options, event, binding)) {
114
+ this._view.tracker.click([binding.value]);
115
+ }
116
+ }
117
+ _destroyTrackable() {
118
+ const {
119
+ unbounds
120
+ } = this._bindings.clear();
121
+ this._untrackViewables(unbounds);
122
+ }
123
+ }
124
+ exports.TrackableMixin = TrackableMixin;
@@ -3,131 +3,79 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.Bindings = void 0;
7
- exports.fallbackListFunction = fallbackListFunction;
8
- var _commons = require("@miso.ai/commons");
9
- function fallbackListFunction(keyAttrName) {
10
- return element => Array.from(element.querySelectorAll(`[${keyAttrName}]`)).map(element => ({
11
- element,
12
- value: {
13
- product_id: element.getAttribute(keyAttrName) // TODO: product_id is ad-hoc
6
+ exports.default = void 0;
7
+ function tuple(keys, values, elements) {
8
+ const k2b = new Map();
9
+ const e2b = new Map();
10
+ const entries = [];
11
+ for (let index = 0; index < keys.length; index++) {
12
+ const key = keys[index];
13
+ const element = elements[index];
14
+ const value = values[index];
15
+ const entry = Object.freeze({
16
+ index,
17
+ key,
18
+ value,
19
+ element
20
+ });
21
+ k2b.set(key, entry);
22
+ e2b.set(element, entry);
23
+ entries.push(entry);
24
+ }
25
+ return {
26
+ k2b,
27
+ e2b,
28
+ entries
29
+ };
30
+ }
31
+ function diff(from, to) {
32
+ const entries = [];
33
+ for (const entry of to.entries) {
34
+ const f = from.e2b.get(entry.element);
35
+ if (!f || f.key !== entry.key) {
36
+ entries.push(entry);
14
37
  }
15
- }));
38
+ }
39
+ return entries;
16
40
  }
17
41
  class Bindings {
18
42
  constructor() {
19
- let {
20
- keyAttrName = 'data-key',
21
- list
22
- } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
23
- this._list = list || fallbackListFunction(keyAttrName);
24
- this._bindings = new Map();
25
- this._e2b = new WeakMap();
43
+ this._k2b = new Map();
44
+ this._e2b = new Map();
45
+ this._entries = [];
26
46
  }
27
- list() {
28
- return [...this._bindings.values()];
47
+ get entries() {
48
+ return [...this._entries];
29
49
  }
30
- get(ref) {
31
- if (!ref) {
32
- throw new Error(`Value or element is required.`);
33
- }
34
- if (!this._root) {
35
- return undefined;
36
- }
37
- if (!(0, _commons.isElement)(ref)) {
38
- return this._bindings.get(ref);
39
- }
40
- return (0, _commons.findInAncestors)(ref, element => this._e2b.get(element) || undefined, {
41
- root: this._root
42
- });
50
+ get(element) {
51
+ return this._e2b.get(element) || undefined;
43
52
  }
44
- refresh(rootElement) {
45
- if (!rootElement) {
46
- return this.unbindAll();
47
- }
48
- this._root = rootElement;
49
- const unbounds = this._purge();
50
- const bounds = [];
51
- // warn for conflict productIds
52
- // TODO
53
- for (const pair of this._list(rootElement)) {
54
- const [binding, ...ubs] = this._bind(pair);
55
- if (binding) {
56
- bounds.push(binding);
57
- }
58
- for (const u of ubs) {
59
- unbounds.push(u);
60
- }
61
- }
53
+ update(keys, values, elements) {
54
+ const newTuple = tuple(keys, values, elements);
55
+ const oldTuple = {
56
+ k2b: this._k2b,
57
+ e2b: this._e2b,
58
+ entries: this._entries
59
+ };
60
+ const bounds = diff(oldTuple, newTuple);
61
+ const unbounds = diff(newTuple, oldTuple);
62
+ this._k2b = newTuple.k2b;
63
+ this._e2b = newTuple.e2b;
64
+ this._entries = newTuple.entries;
62
65
  return {
63
66
  bounds,
64
67
  unbounds
65
68
  };
66
69
  }
67
- unbindAll() {
68
- const unbounds = this.list();
69
- this._bindings.clear();
70
- this._root = undefined;
70
+ clear() {
71
+ const unbounds = this._entries;
72
+ this._k2b = new Map();
73
+ this._e2b = new Map();
74
+ this._entries = [];
71
75
  return {
72
76
  bounds: [],
73
77
  unbounds
74
78
  };
75
79
  }
76
- _bind(_ref) {
77
- let {
78
- element,
79
- key,
80
- value
81
- } = _ref;
82
- key = key || value;
83
- if (!key) {
84
- throw new Error(`Key or value is required.`);
85
- }
86
- if (!element) {
87
- throw new Error(`Element is required.`);
88
- }
89
-
90
- // check if binding already exist
91
- const oldBinding = this._bindings.get(key);
92
- if (oldBinding && oldBinding.element === element) {
93
- return [];
94
- }
95
- const unbound0 = this._unbind(this.get(key));
96
- const unbound1 = this._unbind(this.get(element));
97
- const binding = Object.freeze({
98
- key,
99
- value,
100
- element
101
- });
102
- this._bindings.set(key, binding);
103
- this._e2b.set(element, binding);
104
- const results = [binding];
105
- unbound0 && results.push(unbound0);
106
- unbound1 && results.push(unbound1);
107
- return results;
108
- }
109
- _purge() {
110
- const purged = [];
111
- for (const binding of this._bindings.values()) {
112
- const {
113
- element
114
- } = binding;
115
- if ((0, _commons.isInDocument)(element)) {
116
- continue;
117
- }
118
- purged.push(this._unbind(binding));
119
- }
120
- return purged;
121
- }
122
- _unbind(binding) {
123
- if (binding) {
124
- this._bindings.delete(binding.key);
125
- this._e2b.delete(binding.element);
126
- }
127
- return binding;
128
- }
129
- _destroy() {
130
- this.unbindAll();
131
- }
132
80
  }
133
- exports.Bindings = Bindings;
81
+ exports.default = Bindings;
@@ -15,55 +15,62 @@ const {
15
15
  UNTRACKED,
16
16
  TRIGGERED
17
17
  } = _constants.TRACKING_STATUS;
18
+
19
+ /*
18
20
  const STATES = {
19
21
  NEW: Object.freeze({
20
22
  [IMPRESSION]: UNTRACKED,
21
- [VIEWABLE]: UNTRACKED
23
+ [VIEWABLE]: UNTRACKED,
22
24
  }),
23
25
  UNTRACKED: Object.freeze({
24
26
  [IMPRESSION]: UNTRACKED,
25
27
  [VIEWABLE]: UNTRACKED,
26
- [CLICK]: UNTRACKED
27
- })
28
+ [CLICK]: UNTRACKED,
29
+ }),
28
30
  };
31
+ */
32
+
33
+ const UNTRACKED_STATES = Object.freeze({
34
+ [IMPRESSION]: UNTRACKED,
35
+ [VIEWABLE]: UNTRACKED,
36
+ [CLICK]: UNTRACKED
37
+ });
29
38
 
30
39
  /**
31
40
  * Tracking states for a session to keep track of the tracking status of each product.
32
- * For each entry there are status of impression, viewable, and click events.
33
- * The actual click tracking status depends on the presence of root element, which is not respected in this object.
41
+ * For each entry there are status of impression, viewable, and click events.
34
42
  */
35
43
  class States {
36
44
  constructor(sessionId) {
37
45
  this.sessionId = sessionId;
38
- this._states = new Map(); // productId -> {impression, viewable, click}
46
+ this._states = new Map(); // item key -> {impression, viewable, click}
39
47
  }
40
- getFullState(productId) {
48
+ getFullState(item) {
41
49
  // when we receive a bind event, impression is trigger, making an entry here
42
50
  // so if the state is not found, the product is not present yet => all untracked
43
- const state = this._states.get(getKey(productId));
44
- return state ? Object.assign({}, state) : STATES.UNTRACKED;
51
+ const state = this._states.get(this._getKey(item));
52
+ return state ? Object.assign({}, state) : UNTRACKED_STATES;
45
53
  }
46
- get(productId, type) {
47
- const state = this._states.get(getKey(productId));
54
+ get(item, type) {
55
+ const state = this._states.get(this._getKey(item));
48
56
  return state && state[type] || UNTRACKED;
49
57
  }
50
- set(productIds, type, status) {
58
+ set(items, type, status) {
51
59
  (0, _constants.validateEventType)(type);
52
60
  (0, _constants.validateTrackingStatus)(status);
53
- for (const productId of (0, _commons.asArray)(productIds)) {
54
- this._setOne(getKey(productId), type, status);
61
+ for (const item of (0, _commons.asArray)(items)) {
62
+ this._setOne(item, type, status);
55
63
  }
56
64
  }
57
- _setOne(productId, type, status) {
58
- // leave click untracked/tracking judged by its global state
59
- (0, _commons.computeIfAbsent)(this._states, productId, () => Object.assign({}, STATES.NEW))[type] = status;
65
+ untriggered(items, type) {
66
+ return items.filter(item => this.get(item, type) !== TRIGGERED);
67
+ }
68
+ _getKey(item) {
69
+ // TODO: ad-hoc! should move away to higher level
70
+ return item.product_id || item.text || item.id || item;
60
71
  }
61
- untriggered(productIds, type) {
62
- return productIds.filter(productId => this.get(productId, type) !== TRIGGERED);
72
+ _setOne(item, type, status) {
73
+ (0, _commons.computeIfAbsent)(this._states, this._getKey(item), () => Object.assign({}, UNTRACKED_STATES))[type] = status;
63
74
  }
64
75
  }
65
- exports.default = States;
66
- function getKey(value) {
67
- // TODO: ad-hoc!
68
- return value.product_id || value.text || value;
69
- }
76
+ exports.default = States;