@24i/bigscreen-sdk 1.0.4 → 1.0.5-4.alpha-2832

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 (292) hide show
  1. package/README.md +2 -3
  2. package/ci/is_ci_job_skippable.sh +153 -0
  3. package/package.json +55 -34
  4. package/packages/adobe-heartbeat/src/AdobeHeartbeat.ts +9 -9
  5. package/packages/analytics/README.md +8 -0
  6. package/packages/analytics/src/A.ts +1 -0
  7. package/packages/analytics/src/Analytics.ts +1 -0
  8. package/packages/analytics/src/analyticsOnScroll.ts +1 -0
  9. package/packages/analytics/src/clients/ConsoleAnalytics/ConsoleAnalytics.ts +1 -0
  10. package/packages/analytics/src/clients/ConsoleAnalytics/index.ts +1 -0
  11. package/packages/analytics/src/clients/GoogleAnalytics/GoogleAnalytics.ts +196 -0
  12. package/packages/analytics/src/clients/GoogleAnalytics/constants.ts +126 -0
  13. package/packages/analytics/src/clients/GoogleAnalytics/getUrl.ts +17 -0
  14. package/packages/analytics/src/clients/GoogleAnalytics/index.ts +2 -0
  15. package/packages/analytics/src/clients/GoogleAnalytics/interface.ts +82 -0
  16. package/packages/analytics/src/clients/GoogleAnalytics/mapPayload.ts +51 -0
  17. package/packages/analytics/src/clients/GoogleAnalytics/prepareBody.ts +14 -0
  18. package/packages/analytics/src/clients/TealiumAnalytics/TealiumAnalytics.ts +181 -0
  19. package/packages/analytics/src/clients/TealiumAnalytics/constants.ts +106 -0
  20. package/packages/analytics/src/clients/TealiumAnalytics/findForLanguage.ts +9 -0
  21. package/packages/analytics/src/clients/TealiumAnalytics/index.ts +4 -0
  22. package/packages/analytics/src/clients/TealiumAnalytics/interface.ts +35 -0
  23. package/packages/analytics/src/clients/TealiumAnalytics/mappers/__mocks__/mediaPayload.ts +72 -0
  24. package/packages/analytics/src/clients/TealiumAnalytics/mappers/helper.ts +36 -0
  25. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapAppError.ts +13 -0
  26. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapAppOpen.ts +13 -0
  27. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapFavoriteAdd.ts +11 -0
  28. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapFavoriteRemove.ts +11 -0
  29. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapPlayerClose.ts +15 -0
  30. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapPlayerOpen.ts +15 -0
  31. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapSceneView.ts +18 -0
  32. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapSearch.ts +18 -0
  33. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapSearchFailed.ts +8 -0
  34. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapSearchSuccess.ts +8 -0
  35. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoPause.ts +15 -0
  36. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoProgress.ts +18 -0
  37. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoResume.ts +15 -0
  38. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoStart.ts +15 -0
  39. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoStop.ts +15 -0
  40. package/packages/analytics/src/clients/TealiumAnalytics/types.ts +161 -0
  41. package/packages/analytics/src/clients/TwentyFourIQ/TwentyFourIQClient.ts +107 -0
  42. package/packages/analytics/src/clients/TwentyFourIQ/constants.ts +111 -0
  43. package/packages/analytics/src/clients/TwentyFourIQ/helper.ts +34 -0
  44. package/packages/analytics/src/clients/TwentyFourIQ/index.ts +2 -0
  45. package/packages/analytics/src/clients/TwentyFourIQ/interface.ts +34 -0
  46. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapAdEvent.ts +20 -0
  47. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapBase.ts +24 -0
  48. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapBuffering.ts +15 -0
  49. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapPlayerClose.ts +25 -0
  50. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapPlayerOpen.ts +17 -0
  51. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapSceneView.ts +15 -0
  52. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapScroll.ts +17 -0
  53. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoComplete.ts +22 -0
  54. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoPause.ts +25 -0
  55. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoProgress.ts +25 -0
  56. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoStart.ts +34 -0
  57. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoStop.ts +32 -0
  58. package/packages/analytics/src/clients/TwentyFourIQ/types.ts +132 -0
  59. package/packages/analytics/src/constants.ts +1 -0
  60. package/packages/analytics/src/index.ts +3 -0
  61. package/packages/analytics/src/interface.ts +1 -0
  62. package/packages/analytics/src/utils/generateSessionId.ts +8 -0
  63. package/packages/async-image/src/AsyncImage.tsx +15 -10
  64. package/packages/developer-tools/PlayerDebugWindow/README.md +1 -1
  65. package/packages/developer-tools/src/DeveloperConsole/DeveloperConsole.tsx +1 -0
  66. package/packages/developer-tools/src/DeveloperToolsService/DeveloperToolsList.tsx +11 -0
  67. package/packages/developer-tools/src/PlayerDebugWindow/PlayerDebugWindow.tsx +5 -5
  68. package/packages/developer-tools/src/PlayerDebugWindow/constants.ts +15 -0
  69. package/packages/developer-tools/src/TechnicalInfo/TechnicalInfo.tsx +2 -0
  70. package/packages/developer-tools/src/TechnicalInfo/TechnicalInfoDetail.tsx +2 -1
  71. package/packages/developer-tools/src/TechnicalInfo/TechnicalInfoProvider.ts +57 -5
  72. package/packages/developer-tools/src/TechnicalInfo/__mocks__/Device.ts +12 -0
  73. package/packages/developer-tools/src/TechnicalInfo/translations.ts +8 -0
  74. package/packages/device/src/driver/index.android.tv.ts +1 -0
  75. package/packages/device/src/driver/index.firetv.ts +1 -0
  76. package/packages/device/src/driver/index.smartcast.tv.ts +1 -0
  77. package/packages/device/src/getKeyDigit.ts +2 -2
  78. package/packages/device/src/resolver/resolver.ts +19 -0
  79. package/packages/digital-clock/src/DigitalClock.tsx +15 -4
  80. package/packages/driver-androidtv/src/DeviceAndroidTV.ts +262 -0
  81. package/packages/driver-androidtv/src/__mocks__/javaScriptBridge.ts +45 -0
  82. package/packages/driver-androidtv/src/formatUserAgent.ts +11 -0
  83. package/packages/driver-androidtv/src/index.ts +2 -0
  84. package/packages/driver-androidtv/src/keymap.ts +27 -0
  85. package/packages/driver-androidtv/src/types.ts +155 -0
  86. package/packages/driver-base/src/DeviceBase.ts +73 -2
  87. package/packages/driver-base/src/KeyMap/Key.ts +8 -1
  88. package/packages/driver-base/src/KeyMap/KeyMap.ts +4 -0
  89. package/packages/driver-base/src/KeyMap/interface.ts +1 -0
  90. package/packages/driver-base/src/KeyMap/overrideValues.ts +2 -1
  91. package/packages/driver-base/src/__mocks__/DeviceBase.ts +24 -0
  92. package/packages/driver-base/src/__mocks__/keyMap.ts +1 -0
  93. package/packages/driver-base/src/index.ts +3 -0
  94. package/packages/driver-base/src/types/AdInfo.ts +5 -0
  95. package/packages/driver-base/src/types/DeviceEvent.ts +2 -0
  96. package/packages/driver-base/src/types/InAppPurchase.ts +20 -0
  97. package/packages/driver-base/src/types/KeycodeKeyMap.ts +1 -0
  98. package/packages/driver-browser/src/DeviceBrowser.ts +26 -0
  99. package/packages/driver-browser/src/keymap.ts +8 -0
  100. package/packages/driver-entone/src/DeviceEntone.ts +31 -1
  101. package/packages/driver-entone/src/keymap.ts +1 -0
  102. package/packages/driver-firetv/src/DeviceFireTV.ts +86 -0
  103. package/packages/driver-firetv/src/__mocks__/javaScriptBridge.ts +45 -0
  104. package/packages/driver-firetv/src/index.ts +1 -0
  105. package/packages/driver-firetv/src/types.ts +1 -0
  106. package/packages/driver-hbbtv/src/DeviceHbbTV.ts +26 -0
  107. package/packages/driver-kreatv/src/DeviceKreaTV.ts +26 -0
  108. package/packages/driver-saphi/src/DeviceSaphi.ts +26 -0
  109. package/packages/driver-smartcast/src/DeviceSmartCast.ts +380 -0
  110. package/packages/driver-smartcast/src/__mocks__/api.ts +69 -0
  111. package/packages/driver-smartcast/src/index.ts +1 -0
  112. package/packages/driver-smartcast/src/keymap.ts +9 -0
  113. package/packages/driver-smartcast/src/types.ts +102 -0
  114. package/packages/driver-tizen/src/DeviceTizen.ts +121 -7
  115. package/packages/driver-tizen/src/ITizen.ts +15116 -202
  116. package/packages/driver-tizen/src/IWebapis.ts +8643 -87
  117. package/packages/driver-tizen/src/TizenKeys.ts +4 -2
  118. package/packages/driver-tizen/src/__mocks__/tizen.ts +7 -8
  119. package/packages/driver-tizen/src/constants.ts +1 -195
  120. package/packages/driver-vidaa/src/DeviceVidaa.ts +29 -2
  121. package/packages/driver-vidaa/src/__mocks__/vidaa.ts +1 -1
  122. package/packages/driver-vidaa/src/keymap.ts +2 -0
  123. package/packages/driver-webos/src/DeviceWebos.ts +55 -0
  124. package/packages/driver-webos/src/__mocks__/webos.ts +33 -0
  125. package/packages/driver-webos/src/constants.ts +1 -0
  126. package/packages/driver-webos/src/keymap.ts +2 -1
  127. package/packages/driver-webos/src/types.ts +30 -0
  128. package/packages/driver-xbox/src/DeviceXbox.ts +30 -1
  129. package/packages/driver-xbox/src/keymap.ts +1 -1
  130. package/packages/epg/README.md +3 -1
  131. package/packages/epg/src/v2/Cell.tsx +16 -2
  132. package/packages/epg/src/v2/DataManager.ts +112 -41
  133. package/packages/epg/src/v2/DatePicker.tsx +9 -3
  134. package/packages/epg/src/v2/DateToast/DateToast.tsx +12 -9
  135. package/packages/epg/src/v2/Day.tsx +6 -3
  136. package/packages/epg/src/v2/Epg.tsx +5 -5
  137. package/packages/epg/src/v2/MockGenerator/generator.ts +3 -2
  138. package/packages/epg/src/v2/ProgramInfo/utils.ts +4 -3
  139. package/packages/epg/src/v2/Row.tsx +3 -1
  140. package/packages/epg/src/v2/TimelineSection.tsx +4 -1
  141. package/packages/epg/src/v2/basic/CellsManager.tsx +7 -2
  142. package/packages/epg/src/v2/basic/RowsManager.tsx +3 -1
  143. package/packages/epg/src/v2/interface.ts +13 -0
  144. package/packages/events-manager/src/EventsManager.ts +1 -56
  145. package/packages/focus/README.md +33 -0
  146. package/packages/focus/src/IFocusable.ts +1 -0
  147. package/packages/focus/src/Layout/Base.tsx +41 -6
  148. package/packages/focus/src/Layout/Matrix.tsx +51 -19
  149. package/packages/focus/src/focusFirstExisting.ts +7 -1
  150. package/packages/focus/src/hasFocus.ts +36 -0
  151. package/packages/focus/src/index.ts +2 -1
  152. package/packages/gallup/src/Gallup.ts +3 -3
  153. package/packages/grid/src/Base/Base.tsx +15 -10
  154. package/packages/grid/src/FirstOnlyGrid/FirstOnlyGrid.tsx +4 -2
  155. package/packages/grid/src/UnifiedGridController/UnifiedGridController.ts +6 -6
  156. package/packages/icon/src/Icon.tsx +27 -5
  157. package/packages/input/README.md +1 -1
  158. package/packages/input/src/Input.tsx +10 -10
  159. package/packages/interactable/README.md +2 -1
  160. package/packages/interactable/src/Interactable.tsx +9 -3
  161. package/packages/interactable/src/interface.ts +1 -0
  162. package/packages/jsx/src/index.ts +1 -1
  163. package/packages/jsx/src/test-utils/index.ts +1 -0
  164. package/packages/jsx/src/test-utils/keyup.ts +27 -0
  165. package/packages/keyboard/README.md +2 -0
  166. package/packages/keyboard/src/Backdrop/Backdrop.scss +2 -0
  167. package/packages/keyboard/src/KeyboardBase.tsx +16 -4
  168. package/packages/keyboard/src/WhitelabelKeyboard/Keyboard.scss +10 -0
  169. package/packages/keyboard/src/WhitelabelKeyboard/Keyboard.tsx +128 -142
  170. package/packages/keyboard/src/WhitelabelKeyboard/WhitelabelStyles/whitelabel.scss +4 -0
  171. package/packages/keyboard/src/WhitelabelKeyboard/_sizes.1080.scss +1 -0
  172. package/packages/keyboard/src/WhitelabelKeyboard/_sizes.scss +1 -0
  173. package/packages/keyboard/src/WhitelabelKeyboard/icons/key_language.svg +20 -0
  174. package/packages/keyboard/src/WhitelabelKeyboard/index.ts +1 -1
  175. package/packages/keyboard/src/WhitelabelKeyboard/layouts/arabic.ts +27 -0
  176. package/packages/keyboard/src/WhitelabelKeyboard/layouts/burmese.ts +27 -0
  177. package/packages/keyboard/src/WhitelabelKeyboard/layouts/dari.ts +28 -0
  178. package/packages/keyboard/src/WhitelabelKeyboard/layouts/hebrew.ts +28 -0
  179. package/packages/keyboard/src/WhitelabelKeyboard/layouts/index.ts +15 -0
  180. package/packages/keyboard/src/WhitelabelKeyboard/layouts/korean.ts +26 -0
  181. package/packages/keyboard/src/WhitelabelKeyboard/layouts/latin.ts +26 -0
  182. package/packages/keyboard/src/WhitelabelKeyboard/layouts/pashto.ts +27 -0
  183. package/packages/keyboard/src/WhitelabelKeyboard/layouts/persian.ts +27 -0
  184. package/packages/keyboard/src/WhitelabelKeyboard/layouts/russian.ts +27 -0
  185. package/packages/keyboard/src/WhitelabelKeyboard/layouts/spanish.ts +26 -0
  186. package/packages/keyboard/src/WhitelabelKeyboard/layouts/special.ts +28 -0
  187. package/packages/keyboard/src/WhitelabelKeyboard/layouts/tibetan.ts +26 -0
  188. package/packages/keyboard/src/WhitelabelKeyboard/layouts/turkish.ts +26 -0
  189. package/packages/keyboard/src/WhitelabelKeyboard/layouts/ukrainian.ts +27 -0
  190. package/packages/keyboard/src/WhitelabelKeyboard/layouts/urdu.ts +26 -0
  191. package/packages/keyboard/src/WhitelabelKeyboard/types.ts +22 -2
  192. package/packages/keyboard/src/types/index.ts +1 -1
  193. package/packages/keyboard/src/utils/caret.ts +5 -8
  194. package/packages/keyboard/src/utils/input.ts +5 -6
  195. package/packages/keyboard/src/utils/setInputSelectionRange.ts +10 -0
  196. package/packages/l10n/README.md +18 -0
  197. package/packages/l10n/src/date/common.ts +18 -6
  198. package/packages/l10n/src/date/cs.ts +2 -8
  199. package/packages/l10n/src/date/de.ts +97 -0
  200. package/packages/l10n/src/date/en-001.ts +3 -3
  201. package/packages/l10n/src/date/en-common.ts +5 -4
  202. package/packages/l10n/src/date/en-us.ts +3 -3
  203. package/packages/l10n/src/date/es.ts +71 -0
  204. package/packages/l10n/src/date/fr.ts +94 -0
  205. package/packages/l10n/src/date/he.ts +101 -0
  206. package/packages/l10n/src/date/iso.ts +12 -13
  207. package/packages/l10n/src/date/types.ts +9 -0
  208. package/packages/l10n/src/l10n.ts +61 -3
  209. package/packages/list/src/Base/Base.tsx +19 -9
  210. package/packages/list/src/Base/interface.ts +2 -2
  211. package/packages/list/src/BasicList/BasicList.tsx +7 -7
  212. package/packages/list/src/CenteredList/CenteredList.tsx +2 -2
  213. package/packages/list/src/CenteredList/controller.ts +0 -1
  214. package/packages/list/src/EdgeOffsetList/EdgeOffsetList.tsx +10 -10
  215. package/packages/list/src/FirstOnlyList/FirstOnlyList.tsx +2 -2
  216. package/packages/list/src/FirstOnlyVariedList/FirstOnlyVariedList.tsx +2 -2
  217. package/packages/list/src/FixedToEndList/FixedToEndList.tsx +2 -2
  218. package/packages/list/src/UnifiedListController/UnifiedListController.ts +6 -2
  219. package/packages/list/src/interface.ts +2 -2
  220. package/packages/logger/src/loggers/ConsoleLogger/ConsoleLogger.ts +7 -1
  221. package/packages/logger/src/loggers/SentryLogger/Sentry.ts +1 -0
  222. package/packages/logger/src/loggers/SentryLogger/SentryLogger.ts +5 -3
  223. package/packages/menu/src/MenuAndContentContainer/MenuAndContentContainer.tsx +31 -3
  224. package/packages/menu/src/MenuAndContentContainer/interface.ts +8 -0
  225. package/packages/modal-service/README.md +4 -1
  226. package/packages/modal-service/src/ModalService.tsx +29 -5
  227. package/packages/perf-utils/README.md +1 -120
  228. package/packages/perf-utils/src/array/filter.ts +1 -54
  229. package/packages/perf-utils/src/array/find.ts +1 -43
  230. package/packages/perf-utils/src/array/findIndex.ts +1 -43
  231. package/packages/perf-utils/src/array/forEach.ts +1 -48
  232. package/packages/perf-utils/src/array/includes.ts +1 -41
  233. package/packages/perf-utils/src/array/includesNaN.ts +1 -32
  234. package/packages/perf-utils/src/array/index.ts +1 -7
  235. package/packages/perf-utils/src/array/map.ts +1 -52
  236. package/packages/player-ui/README.md +1 -1
  237. package/packages/player-ui/src/CurrentTime.tsx +2 -2
  238. package/packages/player-ui/src/Duration.tsx +2 -2
  239. package/packages/player-ui/src/PauseButton.tsx +8 -0
  240. package/packages/player-ui/src/PlayerInteractable.tsx +1 -0
  241. package/packages/player-ui/src/PlayerTime.tsx +3 -1
  242. package/packages/player-ui/src/PlayerUI.tsx +68 -35
  243. package/packages/player-ui/src/RemainingTime.tsx +2 -2
  244. package/packages/player-ui/src/Seekbar.tsx +110 -18
  245. package/packages/player-ui/src/Seeking.ts +57 -16
  246. package/packages/player-ui/src/Subtitles.tsx +2 -2
  247. package/packages/player-ui/src/index.ts +1 -0
  248. package/packages/player-ui/src/mocks.ts +32 -8
  249. package/packages/player-ui/src/timeUtils.ts +3 -3
  250. package/packages/player-ui/src/types.ts +9 -3
  251. package/packages/router/README.md +1 -0
  252. package/packages/router/src/Route.tsx +61 -27
  253. package/packages/router/src/Router.tsx +63 -14
  254. package/packages/router/src/history.ts +8 -1
  255. package/packages/router/src/index.ts +1 -1
  256. package/packages/router/src/utils.ts +9 -4
  257. package/packages/sass-utils/src/linear-gradient.scss +9 -4
  258. package/packages/sass-utils/src/scale.1080.scss +3 -1
  259. package/packages/sass-utils/src/scale.720.scss +1 -1
  260. package/packages/time/README.md +4 -1
  261. package/packages/time/src/Time.ts +35 -13
  262. package/packages/time/src/adapters/24iMediaTimeApi.ts +47 -0
  263. package/packages/time/src/constants.ts +1 -0
  264. package/packages/time/src/services/24iMediaTimeApi/24iMediaTimeApi.ts +43 -0
  265. package/packages/time/src/services/24iMediaTimeApi/index.ts +6 -0
  266. package/packages/toast/src/ToastService.scss +1 -0
  267. package/packages/toast/src/ToastService.tsx +16 -5
  268. package/packages/types-bigscreen-jsx/README.md +5 -4
  269. package/packages/types-bigscreen-jsx/index.d.ts +72 -67
  270. package/packages/utils/README.md +27 -0
  271. package/packages/utils/src/elementUtils.ts +25 -0
  272. package/packages/utils/src/forceReflow.ts +14 -0
  273. package/packages/utils/src/index.ts +8 -0
  274. package/packages/utils/src/keyPress/index.ts +6 -0
  275. package/packages/utils/src/keyPress/keyPressSimulator.ts +74 -0
  276. package/packages/utils/src/keyPress/simulateKeyPress.ts +25 -0
  277. package/packages/utils/src/scaledImage.ts +6 -3
  278. package/packages/utils/src/textUtils.ts +46 -14
  279. package/packages/utils/src/wait.ts +3 -1
  280. package/packages/utils/src/xhr/xhrSend.ts +3 -1
  281. package/packages/utils/src/xhr/xhrSendRetry.ts +3 -1
  282. package/packages/zapping/src/ChannelZapping.ts +9 -0
  283. package/packages/zapping/src/Zapping.tsx +10 -0
  284. package/utils/release/release.ts +156 -0
  285. package/packages/driver-tizen/src/types.ts +0 -14
  286. package/packages/focus/src/Layout/__test__/Base.spec.ts +0 -180
  287. package/packages/focus/src/Layout/__test__/Horizontal.spec.ts +0 -94
  288. package/packages/focus/src/Layout/__test__/Matrix.spec.ts +0 -261
  289. package/packages/focus/src/Layout/__test__/Vertical.spec.ts +0 -46
  290. package/packages/focus/src/Layout/__test__/isRtl.spec.ts +0 -23
  291. package/packages/focus/src/Layout/__test__/shared.ts +0 -19
  292. package/packages/keyboard/src/WhitelabelKeyboard/focusMatrix.ts +0 -19
