@miso.ai/client-sdk-ui 1.11.4 → 1.11.5-beta.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 (39) hide show
  1. package/dist/cjs/actor/views.js +1 -0
  2. package/dist/cjs/asset/svgs.js +10 -4
  3. package/dist/cjs/constants.js +3 -2
  4. package/dist/cjs/element/role/index.js +7 -0
  5. package/dist/cjs/element/role/miso-images.js +20 -0
  6. package/dist/cjs/layout/input/option-list.js +1 -1
  7. package/dist/cjs/layout/input/select.js +1 -1
  8. package/dist/cjs/layout/list/carousel.js +43 -84
  9. package/dist/cjs/layout/list/collection.js +11 -5
  10. package/dist/cjs/layout/mixin/swipeable.js +165 -0
  11. package/dist/cjs/layout/{trackable.js → mixin/trackable.js} +4 -3
  12. package/dist/cjs/layout/{triggerable.js → mixin/triggerable.js} +2 -2
  13. package/dist/cjs/layout/radio/radio.js +11 -7
  14. package/dist/cjs/layout/templates.js +24 -5
  15. package/dist/cjs/layout/text/typewriter/index.js +2 -0
  16. package/dist/cjs/util/trackers.js +18 -5
  17. package/dist/cjs/version.js +1 -1
  18. package/dist/cjs/workflow/answer-based.js +23 -4
  19. package/dist/cjs/workflow/search.js +0 -1
  20. package/package.json +2 -2
  21. package/src/actor/views.js +1 -0
  22. package/src/asset/svgs.js +9 -1
  23. package/src/constants.js +3 -0
  24. package/src/element/role/index.js +1 -0
  25. package/src/element/role/miso-images.js +16 -0
  26. package/src/layout/input/option-list.js +1 -1
  27. package/src/layout/input/select.js +1 -1
  28. package/src/layout/list/carousel.js +39 -86
  29. package/src/layout/list/collection.js +13 -6
  30. package/src/layout/mixin/swipeable.js +162 -0
  31. package/src/layout/{trackable.js → mixin/trackable.js} +4 -3
  32. package/src/layout/{triggerable.js → mixin/triggerable.js} +2 -2
  33. package/src/layout/radio/radio.js +7 -7
  34. package/src/layout/templates.js +26 -5
  35. package/src/layout/text/typewriter/index.js +2 -1
  36. package/src/util/trackers.js +17 -4
  37. package/src/version.js +1 -1
  38. package/src/workflow/answer-based.js +14 -4
  39. package/src/workflow/search.js +0 -1
@@ -50,7 +50,7 @@ export default class RadioLayout extends TemplateBasedLayout {
50
50
  view.hub.on(this._field, () => this._refresh()),
51
51
  proxyElement.on('click', (e) => this._handleClick(e)),
52
52
  ];
53
- this._defaultValue ? this._select(this._defaultValue) : this._clear();
53
+ this._defaultValue ? this._select(this._defaultValue, { silent: true }) : this._clear({ silent: true });
54
54
  }
55
55
 
