@playkit-js/transcript 3.0.1 → 3.1.0-canary.2-d22690c

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.
@@ -1,23 +1,17 @@
1
1
  import {h} from 'preact';
2
2
  import {OnClickEvent} from '@playkit-js/common';
3
3
  import {ui} from 'kaltura-player-js';
4
- import {ObjectUtils} from './utils';
4
+ import {UpperBarManager, SidePanelsManager} from '@playkit-js/ui-managers';
5
+ import {ObjectUtils, downloadContent, printContent} from './utils';
6
+ import {icons} from './components/icons';
5
7
  import {PluginButton} from './components/plugin-button/plugin-button';
6
8
  import {Transcript} from './components/transcript';
7
9
  import {getConfigValue, isBoolean, makePlainText, prepareCuePoint} from './utils';
8
- import {TranscriptConfig, PluginPositions, PluginStates, HighlightedMap, CuePointData, ItemTypes, CuePoint} from './types';
9
- import {DownloadPrintMenu, downloadContent, printContent} from './components/download-print-menu';
10
+ import {TranscriptConfig, PluginStates, HighlightedMap, CuePointData, ItemTypes, CuePoint} from './types';
10
11
 
11
12
  const {SidePanelModes, SidePanelPositions, ReservedPresetNames, ReservedPresetAreas} = ui;
12
- const {get} = ObjectUtils;
13
- const {Tooltip} = KalturaPlayer.ui.components;
14
13
  const {withText, Text} = KalturaPlayer.ui.preacti18n;
15
-
16
- const translates = () => ({
17
- printDownloadAreaLabel: <Text id="transcript.print_download_area_label">Download or print current transcript</Text>,
18
- printTranscript: <Text id="transcript.print_transcript">Print current transcript</Text>,
19
- downloadTranscript: <Text id="transcript.download_transcript">Download current transcript</Text>
20
- });
14
+ const {get} = ObjectUtils;
21
15
 
22
16
  interface TimedMetadataEvent {
23
17
  payload: {
@@ -44,9 +38,10 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
44
38
  private _hasError = false;
45
39
  private _triggeredByKeyboard = false;
46
40
 
47
- private _removePopoverIcon: null | Function = null;
48
-
49
- private _transcriptPanel = null;
41
+ private _transcriptPanel = -1;
42
+ private _transcriptIcon = -1;
43
+ private _printIcon = -1;
44
+ private _downloadIcon = -1;
50
45
  private _pluginState: PluginStates | null = null;
51
46
 
52
47
  constructor(name: string, player: KalturaPlayerTypes.Player, config: TranscriptConfig) {
@@ -54,7 +49,11 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
54
49
  }
55
50
 
56
51
  get sidePanelsManager() {
57
- return this.player.getService('sidePanelsManager') as any;
52
+ return this.player.getService('sidePanelsManager') as SidePanelsManager | undefined;
53
+ }
54
+
55
+ get upperBarManager() {
56
+ return this.player.getService('upperBarManager') as UpperBarManager | undefined;
58
57
  }
59
58
 
60
59
  get cuePointManager() {
@@ -66,8 +65,8 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
66
65
  }
67
66
 
68
67
  loadMedia(): void {
69
- if (!this.cuePointManager || !this.sidePanelsManager) {
70
- this.logger.warn("kalturaCuepoints or sidePanelsManager haven't registered");
68
+ if (!this.cuePointManager || !this.sidePanelsManager || !this.upperBarManager) {
69
+ this.logger.warn("kalturaCuepoints, sidePanelsManager or upperBarManager haven't registered");
71
70
  return;
72
71
  }
73
72
  if (this.player.isLive()) {
@@ -86,7 +85,8 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
86
85
  // turn on loading animation till captions added to TextTrack
87
86
  this._isLoading = true;
88
87
  }
89
- this._addPopoverIcon();
88
+ this._addDownloadIcon();
89
+ this._addPrintIcon();
90
90
  this._addTranscriptItem();
91
91
  }
92
92
  });
@@ -103,7 +103,7 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
103
103
 
104
104
  private _updateTranscriptPanel() {
105
105
  if (this._transcriptPanel) {
106
- this.sidePanelsManager.update(this._transcriptPanel);
106
+ this.sidePanelsManager?.update(this._transcriptPanel);
107
107
  }
108
108
  }
109
109
 
@@ -120,14 +120,15 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
120
120
  };