@@ -1,33 +1,42 @@
1
1
  import { Component, createRef } from '@24i/bigscreen-sdk/jsx';
2
2
  import { IFocusable } from '@24i/bigscreen-sdk/focus';
3
3
  import { stopEvent } from '@24i/bigscreen-sdk/utils/stopEvent';
4
- import { ITimeUpdateEvent, IDurationChangeEvent } from '@24i/player-base';
4
+ import { ITimeUpdateEvent, IDurationChangeEvent } from '@24i/bigscreen-players-engine-base';
5
5
  import { createTimeout } from '@24i/bigscreen-sdk/utils/timers';
6
6
  import { switchByKey } from '@24i/bigscreen-sdk/device/keymap';
7
+ import { getDisplayToggler } from '@24i/bigscreen-sdk/utils/displayToggler';
7
8
  import { PlayerTime } from './PlayerTime';
8
9
  import { getLiveProgressBasedOnCurrentTime } from './timeUtils';
9
- import { PlayerUICommonProps } from './types';
10
+ import { IPlayerUIWithSeeking, PlayerUICommonProps } from './types';
10
11
 
11
12
  const CONSECUTIVE_TIMEOUT = 500;
12
13
  const FAST_TRESHOLD = 5;
13
14
  const SLOW_TIME = 10000;