56
56
  _preprocess(states, controls) {
@@ -98,16 +98,16 @@ export default class RadioLayout extends TemplateBasedLayout {
98
98
  this._state = undefined;
99
99
  }
100
100
 
101
- _select(value) {
102
- this._submit({ value });
101
+ _select(value, options) {
102
+ this._submit({ value }, options);
103
103
  }
104
104
 
105
- _clear() {
106
- this._submit({ unselected: true });
105
+ _clear(options) {
106
+ this._submit({ unselected: true }, options);
107
107
  }
108
108
 
109
- async _submit(state) {
110
- this._view.hub.update(this._field, state);
109
+ async _submit(state, options) {
110
+ this._view.hub.update(this._field, state, options);
111
111
  }
112
112
 
113
113
  }
@@ -42,6 +42,17 @@ export function article(layout, state, data, meta) {
42
42
  ].join('');
43
43
  }
44
44
 
45
+ export function image(layout, state, data, meta) {
46
+ const { templates } = layout;
47
+ const [openTag, closeTag] = tagPair(layout, data);
48
+ return [
49
+ openTag,
50
+ (templates.imageBlock || imageBlock)(layout, data, meta),
51
+ (templates.infoBlock || templates.imageInfoBlock || imageInfoBlock)(layout, data, meta),
52
+ closeTag,
53
+ ].join('');
54
+ }
55
+
45
56
  export function affiliation(layout, state, data, meta) {
46
57
  const { templates } = layout;
47
58
  const [openTag, closeTag] = tagPair(layout, data, { link: false});
@@ -82,6 +93,13 @@ export function articleInfoBlock(layout, data, meta) {
82
93
  ].join('')}</div>`;
83
94
  }
84
95
 
96
+ export function imageInfoBlock(layout, data, meta) {
97
+ const { className, templates } = layout;
98
+ return `<div class="${className}__item-info-container">${[
99
+ (templates.titleBlock || titleBlock)(layout, data, meta),
100
+ ].join('')}</div>`;
101
+ }
102
+
85
103
  export function titleBlock({ className }, { title }) {
86
104
  return title ? `<div class="${className}__item-title">${escapeHtml(title)}</div>` : '';
87
105
  }
@@ -134,13 +152,16 @@ export function discountRateText(layout, { discount_rate_percent }) {
134
152
 
135
153
  export function imageBlock(layout, data, meta = {}) {
136
154
  const { className, templates } = layout;
137
- const { cover_image } = data;
138
- if (!cover_image) {
155
+ const { cover_image, image_src, image_alt } = data;
156
+ if (!cover_image && !image_src) {
139
157
  return '';
140
158
  }
141
- const img = `<img class="${className}__item-cover-image" src="${cover_image}">`;
142
- const brand = meta.brand ? (templates.brandBlock || brandBlock)(layout, data, meta) : '';
143
- return `<div class="${className}__item-cover-image-container">${img}${brand}</div>`;
159
+ const subtype = image_src ? 'image' : 'cover-image';
160
+ const img = subtype === 'image' ?
161
+ `<img class="${className}__item-${subtype}" src="${image_src}"${image_alt ? ` alt="${image_alt}"` : ''}>` :
162
+ `<img class="${className}__item-${subtype}" src="${cover_image}">`;
163
+ const brand = subtype === 'cover-image' && meta.brand ? (templates.brandBlock || brandBlock)(layout, data, meta) : '';
164
+ return `<div class="${className}__item-${subtype}-container">${img}${brand}</div>`;
144
165
  }
145
166
 
146
167
  export function indexBlock({ className }, data, { index }) {
@@ -157,7 +157,7 @@ export default class TypewriterLayout extends ProgressiveLayout {
157
157
  if (citationLinkElement) {
158
158
  const index = parseInt(citationLinkElement.dataset.index);
159
159
  if (!Number.isNaN(index)) {
160
- this._view._events.emit('citation-click', { index });
160
+ this._view._events.emit('citation-click', { event, index });
161
161
  }
162
162
  return;
163
163
  }
@@ -169,6 +169,7 @@ export default class TypewriterLayout extends ProgressiveLayout {
169
169
  const { href, innerText, className } = anchorElement;
170
170
  if (href) {
171
171
  this._view._events.emit('link-click', trimObj({
172
+ event,
172
173
  url: href,
173
174
  text: innerText ? innerText.trim() : '',
174
175
  className: className || '',
@@ -1,6 +1,14 @@
1
1
  import { findInAncestors, trimObj } from '@miso.ai/commons';
2
2
 
3
- // TODO: think about how to incorporate this with workflow options
3
+ const TRACKED = Symbol.for('miso:tracked');
4
+
5
+ export function isTracked(event) {
6
+ return !!event[TRACKED];
7
+ }
8
+
9
+ export function markAsTracked(event) {
10
+ event[TRACKED] = true;
11
+ }
4
12
 
5
13
  const DEFAULT_TRACKER_OPTIONS = Object.freeze({
6
14
  impression: Object.freeze({
@@ -19,6 +27,7 @@ function mergeOptions(def, opt) {
19
27
  return !!opt && { ...def, ...opt };
20
28
  }
21
29
 
30
+ // TODO: don't need this anymore
22
31
  export function normalizeTrackerOptions(options) {
23
32
  // TODO: make this { active: false } to keep it an object
24
33
  if (options === false) {
@@ -54,15 +63,19 @@ export function validateClick(options = {}, event) {
54
63
  }
55
64
 
56
65
  // standard criteria
57
- // 1. it must be a left click
66
+ // 1. each event can only be tracked once
67
+ if (isTracked(event)) {
68
+ return false;
69
+ }
70
+ // 2. it must be a left click
58
71
  if (event.button !== 0) {
59
72
  return false;
60
73
  }
61
- // 2. event default must not be prevented
74
+ // 3. event default must not be prevented
62
75
  if (event.defaultPrevented) {
63
76
  return false;
64
77
  }
65
- // 3. must go through a real link
78
+ // 4. must go through a real link
66
79
  if (!findInAncestors(event.target, element => (element.tagName === 'A' && element.href) || undefined)) {
67
80
  return false;
68
81
  }
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export default '1.11.4';
1
+ export default '1.11.5-beta.0';
@@ -2,11 +2,12 @@ import { API } from '@miso.ai/commons';
2
2
  import Workflow from './base.js';
3
3
  import { fields, FeedbackActor } from '../actor/index.js';
4
4
  import { ROLE, STATUS, ORGANIC_QUESTION_SOURCE } from '../constants.js';
5
- import { SearchBoxLayout, TextLayout, ListLayout, TypewriterLayout, FeedbackLayout, AffiliationLayout } from '../layout/index.js';
5
+ import { SearchBoxLayout, TextLayout, ListLayout, CarouselLayout, TypewriterLayout, FeedbackLayout, AffiliationLayout } from '../layout/index.js';
6
6
  import { processData as processAffiliationData } from '../affiliation/index.js';
7
7
  import { mergeRolesOptions, DEFAULT_TRACKER_OPTIONS } from './options/index.js';
8
8
  import { writeAnswerStageToMeta, mergeInteraction } from './processors.js';
9
9
  import { enableUseLink } from './use-link.js';
10
+ import { isTracked, markAsTracked } from '../util/trackers.js';
10
11
 
11
12
  const DEFAULT_API_OPTIONS = Object.freeze({
12
13
  ...Workflow.DEFAULT_API_OPTIONS,
@@ -34,6 +35,7 @@ const DEFAULT_LAYOUTS = Object.freeze({
34
35
  [ROLE.QUESTION]: [TextLayout.type, { tag: 'h2' }],
35
36
  [ROLE.ANSWER]: TypewriterLayout.type,
36
37
  [ROLE.FEEDBACK]: FeedbackLayout.type,
38
+ [ROLE.IMAGES]: [CarouselLayout.type, { incremental: true, itemType: 'image' }],
37
39
  [ROLE.SOURCES]: [ListLayout.type, { incremental: true, itemType: 'article', templates: { ordered: true } }],
38
40
  [ROLE.AFFILIATION]: [AffiliationLayout.type, { incremental: true, itemType: 'affiliation', link: { rel: 'noopener nofollow' } }],
39
41
  });
@@ -46,6 +48,7 @@ const DEFAULT_TRACKERS = Object.freeze({
46
48
  deduplicated: false,
47
49
  click: DEFAULT_TRACKER_OPTIONS.click, // click only
48
50
  },
51
+ [ROLE.IMAGES]: DEFAULT_TRACKER_OPTIONS,
49
52
  [ROLE.SOURCES]: DEFAULT_TRACKER_OPTIONS,
50
53
  [ROLE.AFFILIATION]: DEFAULT_TRACKER_OPTIONS,
51
54
  [ROLE.PRODUCTS]: DEFAULT_TRACKER_OPTIONS,
@@ -268,7 +271,6 @@ export default class AnswerBasedWorkflow extends Workflow {
268
271
  if (args.role !== ROLE.ANSWER) {
269
272
  return payload;
270
273
  }
271
- console.log('writeAnswerClickInteraction', payload, args);
272
274
  const { items = [] } = args;
273
275
  return mergeInteraction(payload, {
274
276
  context: {
@@ -289,7 +291,10 @@ export default class AnswerBasedWorkflow extends Workflow {
289
291
  }
290
292
 
291
293
  // handlers //
292
- _onCitationClick({ index }) {
294
+ _onCitationClick({ index, event }) {
295
+ if (isTracked(event)) {
296
+ return;
297
+ }
293
298
  const { value } = this.states[fields.data()] || {};
294
299
  const { sources } = value || {};
295
300
  // index is 1-based
@@ -298,10 +303,15 @@ export default class AnswerBasedWorkflow extends Workflow {
298
303
  return;
299
304
  }
300
305
  // TODO: should we track impression as well?
306
+ markAsTracked(event);
301
307
  this._views.trackers.sources.click([source.product_id]);
302
308
  }
303
309
 
304
- _onAnswerLinkClick(item) {
310
+ _onAnswerLinkClick({ event, ...item }) {
311
+ if (isTracked(event)) {
312
+ return;
313
+ }
314
+ markAsTracked(event);
305
315
  // put everything into args and let _defaultProcessInteraction() handles it
306
316
  // for it's hard to make it a standard item
307
317
  this._views.trackers.answer.click([], { items: [item] });
@@ -81,7 +81,6 @@ export default class Search extends SearchBasedWorkflow {
81
81
 
82
82
  // destroy //
83
83
  _destroy(options) {
84
- this._feedback._destroy();
85
84
  this._destroyAutocomplete();
86
85
  super._destroy(options);
87
86
  }