@miso.ai/client-sdk-ui 1.10.0-beta.9 → 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.
- package/dist/cjs/actor/index.js +0 -7
- package/dist/cjs/actor/tracker.js +47 -102
- package/dist/cjs/actor/utils.js +1 -1
- package/dist/cjs/actor/view.js +12 -1
- package/dist/cjs/actor/views.js +24 -2
- package/dist/cjs/asset/svgs.js +14 -4
- package/dist/cjs/constants.js +3 -2
- package/dist/cjs/layout/affiliation/affiliation.js +150 -58
- package/dist/cjs/layout/input/option-list.js +34 -49
- package/dist/cjs/layout/list/collection.js +22 -43
- package/dist/cjs/layout/templates.js +54 -32
- package/dist/cjs/layout/text/typewriter/index.js +12 -7
- package/dist/cjs/layout/trackable.js +124 -0
- package/dist/cjs/util/bindings.js +58 -110
- package/dist/cjs/util/states.js +31 -24
- package/dist/cjs/util/trackers.js +75 -0
- package/dist/cjs/util/viewables.js +55 -0
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/workflow/ask.js +1 -5
- package/dist/cjs/workflow/base.js +2 -7
- package/dist/cjs/workflow/recommendation.js +2 -0
- package/package.json +2 -2
- package/src/actor/index.js +0 -1
- package/src/actor/tracker.js +37 -94
- package/src/actor/utils.js +1 -1
- package/src/actor/view.js +14 -1
- package/src/actor/views.js +30 -1
- package/src/asset/svgs.js +13 -2
- package/src/constants.js +7 -1
- package/src/layout/affiliation/affiliation.js +142 -55
- package/src/layout/input/option-list.js +35 -43
- package/src/layout/list/collection.js +20 -38
- package/src/layout/templates.js +25 -19
- package/src/layout/text/typewriter/index.js +8 -6
- package/src/layout/trackable.js +106 -0
- package/src/util/bindings.js +47 -103
- package/src/util/states.js +26 -20
- package/src/util/trackers.js +69 -0
- package/src/util/viewables.js +47 -0
- package/src/version.js +1 -1
- package/src/workflow/ask.js +1 -4
- package/src/workflow/base.js +3 -5
- package/src/workflow/recommendation.js +1 -0
- package/dist/cjs/actor/trackers.js +0 -51
- package/dist/cjs/layout/affiliation/viewable.js +0 -65
- package/dist/cjs/layout/text/typewriter/progress.js +0 -45
- package/dist/cjs/util/tracker.js +0 -348
- package/src/actor/trackers.js +0 -45
- package/src/layout/affiliation/viewable.js +0 -61
- package/src/layout/text/typewriter/progress.js +0 -33
- package/src/util/tracker.js +0 -318
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.normalizeTrackerOptions = normalizeTrackerOptions;
|
|
7
|
+
exports.validateClick = validateClick;
|
|
8
|
+
var _commons = require("@miso.ai/commons");
|
|
9
|
+
const _excluded = ["impression", "viewable", "click"];
|
|
10
|
+
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; }
|
|
11
|
+
const DEFAULT_TRACKER_OPTIONS = Object.freeze({
|
|
12
|
+
impression: Object.freeze({}),
|
|
13
|
+
viewable: Object.freeze({
|
|
14
|
+
area: 0.5,
|
|
15
|
+
duration: 1000
|
|
16
|
+
}),
|
|
17
|
+
click: Object.freeze({
|
|
18
|
+
lenient: false
|
|
19
|
+
}),
|
|
20
|
+
watch: false
|
|
21
|
+
});
|
|
22
|
+
function mergeOptions(def, opt) {
|
|
23
|
+
// if opt is falsy then return false, merge otherwise
|
|
24
|
+
return !!opt && Object.assign({}, def, opt);
|
|
25
|
+
}
|
|
26
|
+
function normalizeTrackerOptions(options) {
|
|
27
|
+
if (options === false) {
|
|
28
|
+
return false; // turn off all tracking
|
|
29
|
+
}
|
|
30
|
+
if (options === true) {
|
|
31
|
+
options = {};
|
|
32
|
+
}
|
|
33
|
+
if (typeof options !== 'object') {
|
|
34
|
+
throw new Error(`Invalid options: ${options}`);
|
|
35
|
+
}
|
|
36
|
+
const {
|
|
37
|
+
impression = {},
|
|
38
|
+
viewable = {},
|
|
39
|
+
click = {}
|
|
40
|
+
} = options,
|
|
41
|
+
rest = _objectWithoutPropertiesLoose(options, _excluded);
|
|
42
|
+
return (0, _commons.trimObj)(Object.assign({}, DEFAULT_TRACKER_OPTIONS, rest, {
|
|
43
|
+
impression: mergeOptions(DEFAULT_TRACKER_OPTIONS.impression, impression),
|
|
44
|
+
viewable: mergeOptions(DEFAULT_TRACKER_OPTIONS.viewable, viewable),
|
|
45
|
+
click: mergeOptions(DEFAULT_TRACKER_OPTIONS.click, click)
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
function validateClick() {
|
|
49
|
+
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
50
|
+
let event = arguments.length > 1 ? arguments[1] : undefined;
|
|
51
|
+
if (!options) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
if (typeof options.validate === 'function') {
|
|
55
|
+
return options.validate(event);
|
|
56
|
+
}
|
|
57
|
+
if (options.lenient) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// standard criteria
|
|
62
|
+
// 1. it must be a left click
|
|
63
|
+
if (event.button !== 0) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
// 2. event default must not be prevented
|
|
67
|
+
if (event.defaultPrevented) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
// 3. must go through a real link
|
|
71
|
+
if (!(0, _commons.findInAncestors)(event.target, element => element.tagName === 'A' && element.href || undefined)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _commons = require("@miso.ai/commons");
|
|
8
|
+
class Viewables {
|
|
9
|
+
constructor() {
|
|
10
|
+
this._entries = new WeakMap();
|
|
11
|
+
}
|
|
12
|
+
isTracked(element) {
|
|
13
|
+
return this._entries.has(element);
|
|
14
|
+
}
|
|
15
|
+
async track(element) {
|
|
16
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
17
|
+
if (!options) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
const entry = this._entries.get(element);
|
|
21
|
+
if (entry) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const ac = new AbortController();
|
|
25
|
+
const {
|
|
26
|
+
signal
|
|
27
|
+
} = ac;
|
|
28
|
+
this._entries.set(element, {
|
|
29
|
+
ac
|
|
30
|
+
});
|
|
31
|
+
let result = false;
|
|
32
|
+
try {
|
|
33
|
+
await (0, _commons.viewable)(element, Object.assign({}, options, {
|
|
34
|
+
signal
|
|
35
|
+
}));
|
|
36
|
+
result = true;
|
|
37
|
+
} catch (e) {
|
|
38
|
+
if (e.name !== 'AbortError') {
|
|
39
|
+
throw e;
|
|
40
|
+
}
|
|
41
|
+
} finally {
|
|
42
|
+
this._entries.delete(element);
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
untrack(element) {
|
|
47
|
+
const entry = this._entries.get(element);
|
|
48
|
+
if (!entry) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
entry.ac.abort();
|
|
52
|
+
this._entries.delete(element);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.default = Viewables;
|
package/dist/cjs/version.js
CHANGED
package/dist/cjs/workflow/ask.js
CHANGED
|
@@ -67,12 +67,8 @@ const DEFAULT_LAYOUTS = Object.freeze({
|
|
|
67
67
|
const DEFAULT_TRACKERS = Object.freeze({
|
|
68
68
|
[_constants.ROLE.SOURCES]: {},
|
|
69
69
|
[_constants.ROLE.RELATED_RESOURCES]: {},
|
|
70
|
-
[_constants.ROLE.AFFILIATION]: {
|
|
71
|
-
viewable: false // track viewable manually
|
|
72
|
-
},
|
|
70
|
+
[_constants.ROLE.AFFILIATION]: {},
|
|
73
71
|
[_constants.ROLE.QUERY_SUGGESTIONS]: {
|
|
74
|
-
active: true,
|
|
75
|
-
// we are tracking events at initial stage, when session is not active yet
|
|
76
72
|
click: {
|
|
77
73
|
validate: event => event.button === 0 // left click only
|
|
78
74
|
}
|
|
@@ -65,7 +65,7 @@ class Workflow extends _commons.Component {
|
|
|
65
65
|
source: sources.api(client),
|
|
66
66
|
options
|
|
67
67
|
});
|
|
68
|
-
|
|
68
|
+
this._views = new _index.ViewsActor(hub, {
|
|
69
69
|
extensions,
|
|
70
70
|
layouts,
|
|
71
71
|
roles,
|
|
@@ -76,10 +76,6 @@ class Workflow extends _commons.Component {
|
|
|
76
76
|
client,
|
|
77
77
|
options
|
|
78
78
|
});
|
|
79
|
-
this._trackers = new _index.Trackers(hub, {
|
|
80
|
-
views,
|
|
81
|
-
options
|
|
82
|
-
});
|
|
83
79
|
this._unsubscribes = [this._hub.on(_index.fields.response(), data => this.updateData(data))];
|
|
84
80
|
}
|
|
85
81
|
get uuid() {
|
|
@@ -171,7 +167,7 @@ class Workflow extends _commons.Component {
|
|
|
171
167
|
|
|
172
168
|
// trackers //
|
|
173
169
|
get trackers() {
|
|
174
|
-
return this.
|
|
170
|
+
return this._views.trackers;
|
|
175
171
|
}
|
|
176
172
|
_preprocessInteraction() {
|
|
177
173
|
let _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -209,7 +205,6 @@ class Workflow extends _commons.Component {
|
|
|
209
205
|
unsubscribe();
|
|
210
206
|
}
|
|
211
207
|
this._unsubscribes = [];
|
|
212
|
-
this._trackers._destroy();
|
|
213
208
|
this._views._destroy({
|
|
214
209
|
dom
|
|
215
210
|
});
|
package/package.json
CHANGED
package/src/actor/index.js
CHANGED
|
@@ -5,7 +5,6 @@ export { default as Hub } from './hub.js';
|
|
|
5
5
|
export { default as SessionMaker } from './sessions.js';
|
|
6
6
|
export { default as DataActor } from './data.js';
|
|
7
7
|
export { default as ViewsActor } from './views.js';
|
|
8
|
-
export { default as Trackers } from './trackers.js';
|
|
9
8
|
export { default as FeedbackActor } from './feedback.js';
|
|
10
9
|
export { default as AutocompleteActor } from './autocomplete.js';
|
|
11
10
|
export { default as InteractionsActor } from './interactions.js';
|
package/src/actor/tracker.js
CHANGED
|
@@ -1,98 +1,55 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { asArray } from '@miso.ai/commons';
|
|
2
|
+
import { TRACKING_EVENT_TYPES, TRACKING_STATUS, validateEventType } from '../constants.js';
|
|
2
3
|
import * as fields from './fields.js';
|
|
3
|
-
import
|
|
4
|
-
import { fallbackListFunction } from '../util/bindings.js';
|
|
4
|
+
import States from '../util/states.js';
|
|
5
5
|
import { toInteraction } from './utils.js';
|
|
6
6
|
|
|
7
|
-
function isReady(viewState) {
|
|
8
|
-
return viewState && viewState.status === STATUS.READY;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
7
|
export default class Tracker {
|
|
12
8
|
|
|
13
|
-
constructor(
|
|
14
|
-
this._hub = hub;
|
|
9
|
+
constructor(view) {
|
|
15
10
|
this._view = view;
|
|
16
|
-
this.
|
|
17
|
-
const role = this._role = view.role;
|
|
11
|
+
this._role = view.role;
|
|
18
12
|
// TODO: know item type
|
|
19
13
|
|
|
20
|
-
this.
|
|
21
|
-
bindings: {
|
|
22
|
-
list: element => this._listBindingsFn()(element),
|
|
23
|
-
},
|
|
24
|
-
proxyElement: view.proxyElement,
|
|
25
|
-
sessionId: () => this._getSessionId(),
|
|
26
|
-
active: active || (() => this._isViewReady()),
|
|
27
|
-
...options,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
this._unsubscribes = [
|
|
31
|
-
this._tracker.on('*', data => this._handleEvent(data)),
|
|
32
|
-
// TODO: view actor has another click event that does not comply to this data format
|
|
33
|
-
...[EVENT_TYPE.VIEWABLE].map(type => this._view.on(type, values => this._handleViewActorEvent(type, values))),
|
|
34
|
-
hub.on(fields.view(role), () => this.refresh()),
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
this.refresh();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
config(options) {
|
|
41
|
-
this._tracker.config(options);
|
|
14
|
+
this._states = new States(this._getSessionId());
|
|
42
15
|
}
|
|
43
16
|
|
|
44
|
-
|
|
45
|
-
|
|
17
|
+
get options() {
|
|
18
|
+
return this._view._getTrackerOptions();
|
|
46
19
|
}
|
|
47
20
|
|
|
48
|
-
|
|
49
|
-
this.
|
|
21
|
+
getState(item) {
|
|
22
|
+
return this._states.getFullState(item);
|
|
50
23
|
}
|
|
51
24
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
this.
|
|
55
|
-
}
|
|
25
|
+
_trigger(type, items, meta = {}) {
|
|
26
|
+
validateEventType(type);
|
|
27
|
+
this._syncSession();
|
|
56
28
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
29
|
+
items = this._states.untriggered(asArray(items), type);
|
|
30
|
+
if (items.length === 0) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
this._states.set(items, type, TRACKING_STATUS.TRIGGERED);
|
|
61
34
|
|
|
62
|
-
|
|
63
|
-
this.
|
|
64
|
-
this.
|
|
65
|
-
}
|
|
35
|
+
const property = this._role === 'results' ? 'products' : this._role; // TODO: ad-hoc, see #83
|
|
36
|
+
const misoId = this._getMisoId();
|
|
37
|
+
const request = this._getRequestPayload();
|
|
66
38
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return this._bindings.list;
|
|
70
|
-
}
|
|
71
|
-
const { layout } = this._view;
|
|
72
|
-
if (layout && layout.bindings && typeof layout.bindings.list === 'function') {
|
|
73
|
-
return layout.bindings.list;
|
|
74
|
-
}
|
|
75
|
-
// TODO: only if item is product typed
|
|
76
|
-
return fallbackListFunction(ATTR_DATA_MISO_PRODUCT_ID);
|
|
39
|
+
// TODO: should trigger 'tracker' and let workflow translate to interactions
|
|
40
|
+
this._view.hub.trigger(fields.interaction(), toInteraction({ property, misoId, request }, { event: type, values: items, meta }));
|
|
77
41
|
}
|
|
78
42
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
43
|
+
_syncSession() {
|
|
44
|
+
const sessionId = this._getSessionId();
|
|
45
|
+
if (!sessionId) {
|
|
46
|
+
return;
|
|
82
47
|
}
|
|
83
|
-
if (!
|
|
84
|
-
|
|
48
|
+
if (!this._states || sessionId !== this._states.sessionId) {
|
|
49
|
+
this._states = new States(sessionId);
|
|
85
50
|
}
|
|
86
51
|
}
|
|
87
52
|
|
|
88
|
-
_getViewState() {
|
|
89
|
-
return this._hub.states[fields.view(this._role)];
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
_isViewReady() {
|
|
93
|
-
return this._hub.active && isReady(this._getViewState());
|
|
94
|
-
}
|
|
95
|
-
|
|
96
53
|
_getSessionId() {
|
|
97
54
|
const { session } = this._getViewState() || {};
|
|
98
55
|
return session && session.uuid;
|
|
@@ -100,7 +57,7 @@ export default class Tracker {
|
|
|
100
57
|
|
|
101
58
|
_getMisoId() {
|
|
102
59
|
const state = this._getViewState();
|
|
103
|
-
return (state && state.meta && state.meta.miso_id) ||
|
|
60
|
+
return (state && state.meta && state.meta.miso_id) || undefined;
|
|
104
61
|
}
|
|
105
62
|
|
|
106
63
|
_getRequestPayload() {
|
|
@@ -108,28 +65,14 @@ export default class Tracker {
|
|
|
108
65
|
return request && request.payload;
|
|
109
66
|
}
|
|
110
67
|
|
|
111
|
-
|
|
112
|
-
return this.
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
_handleViewActorEvent(type, values) {
|
|
116
|
-
this._tracker._trigger(type, values);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
_handleEvent(data) {
|
|
120
|
-
const property = this._role === 'results' ? 'products' : this._role; // TODO: ad-hoc, see #83
|
|
121
|
-
const misoId = this._getMisoId();
|
|
122
|
-
const request = this._getRequestPayload();
|
|
123
|
-
// TODO: should trigger 'tracker' and let workflow translate to interactions
|
|
124
|
-
this._hub.trigger(fields.interaction(), toInteraction({ property, misoId, request }, data));
|
|
68
|
+
_getViewState() {
|
|
69
|
+
return this._view.hub.states[fields.view(this._role)];
|
|
125
70
|
}
|
|
126
71
|
|
|
127
|
-
|
|
128
|
-
for (const unsubscribe of this._unsubscribes) {
|
|
129
|
-
unsubscribe();
|
|
130
|
-
}
|
|
131
|
-
this._unsubscribes = [];
|
|
132
|
-
this._tracker.destroy();
|
|
133
|
-
}
|
|
72
|
+
}
|
|
134
73
|
|
|
74
|
+
for (const type of TRACKING_EVENT_TYPES) {
|
|
75
|
+
Tracker.prototype[type] = function(items, meta) {
|
|
76
|
+
this._trigger(type, items, meta);
|
|
77
|
+
};
|
|
135
78
|
}
|
package/src/actor/utils.js
CHANGED
|
@@ -22,7 +22,7 @@ export function toInteraction({ property, misoId, request }, { event, values, ma
|
|
|
22
22
|
// TODO: ad-hoc
|
|
23
23
|
const question_source = request && request._meta && request._meta.question_source;
|
|
24
24
|
const isProductType = isProduct(property);
|
|
25
|
-
const product_ids = isProductType ? values.map(v => v.product_id).filter(v => v) : [];
|
|
25
|
+
const product_ids = isProductType ? values.map(v => typeof v === 'string' ? v : v.product_id).filter(v => v) : [];
|
|
26
26
|
const items = isProductType ? undefined : values.map(v => v.text || v.id || v);
|
|
27
27
|
const channel = property === ROLE.AFFILIATION ? values[0] && values[0].channel : undefined;
|
|
28
28
|
const positions = property === ROLE.AFFILIATION ? values.map(v => v.position) : undefined;
|
package/src/actor/view.js
CHANGED
|
@@ -2,6 +2,7 @@ import { trimObj, defineValues, delegateGetters, EventEmitter } from '@miso.ai/c
|
|
|
2
2
|
import { STATUS, ROLE, isDataRole } from '../constants.js';
|
|
3
3
|
import * as fields from './fields.js';
|
|
4
4
|
import ProxyElement from '../util/proxy.js';
|
|
5
|
+
import Tracker from './tracker.js';
|
|
5
6
|
|
|
6
7
|
function statesEqual(a, b) {
|
|
7
8
|
return a === b || (a && b &&
|
|
@@ -85,6 +86,13 @@ export default class ViewActor {
|
|
|
85
86
|
this.refresh({ force: true });
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
get tracker() {
|
|
90
|
+
if (!this._tracker) {
|
|
91
|
+
this._tracker = new Tracker(this);
|
|
92
|
+
}
|
|
93
|
+
return this._tracker;
|
|
94
|
+
}
|
|
95
|
+
|
|
88
96
|
async refresh({ force = false, data } = {}) {
|
|
89
97
|
// protocol: no reaction when layout is absent
|
|
90
98
|
if (!this._layout) {
|
|
@@ -134,6 +142,11 @@ export default class ViewActor {
|
|
|
134
142
|
this.hub.update(fields.view(role), state, { silent });
|
|
135
143
|
}
|
|
136
144
|
|
|
145
|
+
_getTrackerOptions() {
|
|
146
|
+
// used by tracker to expose tracker options to layout
|
|
147
|
+
return this._views._getTrackerOptions(this.role);
|
|
148
|
+
}
|
|
149
|
+
|
|
137
150
|
_sliceData({ value, error, status, meta, ...rest }) {
|
|
138
151
|
const sliced = {
|
|
139
152
|
value: this.role === ROLE.ERROR ? error : (value && value[this.role]),
|
|
@@ -205,7 +218,7 @@ export default class ViewActor {
|
|
|
205
218
|
class View {
|
|
206
219
|
|
|
207
220
|
constructor(actor) {
|
|
208
|
-
delegateGetters(this, actor, ['role', 'layout', 'element', 'proxyElement', 'refresh', 'on']);
|
|
221
|
+
delegateGetters(this, actor, ['role', 'layout', 'element', 'proxyElement', 'refresh', 'on', 'tracker']);
|
|
209
222
|
}
|
|
210
223
|
|
|
211
224
|
}
|
package/src/actor/views.js
CHANGED
|
@@ -2,6 +2,7 @@ import { defineValues, delegateGetters } from '@miso.ai/commons';
|
|
|
2
2
|
import { STATUS, ROLE } from '../constants.js';
|
|
3
3
|
import * as fields from './fields.js';
|
|
4
4
|
import ViewActor from './view.js';
|
|
5
|
+
import { normalizeTrackerOptions } from '../util/trackers.js';
|
|
5
6
|
|
|
6
7
|
export default class ViewsActor {
|
|
7
8
|
|
|
@@ -19,6 +20,7 @@ export default class ViewsActor {
|
|
|
19
20
|
this._options = options;
|
|
20
21
|
this._containers = new Map();
|
|
21
22
|
this._views = {};
|
|
23
|
+
this._trackers = new Trackers(this, roles);
|
|
22
24
|
|
|
23
25
|
for (const role of roles) {
|
|
24
26
|
this._views[role] = new ViewActor(this, role);
|
|
@@ -34,12 +36,18 @@ export default class ViewsActor {
|
|
|
34
36
|
this._unsubscribes = [
|
|
35
37
|
() => window.removeEventListener('resize', syncSize),
|
|
36
38
|
hub.on(fields.data(), () => this.refresh()),
|
|
39
|
+
options.on('trackers', () => this._syncTrackers()),
|
|
37
40
|
options.on('layouts', () => this._syncLayouts()),
|
|
38
41
|
];
|
|
39
42
|
|
|
43
|
+
this._syncTrackers();
|
|
40
44
|
this._syncLayouts();
|
|
41
45
|
}
|
|
42
46
|
|
|
47
|
+
get trackers() {
|
|
48
|
+
return this._trackers;
|
|
49
|
+
}
|
|
50
|
+
|
|
43
51
|
// elements //
|
|
44
52
|
addContainer(element) {
|
|
45
53
|
if (this._containers.has(element)) {
|
|
@@ -185,6 +193,14 @@ export default class ViewsActor {
|
|
|
185
193
|
return this._data;
|
|
186
194
|
}
|
|
187
195
|
|
|
196
|
+
_syncTrackers() {
|
|
197
|
+
this._trackerOptions = this._options.resolved.trackers;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
_getTrackerOptions(role) {
|
|
201
|
+
return normalizeTrackerOptions((this._trackerOptions && this._trackerOptions[role]) || false);
|
|
202
|
+
}
|
|
203
|
+
|
|
188
204
|
_error(e) {
|
|
189
205
|
// TODO: hub trigger error event
|
|
190
206
|
console.error(e);
|
|
@@ -208,7 +224,7 @@ class Views {
|
|
|
208
224
|
|
|
209
225
|
constructor(actor) {
|
|
210
226
|
this._actor = actor;
|
|
211
|
-
delegateGetters(this, actor, ['syncSize', 'refresh']);
|
|
227
|
+
delegateGetters(this, actor, ['syncSize', 'refresh', 'trackers']);
|
|
212
228
|
}
|
|
213
229
|
|
|
214
230
|
get(role) {
|
|
@@ -220,3 +236,16 @@ class Views {
|
|
|
220
236
|
}
|
|
221
237
|
|
|
222
238
|
}
|
|
239
|
+
|
|
240
|
+
class Trackers {
|
|
241
|
+
|
|
242
|
+
constructor(views, roles) {
|
|
243
|
+
this._views = views;
|
|
244
|
+
for (const role of roles) {
|
|
245
|
+
Object.defineProperty(this, role, {
|
|
246
|
+
get: () => views.get(role).tracker,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
}
|
package/src/asset/svgs.js
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import version from '../version.js';
|
|
2
2
|
|
|
3
|
+
function trianglePath(r) {
|
|
4
|
+
const l = 100;
|
|
5
|
+
const d = r * Math.tan(3 * Math.PI / 8);
|
|
6
|
+
const e = d * Math.sin(Math.PI / 4);
|
|
7
|
+
return `M${r} 0L${l-d} 0A${r} ${r} 0 0 1 ${l-e} ${e}L${e} ${l-e}A${r} ${r} 0 0 1 0 ${l-d}L0 ${r}Z`;
|
|
8
|
+
}
|
|
9
|
+
|
|
3
10
|
const PREFIX = 'miso-ui-icon';
|
|
4
11
|
const ID = `${PREFIX}-svg-${version.replaceAll('.', '_')}`;
|
|
5
12
|
|
|
6
|
-
//
|
|
13
|
+
// CC0 SVGs
|
|
7
14
|
const ICON_SEND = `<symbol id="${PREFIX}-send" viewBox="0 0 32 32"><path fill="currentColor" d="M11.499,19.173l5.801,-5.849c0.389,-0.392 1.022,-0.394 1.414,-0.006c0.392,0.389 0.395,1.022 0.006,1.414l-5.798,5.847l5.306,8.002c0.207,0.313 0.572,0.483 0.945,0.441c0.373,-0.042 0.691,-0.289 0.824,-0.64l9.024,-23.904c0.138,-0.366 0.05,-0.78 -0.226,-1.058c-0.276,-0.278 -0.689,-0.369 -1.057,-0.233l-24.004,8.892c-0.353,0.13 -0.602,0.448 -0.646,0.821c-0.044,0.373 0.125,0.74 0.438,0.948l7.973,5.325Z"/></symbol>`;
|
|
8
15
|
const ICON_SEARCH = `<symbol id="${PREFIX}-search" viewBox="0 0 24 24"><path fill="currentColor" d="M4 11C4 7.13401 7.13401 4 11 4C14.866 4 18 7.13401 18 11C18 14.866 14.866 18 11 18C7.13401 18 4 14.866 4 11ZM11 2C6.02944 2 2 6.02944 2 11C2 15.9706 6.02944 20 11 20C13.125 20 15.078 19.2635 16.6177 18.0319L20.2929 21.7071C20.6834 22.0976 21.3166 22.0976 21.7071 21.7071C22.0976 21.3166 22.0976 20.6834 21.7071 20.2929L18.0319 16.6177C19.2635 15.078 20 13.125 20 11C20 6.02944 15.9706 2 11 2Z"/></symbol>`;
|
|
9
16
|
|
|
10
|
-
|
|
17
|
+
// Custom SVGs
|
|
18
|
+
const ICON_TRIANGLE = `<symbol id="${PREFIX}-triangle" viewBox="-5 -5 105 105"><path d="${trianglePath(5)}"/></symbol>`;
|
|
19
|
+
|
|
20
|
+
const ICONS = [ICON_SEND, ICON_SEARCH, ICON_TRIANGLE];
|
|
11
21
|
|
|
12
22
|
const SPRITES_SVG = `<svg id="${ID}" style="display:none;">${ICONS.join('')}</svg>`;
|
|
13
23
|
|
|
@@ -29,3 +39,4 @@ function getSvg(name) {
|
|
|
29
39
|
|
|
30
40
|
export const SEND = getSvg('send');
|
|
31
41
|
export const SEARCH = getSvg('search');
|
|
42
|
+
export const TRIANGLE = getSvg('triangle');
|
package/src/constants.js
CHANGED
|
@@ -59,6 +59,12 @@ export const EVENT_TYPE = Object.freeze({
|
|
|
59
59
|
CLICK: 'click',
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
+
export const TRACKING_EVENT_TYPES = [
|
|
63
|
+
EVENT_TYPE.IMPRESSION,
|
|
64
|
+
EVENT_TYPE.VIEWABLE,
|
|
65
|
+
EVENT_TYPE.CLICK,
|
|
66
|
+
];
|
|
67
|
+
|
|
62
68
|
export const TRACKING_STATUS = Object.freeze({
|
|
63
69
|
UNTRACKED: 'untracked',
|
|
64
70
|
TRACKING: 'tracking',
|
|
@@ -77,7 +83,7 @@ export const STATUS = Object.freeze({
|
|
|
77
83
|
});
|
|
78
84
|
|
|
79
85
|
export function validateEventType(value) {
|
|
80
|
-
if (
|
|
86
|
+
if (TRACKING_EVENT_TYPES.indexOf(value) < 0) {
|
|
81
87
|
throw new Error(`Unrecognized event type: ${value}`);
|
|
82
88
|
}
|
|
83
89
|
}
|