14
- const FAST_TIME = 20000;
15
+ const FAST_TIME = 30000;
16
+ const SAFE_END_MARGIN = 10000;
15
17
  const TO_PERCENT = 100;
16
18
 
17
- type Props = PlayerUICommonProps;
19
+ type Props = {
20
+ ui: IPlayerUIWithSeeking;
21
+ children?: JSX.Element;
22
+ } & PlayerUICommonProps;
18
23
 
19
24
  export class Seekbar extends Component<Props> implements IFocusable {
20
25
  wrap = createRef<HTMLDivElement>();
21
26
 
27
+ seekBarWrap = createRef<HTMLDivElement>();
28
+
22
29
  seekBar = createRef<HTMLDivElement>();
23
30
 
24
31
  seekPoint = createRef<HTMLDivElement>();
25
32
 
26
33
  seekTime = createRef<PlayerTime>();
27
34
 
28
- leftConsecutives = 0;
35
+ displaySeekPoint = getDisplayToggler(this.seekPoint);
36
+
37
+ leftConsecutiveness = 0;
29
38
 
30
- rightConsecutives = 0;
39
+ rightConsecutiveness = 0;
31
40
 
32
41
  leftConsecutiveTimeout = createTimeout();
33
42
 
@@ -37,6 +46,10 @@ export class Seekbar extends Component<Props> implements IFocusable {
37
46
 
38
47
  duration = 0;
39
48
 
49
+ isMouseDownPressed = false;
50
+
51
+ seekingDisabled = false;
52
+
40
53
  static defaultProps = {
41
54
  className: '',
42
55
  };
@@ -45,18 +58,59 @@ export class Seekbar extends Component<Props> implements IFocusable {
45
58
  const { ui } = this.props;
46
59
  const playerInstance = ui.getPlayer();
47
60
  this.duration = playerInstance.duration;
61
+ document.addEventListener('mouseup', this.onMouseUp);
62
+ document.addEventListener('mousemove', this.onMouseMove);
48
63
  ui.seeking.addEventListener('seektimeupdate', this.onSeekTimeUpdate);
64
+ ui.seeking.addEventListener('stopautomaticseek', this.onStopAutomaticSeek);
49
65
  ui.getPlayer().addEventListener('timeupdate', this.onTimeUpdate);
50
66
  ui.getPlayer().addEventListener('durationchange', this.onDurationUpdate);
51
67
  }
52
68
 
53
69
  componentWillUnmount() {
54
70
  const { ui } = this.props;
71
+ document.removeEventListener('mouseup', this.onMouseUp);
72
+ document.removeEventListener('mousemove', this.onMouseMove);
55
73
  ui.seeking.removeEventListener('seektimeupdate', this.onSeekTimeUpdate);
74
+ ui.seeking.removeEventListener('stopautomaticseek', this.onStopAutomaticSeek);
56
75
  ui.getPlayer().removeEventListener('timeupdate', this.onTimeUpdate);
57
76
  ui.getPlayer().removeEventListener('durationchange', this.onDurationUpdate);
58
77
  }
59
78
 
79
+ onMouseMove = (event: MouseEvent) => {
80
+ if (!this.isMouseDownPressed || this.seekingDisabled) return;
81
+ const { ui: { seeking } } = this.props;
82
+ const wrapRect = this.wrap.current!.getBoundingClientRect();
83
+ const clientX = event.clientX - wrapRect.left;
84
+ const wrapRight = wrapRect.right - wrapRect.left;
85
+ let percentage = (TO_PERCENT * clientX) / wrapRight;
86
+ percentage = Math.max(0, Math.min(TO_PERCENT, percentage));
87
+ const seekTo = Math.round((this.duration / TO_PERCENT) * percentage);
88
+ seeking.setSeekTime(seekTo);
89
+ };
90
+
91
+ onMouseClick = (event: MouseEvent) => {
92
+ if (this.seekingDisabled) return;
93
+ const { ui: { seeking } } = this.props;
94
+ const wrapWidth = this.wrap.current!.offsetWidth;
95
+ const percentage = (TO_PERCENT * event.offsetX) / wrapWidth;
96
+ const seekTo = Math.round((this.duration / TO_PERCENT) * percentage);
97
+ seeking.setSeekTime(seekTo);
98
+ seeking.confirmSeek();
99
+ };
100
+
101
+ onMouseDown = () => {
102
+ const { ui } = this.props;
103
+ this.isMouseDownPressed = true;
104
+ ui.disableHiding();
105
+ };
106
+
107
+ onMouseUp = () => {
108
+ const { ui } = this.props;
109
+ this.isMouseDownPressed = false;
110
+ ui.seeking.confirmSeek();
111
+ ui.enableHiding();
112
+ };
113
+
60
114
  onKeyDown = (event: KeyboardEvent) => {
61
115
  const processed = switchByKey(event, {
62
116
  LEFT: this.onLeft,
@@ -72,34 +126,50 @@ export class Seekbar extends Component<Props> implements IFocusable {
72
126
  };
73
127
 
74
128
  onLeft = () => {
129
+ if (this.seekingDisabled) return true;
75
130
  const { ui } = this.props;
76
- this.leftConsecutives += 1;
131
+ this.leftConsecutiveness += 1;
77
132
  if (ui.seeking.isAutomaticallySeeking()) {
78
133
  ui.seeking.stopAutomaticSeek();
79
134
  }
80
- ui.seeking.seekBackward(this.leftConsecutives >= FAST_TRESHOLD ? FAST_TIME : SLOW_TIME);
135
+ ui.seeking.seekBackward(this.leftConsecutiveness >= FAST_TRESHOLD ? FAST_TIME : SLOW_TIME);
81
136
  this.leftConsecutiveTimeout.set(() => {
82
- this.leftConsecutives = 0;
137
+ this.leftConsecutiveness = 0;
83
138
  }, CONSECUTIVE_TIMEOUT);
84
139
  return true;
85
140
  };
86
141
 
87
142
  onRight = () => {
143
+ if (this.seekingDisabled) return true;
88
144
  const { ui } = this.props;
89
- this.rightConsecutives += 1;
145
+ const { seekTime } = ui.seeking;
146
+ if (seekTime == null && this.currentTime + SLOW_TIME >= this.duration) return true;
147
+ this.rightConsecutiveness += 1;
90
148
  if (ui.seeking.isAutomaticallySeeking()) {
91
149
  ui.seeking.stopAutomaticSeek();
92
150
  }
93
- ui.seeking.seekForward(this.rightConsecutives >= FAST_TRESHOLD ? FAST_TIME : SLOW_TIME);
151
+ const isFastSeeking = this.rightConsecutiveness >= FAST_TRESHOLD;
152
+ if (
153
+ (seekTime != null
154
+ && (seekTime + SLOW_TIME >= this.duration - SAFE_END_MARGIN
155
+ || (isFastSeeking && seekTime + FAST_TIME >= this.duration - SAFE_END_MARGIN)))
156
+ || (seekTime == null && this.currentTime >= this.duration - SAFE_END_MARGIN)
157
+ ) {
158
+ ui.seeking.setSeekTime(this.duration - SAFE_END_MARGIN);
159
+ } else {
160
+ ui.seeking.seekForward(isFastSeeking ? FAST_TIME : SLOW_TIME);
161
+ }
94
162
  this.rightConsecutiveTimeout.set(() => {
95
- this.rightConsecutives = 0;
163
+ this.rightConsecutiveness = 0;
96
164
  }, CONSECUTIVE_TIMEOUT);
97
165
  return true;
98
166
  };
99
167
 
100
168
  onEnter = () => {
101
- const { ui } = this.props;
102
- return ui.seeking.confirmSeek();
169
+ const { ui: { seeking, getPlayer } } = this.props;
170
+ const player = getPlayer();
171
+ if (!player.playing) player.play();
172
+ return seeking.confirmSeek();
103
173
  };
104
174
 
105
175
  onSeekTimeUpdate = (seekTime: number) => {
@@ -108,6 +178,11 @@ export class Seekbar extends Component<Props> implements IFocusable {
108
178
  this.updateSeekBar();
109
179
  };
110
180
 
181
+ onStopAutomaticSeek = () => {
182
+ const { ui } = this.props;
183
+ ui.enableHiding();
184
+ };
185
+
111
186
  onTimeUpdate = ({ currentTime }: ITimeUpdateEvent) => {
112
187
  const { ui } = this.props;
113
188
  this.currentTime = currentTime;
@@ -121,7 +196,7 @@ export class Seekbar extends Component<Props> implements IFocusable {
121
196
  const { ui } = this.props;
122
197
  const player = ui.getPlayer();
123
198
  if (player.live) {
124
- const { programStart = 0, programEnd = 0 } = player.getMetadata();
199
+ const { programStart = 0, programEnd = 0 } = player.metadata;
125
200
  this.duration = programEnd - programStart || Date.now();
126
201
  } else {
127
202
  this.duration = duration;
@@ -133,7 +208,7 @@ export class Seekbar extends Component<Props> implements IFocusable {
133
208
  const { ui } = this.props;
134
209
  const player = ui.getPlayer();
135
210
  if (player.live) {
136
- const { programStart = 0, programEnd = 0 } = player.getMetadata();
211
+ const { programStart = 0, programEnd = 0 } = player.metadata;
137
212
  const { start, end } = player.seekableRange;
138
213
  return getLiveProgressBasedOnCurrentTime(
139
214
  programStart,
@@ -160,17 +235,34 @@ export class Seekbar extends Component<Props> implements IFocusable {
160
235
  this.seekPoint.current!.style.left = `${percentTime}%`;
161
236
  }
162
237
 
238
+ disableSeeking() {
239
+ this.seekingDisabled = true;
240
+ this.displaySeekPoint.hide();
241
+ }
242
+
243
+ enableSeeking() {
244
+ this.seekingDisabled = false;
245
+ this.displaySeekPoint.show();
246
+ }
247
+
248
+ isSeekingDisabled() {
249
+ return this.seekingDisabled;
250
+ }
251
+
163
252
  render() {
164
- const { className } = this.props;
253
+ const { children, className } = this.props;
165
254
  return (
166
255
  <div
167
256
  className={`seek-bar ${className}`}
168
257
  ref={this.wrap}
169
258
  tabIndex={0}
170
259
  onKeyDown={this.onKeyDown}
260
+ onMouseDown={this.onMouseDown}
261
+ onClick={this.onMouseClick}
171
262
  onBlur={this.onBlur}
172
263
  >
173
- <div className="bar">
264
+ {children}
265
+ <div className="bar" ref={this.seekBarWrap}>
174
266
  <div className="bg" ref={this.seekBar} />
175
267
  </div>
176
268
  <div className="point" ref={this.seekPoint}>
@@ -1,9 +1,12 @@
1
1
  import { IEvents, EventMapType, EventsManager } from '@24i/bigscreen-sdk/events-manager';
2
- import { createInterval } from '@24i/bigscreen-sdk/utils/timers';
3
- import { PlayerBase } from '@24i/player-base';
2
+ import { createInterval, createTimeout } from '@24i/bigscreen-sdk/utils/timers';
3
+ import { PlayerBase } from '@24i/bigscreen-players-engine-base';
4
4
 
5
- const DEFAULT_SEEK_TIME = 20000;
5
+ const DEFAULT_SEEK_TIME = 10000;
6
+ const FAST_SEEK_TIME = 30000;
6
7
  const AUTOMATIC_SEEK_INTERVAL = 300;
8
+ const FAST_THRESHOLD = 5;
9
+ const CONSECUTIVE_TIMEOUT = 500;
7
10
 
8
11
  interface SeekingEventsMap extends EventMapType {
9
12
  'seektimeupdate': (payload: number) => void,
@@ -23,13 +26,21 @@ export class Seeking implements IEvents<SeekingEventsMap> {
23
26
 
24
27
  automaticSeekInterval = createInterval();
25
28
 
26
- player: PlayerBase<any> | null;
29
+ player: PlayerBase | null;
27
30
 
28
31
  isAutomaticallySeekingForward = false;
29
32
 
30
33
  isAutomaticallySeekingBackward = false;
31
34
 
32
- constructor(player: PlayerBase<any> | null = null) {
35
+ ffConsecutiveness = 0;
36
+
37
+ rewConsecutiveness = 0;
38
+
39
+ ffConsecutiveTimeout = createTimeout();
40
+
41
+ rewConsecutiveTimeout = createTimeout();
42
+
43
+ constructor(player: PlayerBase | null = null) {
33
44
  this.player = player;
34
45
  }
35
46
 
@@ -41,7 +52,7 @@ export class Seeking implements IEvents<SeekingEventsMap> {
41
52
  this.player!.removeEventListener('seeked', this.nullSeekTime);
42
53
  }
43
54
 
44
- setPlayer(player: PlayerBase<any>) {
55
+ setPlayer(player: PlayerBase) {
45
56
  this.player = player;
46
57
  }
47
58
 
@@ -76,28 +87,53 @@ export class Seeking implements IEvents<SeekingEventsMap> {
76
87
  this.triggerEvent('seektimeupdate', this.seekTime!);
77
88
  }
78
89
 
79
- startAutomaticSeekForward() {
80
- this.stopAutomaticSeek();
90
+ automaticSeekForward() {
91
+ if (this.isAutomaticallySeekingForward) {
92
+ this.ffConsecutiveTimeout.set(() => {
93
+ this.ffConsecutiveness = 0;
94
+ }, CONSECUTIVE_TIMEOUT);
95
+ this.ffConsecutiveness += 1;
96
+ if (this.ffConsecutiveness === FAST_THRESHOLD) {
97
+ this.automaticSeekInterval.set(
98
+ () => this.seekForward(FAST_SEEK_TIME),
99
+ AUTOMATIC_SEEK_INTERVAL,
100
+ );
101
+ }
102
+ return;
103
+ }
81
104
  this.isAutomaticallySeekingForward = true;
105
+ this.ffConsecutiveness += 1;
82
106
  this.seekForward();
83
- this.automaticSeekInterval.set(() => {
84
- this.seekForward();
85
- }, AUTOMATIC_SEEK_INTERVAL);
107
+ this.automaticSeekInterval.set(() => this.seekForward(), AUTOMATIC_SEEK_INTERVAL);
86
108
  }
87
109
 
88
- startAutomaticSeekBackward() {
89
- this.stopAutomaticSeek();
110
+ automaticSeekBackward() {
111
+ if (this.isAutomaticallySeekingBackward) {
112
+ this.rewConsecutiveTimeout.set(() => {
113
+ this.rewConsecutiveness = 0;
114
+ }, CONSECUTIVE_TIMEOUT);
115
+ this.rewConsecutiveness += 1;
116
+ if (this.rewConsecutiveness === FAST_THRESHOLD) {
117
+ this.automaticSeekInterval.set(
118
+ () => this.seekBackward(FAST_SEEK_TIME),
119
+ AUTOMATIC_SEEK_INTERVAL,
120
+ );
121
+ }
122
+ return;
123
+ }
90
124
  this.isAutomaticallySeekingBackward = true;
125
+ this.rewConsecutiveness += 1;
91
126
  this.seekBackward();
92
- this.automaticSeekInterval.set(() => {
93
- this.seekBackward();
94
- }, AUTOMATIC_SEEK_INTERVAL);
127
+ this.automaticSeekInterval.set(() => this.seekBackward(), AUTOMATIC_SEEK_INTERVAL);
95
128
  }
96
129
 
97
130
  stopAutomaticSeek() {
131
+ if (this.isAutomaticallySeeking()) this.triggerEvent('stopautomaticseek');
98
132
  this.automaticSeekInterval.clear();
99
133
  this.isAutomaticallySeekingForward = false;
100
134
  this.isAutomaticallySeekingBackward = false;
135
+ this.ffConsecutiveness = 0;
136
+ this.rewConsecutiveness = 0;
101
137
  }
102
138
 
103
139
  cancelSeek() {
@@ -110,6 +146,11 @@ export class Seeking implements IEvents<SeekingEventsMap> {
110
146
  this.triggerEvent('seektimeupdate', this.seekTime!);
111
147
  };
112
148
 
149
+ setSeekTime = (seekTime: number) => {
150
+ this.seekTime = seekTime;
151
+ this.triggerEvent('seektimeupdate', this.seekTime!);
152
+ };
153
+
113
154
  confirmSeek() {
114
155
  if (!this.player) return false;
115
156
  this.stopAutomaticSeek();
@@ -1,11 +1,11 @@
1
- import { PlayerBase, ITimeUpdateEvent } from '@24i/player-base';
1
+ import { PlayerBase, ITimeUpdateEvent } from '@24i/bigscreen-players-engine-base';
2
2
  import { Component, createRef, DeclareProps, setText } from '@24i/bigscreen-sdk/jsx';
3
3
  import { getDisplayToggler } from '@24i/bigscreen-sdk/utils';
4
4
  import { SubtitlesType } from '@24i/smartapps-datalayer/src/models';
5
5
  import { timeToMs } from './timeUtils';
6
6
 
7
7
  type Props = {
8
- player: PlayerBase<any>,
8
+ player: PlayerBase,
9
9
  className?: string,
10
10
  };
11
11
 
@@ -1,5 +1,6 @@
1
1
  export { PlayerUI } from './PlayerUI';
2
2
  export type { PlayerUIState } from './PlayerUI';
3
+ export type { IPlayerUIWithSeeking } from './types';
3
4
  export { BackwardButton } from './BackwardButton';
4
5
  export { CurrentTime } from './CurrentTime';
5
6
  export { Duration } from './Duration';
@@ -1,8 +1,8 @@
1
- import { PlayerBase, PlayerBaseMock } from '@24i/player-base';
1
+ import { IPlayerProperties, PlayerBase, PlayerBaseMock } from '@24i/bigscreen-players-engine-base';
2
2
  import { EventsManager } from '@24i/bigscreen-sdk/events-manager';
3
- import { IPlayerUI } from './types';
3
+ import { IPlayerUIWithSeeking } from './types';
4
4
 
5
- const getSeekingMock = (): jest.Mocked<IPlayerUI['seeking']> => ({
5
+ const getSeekingMock = (): jest.Mocked<IPlayerUIWithSeeking['seeking']> => ({
6
6
  events: {} as EventsManager<{}>,
7
7
  addEventListener: jest.fn(),
8
8
  removeEventListener: jest.fn(),
@@ -13,12 +13,16 @@ const getSeekingMock = (): jest.Mocked<IPlayerUI['seeking']> => ({
13
13
  isAutomaticallySeeking: jest.fn(),
14
14
  isAutomaticallySeekingForward: false,
15
15
  isAutomaticallySeekingBackward: false,
16
+ ffConsecutiveness: 0,
17
+ rewConsecutiveness: 0,
18
+ ffConsecutiveTimeout: null!,
19
+ rewConsecutiveTimeout: null!,
16
20
  isSeeking: jest.fn(),
17
21
  startSeeking: jest.fn(),
18
22
  seekForward: jest.fn(),
19
23
  seekBackward: jest.fn(),
20
- startAutomaticSeekForward: jest.fn(),
21
- startAutomaticSeekBackward: jest.fn(),
24
+ automaticSeekForward: jest.fn(),
25
+ automaticSeekBackward: jest.fn(),
22
26
  stopAutomaticSeek: jest.fn(),
23
27
  cancelSeek: jest.fn(),
24
28
  confirmSeek: jest.fn(),
@@ -26,16 +30,36 @@ const getSeekingMock = (): jest.Mocked<IPlayerUI['seeking']> => ({
26
30
  unsubscribeEvents: jest.fn(),
27
31
  setPlayer: jest.fn(),
28
32
  nullSeekTime: jest.fn(),
33
+ setSeekTime: jest.fn(),
29
34
  });
30
35
 
31
- export const getPlayerMock = (): PlayerBase<any> => new PlayerBaseMock();
36
+ const PLAYER_MOCK_DURATION = 60000;
32
37
 
33
- export const getUiMock = (): { ui: jest.Mocked<IPlayerUI> } => ({
38
+ export const getPlayerMock = (): PlayerBase => {
39
+ const initialConfig: IPlayerProperties = {
40
+ source: {
41
+ url: '',
42
+ },
43
+ };
44
+ const parentElement = document.createElement('div');
45
+
46
+ const playerMock = new PlayerBaseMock(initialConfig, parentElement);
47
+ playerMock.source = initialConfig.source;
48
+ jest.spyOn(playerMock, 'duration', 'get').mockReturnValue(PLAYER_MOCK_DURATION);
49
+
50
+ return playerMock;
51
+ };
52
+
53
+ export const getUiMock = (): { ui: jest.Mocked<IPlayerUIWithSeeking> } => ({
34
54
  ui: {
35
- getPlayer: jest.fn((): PlayerBase<any> => getPlayerMock()),
55
+ getPlayer: jest.fn((): PlayerBase => getPlayerMock()),
36
56
  heartbeat: jest.fn(),
37
57
  trigger: jest.fn(),
38
58
  isPlaying: jest.fn(),
59
+ enableHiding: jest.fn(),
60
+ disableHiding: jest.fn(),
61
+ enableSeeking: jest.fn(),
62
+ disableSeeking: jest.fn(),
39
63
  seeking: getSeekingMock(),
40
64
  },
41
65
  });
@@ -63,9 +63,9 @@ export const formatTime = (duration: number, pattern: string) => {
63
63
  const unitValues = calculateUnitValues(duration, units);
64
64
  let result: string = pattern;
65
65
  forEach(matches, (match) => {
66
- const formatedValue = Number.isNaN(unitValues[match.unit]) ?
67
- '--' :
68
- unitValues[match.unit]!.toString().padStart(match.count, '0');
66
+ const formatedValue = Number.isNaN(unitValues[match.unit])
67
+ ? '--'
68
+ : unitValues[match.unit]!.toString().padStart(match.count, '0');
69
69
  result = result.replace(
70
70
  match.completeMatch,
71
71
  formatedValue,
@@ -1,4 +1,4 @@
1
- import { PlayerBase } from '@24i/player-base';
1
+ import { PlayerBase } from '@24i/bigscreen-players-engine-base';
2
2
  import { Seeking } from './Seeking';
3
3
 
4
4
  export enum PlayerAction {
@@ -20,8 +20,12 @@ export interface ActionsWithPayloadMap {
20
20
  }
21
21
 
22
22
  export interface IPlayerUI {
23
- seeking: Seeking;
24
- getPlayer: () => PlayerBase<any>,
23
+ seeking?: Seeking;
24
+ getPlayer: () => PlayerBase,
25
+ disableHiding: () => void,
26
+ enableHiding: () => void,
27
+ disableSeeking: () => void,
28
+ enableSeeking: () => void,
25
29
  heartbeat: () => void,
26
30
  trigger<K extends keyof ActionsWithoutPayloadMap>(action: K): void,
27
31
  trigger<K extends keyof ActionsWithPayloadMap>(
@@ -30,6 +34,8 @@ export interface IPlayerUI {
30
34
  isPlaying: () => boolean,
31
35
  }
32
36
 
37
+ export type IPlayerUIWithSeeking = Required<IPlayerUI>;
38
+
33
39
  export type PlayerUICommonProps = {
34
40
  ui: IPlayerUI,
35
41
  className?: string,
@@ -16,6 +16,7 @@ It will take care of route switching based on hash changes. It also supports par
16
16
  - `children` - Routes
17
17
  - `defaultPath` - optional path to which go after Router is mounted (default: `/`)
18
18
  - `detachInactiveRoutes` - optional flag if routes should detach from DOM entirely during route switching (default: `true`)
19
+ - `canBack` - optional function whether the router can route back
19
20
 
20
21
  ### Interface
21
22
  - `getActiveRoute()`*: Route | null* - Returns active route component
@@ -3,36 +3,38 @@ import {
3
3
  Component,
4
4
  createRef,
5
5
  detachNode,
6
+ Reference,
6
7
  replaceNode,
7
8
  } from '@24i/bigscreen-sdk/jsx';
8
9
  import { filter, forEach } from '@24i/bigscreen-sdk/perf-utils/array';
10
+ import { addClass, removeClass } from '@24i/bigscreen-sdk/utils';
11
+ import { ModalService } from '@24i/bigscreen-sdk/modal-service';
12
+ import { menuService } from '@24i/bigscreen-sdk/menu';
9
13
  import { getCurrentHash } from './utils';
10
14
  import { IRoute, RouteParams } from './types';
11
15
 
12
16
  type Props = {
13
17
  path: string,
18
+ domParent?: Reference<HTMLElement>;
14
19
  regexpPath?: RegExp,
15
20
  paramNames?: string[],
16
- isDetachable?: boolean;
17
21
  Component: Function,
18
22
  };
19
23
 
24
+ const MRCU_DISABLED = 'mrcu-disabled';
25
+
20
26
  export class Route extends Component<Props> {
21
27
  wasCreated = false;
22
28
 
23
29
  isDetached = false;
24
30
 
25
- domParent: HTMLElement | null = null;
26
-
27
31
  domRef = createRef<HTMLDivElement>();
28
32
 
29
33
  component = createRef<IRoute | null>();
30
34
 
31
- componentDidMount() {
32
- const { isDetachable } = this.props;
33
- this.domParent = this.domRef.current?.parentElement!;
34
- if (isDetachable) this.detach();
35
- }
35
+ modalService = createRef<ModalService>();
36
+
37
+ shouldCallReactivateOnCloseModal = false;
36
38
 
37
39
  getParams(): RouteParams {
38
40
  const { regexpPath, paramNames } = this.props;
@@ -49,21 +51,50 @@ export class Route extends Component<Props> {
49
51
  return {};
50
52
  }
51
53
 
54
+ onMenuVisibilityChange = (isVisible: boolean) => {
55
+ if (isVisible) {
56
+ addClass(this.domRef, MRCU_DISABLED);
57
+ } else {
58
+ removeClass(this.domRef, MRCU_DISABLED);
59
+ }
60
+ };
61
+
62
+ onCloseModalService = () => {
63
+ if (this.shouldCallReactivateOnCloseModal) {
64
+ this.component.current?.reactivate(this.getParams());
65
+ }
66
+ this.shouldCallReactivateOnCloseModal = false;
67
+ };
68
+
69
+ getModalService() {
70
+ if (!this.modalService.current) {
71
+ this.appendMount(
72
+ <ModalService
73
+ ref={this.modalService}
74
+ onCloseLastModal={this.onCloseModalService}
75
+ />,
76
+ this.domRef,
77
+ );
78
+ }
79
+ return this.modalService;
80
+ }
81
+
52
82
  show() {
53
- this.showRoute();
83
+ menuService.addEventListener('visibilitychange', this.onMenuVisibilityChange);
54
84
  if (!this.wasCreated) {
55
85
  this.mountRoute();
56
86
  this.component.current?.activate(this.getParams());
87
+ } else if (this.modalService.current?.isOpen()) {
88
+ this.focusModal();
89
+ this.shouldCallReactivateOnCloseModal = true;
57
90
  } else {
58
91
  this.component.current?.reactivate(this.getParams());
59
92
  }
60
93
  }
61
94
 
62
95
  hide() {
63
- if (this.wasCreated) {
64
- this.component.current?.deactivate();
65
- this.hideRoute();
66
- }
96
+ menuService.removeEventListener('visibilitychange', this.onMenuVisibilityChange);
97
+ this.deactivate();
67
98
  }
68
99
 
69
100
  replace(newRoute: Route) {
@@ -75,8 +106,9 @@ export class Route extends Component<Props> {
75
106
  }
76
107
 
77
108
  attach() {
109
+ const { domParent } = this.props;
78
110
  if (this.isDetached) {
79
- attachNode(this.domRef, this.domParent!);
111
+ attachNode(this.domRef, domParent!);
80
112
  this.isDetached = false;
81
113
  }
82
114
  }
@@ -94,20 +126,27 @@ export class Route extends Component<Props> {
94
126
  }
95
127
  }
96
128
 
129
+ private focusModal() {
130
+ const mountedComponent = this.modalService.current!.getMountedComponent();
131
+ mountedComponent.current?.focus();
132
+ }
133
+
97
134
  focus() {
98
135
  if (this.wasCreated) {
99
- this.component.current?.focus();
136
+ if (this.modalService.current?.isOpen()) {
137
+ this.focusModal();
138
+ } else {
139
+ this.component.current?.focus();
140
+ }
100
141
  }
101
142
  }
102
143
 
103
- private showRoute() {
104
- const { isDetachable } = this.props;
105
- if (!isDetachable) this.domRef.current!.style.display = 'block';
144
+ showRoute() {
145
+ this.domRef.current!.style.display = 'block';
106
146
  }
107
147
 
108
- private hideRoute() {
109
- const { isDetachable } = this.props;
110
- if (!isDetachable) this.domRef.current!.style.display = 'none';
148
+ hideRoute() {
149
+ this.domRef.current!.style.display = 'none';
111
150
  }
112
151
 
113
152
  private mountRoute() {
@@ -120,13 +159,8 @@ export class Route extends Component<Props> {
120
159
  }
121
160
 
122
161
  render() {
123
- const { isDetachable } = this.props;
124
162
  return (
125
- <div
126
- className="route"
127
- style={!isDetachable ? { display: 'none' } : {}}
128
- ref={this.domRef}
129
- />
163
+ <div className="route" ref={this.domRef} />
130
164
  );
131
165
  }
132
166
  }