@oat-sa/tao-core-ui 1.5.4 → 1.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ckeditor/ckConfigurator.js +9 -1
- package/dist/mediaEditor/mediaEditorComponent.js +5 -3
- package/dist/mediaEditor/plugins/mediaDimension/mediaDimensionComponent.js +46 -25
- package/dist/mediaplayer/css/player.css +104 -14
- package/dist/mediaplayer/css/player.css.map +1 -1
- package/dist/mediaplayer/players/html5.js +767 -0
- package/dist/mediaplayer/players/youtube.js +470 -0
- package/dist/mediaplayer/players.js +35 -0
- package/dist/mediaplayer/support.js +134 -0
- package/dist/mediaplayer/utils/reminder.js +198 -0
- package/dist/mediaplayer/utils/timeObserver.js +149 -0
- package/dist/mediaplayer/youtubeManager.js +177 -0
- package/dist/mediaplayer.js +1251 -1912
- package/dist/previewer.js +25 -19
- package/package.json +1 -1
- package/scss/basic.scss +1 -0
- package/scss/inc/_jquery.nouislider.scss +254 -0
- package/src/ckeditor/ckConfigurator.js +10 -1
- package/src/itemButtonList/css/item-button-list.css +225 -0
- package/src/itemButtonList/css/item-button-list.css.map +1 -0
- package/src/mediaEditor/mediaEditorComponent.js +25 -26
- package/src/mediaEditor/plugins/mediaDimension/mediaDimensionComponent.js +83 -63
- package/src/mediaplayer/css/player.css +104 -14
- package/src/mediaplayer/css/player.css.map +1 -1
- package/src/mediaplayer/players/html5.js +564 -0
- package/src/mediaplayer/players/youtube.js +323 -0
- package/src/mediaplayer/players.js +29 -0
- package/src/mediaplayer/scss/player.scss +125 -16
- package/src/mediaplayer/support.js +126 -0
- package/src/mediaplayer/tpl/audio.tpl +6 -0
- package/src/mediaplayer/tpl/player.tpl +11 -32
- package/src/mediaplayer/tpl/source.tpl +1 -0
- package/src/mediaplayer/tpl/video.tpl +6 -0
- package/src/mediaplayer/tpl/youtube.tpl +1 -0
- package/src/mediaplayer/utils/reminder.js +184 -0
- package/src/mediaplayer/utils/timeObserver.js +143 -0
- package/src/mediaplayer/youtubeManager.js +161 -0
- package/src/mediaplayer.js +1217 -1901
- package/src/previewer.js +40 -33
- package/src/searchModal/css/advancedSearch.css +190 -0
- package/src/searchModal/css/advancedSearch.css.map +1 -0
- package/src/searchModal/css/searchModal.css +506 -0
- package/src/searchModal/css/searchModal.css.map +1 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This program is free software; you can redistribute it and/or
|
|
3
|
+
* modify it under the terms of the GNU General Public License
|
|
4
|
+
* as published by the Free Software Foundation; under version 2
|
|
5
|
+
* of the License (non-upgradable).
|
|
6
|
+
*
|
|
7
|
+
* This program is distributed in the hope that it will be useful,
|
|
8
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
9
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
10
|
+
* GNU General Public License for more details.
|
|
11
|
+
*
|
|
12
|
+
* You should have received a copy of the GNU General Public License
|
|
13
|
+
* along with this program; if not, write to the Free Software
|
|
14
|
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
15
|
+
*
|
|
16
|
+
* Copyright (c) 2015-2021 (original work) Open Assessment Technologies SA ;
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import $ from 'jquery';
|
|
20
|
+
import eventifier from 'core/eventifier';
|
|
21
|
+
import support from 'ui/mediaplayer/support';
|
|
22
|
+
import youtubeManagerFactory from 'ui/mediaplayer/youtubeManager';
|
|
23
|
+
import youtubeTpl from 'ui/mediaplayer/tpl/youtube';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The polling interval used to update the progress bar while playing a YouTube video.
|
|
27
|
+
* Note : the YouTube API does not provide events to update this progress bar...
|
|
28
|
+
* @type {Number}
|
|
29
|
+
*/
|
|
30
|
+
const youtubePolling = 100;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* List of YouTube events that can be listened to for debugging
|
|
34
|
+
* @type {String[]}
|
|
35
|
+
*/
|
|
36
|
+
const youtubeEvents = ['onApiChange', 'onError', 'onPlaybackQualityChange', 'onPlaybackRateChange', 'onStateChange'];
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* List of player events that can be listened to for debugging
|
|
40
|
+
* @type {String[]}
|
|
41
|
+
*/
|
|
42
|
+
const playerEvents = ['end', 'error', 'pause', 'play', 'ready', 'resize', 'timeupdate'];
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* A local manager for Youtube players.
|
|
46
|
+
* Relies on https://developers.google.com/youtube/iframe_api_reference
|
|
47
|
+
* @type {Object}
|
|
48
|
+
*/
|
|
49
|
+
const youtubeManager = youtubeManagerFactory();
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Defines a player object dedicated to youtube media
|
|
53
|
+
* @param {jQuery} $container - Where to render the player
|
|
54
|
+
* @param {Object} config - The list of config entries
|
|
55
|
+
* @param {Array} config.sources - The list of media sources
|
|
56
|
+
* @param {Boolean} [config.debug] - Enables the debug mode
|
|
57
|
+
* @param {Number} [config.polling=100] - The polling interval used to update the progress bar while playing a YouTube video.
|
|
58
|
+
* @returns {Object} player
|
|
59
|
+
*/
|
|
60
|
+
export default function youtubePlayerFactory($container, config = {}) {
|
|
61
|
+
const sources = config.sources || [];
|
|
62
|
+
const source = sources[0] || {};
|
|
63
|
+
const otherSources = sources.slice(1);
|
|
64
|
+
|
|
65
|
+
config.polling = config.polling || youtubePolling;
|
|
66
|
+
|
|
67
|
+
let $media;
|
|
68
|
+
let media;
|
|
69
|
+
let interval;
|
|
70
|
+
let destroyed;
|
|
71
|
+
let initWidth;
|
|
72
|
+
let initHeight;
|
|
73
|
+
let callbacks = [];
|
|
74
|
+
|
|
75
|
+
// eslint-disable-next-line
|
|
76
|
+
const debug = (action, ...args) => config.debug && window.console.log(`[youtube:${action}]`, ...args);
|
|
77
|
+
|
|
78
|
+
const queueMedia = (url, register) => {
|
|
79
|
+
const id = youtubeManager.extractYoutubeId(url);
|
|
80
|
+
if (id) {
|
|
81
|
+
if (media) {
|
|
82
|
+
register(id);
|
|
83
|
+
} else {
|
|
84
|
+
callbacks.push(() => register(id));
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const player = {
|
|
92
|
+
init() {
|
|
93
|
+
$media = $(
|
|
94
|
+
youtubeTpl({
|
|
95
|
+
src: source.src,
|
|
96
|
+
id: youtubeManager.extractYoutubeId(source.src)
|
|
97
|
+
})
|
|
98
|
+
);
|
|
99
|
+
$container.append($media);
|
|
100
|
+
otherSources.forEach(source => this.addMedia(source.src));
|
|
101
|
+
|
|
102
|
+
media = null;
|
|
103
|
+
destroyed = false;
|
|
104
|
+
|
|
105
|
+
youtubeManager.add($media, this, {
|
|
106
|
+
controls: !support.canControl()
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return true;
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
onReady(event) {
|
|
113
|
+
media = event.target;
|
|
114
|
+
$media = $(media.getIframe()); // the injected media placeholder is replaced by an iframe by the YouTube lib
|
|
115
|
+
|
|
116
|
+
if (!destroyed) {
|
|
117
|
+
// install debug logger
|
|
118
|
+
if (config.debug) {
|
|
119
|
+
debug('installed', media);
|
|
120
|
+
youtubeEvents.forEach(eventName =>
|
|
121
|
+
media.addEventListener(eventName, e => {
|
|
122
|
+
debug('media event', eventName, $media && $media.data('videoSrc'), e);
|
|
123
|
+
})
|
|
124
|
+
);
|
|
125
|
+
playerEvents.forEach(eventName => {
|
|
126
|
+
this.on(eventName, (...args) => {
|
|
127
|
+
debug('player event', eventName, $media && $media.data('videoSrc'), ...args);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (initWidth && initHeight) {
|
|
133
|
+
this.setSize(initWidth, initHeight);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
callbacks.forEach(cb => cb());
|
|
137
|
+
callbacks = [];
|
|
138
|
+
|
|
139
|
+
this.trigger('ready');
|
|
140
|
+
} else {
|
|
141
|
+
this.destroy();
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
onStateChange(event) {
|
|
146
|
+
this.stopPolling();
|
|
147
|
+
|
|
148
|
+
if (!destroyed) {
|
|
149
|
+
switch (event.data) {
|
|
150
|
+
// ended
|
|
151
|
+
case 0:
|
|
152
|
+
this.trigger('end');
|
|
153
|
+
break;
|
|
154
|
+
|
|
155
|
+
// playing
|
|
156
|
+
case 1:
|
|
157
|
+
this.trigger('play');
|
|
158
|
+
this.startPolling();
|
|
159
|
+
break;
|
|
160
|
+
|
|
161
|
+
// paused
|
|
162
|
+
case 2:
|
|
163
|
+
this.trigger('pause');
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
stopPolling() {
|
|
170
|
+
if (interval) {
|
|
171
|
+
window.clearInterval(interval);
|
|
172
|
+
interval = null;
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
startPolling() {
|
|
177
|
+
interval = window.setInterval(() => this.trigger('timeupdate'), config.polling);
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
destroy() {
|
|
181
|
+
debug('api call', 'destroy');
|
|
182
|
+
|
|
183
|
+
destroyed = true;
|
|
184
|
+
|
|
185
|
+
this.stopPolling();
|
|
186
|
+
this.removeAllListeners();
|
|
187
|
+
|
|
188
|
+
if (media) {
|
|
189
|
+
youtubeEvents.forEach(ev => media.removeEventListener(ev));
|
|
190
|
+
media.destroy();
|
|
191
|
+
media = void 0;
|
|
192
|
+
} else {
|
|
193
|
+
youtubeManager.remove($media, this);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if ($media) {
|
|
197
|
+
$media.remove();
|
|
198
|
+
$media = void 0;
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
getMedia() {
|
|
203
|
+
debug('api call', 'getMedia', media);
|
|
204
|
+
|
|
205
|
+
return media;
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
getPosition() {
|
|
209
|
+
let position = 0;
|
|
210
|
+
if (media) {
|
|
211
|
+
position = media.getCurrentTime();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
debug('api call', 'getPosition', position);
|
|
215
|
+
return position;
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
getDuration() {
|
|
219
|
+
let duration = 0;
|
|
220
|
+
if (media) {
|
|
221
|
+
duration = media.getDuration();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
debug('api call', 'getDuration', duration);
|
|
225
|
+
return duration;
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
getVolume() {
|
|
229
|
+
let volume = 0;
|
|
230
|
+
if (media) {
|
|
231
|
+
volume = media.getVolume();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
debug('api call', 'getVolume', volume);
|
|
235
|
+
return volume;
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
setVolume(volume) {
|
|
239
|
+
debug('api call', 'setVolume', volume);
|
|
240
|
+
|
|
241
|
+
if (media) {
|
|
242
|
+
media.setVolume(parseFloat(volume));
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
setSize(width, height) {
|
|
247
|
+
debug('api call', 'setSize', width, height);
|
|
248
|
+
|
|
249
|
+
this.trigger('resize', width, height);
|
|
250
|
+
|
|
251
|
+
if (!media) {
|
|
252
|
+
initWidth = width;
|
|
253
|
+
initHeight = height;
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
seek(time) {
|
|
258
|
+
debug('api call', 'seek', time);
|
|
259
|
+
|
|
260
|
+
if (media) {
|
|
261
|
+
media.seekTo(parseFloat(time), true);
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
play() {
|
|
266
|
+
debug('api call', 'play');
|
|
267
|
+
|
|
268
|
+
if (media) {
|
|
269
|
+
media.playVideo();
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
pause() {
|
|
274
|
+
debug('api call', 'pause');
|
|
275
|
+
|
|
276
|
+
if (media) {
|
|
277
|
+
media.pauseVideo();
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
stop() {
|
|
282
|
+
debug('api call', 'stop');
|
|
283
|
+
|
|
284
|
+
if (media) {
|
|
285
|
+
media.stopVideo();
|
|
286
|
+
this.trigger('end');
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
mute(state) {
|
|
291
|
+
debug('api call', 'mute', state);
|
|
292
|
+
|
|
293
|
+
if (media) {
|
|
294
|
+
media[state ? 'mute' : 'unMute']();
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
isMuted() {
|
|
299
|
+
let mute = false;
|
|
300
|
+
if (media) {
|
|
301
|
+
mute = media.isMuted();
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
debug('api call', 'isMuted', mute);
|
|
305
|
+
return mute;
|
|
306
|
+
},
|
|
307
|
+
|
|
308
|
+
addMedia(url) {
|
|
309
|
+
debug('api call', 'addMedia', url);
|
|
310
|
+
|
|
311
|
+
return queueMedia(url, id => media && media.cueVideoById(id));
|
|
312
|
+
},
|
|
313
|
+
|
|
314
|
+
setMedia(url) {
|
|
315
|
+
debug('api call', 'setMedia', url);
|
|
316
|
+
|
|
317
|
+
callbacks = [];
|
|
318
|
+
return queueMedia(url, id => media && media.loadVideoById(id));
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
return eventifier(player);
|
|
323
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This program is free software; you can redistribute it and/or
|
|
3
|
+
* modify it under the terms of the GNU General Public License
|
|
4
|
+
* as published by the Free Software Foundation; under version 2
|
|
5
|
+
* of the License (non-upgradable).
|
|
6
|
+
*
|
|
7
|
+
* This program is distributed in the hope that it will be useful,
|
|
8
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
9
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
10
|
+
* GNU General Public License for more details.
|
|
11
|
+
*
|
|
12
|
+
* You should have received a copy of the GNU General Public License
|
|
13
|
+
* along with this program; if not, write to the Free Software
|
|
14
|
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
15
|
+
*
|
|
16
|
+
* Copyright (c) 2015-2021 (original work) Open Assessment Technologies SA ;
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import html5PlayerFactory from 'ui/mediaplayer/players/html5';
|
|
20
|
+
import youtubePlayerFactory from 'ui/mediaplayer/players/youtube';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Defines the list of available players
|
|
24
|
+
*/
|
|
25
|
+
export default {
|
|
26
|
+
audio: html5PlayerFactory,
|
|
27
|
+
video: html5PlayerFactory,
|
|
28
|
+
youtube: youtubePlayerFactory
|
|
29
|
+
};
|
|
@@ -12,13 +12,24 @@ $playerSliderBackground: $uiGeneralContentBg;
|
|
|
12
12
|
$playerSliderColor: $darkBar;
|
|
13
13
|
$playerSliderHandle: whiten($playerSliderColor, .4);
|
|
14
14
|
$playerSliderHightlight: whiten($playerSliderColor, .2);
|
|
15
|
+
$controlsHeight: 36px;
|
|
15
16
|
|
|
16
17
|
.mediaplayer {
|
|
17
18
|
position: relative;
|
|
18
19
|
@include simple-border($playerBorder);
|
|
19
20
|
@include border-radius(2);
|
|
20
21
|
background: $playerBackground;
|
|
22
|
+
max-width: 100%;
|
|
23
|
+
min-height: $controlsHeight;
|
|
24
|
+
min-width: 200px;
|
|
21
25
|
|
|
26
|
+
&.youtube {
|
|
27
|
+
.player {
|
|
28
|
+
width: 100%;
|
|
29
|
+
height: 0px;
|
|
30
|
+
padding-bottom: 56.25%; // 56.25% for widescreen 16:9 aspect ratio videos
|
|
31
|
+
}
|
|
32
|
+
}
|
|
22
33
|
.icon-sound:before {
|
|
23
34
|
@include icon-audio();
|
|
24
35
|
}
|
|
@@ -32,12 +43,26 @@ $playerSliderHightlight: whiten($playerSliderColor, .2);
|
|
|
32
43
|
|
|
33
44
|
.player {
|
|
34
45
|
position: relative;
|
|
46
|
+
height: calc(100% - #{$controlsHeight});
|
|
47
|
+
width: 100%;
|
|
35
48
|
|
|
36
49
|
iframe {
|
|
37
50
|
pointer-events: none;
|
|
51
|
+
position: absolute;
|
|
52
|
+
left: 0;
|
|
53
|
+
top: 0;
|
|
54
|
+
width: 100%;
|
|
55
|
+
height: 100%
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.media:not(.youtube) {
|
|
59
|
+
display: block;
|
|
60
|
+
width: 100%;
|
|
61
|
+
height: auto;
|
|
62
|
+
max-height: 100%;
|
|
38
63
|
}
|
|
39
64
|
|
|
40
|
-
.overlay {
|
|
65
|
+
.player-overlay {
|
|
41
66
|
position: absolute;
|
|
42
67
|
z-index: 1;
|
|
43
68
|
top: 0;
|
|
@@ -53,10 +78,8 @@ $playerSliderHightlight: whiten($playerSliderColor, .2);
|
|
|
53
78
|
z-index: 2;
|
|
54
79
|
top: 50%;
|
|
55
80
|
left: 50%;
|
|
56
|
-
|
|
57
|
-
height: 64px;
|
|
81
|
+
transform: translate(-50%);
|
|
58
82
|
margin-top: -32px;
|
|
59
|
-
margin-left: -32px;
|
|
60
83
|
text-align: center;
|
|
61
84
|
text-decoration: none;
|
|
62
85
|
display: none;
|
|
@@ -73,6 +96,30 @@ $playerSliderHightlight: whiten($playerSliderColor, .2);
|
|
|
73
96
|
opacity: 0.6;
|
|
74
97
|
}
|
|
75
98
|
}
|
|
99
|
+
|
|
100
|
+
&.reload {
|
|
101
|
+
width: 100%;
|
|
102
|
+
font-size: 50px;
|
|
103
|
+
line-height: 30px;
|
|
104
|
+
|
|
105
|
+
&:hover {
|
|
106
|
+
.icon {
|
|
107
|
+
opacity: 1;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.icon {
|
|
112
|
+
opacity: 0.6;
|
|
113
|
+
background: none;
|
|
114
|
+
}
|
|
115
|
+
.message {
|
|
116
|
+
font-size: 20px;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.icon, .message {
|
|
120
|
+
text-shadow: 1px 0 0 #000, 0 -1px 0 #000, 0 1px 0 #000, -1px 0 0 #000;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
76
123
|
}
|
|
77
124
|
}
|
|
78
125
|
|
|
@@ -84,6 +131,7 @@ $playerSliderHightlight: whiten($playerSliderColor, .2);
|
|
|
84
131
|
table-layout: fixed;
|
|
85
132
|
width: 100%;
|
|
86
133
|
border-top: 1px solid $playerBorder;
|
|
134
|
+
height: $controlsHeight;
|
|
87
135
|
|
|
88
136
|
.bar {
|
|
89
137
|
display: table-row;
|
|
@@ -295,6 +343,43 @@ $playerSliderHightlight: whiten($playerSliderColor, .2);
|
|
|
295
343
|
bottom: 0;
|
|
296
344
|
}
|
|
297
345
|
}
|
|
346
|
+
|
|
347
|
+
&.stalled {
|
|
348
|
+
.player {
|
|
349
|
+
.player-overlay {
|
|
350
|
+
[data-control="reload"] {
|
|
351
|
+
display: flex;
|
|
352
|
+
align-items: center;
|
|
353
|
+
background-color: #000;
|
|
354
|
+
margin: 0;
|
|
355
|
+
flex-wrap: wrap;
|
|
356
|
+
padding: 5px 5px 5px 50px;
|
|
357
|
+
text-align: left;
|
|
358
|
+
line-height: 2.3rem;
|
|
359
|
+
&.reload {
|
|
360
|
+
width: calc(100% + 2px);
|
|
361
|
+
font-size: 20px;
|
|
362
|
+
line-height: 20px;
|
|
363
|
+
min-height: 36px;
|
|
364
|
+
|
|
365
|
+
.icon {
|
|
366
|
+
text-shadow: none;
|
|
367
|
+
position: absolute;
|
|
368
|
+
left: 0;
|
|
369
|
+
font-size: 2rem;
|
|
370
|
+
font-weight: bold;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.message {
|
|
374
|
+
text-shadow: none;
|
|
375
|
+
font-size: 1.3rem;
|
|
376
|
+
margin-right: 5px;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
298
383
|
}
|
|
299
384
|
|
|
300
385
|
&.ready {
|
|
@@ -303,17 +388,19 @@ $playerSliderHightlight: whiten($playerSliderColor, .2);
|
|
|
303
388
|
}
|
|
304
389
|
|
|
305
390
|
&.paused.canplay {
|
|
306
|
-
.overlay {
|
|
391
|
+
.player-overlay {
|
|
307
392
|
cursor: pointer;
|
|
308
393
|
}
|
|
309
394
|
|
|
310
|
-
.
|
|
311
|
-
|
|
312
|
-
|
|
395
|
+
&:not(.audio) {
|
|
396
|
+
.player:hover {
|
|
397
|
+
[data-control="play"] {
|
|
398
|
+
display: inline-block;
|
|
399
|
+
}
|
|
313
400
|
}
|
|
314
401
|
}
|
|
315
402
|
|
|
316
|
-
&.youtube.ended {
|
|
403
|
+
&.youtube.ended, &:not(.preview) {
|
|
317
404
|
.player:hover {
|
|
318
405
|
[data-control="play"] {
|
|
319
406
|
display: none;
|
|
@@ -323,13 +410,15 @@ $playerSliderHightlight: whiten($playerSliderColor, .2);
|
|
|
323
410
|
}
|
|
324
411
|
|
|
325
412
|
&.playing.canpause {
|
|
326
|
-
.overlay {
|
|
413
|
+
.player-overlay {
|
|
327
414
|
cursor: pointer;
|
|
328
415
|
}
|
|
329
416
|
|
|
330
|
-
.
|
|
331
|
-
|
|
332
|
-
|
|
417
|
+
&:not(.audio) {
|
|
418
|
+
.player:hover {
|
|
419
|
+
[data-control="pause"] {
|
|
420
|
+
display: inline-block;
|
|
421
|
+
}
|
|
333
422
|
}
|
|
334
423
|
}
|
|
335
424
|
}
|
|
@@ -371,7 +460,7 @@ $playerSliderHightlight: whiten($playerSliderColor, .2);
|
|
|
371
460
|
pointer-events: inherit;
|
|
372
461
|
}
|
|
373
462
|
}
|
|
374
|
-
.overlay {
|
|
463
|
+
.player-overlay {
|
|
375
464
|
display: none !important;
|
|
376
465
|
}
|
|
377
466
|
.controls {
|
|
@@ -379,7 +468,7 @@ $playerSliderHightlight: whiten($playerSliderColor, .2);
|
|
|
379
468
|
}
|
|
380
469
|
}
|
|
381
470
|
|
|
382
|
-
&.error {
|
|
471
|
+
&.error:not(.stalled) {
|
|
383
472
|
.media, .controls {
|
|
384
473
|
display: none;
|
|
385
474
|
}
|
|
@@ -398,7 +487,7 @@ $playerSliderHightlight: whiten($playerSliderColor, .2);
|
|
|
398
487
|
}
|
|
399
488
|
}
|
|
400
489
|
|
|
401
|
-
&.loading::before {
|
|
490
|
+
&.loading:not(.stalled)::before {
|
|
402
491
|
@keyframes spinner {
|
|
403
492
|
to { transform: rotate(360deg); }
|
|
404
493
|
}
|
|
@@ -417,4 +506,24 @@ $playerSliderHightlight: whiten($playerSliderColor, .2);
|
|
|
417
506
|
border-top-color: #07d;
|
|
418
507
|
animation: spinner .6s linear infinite;
|
|
419
508
|
}
|
|
509
|
+
|
|
510
|
+
&.stalled {
|
|
511
|
+
.video {
|
|
512
|
+
filter: blur(4px);
|
|
513
|
+
opacity: 0.4;
|
|
514
|
+
}
|
|
515
|
+
.player-overlay {
|
|
516
|
+
[data-control="reload"] {
|
|
517
|
+
display: inline-block;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
&.video:not(.preview):not(.error) {
|
|
523
|
+
.player-overlay {
|
|
524
|
+
[data-control="start"] {
|
|
525
|
+
display: inline-block;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
420
529
|
}
|