ravnur-player-public 3.4.3 → 3.4.4
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/.eslintignore +7 -0
- package/.eslintrc.js +206 -0
- package/.flowconfig +3 -0
- package/.vscode/extensions.json +7 -0
- package/.vscode/launch.json +37 -0
- package/.vscode/settings.json +4 -0
- package/README-Private.md +54 -0
- package/babel.config.js +28 -0
- package/bitbucket-pipelines.yml +61 -0
- package/cert.pem +23 -0
- package/demo/BaseM.mp4 +0 -0
- package/demo/HD.mp4 +0 -0
- package/demo/annotations.json +50 -0
- package/demo/annotations_ge.json +50 -0
- package/demo/base.mp3 +0 -0
- package/demo/cc_2125en.vtt +4958 -0
- package/demo/cc_en.vtt +171 -0
- package/demo/cc_ge.vtt +178 -0
- package/demo/chapters_en.vtt +38 -0
- package/demo/chapters_ge.vtt +5 -0
- package/demo/chapters_ge1.json +23 -0
- package/demo/hls/audio/stereo/en/128kbit.m3u8 +912 -0
- package/demo/hls/audio/stereo/none/128kbit.m3u8 +912 -0
- package/demo/hls/audio/surround/en/320kbit.m3u8 +912 -0
- package/demo/hls/playlist.m3u8 +31 -0
- package/demo/hls/video/10000kbit.m3u8 +894 -0
- package/demo/hls/video/1100kbit.m3u8 +894 -0
- package/demo/hls/video/1500kbit.m3u8 +894 -0
- package/demo/hls/video/250kbit.m3u8 +894 -0
- package/demo/hls/video/4000kbit.m3u8 +894 -0
- package/demo/hls/video/500kbit.m3u8 +894 -0
- package/demo/hls/video/6000kbit.m3u8 +894 -0
- package/demo/hls/video/800kbit.m3u8 +894 -0
- package/demo/hls.js +5 -0
- package/demo/hls.js.map +1 -0
- package/demo/hls.min.js +2 -0
- package/demo/hls.min.js.map +1 -0
- package/demo/playlist.m3u8 +31 -0
- package/demo/ravnur-flash-audio.swf +0 -0
- package/demo/ravnur-flash-video-hls.swf +0 -0
- package/demo/ravnur-flash-video.swf +0 -0
- package/demo/shaka/shaka-player.foo.debug.d.ts +4532 -0
- package/demo/shaka/shaka-player.foo.debug.externs.js +3886 -0
- package/demo/shaka/shaka-player.foo.debug.js +1746 -0
- package/demo/shaka/shaka-player.foo.debug.map +8 -0
- package/demo/shaka/wrapper.js +7 -0
- package/demo/test.html +458 -0
- package/dist/RavnurMediaPlayer.min.js +1 -1
- package/dist/cdn/RavnurMediaPlayer.min.js +1 -1
- package/jest.config.js +4 -0
- package/key.pem +27 -0
- package/lib/es5.js +344 -0
- package/lib/images/Spinner-small.gif +0 -0
- package/lib/images/close.png +0 -0
- package/lib/images/ic_check_box_black_24dp_1x.png +0 -0
- package/lib/images/ic_check_box_outline_blank_black_24dp_1x.png +0 -0
- package/lib/images/ic_chevron_left_white_24dp_1x.png +0 -0
- package/lib/images/ic_chevron_right_white_24dp_1x.png +0 -0
- package/lib/images/ic_closed_caption_white_24dp_1x.png +0 -0
- package/lib/images/ic_fast_forward_white_24dp_1x.png +0 -0
- package/lib/images/ic_fast_rewind_white_24dp_1x.png +0 -0
- package/lib/images/ic_fullscreen_exit_white_24dp_1x.png +0 -0
- package/lib/images/ic_fullscreen_white_24dp_1x.png +0 -0
- package/lib/images/ic_hd_white_24dp_1x.png +0 -0
- package/lib/images/ic_keyboard_arrow_left_black_24dp_1x.png +0 -0
- package/lib/images/ic_keyboard_arrow_right_black_24dp_1x.png +0 -0
- package/lib/images/ic_pause_white_24dp_1x.png +0 -0
- package/lib/images/ic_photo_white_24dp_1x.png +0 -0
- package/lib/images/ic_play_arrow_white_24dp_1x.png +0 -0
- package/lib/images/ic_refresh_white_24dp_1x.png +0 -0
- package/lib/images/ic_settings_white_24dp_1x.png +0 -0
- package/lib/images/ic_skip_next_white_24dp_1x.png +0 -0
- package/lib/images/ic_skip_previous_white_24dp_1x.png +0 -0
- package/lib/images/ic_toc_white_24dp_1x.png +0 -0
- package/lib/images/ic_volume_off_white_24dp_1x.png +0 -0
- package/lib/images/ic_volume_up_white_24dp_1x.png +0 -0
- package/lib/player4ie8.css +225 -0
- package/package.json +3 -7
- package/server.js +29 -0
- package/src/config/cc.js +56 -0
- package/src/config/i18n.js +101 -0
- package/src/config/options.js +123 -0
- package/src/config/playlist.js +9 -0
- package/src/config/source.js +23 -0
- package/src/config/statuses.js +8 -0
- package/src/config/styles.js +16 -0
- package/src/entity.js +27 -0
- package/src/events.js +5 -0
- package/src/extensions/annotations.js +142 -0
- package/src/extensions/audio-tarcks.js +115 -0
- package/src/extensions/backward.js +45 -0
- package/src/extensions/base.js +73 -0
- package/src/extensions/bottom-next.js +50 -0
- package/src/extensions/bottom-prev.js +50 -0
- package/src/extensions/buffering.js +78 -0
- package/src/extensions/c2pa.js +350 -0
- package/src/extensions/caption-search.js +230 -0
- package/src/extensions/cc.js +874 -0
- package/src/extensions/crawl.js +118 -0
- package/src/extensions/download.js +411 -0
- package/src/extensions/error.js +47 -0
- package/src/extensions/forward.js +44 -0
- package/src/extensions/fullscreen.js +84 -0
- package/src/extensions/help.js +201 -0
- package/src/extensions/helpers/FileSaver.js +157 -0
- package/src/extensions/helpers/clickOpener.js +180 -0
- package/src/extensions/helpers/opener.js +30 -0
- package/src/extensions/helpers/openerHeightChecker.js +13 -0
- package/src/extensions/helpers/popover.js +33 -0
- package/src/extensions/helpers/popoverPosition.js +30 -0
- package/src/extensions/helpers/scrollIntoView.js +9 -0
- package/src/extensions/helpers/storage.js +20 -0
- package/src/extensions/helpers/textContent.js +6 -0
- package/src/extensions/helpers/timeCodeToSeconds.js +44 -0
- package/src/extensions/helpers/transport.js +43 -0
- package/src/extensions/helpers/vtt-loader.js +42 -0
- package/src/extensions/index.js +87 -0
- package/src/extensions/live.js +76 -0
- package/src/extensions/mux.js +57 -0
- package/src/extensions/next-frame.js +44 -0
- package/src/extensions/next.js +48 -0
- package/src/extensions/placeholder.js +241 -0
- package/src/extensions/play.js +102 -0
- package/src/extensions/poster.js +47 -0
- package/src/extensions/prev-frame.js +44 -0
- package/src/extensions/prev.js +48 -0
- package/src/extensions/progress.js +465 -0
- package/src/extensions/resizer.js +37 -0
- package/src/extensions/settings.js +367 -0
- package/src/extensions/theater.js +56 -0
- package/src/extensions/title.js +38 -0
- package/src/extensions/toc.js +334 -0
- package/src/extensions/volume.js +196 -0
- package/src/flash/FlashPlugin.js +301 -0
- package/src/flash/MediaElement.js +361 -0
- package/src/flash/plugins.js +32 -0
- package/src/flash-detector.js +66 -0
- package/src/helpers/$t.js +10 -0
- package/src/helpers/binder.js +11 -0
- package/src/helpers/isAndroid.js +5 -0
- package/src/helpers/isBlackBerry.js +5 -0
- package/src/helpers/isCanvasSupported.js +6 -0
- package/src/helpers/isIE.js +21 -0
- package/src/helpers/isMobile.js +10 -0
- package/src/helpers/isWindows.js +5 -0
- package/src/helpers/isWindowsPhone.js +5 -0
- package/src/helpers/isiOS.js +5 -0
- package/src/html5media.js +19 -0
- package/src/index.js +2 -0
- package/src/logger.js +31 -0
- package/src/microevent.js +65 -0
- package/src/normalize-options.js +139 -0
- package/src/player.js +864 -0
- package/src/players/base.js +209 -0
- package/src/players/flash.js +172 -0
- package/src/players/hls.js +278 -0
- package/src/players/html.js +205 -0
- package/src/players/index.js +59 -0
- package/src/players/shaka.js +219 -0
- package/src/playlist.js +362 -0
- package/src/screenfull.js +121 -0
- package/src/state.js +474 -0
- package/src/static/es5.js +344 -0
- package/src/static/images/Spinner-small.gif +0 -0
- package/src/static/images/close.png +0 -0
- package/src/static/images/ic_check_box_black_24dp_1x.png +0 -0
- package/src/static/images/ic_check_box_outline_blank_black_24dp_1x.png +0 -0
- package/src/static/images/ic_chevron_left_white_24dp_1x.png +0 -0
- package/src/static/images/ic_chevron_right_white_24dp_1x.png +0 -0
- package/src/static/images/ic_closed_caption_white_24dp_1x.png +0 -0
- package/src/static/images/ic_fast_forward_white_24dp_1x.png +0 -0
- package/src/static/images/ic_fast_rewind_white_24dp_1x.png +0 -0
- package/src/static/images/ic_fullscreen_exit_white_24dp_1x.png +0 -0
- package/src/static/images/ic_fullscreen_white_24dp_1x.png +0 -0
- package/src/static/images/ic_hd_white_24dp_1x.png +0 -0
- package/src/static/images/ic_keyboard_arrow_left_black_24dp_1x.png +0 -0
- package/src/static/images/ic_keyboard_arrow_right_black_24dp_1x.png +0 -0
- package/src/static/images/ic_pause_white_24dp_1x.png +0 -0
- package/src/static/images/ic_play_arrow_white_24dp_1x.png +0 -0
- package/src/static/images/ic_refresh_white_24dp_1x.png +0 -0
- package/src/static/images/ic_settings_white_24dp_1x.png +0 -0
- package/src/static/images/ic_skip_next_white_24dp_1x.png +0 -0
- package/src/static/images/ic_skip_previous_white_24dp_1x.png +0 -0
- package/src/static/images/ic_toc_white_24dp_1x.png +0 -0
- package/src/static/images/ic_volume_off_white_24dp_1x.png +0 -0
- package/src/static/images/ic_volume_up_white_24dp_1x.png +0 -0
- package/src/static/player4ie8.css +225 -0
- package/src/styles/bplaylist.css.js +124 -0
- package/src/styles/index.js +1966 -0
- package/src/styles/playlist.css.js +84 -0
- package/src/styles/rplaylist.css.js +98 -0
- package/src/svgs.js +111 -0
- package/src/types/Logger.js +10 -0
- package/src/types/Options.js +179 -0
- package/src/types/Playlist.js +3 -0
- package/src/types/Source.js +28 -0
- package/src/types/State.js +46 -0
- package/src/types/Styles.js +11 -0
- package/src/types/TimeData.js +8 -0
- package/src/types/Translation.js +69 -0
- package/src/utils/absolutizeUrl.js +9 -0
- package/src/utils/addClass.js +9 -0
- package/src/utils/addEvent.js +31 -0
- package/src/utils/addProperty.js +65 -0
- package/src/utils/appendChild.js +14 -0
- package/src/utils/buff2hex.js +5 -0
- package/src/utils/contains.js +33 -0
- package/src/utils/createElement.js +24 -0
- package/src/utils/each.js +34 -0
- package/src/utils/escapeHTML.js +8 -0
- package/src/utils/existy.js +4 -0
- package/src/utils/extend.js +17 -0
- package/src/utils/filter.js +16 -0
- package/src/utils/find.js +11 -0
- package/src/utils/findIndex.js +20 -0
- package/src/utils/first.js +5 -0
- package/src/utils/get.js +19 -0
- package/src/utils/has.js +5 -0
- package/src/utils/hasClass.js +6 -0
- package/src/utils/head.js +11 -0
- package/src/utils/inRange.js +16 -0
- package/src/utils/index.js +73 -0
- package/src/utils/isArray.js +4 -0
- package/src/utils/isBoolean.js +3 -0
- package/src/utils/isElement.js +7 -0
- package/src/utils/isEmpty.js +6 -0
- package/src/utils/isEqual.js +33 -0
- package/src/utils/isEqualBuffer.js +13 -0
- package/src/utils/isFunction.js +3 -0
- package/src/utils/isNotEmpty.js +5 -0
- package/src/utils/isObject.js +5 -0
- package/src/utils/isString.js +9 -0
- package/src/utils/last.js +4 -0
- package/src/utils/map.js +11 -0
- package/src/utils/negate.js +8 -0
- package/src/utils/noop.js +1 -0
- package/src/utils/notExisty.js +5 -0
- package/src/utils/reduce.js +8 -0
- package/src/utils/remove.js +7 -0
- package/src/utils/removeClass.js +8 -0
- package/src/utils/removeEvent.js +7 -0
- package/src/utils/toArray.js +7 -0
- package/src/utils/toggleClass.js +16 -0
- package/src/utils/uidGenerator.js +8 -0
- package/src/utils/upperFirst.js +4 -0
- package/tests/extensions/__snapshots__/download.spec.js.snap +226 -0
- package/tests/extensions/__snapshots__/fullscreen.spec.js.snap +30 -0
- package/tests/extensions/__snapshots__/title.spec.js.snap +16 -0
- package/tests/extensions/download.spec.js +111 -0
- package/tests/extensions/fullscreen.spec.js +56 -0
- package/tests/extensions/title.spec.js +35 -0
- package/tests/mocks/assets/BaseM.mp4 +0 -0
- package/tests/mocks/assets/hls.min.js +5 -0
- package/tests/mocks/assets/styleMock.js +1 -0
- package/tests/mocks/base-player-options.js +47 -0
- package/tests/mocks/sources.js +58 -0
- package/tests/mocks/timedata/cc_en.vtt +171 -0
- package/tests/mocks/timedata/cc_ge.vtt +178 -0
- package/tests/utils/wait.js +1 -0
- package/webpack.config.js +78 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import BaseExtension from './base';
|
|
2
|
+
|
|
3
|
+
import { createElement, addEvent, addClass, removeClass, each } from '../utils';
|
|
4
|
+
|
|
5
|
+
// import popover from './helpers/popover';
|
|
6
|
+
import createSvg, { HELP } from '../svgs';
|
|
7
|
+
|
|
8
|
+
const CN = 'rmp-ext-help';
|
|
9
|
+
|
|
10
|
+
const BUTTON_CN = `${CN}__button`;
|
|
11
|
+
const CANVAS_CN = `${CN}__canvas`;
|
|
12
|
+
const CANVAS_VISIBLE_CN = `${CANVAS_CN}--visible`;
|
|
13
|
+
|
|
14
|
+
const START_POSITION = 11;
|
|
15
|
+
const STEP = 36;
|
|
16
|
+
|
|
17
|
+
const RECT_WIDTH = 32;
|
|
18
|
+
const BUTTON_WIDTH = 26;
|
|
19
|
+
const BUTTON_MIDDLE = BUTTON_WIDTH / 2;
|
|
20
|
+
const THINKNESS = 2;
|
|
21
|
+
const TEXT_HEIGHT = 14;
|
|
22
|
+
|
|
23
|
+
export default class HelpExtension extends BaseExtension {
|
|
24
|
+
/** @type {HTMLElement} */
|
|
25
|
+
$outer;
|
|
26
|
+
/** @type {HTMLElement} */
|
|
27
|
+
$button;
|
|
28
|
+
/** @type {HTMLCanvasElement} */
|
|
29
|
+
$outer;
|
|
30
|
+
|
|
31
|
+
constructor(player, state, options) {
|
|
32
|
+
super(player, state, options, ['play']);
|
|
33
|
+
this.logger.debug('help:extension:creating');
|
|
34
|
+
|
|
35
|
+
this.showHelp = this.showHelp.bind(this);
|
|
36
|
+
this.hideHelp = this.hideHelp.bind(this);
|
|
37
|
+
|
|
38
|
+
this.render();
|
|
39
|
+
this.init();
|
|
40
|
+
|
|
41
|
+
this.logger.debug('help:extension:created');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
init() {
|
|
45
|
+
// setTimeout(() => {
|
|
46
|
+
// popover(this, { $button: this.$button, text: this.$t('help') });
|
|
47
|
+
// });
|
|
48
|
+
addEvent(this.$button, 'click', this.showHelp);
|
|
49
|
+
addEvent(this.$canvas, 'click', this.hideHelp);
|
|
50
|
+
addEvent(this.$canvas, 'mouseleave', this.hideHelp);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
render() {
|
|
54
|
+
this.$outer = createElement('div', { class: CN });
|
|
55
|
+
|
|
56
|
+
this.$canvas = createElement('canvas', { class: CANVAS_CN, tabindex: -1 }, this.$outer);
|
|
57
|
+
this.$button = createElement('button', { type: 'button', class: BUTTON_CN }, this.$outer);
|
|
58
|
+
this.$button.setAttribute('aria-label', this.$t('help'));
|
|
59
|
+
createSvg(this.$button, HELP);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
onPlay() {
|
|
63
|
+
this.hideHelp();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
showHelp(e) {
|
|
67
|
+
e.stopPropagation();
|
|
68
|
+
this.player.pause();
|
|
69
|
+
addClass(this.$outer, CANVAS_VISIBLE_CN);
|
|
70
|
+
/** @type {HTMLElement} */
|
|
71
|
+
const parent = this.$outer.parentNode;
|
|
72
|
+
const rect = parent.getBoundingClientRect();
|
|
73
|
+
|
|
74
|
+
this.$canvas.setAttribute('width', rect.width);
|
|
75
|
+
this.$canvas.setAttribute('height', rect.height);
|
|
76
|
+
|
|
77
|
+
const ctx = this.$canvas.getContext('2d');
|
|
78
|
+
ctx.globalCompositeOperation = 'xor';
|
|
79
|
+
ctx.font = rect.width < 500 ? '12px Verdana' : '14px Verdana';
|
|
80
|
+
|
|
81
|
+
ctx.fillStyle = 'rgba(0, 0, 0, 0.75)';
|
|
82
|
+
ctx.beginPath();
|
|
83
|
+
ctx.fillRect(0, 0, rect.width, rect.height);
|
|
84
|
+
ctx.fill();
|
|
85
|
+
|
|
86
|
+
const recttop = rect.height - RECT_WIDTH;
|
|
87
|
+
|
|
88
|
+
let top = TEXT_HEIGHT;
|
|
89
|
+
const linebottom = rect.height - RECT_WIDTH - THINKNESS;
|
|
90
|
+
|
|
91
|
+
let pointPosion = START_POSITION;
|
|
92
|
+
|
|
93
|
+
const points = [];
|
|
94
|
+
|
|
95
|
+
if (this.options.showForward) {
|
|
96
|
+
points.push(['help-bacward', pointPosion]);
|
|
97
|
+
pointPosion += STEP;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
points.push(['help-play', pointPosion]);
|
|
101
|
+
pointPosion += STEP;
|
|
102
|
+
|
|
103
|
+
if (this.options.showBackward) {
|
|
104
|
+
points.push(['help-skip', pointPosion]);
|
|
105
|
+
pointPosion += STEP;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
points.push(['help-volume', pointPosion]);
|
|
109
|
+
// pointPosion += STEP;
|
|
110
|
+
|
|
111
|
+
each(points, ([key, position], idx) => {
|
|
112
|
+
if (idx) {
|
|
113
|
+
top += 2 * TEXT_HEIGHT;
|
|
114
|
+
}
|
|
115
|
+
_rect(ctx, position, recttop);
|
|
116
|
+
_line(ctx, position, top, linebottom);
|
|
117
|
+
let left = position + BUTTON_MIDDLE;
|
|
118
|
+
_circle(ctx, left, top, THINKNESS);
|
|
119
|
+
|
|
120
|
+
left += 10;
|
|
121
|
+
top = wrapText(ctx, this.$t(key), left, top + 6, rect.width - left);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
if (this.options.showFullScreen) {
|
|
125
|
+
top += 2 * TEXT_HEIGHT;
|
|
126
|
+
const fullscreenPosition = rect.width - START_POSITION - BUTTON_WIDTH;
|
|
127
|
+
_rect(ctx, fullscreenPosition, recttop);
|
|
128
|
+
_line(ctx, fullscreenPosition, top, linebottom);
|
|
129
|
+
_circle(ctx, fullscreenPosition + BUTTON_MIDDLE, top, THINKNESS);
|
|
130
|
+
ctx.textAlign = 'right';
|
|
131
|
+
ctx.fillText(this.$t('help-esc'), fullscreenPosition + BUTTON_MIDDLE - 10, top + 6);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
hideHelp() {
|
|
136
|
+
removeClass(this.$outer, CANVAS_VISIBLE_CN);
|
|
137
|
+
const parent = this.$outer.parentNode;
|
|
138
|
+
const rect = parent.getBoundingClientRect();
|
|
139
|
+
const ctx = this.$canvas.getContext('2d');
|
|
140
|
+
ctx.fillRect(0, 0, rect.width, rect.height);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
getOuter() {
|
|
144
|
+
return this.$outer;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
destroy() {
|
|
148
|
+
super.destroy();
|
|
149
|
+
|
|
150
|
+
this.$outer.parentNode.removeChild(this.$outer);
|
|
151
|
+
|
|
152
|
+
this.$button = null;
|
|
153
|
+
this.$canvas = null;
|
|
154
|
+
this.$outer = null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// eslint-disable-next-line
|
|
159
|
+
function _rect(ctx, x, y) {
|
|
160
|
+
ctx.clearRect(x, y, BUTTON_WIDTH, BUTTON_WIDTH);
|
|
161
|
+
ctx.globalCompositeOperation = 'source-over';
|
|
162
|
+
ctx.strokeStyle = '#FFF';
|
|
163
|
+
ctx.lineWidth = THINKNESS;
|
|
164
|
+
const width = BUTTON_WIDTH + THINKNESS + THINKNESS;
|
|
165
|
+
const height = width;
|
|
166
|
+
ctx.strokeRect(x - THINKNESS, y - THINKNESS, width, height);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function _line(ctx, x, y1, y2) {
|
|
170
|
+
ctx.fillStyle = '#FFFFFF';
|
|
171
|
+
ctx.globalCompositeOperation = 'source-over';
|
|
172
|
+
ctx.lineWidth = 3;
|
|
173
|
+
ctx.strokeStyle = '#FFFFFF';
|
|
174
|
+
ctx.moveTo(x + BUTTON_MIDDLE, y1);
|
|
175
|
+
ctx.lineTo(x + BUTTON_MIDDLE, y2);
|
|
176
|
+
ctx.stroke();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function _circle(ctx, x, y, r) {
|
|
180
|
+
ctx.beginPath();
|
|
181
|
+
ctx.arc(x, y, r, 0, 2 * Math.PI);
|
|
182
|
+
ctx.stroke();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function wrapText(context, text, left, top, maxWidth) {
|
|
186
|
+
const lineHeight = 18;
|
|
187
|
+
let line = '';
|
|
188
|
+
each(text.split(' '), word => {
|
|
189
|
+
var testLine = line + word + ' ';
|
|
190
|
+
var testWidth = context.measureText(testLine).width;
|
|
191
|
+
if (testWidth > maxWidth) {
|
|
192
|
+
context.fillText(line, left, top);
|
|
193
|
+
line = word + ' ';
|
|
194
|
+
top += lineHeight;
|
|
195
|
+
} else {
|
|
196
|
+
line = testLine;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
context.fillText(line, left, top);
|
|
200
|
+
return top;
|
|
201
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// The one and only way of getting global scope in all environments
|
|
2
|
+
// https://stackoverflow.com/q/3277182/1008999
|
|
3
|
+
var _global = typeof window === 'object' && window.window === window
|
|
4
|
+
? window
|
|
5
|
+
: typeof self === 'object' && self.self === self
|
|
6
|
+
? self
|
|
7
|
+
: typeof global === 'object' && global.global === global
|
|
8
|
+
? global
|
|
9
|
+
: this;
|
|
10
|
+
|
|
11
|
+
function bom (blob, opts) {
|
|
12
|
+
if (typeof opts === 'undefined') opts = { autoBom: false };
|
|
13
|
+
else if (typeof opts !== 'object') {
|
|
14
|
+
console.warn('Deprecated: Expected third argument to be a object');
|
|
15
|
+
opts = { autoBom: !opts };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// prepend BOM for UTF-8 XML and text/* types (including HTML)
|
|
19
|
+
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
|
|
20
|
+
if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
|
|
21
|
+
return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type });
|
|
22
|
+
}
|
|
23
|
+
return blob;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function download (url, name, opts) {
|
|
27
|
+
var xhr = new XMLHttpRequest();
|
|
28
|
+
xhr.open('GET', url);
|
|
29
|
+
xhr.responseType = 'blob';
|
|
30
|
+
xhr.onload = function () {
|
|
31
|
+
saveAs(xhr.response, name, opts);
|
|
32
|
+
};
|
|
33
|
+
xhr.onerror = function () {
|
|
34
|
+
console.error('could not download file');
|
|
35
|
+
};
|
|
36
|
+
xhr.send();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function corsEnabled (url) {
|
|
40
|
+
var xhr = new XMLHttpRequest();
|
|
41
|
+
// use sync to avoid popup blocker
|
|
42
|
+
xhr.open('HEAD', url, false);
|
|
43
|
+
try {
|
|
44
|
+
xhr.send();
|
|
45
|
+
} catch (e) {}
|
|
46
|
+
return xhr.status >= 200 && xhr.status <= 299;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// `a.click()` doesn't work for all browsers (#465)
|
|
50
|
+
function click (node) {
|
|
51
|
+
try {
|
|
52
|
+
node.dispatchEvent(new MouseEvent('click'));
|
|
53
|
+
} catch (e) {
|
|
54
|
+
var evt = document.createEvent('MouseEvents');
|
|
55
|
+
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80,
|
|
56
|
+
20, false, false, false, false, 0, null);
|
|
57
|
+
node.dispatchEvent(evt);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Detect WebView inside a native macOS app by ruling out all browsers
|
|
62
|
+
// We just need to check for 'Safari' because all other browsers (besides Firefox) include that too
|
|
63
|
+
// https://www.whatismybrowser.com/guides/the-latest-user-agent/macos
|
|
64
|
+
var isMacOSWebView = /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent);
|
|
65
|
+
|
|
66
|
+
export var saveAs = _global.saveAs || (
|
|
67
|
+
// probably in some web worker
|
|
68
|
+
(typeof window !== 'object' || window !== _global)
|
|
69
|
+
? function saveAs () { /* noop */ }
|
|
70
|
+
|
|
71
|
+
// Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView
|
|
72
|
+
: ('download' in HTMLAnchorElement.prototype && !isMacOSWebView)
|
|
73
|
+
? function saveAs (blob, name, opts) {
|
|
74
|
+
var URL = _global.URL || _global.webkitURL;
|
|
75
|
+
var a = document.createElement('a');
|
|
76
|
+
name = name || blob.name || 'download';
|
|
77
|
+
|
|
78
|
+
a.download = name;
|
|
79
|
+
a.rel = 'noopener'; // tabnabbing
|
|
80
|
+
|
|
81
|
+
// TODO: detect chrome extensions & packaged apps
|
|
82
|
+
// a.target = '_blank'
|
|
83
|
+
|
|
84
|
+
if (typeof blob === 'string') {
|
|
85
|
+
// Support regular links
|
|
86
|
+
a.href = blob;
|
|
87
|
+
if (a.origin !== location.origin) {
|
|
88
|
+
corsEnabled(a.href)
|
|
89
|
+
? download(blob, name, opts)
|
|
90
|
+
: click(a, a.target = '_blank');
|
|
91
|
+
} else {
|
|
92
|
+
click(a);
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
// Support blobs
|
|
96
|
+
a.href = URL.createObjectURL(blob);
|
|
97
|
+
setTimeout(function () { URL.revokeObjectURL(a.href); }, 4E4); // 40s
|
|
98
|
+
setTimeout(function () { click(a); }, 0);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Use msSaveOrOpenBlob as a second approach
|
|
103
|
+
: 'msSaveOrOpenBlob' in navigator
|
|
104
|
+
? function saveAs (blob, name, opts) {
|
|
105
|
+
name = name || blob.name || 'download';
|
|
106
|
+
|
|
107
|
+
if (typeof blob === 'string') {
|
|
108
|
+
if (corsEnabled(blob)) {
|
|
109
|
+
download(blob, name, opts);
|
|
110
|
+
} else {
|
|
111
|
+
var a = document.createElement('a');
|
|
112
|
+
a.href = blob;
|
|
113
|
+
a.target = '_blank';
|
|
114
|
+
setTimeout(function () { click(a); });
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
navigator.msSaveOrOpenBlob(bom(blob, opts), name);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Fallback to using FileReader and a popup
|
|
122
|
+
: function saveAs (blob, name, opts, popup) {
|
|
123
|
+
// Open a popup immediately do go around popup blocker
|
|
124
|
+
// Mostly only available on user interaction and the fileReader is async so...
|
|
125
|
+
popup = popup || open('', '_blank');
|
|
126
|
+
if (popup) {
|
|
127
|
+
popup.document.title =
|
|
128
|
+
popup.document.body.innerText = 'downloading...';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (typeof blob === 'string') return download(blob, name, opts);
|
|
132
|
+
|
|
133
|
+
var force = blob.type === 'application/octet-stream';
|
|
134
|
+
var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari;
|
|
135
|
+
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent);
|
|
136
|
+
|
|
137
|
+
if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && typeof FileReader !== 'undefined') {
|
|
138
|
+
// Safari doesn't allow downloading of blob URLs
|
|
139
|
+
var reader = new FileReader();
|
|
140
|
+
reader.onloadend = function () {
|
|
141
|
+
var url = reader.result;
|
|
142
|
+
url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;');
|
|
143
|
+
if (popup) popup.location.href = url;
|
|
144
|
+
else location = url;
|
|
145
|
+
popup = null; // reverse-tabnabbing #460
|
|
146
|
+
};
|
|
147
|
+
reader.readAsDataURL(blob);
|
|
148
|
+
} else {
|
|
149
|
+
var URL = _global.URL || _global.webkitURL;
|
|
150
|
+
var url = URL.createObjectURL(blob);
|
|
151
|
+
if (popup) popup.location = url;
|
|
152
|
+
else location.href = url;
|
|
153
|
+
popup = null; // reverse-tabnabbing #460
|
|
154
|
+
setTimeout(function () { URL.revokeObjectURL(url); }, 4E4); // 40s
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
);
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { removeClass, addClass, removeEvent, addEvent, existy } from '../../utils';
|
|
2
|
+
|
|
3
|
+
import popoverPosition from './popoverPosition';
|
|
4
|
+
import openerHeightChecker from './openerHeightChecker';
|
|
5
|
+
|
|
6
|
+
const UP_CODE = 38;
|
|
7
|
+
const DOWN_CODE = 40;
|
|
8
|
+
const LEFT_CODE = 37;
|
|
9
|
+
const RIGHT_CODE = 39;
|
|
10
|
+
const ESC_CODE = 27;
|
|
11
|
+
|
|
12
|
+
export default function handle(extension, {
|
|
13
|
+
$button,
|
|
14
|
+
$selector,
|
|
15
|
+
SELECTOR_OPEN_CN,
|
|
16
|
+
reposition = true,
|
|
17
|
+
closeOnClick = false,
|
|
18
|
+
heightControl = false,
|
|
19
|
+
firstFocusItemSelector = '',
|
|
20
|
+
toMainFn = () => {}
|
|
21
|
+
}) {
|
|
22
|
+
let outerClickToken = null;
|
|
23
|
+
|
|
24
|
+
extension.addEvent($button, 'click', toggle);
|
|
25
|
+
|
|
26
|
+
if (!closeOnClick) {
|
|
27
|
+
extension.addEvent($selector, 'click', e => e.stopPropagation() );
|
|
28
|
+
}
|
|
29
|
+
extension.addEvent(extension.player.getElement(), 'mouseleave', hide);
|
|
30
|
+
extension.addEvent(extension.$selector, 'keydown', handleKeydown);
|
|
31
|
+
extension.bus.on('resizeplayer', hide);
|
|
32
|
+
|
|
33
|
+
function toggle() {
|
|
34
|
+
if (existy(outerClickToken)) {
|
|
35
|
+
hide();
|
|
36
|
+
} else {
|
|
37
|
+
show();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Accessability: Handle arrow keys press
|
|
42
|
+
// TODO: This is not generic way, we can find better one
|
|
43
|
+
// To be able to improve this we should refactor the way we rendering our extensions
|
|
44
|
+
// Ex.: Remove hidden elements from DOM, fix the order of element rendering, etc.
|
|
45
|
+
function handleKeydown(e) {
|
|
46
|
+
e.stopPropagation();
|
|
47
|
+
|
|
48
|
+
const keyCode = e.keyCode;
|
|
49
|
+
const activeElement = document.activeElement;
|
|
50
|
+
|
|
51
|
+
if (keyCode === ESC_CODE) {
|
|
52
|
+
e.preventDefault();
|
|
53
|
+
hide();
|
|
54
|
+
extension.$button.focus();
|
|
55
|
+
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// If nested menu, move to next step
|
|
60
|
+
if (keyCode === RIGHT_CODE) {
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
|
|
63
|
+
if (activeElement.classList.value.includes('__more')) {
|
|
64
|
+
activeElement.click();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// If nested menu, move to prev step
|
|
71
|
+
if (keyCode === LEFT_CODE) {
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
|
|
74
|
+
const allBackButtons = extension.$selector.querySelectorAll('button[class$="__back"]');
|
|
75
|
+
const visibleBackButton = Array.from(allBackButtons).find((btn) => btn.offsetWidth > 0 || btn.offsetHeight > 0);
|
|
76
|
+
|
|
77
|
+
if (visibleBackButton) visibleBackButton.click();
|
|
78
|
+
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (keyCode === DOWN_CODE) {
|
|
83
|
+
e.preventDefault();
|
|
84
|
+
let nextFocus = activeElement.nextElementSibling;
|
|
85
|
+
nextFocus = checkVisibility(nextFocus, 'nextElementSibling');
|
|
86
|
+
nextFocus = handleWrapperSibling(nextFocus, 'firstElementChild');
|
|
87
|
+
|
|
88
|
+
if (!nextFocus) {
|
|
89
|
+
nextFocus = handleWrapperParent(nextFocus, 'nextElementSibling');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (nextFocus) nextFocus.focus();
|
|
93
|
+
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (keyCode === UP_CODE) {
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
let prevFocus = activeElement.previousElementSibling;
|
|
100
|
+
prevFocus = handleWrapperParent(prevFocus, 'previousElementSibling');
|
|
101
|
+
prevFocus = checkVisibility(prevFocus, 'previousElementSibling');
|
|
102
|
+
prevFocus = handleWrapperSibling(prevFocus, 'lastElementChild');
|
|
103
|
+
|
|
104
|
+
if (prevFocus) prevFocus.focus();
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function handleWrapperParent(el, sibling) {
|
|
110
|
+
const activeElement = document.activeElement;
|
|
111
|
+
let element = el;
|
|
112
|
+
// check if there is no next element and parent is wrapper
|
|
113
|
+
const isInsideWrapper = !element && activeElement.parentElement.classList.value.includes('tab-content');
|
|
114
|
+
|
|
115
|
+
if (isInsideWrapper) {
|
|
116
|
+
element = activeElement.parentElement[sibling];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return element;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function handleWrapperSibling(el, child) {
|
|
123
|
+
let element = el;
|
|
124
|
+
// check if nextElement is wrapper element
|
|
125
|
+
const isWrapper = element && element.classList.value.includes('tab-content');
|
|
126
|
+
|
|
127
|
+
if (isWrapper) {
|
|
128
|
+
element = element[child];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return element;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function checkVisibility(el, direction) {
|
|
135
|
+
let element = el;
|
|
136
|
+
let visible = el && (element.offsetWidth > 0 || element.offsetHeight > 0);
|
|
137
|
+
|
|
138
|
+
while (!visible && element) {
|
|
139
|
+
element = element[direction];
|
|
140
|
+
visible = el && (element.offsetWidth > 0 || element.offsetHeight > 0);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return element;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function hide() {
|
|
147
|
+
toMainFn();
|
|
148
|
+
extension.bus.emit('hidepopup');
|
|
149
|
+
removeClass($selector, SELECTOR_OPEN_CN);
|
|
150
|
+
if (existy(outerClickToken)) {
|
|
151
|
+
removeEvent(outerClickToken);
|
|
152
|
+
outerClickToken = null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function show() {
|
|
157
|
+
addClass($selector, SELECTOR_OPEN_CN);
|
|
158
|
+
|
|
159
|
+
if (reposition) {
|
|
160
|
+
popoverPosition(extension.player, $button, $selector);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
setTimeout(() => {
|
|
164
|
+
extension.bus.emit('showpopup', $selector);
|
|
165
|
+
outerClickToken = addEvent(document, 'click', hide);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
if (heightControl) {
|
|
169
|
+
openerHeightChecker(extension.player, $selector);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Accessability: If presented, focus on the first menu item
|
|
173
|
+
if (firstFocusItemSelector) {
|
|
174
|
+
setTimeout(() => {
|
|
175
|
+
const firstFocusItem = $selector.querySelector(firstFocusItemSelector);
|
|
176
|
+
firstFocusItem.focus();
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { toggleClass, removeClass, addClass } from '../../utils';
|
|
2
|
+
|
|
3
|
+
import popoverPosition from './popoverPosition';
|
|
4
|
+
|
|
5
|
+
const DELAY = 200;
|
|
6
|
+
|
|
7
|
+
export default function handle(extension, { $button, $selector, SELECTOR_OPEN_CN }) {
|
|
8
|
+
extension.addEvent($button, 'click', toggle);
|
|
9
|
+
|
|
10
|
+
let timerId = 0;
|
|
11
|
+
|
|
12
|
+
extension.addEvent(extension.getElement(), 'mouseleave', hide);
|
|
13
|
+
|
|
14
|
+
extension.addEvent($button, 'mouseenter', () => timerId = setTimeout(show, DELAY) );
|
|
15
|
+
|
|
16
|
+
function toggle() {
|
|
17
|
+
toggleClass($selector, SELECTOR_OPEN_CN);
|
|
18
|
+
popoverPosition(extension.player, $button, $selector);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function hide() {
|
|
22
|
+
clearTimeout(timerId);
|
|
23
|
+
removeClass($selector, SELECTOR_OPEN_CN);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function show() {
|
|
27
|
+
addClass($selector, SELECTOR_OPEN_CN);
|
|
28
|
+
popoverPosition(extension.player, $button, $selector);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
const OPENER_MARGIN = 100;
|
|
3
|
+
const MAX_MAX_HEIGHT = 300;
|
|
4
|
+
|
|
5
|
+
export default function openerHeightChecker(player, $selector) {
|
|
6
|
+
if (!player || !player.getElement()) return;
|
|
7
|
+
|
|
8
|
+
$selector.style.maxHeight = '';
|
|
9
|
+
const rect = player.getElement().parentNode.getBoundingClientRect();
|
|
10
|
+
const mh = (rect.height || rect.bottom - rect.top) - OPENER_MARGIN;
|
|
11
|
+
|
|
12
|
+
$selector.style.maxHeight = `${Math.min(mh, MAX_MAX_HEIGHT)}px`;
|
|
13
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createElement, append, removeClass, addClass, isFunction } from '../../utils';
|
|
2
|
+
|
|
3
|
+
import popoverPosition from './popoverPosition';
|
|
4
|
+
|
|
5
|
+
const CN = 'rmp-ext-popover';
|
|
6
|
+
const VISIBLE_CN = `${CN}--visible`;
|
|
7
|
+
|
|
8
|
+
const DELAY = 500;
|
|
9
|
+
|
|
10
|
+
export default function popover(extension, { $button, text }) {
|
|
11
|
+
const parent = $button.parentNode;
|
|
12
|
+
const span = createElement('span', { class: CN, tabindex: 0 });
|
|
13
|
+
append(parent, span, $button);
|
|
14
|
+
$button.setAttribute('aria-label', isFunction(text) ? text() : text);
|
|
15
|
+
|
|
16
|
+
let timerId = 0;
|
|
17
|
+
|
|
18
|
+
extension.addEvent($button, 'mouseenter', () => timerId = setTimeout(show, DELAY) );
|
|
19
|
+
extension.addEvent($button, 'mouseleave', hide);
|
|
20
|
+
extension.addEvent($button, 'click', hide);
|
|
21
|
+
|
|
22
|
+
function show() {
|
|
23
|
+
span.textContent = isFunction(text) ? text() : text;
|
|
24
|
+
span.style.left = '0';
|
|
25
|
+
popoverPosition(extension.player, $button, span);
|
|
26
|
+
addClass(span, VISIBLE_CN);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function hide() {
|
|
30
|
+
clearTimeout(timerId);
|
|
31
|
+
removeClass(span, VISIBLE_CN);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import isElement from '../../utils/isElement';
|
|
2
|
+
|
|
3
|
+
const HALF = 2;
|
|
4
|
+
|
|
5
|
+
const PADDING = 3;
|
|
6
|
+
|
|
7
|
+
export default function popoverPosition(player, position, $popover) {
|
|
8
|
+
$popover.style.display = 'block';
|
|
9
|
+
let element = player.getElement();
|
|
10
|
+
const mediaWidth = element ? element.offsetWidth : 0;
|
|
11
|
+
if ( isElement(position) ) {
|
|
12
|
+
const parent = mediaWidth ? element : element.parentNode;
|
|
13
|
+
const parentRect = parent.getBoundingClientRect();
|
|
14
|
+
const rect = position.getBoundingClientRect();
|
|
15
|
+
position = _half(rect.left + rect.right) - parentRect.left;
|
|
16
|
+
}
|
|
17
|
+
const w = $popover.offsetWidth;
|
|
18
|
+
let l = Math.max(PADDING, position - _half(w));
|
|
19
|
+
// native audio element doesn't have any width
|
|
20
|
+
if (mediaWidth) {
|
|
21
|
+
l = Math.min(l, mediaWidth - w - PADDING);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
$popover.style.left = `${l}px`;
|
|
25
|
+
$popover.style.display = '';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function _half(num) {
|
|
29
|
+
return Math.floor(num / HALF);
|
|
30
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export default function scrollIntoView(el, parent) {
|
|
2
|
+
const { top } = el.getBoundingClientRect();
|
|
3
|
+
const rect = parent.getBoundingClientRect();
|
|
4
|
+
|
|
5
|
+
const startPosition = parent.scrollTop;
|
|
6
|
+
const delta = Math.floor(top - rect.top);
|
|
7
|
+
|
|
8
|
+
parent.scrollTop = startPosition + delta;
|
|
9
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import existy from '../../utils/existy';
|
|
2
|
+
|
|
3
|
+
const PREFIX = 'rmp-';
|
|
4
|
+
|
|
5
|
+
export function storeData(key, value) {
|
|
6
|
+
try {
|
|
7
|
+
localStorage.setItem(PREFIX + key, value);
|
|
8
|
+
} catch (e) {
|
|
9
|
+
//
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function getStoredData(key, defaultValue) {
|
|
14
|
+
try {
|
|
15
|
+
const res = localStorage.getItem(PREFIX + key);
|
|
16
|
+
return existy(res) ? res : defaultValue;
|
|
17
|
+
} catch (e) {
|
|
18
|
+
return defaultValue;
|
|
19
|
+
}
|
|
20
|
+
}
|