@24i/bigscreen-sdk 1.0.43-alpha.2726 → 1.0.44

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@24i/bigscreen-sdk",
3
- "version": "1.0.43-alpha.2726",
3
+ "version": "1.0.44",
4
4
  "description": "SmartApps BIGscreen SDK monorepo",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -2,7 +2,7 @@ import { Storage } from '@24i/bigscreen-sdk/storage';
2
2
  import { MINUTE_IN_MS } from '@24i/bigscreen-sdk/utils/timeConstants';
3
3
  import { createTimeout } from '@24i/bigscreen-sdk/utils/timers';
4
4
  import { AnalyticsTriggers } from '@24i/appstage-shared-analytics';
5
- import { findIdForLanguage } from './findIdForLanguage';
5
+ import { findForLanguage } from './findForLanguage';
6
6
  import {
7
7
  BIGSCREEN_APP_TYPE,
8
8
  BIGSCREEN_OTT_TYPE,
@@ -18,8 +18,8 @@ import type {
18
18
  TealiumAnalyticsConfiguration,
19
19
  TeaResult,
20
20
  TealiumDataMapper,
21
- TealiumCustomConfiguration,
22
21
  CustomMappers,
22
+ TeaDynamicCoreResult,
23
23
  } from './types';
24
24
 
25
25
  // eslint-disable-next-line no-magic-numbers
@@ -30,11 +30,7 @@ const TEALIUM_BASE_URL = 'https://collect.tealiumiq.com/event';
30
30
  const DEFAULT_PAYLOAD: TeaStaticCoreResult = {
31
31
  tealium_account: '',
32
32
  tealium_profile: '',
33
- language: '',
34
- language_service: '',
35
33
  entity: '',
36
- property_id: '',
37
- short_language_service: '',
38
34
  platform_short: BIGSCREEN_PLATFORM_SHORT,
39
35
  platform_type: BIGSCREEN_PLATFORM_TYPE,
40
36
  app_type: BIGSCREEN_APP_TYPE,
@@ -78,27 +74,15 @@ export class TealiumAnalytics implements AnalyticsClient {
78
74
  datasource,
79
75
  customMappers,
80
76
  dataMapper = {} as TealiumDataMapper,
81
- } = this.config || {} as TealiumCustomConfiguration;
82
- const {
83
- entity,
84
- property_ids: propertyIds,
85
- language,
86
- short_language_service: shortLanguageService,
87
- platform_short: platformShort,
88
- platform_type: platformType,
89
- app_type: appType,
90
- } = dataMapper || {} as TealiumDataMapper;
77
+ } = this.config;
78
+ const { entity, platformShort, platformType, appType } = dataMapper;
91
79
  this.customMappers = customMappers;
92
80
  this.constantPayload = {
93
81
  tealium_account: account,
94
82
  tealium_profile: profile,
95
83
  tealium_environment: environment,
96
- ...(datasource && { tealium_datasource: datasource }),
97
- language: language || '',
98
- language_service: `${entity} ${language}`,
99
84
  entity,
100
- property_id: findIdForLanguage(propertyIds, language || '').toString(),
101
- short_language_service: shortLanguageService || '',
85
+ ...(datasource && { tealium_datasource: datasource }),
102
86
  platform_short: platformShort ?? BIGSCREEN_PLATFORM_SHORT,
103
87
  platform_type: platformType ?? BIGSCREEN_PLATFORM_TYPE,
104
88
  app_type: appType ?? BIGSCREEN_APP_TYPE,
@@ -107,6 +91,24 @@ export class TealiumAnalytics implements AnalyticsClient {
107
91
  };
108
92
  }
109
93
 
94
+ getDynamicPayload({ language: payloadLanguage }: AnyPayload): TeaDynamicCoreResult {
95
+ if (!this.config || !this.config.dataMapper) {
96
+ console.warn(`[${this.name}] getDynamicPayload missing configuration`);
97
+ return {
98
+ language: '', language_service: '', property_id: '', short_language_service: '',
99
+ };
100
+ }
101
+ const { dataMapper } = this.config;
102
+ const { entity, languageMap, propertyIdsMap, shortLanguageServiceMap } = dataMapper;
103
+ const tealiumLanguage = findForLanguage(languageMap, payloadLanguage) || '';
104
+ return {
105
+ language: tealiumLanguage || '',
106
+ language_service: `${entity} ${tealiumLanguage}`,
107
+ property_id: findForLanguage(propertyIdsMap, payloadLanguage) || '',
108
+ short_language_service: findForLanguage(shortLanguageServiceMap, payloadLanguage) || '',
109
+ };
110
+ }
111
+
110
112
  async startSession() {
111
113
  const sessionNumber = parseInt(
112
114
  await Storage.getItem(TEALIUM_SESSION_COUNTER) ?? '0', 10,
@@ -157,6 +159,7 @@ export class TealiumAnalytics implements AnalyticsClient {
157
159
  }
158
160
  const eventBody = {
159
161
  ...this.constantPayload,
162
+ ...this.getDynamicPayload(payload),
160
163
  ...mappingFunction(triggerName, payload as Payload, this.config),
161
164
  };
162
165
  const filteredEventBody: TeaResult = Object.entries(eventBody).reduce(
@@ -0,0 +1,9 @@
1
+ import { LanguageMapper } from '@24i/bigscreen-sdk/analytics/TealiumAnalytics';
2
+
3
+ export const findForLanguage = (
4
+ languageMapper: LanguageMapper = {},
5
+ language: string = '',
6
+ ) => {
7
+ const languageKey = Object.keys(languageMapper).find((key) => key === language);
8
+ return languageKey ? languageMapper[languageKey] : null;
9
+ };
@@ -1,4 +1,4 @@
1
1
  export { TealiumAnalytics } from './TealiumAnalytics';
2
- export { findIdForLanguage } from './findIdForLanguage';
2
+ export { findForLanguage } from './findForLanguage';
3
3
  export * from './constants';
4
4
  export * from './types';
@@ -29,6 +29,8 @@ export const MEDIA_PAYLOAD: Payload = {
29
29
  section: 'BROWSE',
30
30
  subcontentType: 'section',
31
31
  seriesTitle: 'section',
32
+ language: 'en',
33
+ resolution: '1920x1080',
32
34
  };
33
35
 
34
36
  export const TEALIUM_PAGEINFO_PAYLOAD = {
@@ -1,7 +1,7 @@
1
1
  import { AnalyticsTriggers } from '@24i/appstage-shared-analytics';
2
2
  import { AppEvents, EVENTS, TrackEventType as TrackEventTypeEnum } from './constants';
3
3
  import type {
4
- UserInfo, AppInfo, VideoProgress, SceneInfo, PlayerSession, ErrorInfo,
4
+ UserInfo, GeneralAppData, AppInfo, VideoProgress, SceneInfo, PlayerSession, ErrorInfo,
5
5
  } from '../../interface';
6
6
 
7
7
  export type TeaEventType = 'view' | 'link';
@@ -12,20 +12,20 @@ type TeaTrackEventType = `${TrackEventTypeEnum}`;
12
12
  type TeaAppEventValues = typeof AppEvents[keyof typeof AppEvents];
13
13
  type TeaAnalyticsTriggerValues = `${AnalyticsTriggers}`;
14
14
 
15
- export interface PropertyIds {
16
- [key: string]: number;
15
+ export interface LanguageMapper {
16
+ [key: string]: string;
17
17
  }
18
18
 
19
19
  export type CustomMappers = Partial<Record<EVENTS, EventMappingFunction>>;
20
20
 
21
21
  export type TealiumDataMapper = {
22
- app_type: TeaAppType, // e.g. 'html5' for bigscreen
22
+ appType?: TeaAppType,
23
23
  entity: string, // e.g: 'rfe'
24
- property_ids: PropertyIds, // e.g: 414
25
- language?: string, // e.g: 'english'
26
- platform_short?: string,
27
- platform_type?: string,
28
- short_language_service?: string, // e.g: 'eng'
24
+ platformShort?: string,
25
+ platformType?: string,
26
+ languageMap: LanguageMapper, // e.g: 'english'
27
+ propertyIdsMap: LanguageMapper, // e.g: 414
28
+ shortLanguageServiceMap: LanguageMapper, // e.g: 'eng'
29
29
  };
30
30
 
31
31
  export type TealiumCustomConfiguration = {
@@ -71,6 +71,7 @@ export type SubPageInfo = {
71
71
  };
72
72
 
73
73
  export type Payload = CorePayload &
74
+ GeneralAppData &
74
75
  AppInfo &
75
76
  SceneInfo &
76
77
  SubPageInfo &
@@ -87,6 +88,13 @@ export type EventMappingFunction = (
87
88
  config?: TealiumAnalyticsConfiguration,
88
89
  ) => TeaResult;
89
90
 
91
+ export type TeaDynamicCoreResult = {
92
+ language: string;
93
+ language_service: string;
94
+ property_id: string;
95
+ short_language_service: string;
96
+ };
97
+
90
98
  export type TeaStaticCoreResult = {
91
99
  tealium_account: string,
92
100
  tealium_profile: string,
@@ -96,13 +104,9 @@ export type TeaStaticCoreResult = {
96
104
  app_id: string;
97
105
  app_type: TeaAppType;
98
106
  entity: string;
99
- language: string;
100
- language_service: string;
101
107
  ott_type: TeaOttType;
102
108
  platform_short: string;
103
109
  platform_type: string;
104
- property_id: string;
105
- short_language_service: string;
106
110
  };
107
111
 
108
112
  export type TeaCoreResult = {
@@ -60,6 +60,3 @@ The reason for no styling is to limit unnecessary CSS code that would be overrid
60
60
  `.native-input-wrap` is set to `display: none`. This is the native input used on the background.
61
61
 
62
62
  `.input-field` is a custom component that should look like input field with possibility of custom styling.
63
-
64
- `.caret` position is counted from the left side of the input in LTR layout and from the right side of the
65
- input in RTL layout.
@@ -1,4 +1,4 @@
1
- import { createRef, Component, DeclareProps } from '@24i/bigscreen-sdk/jsx';
1
+ import { createRef, Component, setText, DeclareProps } from '@24i/bigscreen-sdk/jsx';
2
2
  import { Interactable } from '@24i/bigscreen-sdk/interactable';
3
3
  import { IFocusable } from '@24i/bigscreen-sdk/focus';
4
4
  import { isRtl } from '@24i/bigscreen-sdk/i18n';
@@ -9,7 +9,7 @@ import { stopEvent } from '@24i/bigscreen-sdk/utils/stopEvent';
9
9
  import { addClass } from '@24i/bigscreen-sdk/utils/addClass';
10
10
  import { removeClass } from '@24i/bigscreen-sdk/utils/removeClass';
11
11
  import { offsetPosition } from '@24i/bigscreen-sdk/utils/offsetPosition';
12
- import { checkCharOrderMishmash, handleOverflow } from './utils';
12
+ import { handleOverflow } from './handleOverflow';
13
13
  import './Input.scss';
14
14
 
15
15
  type Props = {
@@ -42,8 +42,6 @@ export class Input extends Component<Props> implements IFocusable {
42
42
 
43
43
  caret = createRef<HTMLDivElement>();
44
44
 
45
- caretPosition = 0;
46
-
47
45
  isInputting = false;
48
46
 
49
47
  lastValue: string;
@@ -70,11 +68,6 @@ export class Input extends Component<Props> implements IFocusable {
70
68
  this.isPlaceholderVisible = value.length === 0;
71
69
  }
72
70
 
73
- componentDidMount() {
74
- const { value } = this.props;
75
- if (value) this.setText(value);
76
- }
77
-
78
71
  getType() {
79
72
  return this.nativeInput.current?.type;
80
73
  }
@@ -92,10 +85,13 @@ export class Input extends Component<Props> implements IFocusable {
92
85
 
93
86
  onCaretPositionChange = (position: number | null) => {
94
87
  if (position === null) return;
88
+ const { shouldHandleOverflow } = this.props;
95
89
  const value = this.getValue();
96
- this.setText(value);
97
- this.updateCaretPosition(position);
98
- this.updateTextOverflow();
90
+ setText(this.text, this.filterText(value));
91
+ this.setCaretPosition(position);
92
+ if (shouldHandleOverflow) {
93
+ handleOverflow(this.wrap.current, this.caret.current, this.text.current);
94
+ }
99
95
  if (this.lastValue !== value) {
100
96
  const { onChange } = this.props;
101
97
  this.lastValue = value;
@@ -110,59 +106,33 @@ export class Input extends Component<Props> implements IFocusable {
110
106
 
111
107
  setValue(value: string) {
112
108
  this.nativeInput.current!.value = value;
113
- this.setText(value);
114
109
  }
115
110
 
116
111
  setType(type: Props['type']) {
117
112
  if (this.getType() === type) return;
118
113
  const value = this.getValue();
119
114
  this.nativeInput.current!.type = type;
120
- this.setText(value);
115
+ setText(this.text, this.filterText(value));
121
116
  }
122
117
 
123
- setText(text: string): void {
124
- const filtered = this.filterText(text);
125
- this.renderText(filtered);
126
- }
127
-
128
- updateCaretPosition(position: number) {
118
+ setCaretPosition(position: number) {
129
119
  const textNode = this.text.current!.firstChild;
130
- if (!textNode || position <= 0) {
131
- this.caretPosition = 0;
120
+ if (!textNode) {
132
121
  offsetPosition(this.caret, { x: 0 });
133
122
  return;
134
123
  }
135
- const wholeTextDimensions = this.text.current!.getBoundingClientRect();
136
- if (position >= this.text.current!.children.length) {
137
- const offset = wholeTextDimensions.right - wholeTextDimensions.left;
138
- this.caretPosition = isRtl() ? -offset : offset;
139
- offsetPosition(this.caret, { x: this.caretPosition }, false);
140
- return;
141
- }
142
- const charNode = this.text.current!.children[position - 1];
143
- const charDimensions = charNode!.getBoundingClientRect();
144
- const isCharMishmash = checkCharOrderMishmash(this.text.current!, position - 1);
145
- if (isRtl()) {
146
- if (isCharMishmash) {
147
- this.caretPosition = charDimensions.right - wholeTextDimensions.right;
148
- } else {
149
- this.caretPosition = charDimensions.left - wholeTextDimensions.right;
150
- }
151
- } else if (isCharMishmash) {
152
- this.caretPosition = charDimensions.left - wholeTextDimensions.left;
153
- } else {
154
- this.caretPosition = charDimensions.right - wholeTextDimensions.left;
155
- }
156
- offsetPosition(this.caret, { x: this.caretPosition }, false);
157
- }
158
-
159
- updateTextOverflow() {
160
- const { shouldHandleOverflow } = this.props;
161
- if (!shouldHandleOverflow) return;
162
- const textMargin = handleOverflow(
163
- this.wrap.current, this.caret.current, this.text.current,
164
- );
165
- offsetPosition(this.caret, { x: this.caretPosition - textMargin }, false);
124
+ const range = new Range();
125
+ range.selectNode(textNode);
126
+ const wholeText = range.getBoundingClientRect();
127
+ range.setStart(textNode, 0);
128
+ range.setEnd(textNode, position);
129
+ const caretText = range.getBoundingClientRect();
130
+ const [initialCaretPosition, currentCarretPosition, offsetBase] = isRtl()
131
+ ? [wholeText.right, caretText.left, wholeText.left]
132
+ : [wholeText.left, caretText.right, wholeText.right];
133
+ const caretPos = position === 0 ? initialCaretPosition : currentCarretPosition;
134
+ const offset = offsetBase - caretPos;
135
+ offsetPosition(this.caret, { x: -offset }, false);
166
136
  }
167
137
 
168
138
  /**
@@ -226,14 +196,6 @@ export class Input extends Component<Props> implements IFocusable {
226
196
  return text.replace(/ /g, NBSP);
227
197
  }
228
198
 
229
- renderText(text: string): void {
230
- const chars: JSX.Element[] = [];
231
- for (let i = 0; i < text.length; i++) {
232
- chars.push(<span className="char">{text[i]}</span>);
233
- }
234
- this.clearMount(chars, this.text);
235
- }
236
-
237
199
  render() {
238
200
  const { value, type, placeholder, onFocus, onBlur } = this.props;
239
201
  return (
@@ -258,7 +220,9 @@ export class Input extends Component<Props> implements IFocusable {
258
220
  >
259
221
  {placeholder}
260
222
  </div>
261
- <div ref={this.text} className="text" />
223
+ <div ref={this.text} className="text">
224
+ {this.filterText(value)}
225
+ </div>
262
226
  <div ref={this.caret} className="caret" />
263
227
  </div>
264
228
  </Interactable>
@@ -0,0 +1,29 @@
1
+ import { isRtl } from '@24i/bigscreen-sdk/i18n';
2
+
3
+ export const handleOverflow = (
4
+ wrap: HTMLDivElement | null,
5
+ caret: HTMLDivElement | null,
6
+ text: HTMLDivElement | null,
7
+ ) => {
8
+ if (!wrap || !caret || !text) return;
9
+ const { width: wrapWidth, left: wrapLeft } = wrap.getBoundingClientRect();
10
+ const { width: caretWidth, left: caretLeft } = caret.getBoundingClientRect();
11
+ const textMargin = parseInt(text.dataset.margin!, 10) || 0;
12
+ const caretOffset = isRtl()
13
+ ? caretLeft + textMargin - caretWidth
14
+ : caretLeft - textMargin + caretWidth;
15
+ if (!isRtl() && wrapWidth + wrapLeft < caretOffset) {
16
+ const margin = -(caretOffset - wrapWidth - wrapLeft);
17
+ text.style.marginLeft = `${margin}px`;
18
+ text.style.marginRight = '0px';
19
+ text.dataset.margin = margin.toString();
20
+ } else if (isRtl() && caretOffset < wrapLeft) {
21
+ const margin = -(wrapLeft - caretOffset);
22
+ text.style.marginLeft = '0px';
23
+ text.style.marginRight = `${margin}px`;
24
+ text.dataset.margin = margin.toString();
25
+ } else {
26
+ text.style.marginLeft = '0px';
27
+ text.style.marginRight = '0px';
28
+ }
29
+ };
@@ -1,9 +0,0 @@
1
- import { PropertyIds } from '@24i/bigscreen-sdk/analytics/TealiumAnalytics';
2
-
3
- export const findIdForLanguage = (
4
- property_ids: PropertyIds = {},
5
- language: string,
6
- ): number => {
7
- const languageKey = Object.keys(property_ids).find((key) => key.endsWith(language));
8
- return languageKey ? property_ids[languageKey] : -1;
9
- };
@@ -1,71 +0,0 @@
1
- import { isRtl } from '@24i/bigscreen-sdk/i18n';
2
-
3
- /**
4
- * Handles overflowing text in the input by moving with the inner
5
- * text element.
6
- * @param wrap input wrapper
7
- * @param caret caret element
8
- * @param text input inner text element
9
- * @returns value how much is text element moved
10
- */
11
- export const handleOverflow = (
12
- wrap: HTMLDivElement | null,
13
- caret: HTMLDivElement | null,
14
- text: HTMLDivElement | null,
15
- ) => {
16
- if (!wrap || !caret || !text) return 0;
17
- const { width: wrapWidth, left: wrapLeft } = wrap.getBoundingClientRect();
18
- const { width: caretWidth, left: caretLeft } = caret.getBoundingClientRect();
19
- const caretOffset = isRtl() ? caretLeft - caretWidth : caretLeft + caretWidth;
20
- if (!isRtl() && wrapWidth + wrapLeft < caretOffset) {
21
- const margin = -(caretOffset - wrapWidth - wrapLeft);
22
- text.style.marginLeft = `${margin}px`;
23
- text.style.marginRight = '0px';
24
- return margin;
25
- }
26
- if (isRtl() && caretOffset < wrapLeft) {
27
- const margin = -(wrapLeft - caretOffset);
28
- text.style.marginLeft = '0px';
29
- text.style.marginRight = `${margin}px`;
30
- return margin;
31
- }
32
- text.style.marginLeft = '0px';
33
- text.style.marginRight = '0px';
34
- return 0;
35
- };
36
-
37
- /**
38
- * Check for char element position mishmash in the input's text element. This is
39
- * necessary to recognize if the char is in the wrong direction than it's position
40
- * in children collection, this means that the char is LTR char in RTL scheme or RTL
41
- * char in LTR scheme.
42
- * @param text input inner text element
43
- * @param position position of the char in children collection
44
- * @returns true if char has position mishmash
45
- */
46
- export const checkCharOrderMishmash = (text: HTMLDivElement, position: number) => {
47
- const { children } = text!;
48
- if (!children.length) return false;
49
- const charOffsets: {
50
- index: number,
51
- offset: number,
52
- }[] = [];
53
- for (let i = 0; i < children.length; i++) {
54
- charOffsets.push({
55
- index: i,
56
- offset: (children[i] as HTMLElement).getBoundingClientRect().left,
57
- });
58
- }
59
- charOffsets.sort((a, b) => {
60
- if (a.offset < b.offset) return isRtl() ? 1 : -1;
61
- if (a.offset > b.offset) return isRtl() ? -1 : 1;
62
- return 0;
63
- });
64
- const lastPos = children.length - 1;
65
- const posBefore = position - 1;
66
- const mishmashBefore = posBefore < 0
67
- ? false : charOffsets[posBefore].index !== posBefore;
68
- const mishmashCurrent = charOffsets[position].index !== position;
69
- if (mishmashCurrent) return true;
70
- return !mishmashCurrent && mishmashBefore && position !== lastPos;
71
- };