121
121
 
122
122
  private _onTimedMetadataChange = ({payload}: TimedMetadataEvent) => {
123
- const transcriptCuePoints: Array<CuePoint> = payload.cues.filter((cue: CuePoint) => {
124
- return cue.metadata.cuePointType === ItemTypes.Caption;
123
+ const transcriptCuePoints: Array<CuePoint> = payload.cues
124
+ .filter((cue: CuePoint) => {
125
+ return cue.metadata.cuePointType === ItemTypes.Caption;
125
126
  })
126
127
  .filter((cue, index, array) => {
127
128
  // filter out captions that has endTime eq to next caption startTime
128
129
  const nextCue = array[index + 1];
129
130
  return !nextCue || cue.endTime !== nextCue.startTime;
130
- });
131
+ });
131
132
  this._activeCuePointsMap = {};
132
133
  transcriptCuePoints.forEach(cue => {
133
134
  this._activeCuePointsMap[cue.id] = true;
@@ -152,42 +153,76 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
152
153
  return `${activeTextTrack?.language}-${activeTextTrack?.label}`;
153
154
  };
154
155
 
155
- private _handleCloseClick = () => {
156
- this.sidePanelsManager.deactivateItem(this._transcriptPanel);
157
- this._pluginState = PluginStates.CLOSED;
156
+ private _activatePlugin = () => {
157
+ this.ready.then(() => {
158
+ this.sidePanelsManager?.activateItem(this._transcriptPanel);
159
+ this._pluginState === PluginStates.OPENED;
160
+ this.upperBarManager?.update(this._transcriptIcon);
161
+ });
162
+ };
163
+
164
+ private _deactivatePlugin = () => {
165
+ this.ready.then(() => {
166
+ this.sidePanelsManager?.deactivateItem(this._transcriptPanel);
167
+ this._pluginState = PluginStates.CLOSED;
168
+ this.upperBarManager?.update(this._transcriptIcon);
169
+ });
170
+ };
171
+
172
+ private _isPluginActive = () => {
173
+ return this.sidePanelsManager!.isItemActive(this._transcriptPanel);
158
174
  };
159
175
 
160
- private _addPopoverIcon(): void {
161
- const {downloadDisabled, printDisabled} = this.config;
162
- if (this._removePopoverIcon) {
176
+ private _handleClickOnPluginIcon = (e: OnClickEvent, byKeyboard?: boolean) => {
177
+ if (this._isPluginActive()) {
178
+ this._triggeredByKeyboard = false;
179
+ this._deactivatePlugin();
180
+ } else {
181
+ this._triggeredByKeyboard = Boolean(byKeyboard);
182
+ this._activatePlugin();
183
+ }
184
+ };
185
+
186
+ private _addDownloadIcon(): void {
187
+ const {downloadDisabled} = this.config;
188
+ if (this._downloadIcon > 0 || downloadDisabled) {
163
189
  return;
164
190
  }
165
- this._removePopoverIcon = this.player.ui.addComponent({
166
- label: 'Download or print transcript',
167
- area: ReservedPresetAreas.TopBarRightControls,
168
- presets: [ReservedPresetNames.Playback, ReservedPresetNames.Live],
169
- get: withText(translates)(({printDownloadAreaLabel, printTranscript, downloadTranscript}: Record<string, string>) => (
170
- <DownloadPrintMenu
171
- onDownload={this._handleDownload}
172
- onPrint={this._handlePrint}
173
- downloadDisabled={getConfigValue(downloadDisabled, isBoolean, false)}
174
- printDisabled={getConfigValue(printDisabled, isBoolean, false)}
175
- dropdownAriaLabel={printDownloadAreaLabel}
176
- printButtonAriaLabel={printTranscript}
177
- downloadButtonAriaLabel={downloadTranscript}
178
- />
191
+ const translate = {
192
+ label: <Text id="transcript.download_transcript">Download current transcript</Text>
193
+ };
194
+ this._downloadIcon = this.upperBarManager!.add({
195
+ label: translate.label as any,
196
+ svgIcon: {path: icons.DOWNLOAD_ICON, viewBox: `0 0 ${icons.BigSize} ${icons.BigSize}`},
197
+ onClick: this._handleDownload,
198
+ component: withText(translate)((props: {label: string}) => (
199
+ <PluginButton isActive={false} onClick={this._handleDownload} id={'download-transcript'} icon={icons.DOWNLOAD_ICON} label={props.label} />
179
200
  ))
180
- });
201
+ }) as number;
202
+ }
203
+ private _addPrintIcon(): void {
204
+ const {printDisabled} = this.config;
205
+ if (this._printIcon > 0 || printDisabled) {
206
+ return;
207
+ }
208
+ const translate = {
209
+ label: <Text id="transcript.print_transcript">Print current transcript</Text>
210
+ };
211
+ this._printIcon = this.upperBarManager!.add({
212
+ label: translate.label as any,
213
+ svgIcon: {path: icons.PRINT_ICON, viewBox: `0 0 ${icons.BigSize} ${icons.BigSize}`},
214
+ onClick: this._handlePrint,
215
+ component: withText(translate)((props: {label: string}) => (
216
+ <PluginButton isActive={false} onClick={this._handlePrint} id={'print-transcript'} icon={icons.PRINT_ICON} label={props.label} />
217
+ ))
218
+ }) as number;
181
219
  }
182
220
 
183
221
  private _addTranscriptItem(): void {
184
- const buttonLabel = 'Transcript';
185
222
  const {expandMode, position, expandOnFirstPlay} = this.config;
186
- const pluginMode: PluginPositions = [SidePanelPositions.RIGHT, SidePanelPositions.LEFT].includes(position)
187
- ? PluginPositions.VERTICAL
188
- : PluginPositions.HORIZONTAL;
189
223
  const {showTime, scrollOffset, searchDebounceTimeout, searchNextPrevDebounceTimeout} = this.config;
190
- this._transcriptPanel = this.sidePanelsManager.addItem({
224
+
225
+ this._transcriptPanel = this.sidePanelsManager!.add({
191
226
  label: 'Transcript',
192
227
  panelComponent: () => {
193
228
  return (
@@ -198,7 +233,6 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
198
233
  searchNextPrevDebounceTimeout={getConfigValue(searchNextPrevDebounceTimeout, Number.isInteger, 100)}
199
234
  highlightedMap={this._activeCuePointsMap}
200
235
  onSeek={this._seekTo}
201
- pluginMode={pluginMode}
202
236
  onItemClicked={this._seekTo}
203
237
  captions={this._data}
204
238
  isLoading={this._isLoading}
@@ -206,43 +240,36 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
206
240
  onRetryLoad={this._updateTranscriptPanel}
207
241
  currentTime={this.player.currentTime}
208
242
  videoDuration={this.player.duration}
209
- kitchenSinkActive={!!this.sidePanelsManager.isItemActive(this._transcriptPanel)}
243
+ kitchenSinkActive={this._isPluginActive()}
210
244
  toggledWithEnter={this._triggeredByKeyboard}
211
- onClose={this._handleCloseClick}
245
+ onClose={this._deactivatePlugin}
212
246
  />
213
247
  );
214
248
  },
215
- iconComponent: ({isActive}: {isActive: boolean}) => {
216
- return (
217
- <Tooltip label={buttonLabel} type="bottom">
218
- <PluginButton
219
- isActive={isActive}
220
- label={buttonLabel}
221
- onClick={(e: OnClickEvent, byKeyboard?: boolean) => {
222
- if (this.sidePanelsManager.isItemActive(this._transcriptPanel)) {
223
- this._triggeredByKeyboard = false;
224
- this._handleCloseClick();
225
- } else {
226
- this._triggeredByKeyboard = Boolean(byKeyboard);
227
- this.sidePanelsManager.activateItem(this._transcriptPanel);
228
- }
229
- }}
230
- />
231
- </Tooltip>
232
- );
233
- },
234
249
  presets: [ReservedPresetNames.Playback, ReservedPresetNames.Live, ReservedPresetNames.Ads],
235
250
  position: position,
236
251
  expandMode: expandMode === SidePanelModes.ALONGSIDE ? SidePanelModes.ALONGSIDE : SidePanelModes.OVER,
237
- onActivate: () => {
238
- this._pluginState = PluginStates.OPENED;
239
- }
240
- });
252
+ onDeactivate: this._deactivatePlugin
253
+ }) as number;
254
+ const translates = {
255
+ showTranscript: <Text id="transcript.show_plugin">Show Transcript</Text>,
256
+ hideTranscript: <Text id="transcript.hide_plugin">Hide Transcript</Text>
257
+ };
258
+ this._transcriptIcon = this.upperBarManager!.add({
259
+ label: 'Transcript',
260
+ svgIcon: {path: icons.PLUGIN_ICON, viewBox: `0 0 ${icons.BigSize} ${icons.BigSize}`},
261
+ onClick: this._handleClickOnPluginIcon as () => void,
262
+ component: withText(translates)((props: {showTranscript: string; hideTranscript: string}) => {
263
+ const isActive = this._isPluginActive();
264
+ const label = isActive ? props.hideTranscript : props.showTranscript;
265
+ return (
266
+ <PluginButton isActive={isActive} onClick={this._handleClickOnPluginIcon} id="transcript-icon" label={label} icon={icons.PLUGIN_ICON} />
267
+ );
268
+ })
269
+ }) as number;
241
270
 
242
271
  if ((expandOnFirstPlay && !this._pluginState) || this._pluginState === PluginStates.OPENED) {
243
- this.player.ready().then(() => {
244
- this.sidePanelsManager.activateItem(this._transcriptPanel);
245
- });
272
+ this._activatePlugin();
246
273
  }
247
274
  }
248
275
 
@@ -276,13 +303,19 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
276
303
 
277
304
  reset(): void {
278
305
  this.eventManager.removeAll();
279
- if (this._removePopoverIcon) {
280
- this._removePopoverIcon();
281
- this._removePopoverIcon = null;
306
+ if (Math.max(this._transcriptPanel, this._transcriptIcon) > 0) {
307
+ this.sidePanelsManager?.remove(this._transcriptPanel);
308
+ this.upperBarManager!.remove(this._transcriptIcon);
309
+ this._transcriptPanel = -1;
310
+ this._transcriptIcon = -1;
282
311
  }
283
- if (this._transcriptPanel) {
284
- this.sidePanelsManager.removeItem(this._transcriptPanel);
285
- this._transcriptPanel = null;
312
+ if (this._printIcon > 0) {
313
+ this.upperBarManager!.remove(this._printIcon);
314
+ this._printIcon = -1;
315
+ }
316
+ if (this._downloadIcon > 0) {
317
+ this.upperBarManager!.remove(this._downloadIcon);
318
+ this._downloadIcon = -1;
286
319
  }
287
320
  this._captionMap = new Map();
288
321
  this._activeCaptionMapId = '';
@@ -1,10 +1,3 @@
1
- export type OnClick = (e: KeyboardEvent | MouseEvent, byKeyboard?: boolean) => void;
2
-
3
- export enum PluginPositions {
4
- HORIZONTAL = 'horizontal',
5
- VERTICAL = 'vertical'
6
- }
7
-
8
1
  export enum PluginStates {
9
2
  OPENED = 'opened',
10
3
  CLOSED = 'closed'
@@ -1,4 +1,3 @@
1
1
  export * from './utils';
2
2
  export * from './object-utils';
3
3
  export * from './debounce';
4
- export * from './popover/popover';
@@ -84,3 +84,37 @@ export const prepareCuePoint = (cuePoint: CuePoint): CuePointData => {
84
84
 
85
85
  return itemData;
86
86
  };
87
+
88
+ export function downloadContent(content: string, name: string): void {
89
+ const blob = new Blob([content], {type: 'text/plain;charset=utf-8;'});
90
+ const anchor = document.createElement('a');
91
+ const {navigator} = window as any;
92
+
93
+ if (navigator.msSaveBlob) {
94
+ // IE
95
+ navigator.msSaveOrOpenBlob(blob, name);
96
+ return;
97
+ }
98
+ if (navigator.userAgent.search('Firefox') !== -1) {
99
+ // Firefox
100
+ anchor.style.display = 'none';
101
+ anchor.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(content));
102
+ } else {
103
+ // Chrome
104
+ anchor.setAttribute('href', URL.createObjectURL(blob));
105
+ }
106
+ anchor.setAttribute('target', '_blank');
107
+ anchor.setAttribute('download', name);
108
+ anchor.click();
109
+ anchor.remove();
110
+ }
111
+ export function printContent(content: string): void {
112
+ const printWindow = window.open('', '', 'width=400,height=600');
113
+ if (printWindow) {
114
+ printWindow.document.write(content);
115
+ printWindow.document.close();
116
+ printWindow.focus();
117
+ printWindow.print();
118
+ printWindow.close();
119
+ }
120
+ }
@@ -1,23 +0,0 @@
1
- import {h} from 'preact';
2
-
3
- export const PrintIcon = () => (
4
- <svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
5
- <g id="Icons/32/print" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
6
- <path
7
- d="M21,3 C22.0543618,3 22.9181651,3.81587779 22.9945143,4.85073766 L23,5 L23,9 L26,9 C27.1045695,9 28,9.8954305 28,11 L28,21 C28,22.1045695 27.1045695,23 26,23 L23,23 L23,28 C23,29.1045695 22.1045695,30 21,30 L11,30 C9.8954305,30 9,29.1045695 9,28 L9,23 L6,23 C4.8954305,23 4,22.1045695 4,21 L4,11 C4,9.8954305 4.8954305,9 6,9 L9,9 L9,5 C9,3.9456382 9.81587779,3.08183488 10.8507377,3.00548574 L11,3 L21,3 Z M21,19 L11,19 L11,28 L21,28 L21,19 Z M26,11 L6,11 L6,21 L9,21 L9,19 C8.44771525,19 8,18.5522847 8,18 C8,17.4477153 8.44771525,17 9,17 L23,17 C23.5522847,17 24,17.4477153 24,18 C24,18.5522847 23.5522847,19 23,19 L23,21 L26,21 L26,11 Z M21,5 L11,5 L11,9 L21,9 L21,5 Z"
8
- id="Combined-Shape"
9
- fill="#fff"></path>
10
- </g>
11
- </svg>
12
- );
13
-
14
- export const DownloadIcon = () => (
15
- <svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
16
- <g id="Icons/32/Download" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
17
- <path
18
- d="M26,25 C26.5522847,25 27,25.4477153 27,26 C27,26.5522847 26.5522847,27 26,27 L26,27 L7,27 C6.44771525,27 6,26.5522847 6,26 C6,25.4477153 6.44771525,25 7,25 L7,25 Z M15.897,20.797 L15.817,20.73 L15.8163834,20.7298413 L8.34305882,13.7298413 C7.93997861,13.3522902 7.91928313,12.7194636 8.29683417,12.3163834 C8.67438521,11.9133032 9.30721188,11.8926077 9.71029209,12.2701587 L15.4996721,17.693 L15.5,6 C15.5,5.48716416 15.8860402,5.06449284 16.3833789,5.00672773 L16.5,5 C17.0522847,5 17.5,5.44771525 17.5,6 L17.4996721,17.694 L23.2951711,12.2699211 C23.6673663,11.9215418 24.2352038,11.9125649 24.6172049,12.230382 L24.7086128,12.3166371 C25.0860237,12.7198486 25.0651082,13.352668 24.6618968,13.7300789 L17.1833629,20.7300789 L17.1610165,20.7503813 L17.1610165,20.7503813 C17.1421868,20.7669999 17.1224361,20.7831339 17.102079,20.7985075 C17.0891381,20.8082894 17.0764369,20.8174134 17.0635772,20.826204 C17.0434306,20.8399634 17.0223437,20.8532674 17.0007451,20.8657864 C16.9872099,20.8736423 16.9734873,20.8811624 16.959633,20.8883367 L16.8877511,20.9220455 L16.8877511,20.9220455 C16.8756318,20.927087 16.8632234,20.9320132 16.8507409,20.9366814 C16.83028,20.9444208 16.8097352,20.9513578 16.7889039,20.9576336 C16.7705976,20.9630349 16.752126,20.968019 16.7335525,20.9724647 C16.6585039,20.9905214 16.5803589,21 16.5,21 C16.4170842,21 16.3365254,20.9899086 16.2594848,20.9708871 C16.2500284,20.9684434 16.2399293,20.9657886 16.2298654,20.9629733 C16.2028024,20.9554899 16.1769173,20.947049 16.1515197,20.9376057 C16.1370523,20.9321598 16.1223107,20.9262914 16.1076867,20.9200585 C16.0832011,20.9096448 16.0596143,20.8984375 16.036557,20.886357 C16.025923,20.8807972 16.0148138,20.8747205 16.0037984,20.8684173 C15.9792921,20.8543502 15.955966,20.8396537 15.9333153,20.8240474 L15.898,20.798 L15.897,20.797 Z M15.867,20.774 L15.888,20.79 L15.8735171,20.7794831 L15.8735171,20.7794831 L15.867,20.774 Z M15.817,20.73 L15.9035191,20.8027045 C15.8784859,20.7840722 15.8543541,20.7642966 15.831201,20.7434548 L15.817,20.73 Z"
19
- id="Combined-Shape"
20
- fill="#ffffff"></path>
21
- </g>
22
- </svg>
23
- );
@@ -1,44 +0,0 @@
1
- @import '../../variables.scss';
2
-
3
- .download-print-button {
4
- display: inline-block;
5
- width: 36px;
6
- height: 36px;
7
- color: $white-color;
8
- border: none;
9
- cursor: pointer;
10
- padding: 0;
11
- background: none;
12
- border-radius: 4px;
13
- outline-offset: 0 -1px;
14
- &:hover,
15
- &:active {
16
- border-radius: 4px;
17
- background-color: rgba(0, 0, 0, 0.8);
18
- }
19
- &:focus {
20
- outline: 1px solid $focus-color;
21
- }
22
- .icon {
23
- width: 100%;
24
- height: 100%;
25
- background-position: center;
26
- background-size: cover;
27
- }
28
- }
29
- .popover-menu-item {
30
- display: flex;
31
- align-items: center;
32
- padding: 9px 24px 9px 16px;
33
- white-space: nowrap;
34
- min-height: 30px;
35
- line-height: 18px;
36
- font-size: 15px;
37
- &:hover {
38
- cursor: pointer;
39
- background-color: $semigray-color;
40
- }
41
- &:focus {
42
- outline: 1px solid $focus-color;
43
- }
44
- }
@@ -1,164 +0,0 @@
1
- import {h, Component, ComponentChild, VNode} from 'preact';
2
- import {Popover, PopoverHorizontalPositions, PopoverVerticalPositions} from '../../utils';
3
- import {PopoverMenu, PopoverMenuItem} from '../popover-menu';
4
- import * as styles from './download-print-menu.scss';
5
- import {DownloadIcon, PrintIcon} from './download-print-icons';
6
-
7
- const {ENTER, Esc} = KalturaPlayer.ui.utils.KeyMap;
8
-
9
- export function downloadContent(content: string, name: string): void {
10
- const blob = new Blob([content], {type: 'text/plain;charset=utf-8;'});
11
- const anchor = document.createElement('a');
12
- const {navigator} = window as any;
13
-
14
- if (navigator.msSaveBlob) {
15
- // IE
16
- navigator.msSaveOrOpenBlob(blob, name);
17
- return;
18
- }
19
- if (navigator.userAgent.search('Firefox') !== -1) {
20
- // Firefox
21
- anchor.style.display = 'none';
22
- anchor.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(content));
23
- } else {
24
- // Chrome
25
- anchor.setAttribute('href', URL.createObjectURL(blob));
26
- }
27
- anchor.setAttribute('target', '_blank');
28
- anchor.setAttribute('download', name);
29
- anchor.click();
30
- anchor.remove();
31
- }
32
-
33
- export function printContent(content: string): void {
34
- const printWindow = window.open('', '', 'width=400,height=600');
35
- if (printWindow) {
36
- printWindow.document.write(content);
37
- printWindow.document.close();
38
- printWindow.focus();
39
- printWindow.print();
40
- printWindow.close();
41
- }
42
- }
43
-
44
- interface DownloadPrintMenuProps {
45
- dropdownAriaLabel: string;
46
- printButtonAriaLabel: string;
47
- downloadButtonAriaLabel: string;
48
- onDownload: () => void;
49
- onPrint: () => void;
50
- downloadDisabled: boolean;
51
- printDisabled: boolean;
52
- }
53
-
54
- interface ButtonProperties {
55
- ['aria-label']: string;
56
- buttonStyles: string;
57
- onClick?: () => void;
58
- tabIndex?: number;
59
- iconStyles: string;
60
- icon: VNode;
61
- }
62
-
63
- interface DownloadPrintMenuState {
64
- popoverOpen: boolean;
65
- }
66
-
67
- export class DownloadPrintMenu extends Component<DownloadPrintMenuProps, DownloadPrintMenuState> {
68
- state: DownloadPrintMenuState = {
69
- popoverOpen: false
70
- };
71
-
72
- private _onDownloadClicked = () => {
73
- this.props.onDownload();
74
- };
75
-
76
- private _onPrintClicked = () => {
77
- this.props.onPrint();
78
- };
79
- private _onKeyDown = (e: KeyboardEvent, callBack: Function) => {
80
- if (e.keyCode !== ENTER && e.keyCode !== Esc) {
81
- // don't stopPropagation on ESC and Enter pressed as it prevent the popup closing
82
- e.stopPropagation();
83
- }
84
- switch (e.keyCode) {
85
- case 13: // Enter pressed
86
- callBack();
87
- break;
88
- }
89
- };
90
- private _popoverMenuItemRenderer = (el: PopoverMenuItem) => (
91
- <div
92
- tabIndex={1}
93
- role="button"
94
- onClick={() => el.onMenuChosen()}
95
- onKeyDown={(e: KeyboardEvent) => this._onKeyDown(e, el.onMenuChosen)}
96
- className={styles.popoverMenuItem}>
97
- {el.label}
98
- </div>
99
- );
100
-
101
- private _getPopoverMenuOptions = () => {
102
- return [
103
- {
104
- label: this.props.downloadButtonAriaLabel,
105
- onMenuChosen: this._onDownloadClicked
106
- },
107
- {
108
- label: this.props.printButtonAriaLabel,
109
- onMenuChosen: this._onPrintClicked
110
- }
111
- ];
112
- };
113
-
114
- private _renderIcon = ({buttonStyles, tabIndex = 0, iconStyles, icon, ...props}: ButtonProperties): ComponentChild => {
115
- return (
116
- <button className={buttonStyles} tabIndex={tabIndex} {...props}>
117
- <div className={iconStyles}>{icon}</div>
118
- </button>
119
- );
120
- };
121
-
122
- private _popoverContent = () => {
123
- return <PopoverMenu itemRenderer={this._popoverMenuItemRenderer} options={this._getPopoverMenuOptions()} />;
124
- };
125
-
126
- render(props: DownloadPrintMenuProps) {
127
- const {downloadDisabled, printDisabled} = props;
128
- if (!downloadDisabled && !printDisabled) {
129
- return (
130
- <Popover
131
- className="download-print-popover"
132
- verticalPosition={PopoverVerticalPositions.Bottom}
133
- horizontalPosition={PopoverHorizontalPositions.Left}
134
- content={this._popoverContent()}>
135
- {this._renderIcon({
136
- ['aria-label']: props.dropdownAriaLabel,
137
- buttonStyles: styles.downloadPrintButton,
138
- iconStyles: styles.icon,
139
- icon: <DownloadIcon />
140
- })}
141
- </Popover>
142
- );
143
- }
144
- if (!downloadDisabled && printDisabled) {
145
- return this._renderIcon({
146
- ['aria-label']: props.downloadButtonAriaLabel,
147
- buttonStyles: styles.downloadPrintButton,
148
- iconStyles: styles.icon,
149
- onClick: this._onDownloadClicked,
150
- icon: <DownloadIcon />
151
- });
152
- }
153
- if (downloadDisabled && !printDisabled) {
154
- return this._renderIcon({
155
- ['aria-label']: props.printButtonAriaLabel,
156
- buttonStyles: styles.downloadPrintButton,
157
- iconStyles: styles.icon,
158
- onClick: this._onPrintClicked,
159
- icon: <PrintIcon />
160
- });
161
- }
162
- return null;
163
- }
164
- }
@@ -1 +0,0 @@
1
- export * from './download-print-menu';
@@ -1 +0,0 @@
1
- export * from './popover-menu';
@@ -1,6 +0,0 @@
1
- @import '../../variables.scss';
2
-
3
- .popover-menu {
4
- padding-top: 6px;
5
- padding-bottom: 6px;
6
- }
@@ -1,52 +0,0 @@
1
- import {h, Component, ComponentChild} from 'preact';
2
- import * as styles from './popover-menu.scss';
3
-
4
- export interface PopoverMenuItem {
5
- label: string;
6
- onMenuChosen: Function;
7
- customRenderer?: (el: PopoverMenuItem) => ComponentChild;
8
- }
9
-
10
- interface PopoverMenuProps {
11
- options: Array<PopoverMenuItem>;
12
- itemRenderer?: (el: PopoverMenuItem) => ComponentChild;
13
- }
14
-
15
- /**
16
- * Popover menu renders list of options.
17
- * options example:
18
- * [
19
- * {label: 'option_1', onMenuChosen: () => console.log('selected first')},
20
- * {label: 'option_2', onMenuChosen: () => console.log('selected second')}
21
- * ]
22
- * In case when 'itemRenderer' properdy hasn't provided - PopoverMenu renders
23
- * div with class "popover-menu-item" that contain label for the current option.
24
- * Default render of options can be changed by providing 'itemRenderer' - it should be
25
- * function that takes current option and returns valid 'preact' node.
26
- * If some option need to be rendered with a different method - specific render
27
- * method can be provided with 'customRenderer' property for the current option.
28
- * option example with specific render method:
29
- * { label: 'specific render', onMenuChosen: () => {}, customRenderer: el => (<span>{el.label}</span>)}
30
- */
31
-
32
- export class PopoverMenu extends Component<PopoverMenuProps> {
33
- render(props: any) {
34
- return (
35
- <div className={styles.popoverMenu}>
36
- {props.options.map((el: PopoverMenuItem) => {
37
- if (el.customRenderer) {
38
- return el.customRenderer(el);
39
- }
40
- if (props.itemRenderer) {
41
- return props.itemRenderer(el);
42
- }
43
- return (
44
- <div className="popover-menu-item" onClick={() => el.onMenuChosen(el)}>
45
- {el.label}
46
- </div>
47
- );
48
- })}
49
- </div>
50
- );
51
- }
52
- }