plyr-rails 2.0.11 → 2.0.12
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.
- checksums.yaml +4 -4
- data/lib/plyr/rails.rb +1 -4
- data/lib/plyr/rails/version.rb +1 -1
- data/vendor/assets/javascripts/plyr.js +2 -3775
- data/vendor/assets/stylesheets/plyr.css +1 -0
- metadata +2 -4
- data/vendor/assets/stylesheets/mixins.scss +0 -29
- data/vendor/assets/stylesheets/plyr.scss +0 -758
- data/vendor/assets/stylesheets/variables.scss +0 -73
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b68c85d16f138eb61ed634f6d49e0559963627c
|
4
|
+
data.tar.gz: c091f2d0729a0c7acf9c01cb063e411902746482
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1893b4c943ce6b0f37bfa8cadc2c0bb3a0e8135135b1b53a07aca3010cff0c18d9b74f3efec897f171c48ceb75c36b170818cecea0fbce18befc0823d82a5d80
|
7
|
+
data.tar.gz: d91e46ac89e5b08bd5cff73c014383fa5afff009a1a149b5c724554588ea4f4ed15342b3071e159435c5a354e8736d53054cd50a639fda8a8cf99369ab5790b2
|
data/lib/plyr/rails.rb
CHANGED
@@ -4,10 +4,7 @@ module Plyr
|
|
4
4
|
module Rails
|
5
5
|
class Engine < ::Rails::Engine
|
6
6
|
initializer :append_dependent_assets_path, :group => :all do |app|
|
7
|
-
app.config.assets.paths += %w( sprite )
|
8
|
-
|
9
|
-
app.config.assets.precompile += %w( plyr.scss )
|
10
|
-
app.config.assets.precompile += %w( plyr.js )
|
7
|
+
app.config.assets.paths += %w( sprite )
|
11
8
|
|
12
9
|
app.config.assets.precompile += %w( plyr-captions-off.svg )
|
13
10
|
app.config.assets.precompile += %w( plyr-captions-on.svg )
|
data/lib/plyr/rails/version.rb
CHANGED
@@ -1,3775 +1,2 @@
|
|
1
|
-
// ==========================================================================
|
2
|
-
// Plyr
|
3
|
-
// plyr.js v2.0.11
|
4
|
-
// https://github.com/selz/plyr
|
5
|
-
// License: The MIT License (MIT)
|
6
|
-
// ==========================================================================
|
7
|
-
// Credits: http://paypal.github.io/accessible-html5-video-player/
|
8
|
-
// ==========================================================================
|
9
|
-
|
10
|
-
;(function(root, factory) {
|
11
|
-
'use strict';
|
12
|
-
/*global define,module*/
|
13
|
-
|
14
|
-
if (typeof module === 'object' && typeof module.exports === 'object') {
|
15
|
-
// Node, CommonJS-like
|
16
|
-
module.exports = factory(root, document);
|
17
|
-
} else if (typeof define === 'function' && define.amd) {
|
18
|
-
// AMD
|
19
|
-
define([], function () { return factory(root, document); });
|
20
|
-
} else {
|
21
|
-
// Browser globals (root is window)
|
22
|
-
root.plyr = factory(root, document);
|
23
|
-
}
|
24
|
-
}(typeof window !== 'undefined' ? window : this, function(window, document) {
|
25
|
-
'use strict';
|
26
|
-
|
27
|
-
// Globals
|
28
|
-
var fullscreen,
|
29
|
-
scroll = { x: 0, y: 0 },
|
30
|
-
|
31
|
-
// Default config
|
32
|
-
defaults = {
|
33
|
-
enabled: true,
|
34
|
-
debug: false,
|
35
|
-
autoplay: false,
|
36
|
-
loop: false,
|
37
|
-
seekTime: 10,
|
38
|
-
volume: 10,
|
39
|
-
volumeMin: 0,
|
40
|
-
volumeMax: 10,
|
41
|
-
volumeStep: 1,
|
42
|
-
duration: null,
|
43
|
-
displayDuration: true,
|
44
|
-
loadSprite: true,
|
45
|
-
iconPrefix: 'plyr',
|
46
|
-
iconUrl: 'https://cdn.plyr.io/2.0.11/plyr.svg',
|
47
|
-
clickToPlay: true,
|
48
|
-
hideControls: true,
|
49
|
-
showPosterOnEnd: false,
|
50
|
-
disableContextMenu: true,
|
51
|
-
keyboardShorcuts: {
|
52
|
-
focused: true,
|
53
|
-
global: false
|
54
|
-
},
|
55
|
-
tooltips: {
|
56
|
-
controls: false,
|
57
|
-
seek: true
|
58
|
-
},
|
59
|
-
selectors: {
|
60
|
-
html5: 'video, audio',
|
61
|
-
embed: '[data-type]',
|
62
|
-
editable: 'input, textarea, select, [contenteditable]',
|
63
|
-
container: '.plyr',
|
64
|
-
controls: {
|
65
|
-
container: null,
|
66
|
-
wrapper: '.plyr__controls'
|
67
|
-
},
|
68
|
-
labels: '[data-plyr]',
|
69
|
-
buttons: {
|
70
|
-
seek: '[data-plyr="seek"]',
|
71
|
-
play: '[data-plyr="play"]',
|
72
|
-
pause: '[data-plyr="pause"]',
|
73
|
-
restart: '[data-plyr="restart"]',
|
74
|
-
rewind: '[data-plyr="rewind"]',
|
75
|
-
forward: '[data-plyr="fast-forward"]',
|
76
|
-
mute: '[data-plyr="mute"]',
|
77
|
-
captions: '[data-plyr="captions"]',
|
78
|
-
fullscreen: '[data-plyr="fullscreen"]'
|
79
|
-
},
|
80
|
-
volume: {
|
81
|
-
input: '[data-plyr="volume"]',
|
82
|
-
display: '.plyr__volume--display'
|
83
|
-
},
|
84
|
-
progress: {
|
85
|
-
container: '.plyr__progress',
|
86
|
-
buffer: '.plyr__progress--buffer',
|
87
|
-
played: '.plyr__progress--played'
|
88
|
-
},
|
89
|
-
captions: '.plyr__captions',
|
90
|
-
currentTime: '.plyr__time--current',
|
91
|
-
duration: '.plyr__time--duration'
|
92
|
-
},
|
93
|
-
classes: {
|
94
|
-
setup: 'plyr--setup',
|
95
|
-
ready: 'plyr--ready',
|
96
|
-
videoWrapper: 'plyr__video-wrapper',
|
97
|
-
embedWrapper: 'plyr__video-embed',
|
98
|
-
type: 'plyr--{0}',
|
99
|
-
stopped: 'plyr--stopped',
|
100
|
-
playing: 'plyr--playing',
|
101
|
-
muted: 'plyr--muted',
|
102
|
-
loading: 'plyr--loading',
|
103
|
-
hover: 'plyr--hover',
|
104
|
-
tooltip: 'plyr__tooltip',
|
105
|
-
hidden: 'plyr__sr-only',
|
106
|
-
hideControls: 'plyr--hide-controls',
|
107
|
-
isIos: 'plyr--is-ios',
|
108
|
-
isTouch: 'plyr--is-touch',
|
109
|
-
captions: {
|
110
|
-
enabled: 'plyr--captions-enabled',
|
111
|
-
active: 'plyr--captions-active'
|
112
|
-
},
|
113
|
-
fullscreen: {
|
114
|
-
enabled: 'plyr--fullscreen-enabled',
|
115
|
-
active: 'plyr--fullscreen-active'
|
116
|
-
},
|
117
|
-
tabFocus: 'tab-focus'
|
118
|
-
},
|
119
|
-
captions: {
|
120
|
-
defaultActive: false
|
121
|
-
},
|
122
|
-
fullscreen: {
|
123
|
-
enabled: true,
|
124
|
-
fallback: true,
|
125
|
-
allowAudio: false
|
126
|
-
},
|
127
|
-
storage: {
|
128
|
-
enabled: true,
|
129
|
-
key: 'plyr'
|
130
|
-
},
|
131
|
-
controls: ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'captions', 'fullscreen'],
|
132
|
-
i18n: {
|
133
|
-
restart: 'Restart',
|
134
|
-
rewind: 'Rewind {seektime} secs',
|
135
|
-
play: 'Play',
|
136
|
-
pause: 'Pause',
|
137
|
-
forward: 'Forward {seektime} secs',
|
138
|
-
played: 'played',
|
139
|
-
buffered: 'buffered',
|
140
|
-
currentTime: 'Current time',
|
141
|
-
duration: 'Duration',
|
142
|
-
volume: 'Volume',
|
143
|
-
toggleMute: 'Toggle Mute',
|
144
|
-
toggleCaptions: 'Toggle Captions',
|
145
|
-
toggleFullscreen: 'Toggle Fullscreen',
|
146
|
-
frameTitle: 'Player for {title}'
|
147
|
-
},
|
148
|
-
types: {
|
149
|
-
embed: ['youtube', 'vimeo', 'soundcloud'],
|
150
|
-
html5: ['video', 'audio']
|
151
|
-
},
|
152
|
-
// URLs
|
153
|
-
urls: {
|
154
|
-
vimeo: {
|
155
|
-
api: 'https://player.vimeo.com/api/player.js',
|
156
|
-
},
|
157
|
-
youtube: {
|
158
|
-
api: 'https://www.youtube.com/iframe_api'
|
159
|
-
},
|
160
|
-
soundcloud: {
|
161
|
-
api: 'https://w.soundcloud.com/player/api.js'
|
162
|
-
}
|
163
|
-
},
|
164
|
-
// Custom control listeners
|
165
|
-
listeners: {
|
166
|
-
seek: null,
|
167
|
-
play: null,
|
168
|
-
pause: null,
|
169
|
-
restart: null,
|
170
|
-
rewind: null,
|
171
|
-
forward: null,
|
172
|
-
mute: null,
|
173
|
-
volume: null,
|
174
|
-
captions: null,
|
175
|
-
fullscreen: null
|
176
|
-
},
|
177
|
-
// Events to watch on HTML5 media elements
|
178
|
-
events: ['ready', 'ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'seeked', 'emptied'],
|
179
|
-
// Logging
|
180
|
-
logPrefix: '[Plyr]'
|
181
|
-
};
|
182
|
-
|
183
|
-
// Credits: http://paypal.github.io/accessible-html5-video-player/
|
184
|
-
// Unfortunately, due to mixed support, UA sniffing is required
|
185
|
-
function _browserSniff() {
|
186
|
-
var ua = navigator.userAgent,
|
187
|
-
name = navigator.appName,
|
188
|
-
fullVersion = '' + parseFloat(navigator.appVersion),
|
189
|
-
majorVersion = parseInt(navigator.appVersion, 10),
|
190
|
-
nameOffset,
|
191
|
-
verOffset,
|
192
|
-
ix,
|
193
|
-
isIE = false,
|
194
|
-
isFirefox = false,
|
195
|
-
isChrome = false,
|
196
|
-
isSafari = false;
|
197
|
-
|
198
|
-
if ((navigator.appVersion.indexOf('Windows NT') !== -1) && (navigator.appVersion.indexOf('rv:11') !== -1)) {
|
199
|
-
// MSIE 11
|
200
|
-
isIE = true;
|
201
|
-
name = 'IE';
|
202
|
-
fullVersion = '11';
|
203
|
-
} else if ((verOffset = ua.indexOf('MSIE')) !== -1) {
|
204
|
-
// MSIE
|
205
|
-
isIE = true;
|
206
|
-
name = 'IE';
|
207
|
-
fullVersion = ua.substring(verOffset + 5);
|
208
|
-
} else if ((verOffset = ua.indexOf('Chrome')) !== -1) {
|
209
|
-
// Chrome
|
210
|
-
isChrome = true;
|
211
|
-
name = 'Chrome';
|
212
|
-
fullVersion = ua.substring(verOffset + 7);
|
213
|
-
} else if ((verOffset = ua.indexOf('Safari')) !== -1) {
|
214
|
-
// Safari
|
215
|
-
isSafari = true;
|
216
|
-
name = 'Safari';
|
217
|
-
fullVersion = ua.substring(verOffset + 7);
|
218
|
-
if ((verOffset = ua.indexOf('Version')) !== -1) {
|
219
|
-
fullVersion = ua.substring(verOffset + 8);
|
220
|
-
}
|
221
|
-
} else if ((verOffset = ua.indexOf('Firefox')) !== -1) {
|
222
|
-
// Firefox
|
223
|
-
isFirefox = true;
|
224
|
-
name = 'Firefox';
|
225
|
-
fullVersion = ua.substring(verOffset + 8);
|
226
|
-
} else if ((nameOffset = ua.lastIndexOf(' ') + 1) < (verOffset = ua.lastIndexOf('/'))) {
|
227
|
-
// In most other browsers, 'name/version' is at the end of userAgent
|
228
|
-
name = ua.substring(nameOffset,verOffset);
|
229
|
-
fullVersion = ua.substring(verOffset + 1);
|
230
|
-
|
231
|
-
if (name.toLowerCase() === name.toUpperCase()) {
|
232
|
-
name = navigator.appName;
|
233
|
-
}
|
234
|
-
}
|
235
|
-
|
236
|
-
// Trim the fullVersion string at semicolon/space if present
|
237
|
-
if ((ix = fullVersion.indexOf(';')) !== -1) {
|
238
|
-
fullVersion = fullVersion.substring(0, ix);
|
239
|
-
}
|
240
|
-
if ((ix = fullVersion.indexOf(' ')) !== -1) {
|
241
|
-
fullVersion = fullVersion.substring(0, ix);
|
242
|
-
}
|
243
|
-
|
244
|
-
// Get major version
|
245
|
-
majorVersion = parseInt('' + fullVersion, 10);
|
246
|
-
if (isNaN(majorVersion)) {
|
247
|
-
fullVersion = '' + parseFloat(navigator.appVersion);
|
248
|
-
majorVersion = parseInt(navigator.appVersion, 10);
|
249
|
-
}
|
250
|
-
|
251
|
-
// Return data
|
252
|
-
return {
|
253
|
-
name: name,
|
254
|
-
version: majorVersion,
|
255
|
-
isIE: isIE,
|
256
|
-
isFirefox: isFirefox,
|
257
|
-
isChrome: isChrome,
|
258
|
-
isSafari: isSafari,
|
259
|
-
isIos: /(iPad|iPhone|iPod)/g.test(navigator.platform),
|
260
|
-
isIphone: /(iPhone|iPod)/g.test(navigator.userAgent),
|
261
|
-
isTouch: 'ontouchstart' in document.documentElement
|
262
|
-
};
|
263
|
-
}
|
264
|
-
|
265
|
-
// Check for mime type support against a player instance
|
266
|
-
// Credits: http://diveintohtml5.info/everything.html
|
267
|
-
// Related: http://www.leanbackplyr.com/test/h5mt.html
|
268
|
-
function _supportMime(plyr, mimeType) {
|
269
|
-
var media = plyr.media;
|
270
|
-
|
271
|
-
if (plyr.type === 'video') {
|
272
|
-
// Check type
|
273
|
-
switch (mimeType) {
|
274
|
-
case 'video/webm': return !!(media.canPlayType && media.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/, ''));
|
275
|
-
case 'video/mp4': return !!(media.canPlayType && media.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, ''));
|
276
|
-
case 'video/ogg': return !!(media.canPlayType && media.canPlayType('video/ogg; codecs="theora"').replace(/no/, ''));
|
277
|
-
}
|
278
|
-
} else if (plyr.type === 'audio') {
|
279
|
-
// Check type
|
280
|
-
switch (mimeType) {
|
281
|
-
case 'audio/mpeg': return !!(media.canPlayType && media.canPlayType('audio/mpeg;').replace(/no/, ''));
|
282
|
-
case 'audio/ogg': return !!(media.canPlayType && media.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, ''));
|
283
|
-
case 'audio/wav': return !!(media.canPlayType && media.canPlayType('audio/wav; codecs="1"').replace(/no/, ''));
|
284
|
-
}
|
285
|
-
}
|
286
|
-
|
287
|
-
// If we got this far, we're stuffed
|
288
|
-
return false;
|
289
|
-
}
|
290
|
-
|
291
|
-
// Inject a script
|
292
|
-
function _injectScript(source) {
|
293
|
-
if (document.querySelectorAll('script[src="' + source + '"]').length) {
|
294
|
-
return;
|
295
|
-
}
|
296
|
-
|
297
|
-
var tag = document.createElement('script');
|
298
|
-
tag.src = source;
|
299
|
-
var firstScriptTag = document.getElementsByTagName('script')[0];
|
300
|
-
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
|
301
|
-
}
|
302
|
-
|
303
|
-
// Element exists in an array
|
304
|
-
function _inArray(haystack, needle) {
|
305
|
-
return Array.prototype.indexOf && (haystack.indexOf(needle) !== -1);
|
306
|
-
}
|
307
|
-
|
308
|
-
// Replace all
|
309
|
-
function _replaceAll(string, find, replace) {
|
310
|
-
return string.replace(new RegExp(find.replace(/([.*+?\^=!:${}()|\[\]\/\\])/g, '\\$1'), 'g'), replace);
|
311
|
-
}
|
312
|
-
|
313
|
-
// Wrap an element
|
314
|
-
function _wrap(elements, wrapper) {
|
315
|
-
// Convert `elements` to an array, if necessary.
|
316
|
-
if (!elements.length) {
|
317
|
-
elements = [elements];
|
318
|
-
}
|
319
|
-
|
320
|
-
// Loops backwards to prevent having to clone the wrapper on the
|
321
|
-
// first element (see `child` below).
|
322
|
-
for (var i = elements.length - 1; i >= 0; i--) {
|
323
|
-
var child = (i > 0) ? wrapper.cloneNode(true) : wrapper;
|
324
|
-
var element = elements[i];
|
325
|
-
|
326
|
-
// Cache the current parent and sibling.
|
327
|
-
var parent = element.parentNode;
|
328
|
-
var sibling = element.nextSibling;
|
329
|
-
|
330
|
-
// Wrap the element (is automatically removed from its current
|
331
|
-
// parent).
|
332
|
-
child.appendChild(element);
|
333
|
-
|
334
|
-
// If the element had a sibling, insert the wrapper before
|
335
|
-
// the sibling to maintain the HTML structure; otherwise, just
|
336
|
-
// append it to the parent.
|
337
|
-
if (sibling) {
|
338
|
-
parent.insertBefore(child, sibling);
|
339
|
-
} else {
|
340
|
-
parent.appendChild(child);
|
341
|
-
}
|
342
|
-
|
343
|
-
return child;
|
344
|
-
}
|
345
|
-
}
|
346
|
-
|
347
|
-
// Unwrap an element
|
348
|
-
// http://plainjs.com/javascript/manipulation/unwrap-a-dom-element-35/
|
349
|
-
/*function _unwrap(wrapper) {
|
350
|
-
// Get the element's parent node
|
351
|
-
var parent = wrapper.parentNode;
|
352
|
-
|
353
|
-
// Move all children out of the element
|
354
|
-
while (wrapper.firstChild) {
|
355
|
-
parent.insertBefore(wrapper.firstChild, wrapper);
|
356
|
-
}
|
357
|
-
|
358
|
-
// Remove the empty element
|
359
|
-
parent.removeChild(wrapper);
|
360
|
-
}*/
|
361
|
-
|
362
|
-
// Remove an element
|
363
|
-
function _remove(element) {
|
364
|
-
if (!element) {
|
365
|
-
return;
|
366
|
-
}
|
367
|
-
element.parentNode.removeChild(element);
|
368
|
-
}
|
369
|
-
|
370
|
-
// Prepend child
|
371
|
-
function _prependChild(parent, element) {
|
372
|
-
parent.insertBefore(element, parent.firstChild);
|
373
|
-
}
|
374
|
-
|
375
|
-
// Set attributes
|
376
|
-
function _setAttributes(element, attributes) {
|
377
|
-
for (var key in attributes) {
|
378
|
-
element.setAttribute(key, (_is.boolean(attributes[key]) && attributes[key]) ? '' : attributes[key]);
|
379
|
-
}
|
380
|
-
}
|
381
|
-
|
382
|
-
// Insert a HTML element
|
383
|
-
function _insertElement(type, parent, attributes) {
|
384
|
-
// Create a new <element>
|
385
|
-
var element = document.createElement(type);
|
386
|
-
|
387
|
-
// Set all passed attributes
|
388
|
-
_setAttributes(element, attributes);
|
389
|
-
|
390
|
-
// Inject the new element
|
391
|
-
_prependChild(parent, element);
|
392
|
-
}
|
393
|
-
|
394
|
-
// Get a classname from selector
|
395
|
-
function _getClassname(selector) {
|
396
|
-
return selector.replace('.', '');
|
397
|
-
}
|
398
|
-
|
399
|
-
// Toggle class on an element
|
400
|
-
function _toggleClass(element, className, state) {
|
401
|
-
if (element) {
|
402
|
-
if (element.classList) {
|
403
|
-
element.classList[state ? 'add' : 'remove'](className);
|
404
|
-
} else {
|
405
|
-
var name = (' ' + element.className + ' ').replace(/\s+/g, ' ').replace(' ' + className + ' ', '');
|
406
|
-
element.className = name + (state ? ' ' + className : '');
|
407
|
-
}
|
408
|
-
}
|
409
|
-
}
|
410
|
-
|
411
|
-
// Has class name
|
412
|
-
function _hasClass(element, className) {
|
413
|
-
if (element) {
|
414
|
-
if (element.classList) {
|
415
|
-
return element.classList.contains(className);
|
416
|
-
} else {
|
417
|
-
return new RegExp('(\\s|^)' + className + '(\\s|$)').test(element.className);
|
418
|
-
}
|
419
|
-
}
|
420
|
-
return false;
|
421
|
-
}
|
422
|
-
|
423
|
-
// Element matches selector
|
424
|
-
function _matches(element, selector) {
|
425
|
-
var p = Element.prototype;
|
426
|
-
|
427
|
-
var f = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || function(s) {
|
428
|
-
return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
|
429
|
-
};
|
430
|
-
|
431
|
-
return f.call(element, selector);
|
432
|
-
}
|
433
|
-
|
434
|
-
// Bind along with custom handler
|
435
|
-
function _proxyListener(element, eventName, userListener, defaultListener, useCapture) {
|
436
|
-
_on(element, eventName, function(event) {
|
437
|
-
if (userListener) {
|
438
|
-
userListener.apply(element, [event]);
|
439
|
-
}
|
440
|
-
defaultListener.apply(element, [event]);
|
441
|
-
}, useCapture);
|
442
|
-
}
|
443
|
-
|
444
|
-
// Toggle event listener
|
445
|
-
function _toggleListener(element, events, callback, toggle, useCapture) {
|
446
|
-
var eventList = events.split(' ');
|
447
|
-
|
448
|
-
// Whether the listener is a capturing listener or not
|
449
|
-
// Default to false
|
450
|
-
if (!_is.boolean(useCapture)) {
|
451
|
-
useCapture = false;
|
452
|
-
}
|
453
|
-
|
454
|
-
// If a nodelist is passed, call itself on each node
|
455
|
-
if (element instanceof NodeList) {
|
456
|
-
for (var x = 0; x < element.length; x++) {
|
457
|
-
if (element[x] instanceof Node) {
|
458
|
-
_toggleListener(element[x], arguments[1], arguments[2], arguments[3]);
|
459
|
-
}
|
460
|
-
}
|
461
|
-
return;
|
462
|
-
}
|
463
|
-
|
464
|
-
// If a single node is passed, bind the event listener
|
465
|
-
for (var i = 0; i < eventList.length; i++) {
|
466
|
-
element[toggle ? 'addEventListener' : 'removeEventListener'](eventList[i], callback, useCapture);
|
467
|
-
}
|
468
|
-
}
|
469
|
-
|
470
|
-
// Bind event
|
471
|
-
function _on(element, events, callback, useCapture) {
|
472
|
-
if (element) {
|
473
|
-
_toggleListener(element, events, callback, true, useCapture);
|
474
|
-
}
|
475
|
-
}
|
476
|
-
|
477
|
-
// Unbind event
|
478
|
-
/*function _off(element, events, callback, useCapture) {
|
479
|
-
if (element) {
|
480
|
-
_toggleListener(element, events, callback, false, useCapture);
|
481
|
-
}
|
482
|
-
}*/
|
483
|
-
|
484
|
-
// Trigger event
|
485
|
-
function _event(element, type, bubbles, properties) {
|
486
|
-
// Bail if no element
|
487
|
-
if (!element || !type) {
|
488
|
-
return;
|
489
|
-
}
|
490
|
-
|
491
|
-
// Default bubbles to false
|
492
|
-
if (!_is.boolean(bubbles)) {
|
493
|
-
bubbles = false;
|
494
|
-
}
|
495
|
-
|
496
|
-
// Create and dispatch the event
|
497
|
-
var event = new CustomEvent(type, {
|
498
|
-
bubbles: bubbles,
|
499
|
-
detail: properties
|
500
|
-
});
|
501
|
-
|
502
|
-
// Dispatch the event
|
503
|
-
element.dispatchEvent(event);
|
504
|
-
}
|
505
|
-
|
506
|
-
// Toggle aria-pressed state on a toggle button
|
507
|
-
// http://www.ssbbartgroup.com/blog/how-not-to-misuse-aria-states-properties-and-roles
|
508
|
-
function _toggleState(target, state) {
|
509
|
-
// Bail if no target
|
510
|
-
if (!target) {
|
511
|
-
return;
|
512
|
-
}
|
513
|
-
|
514
|
-
// Get state
|
515
|
-
state = (_is.boolean(state) ? state : !target.getAttribute('aria-pressed'));
|
516
|
-
|
517
|
-
// Set the attribute on target
|
518
|
-
target.setAttribute('aria-pressed', state);
|
519
|
-
|
520
|
-
return state;
|
521
|
-
}
|
522
|
-
|
523
|
-
// Get percentage
|
524
|
-
function _getPercentage(current, max) {
|
525
|
-
if (current === 0 || max === 0 || isNaN(current) || isNaN(max)) {
|
526
|
-
return 0;
|
527
|
-
}
|
528
|
-
return ((current / max) * 100).toFixed(2);
|
529
|
-
}
|
530
|
-
|
531
|
-
// Deep extend/merge destination object with N more objects
|
532
|
-
// http://andrewdupont.net/2009/08/28/deep-extending-objects-in-javascript/
|
533
|
-
// Removed call to arguments.callee (used explicit function name instead)
|
534
|
-
function _extend() {
|
535
|
-
// Get arguments
|
536
|
-
var objects = arguments;
|
537
|
-
|
538
|
-
// Bail if nothing to merge
|
539
|
-
if (!objects.length) {
|
540
|
-
return;
|
541
|
-
}
|
542
|
-
|
543
|
-
// Return first if specified but nothing to merge
|
544
|
-
if (objects.length === 1) {
|
545
|
-
return objects[0];
|
546
|
-
}
|
547
|
-
|
548
|
-
// First object is the destination
|
549
|
-
var destination = Array.prototype.shift.call(objects),
|
550
|
-
length = objects.length;
|
551
|
-
|
552
|
-
// Loop through all objects to merge
|
553
|
-
for (var i = 0; i < length; i++) {
|
554
|
-
var source = objects[i];
|
555
|
-
|
556
|
-
for (var property in source) {
|
557
|
-
if (source[property] && source[property].constructor && source[property].constructor === Object) {
|
558
|
-
destination[property] = destination[property] || {};
|
559
|
-
_extend(destination[property], source[property]);
|
560
|
-
} else {
|
561
|
-
destination[property] = source[property];
|
562
|
-
}
|
563
|
-
}
|
564
|
-
}
|
565
|
-
|
566
|
-
return destination;
|
567
|
-
}
|
568
|
-
|
569
|
-
// Check variable types
|
570
|
-
var _is = {
|
571
|
-
object: function(input) {
|
572
|
-
return input !== null && typeof(input) === 'object';
|
573
|
-
},
|
574
|
-
array: function(input) {
|
575
|
-
return input !== null && (typeof(input) === 'object' && input.constructor === Array);
|
576
|
-
},
|
577
|
-
number: function(input) {
|
578
|
-
return input !== null && (typeof(input) === 'number' && !isNaN(input - 0) || (typeof input === 'object' && input.constructor === Number));
|
579
|
-
},
|
580
|
-
string: function(input) {
|
581
|
-
return input !== null && (typeof input === 'string' || (typeof input === 'object' && input.constructor === String));
|
582
|
-
},
|
583
|
-
boolean: function(input) {
|
584
|
-
return input !== null && typeof input === 'boolean';
|
585
|
-
},
|
586
|
-
nodeList: function(input) {
|
587
|
-
return input !== null && input instanceof NodeList;
|
588
|
-
},
|
589
|
-
htmlElement: function(input) {
|
590
|
-
return input !== null && input instanceof HTMLElement;
|
591
|
-
},
|
592
|
-
function: function(input) {
|
593
|
-
return input !== null && typeof input === 'function';
|
594
|
-
},
|
595
|
-
undefined: function(input) {
|
596
|
-
return input !== null && typeof input === 'undefined';
|
597
|
-
}
|
598
|
-
};
|
599
|
-
|
600
|
-
// Parse YouTube ID from url
|
601
|
-
function _parseYouTubeId(url) {
|
602
|
-
var regex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
|
603
|
-
return (url.match(regex)) ? RegExp.$2 : url;
|
604
|
-
}
|
605
|
-
|
606
|
-
// Parse Vimeo ID from url
|
607
|
-
function _parseVimeoId(url) {
|
608
|
-
var regex = /^.*(vimeo.com\/|video\/)(\d+).*/;
|
609
|
-
return (url.match(regex)) ? RegExp.$2 : url;
|
610
|
-
}
|
611
|
-
|
612
|
-
// Fullscreen API
|
613
|
-
function _fullscreen() {
|
614
|
-
var fullscreen = {
|
615
|
-
supportsFullScreen: false,
|
616
|
-
isFullScreen: function() { return false; },
|
617
|
-
requestFullScreen: function() {},
|
618
|
-
cancelFullScreen: function() {},
|
619
|
-
fullScreenEventName: '',
|
620
|
-
element: null,
|
621
|
-
prefix: ''
|
622
|
-
},
|
623
|
-
browserPrefixes = 'webkit o moz ms khtml'.split(' ');
|
624
|
-
|
625
|
-
// Check for native support
|
626
|
-
if (!_is.undefined(document.cancelFullScreen)) {
|
627
|
-
fullscreen.supportsFullScreen = true;
|
628
|
-
} else {
|
629
|
-
// Check for fullscreen support by vendor prefix
|
630
|
-
for (var i = 0, il = browserPrefixes.length; i < il; i++ ) {
|
631
|
-
fullscreen.prefix = browserPrefixes[i];
|
632
|
-
|
633
|
-
if (!_is.undefined(document[fullscreen.prefix + 'CancelFullScreen'])) {
|
634
|
-
fullscreen.supportsFullScreen = true;
|
635
|
-
break;
|
636
|
-
} else if (!_is.undefined(document.msExitFullscreen) && document.msFullscreenEnabled) {
|
637
|
-
// Special case for MS (when isn't it?)
|
638
|
-
fullscreen.prefix = 'ms';
|
639
|
-
fullscreen.supportsFullScreen = true;
|
640
|
-
break;
|
641
|
-
}
|
642
|
-
}
|
643
|
-
}
|
644
|
-
|
645
|
-
// Update methods to do something useful
|
646
|
-
if (fullscreen.supportsFullScreen) {
|
647
|
-
// Yet again Microsoft awesomeness,
|
648
|
-
// Sometimes the prefix is 'ms', sometimes 'MS' to keep you on your toes
|
649
|
-
fullscreen.fullScreenEventName = (fullscreen.prefix === 'ms' ? 'MSFullscreenChange' : fullscreen.prefix + 'fullscreenchange');
|
650
|
-
|
651
|
-
fullscreen.isFullScreen = function(element) {
|
652
|
-
if (_is.undefined(element)) {
|
653
|
-
element = document.body;
|
654
|
-
}
|
655
|
-
switch (this.prefix) {
|
656
|
-
case '':
|
657
|
-
return document.fullscreenElement === element;
|
658
|
-
case 'moz':
|
659
|
-
return document.mozFullScreenElement === element;
|
660
|
-
default:
|
661
|
-
return document[this.prefix + 'FullscreenElement'] === element;
|
662
|
-
}
|
663
|
-
};
|
664
|
-
fullscreen.requestFullScreen = function(element) {
|
665
|
-
if (_is.undefined(element)) {
|
666
|
-
element = document.body;
|
667
|
-
}
|
668
|
-
return (this.prefix === '') ? element.requestFullScreen() : element[this.prefix + (this.prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen')]();
|
669
|
-
};
|
670
|
-
fullscreen.cancelFullScreen = function() {
|
671
|
-
return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + (this.prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen')]();
|
672
|
-
};
|
673
|
-
fullscreen.element = function() {
|
674
|
-
return (this.prefix === '') ? document.fullscreenElement : document[this.prefix + 'FullscreenElement'];
|
675
|
-
};
|
676
|
-
}
|
677
|
-
|
678
|
-
return fullscreen;
|
679
|
-
}
|
680
|
-
|
681
|
-
// Local storage
|
682
|
-
var _storage = {
|
683
|
-
supported: (function() {
|
684
|
-
if (!('localStorage' in window)) {
|
685
|
-
return false;
|
686
|
-
}
|
687
|
-
|
688
|
-
// Try to use it (it might be disabled, e.g. user is in private/porn mode)
|
689
|
-
// see: https://github.com/Selz/plyr/issues/131
|
690
|
-
try {
|
691
|
-
// Add test item
|
692
|
-
window.localStorage.setItem('___test', 'OK');
|
693
|
-
|
694
|
-
// Get the test item
|
695
|
-
var result = window.localStorage.getItem('___test');
|
696
|
-
|
697
|
-
// Clean up
|
698
|
-
window.localStorage.removeItem('___test');
|
699
|
-
|
700
|
-
// Check if value matches
|
701
|
-
return (result === 'OK');
|
702
|
-
}
|
703
|
-
catch (e) {
|
704
|
-
return false;
|
705
|
-
}
|
706
|
-
|
707
|
-
return false;
|
708
|
-
})()
|
709
|
-
};
|
710
|
-
|
711
|
-
// Player instance
|
712
|
-
function Plyr(media, config) {
|
713
|
-
var plyr = this,
|
714
|
-
timers = {},
|
715
|
-
api;
|
716
|
-
|
717
|
-
// Set media
|
718
|
-
plyr.media = media;
|
719
|
-
var original = media.cloneNode(true);
|
720
|
-
|
721
|
-
// Trigger events, with plyr instance passed
|
722
|
-
function _triggerEvent(element, type, bubbles, properties) {
|
723
|
-
_event(element, type, bubbles, _extend({}, properties, {
|
724
|
-
plyr: api
|
725
|
-
}));
|
726
|
-
}
|
727
|
-
|
728
|
-
// Debugging
|
729
|
-
function _console(type, args) {
|
730
|
-
if (config.debug && window.console) {
|
731
|
-
args = Array.prototype.slice.call(args);
|
732
|
-
|
733
|
-
if (_is.string(config.logPrefix) && config.logPrefix.length) {
|
734
|
-
args.unshift(config.logPrefix);
|
735
|
-
}
|
736
|
-
|
737
|
-
console[type].apply(console, args);
|
738
|
-
}
|
739
|
-
}
|
740
|
-
var _log = function() { _console('log', arguments) },
|
741
|
-
_warn = function() { _console('warn', arguments) };
|
742
|
-
|
743
|
-
// Log config options
|
744
|
-
_log('Config', config);
|
745
|
-
|
746
|
-
// Get icon URL
|
747
|
-
function _getIconUrl() {
|
748
|
-
return {
|
749
|
-
url: config.iconUrl,
|
750
|
-
absolute: (config.iconUrl.indexOf("http") === 0) || plyr.browser.isIE
|
751
|
-
};
|
752
|
-
}
|
753
|
-
|
754
|
-
// Build the default HTML
|
755
|
-
function _buildControls() {
|
756
|
-
// Create html array
|
757
|
-
var html = [],
|
758
|
-
iconUrl = _getIconUrl(),
|
759
|
-
iconPath = (!iconUrl.absolute ? iconUrl.url : '') + '#' + config.iconPrefix;
|
760
|
-
|
761
|
-
// Larger overlaid play button
|
762
|
-
if (_inArray(config.controls, 'play-large')) {
|
763
|
-
html.push(
|
764
|
-
'<button type="button" data-plyr="play" class="plyr__play-large">',
|
765
|
-
'<svg><use xlink:href="' + iconPath + '-play" /></svg>',
|
766
|
-
'<span class="plyr__sr-only">' + config.i18n.play + '</span>',
|
767
|
-
'</button>'
|
768
|
-
);
|
769
|
-
}
|
770
|
-
|
771
|
-
html.push('<div class="plyr__controls">');
|
772
|
-
|
773
|
-
// Restart button
|
774
|
-
if (_inArray(config.controls, 'restart')) {
|
775
|
-
html.push(
|
776
|
-
'<button type="button" data-plyr="restart">',
|
777
|
-
'<svg><use xlink:href="' + iconPath + '-restart" /></svg>',
|
778
|
-
'<span class="plyr__sr-only">' + config.i18n.restart + '</span>',
|
779
|
-
'</button>'
|
780
|
-
);
|
781
|
-
}
|
782
|
-
|
783
|
-
// Rewind button
|
784
|
-
if (_inArray(config.controls, 'rewind')) {
|
785
|
-
html.push(
|
786
|
-
'<button type="button" data-plyr="rewind">',
|
787
|
-
'<svg><use xlink:href="' + iconPath + '-rewind" /></svg>',
|
788
|
-
'<span class="plyr__sr-only">' + config.i18n.rewind + '</span>',
|
789
|
-
'</button>'
|
790
|
-
);
|
791
|
-
}
|
792
|
-
|
793
|
-
// Play Pause button
|
794
|
-
// TODO: This should be a toggle button really?
|
795
|
-
if (_inArray(config.controls, 'play')) {
|
796
|
-
html.push(
|
797
|
-
'<button type="button" data-plyr="play">',
|
798
|
-
'<svg><use xlink:href="' + iconPath + '-play" /></svg>',
|
799
|
-
'<span class="plyr__sr-only">' + config.i18n.play + '</span>',
|
800
|
-
'</button>',
|
801
|
-
'<button type="button" data-plyr="pause">',
|
802
|
-
'<svg><use xlink:href="' + iconPath + '-pause" /></svg>',
|
803
|
-
'<span class="plyr__sr-only">' + config.i18n.pause + '</span>',
|
804
|
-
'</button>'
|
805
|
-
);
|
806
|
-
}
|
807
|
-
|
808
|
-
// Fast forward button
|
809
|
-
if (_inArray(config.controls, 'fast-forward')) {
|
810
|
-
html.push(
|
811
|
-
'<button type="button" data-plyr="fast-forward">',
|
812
|
-
'<svg><use xlink:href="' + iconPath + '-fast-forward" /></svg>',
|
813
|
-
'<span class="plyr__sr-only">' + config.i18n.forward + '</span>',
|
814
|
-
'</button>'
|
815
|
-
);
|
816
|
-
}
|
817
|
-
|
818
|
-
// Progress
|
819
|
-
if (_inArray(config.controls, 'progress')) {
|
820
|
-
// Create progress
|
821
|
-
html.push('<span class="plyr__progress">',
|
822
|
-
'<label for="seek{id}" class="plyr__sr-only">Seek</label>',
|
823
|
-
'<input id="seek{id}" class="plyr__progress--seek" type="range" min="0" max="100" step="0.1" value="0" data-plyr="seek">',
|
824
|
-
'<progress class="plyr__progress--played" max="100" value="0" role="presentation"></progress>',
|
825
|
-
'<progress class="plyr__progress--buffer" max="100" value="0">',
|
826
|
-
'<span>0</span>% ' + config.i18n.buffered,
|
827
|
-
'</progress>');
|
828
|
-
|
829
|
-
// Seek tooltip
|
830
|
-
if (config.tooltips.seek) {
|
831
|
-
html.push('<span class="plyr__tooltip">00:00</span>');
|
832
|
-
}
|
833
|
-
|
834
|
-
// Close
|
835
|
-
html.push('</span>');
|
836
|
-
}
|
837
|
-
|
838
|
-
// Media current time display
|
839
|
-
if (_inArray(config.controls, 'current-time')) {
|
840
|
-
html.push(
|
841
|
-
'<span class="plyr__time">',
|
842
|
-
'<span class="plyr__sr-only">' + config.i18n.currentTime + '</span>',
|
843
|
-
'<span class="plyr__time--current">00:00</span>',
|
844
|
-
'</span>'
|
845
|
-
);
|
846
|
-
}
|
847
|
-
|
848
|
-
// Media duration display
|
849
|
-
if (_inArray(config.controls, 'duration')) {
|
850
|
-
html.push(
|
851
|
-
'<span class="plyr__time">',
|
852
|
-
'<span class="plyr__sr-only">' + config.i18n.duration + '</span>',
|
853
|
-
'<span class="plyr__time--duration">00:00</span>',
|
854
|
-
'</span>'
|
855
|
-
);
|
856
|
-
}
|
857
|
-
|
858
|
-
// Toggle mute button
|
859
|
-
if (_inArray(config.controls, 'mute')) {
|
860
|
-
html.push(
|
861
|
-
'<button type="button" data-plyr="mute">',
|
862
|
-
'<svg class="icon--muted"><use xlink:href="' + iconPath + '-muted" /></svg>',
|
863
|
-
'<svg><use xlink:href="' + iconPath + '-volume" /></svg>',
|
864
|
-
'<span class="plyr__sr-only">' + config.i18n.toggleMute + '</span>',
|
865
|
-
'</button>'
|
866
|
-
);
|
867
|
-
}
|
868
|
-
|
869
|
-
// Volume range control
|
870
|
-
if (_inArray(config.controls, 'volume')) {
|
871
|
-
html.push(
|
872
|
-
'<span class="plyr__volume">',
|
873
|
-
'<label for="volume{id}" class="plyr__sr-only">' + config.i18n.volume + '</label>',
|
874
|
-
'<input id="volume{id}" class="plyr__volume--input" type="range" min="' + config.volumeMin + '" max="' + config.volumeMax + '" value="' + config.volume + '" data-plyr="volume">',
|
875
|
-
'<progress class="plyr__volume--display" max="' + config.volumeMax + '" value="' + config.volumeMin + '" role="presentation"></progress>',
|
876
|
-
'</span>'
|
877
|
-
);
|
878
|
-
}
|
879
|
-
|
880
|
-
// Toggle captions button
|
881
|
-
if (_inArray(config.controls, 'captions')) {
|
882
|
-
html.push(
|
883
|
-
'<button type="button" data-plyr="captions">',
|
884
|
-
'<svg class="icon--captions-on"><use xlink:href="' + iconPath + '-captions-on" /></svg>',
|
885
|
-
'<svg><use xlink:href="' + iconPath+ '-captions-off" /></svg>',
|
886
|
-
'<span class="plyr__sr-only">' + config.i18n.toggleCaptions + '</span>',
|
887
|
-
'</button>'
|
888
|
-
);
|
889
|
-
}
|
890
|
-
|
891
|
-
// Toggle fullscreen button
|
892
|
-
if (_inArray(config.controls, 'fullscreen')) {
|
893
|
-
html.push(
|
894
|
-
'<button type="button" data-plyr="fullscreen">',
|
895
|
-
'<svg class="icon--exit-fullscreen"><use xlink:href="' + iconPath + '-exit-fullscreen" /></svg>',
|
896
|
-
'<svg><use xlink:href="' + iconPath + '-enter-fullscreen" /></svg>',
|
897
|
-
'<span class="plyr__sr-only">' + config.i18n.toggleFullscreen + '</span>',
|
898
|
-
'</button>'
|
899
|
-
);
|
900
|
-
}
|
901
|
-
|
902
|
-
// Close everything
|
903
|
-
html.push('</div>');
|
904
|
-
|
905
|
-
return html.join('');
|
906
|
-
}
|
907
|
-
|
908
|
-
// Setup fullscreen
|
909
|
-
function _setupFullscreen() {
|
910
|
-
if (!plyr.supported.full) {
|
911
|
-
return;
|
912
|
-
}
|
913
|
-
|
914
|
-
if ((plyr.type !== 'audio' || config.fullscreen.allowAudio) && config.fullscreen.enabled) {
|
915
|
-
// Check for native support
|
916
|
-
var nativeSupport = fullscreen.supportsFullScreen;
|
917
|
-
|
918
|
-
if (nativeSupport || (config.fullscreen.fallback && !_inFrame())) {
|
919
|
-
_log((nativeSupport ? 'Native' : 'Fallback') + ' fullscreen enabled');
|
920
|
-
|
921
|
-
// Add styling hook
|
922
|
-
_toggleClass(plyr.container, config.classes.fullscreen.enabled, true);
|
923
|
-
} else {
|
924
|
-
_log('Fullscreen not supported and fallback disabled');
|
925
|
-
}
|
926
|
-
|
927
|
-
// Toggle state
|
928
|
-
if (plyr.buttons && plyr.buttons.fullscreen) {
|
929
|
-
_toggleState(plyr.buttons.fullscreen, false);
|
930
|
-
}
|
931
|
-
|
932
|
-
// Setup focus trap
|
933
|
-
_focusTrap();
|
934
|
-
}
|
935
|
-
}
|
936
|
-
|
937
|
-
// Setup captions
|
938
|
-
function _setupCaptions() {
|
939
|
-
// Bail if not HTML5 video
|
940
|
-
if (plyr.type !== 'video') {
|
941
|
-
return;
|
942
|
-
}
|
943
|
-
|
944
|
-
// Inject the container
|
945
|
-
if (!_getElement(config.selectors.captions)) {
|
946
|
-
plyr.videoContainer.insertAdjacentHTML('afterbegin', '<div class="' + _getClassname(config.selectors.captions) + '"></div>');
|
947
|
-
}
|
948
|
-
|
949
|
-
// Determine if HTML5 textTracks is supported
|
950
|
-
plyr.usingTextTracks = false;
|
951
|
-
if (plyr.media.textTracks) {
|
952
|
-
plyr.usingTextTracks = true;
|
953
|
-
}
|
954
|
-
|
955
|
-
// Get URL of caption file if exists
|
956
|
-
var captionSrc = '',
|
957
|
-
kind,
|
958
|
-
children = plyr.media.childNodes;
|
959
|
-
|
960
|
-
for (var i = 0; i < children.length; i++) {
|
961
|
-
if (children[i].nodeName.toLowerCase() === 'track') {
|
962
|
-
kind = children[i].kind;
|
963
|
-
if (kind === 'captions' || kind === 'subtitles') {
|
964
|
-
captionSrc = children[i].getAttribute('src');
|
965
|
-
}
|
966
|
-
}
|
967
|
-
}
|
968
|
-
|
969
|
-
// Record if caption file exists or not
|
970
|
-
plyr.captionExists = true;
|
971
|
-
if (captionSrc === '') {
|
972
|
-
plyr.captionExists = false;
|
973
|
-
_log('No caption track found');
|
974
|
-
} else {
|
975
|
-
_log('Caption track found; URI: ' + captionSrc);
|
976
|
-
}
|
977
|
-
|
978
|
-
// If no caption file exists, hide container for caption text
|
979
|
-
if (!plyr.captionExists) {
|
980
|
-
_toggleClass(plyr.container, config.classes.captions.enabled);
|
981
|
-
} else {
|
982
|
-
// Turn off native caption rendering to avoid double captions
|
983
|
-
// This doesn't seem to work in Safari 7+, so the <track> elements are removed from the dom below
|
984
|
-
var tracks = plyr.media.textTracks;
|
985
|
-
for (var x = 0; x < tracks.length; x++) {
|
986
|
-
tracks[x].mode = 'hidden';
|
987
|
-
}
|
988
|
-
|
989
|
-
// Enable UI
|
990
|
-
_showCaptions(plyr);
|
991
|
-
|
992
|
-
// Disable unsupported browsers than report false positive
|
993
|
-
// Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1033144
|
994
|
-
if ((plyr.browser.isIE && plyr.browser.version >= 10) ||
|
995
|
-
(plyr.browser.isFirefox && plyr.browser.version >= 31)) {
|
996
|
-
|
997
|
-
// Debugging
|
998
|
-
_log('Detected browser with known TextTrack issues - using manual fallback');
|
999
|
-
|
1000
|
-
// Set to false so skips to 'manual' captioning
|
1001
|
-
plyr.usingTextTracks = false;
|
1002
|
-
}
|
1003
|
-
|
1004
|
-
// Rendering caption tracks
|
1005
|
-
// Native support required - http://caniuse.com/webvtt
|
1006
|
-
if (plyr.usingTextTracks) {
|
1007
|
-
_log('TextTracks supported');
|
1008
|
-
|
1009
|
-
for (var y = 0; y < tracks.length; y++) {
|
1010
|
-
var track = tracks[y];
|
1011
|
-
|
1012
|
-
if (track.kind === 'captions' || track.kind === 'subtitles') {
|
1013
|
-
_on(track, 'cuechange', function() {
|
1014
|
-
// Display a cue, if there is one
|
1015
|
-
if (this.activeCues[0] && 'text' in this.activeCues[0]) {
|
1016
|
-
_setCaption(this.activeCues[0].getCueAsHTML());
|
1017
|
-
} else {
|
1018
|
-
_setCaption();
|
1019
|
-
}
|
1020
|
-
});
|
1021
|
-
}
|
1022
|
-
}
|
1023
|
-
} else {
|
1024
|
-
// Caption tracks not natively supported
|
1025
|
-
_log('TextTracks not supported so rendering captions manually');
|
1026
|
-
|
1027
|
-
// Render captions from array at appropriate time
|
1028
|
-
plyr.currentCaption = '';
|
1029
|
-
plyr.captions = [];
|
1030
|
-
|
1031
|
-
if (captionSrc !== '') {
|
1032
|
-
// Create XMLHttpRequest Object
|
1033
|
-
var xhr = new XMLHttpRequest();
|
1034
|
-
|
1035
|
-
xhr.onreadystatechange = function() {
|
1036
|
-
if (xhr.readyState === 4) {
|
1037
|
-
if (xhr.status === 200) {
|
1038
|
-
var captions = [],
|
1039
|
-
caption,
|
1040
|
-
req = xhr.responseText;
|
1041
|
-
|
1042
|
-
//According to webvtt spec, line terminator consists of one of the following
|
1043
|
-
// CRLF (U+000D U+000A), LF (U+000A) or CR (U+000D)
|
1044
|
-
var lineSeparator = '\r\n';
|
1045
|
-
if(req.indexOf(lineSeparator+lineSeparator) === -1) {
|
1046
|
-
if(req.indexOf('\r\r') !== -1){
|
1047
|
-
lineSeparator = '\r';
|
1048
|
-
} else {
|
1049
|
-
lineSeparator = '\n';
|
1050
|
-
}
|
1051
|
-
}
|
1052
|
-
|
1053
|
-
captions = req.split(lineSeparator+lineSeparator);
|
1054
|
-
|
1055
|
-
for (var r = 0; r < captions.length; r++) {
|
1056
|
-
caption = captions[r];
|
1057
|
-
plyr.captions[r] = [];
|
1058
|
-
|
1059
|
-
// Get the parts of the captions
|
1060
|
-
var parts = caption.split(lineSeparator),
|
1061
|
-
index = 0;
|
1062
|
-
|
1063
|
-
// Incase caption numbers are added
|
1064
|
-
if (parts[index].indexOf(":") === -1) {
|
1065
|
-
index = 1;
|
1066
|
-
}
|
1067
|
-
|
1068
|
-
plyr.captions[r] = [parts[index], parts[index + 1]];
|
1069
|
-
}
|
1070
|
-
|
1071
|
-
// Remove first element ('VTT')
|
1072
|
-
plyr.captions.shift();
|
1073
|
-
|
1074
|
-
_log('Successfully loaded the caption file via AJAX');
|
1075
|
-
} else {
|
1076
|
-
_warn(config.logPrefix + 'There was a problem loading the caption file via AJAX');
|
1077
|
-
}
|
1078
|
-
}
|
1079
|
-
};
|
1080
|
-
|
1081
|
-
xhr.open('get', captionSrc, true);
|
1082
|
-
|
1083
|
-
xhr.send();
|
1084
|
-
}
|
1085
|
-
}
|
1086
|
-
}
|
1087
|
-
}
|
1088
|
-
|
1089
|
-
// Set the current caption
|
1090
|
-
function _setCaption(caption) {
|
1091
|
-
/* jshint unused:false */
|
1092
|
-
var container = _getElement(config.selectors.captions),
|
1093
|
-
content = document.createElement('span');
|
1094
|
-
|
1095
|
-
// Empty the container
|
1096
|
-
container.innerHTML = '';
|
1097
|
-
|
1098
|
-
// Default to empty
|
1099
|
-
if (_is.undefined(caption)) {
|
1100
|
-
caption = '';
|
1101
|
-
}
|
1102
|
-
|
1103
|
-
// Set the span content
|
1104
|
-
if (_is.string(caption)) {
|
1105
|
-
content.innerHTML = caption.trim();
|
1106
|
-
} else {
|
1107
|
-
content.appendChild(caption);
|
1108
|
-
}
|
1109
|
-
|
1110
|
-
// Set new caption text
|
1111
|
-
container.appendChild(content);
|
1112
|
-
|
1113
|
-
// Force redraw (for Safari)
|
1114
|
-
var redraw = container.offsetHeight;
|
1115
|
-
}
|
1116
|
-
|
1117
|
-
// Captions functions
|
1118
|
-
// Seek the manual caption time and update UI
|
1119
|
-
function _seekManualCaptions(time) {
|
1120
|
-
// Utilities for caption time codes
|
1121
|
-
function _timecodeCommon(tc, pos) {
|
1122
|
-
var tcpair = [];
|
1123
|
-
tcpair = tc.split(' --> ');
|
1124
|
-
for(var i = 0; i < tcpair.length; i++) {
|
1125
|
-
// WebVTT allows for extra meta data after the timestamp line
|
1126
|
-
// So get rid of this if it exists
|
1127
|
-
tcpair[i] = tcpair[i].replace(/(\d+:\d+:\d+\.\d+).*/, "$1");
|
1128
|
-
}
|
1129
|
-
return _subTcSecs(tcpair[pos]);
|
1130
|
-
}
|
1131
|
-
function _timecodeMin(tc) {
|
1132
|
-
return _timecodeCommon(tc, 0);
|
1133
|
-
}
|
1134
|
-
function _timecodeMax(tc) {
|
1135
|
-
return _timecodeCommon(tc, 1);
|
1136
|
-
}
|
1137
|
-
function _subTcSecs(tc) {
|
1138
|
-
if (tc === null || tc === undefined) {
|
1139
|
-
return 0;
|
1140
|
-
} else {
|
1141
|
-
var tc1 = [],
|
1142
|
-
tc2 = [],
|
1143
|
-
seconds;
|
1144
|
-
tc1 = tc.split(',');
|
1145
|
-
tc2 = tc1[0].split(':');
|
1146
|
-
seconds = Math.floor(tc2[0]*60*60) + Math.floor(tc2[1]*60) + Math.floor(tc2[2]);
|
1147
|
-
return seconds;
|
1148
|
-
}
|
1149
|
-
}
|
1150
|
-
|
1151
|
-
// If it's not video, or we're using textTracks, bail.
|
1152
|
-
if (plyr.usingTextTracks || plyr.type !== 'video' || !plyr.supported.full) {
|
1153
|
-
return;
|
1154
|
-
}
|
1155
|
-
|
1156
|
-
// Reset subcount
|
1157
|
-
plyr.subcount = 0;
|
1158
|
-
|
1159
|
-
// Check time is a number, if not use currentTime
|
1160
|
-
// IE has a bug where currentTime doesn't go to 0
|
1161
|
-
// https://twitter.com/Sam_Potts/status/573715746506731521
|
1162
|
-
time = _is.number(time) ? time : plyr.media.currentTime;
|
1163
|
-
|
1164
|
-
// If there's no subs available, bail
|
1165
|
-
if (!plyr.captions[plyr.subcount]) {
|
1166
|
-
return;
|
1167
|
-
}
|
1168
|
-
|
1169
|
-
while (_timecodeMax(plyr.captions[plyr.subcount][0]) < time.toFixed(1)) {
|
1170
|
-
plyr.subcount++;
|
1171
|
-
if (plyr.subcount > plyr.captions.length - 1) {
|
1172
|
-
plyr.subcount = plyr.captions.length - 1;
|
1173
|
-
break;
|
1174
|
-
}
|
1175
|
-
}
|
1176
|
-
|
1177
|
-
// Check if the next caption is in the current time range
|
1178
|
-
if (plyr.media.currentTime.toFixed(1) >= _timecodeMin(plyr.captions[plyr.subcount][0]) &&
|
1179
|
-
plyr.media.currentTime.toFixed(1) <= _timecodeMax(plyr.captions[plyr.subcount][0])) {
|
1180
|
-
plyr.currentCaption = plyr.captions[plyr.subcount][1];
|
1181
|
-
|
1182
|
-
// Render the caption
|
1183
|
-
_setCaption(plyr.currentCaption);
|
1184
|
-
} else {
|
1185
|
-
_setCaption();
|
1186
|
-
}
|
1187
|
-
}
|
1188
|
-
|
1189
|
-
// Display captions container and button (for initialization)
|
1190
|
-
function _showCaptions() {
|
1191
|
-
// If there's no caption toggle, bail
|
1192
|
-
if (!plyr.buttons.captions) {
|
1193
|
-
return;
|
1194
|
-
}
|
1195
|
-
|
1196
|
-
_toggleClass(plyr.container, config.classes.captions.enabled, true);
|
1197
|
-
|
1198
|
-
// Try to load the value from storage
|
1199
|
-
var active = plyr.storage.captionsEnabled;
|
1200
|
-
|
1201
|
-
// Otherwise fall back to the default config
|
1202
|
-
if (!_is.boolean(active)) {
|
1203
|
-
active = config.captions.defaultActive;
|
1204
|
-
}
|
1205
|
-
|
1206
|
-
if (active) {
|
1207
|
-
_toggleClass(plyr.container, config.classes.captions.active, true);
|
1208
|
-
_toggleState(plyr.buttons.captions, true);
|
1209
|
-
}
|
1210
|
-
}
|
1211
|
-
|
1212
|
-
// Find all elements
|
1213
|
-
function _getElements(selector) {
|
1214
|
-
return plyr.container.querySelectorAll(selector);
|
1215
|
-
}
|
1216
|
-
|
1217
|
-
// Find a single element
|
1218
|
-
function _getElement(selector) {
|
1219
|
-
return _getElements(selector)[0];
|
1220
|
-
}
|
1221
|
-
|
1222
|
-
// Determine if we're in an iframe
|
1223
|
-
function _inFrame() {
|
1224
|
-
try {
|
1225
|
-
return window.self !== window.top;
|
1226
|
-
}
|
1227
|
-
catch (e) {
|
1228
|
-
return true;
|
1229
|
-
}
|
1230
|
-
}
|
1231
|
-
|
1232
|
-
// Trap focus inside container
|
1233
|
-
function _focusTrap() {
|
1234
|
-
var tabbables = _getElements('input:not([disabled]), button:not([disabled])'),
|
1235
|
-
first = tabbables[0],
|
1236
|
-
last = tabbables[tabbables.length - 1];
|
1237
|
-
|
1238
|
-
function _checkFocus(event) {
|
1239
|
-
// If it is TAB
|
1240
|
-
if (event.which === 9 && plyr.isFullscreen) {
|
1241
|
-
if (event.target === last && !event.shiftKey) {
|
1242
|
-
// Move focus to first element that can be tabbed if Shift isn't used
|
1243
|
-
event.preventDefault();
|
1244
|
-
first.focus();
|
1245
|
-
} else if (event.target === first && event.shiftKey) {
|
1246
|
-
// Move focus to last element that can be tabbed if Shift is used
|
1247
|
-
event.preventDefault();
|
1248
|
-
last.focus();
|
1249
|
-
}
|
1250
|
-
}
|
1251
|
-
}
|
1252
|
-
|
1253
|
-
// Bind the handler
|
1254
|
-
_on(plyr.container, 'keydown', _checkFocus);
|
1255
|
-
}
|
1256
|
-
|
1257
|
-
// Add elements to HTML5 media (source, tracks, etc)
|
1258
|
-
function _insertChildElements(type, attributes) {
|
1259
|
-
if (_is.string(attributes)) {
|
1260
|
-
_insertElement(type, plyr.media, { src: attributes });
|
1261
|
-
} else if (attributes.constructor === Array) {
|
1262
|
-
for (var i = attributes.length - 1; i >= 0; i--) {
|
1263
|
-
_insertElement(type, plyr.media, attributes[i]);
|
1264
|
-
}
|
1265
|
-
}
|
1266
|
-
}
|
1267
|
-
|
1268
|
-
// Insert controls
|
1269
|
-
function _injectControls() {
|
1270
|
-
// Sprite
|
1271
|
-
if (config.loadSprite) {
|
1272
|
-
var iconUrl = _getIconUrl();
|
1273
|
-
|
1274
|
-
// Only load external sprite using AJAX
|
1275
|
-
if (iconUrl.absolute) {
|
1276
|
-
_log('AJAX loading absolute SVG sprite' + (plyr.browser.isIE ? ' (due to IE)' : ''));
|
1277
|
-
loadSprite(iconUrl.url, "sprite-plyr");
|
1278
|
-
} else {
|
1279
|
-
_log('Sprite will be used as external resource directly');
|
1280
|
-
}
|
1281
|
-
}
|
1282
|
-
|
1283
|
-
// Make a copy of the html
|
1284
|
-
var html = config.html;
|
1285
|
-
|
1286
|
-
// Insert custom video controls
|
1287
|
-
_log('Injecting custom controls');
|
1288
|
-
|
1289
|
-
// If no controls are specified, create default
|
1290
|
-
if (!html) {
|
1291
|
-
html = _buildControls();
|
1292
|
-
}
|
1293
|
-
|
1294
|
-
// Replace seek time instances
|
1295
|
-
html = _replaceAll(html, '{seektime}', config.seekTime);
|
1296
|
-
|
1297
|
-
// Replace all id references with random numbers
|
1298
|
-
html = _replaceAll(html, '{id}', Math.floor(Math.random() * (10000)));
|
1299
|
-
|
1300
|
-
// Controls container
|
1301
|
-
var target;
|
1302
|
-
|
1303
|
-
// Inject to custom location
|
1304
|
-
if (_is.string(config.selectors.controls.container)) {
|
1305
|
-
target = document.querySelector(config.selectors.controls.container);
|
1306
|
-
}
|
1307
|
-
|
1308
|
-
// Inject into the container by default
|
1309
|
-
if (!_is.htmlElement(target)) {
|
1310
|
-
target = plyr.container
|
1311
|
-
}
|
1312
|
-
|
1313
|
-
// Inject controls HTML
|
1314
|
-
target.insertAdjacentHTML('beforeend', html);
|
1315
|
-
|
1316
|
-
// Setup tooltips
|
1317
|
-
if (config.tooltips.controls) {
|
1318
|
-
var labels = _getElements([config.selectors.controls.wrapper, ' ', config.selectors.labels, ' .', config.classes.hidden].join(''));
|
1319
|
-
|
1320
|
-
for (var i = labels.length - 1; i >= 0; i--) {
|
1321
|
-
var label = labels[i];
|
1322
|
-
|
1323
|
-
_toggleClass(label, config.classes.hidden, false);
|
1324
|
-
_toggleClass(label, config.classes.tooltip, true);
|
1325
|
-
}
|
1326
|
-
}
|
1327
|
-
}
|
1328
|
-
|
1329
|
-
// Find the UI controls and store references
|
1330
|
-
function _findElements() {
|
1331
|
-
try {
|
1332
|
-
plyr.controls = _getElement(config.selectors.controls.wrapper);
|
1333
|
-
|
1334
|
-
// Buttons
|
1335
|
-
plyr.buttons = {};
|
1336
|
-
plyr.buttons.seek = _getElement(config.selectors.buttons.seek);
|
1337
|
-
plyr.buttons.play = _getElements(config.selectors.buttons.play);
|
1338
|
-
plyr.buttons.pause = _getElement(config.selectors.buttons.pause);
|
1339
|
-
plyr.buttons.restart = _getElement(config.selectors.buttons.restart);
|
1340
|
-
plyr.buttons.rewind = _getElement(config.selectors.buttons.rewind);
|
1341
|
-
plyr.buttons.forward = _getElement(config.selectors.buttons.forward);
|
1342
|
-
plyr.buttons.fullscreen = _getElement(config.selectors.buttons.fullscreen);
|
1343
|
-
|
1344
|
-
// Inputs
|
1345
|
-
plyr.buttons.mute = _getElement(config.selectors.buttons.mute);
|
1346
|
-
plyr.buttons.captions = _getElement(config.selectors.buttons.captions);
|
1347
|
-
|
1348
|
-
// Progress
|
1349
|
-
plyr.progress = {};
|
1350
|
-
plyr.progress.container = _getElement(config.selectors.progress.container);
|
1351
|
-
|
1352
|
-
// Progress - Buffering
|
1353
|
-
plyr.progress.buffer = {};
|
1354
|
-
plyr.progress.buffer.bar = _getElement(config.selectors.progress.buffer);
|
1355
|
-
plyr.progress.buffer.text = plyr.progress.buffer.bar && plyr.progress.buffer.bar.getElementsByTagName('span')[0];
|
1356
|
-
|
1357
|
-
// Progress - Played
|
1358
|
-
plyr.progress.played = _getElement(config.selectors.progress.played);
|
1359
|
-
|
1360
|
-
// Seek tooltip
|
1361
|
-
plyr.progress.tooltip = plyr.progress.container && plyr.progress.container.querySelector('.' + config.classes.tooltip);
|
1362
|
-
|
1363
|
-
// Volume
|
1364
|
-
plyr.volume = {};
|
1365
|
-
plyr.volume.input = _getElement(config.selectors.volume.input);
|
1366
|
-
plyr.volume.display = _getElement(config.selectors.volume.display);
|
1367
|
-
|
1368
|
-
// Timing
|
1369
|
-
plyr.duration = _getElement(config.selectors.duration);
|
1370
|
-
plyr.currentTime = _getElement(config.selectors.currentTime);
|
1371
|
-
plyr.seekTime = _getElements(config.selectors.seekTime);
|
1372
|
-
|
1373
|
-
return true;
|
1374
|
-
}
|
1375
|
-
catch(e) {
|
1376
|
-
_warn('It looks like there is a problem with your controls HTML');
|
1377
|
-
|
1378
|
-
// Restore native video controls
|
1379
|
-
_toggleNativeControls(true);
|
1380
|
-
|
1381
|
-
return false;
|
1382
|
-
}
|
1383
|
-
}
|
1384
|
-
|
1385
|
-
// Toggle style hook
|
1386
|
-
function _toggleStyleHook() {
|
1387
|
-
_toggleClass(plyr.container, config.selectors.container.replace('.', ''), plyr.supported.full);
|
1388
|
-
}
|
1389
|
-
|
1390
|
-
// Toggle native controls
|
1391
|
-
function _toggleNativeControls(toggle) {
|
1392
|
-
if (toggle && _inArray(config.types.html5, plyr.type)) {
|
1393
|
-
plyr.media.setAttribute('controls', '');
|
1394
|
-
} else {
|
1395
|
-
plyr.media.removeAttribute('controls');
|
1396
|
-
}
|
1397
|
-
}
|
1398
|
-
|
1399
|
-
// Setup aria attribute for play and iframe title
|
1400
|
-
function _setTitle(iframe) {
|
1401
|
-
// Find the current text
|
1402
|
-
var label = config.i18n.play;
|
1403
|
-
|
1404
|
-
// If there's a media title set, use that for the label
|
1405
|
-
if (_is.string(config.title) && config.title.length) {
|
1406
|
-
label += ', ' + config.title;
|
1407
|
-
|
1408
|
-
// Set container label
|
1409
|
-
plyr.container.setAttribute('aria-label', config.title);
|
1410
|
-
}
|
1411
|
-
|
1412
|
-
// If there's a play button, set label
|
1413
|
-
if (plyr.supported.full && plyr.buttons.play) {
|
1414
|
-
for (var i = plyr.buttons.play.length - 1; i >= 0; i--) {
|
1415
|
-
plyr.buttons.play[i].setAttribute('aria-label', label);
|
1416
|
-
}
|
1417
|
-
}
|
1418
|
-
|
1419
|
-
// Set iframe title
|
1420
|
-
// https://github.com/Selz/plyr/issues/124
|
1421
|
-
if (_is.htmlElement(iframe)) {
|
1422
|
-
iframe.setAttribute('title', config.i18n.frameTitle.replace('{title}', config.title));
|
1423
|
-
}
|
1424
|
-
}
|
1425
|
-
|
1426
|
-
// Setup localStorage
|
1427
|
-
function _setupStorage() {
|
1428
|
-
var value = null;
|
1429
|
-
plyr.storage = {};
|
1430
|
-
|
1431
|
-
// Bail if we don't have localStorage support or it's disabled
|
1432
|
-
if (!_storage.supported || !config.storage.enabled) {
|
1433
|
-
return;
|
1434
|
-
}
|
1435
|
-
|
1436
|
-
// Clean up old volume
|
1437
|
-
// https://github.com/Selz/plyr/issues/171
|
1438
|
-
window.localStorage.removeItem('plyr-volume');
|
1439
|
-
|
1440
|
-
// load value from the current key
|
1441
|
-
value = window.localStorage.getItem(config.storage.key);
|
1442
|
-
|
1443
|
-
if (!value) {
|
1444
|
-
// Key wasn't set (or had been cleared), move along
|
1445
|
-
return;
|
1446
|
-
} else if (/^\d+(\.\d+)?$/.test(value)) {
|
1447
|
-
// If value is a number, it's probably volume from an older
|
1448
|
-
// version of plyr. See: https://github.com/Selz/plyr/pull/313
|
1449
|
-
// Update the key to be JSON
|
1450
|
-
_updateStorage({volume: parseFloat(value)});
|
1451
|
-
} else {
|
1452
|
-
// Assume it's JSON from this or a later version of plyr
|
1453
|
-
plyr.storage = JSON.parse(value);
|
1454
|
-
}
|
1455
|
-
}
|
1456
|
-
|
1457
|
-
// Save a value back to local storage
|
1458
|
-
function _updateStorage(value) {
|
1459
|
-
// Bail if we don't have localStorage support or it's disabled
|
1460
|
-
if (!_storage.supported || !config.storage.enabled) {
|
1461
|
-
return;
|
1462
|
-
}
|
1463
|
-
|
1464
|
-
// Update the working copy of the values
|
1465
|
-
_extend(plyr.storage, value);
|
1466
|
-
|
1467
|
-
// Update storage
|
1468
|
-
window.localStorage.setItem(config.storage.key, JSON.stringify(plyr.storage));
|
1469
|
-
}
|
1470
|
-
|
1471
|
-
// Setup media
|
1472
|
-
function _setupMedia() {
|
1473
|
-
// If there's no media, bail
|
1474
|
-
if (!plyr.media) {
|
1475
|
-
_warn('No media element found!');
|
1476
|
-
return;
|
1477
|
-
}
|
1478
|
-
|
1479
|
-
if (plyr.supported.full) {
|
1480
|
-
// Add type class
|
1481
|
-
_toggleClass(plyr.container, config.classes.type.replace('{0}', plyr.type), true);
|
1482
|
-
|
1483
|
-
// Add video class for embeds
|
1484
|
-
// This will require changes if audio embeds are added
|
1485
|
-
if (_inArray(config.types.embed, plyr.type)) {
|
1486
|
-
_toggleClass(plyr.container, config.classes.type.replace('{0}', 'video'), true);
|
1487
|
-
}
|
1488
|
-
|
1489
|
-
// If there's no autoplay attribute, assume the video is stopped and add state class
|
1490
|
-
_toggleClass(plyr.container, config.classes.stopped, config.autoplay);
|
1491
|
-
|
1492
|
-
// Add iOS class
|
1493
|
-
_toggleClass(plyr.ontainer, config.classes.isIos, plyr.browser.isIos);
|
1494
|
-
|
1495
|
-
// Add touch class
|
1496
|
-
_toggleClass(plyr.container, config.classes.isTouch, plyr.browser.isTouch);
|
1497
|
-
|
1498
|
-
// Inject the player wrapper
|
1499
|
-
if (plyr.type === 'video') {
|
1500
|
-
// Create the wrapper div
|
1501
|
-
var wrapper = document.createElement('div');
|
1502
|
-
wrapper.setAttribute('class', config.classes.videoWrapper);
|
1503
|
-
|
1504
|
-
// Wrap the video in a container
|
1505
|
-
_wrap(plyr.media, wrapper);
|
1506
|
-
|
1507
|
-
// Cache the container
|
1508
|
-
plyr.videoContainer = wrapper;
|
1509
|
-
}
|
1510
|
-
}
|
1511
|
-
|
1512
|
-
// Embeds
|
1513
|
-
if (_inArray(config.types.embed, plyr.type)) {
|
1514
|
-
_setupEmbed();
|
1515
|
-
}
|
1516
|
-
}
|
1517
|
-
|
1518
|
-
// Setup YouTube/Vimeo
|
1519
|
-
function _setupEmbed() {
|
1520
|
-
var container = document.createElement('div'),
|
1521
|
-
mediaId,
|
1522
|
-
id = plyr.type + '-' + Math.floor(Math.random() * (10000));
|
1523
|
-
|
1524
|
-
// Parse IDs from URLs if supplied
|
1525
|
-
switch (plyr.type) {
|
1526
|
-
case 'youtube':
|
1527
|
-
mediaId = _parseYouTubeId(plyr.embedId);
|
1528
|
-
break;
|
1529
|
-
|
1530
|
-
case 'vimeo':
|
1531
|
-
mediaId = _parseVimeoId(plyr.embedId);
|
1532
|
-
break;
|
1533
|
-
|
1534
|
-
default:
|
1535
|
-
mediaId = plyr.embedId;
|
1536
|
-
}
|
1537
|
-
|
1538
|
-
// Remove old containers
|
1539
|
-
var containers = _getElements('[id^="' + plyr.type + '-"]');
|
1540
|
-
for (var i = containers.length - 1; i >= 0; i--) {
|
1541
|
-
_remove(containers[i]);
|
1542
|
-
}
|
1543
|
-
|
1544
|
-
// Add embed class for responsive
|
1545
|
-
_toggleClass(plyr.media, config.classes.videoWrapper, true);
|
1546
|
-
_toggleClass(plyr.media, config.classes.embedWrapper, true);
|
1547
|
-
|
1548
|
-
if (plyr.type === 'youtube') {
|
1549
|
-
// Create the YouTube container
|
1550
|
-
plyr.media.appendChild(container);
|
1551
|
-
|
1552
|
-
// Set ID
|
1553
|
-
container.setAttribute('id', id);
|
1554
|
-
|
1555
|
-
// Setup API
|
1556
|
-
if (_is.object(window.YT)) {
|
1557
|
-
_youTubeReady(mediaId, container);
|
1558
|
-
} else {
|
1559
|
-
// Load the API
|
1560
|
-
_injectScript(config.urls.youtube.api);
|
1561
|
-
|
1562
|
-
// Setup callback for the API
|
1563
|
-
window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];
|
1564
|
-
|
1565
|
-
// Add to queue
|
1566
|
-
window.onYouTubeReadyCallbacks.push(function() { _youTubeReady(mediaId, container); });
|
1567
|
-
|
1568
|
-
// Set callback to process queue
|
1569
|
-
window.onYouTubeIframeAPIReady = function () {
|
1570
|
-
window.onYouTubeReadyCallbacks.forEach(function(callback) { callback(); });
|
1571
|
-
};
|
1572
|
-
}
|
1573
|
-
} else if (plyr.type === 'vimeo') {
|
1574
|
-
// Vimeo needs an extra div to hide controls on desktop (which has full support)
|
1575
|
-
if (plyr.supported.full) {
|
1576
|
-
plyr.media.appendChild(container);
|
1577
|
-
} else {
|
1578
|
-
container = plyr.media;
|
1579
|
-
}
|
1580
|
-
|
1581
|
-
// Set ID
|
1582
|
-
container.setAttribute('id', id);
|
1583
|
-
|
1584
|
-
// Load the API if not already
|
1585
|
-
if (!_is.object(window.Vimeo)) {
|
1586
|
-
_injectScript(config.urls.vimeo.api);
|
1587
|
-
|
1588
|
-
// Wait for fragaloop load
|
1589
|
-
var vimeoTimer = window.setInterval(function() {
|
1590
|
-
if (_is.object(window.Vimeo)) {
|
1591
|
-
window.clearInterval(vimeoTimer);
|
1592
|
-
_vimeoReady(mediaId, container);
|
1593
|
-
}
|
1594
|
-
}, 50);
|
1595
|
-
} else {
|
1596
|
-
_vimeoReady(mediaId, container);
|
1597
|
-
}
|
1598
|
-
} else if (plyr.type === 'soundcloud') {
|
1599
|
-
// TODO: Currently unsupported and undocumented
|
1600
|
-
// Inject the iframe
|
1601
|
-
var soundCloud = document.createElement('iframe');
|
1602
|
-
|
1603
|
-
// Watch for iframe load
|
1604
|
-
soundCloud.loaded = false;
|
1605
|
-
_on(soundCloud, 'load', function() { soundCloud.loaded = true; });
|
1606
|
-
|
1607
|
-
_setAttributes(soundCloud, {
|
1608
|
-
'src': 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/' + mediaId,
|
1609
|
-
'id': id
|
1610
|
-
});
|
1611
|
-
|
1612
|
-
container.appendChild(soundCloud);
|
1613
|
-
plyr.media.appendChild(container);
|
1614
|
-
|
1615
|
-
// Load the API if not already
|
1616
|
-
if (!window.SC) {
|
1617
|
-
_injectScript(config.urls.soundcloud.api);
|
1618
|
-
}
|
1619
|
-
|
1620
|
-
// Wait for SC load
|
1621
|
-
var soundCloudTimer = window.setInterval(function() {
|
1622
|
-
if (window.SC && soundCloud.loaded) {
|
1623
|
-
window.clearInterval(soundCloudTimer);
|
1624
|
-
_soundcloudReady.call(soundCloud);
|
1625
|
-
}
|
1626
|
-
}, 50);
|
1627
|
-
}
|
1628
|
-
}
|
1629
|
-
|
1630
|
-
// When embeds are ready
|
1631
|
-
function _embedReady() {
|
1632
|
-
// Setup the UI and call ready if full support
|
1633
|
-
if (plyr.supported.full) {
|
1634
|
-
_setupInterface();
|
1635
|
-
_ready();
|
1636
|
-
}
|
1637
|
-
|
1638
|
-
// Set title
|
1639
|
-
_setTitle(_getElement('iframe'));
|
1640
|
-
}
|
1641
|
-
|
1642
|
-
// Handle YouTube API ready
|
1643
|
-
function _youTubeReady(videoId, container) {
|
1644
|
-
// Setup instance
|
1645
|
-
// https://developers.google.com/youtube/iframe_api_reference
|
1646
|
-
plyr.embed = new window.YT.Player(container.id, {
|
1647
|
-
videoId: videoId,
|
1648
|
-
playerVars: {
|
1649
|
-
autoplay: (config.autoplay ? 1 : 0),
|
1650
|
-
controls: (plyr.supported.full ? 0 : 1),
|
1651
|
-
rel: 0,
|
1652
|
-
showinfo: 0,
|
1653
|
-
iv_load_policy: 3,
|
1654
|
-
cc_load_policy: (config.captions.defaultActive ? 1 : 0),
|
1655
|
-
cc_lang_pref: 'en',
|
1656
|
-
wmode: 'transparent',
|
1657
|
-
modestbranding: 1,
|
1658
|
-
disablekb: 1,
|
1659
|
-
origin: '*' // https://code.google.com/p/gdata-issues/issues/detail?id=5788#c45
|
1660
|
-
},
|
1661
|
-
events: {
|
1662
|
-
'onError': function(event) {
|
1663
|
-
_triggerEvent(plyr.container, 'error', true, {
|
1664
|
-
code: event.data,
|
1665
|
-
embed: event.target
|
1666
|
-
});
|
1667
|
-
},
|
1668
|
-
'onReady': function(event) {
|
1669
|
-
// Get the instance
|
1670
|
-
var instance = event.target;
|
1671
|
-
|
1672
|
-
// Create a faux HTML5 API using the YouTube API
|
1673
|
-
plyr.media.play = function() {
|
1674
|
-
instance.playVideo();
|
1675
|
-
plyr.media.paused = false;
|
1676
|
-
};
|
1677
|
-
plyr.media.pause = function() {
|
1678
|
-
instance.pauseVideo();
|
1679
|
-
plyr.media.paused = true;
|
1680
|
-
};
|
1681
|
-
plyr.media.stop = function() {
|
1682
|
-
instance.stopVideo();
|
1683
|
-
plyr.media.paused = true;
|
1684
|
-
};
|
1685
|
-
plyr.media.duration = instance.getDuration();
|
1686
|
-
plyr.media.paused = true;
|
1687
|
-
plyr.media.currentTime = 0;
|
1688
|
-
plyr.media.muted = instance.isMuted();
|
1689
|
-
|
1690
|
-
// Set title
|
1691
|
-
config.title = instance.getVideoData().title;
|
1692
|
-
|
1693
|
-
// Set the tabindex
|
1694
|
-
if (plyr.supported.full) {
|
1695
|
-
plyr.media.querySelector('iframe').setAttribute('tabindex', '-1');
|
1696
|
-
}
|
1697
|
-
|
1698
|
-
// Update UI
|
1699
|
-
_embedReady();
|
1700
|
-
|
1701
|
-
// Trigger timeupdate
|
1702
|
-
_triggerEvent(plyr.media, 'timeupdate');
|
1703
|
-
|
1704
|
-
// Trigger timeupdate
|
1705
|
-
_triggerEvent(plyr.media, 'durationchange');
|
1706
|
-
|
1707
|
-
// Reset timer
|
1708
|
-
window.clearInterval(timers.buffering);
|
1709
|
-
|
1710
|
-
// Setup buffering
|
1711
|
-
timers.buffering = window.setInterval(function() {
|
1712
|
-
// Get loaded % from YouTube
|
1713
|
-
plyr.media.buffered = instance.getVideoLoadedFraction();
|
1714
|
-
|
1715
|
-
// Trigger progress only when we actually buffer something
|
1716
|
-
if (plyr.media.lastBuffered === null || plyr.media.lastBuffered < plyr.media.buffered) {
|
1717
|
-
_triggerEvent(plyr.media, 'progress');
|
1718
|
-
}
|
1719
|
-
|
1720
|
-
// Set last buffer point
|
1721
|
-
plyr.media.lastBuffered = plyr.media.buffered;
|
1722
|
-
|
1723
|
-
// Bail if we're at 100%
|
1724
|
-
if (plyr.media.buffered === 1) {
|
1725
|
-
window.clearInterval(timers.buffering);
|
1726
|
-
|
1727
|
-
// Trigger event
|
1728
|
-
_triggerEvent(plyr.media, 'canplaythrough');
|
1729
|
-
}
|
1730
|
-
}, 200);
|
1731
|
-
},
|
1732
|
-
'onStateChange': function(event) {
|
1733
|
-
// Get the instance
|
1734
|
-
var instance = event.target;
|
1735
|
-
|
1736
|
-
// Reset timer
|
1737
|
-
window.clearInterval(timers.playing);
|
1738
|
-
|
1739
|
-
// Handle events
|
1740
|
-
// -1 Unstarted
|
1741
|
-
// 0 Ended
|
1742
|
-
// 1 Playing
|
1743
|
-
// 2 Paused
|
1744
|
-
// 3 Buffering
|
1745
|
-
// 5 Video cued
|
1746
|
-
switch (event.data) {
|
1747
|
-
case 0:
|
1748
|
-
plyr.media.paused = true;
|
1749
|
-
_triggerEvent(plyr.media, 'ended');
|
1750
|
-
break;
|
1751
|
-
|
1752
|
-
case 1:
|
1753
|
-
plyr.media.paused = false;
|
1754
|
-
|
1755
|
-
// If we were seeking, fire seeked event
|
1756
|
-
if (plyr.media.seeking) {
|
1757
|
-
_triggerEvent(plyr.media, 'seeked');
|
1758
|
-
}
|
1759
|
-
|
1760
|
-
plyr.media.seeking = false;
|
1761
|
-
_triggerEvent(plyr.media, 'play');
|
1762
|
-
_triggerEvent(plyr.media, 'playing');
|
1763
|
-
|
1764
|
-
// Poll to get playback progress
|
1765
|
-
timers.playing = window.setInterval(function() {
|
1766
|
-
// Set the current time
|
1767
|
-
plyr.media.currentTime = instance.getCurrentTime();
|
1768
|
-
|
1769
|
-
// Trigger timeupdate
|
1770
|
-
_triggerEvent(plyr.media, 'timeupdate');
|
1771
|
-
}, 100);
|
1772
|
-
|
1773
|
-
// Check duration again due to YouTube bug
|
1774
|
-
// https://github.com/Selz/plyr/issues/374
|
1775
|
-
// https://code.google.com/p/gdata-issues/issues/detail?id=8690
|
1776
|
-
if (plyr.media.duration !== instance.getDuration()) {
|
1777
|
-
plyr.media.duration = instance.getDuration();
|
1778
|
-
_triggerEvent(plyr.media, 'durationchange');
|
1779
|
-
}
|
1780
|
-
|
1781
|
-
break;
|
1782
|
-
|
1783
|
-
case 2:
|
1784
|
-
plyr.media.paused = true;
|
1785
|
-
_triggerEvent(plyr.media, 'pause');
|
1786
|
-
break;
|
1787
|
-
}
|
1788
|
-
|
1789
|
-
_triggerEvent(plyr.container, 'statechange', false, {
|
1790
|
-
code: event.data
|
1791
|
-
});
|
1792
|
-
}
|
1793
|
-
}
|
1794
|
-
});
|
1795
|
-
}
|
1796
|
-
|
1797
|
-
// Vimeo ready
|
1798
|
-
function _vimeoReady(mediaId, container) {
|
1799
|
-
// Setup instance
|
1800
|
-
// https://github.com/vimeo/player.js
|
1801
|
-
plyr.embed = new window.Vimeo.Player(container, {
|
1802
|
-
id: parseInt(mediaId),
|
1803
|
-
loop: config.loop,
|
1804
|
-
autoplay: config.autoplay,
|
1805
|
-
byline: false,
|
1806
|
-
portrait: false,
|
1807
|
-
title: false
|
1808
|
-
});
|
1809
|
-
|
1810
|
-
// Create a faux HTML5 API using the Vimeo API
|
1811
|
-
plyr.media.play = function() {
|
1812
|
-
plyr.embed.play();
|
1813
|
-
plyr.media.paused = false;
|
1814
|
-
};
|
1815
|
-
plyr.media.pause = function() {
|
1816
|
-
plyr.embed.pause();
|
1817
|
-
plyr.media.paused = true;
|
1818
|
-
};
|
1819
|
-
plyr.media.stop = function() {
|
1820
|
-
plyr.embed.stop();
|
1821
|
-
plyr.media.paused = true;
|
1822
|
-
};
|
1823
|
-
|
1824
|
-
plyr.media.paused = true;
|
1825
|
-
plyr.media.currentTime = 0;
|
1826
|
-
|
1827
|
-
// Update UI
|
1828
|
-
_embedReady();
|
1829
|
-
|
1830
|
-
plyr.embed.getCurrentTime().then(function(value) {
|
1831
|
-
plyr.media.currentTime = value;
|
1832
|
-
|
1833
|
-
// Trigger timeupdate
|
1834
|
-
_triggerEvent(plyr.media, 'timeupdate');
|
1835
|
-
});
|
1836
|
-
|
1837
|
-
plyr.embed.getDuration().then(function(value) {
|
1838
|
-
plyr.media.duration = value;
|
1839
|
-
|
1840
|
-
// Trigger timeupdate
|
1841
|
-
_triggerEvent(plyr.media, 'durationchange');
|
1842
|
-
});
|
1843
|
-
|
1844
|
-
// TODO: Captions
|
1845
|
-
/*if (config.captions.defaultActive) {
|
1846
|
-
plyr.embed.enableTextTrack('en');
|
1847
|
-
}*/
|
1848
|
-
|
1849
|
-
plyr.embed.on('loaded', function() {
|
1850
|
-
// Fix keyboard focus issues
|
1851
|
-
// https://github.com/Selz/plyr/issues/317
|
1852
|
-
if (_is.htmlElement(plyr.embed.element) && plyr.supported.full) {
|
1853
|
-
plyr.embed.element.setAttribute('tabindex', '-1');
|
1854
|
-
}
|
1855
|
-
});
|
1856
|
-
|
1857
|
-
plyr.embed.on('play', function() {
|
1858
|
-
plyr.media.paused = false;
|
1859
|
-
_triggerEvent(plyr.media, 'play');
|
1860
|
-
_triggerEvent(plyr.media, 'playing');
|
1861
|
-
});
|
1862
|
-
|
1863
|
-
plyr.embed.on('pause', function() {
|
1864
|
-
plyr.media.paused = true;
|
1865
|
-
_triggerEvent(plyr.media, 'pause');
|
1866
|
-
});
|
1867
|
-
|
1868
|
-
plyr.embed.on('timeupdate', function(data) {
|
1869
|
-
plyr.media.seeking = false;
|
1870
|
-
plyr.media.currentTime = data.seconds;
|
1871
|
-
_triggerEvent(plyr.media, 'timeupdate');
|
1872
|
-
});
|
1873
|
-
|
1874
|
-
plyr.embed.on('progress', function(data) {
|
1875
|
-
plyr.media.buffered = data.percent;
|
1876
|
-
_triggerEvent(plyr.media, 'progress');
|
1877
|
-
|
1878
|
-
if (parseInt(data.percent) === 1) {
|
1879
|
-
// Trigger event
|
1880
|
-
_triggerEvent(plyr.media, 'canplaythrough');
|
1881
|
-
}
|
1882
|
-
});
|
1883
|
-
|
1884
|
-
plyr.embed.on('seeked', function() {
|
1885
|
-
plyr.media.seeking = false;
|
1886
|
-
_triggerEvent(plyr.media, 'seeked');
|
1887
|
-
_triggerEvent(plyr.media, 'play');
|
1888
|
-
});
|
1889
|
-
|
1890
|
-
plyr.embed.on('ended', function() {
|
1891
|
-
plyr.media.paused = true;
|
1892
|
-
_triggerEvent(plyr.media, 'ended');
|
1893
|
-
});
|
1894
|
-
}
|
1895
|
-
|
1896
|
-
// Soundcloud ready
|
1897
|
-
function _soundcloudReady() {
|
1898
|
-
/* jshint validthis: true */
|
1899
|
-
plyr.embed = window.SC.Widget(this);
|
1900
|
-
|
1901
|
-
// Setup on ready
|
1902
|
-
plyr.embed.bind(window.SC.Widget.Events.READY, function() {
|
1903
|
-
// Create a faux HTML5 API using the Soundcloud API
|
1904
|
-
plyr.media.play = function() {
|
1905
|
-
plyr.embed.play();
|
1906
|
-
plyr.media.paused = false;
|
1907
|
-
};
|
1908
|
-
plyr.media.pause = function() {
|
1909
|
-
plyr.embed.pause();
|
1910
|
-
plyr.media.paused = true;
|
1911
|
-
};
|
1912
|
-
plyr.media.stop = function() {
|
1913
|
-
plyr.embed.seekTo(0);
|
1914
|
-
plyr.embed.pause();
|
1915
|
-
plyr.media.paused = true;
|
1916
|
-
};
|
1917
|
-
|
1918
|
-
plyr.media.paused = true;
|
1919
|
-
plyr.media.currentTime = 0;
|
1920
|
-
|
1921
|
-
plyr.embed.getDuration(function(value) {
|
1922
|
-
plyr.media.duration = value/1000;
|
1923
|
-
|
1924
|
-
// Update UI
|
1925
|
-
_embedReady();
|
1926
|
-
});
|
1927
|
-
|
1928
|
-
plyr.embed.getPosition(function(value) {
|
1929
|
-
plyr.media.currentTime = value;
|
1930
|
-
|
1931
|
-
// Trigger timeupdate
|
1932
|
-
_triggerEvent(plyr.media, 'timeupdate');
|
1933
|
-
});
|
1934
|
-
|
1935
|
-
plyr.embed.bind(window.SC.Widget.Events.PLAY, function() {
|
1936
|
-
plyr.media.paused = false;
|
1937
|
-
_triggerEvent(plyr.media, 'play');
|
1938
|
-
_triggerEvent(plyr.media, 'playing');
|
1939
|
-
});
|
1940
|
-
|
1941
|
-
plyr.embed.bind(window.SC.Widget.Events.PAUSE, function() {
|
1942
|
-
plyr.media.paused = true;
|
1943
|
-
_triggerEvent(plyr.media, 'pause');
|
1944
|
-
});
|
1945
|
-
|
1946
|
-
plyr.embed.bind(window.SC.Widget.Events.PLAY_PROGRESS, function(data) {
|
1947
|
-
plyr.media.seeking = false;
|
1948
|
-
plyr.media.currentTime = data.currentPosition/1000;
|
1949
|
-
_triggerEvent(plyr.media, 'timeupdate');
|
1950
|
-
});
|
1951
|
-
|
1952
|
-
plyr.embed.bind(window.SC.Widget.Events.LOAD_PROGRESS, function(data) {
|
1953
|
-
plyr.media.buffered = data.loadProgress;
|
1954
|
-
_triggerEvent(plyr.media, 'progress');
|
1955
|
-
|
1956
|
-
if (parseInt(data.loadProgress) === 1) {
|
1957
|
-
// Trigger event
|
1958
|
-
_triggerEvent(plyr.media, 'canplaythrough');
|
1959
|
-
}
|
1960
|
-
});
|
1961
|
-
|
1962
|
-
plyr.embed.bind(window.SC.Widget.Events.FINISH, function() {
|
1963
|
-
plyr.media.paused = true;
|
1964
|
-
_triggerEvent(plyr.media, 'ended');
|
1965
|
-
});
|
1966
|
-
});
|
1967
|
-
}
|
1968
|
-
|
1969
|
-
// Play media
|
1970
|
-
function _play() {
|
1971
|
-
if ('play' in plyr.media) {
|
1972
|
-
plyr.media.play();
|
1973
|
-
}
|
1974
|
-
}
|
1975
|
-
|
1976
|
-
// Pause media
|
1977
|
-
function _pause() {
|
1978
|
-
if ('pause' in plyr.media) {
|
1979
|
-
plyr.media.pause();
|
1980
|
-
}
|
1981
|
-
}
|
1982
|
-
|
1983
|
-
// Toggle playback
|
1984
|
-
function _togglePlay(toggle) {
|
1985
|
-
// True toggle
|
1986
|
-
if (!_is.boolean(toggle)) {
|
1987
|
-
toggle = plyr.media.paused;
|
1988
|
-
}
|
1989
|
-
|
1990
|
-
if (toggle) {
|
1991
|
-
_play();
|
1992
|
-
} else {
|
1993
|
-
_pause();
|
1994
|
-
}
|
1995
|
-
|
1996
|
-
return toggle;
|
1997
|
-
}
|
1998
|
-
|
1999
|
-
// Rewind
|
2000
|
-
function _rewind(seekTime) {
|
2001
|
-
// Use default if needed
|
2002
|
-
if (!_is.number(seekTime)) {
|
2003
|
-
seekTime = config.seekTime;
|
2004
|
-
}
|
2005
|
-
_seek(plyr.media.currentTime - seekTime);
|
2006
|
-
}
|
2007
|
-
|
2008
|
-
// Fast forward
|
2009
|
-
function _forward(seekTime) {
|
2010
|
-
// Use default if needed
|
2011
|
-
if (!_is.number(seekTime)) {
|
2012
|
-
seekTime = config.seekTime;
|
2013
|
-
}
|
2014
|
-
_seek(plyr.media.currentTime + seekTime);
|
2015
|
-
}
|
2016
|
-
|
2017
|
-
// Seek to time
|
2018
|
-
// The input parameter can be an event or a number
|
2019
|
-
function _seek(input) {
|
2020
|
-
var targetTime = 0,
|
2021
|
-
paused = plyr.media.paused,
|
2022
|
-
duration = _getDuration();
|
2023
|
-
|
2024
|
-
if (_is.number(input)) {
|
2025
|
-
targetTime = input;
|
2026
|
-
} else if (_is.object(input) && _inArray(['input', 'change'], input.type)) {
|
2027
|
-
// It's the seek slider
|
2028
|
-
// Seek to the selected time
|
2029
|
-
targetTime = ((input.target.value / input.target.max) * duration);
|
2030
|
-
}
|
2031
|
-
|
2032
|
-
// Normalise targetTime
|
2033
|
-
if (targetTime < 0) {
|
2034
|
-
targetTime = 0;
|
2035
|
-
} else if (targetTime > duration) {
|
2036
|
-
targetTime = duration;
|
2037
|
-
}
|
2038
|
-
|
2039
|
-
// Update seek range and progress
|
2040
|
-
_updateSeekDisplay(targetTime);
|
2041
|
-
|
2042
|
-
// Set the current time
|
2043
|
-
// Try/catch incase the media isn't set and we're calling seek() from source() and IE moans
|
2044
|
-
try {
|
2045
|
-
plyr.media.currentTime = targetTime.toFixed(4);
|
2046
|
-
}
|
2047
|
-
catch(e) {}
|
2048
|
-
|
2049
|
-
// Embeds
|
2050
|
-
if (_inArray(config.types.embed, plyr.type)) {
|
2051
|
-
switch(plyr.type) {
|
2052
|
-
case 'youtube':
|
2053
|
-
plyr.embed.seekTo(targetTime);
|
2054
|
-
break;
|
2055
|
-
|
2056
|
-
case 'vimeo':
|
2057
|
-
// Round to nearest second for vimeo
|
2058
|
-
plyr.embed.setCurrentTime(targetTime.toFixed(0));
|
2059
|
-
break;
|
2060
|
-
|
2061
|
-
case 'soundcloud':
|
2062
|
-
plyr.embed.seekTo(targetTime * 1000);
|
2063
|
-
break;
|
2064
|
-
}
|
2065
|
-
|
2066
|
-
if (paused) {
|
2067
|
-
_pause();
|
2068
|
-
}
|
2069
|
-
|
2070
|
-
// Trigger timeupdate
|
2071
|
-
_triggerEvent(plyr.media, 'timeupdate');
|
2072
|
-
|
2073
|
-
// Set seeking flag
|
2074
|
-
plyr.media.seeking = true;
|
2075
|
-
|
2076
|
-
// Trigger seeking
|
2077
|
-
_triggerEvent(plyr.media, 'seeking');
|
2078
|
-
}
|
2079
|
-
|
2080
|
-
// Logging
|
2081
|
-
_log('Seeking to ' + plyr.media.currentTime + ' seconds');
|
2082
|
-
|
2083
|
-
// Special handling for 'manual' captions
|
2084
|
-
_seekManualCaptions(targetTime);
|
2085
|
-
}
|
2086
|
-
|
2087
|
-
// Get the duration (or custom if set)
|
2088
|
-
function _getDuration() {
|
2089
|
-
// It should be a number, but parse it just incase
|
2090
|
-
var duration = parseInt(config.duration),
|
2091
|
-
|
2092
|
-
// True duration
|
2093
|
-
mediaDuration = 0;
|
2094
|
-
|
2095
|
-
// Only if duration available
|
2096
|
-
if (plyr.media.duration !== null && !isNaN(plyr.media.duration)) {
|
2097
|
-
mediaDuration = plyr.media.duration;
|
2098
|
-
}
|
2099
|
-
|
2100
|
-
// If custom duration is funky, use regular duration
|
2101
|
-
return (isNaN(duration) ? mediaDuration : duration);
|
2102
|
-
}
|
2103
|
-
|
2104
|
-
// Check playing state
|
2105
|
-
function _checkPlaying() {
|
2106
|
-
_toggleClass(plyr.container, config.classes.playing, !plyr.media.paused);
|
2107
|
-
|
2108
|
-
_toggleClass(plyr.container, config.classes.stopped, plyr.media.paused);
|
2109
|
-
|
2110
|
-
_toggleControls(plyr.media.paused);
|
2111
|
-
}
|
2112
|
-
|
2113
|
-
// Save scroll position
|
2114
|
-
function _saveScrollPosition() {
|
2115
|
-
scroll = {
|
2116
|
-
x: window.pageXOffset || 0,
|
2117
|
-
y: window.pageYOffset || 0
|
2118
|
-
};
|
2119
|
-
}
|
2120
|
-
|
2121
|
-
// Restore scroll position
|
2122
|
-
function _restoreScrollPosition() {
|
2123
|
-
window.scrollTo(scroll.x, scroll.y);
|
2124
|
-
}
|
2125
|
-
|
2126
|
-
// Toggle fullscreen
|
2127
|
-
function _toggleFullscreen(event) {
|
2128
|
-
// Check for native support
|
2129
|
-
var nativeSupport = fullscreen.supportsFullScreen;
|
2130
|
-
|
2131
|
-
if (nativeSupport) {
|
2132
|
-
// If it's a fullscreen change event, update the UI
|
2133
|
-
if (event && event.type === fullscreen.fullScreenEventName) {
|
2134
|
-
plyr.isFullscreen = fullscreen.isFullScreen(plyr.container);
|
2135
|
-
} else {
|
2136
|
-
// Else it's a user request to enter or exit
|
2137
|
-
if (!fullscreen.isFullScreen(plyr.container)) {
|
2138
|
-
// Save scroll position
|
2139
|
-
_saveScrollPosition();
|
2140
|
-
|
2141
|
-
// Request full screen
|
2142
|
-
fullscreen.requestFullScreen(plyr.container);
|
2143
|
-
} else {
|
2144
|
-
// Bail from fullscreen
|
2145
|
-
fullscreen.cancelFullScreen();
|
2146
|
-
}
|
2147
|
-
|
2148
|
-
// Check if we're actually full screen (it could fail)
|
2149
|
-
plyr.isFullscreen = fullscreen.isFullScreen(plyr.container);
|
2150
|
-
|
2151
|
-
return;
|
2152
|
-
}
|
2153
|
-
} else {
|
2154
|
-
// Otherwise, it's a simple toggle
|
2155
|
-
plyr.isFullscreen = !plyr.isFullscreen;
|
2156
|
-
|
2157
|
-
// Bind/unbind escape key
|
2158
|
-
document.body.style.overflow = plyr.isFullscreen ? 'hidden' : '';
|
2159
|
-
}
|
2160
|
-
|
2161
|
-
// Set class hook
|
2162
|
-
_toggleClass(plyr.container, config.classes.fullscreen.active, plyr.isFullscreen);
|
2163
|
-
|
2164
|
-
// Trap focus
|
2165
|
-
_focusTrap(plyr.isFullscreen);
|
2166
|
-
|
2167
|
-
// Set button state
|
2168
|
-
if (plyr.buttons && plyr.buttons.fullscreen) {
|
2169
|
-
_toggleState(plyr.buttons.fullscreen, plyr.isFullscreen);
|
2170
|
-
}
|
2171
|
-
|
2172
|
-
// Trigger an event
|
2173
|
-
_triggerEvent(plyr.container, plyr.isFullscreen ? 'enterfullscreen' : 'exitfullscreen', true);
|
2174
|
-
|
2175
|
-
// Restore scroll position
|
2176
|
-
if (!plyr.isFullscreen && nativeSupport) {
|
2177
|
-
_restoreScrollPosition();
|
2178
|
-
}
|
2179
|
-
}
|
2180
|
-
|
2181
|
-
// Mute
|
2182
|
-
function _toggleMute(muted) {
|
2183
|
-
// If the method is called without parameter, toggle based on current value
|
2184
|
-
if (!_is.boolean(muted)) {
|
2185
|
-
muted = !plyr.media.muted;
|
2186
|
-
}
|
2187
|
-
|
2188
|
-
// Set button state
|
2189
|
-
_toggleState(plyr.buttons.mute, muted);
|
2190
|
-
|
2191
|
-
// Set mute on the player
|
2192
|
-
plyr.media.muted = muted;
|
2193
|
-
|
2194
|
-
// If volume is 0 after unmuting, set to default
|
2195
|
-
if (plyr.media.volume === 0) {
|
2196
|
-
_setVolume(config.volume);
|
2197
|
-
}
|
2198
|
-
|
2199
|
-
// Embeds
|
2200
|
-
if (_inArray(config.types.embed, plyr.type)) {
|
2201
|
-
// YouTube
|
2202
|
-
switch(plyr.type) {
|
2203
|
-
case 'youtube':
|
2204
|
-
plyr.embed[plyr.media.muted ? 'mute' : 'unMute']();
|
2205
|
-
break;
|
2206
|
-
|
2207
|
-
case 'vimeo':
|
2208
|
-
case 'soundcloud':
|
2209
|
-
plyr.embed.setVolume(plyr.media.muted ? 0 : parseFloat(config.volume / config.volumeMax));
|
2210
|
-
break;
|
2211
|
-
}
|
2212
|
-
|
2213
|
-
// Trigger volumechange for embeds
|
2214
|
-
_triggerEvent(plyr.media, 'volumechange');
|
2215
|
-
}
|
2216
|
-
}
|
2217
|
-
|
2218
|
-
// Set volume
|
2219
|
-
function _setVolume(volume) {
|
2220
|
-
var max = config.volumeMax,
|
2221
|
-
min = config.volumeMin;
|
2222
|
-
|
2223
|
-
// Load volume from storage if no value specified
|
2224
|
-
if (_is.undefined(volume)) {
|
2225
|
-
volume = plyr.storage.volume;
|
2226
|
-
}
|
2227
|
-
|
2228
|
-
// Use config if all else fails
|
2229
|
-
if (volume === null || isNaN(volume)) {
|
2230
|
-
volume = config.volume;
|
2231
|
-
}
|
2232
|
-
|
2233
|
-
// Maximum is volumeMax
|
2234
|
-
if (volume > max) {
|
2235
|
-
volume = max;
|
2236
|
-
}
|
2237
|
-
// Minimum is volumeMin
|
2238
|
-
if (volume < min) {
|
2239
|
-
volume = min;
|
2240
|
-
}
|
2241
|
-
|
2242
|
-
// Set the player volume
|
2243
|
-
plyr.media.volume = parseFloat(volume / max);
|
2244
|
-
|
2245
|
-
// Set the display
|
2246
|
-
if (plyr.volume.display) {
|
2247
|
-
plyr.volume.display.value = volume;
|
2248
|
-
}
|
2249
|
-
|
2250
|
-
// Embeds
|
2251
|
-
if (_inArray(config.types.embed, plyr.type)) {
|
2252
|
-
switch(plyr.type) {
|
2253
|
-
case 'youtube':
|
2254
|
-
plyr.embed.setVolume(plyr.media.volume * 100);
|
2255
|
-
break;
|
2256
|
-
|
2257
|
-
case 'vimeo':
|
2258
|
-
case 'soundcloud':
|
2259
|
-
plyr.embed.setVolume(plyr.media.volume);
|
2260
|
-
break;
|
2261
|
-
}
|
2262
|
-
|
2263
|
-
// Trigger volumechange for embeds
|
2264
|
-
_triggerEvent(plyr.media, 'volumechange');
|
2265
|
-
}
|
2266
|
-
|
2267
|
-
// Toggle muted state
|
2268
|
-
if (volume === 0) {
|
2269
|
-
plyr.media.muted = true;
|
2270
|
-
} else if (plyr.media.muted && volume > 0) {
|
2271
|
-
_toggleMute();
|
2272
|
-
}
|
2273
|
-
}
|
2274
|
-
|
2275
|
-
// Increase volume
|
2276
|
-
function _increaseVolume(step) {
|
2277
|
-
var volume = plyr.media.muted ? 0 : (plyr.media.volume * config.volumeMax);
|
2278
|
-
|
2279
|
-
if (!_is.number(step)) {
|
2280
|
-
step = config.volumeStep;
|
2281
|
-
}
|
2282
|
-
|
2283
|
-
_setVolume(volume + step);
|
2284
|
-
}
|
2285
|
-
|
2286
|
-
// Decrease volume
|
2287
|
-
function _decreaseVolume(step) {
|
2288
|
-
var volume = plyr.media.muted ? 0 : (plyr.media.volume * config.volumeMax);
|
2289
|
-
|
2290
|
-
if (!_is.number(step)) {
|
2291
|
-
step = config.volumeStep;
|
2292
|
-
}
|
2293
|
-
|
2294
|
-
_setVolume(volume - step);
|
2295
|
-
}
|
2296
|
-
|
2297
|
-
// Update volume UI and storage
|
2298
|
-
function _updateVolume() {
|
2299
|
-
// Get the current volume
|
2300
|
-
var volume = plyr.media.muted ? 0 : (plyr.media.volume * config.volumeMax);
|
2301
|
-
|
2302
|
-
// Update the <input type="range"> if present
|
2303
|
-
if (plyr.supported.full) {
|
2304
|
-
if (plyr.volume.input) {
|
2305
|
-
plyr.volume.input.value = volume;
|
2306
|
-
}
|
2307
|
-
if (plyr.volume.display) {
|
2308
|
-
plyr.volume.display.value = volume;
|
2309
|
-
}
|
2310
|
-
}
|
2311
|
-
|
2312
|
-
// Update the volume in storage
|
2313
|
-
_updateStorage({volume: volume});
|
2314
|
-
|
2315
|
-
// Toggle class if muted
|
2316
|
-
_toggleClass(plyr.container, config.classes.muted, (volume === 0));
|
2317
|
-
|
2318
|
-
// Update checkbox for mute state
|
2319
|
-
if (plyr.supported.full && plyr.buttons.mute) {
|
2320
|
-
_toggleState(plyr.buttons.mute, (volume === 0));
|
2321
|
-
}
|
2322
|
-
}
|
2323
|
-
|
2324
|
-
// Toggle captions
|
2325
|
-
function _toggleCaptions(show) {
|
2326
|
-
// If there's no full support, or there's no caption toggle
|
2327
|
-
if (!plyr.supported.full || !plyr.buttons.captions) {
|
2328
|
-
return;
|
2329
|
-
}
|
2330
|
-
|
2331
|
-
// If the method is called without parameter, toggle based on current value
|
2332
|
-
if (!_is.boolean(show)) {
|
2333
|
-
show = (plyr.container.className.indexOf(config.classes.captions.active) === -1);
|
2334
|
-
}
|
2335
|
-
|
2336
|
-
// Set global
|
2337
|
-
plyr.captionsEnabled = show;
|
2338
|
-
|
2339
|
-
// Toggle state
|
2340
|
-
_toggleState(plyr.buttons.captions, plyr.captionsEnabled);
|
2341
|
-
|
2342
|
-
// Add class hook
|
2343
|
-
_toggleClass(plyr.container, config.classes.captions.active, plyr.captionsEnabled);
|
2344
|
-
|
2345
|
-
// Trigger an event
|
2346
|
-
_triggerEvent(plyr.container, plyr.captionsEnabled ? 'captionsenabled' : 'captionsdisabled', true);
|
2347
|
-
|
2348
|
-
// Save captions state to localStorage
|
2349
|
-
_updateStorage({captionsEnabled: plyr.captionsEnabled});
|
2350
|
-
}
|
2351
|
-
|
2352
|
-
// Check if media is loading
|
2353
|
-
function _checkLoading(event) {
|
2354
|
-
var loading = (event.type === 'waiting');
|
2355
|
-
|
2356
|
-
// Clear timer
|
2357
|
-
clearTimeout(timers.loading);
|
2358
|
-
|
2359
|
-
// Timer to prevent flicker when seeking
|
2360
|
-
timers.loading = setTimeout(function() {
|
2361
|
-
// Toggle container class hook
|
2362
|
-
_toggleClass(plyr.container, config.classes.loading, loading);
|
2363
|
-
|
2364
|
-
// Show controls if loading, hide if done
|
2365
|
-
_toggleControls(loading);
|
2366
|
-
}, (loading ? 250 : 0));
|
2367
|
-
}
|
2368
|
-
|
2369
|
-
// Update <progress> elements
|
2370
|
-
function _updateProgress(event) {
|
2371
|
-
if (!plyr.supported.full) {
|
2372
|
-
return;
|
2373
|
-
}
|
2374
|
-
|
2375
|
-
var progress = plyr.progress.played,
|
2376
|
-
value = 0,
|
2377
|
-
duration = _getDuration();
|
2378
|
-
|
2379
|
-
if (event) {
|
2380
|
-
switch (event.type) {
|
2381
|
-
// Video playing
|
2382
|
-
case 'timeupdate':
|
2383
|
-
case 'seeking':
|
2384
|
-
if (plyr.controls.pressed) {
|
2385
|
-
return;
|
2386
|
-
}
|
2387
|
-
|
2388
|
-
value = _getPercentage(plyr.media.currentTime, duration);
|
2389
|
-
|
2390
|
-
// Set seek range value only if it's a 'natural' time event
|
2391
|
-
if (event.type === 'timeupdate' && plyr.buttons.seek) {
|
2392
|
-
plyr.buttons.seek.value = value;
|
2393
|
-
}
|
2394
|
-
|
2395
|
-
break;
|
2396
|
-
|
2397
|
-
// Check buffer status
|
2398
|
-
case 'playing':
|
2399
|
-
case 'progress':
|
2400
|
-
progress = plyr.progress.buffer;
|
2401
|
-
value = (function() {
|
2402
|
-
var buffered = plyr.media.buffered;
|
2403
|
-
|
2404
|
-
if (buffered && buffered.length) {
|
2405
|
-
// HTML5
|
2406
|
-
return _getPercentage(buffered.end(0), duration);
|
2407
|
-
} else if (_is.number(buffered)) {
|
2408
|
-
// YouTube returns between 0 and 1
|
2409
|
-
return (buffered * 100);
|
2410
|
-
}
|
2411
|
-
|
2412
|
-
return 0;
|
2413
|
-
})();
|
2414
|
-
|
2415
|
-
break;
|
2416
|
-
}
|
2417
|
-
}
|
2418
|
-
|
2419
|
-
// Set values
|
2420
|
-
_setProgress(progress, value);
|
2421
|
-
}
|
2422
|
-
|
2423
|
-
// Set <progress> value
|
2424
|
-
function _setProgress(progress, value) {
|
2425
|
-
if (!plyr.supported.full) {
|
2426
|
-
return;
|
2427
|
-
}
|
2428
|
-
|
2429
|
-
// Default to 0
|
2430
|
-
if (_is.undefined(value)) {
|
2431
|
-
value = 0;
|
2432
|
-
}
|
2433
|
-
// Default to buffer or bail
|
2434
|
-
if (_is.undefined(progress)) {
|
2435
|
-
if (plyr.progress && plyr.progress.buffer) {
|
2436
|
-
progress = plyr.progress.buffer;
|
2437
|
-
} else {
|
2438
|
-
return;
|
2439
|
-
}
|
2440
|
-
}
|
2441
|
-
|
2442
|
-
// One progress element passed
|
2443
|
-
if (_is.htmlElement(progress)) {
|
2444
|
-
progress.value = value;
|
2445
|
-
} else if (progress) {
|
2446
|
-
// Object of progress + text element
|
2447
|
-
if (progress.bar) {
|
2448
|
-
progress.bar.value = value;
|
2449
|
-
}
|
2450
|
-
if (progress.text) {
|
2451
|
-
progress.text.innerHTML = value;
|
2452
|
-
}
|
2453
|
-
}
|
2454
|
-
}
|
2455
|
-
|
2456
|
-
// Update the displayed time
|
2457
|
-
function _updateTimeDisplay(time, element) {
|
2458
|
-
// Bail if there's no duration display
|
2459
|
-
if (!element) {
|
2460
|
-
return;
|
2461
|
-
}
|
2462
|
-
|
2463
|
-
// Fallback to 0
|
2464
|
-
if (isNaN(time)) {
|
2465
|
-
time = 0;
|
2466
|
-
}
|
2467
|
-
|
2468
|
-
plyr.secs = parseInt(time % 60);
|
2469
|
-
plyr.mins = parseInt((time / 60) % 60);
|
2470
|
-
plyr.hours = parseInt(((time / 60) / 60) % 60);
|
2471
|
-
|
2472
|
-
// Do we need to display hours?
|
2473
|
-
var displayHours = (parseInt(((_getDuration() / 60) / 60) % 60) > 0);
|
2474
|
-
|
2475
|
-
// Ensure it's two digits. For example, 03 rather than 3.
|
2476
|
-
plyr.secs = ('0' + plyr.secs).slice(-2);
|
2477
|
-
plyr.mins = ('0' + plyr.mins).slice(-2);
|
2478
|
-
|
2479
|
-
// Render
|
2480
|
-
element.innerHTML = (displayHours ? plyr.hours + ':' : '') + plyr.mins + ':' + plyr.secs;
|
2481
|
-
}
|
2482
|
-
|
2483
|
-
// Show the duration on metadataloaded
|
2484
|
-
function _displayDuration() {
|
2485
|
-
if (!plyr.supported.full) {
|
2486
|
-
return;
|
2487
|
-
}
|
2488
|
-
|
2489
|
-
// Determine duration
|
2490
|
-
var duration = _getDuration() || 0;
|
2491
|
-
|
2492
|
-
// If there's only one time display, display duration there
|
2493
|
-
if (!plyr.duration && config.displayDuration && plyr.media.paused) {
|
2494
|
-
_updateTimeDisplay(duration, plyr.currentTime);
|
2495
|
-
}
|
2496
|
-
|
2497
|
-
// If there's a duration element, update content
|
2498
|
-
if (plyr.duration) {
|
2499
|
-
_updateTimeDisplay(duration, plyr.duration);
|
2500
|
-
}
|
2501
|
-
|
2502
|
-
// Update the tooltip (if visible)
|
2503
|
-
_updateSeekTooltip();
|
2504
|
-
}
|
2505
|
-
|
2506
|
-
// Handle time change event
|
2507
|
-
function _timeUpdate(event) {
|
2508
|
-
// Duration
|
2509
|
-
_updateTimeDisplay(plyr.media.currentTime, plyr.currentTime);
|
2510
|
-
|
2511
|
-
// Ignore updates while seeking
|
2512
|
-
if (event && event.type === 'timeupdate' && plyr.media.seeking) {
|
2513
|
-
return;
|
2514
|
-
}
|
2515
|
-
|
2516
|
-
// Playing progress
|
2517
|
-
_updateProgress(event);
|
2518
|
-
}
|
2519
|
-
|
2520
|
-
// Update seek range and progress
|
2521
|
-
function _updateSeekDisplay(time) {
|
2522
|
-
// Default to 0
|
2523
|
-
if (!_is.number(time)) {
|
2524
|
-
time = 0;
|
2525
|
-
}
|
2526
|
-
|
2527
|
-
var duration = _getDuration(),
|
2528
|
-
value = _getPercentage(time, duration);
|
2529
|
-
|
2530
|
-
// Update progress
|
2531
|
-
if (plyr.progress && plyr.progress.played) {
|
2532
|
-
plyr.progress.played.value = value;
|
2533
|
-
}
|
2534
|
-
|
2535
|
-
// Update seek range input
|
2536
|
-
if (plyr.buttons && plyr.buttons.seek) {
|
2537
|
-
plyr.buttons.seek.value = value;
|
2538
|
-
}
|
2539
|
-
}
|
2540
|
-
|
2541
|
-
// Update hover tooltip for seeking
|
2542
|
-
function _updateSeekTooltip(event) {
|
2543
|
-
var duration = _getDuration();
|
2544
|
-
|
2545
|
-
// Bail if setting not true
|
2546
|
-
if (!config.tooltips.seek || !plyr.progress.container || duration === 0) {
|
2547
|
-
return;
|
2548
|
-
}
|
2549
|
-
|
2550
|
-
// Calculate percentage
|
2551
|
-
var clientRect = plyr.progress.container.getBoundingClientRect(),
|
2552
|
-
percent = 0,
|
2553
|
-
visible = config.classes.tooltip + '--visible';
|
2554
|
-
|
2555
|
-
// Determine percentage, if already visible
|
2556
|
-
if (!event) {
|
2557
|
-
if (_hasClass(plyr.progress.tooltip, visible)) {
|
2558
|
-
percent = plyr.progress.tooltip.style.left.replace('%', '');
|
2559
|
-
} else {
|
2560
|
-
return;
|
2561
|
-
}
|
2562
|
-
} else {
|
2563
|
-
percent = ((100 / clientRect.width) * (event.pageX - clientRect.left));
|
2564
|
-
}
|
2565
|
-
|
2566
|
-
// Set bounds
|
2567
|
-
if (percent < 0) {
|
2568
|
-
percent = 0;
|
2569
|
-
} else if (percent > 100) {
|
2570
|
-
percent = 100;
|
2571
|
-
}
|
2572
|
-
|
2573
|
-
// Display the time a click would seek to
|
2574
|
-
_updateTimeDisplay(((duration / 100) * percent), plyr.progress.tooltip);
|
2575
|
-
|
2576
|
-
// Set position
|
2577
|
-
plyr.progress.tooltip.style.left = percent + "%";
|
2578
|
-
|
2579
|
-
// Show/hide the tooltip
|
2580
|
-
// If the event is a moues in/out and percentage is inside bounds
|
2581
|
-
if (event && _inArray(['mouseenter', 'mouseleave'], event.type)) {
|
2582
|
-
_toggleClass(plyr.progress.tooltip, visible, (event.type === 'mouseenter'));
|
2583
|
-
}
|
2584
|
-
}
|
2585
|
-
|
2586
|
-
// Show the player controls in fullscreen mode
|
2587
|
-
function _toggleControls(toggle) {
|
2588
|
-
// Don't hide if config says not to, it's audio, or not ready or loading
|
2589
|
-
if (!config.hideControls || plyr.type === 'audio') {
|
2590
|
-
return;
|
2591
|
-
}
|
2592
|
-
|
2593
|
-
var delay = 0,
|
2594
|
-
isEnterFullscreen = false,
|
2595
|
-
show = toggle,
|
2596
|
-
loading = _hasClass(plyr.container, config.classes.loading);
|
2597
|
-
|
2598
|
-
// Default to false if no boolean
|
2599
|
-
if (!_is.boolean(toggle)) {
|
2600
|
-
if (toggle && toggle.type) {
|
2601
|
-
// Is the enter fullscreen event
|
2602
|
-
isEnterFullscreen = (toggle.type === 'enterfullscreen');
|
2603
|
-
|
2604
|
-
// Whether to show controls
|
2605
|
-
show = _inArray(['mousemove', 'touchstart', 'mouseenter', 'focus'], toggle.type);
|
2606
|
-
|
2607
|
-
// Delay hiding on move events
|
2608
|
-
if (_inArray(['mousemove', 'touchmove'], toggle.type)) {
|
2609
|
-
delay = 2000;
|
2610
|
-
}
|
2611
|
-
|
2612
|
-
// Delay a little more for keyboard users
|
2613
|
-
if (toggle.type === 'focus') {
|
2614
|
-
delay = 3000;
|
2615
|
-
}
|
2616
|
-
} else {
|
2617
|
-
show = _hasClass(plyr.container, config.classes.hideControls);
|
2618
|
-
}
|
2619
|
-
}
|
2620
|
-
|
2621
|
-
// Clear timer every movement
|
2622
|
-
window.clearTimeout(timers.hover);
|
2623
|
-
|
2624
|
-
// If the mouse is not over the controls, set a timeout to hide them
|
2625
|
-
if (show || plyr.media.paused || loading) {
|
2626
|
-
_toggleClass(plyr.container, config.classes.hideControls, false);
|
2627
|
-
|
2628
|
-
// Always show controls when paused or if touch
|
2629
|
-
if (plyr.media.paused || loading) {
|
2630
|
-
return;
|
2631
|
-
}
|
2632
|
-
|
2633
|
-
// Delay for hiding on touch
|
2634
|
-
if (plyr.browser.isTouch) {
|
2635
|
-
delay = 3000;
|
2636
|
-
}
|
2637
|
-
}
|
2638
|
-
|
2639
|
-
// If toggle is false or if we're playing (regardless of toggle),
|
2640
|
-
// then set the timer to hide the controls
|
2641
|
-
if (!show || !plyr.media.paused) {
|
2642
|
-
timers.hover = window.setTimeout(function() {
|
2643
|
-
// If the mouse is over the controls (and not entering fullscreen), bail
|
2644
|
-
if ((plyr.controls.pressed || plyr.controls.hover) && !isEnterFullscreen) {
|
2645
|
-
return;
|
2646
|
-
}
|
2647
|
-
|
2648
|
-
_toggleClass(plyr.container, config.classes.hideControls, true);
|
2649
|
-
}, delay);
|
2650
|
-
}
|
2651
|
-
}
|
2652
|
-
|
2653
|
-
// Add common function to retrieve media source
|
2654
|
-
function _source(source) {
|
2655
|
-
// If not null or undefined, parse it
|
2656
|
-
if (!_is.undefined(source)) {
|
2657
|
-
_updateSource(source);
|
2658
|
-
return;
|
2659
|
-
}
|
2660
|
-
|
2661
|
-
// Return the current source
|
2662
|
-
var url;
|
2663
|
-
switch(plyr.type) {
|
2664
|
-
case 'youtube':
|
2665
|
-
url = plyr.embed.getVideoUrl();
|
2666
|
-
break;
|
2667
|
-
|
2668
|
-
case 'vimeo':
|
2669
|
-
plyr.embed.getVideoUrl.then(function (value) {
|
2670
|
-
url = value;
|
2671
|
-
});
|
2672
|
-
break;
|
2673
|
-
|
2674
|
-
case 'soundcloud':
|
2675
|
-
plyr.embed.getCurrentSound(function(object) {
|
2676
|
-
url = object.permalink_url;
|
2677
|
-
});
|
2678
|
-
break;
|
2679
|
-
|
2680
|
-
default:
|
2681
|
-
url = plyr.media.currentSrc;
|
2682
|
-
break;
|
2683
|
-
}
|
2684
|
-
|
2685
|
-
return url || '';
|
2686
|
-
}
|
2687
|
-
|
2688
|
-
// Update source
|
2689
|
-
// Sources are not checked for support so be careful
|
2690
|
-
function _updateSource(source) {
|
2691
|
-
if (!_is.object(source) || !('sources' in source) || !source.sources.length) {
|
2692
|
-
_warn('Invalid source format');
|
2693
|
-
return;
|
2694
|
-
}
|
2695
|
-
|
2696
|
-
// Remove ready class hook
|
2697
|
-
_toggleClass(plyr.container, config.classes.ready, false);
|
2698
|
-
|
2699
|
-
// Pause playback
|
2700
|
-
_pause();
|
2701
|
-
|
2702
|
-
// Update seek range and progress
|
2703
|
-
_updateSeekDisplay();
|
2704
|
-
|
2705
|
-
// Reset buffer progress
|
2706
|
-
_setProgress();
|
2707
|
-
|
2708
|
-
// Cancel current network requests
|
2709
|
-
_cancelRequests();
|
2710
|
-
|
2711
|
-
// Setup new source
|
2712
|
-
function setup() {
|
2713
|
-
// Remove embed object
|
2714
|
-
plyr.embed = null;
|
2715
|
-
|
2716
|
-
// Remove the old media
|
2717
|
-
_remove(plyr.media);
|
2718
|
-
|
2719
|
-
// Remove video container
|
2720
|
-
if (plyr.type === 'video' && plyr.videoContainer) {
|
2721
|
-
_remove(plyr.videoContainer);
|
2722
|
-
}
|
2723
|
-
|
2724
|
-
// Reset class name
|
2725
|
-
if (plyr.container) {
|
2726
|
-
plyr.container.removeAttribute('class');
|
2727
|
-
}
|
2728
|
-
|
2729
|
-
// Set the type
|
2730
|
-
if ('type' in source) {
|
2731
|
-
plyr.type = source.type;
|
2732
|
-
|
2733
|
-
// Get child type for video (it might be an embed)
|
2734
|
-
if (plyr.type === 'video') {
|
2735
|
-
var firstSource = source.sources[0];
|
2736
|
-
|
2737
|
-
if ('type' in firstSource && _inArray(config.types.embed, firstSource.type)) {
|
2738
|
-
plyr.type = firstSource.type;
|
2739
|
-
}
|
2740
|
-
}
|
2741
|
-
}
|
2742
|
-
|
2743
|
-
// Check for support
|
2744
|
-
plyr.supported = supported(plyr.type);
|
2745
|
-
|
2746
|
-
// Create new markup
|
2747
|
-
switch(plyr.type) {
|
2748
|
-
case 'video':
|
2749
|
-
plyr.media = document.createElement('video');
|
2750
|
-
break;
|
2751
|
-
|
2752
|
-
case 'audio':
|
2753
|
-
plyr.media = document.createElement('audio');
|
2754
|
-
break;
|
2755
|
-
|
2756
|
-
case 'youtube':
|
2757
|
-
case 'vimeo':
|
2758
|
-
case 'soundcloud':
|
2759
|
-
plyr.media = document.createElement('div');
|
2760
|
-
plyr.embedId = source.sources[0].src;
|
2761
|
-
break;
|
2762
|
-
}
|
2763
|
-
|
2764
|
-
// Inject the new element
|
2765
|
-
_prependChild(plyr.container, plyr.media);
|
2766
|
-
|
2767
|
-
// Autoplay the new source?
|
2768
|
-
if (_is.boolean(source.autoplay)) {
|
2769
|
-
config.autoplay = source.autoplay;
|
2770
|
-
}
|
2771
|
-
|
2772
|
-
// Set attributes for audio and video
|
2773
|
-
if (_inArray(config.types.html5, plyr.type)) {
|
2774
|
-
if (config.crossorigin) {
|
2775
|
-
plyr.media.setAttribute('crossorigin', '');
|
2776
|
-
}
|
2777
|
-
if (config.autoplay) {
|
2778
|
-
plyr.media.setAttribute('autoplay', '');
|
2779
|
-
}
|
2780
|
-
if ('poster' in source) {
|
2781
|
-
plyr.media.setAttribute('poster', source.poster);
|
2782
|
-
}
|
2783
|
-
if (config.loop) {
|
2784
|
-
plyr.media.setAttribute('loop', '');
|
2785
|
-
}
|
2786
|
-
}
|
2787
|
-
|
2788
|
-
// Restore class hooks
|
2789
|
-
_toggleClass(plyr.container, config.classes.fullscreen.active, plyr.isFullscreen);
|
2790
|
-
_toggleClass(plyr.container, config.classes.captions.active, plyr.captionsEnabled);
|
2791
|
-
_toggleStyleHook();
|
2792
|
-
|
2793
|
-
// Set new sources for html5
|
2794
|
-
if (_inArray(config.types.html5, plyr.type)) {
|
2795
|
-
_insertChildElements('source', source.sources);
|
2796
|
-
}
|
2797
|
-
|
2798
|
-
// Set up from scratch
|
2799
|
-
_setupMedia();
|
2800
|
-
|
2801
|
-
// HTML5 stuff
|
2802
|
-
if (_inArray(config.types.html5, plyr.type)) {
|
2803
|
-
// Setup captions
|
2804
|
-
if ('tracks' in source) {
|
2805
|
-
_insertChildElements('track', source.tracks);
|
2806
|
-
}
|
2807
|
-
|
2808
|
-
// Load HTML5 sources
|
2809
|
-
plyr.media.load();
|
2810
|
-
}
|
2811
|
-
|
2812
|
-
// If HTML5 or embed but not fully supported, setupInterface and call ready now
|
2813
|
-
if (_inArray(config.types.html5, plyr.type) || (_inArray(config.types.embed, plyr.type) && !plyr.supported.full)) {
|
2814
|
-
// Setup interface
|
2815
|
-
_setupInterface();
|
2816
|
-
|
2817
|
-
// Call ready
|
2818
|
-
_ready();
|
2819
|
-
}
|
2820
|
-
|
2821
|
-
// Set aria title and iframe title
|
2822
|
-
config.title = source.title;
|
2823
|
-
_setTitle();
|
2824
|
-
}
|
2825
|
-
|
2826
|
-
// Destroy instance adn wait for callback
|
2827
|
-
// Vimeo throws a wobbly if you don't wait
|
2828
|
-
_destroy(setup, false);
|
2829
|
-
}
|
2830
|
-
|
2831
|
-
// Update poster
|
2832
|
-
function _updatePoster(source) {
|
2833
|
-
if (plyr.type === 'video') {
|
2834
|
-
plyr.media.setAttribute('poster', source);
|
2835
|
-
}
|
2836
|
-
}
|
2837
|
-
|
2838
|
-
// Listen for control events
|
2839
|
-
function _controlListeners() {
|
2840
|
-
// IE doesn't support input event, so we fallback to change
|
2841
|
-
var inputEvent = (plyr.browser.isIE ? 'change' : 'input');
|
2842
|
-
|
2843
|
-
// Click play/pause helper
|
2844
|
-
function togglePlay() {
|
2845
|
-
var play = _togglePlay();
|
2846
|
-
|
2847
|
-
// Determine which buttons
|
2848
|
-
var trigger = plyr.buttons[play ? 'play' : 'pause'],
|
2849
|
-
target = plyr.buttons[play ? 'pause' : 'play'];
|
2850
|
-
|
2851
|
-
// Get the last play button to account for the large play button
|
2852
|
-
if (target && target.length > 1) {
|
2853
|
-
target = target[target.length - 1];
|
2854
|
-
} else {
|
2855
|
-
target = target[0];
|
2856
|
-
}
|
2857
|
-
|
2858
|
-
// Setup focus and tab focus
|
2859
|
-
if (target) {
|
2860
|
-
var hadTabFocus = _hasClass(trigger, config.classes.tabFocus);
|
2861
|
-
|
2862
|
-
setTimeout(function() {
|
2863
|
-
target.focus();
|
2864
|
-
|
2865
|
-
if (hadTabFocus) {
|
2866
|
-
_toggleClass(trigger, config.classes.tabFocus, false);
|
2867
|
-
_toggleClass(target, config.classes.tabFocus, true);
|
2868
|
-
}
|
2869
|
-
}, 100);
|
2870
|
-
}
|
2871
|
-
}
|
2872
|
-
|
2873
|
-
// Get the focused element
|
2874
|
-
function getFocusElement() {
|
2875
|
-
var focused = document.activeElement;
|
2876
|
-
|
2877
|
-
if (!focused || focused === document.body) {
|
2878
|
-
focused = null;
|
2879
|
-
} else {
|
2880
|
-
focused = document.querySelector(':focus');
|
2881
|
-
}
|
2882
|
-
|
2883
|
-
return focused;
|
2884
|
-
}
|
2885
|
-
|
2886
|
-
// Get the key code for an event
|
2887
|
-
function getKeyCode(event) {
|
2888
|
-
return event.keyCode ? event.keyCode : event.which;
|
2889
|
-
}
|
2890
|
-
|
2891
|
-
// Detect tab focus
|
2892
|
-
function checkTabFocus(focused) {
|
2893
|
-
for (var button in plyr.buttons) {
|
2894
|
-
var element = plyr.buttons[button];
|
2895
|
-
|
2896
|
-
if (_is.nodeList(element)) {
|
2897
|
-
for (var i = 0; i < element.length; i++) {
|
2898
|
-
_toggleClass(element[i], config.classes.tabFocus, (element[i] === focused));
|
2899
|
-
}
|
2900
|
-
} else {
|
2901
|
-
_toggleClass(element, config.classes.tabFocus, (element === focused));
|
2902
|
-
}
|
2903
|
-
}
|
2904
|
-
}
|
2905
|
-
|
2906
|
-
// Keyboard shortcuts
|
2907
|
-
if (config.keyboardShorcuts.focused) {
|
2908
|
-
var last = null;
|
2909
|
-
|
2910
|
-
// Handle global presses
|
2911
|
-
if (config.keyboardShorcuts.global) {
|
2912
|
-
_on(window, 'keydown keyup', function(event) {
|
2913
|
-
var code = getKeyCode(event),
|
2914
|
-
focused = getFocusElement(),
|
2915
|
-
allowed = [48,49,50,51,52,53,54,56,57,75,77,70,67],
|
2916
|
-
count = get().length;
|
2917
|
-
|
2918
|
-
// Only handle global key press if there's only one player
|
2919
|
-
// and the key is in the allowed keys
|
2920
|
-
// and if the focused element is not editable (e.g. text input)
|
2921
|
-
// and any that accept key input http://webaim.org/techniques/keyboard/
|
2922
|
-
if (count === 1 && _inArray(allowed, code) && (!_is.htmlElement(focused) || !_matches(focused, config.selectors.editable))) {
|
2923
|
-
handleKey(event);
|
2924
|
-
}
|
2925
|
-
});
|
2926
|
-
}
|
2927
|
-
|
2928
|
-
// Handle presses on focused
|
2929
|
-
_on(plyr.container, 'keydown keyup', handleKey);
|
2930
|
-
}
|
2931
|
-
|
2932
|
-
function handleKey(event) {
|
2933
|
-
var code = getKeyCode(event),
|
2934
|
-
pressed = event.type === 'keydown',
|
2935
|
-
held = pressed && code === last;
|
2936
|
-
|
2937
|
-
// If the event is bubbled from the media element
|
2938
|
-
// Firefox doesn't get the keycode for whatever reason
|
2939
|
-
if (!_is.number(code)) {
|
2940
|
-
return;
|
2941
|
-
}
|
2942
|
-
|
2943
|
-
// Seek by the number keys
|
2944
|
-
function seekByKey() {
|
2945
|
-
// Get current duration
|
2946
|
-
var duration = plyr.media.duration;
|
2947
|
-
|
2948
|
-
// Bail if we have no duration set
|
2949
|
-
if (!_is.number(duration)) {
|
2950
|
-
return;
|
2951
|
-
}
|
2952
|
-
|
2953
|
-
// Divide the max duration into 10th's and times by the number value
|
2954
|
-
_seek((duration / 10) * (code - 48));
|
2955
|
-
}
|
2956
|
-
|
2957
|
-
// Handle the key on keydown
|
2958
|
-
// Reset on keyup
|
2959
|
-
if (pressed) {
|
2960
|
-
// Which keycodes should we prevent default
|
2961
|
-
var preventDefault = [48,49,50,51,52,53,54,56,57,32,75,38,40,77,39,37,70,67];
|
2962
|
-
|
2963
|
-
// If the code is found prevent default (e.g. prevent scrolling for arrows)
|
2964
|
-
if (_inArray(preventDefault, code)) {
|
2965
|
-
event.preventDefault();
|
2966
|
-
event.stopPropagation();
|
2967
|
-
}
|
2968
|
-
|
2969
|
-
switch(code) {
|
2970
|
-
// 0-9
|
2971
|
-
case 48:
|
2972
|
-
case 49:
|
2973
|
-
case 50:
|
2974
|
-
case 51:
|
2975
|
-
case 52:
|
2976
|
-
case 53:
|
2977
|
-
case 54:
|
2978
|
-
case 55:
|
2979
|
-
case 56:
|
2980
|
-
case 57: if (!held) { seekByKey(); } break;
|
2981
|
-
// Space and K key
|
2982
|
-
case 32:
|
2983
|
-
case 75: if (!held) { _togglePlay(); } break;
|
2984
|
-
// Arrow up
|
2985
|
-
case 38: _increaseVolume(); break;
|
2986
|
-
// Arrow down
|
2987
|
-
case 40: _decreaseVolume(); break;
|
2988
|
-
// M key
|
2989
|
-
case 77: if (!held) { _toggleMute() } break;
|
2990
|
-
// Arrow forward
|
2991
|
-
case 39: _forward(); break;
|
2992
|
-
// Arrow back
|
2993
|
-
case 37: _rewind(); break;
|
2994
|
-
// F key
|
2995
|
-
case 70: _toggleFullscreen(); break;
|
2996
|
-
// C key
|
2997
|
-
case 67: if (!held) { _toggleCaptions(); } break;
|
2998
|
-
}
|
2999
|
-
|
3000
|
-
// Escape is handle natively when in full screen
|
3001
|
-
// So we only need to worry about non native
|
3002
|
-
if (!fullscreen.supportsFullScreen && plyr.isFullscreen && code === 27) {
|
3003
|
-
_toggleFullscreen();
|
3004
|
-
}
|
3005
|
-
|
3006
|
-
// Store last code for next cycle
|
3007
|
-
last = code;
|
3008
|
-
} else {
|
3009
|
-
last = null;
|
3010
|
-
}
|
3011
|
-
}
|
3012
|
-
|
3013
|
-
// Focus/tab management
|
3014
|
-
_on(window, 'keyup', function(event) {
|
3015
|
-
var code = getKeyCode(event),
|
3016
|
-
focused = getFocusElement();
|
3017
|
-
|
3018
|
-
if (code === 9) {
|
3019
|
-
checkTabFocus(focused);
|
3020
|
-
}
|
3021
|
-
});
|
3022
|
-
_on(document.body, 'click', function() {
|
3023
|
-
_toggleClass(_getElement('.' + config.classes.tabFocus), config.classes.tabFocus, false);
|
3024
|
-
});
|
3025
|
-
for (var button in plyr.buttons) {
|
3026
|
-
var element = plyr.buttons[button];
|
3027
|
-
|
3028
|
-
_on(element, 'blur', function() {
|
3029
|
-
_toggleClass(element, 'tab-focus', false);
|
3030
|
-
});
|
3031
|
-
}
|
3032
|
-
|
3033
|
-
// Play
|
3034
|
-
_proxyListener(plyr.buttons.play, 'click', config.listeners.play, togglePlay);
|
3035
|
-
|
3036
|
-
// Pause
|
3037
|
-
_proxyListener(plyr.buttons.pause, 'click', config.listeners.pause, togglePlay);
|
3038
|
-
|
3039
|
-
// Restart
|
3040
|
-
_proxyListener(plyr.buttons.restart, 'click', config.listeners.restart, _seek);
|
3041
|
-
|
3042
|
-
// Rewind
|
3043
|
-
_proxyListener(plyr.buttons.rewind, 'click', config.listeners.rewind, _rewind);
|
3044
|
-
|
3045
|
-
// Fast forward
|
3046
|
-
_proxyListener(plyr.buttons.forward, 'click', config.listeners.forward, _forward);
|
3047
|
-
|
3048
|
-
// Seek
|
3049
|
-
_proxyListener(plyr.buttons.seek, inputEvent, config.listeners.seek, _seek);
|
3050
|
-
|
3051
|
-
// Set volume
|
3052
|
-
_proxyListener(plyr.volume.input, inputEvent, config.listeners.volume, function() {
|
3053
|
-
_setVolume(plyr.volume.input.value);
|
3054
|
-
});
|
3055
|
-
|
3056
|
-
// Mute
|
3057
|
-
_proxyListener(plyr.buttons.mute, 'click', config.listeners.mute, _toggleMute);
|
3058
|
-
|
3059
|
-
// Fullscreen
|
3060
|
-
_proxyListener(plyr.buttons.fullscreen, 'click', config.listeners.fullscreen, _toggleFullscreen);
|
3061
|
-
|
3062
|
-
// Handle user exiting fullscreen by escaping etc
|
3063
|
-
if (fullscreen.supportsFullScreen) {
|
3064
|
-
_on(document, fullscreen.fullScreenEventName, _toggleFullscreen);
|
3065
|
-
}
|
3066
|
-
|
3067
|
-
// Captions
|
3068
|
-
_on(plyr.buttons.captions, 'click', _toggleCaptions);
|
3069
|
-
|
3070
|
-
// Seek tooltip
|
3071
|
-
_on(plyr.progress.container, 'mouseenter mouseleave mousemove', _updateSeekTooltip);
|
3072
|
-
|
3073
|
-
// Toggle controls visibility based on mouse movement
|
3074
|
-
if (config.hideControls) {
|
3075
|
-
// Toggle controls on mouse events and entering fullscreen
|
3076
|
-
_on(plyr.container, 'mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen', _toggleControls);
|
3077
|
-
|
3078
|
-
// Watch for cursor over controls so they don't hide when trying to interact
|
3079
|
-
_on(plyr.controls, 'mouseenter mouseleave', function(event) {
|
3080
|
-
plyr.controls.hover = event.type === 'mouseenter';
|
3081
|
-
});
|
3082
|
-
|
3083
|
-
// Watch for cursor over controls so they don't hide when trying to interact
|
3084
|
-
_on(plyr.controls, 'mousedown mouseup touchstart touchend touchcancel', function(event) {
|
3085
|
-
plyr.controls.pressed = _inArray(['mousedown', 'touchstart'], event.type);
|
3086
|
-
});
|
3087
|
-
|
3088
|
-
// Focus in/out on controls
|
3089
|
-
_on(plyr.controls, 'focus blur', _toggleControls, true);
|
3090
|
-
}
|
3091
|
-
|
3092
|
-
// Adjust volume on scroll
|
3093
|
-
_on(plyr.volume.input, 'wheel', function(event) {
|
3094
|
-
event.preventDefault();
|
3095
|
-
|
3096
|
-
// Detect "natural" scroll - suppored on OS X Safari only
|
3097
|
-
// Other browsers on OS X will be inverted until support improves
|
3098
|
-
var inverted = event.webkitDirectionInvertedFromDevice,
|
3099
|
-
step = (config.volumeStep / 5);
|
3100
|
-
|
3101
|
-
// Scroll down (or up on natural) to decrease
|
3102
|
-
if (event.deltaY < 0 || event.deltaX > 0) {
|
3103
|
-
if (inverted) {
|
3104
|
-
_decreaseVolume(step);
|
3105
|
-
} else {
|
3106
|
-
_increaseVolume(step);
|
3107
|
-
}
|
3108
|
-
}
|
3109
|
-
|
3110
|
-
// Scroll up (or down on natural) to increase
|
3111
|
-
if (event.deltaY > 0 || event.deltaX < 0) {
|
3112
|
-
if (inverted) {
|
3113
|
-
_increaseVolume(step);
|
3114
|
-
} else {
|
3115
|
-
_decreaseVolume(step);
|
3116
|
-
}
|
3117
|
-
}
|
3118
|
-
});
|
3119
|
-
}
|
3120
|
-
|
3121
|
-
// Listen for media events
|
3122
|
-
function _mediaListeners() {
|
3123
|
-
// Time change on media
|
3124
|
-
_on(plyr.media, 'timeupdate seeking', _timeUpdate);
|
3125
|
-
|
3126
|
-
// Update manual captions
|
3127
|
-
_on(plyr.media, 'timeupdate', _seekManualCaptions);
|
3128
|
-
|
3129
|
-
// Display duration
|
3130
|
-
_on(plyr.media, 'durationchange loadedmetadata', _displayDuration);
|
3131
|
-
|
3132
|
-
// Handle the media finishing
|
3133
|
-
_on(plyr.media, 'ended', function() {
|
3134
|
-
// Show poster on end
|
3135
|
-
if (plyr.type === 'video' && config.showPosterOnEnd) {
|
3136
|
-
// Clear
|
3137
|
-
if (plyr.type === 'video') {
|
3138
|
-
_setCaption();
|
3139
|
-
}
|
3140
|
-
|
3141
|
-
// Restart
|
3142
|
-
_seek();
|
3143
|
-
|
3144
|
-
// Re-load media
|
3145
|
-
plyr.media.load();
|
3146
|
-
}
|
3147
|
-
});
|
3148
|
-
|
3149
|
-
// Check for buffer progress
|
3150
|
-
_on(plyr.media, 'progress playing', _updateProgress);
|
3151
|
-
|
3152
|
-
// Handle native mute
|
3153
|
-
_on(plyr.media, 'volumechange', _updateVolume);
|
3154
|
-
|
3155
|
-
// Handle native play/pause
|
3156
|
-
_on(plyr.media, 'play pause ended', _checkPlaying);
|
3157
|
-
|
3158
|
-
// Loading
|
3159
|
-
_on(plyr.media, 'waiting canplay seeked', _checkLoading);
|
3160
|
-
|
3161
|
-
// Click video
|
3162
|
-
if (config.clickToPlay && plyr.type !== 'audio') {
|
3163
|
-
// Re-fetch the wrapper
|
3164
|
-
var wrapper = _getElement('.' + config.classes.videoWrapper);
|
3165
|
-
|
3166
|
-
// Bail if there's no wrapper (this should never happen)
|
3167
|
-
if (!wrapper) {
|
3168
|
-
return;
|
3169
|
-
}
|
3170
|
-
|
3171
|
-
// Set cursor
|
3172
|
-
wrapper.style.cursor = "pointer";
|
3173
|
-
|
3174
|
-
// On click play, pause ore restart
|
3175
|
-
_on(wrapper, 'click', function() {
|
3176
|
-
// Touch devices will just show controls (if we're hiding controls)
|
3177
|
-
if (config.hideControls && plyr.browser.isTouch && !plyr.media.paused) {
|
3178
|
-
return;
|
3179
|
-
}
|
3180
|
-
|
3181
|
-
if (plyr.media.paused) {
|
3182
|
-
_play();
|
3183
|
-
} else if (plyr.media.ended) {
|
3184
|
-
_seek();
|
3185
|
-
_play();
|
3186
|
-
} else {
|
3187
|
-
_pause();
|
3188
|
-
}
|
3189
|
-
});
|
3190
|
-
}
|
3191
|
-
|
3192
|
-
// Disable right click
|
3193
|
-
if (config.disableContextMenu) {
|
3194
|
-
_on(plyr.media, 'contextmenu', function(event) { event.preventDefault(); });
|
3195
|
-
}
|
3196
|
-
|
3197
|
-
// Proxy events to container
|
3198
|
-
// Bubble up key events for Edge
|
3199
|
-
_on(plyr.media, config.events.concat(['keyup', 'keydown']).join(' '), function(event) {
|
3200
|
-
_triggerEvent(plyr.container, event.type, true);
|
3201
|
-
});
|
3202
|
-
}
|
3203
|
-
|
3204
|
-
// Cancel current network requests
|
3205
|
-
// See https://github.com/Selz/plyr/issues/174
|
3206
|
-
function _cancelRequests() {
|
3207
|
-
if (!_inArray(config.types.html5, plyr.type)) {
|
3208
|
-
return;
|
3209
|
-
}
|
3210
|
-
|
3211
|
-
// Remove child sources
|
3212
|
-
var sources = plyr.media.querySelectorAll('source');
|
3213
|
-
for (var i = 0; i < sources.length; i++) {
|
3214
|
-
_remove(sources[i]);
|
3215
|
-
}
|
3216
|
-
|
3217
|
-
// Set blank video src attribute
|
3218
|
-
// This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
|
3219
|
-
// Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection
|
3220
|
-
plyr.media.setAttribute('src', 'https://cdn.selz.com/plyr/blank.mp4');
|
3221
|
-
|
3222
|
-
// Load the new empty source
|
3223
|
-
// This will cancel existing requests
|
3224
|
-
// See https://github.com/Selz/plyr/issues/174
|
3225
|
-
plyr.media.load();
|
3226
|
-
|
3227
|
-
// Debugging
|
3228
|
-
_log('Cancelled network requests');
|
3229
|
-
}
|
3230
|
-
|
3231
|
-
// Destroy an instance
|
3232
|
-
// Event listeners are removed when elements are removed
|
3233
|
-
// http://stackoverflow.com/questions/12528049/if-a-dom-element-is-removed-are-its-listeners-also-removed-from-memory
|
3234
|
-
function _destroy(callback, restore) {
|
3235
|
-
// Bail if the element is not initialized
|
3236
|
-
if (!plyr.init) {
|
3237
|
-
return null;
|
3238
|
-
}
|
3239
|
-
|
3240
|
-
// Type specific stuff
|
3241
|
-
switch (plyr.type) {
|
3242
|
-
case 'youtube':
|
3243
|
-
// Clear timers
|
3244
|
-
window.clearInterval(timers.buffering);
|
3245
|
-
window.clearInterval(timers.playing);
|
3246
|
-
|
3247
|
-
// Destroy YouTube API
|
3248
|
-
plyr.embed.destroy();
|
3249
|
-
|
3250
|
-
// Clean up
|
3251
|
-
cleanUp();
|
3252
|
-
|
3253
|
-
break;
|
3254
|
-
|
3255
|
-
case 'vimeo':
|
3256
|
-
// Destroy Vimeo API
|
3257
|
-
// then clean up (wait, to prevent postmessage errors)
|
3258
|
-
plyr.embed.unload().then(cleanUp);
|
3259
|
-
|
3260
|
-
// Vimeo does not always return
|
3261
|
-
timers.cleanUp = window.setTimeout(cleanUp, 200);
|
3262
|
-
|
3263
|
-
break;
|
3264
|
-
|
3265
|
-
case 'video':
|
3266
|
-
case 'audio':
|
3267
|
-
// Restore native video controls
|
3268
|
-
_toggleNativeControls(true);
|
3269
|
-
|
3270
|
-
// Clean up
|
3271
|
-
cleanUp();
|
3272
|
-
|
3273
|
-
break;
|
3274
|
-
}
|
3275
|
-
|
3276
|
-
function cleanUp() {
|
3277
|
-
clearTimeout(timers.cleanUp);
|
3278
|
-
|
3279
|
-
// Default to restore original element
|
3280
|
-
if (!_is.boolean(restore)) {
|
3281
|
-
restore = true;
|
3282
|
-
}
|
3283
|
-
|
3284
|
-
// Callback
|
3285
|
-
if (_is.function(callback)) {
|
3286
|
-
callback.call(original);
|
3287
|
-
}
|
3288
|
-
|
3289
|
-
// Bail if we don't need to restore the original element
|
3290
|
-
if (!restore) {
|
3291
|
-
return;
|
3292
|
-
}
|
3293
|
-
|
3294
|
-
// Remove init flag
|
3295
|
-
plyr.init = false;
|
3296
|
-
|
3297
|
-
// Replace the container with the original element provided
|
3298
|
-
plyr.container.parentNode.replaceChild(original, plyr.container);
|
3299
|
-
|
3300
|
-
// Allow overflow (set on fullscreen)
|
3301
|
-
document.body.style.overflow = '';
|
3302
|
-
|
3303
|
-
// Event
|
3304
|
-
_triggerEvent(original, 'destroyed', true);
|
3305
|
-
}
|
3306
|
-
}
|
3307
|
-
|
3308
|
-
// Setup a player
|
3309
|
-
function _init() {
|
3310
|
-
// Bail if the element is initialized
|
3311
|
-
if (plyr.init) {
|
3312
|
-
return null;
|
3313
|
-
}
|
3314
|
-
|
3315
|
-
// Setup the fullscreen api
|
3316
|
-
fullscreen = _fullscreen();
|
3317
|
-
|
3318
|
-
// Sniff out the browser
|
3319
|
-
plyr.browser = _browserSniff();
|
3320
|
-
|
3321
|
-
// Bail if nothing to setup
|
3322
|
-
if (!_is.htmlElement(plyr.media)) {
|
3323
|
-
return;
|
3324
|
-
}
|
3325
|
-
|
3326
|
-
// Load saved settings from localStorage
|
3327
|
-
_setupStorage();
|
3328
|
-
|
3329
|
-
// Set media type based on tag or data attribute
|
3330
|
-
// Supported: video, audio, vimeo, youtube
|
3331
|
-
var tagName = media.tagName.toLowerCase();
|
3332
|
-
if (tagName === 'div') {
|
3333
|
-
plyr.type = media.getAttribute('data-type');
|
3334
|
-
plyr.embedId = media.getAttribute('data-video-id');
|
3335
|
-
|
3336
|
-
// Clean up
|
3337
|
-
media.removeAttribute('data-type');
|
3338
|
-
media.removeAttribute('data-video-id');
|
3339
|
-
} else {
|
3340
|
-
plyr.type = tagName;
|
3341
|
-
config.crossorigin = (media.getAttribute('crossorigin') !== null);
|
3342
|
-
config.autoplay = (config.autoplay || (media.getAttribute('autoplay') !== null));
|
3343
|
-
config.loop = (config.loop || (media.getAttribute('loop') !== null));
|
3344
|
-
}
|
3345
|
-
|
3346
|
-
// Check for support
|
3347
|
-
plyr.supported = supported(plyr.type);
|
3348
|
-
|
3349
|
-
// If no native support, bail
|
3350
|
-
if (!plyr.supported.basic) {
|
3351
|
-
return;
|
3352
|
-
}
|
3353
|
-
|
3354
|
-
// Wrap media
|
3355
|
-
plyr.container = _wrap(media, document.createElement('div'));
|
3356
|
-
|
3357
|
-
// Allow focus to be captured
|
3358
|
-
plyr.container.setAttribute('tabindex', 0);
|
3359
|
-
|
3360
|
-
// Add style hook
|
3361
|
-
_toggleStyleHook();
|
3362
|
-
|
3363
|
-
// Debug info
|
3364
|
-
_log('' + plyr.browser.name + ' ' + plyr.browser.version);
|
3365
|
-
|
3366
|
-
// Setup media
|
3367
|
-
_setupMedia();
|
3368
|
-
|
3369
|
-
// Setup interface
|
3370
|
-
// If embed but not fully supported, setupInterface (to avoid flash of controls) and call ready now
|
3371
|
-
if (_inArray(config.types.html5, plyr.type) || (_inArray(config.types.embed, plyr.type) && !plyr.supported.full)) {
|
3372
|
-
// Setup UI
|
3373
|
-
_setupInterface();
|
3374
|
-
|
3375
|
-
// Call ready
|
3376
|
-
_ready();
|
3377
|
-
|
3378
|
-
// Set title on button and frame
|
3379
|
-
_setTitle();
|
3380
|
-
}
|
3381
|
-
|
3382
|
-
// Successful setup
|
3383
|
-
plyr.init = true;
|
3384
|
-
}
|
3385
|
-
|
3386
|
-
// Setup the UI
|
3387
|
-
function _setupInterface() {
|
3388
|
-
// Don't setup interface if no support
|
3389
|
-
if (!plyr.supported.full) {
|
3390
|
-
_warn('Basic support only', plyr.type);
|
3391
|
-
|
3392
|
-
// Remove controls
|
3393
|
-
_remove(_getElement(config.selectors.controls.wrapper));
|
3394
|
-
|
3395
|
-
// Remove large play
|
3396
|
-
_remove(_getElement(config.selectors.buttons.play));
|
3397
|
-
|
3398
|
-
// Restore native controls
|
3399
|
-
_toggleNativeControls(true);
|
3400
|
-
|
3401
|
-
// Bail
|
3402
|
-
return;
|
3403
|
-
}
|
3404
|
-
|
3405
|
-
// Inject custom controls if not present
|
3406
|
-
var controlsMissing = !_getElements(config.selectors.controls.wrapper).length;
|
3407
|
-
if (controlsMissing) {
|
3408
|
-
// Inject custom controls
|
3409
|
-
_injectControls();
|
3410
|
-
}
|
3411
|
-
|
3412
|
-
// Find the elements
|
3413
|
-
if (!_findElements()) {
|
3414
|
-
return;
|
3415
|
-
}
|
3416
|
-
|
3417
|
-
// If the controls are injected, re-bind listeners for controls
|
3418
|
-
if (controlsMissing) {
|
3419
|
-
_controlListeners();
|
3420
|
-
}
|
3421
|
-
|
3422
|
-
// Media element listeners
|
3423
|
-
_mediaListeners();
|
3424
|
-
|
3425
|
-
// Remove native controls
|
3426
|
-
_toggleNativeControls();
|
3427
|
-
|
3428
|
-
// Setup fullscreen
|
3429
|
-
_setupFullscreen();
|
3430
|
-
|
3431
|
-
// Captions
|
3432
|
-
_setupCaptions();
|
3433
|
-
|
3434
|
-
// Set volume
|
3435
|
-
_setVolume();
|
3436
|
-
_updateVolume();
|
3437
|
-
|
3438
|
-
// Reset time display
|
3439
|
-
_timeUpdate();
|
3440
|
-
|
3441
|
-
// Update the UI
|
3442
|
-
_checkPlaying();
|
3443
|
-
}
|
3444
|
-
|
3445
|
-
api = {
|
3446
|
-
getOriginal: function() { return original; },
|
3447
|
-
getContainer: function() { return plyr.container },
|
3448
|
-
getEmbed: function() { return plyr.embed; },
|
3449
|
-
getMedia: function() { return plyr.media; },
|
3450
|
-
getType: function() { return plyr.type; },
|
3451
|
-
getDuration: _getDuration,
|
3452
|
-
getCurrentTime: function() { return plyr.media.currentTime; },
|
3453
|
-
getVolume: function() { return plyr.media.volume; },
|
3454
|
-
isMuted: function() { return plyr.media.muted; },
|
3455
|
-
isReady: function() { return _hasClass(plyr.container, config.classes.ready); },
|
3456
|
-
isLoading: function() { return _hasClass(plyr.container, config.classes.loading); },
|
3457
|
-
isPaused: function() { return plyr.media.paused; },
|
3458
|
-
on: function(event, callback) { _on(plyr.container, event, callback); return this; },
|
3459
|
-
play: _play,
|
3460
|
-
pause: _pause,
|
3461
|
-
stop: function() { _pause(); _seek(); },
|
3462
|
-
restart: _seek,
|
3463
|
-
rewind: _rewind,
|
3464
|
-
forward: _forward,
|
3465
|
-
seek: _seek,
|
3466
|
-
source: _source,
|
3467
|
-
poster: _updatePoster,
|
3468
|
-
setVolume: _setVolume,
|
3469
|
-
togglePlay: _togglePlay,
|
3470
|
-
toggleMute: _toggleMute,
|
3471
|
-
toggleCaptions: _toggleCaptions,
|
3472
|
-
toggleFullscreen: _toggleFullscreen,
|
3473
|
-
toggleControls: _toggleControls,
|
3474
|
-
isFullscreen: function() { return plyr.isFullscreen || false; },
|
3475
|
-
support: function(mimeType) { return _supportMime(plyr, mimeType); },
|
3476
|
-
destroy: _destroy
|
3477
|
-
};
|
3478
|
-
|
3479
|
-
// Everything done
|
3480
|
-
function _ready() {
|
3481
|
-
// Ready event at end of execution stack
|
3482
|
-
window.setTimeout(function() {
|
3483
|
-
_triggerEvent(plyr.media, 'ready');
|
3484
|
-
}, 0);
|
3485
|
-
|
3486
|
-
// Set class hook on media element
|
3487
|
-
_toggleClass(plyr.media, defaults.classes.setup, true);
|
3488
|
-
|
3489
|
-
// Set container class for ready
|
3490
|
-
_toggleClass(plyr.container, config.classes.ready, true);
|
3491
|
-
|
3492
|
-
// Store a refernce to instance
|
3493
|
-
plyr.media.plyr = api;
|
3494
|
-
|
3495
|
-
// Autoplay
|
3496
|
-
if (config.autoplay) {
|
3497
|
-
_play();
|
3498
|
-
}
|
3499
|
-
}
|
3500
|
-
|
3501
|
-
// Initialize instance
|
3502
|
-
_init();
|
3503
|
-
|
3504
|
-
// If init failed, return null
|
3505
|
-
if (!plyr.init) {
|
3506
|
-
return null;
|
3507
|
-
}
|
3508
|
-
|
3509
|
-
return api;
|
3510
|
-
}
|
3511
|
-
|
3512
|
-
// Load a sprite
|
3513
|
-
function loadSprite(url, id) {
|
3514
|
-
var x = new XMLHttpRequest();
|
3515
|
-
|
3516
|
-
// If the id is set and sprite exists, bail
|
3517
|
-
if (_is.string(id) && _is.htmlElement(document.querySelector('#' + id))) {
|
3518
|
-
return;
|
3519
|
-
}
|
3520
|
-
|
3521
|
-
// Create placeholder (to prevent loading twice)
|
3522
|
-
var container = document.createElement('div');
|
3523
|
-
container.setAttribute('hidden', '');
|
3524
|
-
if (_is.string(id)) {
|
3525
|
-
container.setAttribute('id', id);
|
3526
|
-
}
|
3527
|
-
document.body.insertBefore(container, document.body.childNodes[0]);
|
3528
|
-
|
3529
|
-
// Check for CORS support
|
3530
|
-
if ('withCredentials' in x) {
|
3531
|
-
x.open('GET', url, true);
|
3532
|
-
} else {
|
3533
|
-
return;
|
3534
|
-
}
|
3535
|
-
|
3536
|
-
// Inject hidden div with sprite on load
|
3537
|
-
x.onload = function() {
|
3538
|
-
container.innerHTML = x.responseText;
|
3539
|
-
}
|
3540
|
-
|
3541
|
-
x.send();
|
3542
|
-
}
|
3543
|
-
|
3544
|
-
// Check for support
|
3545
|
-
function supported(type) {
|
3546
|
-
var browser = _browserSniff(),
|
3547
|
-
isOldIE = (browser.isIE && browser.version <= 9),
|
3548
|
-
isIos = browser.isIos,
|
3549
|
-
isIphone = browser.isIphone,
|
3550
|
-
audioSupport = !!document.createElement('audio').canPlayType,
|
3551
|
-
videoSupport = !!document.createElement('video').canPlayType,
|
3552
|
-
basic = false,
|
3553
|
-
full = false;
|
3554
|
-
|
3555
|
-
switch (type) {
|
3556
|
-
case 'video':
|
3557
|
-
basic = videoSupport;
|
3558
|
-
full = (basic && (!isOldIE && !isIphone));
|
3559
|
-
break;
|
3560
|
-
|
3561
|
-
case 'audio':
|
3562
|
-
basic = audioSupport;
|
3563
|
-
full = (basic && !isOldIE);
|
3564
|
-
break;
|
3565
|
-
|
3566
|
-
// Vimeo does not seem to be supported on iOS via API
|
3567
|
-
// Issue raised https://github.com/vimeo/player.js/issues/87
|
3568
|
-
case 'vimeo':
|
3569
|
-
basic = true;
|
3570
|
-
full = (!isOldIE && !isIos);
|
3571
|
-
break;
|
3572
|
-
|
3573
|
-
case 'youtube':
|
3574
|
-
basic = true;
|
3575
|
-
full = (!isOldIE && !isIos);
|
3576
|
-
|
3577
|
-
// YouTube seems to work on iOS 10+ on iPad
|
3578
|
-
if (isIos && !isIphone && browser.version >= 10) {
|
3579
|
-
full = true;
|
3580
|
-
}
|
3581
|
-
|
3582
|
-
break;
|
3583
|
-
|
3584
|
-
case 'soundcloud':
|
3585
|
-
basic = true;
|
3586
|
-
full = (!isOldIE && !isIphone);
|
3587
|
-
break;
|
3588
|
-
|
3589
|
-
default:
|
3590
|
-
basic = (audioSupport && videoSupport);
|
3591
|
-
full = (basic && !isOldIE);
|
3592
|
-
}
|
3593
|
-
|
3594
|
-
return {
|
3595
|
-
basic: basic,
|
3596
|
-
full: full
|
3597
|
-
};
|
3598
|
-
}
|
3599
|
-
|
3600
|
-
// Setup function
|
3601
|
-
function setup(targets, options) {
|
3602
|
-
// Get the players
|
3603
|
-
var players = [],
|
3604
|
-
instances = [],
|
3605
|
-
selector = [defaults.selectors.html5, defaults.selectors.embed].join(',');
|
3606
|
-
|
3607
|
-
// Select the elements
|
3608
|
-
if (_is.string(targets)) {
|
3609
|
-
// String selector passed
|
3610
|
-
targets = document.querySelectorAll(targets);
|
3611
|
-
} else if (_is.htmlElement(targets)) {
|
3612
|
-
// Single HTMLElement passed
|
3613
|
-
targets = [targets];
|
3614
|
-
} else if (!_is.nodeList(targets) && !_is.array(targets) && !_is.string(targets)) {
|
3615
|
-
// No selector passed, possibly options as first argument
|
3616
|
-
// If options are the first argument
|
3617
|
-
if (_is.undefined(options) && _is.object(targets)) {
|
3618
|
-
options = targets;
|
3619
|
-
}
|
3620
|
-
|
3621
|
-
// Use default selector
|
3622
|
-
targets = document.querySelectorAll(selector);
|
3623
|
-
}
|
3624
|
-
|
3625
|
-
// Convert NodeList to array
|
3626
|
-
if (_is.nodeList(targets)) {
|
3627
|
-
targets = Array.prototype.slice.call(targets);
|
3628
|
-
}
|
3629
|
-
|
3630
|
-
// Bail if disabled or no basic support
|
3631
|
-
// You may want to disable certain UAs etc
|
3632
|
-
if (!supported().basic || !targets.length) {
|
3633
|
-
return false;
|
3634
|
-
}
|
3635
|
-
|
3636
|
-
// Add to container list
|
3637
|
-
function add(target, media) {
|
3638
|
-
if (!_hasClass(media, defaults.classes.hook)) {
|
3639
|
-
players.push({
|
3640
|
-
// Always wrap in a <div> for styling
|
3641
|
-
//container: _wrap(media, document.createElement('div')),
|
3642
|
-
// Could be a container or the media itself
|
3643
|
-
target: target,
|
3644
|
-
// This should be the <video>, <audio> or <div> (YouTube/Vimeo)
|
3645
|
-
media: media
|
3646
|
-
});
|
3647
|
-
}
|
3648
|
-
}
|
3649
|
-
|
3650
|
-
// Check if the targets have multiple media elements
|
3651
|
-
for (var i = 0; i < targets.length; i++) {
|
3652
|
-
var target = targets[i];
|
3653
|
-
|
3654
|
-
// Get children
|
3655
|
-
var children = target.querySelectorAll(selector);
|
3656
|
-
|
3657
|
-
// If there's more than one media element child, wrap them
|
3658
|
-
if (children.length) {
|
3659
|
-
for (var x = 0; x < children.length; x++) {
|
3660
|
-
add(target, children[x]);
|
3661
|
-
}
|
3662
|
-
} else if (_matches(target, selector)) {
|
3663
|
-
// Target is media element
|
3664
|
-
add(target, target);
|
3665
|
-
}
|
3666
|
-
}
|
3667
|
-
|
3668
|
-
// Create a player instance for each element
|
3669
|
-
players.forEach(function(player) {
|
3670
|
-
var element = player.target,
|
3671
|
-
media = player.media,
|
3672
|
-
match = false;
|
3673
|
-
|
3674
|
-
// The target element can also be the media element
|
3675
|
-
if (media === element) {
|
3676
|
-
match = true;
|
3677
|
-
}
|
3678
|
-
|
3679
|
-
// Setup a player instance and add to the element
|
3680
|
-
// Create instance-specific config
|
3681
|
-
var data = {};
|
3682
|
-
|
3683
|
-
// Try parsing data attribute config
|
3684
|
-
try { data = JSON.parse(element.getAttribute('data-plyr')); }
|
3685
|
-
catch(e) { }
|
3686
|
-
|
3687
|
-
var config = _extend({}, defaults, options, data);
|
3688
|
-
|
3689
|
-
// Bail if not enabled
|
3690
|
-
if (!config.enabled) {
|
3691
|
-
return null;
|
3692
|
-
}
|
3693
|
-
|
3694
|
-
// Create new instance
|
3695
|
-
var instance = new Plyr(media, config);
|
3696
|
-
|
3697
|
-
// Go to next if setup failed
|
3698
|
-
if (!_is.object(instance)) {
|
3699
|
-
return;
|
3700
|
-
}
|
3701
|
-
|
3702
|
-
// Listen for events if debugging
|
3703
|
-
if (config.debug) {
|
3704
|
-
var events = config.events.concat(['setup', 'statechange', 'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled']);
|
3705
|
-
|
3706
|
-
_on(instance.getContainer(), events.join(' '), function(event) {
|
3707
|
-
console.log([config.logPrefix, 'event:', event.type].join(' '), event.detail.plyr);
|
3708
|
-
});
|
3709
|
-
}
|
3710
|
-
|
3711
|
-
// Callback
|
3712
|
-
_event(instance.getContainer(), 'setup', true, {
|
3713
|
-
plyr: instance
|
3714
|
-
});
|
3715
|
-
|
3716
|
-
// Add to return array even if it's already setup
|
3717
|
-
instances.push(instance);
|
3718
|
-
});
|
3719
|
-
|
3720
|
-
return instances;
|
3721
|
-
}
|
3722
|
-
|
3723
|
-
// Get all instances within a provided container
|
3724
|
-
function get(container) {
|
3725
|
-
if (_is.string(container)) {
|
3726
|
-
// Get selector if string passed
|
3727
|
-
container = document.querySelector(container);
|
3728
|
-
} else if (_is.undefined(container)) {
|
3729
|
-
// Use body by default to get all on page
|
3730
|
-
container = document.body;
|
3731
|
-
}
|
3732
|
-
|
3733
|
-
// If we have a HTML element
|
3734
|
-
if (_is.htmlElement(container)) {
|
3735
|
-
var elements = container.querySelectorAll('.' + defaults.classes.setup),
|
3736
|
-
instances = [];
|
3737
|
-
|
3738
|
-
Array.prototype.slice.call(elements).forEach(function(element) {
|
3739
|
-
if (_is.object(element.plyr)) {
|
3740
|
-
instances.push(element.plyr);
|
3741
|
-
}
|
3742
|
-
});
|
3743
|
-
|
3744
|
-
return instances;
|
3745
|
-
}
|
3746
|
-
|
3747
|
-
return [];
|
3748
|
-
}
|
3749
|
-
|
3750
|
-
return {
|
3751
|
-
setup: setup,
|
3752
|
-
supported: supported,
|
3753
|
-
loadSprite: loadSprite,
|
3754
|
-
get: get
|
3755
|
-
};
|
3756
|
-
}));
|
3757
|
-
|
3758
|
-
// Custom event polyfill
|
3759
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
|
3760
|
-
(function () {
|
3761
|
-
if (typeof window.CustomEvent === 'function') {
|
3762
|
-
return;
|
3763
|
-
}
|
3764
|
-
|
3765
|
-
function CustomEvent(event, params) {
|
3766
|
-
params = params || { bubbles: false, cancelable: false, detail: undefined };
|
3767
|
-
var evt = document.createEvent('CustomEvent');
|
3768
|
-
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
|
3769
|
-
return evt;
|
3770
|
-
}
|
3771
|
-
|
3772
|
-
CustomEvent.prototype = window.Event.prototype;
|
3773
|
-
|
3774
|
-
window.CustomEvent = CustomEvent;
|
3775
|
-
})();
|
1
|
+
!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=t(e,document):"function"==typeof define&&define.amd?define([],function(){return t(e,document)}):e.plyr=t(e,document)}("undefined"!=typeof window?window:this,function(e,t){"use strict";function n(){var e,n,r,a=navigator.userAgent,s=navigator.appName,o=""+parseFloat(navigator.appVersion),i=parseInt(navigator.appVersion,10),l=!1,u=!1,c=!1,d=!1;return navigator.appVersion.indexOf("Windows NT")!==-1&&navigator.appVersion.indexOf("rv:11")!==-1?(l=!0,s="IE",o="11"):(n=a.indexOf("MSIE"))!==-1?(l=!0,s="IE",o=a.substring(n+5)):(n=a.indexOf("Chrome"))!==-1?(c=!0,s="Chrome",o=a.substring(n+7)):(n=a.indexOf("Safari"))!==-1?(d=!0,s="Safari",o=a.substring(n+7),(n=a.indexOf("Version"))!==-1&&(o=a.substring(n+8))):(n=a.indexOf("Firefox"))!==-1?(u=!0,s="Firefox",o=a.substring(n+8)):(e=a.lastIndexOf(" ")+1)<(n=a.lastIndexOf("/"))&&(s=a.substring(e,n),o=a.substring(n+1),s.toLowerCase()===s.toUpperCase()&&(s=navigator.appName)),(r=o.indexOf(";"))!==-1&&(o=o.substring(0,r)),(r=o.indexOf(" "))!==-1&&(o=o.substring(0,r)),i=parseInt(""+o,10),isNaN(i)&&(o=""+parseFloat(navigator.appVersion),i=parseInt(navigator.appVersion,10)),{name:s,version:i,isIE:l,isFirefox:u,isChrome:c,isSafari:d,isIos:/(iPad|iPhone|iPod)/g.test(navigator.platform),isIphone:/(iPhone|iPod)/g.test(navigator.userAgent),isTouch:"ontouchstart"in t.documentElement}}function r(e,t){var n=e.media;if("video"===e.type)switch(t){case"video/webm":return!(!n.canPlayType||!n.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/,""));case"video/mp4":return!(!n.canPlayType||!n.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/,""));case"video/ogg":return!(!n.canPlayType||!n.canPlayType('video/ogg; codecs="theora"').replace(/no/,""))}else if("audio"===e.type)switch(t){case"audio/mpeg":return!(!n.canPlayType||!n.canPlayType("audio/mpeg;").replace(/no/,""));case"audio/ogg":return!(!n.canPlayType||!n.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/,""));case"audio/wav":return!(!n.canPlayType||!n.canPlayType('audio/wav; codecs="1"').replace(/no/,""))}return!1}function a(e){if(!t.querySelectorAll('script[src="'+e+'"]').length){var n=t.createElement("script");n.src=e;var r=t.getElementsByTagName("script")[0];r.parentNode.insertBefore(n,r)}}function s(e,t){return Array.prototype.indexOf&&e.indexOf(t)!==-1}function o(e,t,n){return e.replace(new RegExp(t.replace(/([.*+?\^=!:${}()|\[\]\/\\])/g,"\\$1"),"g"),n)}function i(e,t){e.length||(e=[e]);for(var n=e.length-1;n>=0;n--){var r=n>0?t.cloneNode(!0):t,a=e[n],s=a.parentNode,o=a.nextSibling;return r.appendChild(a),o?s.insertBefore(r,o):s.appendChild(r),r}}function l(e){e&&e.parentNode.removeChild(e)}function u(e,t){e.insertBefore(t,e.firstChild)}function c(e,t){for(var n in t)e.setAttribute(n,O.boolean(t[n])&&t[n]?"":t[n])}function d(e,n,r){var a=t.createElement(e);c(a,r),u(n,a)}function p(e){return e.replace(".","")}function m(e,t,n){if(e)if(e.classList)e.classList[n?"add":"remove"](t);else{var r=(" "+e.className+" ").replace(/\s+/g," ").replace(" "+t+" ","");e.className=r+(n?" "+t:"")}}function f(e,t){return!!e&&(e.classList?e.classList.contains(t):new RegExp("(\\s|^)"+t+"(\\s|$)").test(e.className))}function y(e,n){var r=Element.prototype,a=r.matches||r.webkitMatchesSelector||r.mozMatchesSelector||r.msMatchesSelector||function(e){return[].indexOf.call(t.querySelectorAll(e),this)!==-1};return a.call(e,n)}function b(e,t,n,r,a){g(e,t,function(t){n&&n.apply(e,[t]),r.apply(e,[t])},a)}function v(e,t,n,r,a){var s=t.split(" ");if(O.boolean(a)||(a=!1),e instanceof NodeList)for(var o=0;o<e.length;o++)e[o]instanceof Node&&v(e[o],arguments[1],arguments[2],arguments[3]);else for(var i=0;i<s.length;i++)e[r?"addEventListener":"removeEventListener"](s[i],n,a)}function g(e,t,n,r){e&&v(e,t,n,!0,r)}function h(e,t,n,r){if(e&&t){O.boolean(n)||(n=!1);var a=new CustomEvent(t,{bubbles:n,detail:r});e.dispatchEvent(a)}}function k(e,t){if(e)return t=O.boolean(t)?t:!e.getAttribute("aria-pressed"),e.setAttribute("aria-pressed",t),t}function w(e,t){return 0===e||0===t||isNaN(e)||isNaN(t)?0:(e/t*100).toFixed(2)}function x(){var e=arguments;if(e.length){if(1===e.length)return e[0];for(var t=Array.prototype.shift.call(e),n=e.length,r=0;r<n;r++){var a=e[r];for(var s in a)a[s]&&a[s].constructor&&a[s].constructor===Object?(t[s]=t[s]||{},x(t[s],a[s])):t[s]=a[s]}return t}}function T(e){var t=/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;return e.match(t)?RegExp.$2:e}function S(e){var t=/^.*(vimeo.com\/|video\/)(\d+).*/;return e.match(t)?RegExp.$2:e}function _(){var e={supportsFullScreen:!1,isFullScreen:function(){return!1},requestFullScreen:function(){},cancelFullScreen:function(){},fullScreenEventName:"",element:null,prefix:""},n="webkit o moz ms khtml".split(" ");if(O.undefined(t.cancelFullScreen))for(var r=0,a=n.length;r<a;r++){if(e.prefix=n[r],!O.undefined(t[e.prefix+"CancelFullScreen"])){e.supportsFullScreen=!0;break}if(!O.undefined(t.msExitFullscreen)&&t.msFullscreenEnabled){e.prefix="ms",e.supportsFullScreen=!0;break}}else e.supportsFullScreen=!0;return e.supportsFullScreen&&(e.fullScreenEventName="ms"===e.prefix?"MSFullscreenChange":e.prefix+"fullscreenchange",e.isFullScreen=function(e){switch(O.undefined(e)&&(e=t.body),this.prefix){case"":return t.fullscreenElement===e;case"moz":return t.mozFullScreenElement===e;default:return t[this.prefix+"FullscreenElement"]===e}},e.requestFullScreen=function(e){return O.undefined(e)&&(e=t.body),""===this.prefix?e.requestFullScreen():e[this.prefix+("ms"===this.prefix?"RequestFullscreen":"RequestFullScreen")]()},e.cancelFullScreen=function(){return""===this.prefix?t.cancelFullScreen():t[this.prefix+("ms"===this.prefix?"ExitFullscreen":"CancelFullScreen")]()},e.element=function(){return""===this.prefix?t.fullscreenElement:t[this.prefix+"FullscreenElement"]}),e}function E(v,E){function A(e,t,n,r){h(e,t,n,x({},r,{plyr:Be}))}function j(t,n){E.debug&&e.console&&(n=Array.prototype.slice.call(n),O.string(E.logPrefix)&&E.logPrefix.length&&n.unshift(E.logPrefix),console[t].apply(console,n))}function V(){return{url:E.iconUrl,absolute:0===E.iconUrl.indexOf("http")||Ue.browser.isIE}}function R(){var e=[],t=V(),n=(t.absolute?"":t.url)+"#"+E.iconPrefix;return s(E.controls,"play-large")&&e.push('<button type="button" data-plyr="play" class="plyr__play-large">','<svg><use xlink:href="'+n+'-play" /></svg>','<span class="plyr__sr-only">'+E.i18n.play+"</span>","</button>"),e.push('<div class="plyr__controls">'),s(E.controls,"restart")&&e.push('<button type="button" data-plyr="restart">','<svg><use xlink:href="'+n+'-restart" /></svg>','<span class="plyr__sr-only">'+E.i18n.restart+"</span>","</button>"),s(E.controls,"rewind")&&e.push('<button type="button" data-plyr="rewind">','<svg><use xlink:href="'+n+'-rewind" /></svg>','<span class="plyr__sr-only">'+E.i18n.rewind+"</span>","</button>"),s(E.controls,"play")&&e.push('<button type="button" data-plyr="play">','<svg><use xlink:href="'+n+'-play" /></svg>','<span class="plyr__sr-only">'+E.i18n.play+"</span>","</button>",'<button type="button" data-plyr="pause">','<svg><use xlink:href="'+n+'-pause" /></svg>','<span class="plyr__sr-only">'+E.i18n.pause+"</span>","</button>"),s(E.controls,"fast-forward")&&e.push('<button type="button" data-plyr="fast-forward">','<svg><use xlink:href="'+n+'-fast-forward" /></svg>','<span class="plyr__sr-only">'+E.i18n.forward+"</span>","</button>"),s(E.controls,"progress")&&(e.push('<span class="plyr__progress">','<label for="seek{id}" class="plyr__sr-only">Seek</label>','<input id="seek{id}" class="plyr__progress--seek" type="range" min="0" max="100" step="0.1" value="0" data-plyr="seek">','<progress class="plyr__progress--played" max="100" value="0" role="presentation"></progress>','<progress class="plyr__progress--buffer" max="100" value="0">',"<span>0</span>% "+E.i18n.buffered,"</progress>"),E.tooltips.seek&&e.push('<span class="plyr__tooltip">00:00</span>'),e.push("</span>")),s(E.controls,"current-time")&&e.push('<span class="plyr__time">','<span class="plyr__sr-only">'+E.i18n.currentTime+"</span>",'<span class="plyr__time--current">00:00</span>',"</span>"),s(E.controls,"duration")&&e.push('<span class="plyr__time">','<span class="plyr__sr-only">'+E.i18n.duration+"</span>",'<span class="plyr__time--duration">00:00</span>',"</span>"),s(E.controls,"mute")&&e.push('<button type="button" data-plyr="mute">','<svg class="icon--muted"><use xlink:href="'+n+'-muted" /></svg>','<svg><use xlink:href="'+n+'-volume" /></svg>','<span class="plyr__sr-only">'+E.i18n.toggleMute+"</span>","</button>"),s(E.controls,"volume")&&e.push('<span class="plyr__volume">','<label for="volume{id}" class="plyr__sr-only">'+E.i18n.volume+"</label>",'<input id="volume{id}" class="plyr__volume--input" type="range" min="'+E.volumeMin+'" max="'+E.volumeMax+'" value="'+E.volume+'" data-plyr="volume">','<progress class="plyr__volume--display" max="'+E.volumeMax+'" value="'+E.volumeMin+'" role="presentation"></progress>',"</span>"),s(E.controls,"captions")&&e.push('<button type="button" data-plyr="captions">','<svg class="icon--captions-on"><use xlink:href="'+n+'-captions-on" /></svg>','<svg><use xlink:href="'+n+'-captions-off" /></svg>','<span class="plyr__sr-only">'+E.i18n.toggleCaptions+"</span>","</button>"),s(E.controls,"fullscreen")&&e.push('<button type="button" data-plyr="fullscreen">','<svg class="icon--exit-fullscreen"><use xlink:href="'+n+'-exit-fullscreen" /></svg>','<svg><use xlink:href="'+n+'-enter-fullscreen" /></svg>','<span class="plyr__sr-only">'+E.i18n.toggleFullscreen+"</span>","</button>"),e.push("</div>"),e.join("")}function q(){if(Ue.supported.full&&("audio"!==Ue.type||E.fullscreen.allowAudio)&&E.fullscreen.enabled){var e=N.supportsFullScreen;e||E.fullscreen.fallback&&!X()?(Je((e?"Native":"Fallback")+" fullscreen enabled"),m(Ue.container,E.classes.fullscreen.enabled,!0)):Je("Fullscreen not supported and fallback disabled"),Ue.buttons&&Ue.buttons.fullscreen&&k(Ue.buttons.fullscreen,!1),$()}}function D(){if("video"===Ue.type){U(E.selectors.captions)||Ue.videoContainer.insertAdjacentHTML("afterbegin",'<div class="'+p(E.selectors.captions)+'"></div>'),Ue.usingTextTracks=!1,Ue.media.textTracks&&(Ue.usingTextTracks=!0);for(var e,t="",n=Ue.media.childNodes,r=0;r<n.length;r++)"track"===n[r].nodeName.toLowerCase()&&(e=n[r].kind,"captions"!==e&&"subtitles"!==e||(t=n[r].getAttribute("src")));if(Ue.captionExists=!0,""===t?(Ue.captionExists=!1,Je("No caption track found")):Je("Caption track found; URI: "+t),Ue.captionExists){for(var a=Ue.media.textTracks,s=0;s<a.length;s++)a[s].mode="hidden";if(Y(Ue),(Ue.browser.isIE&&Ue.browser.version>=10||Ue.browser.isFirefox&&Ue.browser.version>=31)&&(Je("Detected browser with known TextTrack issues - using manual fallback"),Ue.usingTextTracks=!1),Ue.usingTextTracks){Je("TextTracks supported");for(var o=0;o<a.length;o++){var i=a[o];"captions"!==i.kind&&"subtitles"!==i.kind||g(i,"cuechange",function(){this.activeCues[0]&&"text"in this.activeCues[0]?H(this.activeCues[0].getCueAsHTML()):H()})}}else if(Je("TextTracks not supported so rendering captions manually"),Ue.currentCaption="",Ue.captions=[],""!==t){var l=new XMLHttpRequest;l.onreadystatechange=function(){if(4===l.readyState)if(200===l.status){var e,t=[],n=l.responseText,r="\r\n";n.indexOf(r+r)===-1&&(r=n.indexOf("\r\r")!==-1?"\r":"\n"),t=n.split(r+r);for(var a=0;a<t.length;a++){e=t[a],Ue.captions[a]=[];var s=e.split(r),o=0;s[o].indexOf(":")===-1&&(o=1),Ue.captions[a]=[s[o],s[o+1]]}Ue.captions.shift(),Je("Successfully loaded the caption file via AJAX")}else ze(E.logPrefix+"There was a problem loading the caption file via AJAX")},l.open("get",t,!0),l.send()}}else m(Ue.container,E.classes.captions.enabled)}}function H(e){var n=U(E.selectors.captions),r=t.createElement("span");n.innerHTML="",O.undefined(e)&&(e=""),O.string(e)?r.innerHTML=e.trim():r.appendChild(e),n.appendChild(r);n.offsetHeight}function W(e){function t(e,t){var n=[];n=e.split(" --> ");for(var r=0;r<n.length;r++)n[r]=n[r].replace(/(\d+:\d+:\d+\.\d+).*/,"$1");return a(n[t])}function n(e){return t(e,0)}function r(e){return t(e,1)}function a(e){if(null===e||void 0===e)return 0;var t,n=[],r=[];return n=e.split(","),r=n[0].split(":"),t=Math.floor(60*r[0]*60)+Math.floor(60*r[1])+Math.floor(r[2])}if(!Ue.usingTextTracks&&"video"===Ue.type&&Ue.supported.full&&(Ue.subcount=0,e=O.number(e)?e:Ue.media.currentTime,Ue.captions[Ue.subcount])){for(;r(Ue.captions[Ue.subcount][0])<e.toFixed(1);)if(Ue.subcount++,Ue.subcount>Ue.captions.length-1){Ue.subcount=Ue.captions.length-1;break}Ue.media.currentTime.toFixed(1)>=n(Ue.captions[Ue.subcount][0])&&Ue.media.currentTime.toFixed(1)<=r(Ue.captions[Ue.subcount][0])?(Ue.currentCaption=Ue.captions[Ue.subcount][1],H(Ue.currentCaption)):H()}}function Y(){if(Ue.buttons.captions){m(Ue.container,E.classes.captions.enabled,!0);var e=Ue.storage.captionsEnabled;O.boolean(e)||(e=E.captions.defaultActive),e&&(m(Ue.container,E.classes.captions.active,!0),k(Ue.buttons.captions,!0))}}function B(e){return Ue.container.querySelectorAll(e)}function U(e){return B(e)[0]}function X(){try{return e.self!==e.top}catch(e){return!0}}function $(){function e(e){9===e.which&&Ue.isFullscreen&&(e.target!==r||e.shiftKey?e.target===n&&e.shiftKey&&(e.preventDefault(),r.focus()):(e.preventDefault(),n.focus()))}var t=B("input:not([disabled]), button:not([disabled])"),n=t[0],r=t[t.length-1];g(Ue.container,"keydown",e)}function J(e,t){if(O.string(t))d(e,Ue.media,{src:t});else if(t.constructor===Array)for(var n=t.length-1;n>=0;n--)d(e,Ue.media,t[n])}function z(){if(E.loadSprite){var e=V();e.absolute?(Je("AJAX loading absolute SVG sprite"+(Ue.browser.isIE?" (due to IE)":"")),C(e.url,"sprite-plyr")):Je("Sprite will be used as external resource directly")}var n=E.html;Je("Injecting custom controls"),n||(n=R()),n=o(n,"{seektime}",E.seekTime),n=o(n,"{id}",Math.floor(1e4*Math.random()));var r;if(O.string(E.selectors.controls.container)&&(r=t.querySelector(E.selectors.controls.container)),O.htmlElement(r)||(r=Ue.container),r.insertAdjacentHTML("beforeend",n),E.tooltips.controls)for(var a=B([E.selectors.controls.wrapper," ",E.selectors.labels," .",E.classes.hidden].join("")),s=a.length-1;s>=0;s--){var i=a[s];m(i,E.classes.hidden,!1),m(i,E.classes.tooltip,!0)}}function G(){try{return Ue.controls=U(E.selectors.controls.wrapper),Ue.buttons={},Ue.buttons.seek=U(E.selectors.buttons.seek),Ue.buttons.play=B(E.selectors.buttons.play),Ue.buttons.pause=U(E.selectors.buttons.pause),Ue.buttons.restart=U(E.selectors.buttons.restart),Ue.buttons.rewind=U(E.selectors.buttons.rewind),Ue.buttons.forward=U(E.selectors.buttons.forward),Ue.buttons.fullscreen=U(E.selectors.buttons.fullscreen),Ue.buttons.mute=U(E.selectors.buttons.mute),Ue.buttons.captions=U(E.selectors.buttons.captions),Ue.progress={},Ue.progress.container=U(E.selectors.progress.container),Ue.progress.buffer={},Ue.progress.buffer.bar=U(E.selectors.progress.buffer),Ue.progress.buffer.text=Ue.progress.buffer.bar&&Ue.progress.buffer.bar.getElementsByTagName("span")[0],Ue.progress.played=U(E.selectors.progress.played),Ue.progress.tooltip=Ue.progress.container&&Ue.progress.container.querySelector("."+E.classes.tooltip),Ue.volume={},Ue.volume.input=U(E.selectors.volume.input),Ue.volume.display=U(E.selectors.volume.display),Ue.duration=U(E.selectors.duration),Ue.currentTime=U(E.selectors.currentTime),Ue.seekTime=B(E.selectors.seekTime),!0}catch(e){return ze("It looks like there is a problem with your controls HTML"),Q(!0),!1}}function K(){m(Ue.container,E.selectors.container.replace(".",""),Ue.supported.full)}function Q(e){e&&s(E.types.html5,Ue.type)?Ue.media.setAttribute("controls",""):Ue.media.removeAttribute("controls")}function Z(e){var t=E.i18n.play;if(O.string(E.title)&&E.title.length&&(t+=", "+E.title,Ue.container.setAttribute("aria-label",E.title)),Ue.supported.full&&Ue.buttons.play)for(var n=Ue.buttons.play.length-1;n>=0;n--)Ue.buttons.play[n].setAttribute("aria-label",t);O.htmlElement(e)&&e.setAttribute("title",E.i18n.frameTitle.replace("{title}",E.title))}function ee(){var t=null;Ue.storage={},L.supported&&E.storage.enabled&&(e.localStorage.removeItem("plyr-volume"),t=e.localStorage.getItem(E.storage.key),t&&(/^\d+(\.\d+)?$/.test(t)?te({volume:parseFloat(t)}):Ue.storage=JSON.parse(t)))}function te(t){L.supported&&E.storage.enabled&&(x(Ue.storage,t),e.localStorage.setItem(E.storage.key,JSON.stringify(Ue.storage)))}function ne(){if(!Ue.media)return void ze("No media element found!");if(Ue.supported.full&&(m(Ue.container,E.classes.type.replace("{0}",Ue.type),!0),s(E.types.embed,Ue.type)&&m(Ue.container,E.classes.type.replace("{0}","video"),!0),m(Ue.container,E.classes.stopped,E.autoplay),m(Ue.ontainer,E.classes.isIos,Ue.browser.isIos),m(Ue.container,E.classes.isTouch,Ue.browser.isTouch),"video"===Ue.type)){var e=t.createElement("div");e.setAttribute("class",E.classes.videoWrapper),i(Ue.media,e),Ue.videoContainer=e}s(E.types.embed,Ue.type)&&re()}function re(){var n,r=t.createElement("div"),s=Ue.type+"-"+Math.floor(1e4*Math.random());switch(Ue.type){case"youtube":n=T(Ue.embedId);break;case"vimeo":n=S(Ue.embedId);break;default:n=Ue.embedId}for(var o=B('[id^="'+Ue.type+'-"]'),i=o.length-1;i>=0;i--)l(o[i]);if(m(Ue.media,E.classes.videoWrapper,!0),m(Ue.media,E.classes.embedWrapper,!0),"youtube"===Ue.type)Ue.media.appendChild(r),r.setAttribute("id",s),O.object(e.YT)?se(n,r):(a(E.urls.youtube.api),e.onYouTubeReadyCallbacks=e.onYouTubeReadyCallbacks||[],e.onYouTubeReadyCallbacks.push(function(){se(n,r)}),e.onYouTubeIframeAPIReady=function(){e.onYouTubeReadyCallbacks.forEach(function(e){e()})});else if("vimeo"===Ue.type)if(Ue.supported.full?Ue.media.appendChild(r):r=Ue.media,r.setAttribute("id",s),O.object(e.Vimeo))oe(n,r);else{a(E.urls.vimeo.api);var u=e.setInterval(function(){O.object(e.Vimeo)&&(e.clearInterval(u),oe(n,r))},50)}else if("soundcloud"===Ue.type){var d=t.createElement("iframe");d.loaded=!1,g(d,"load",function(){d.loaded=!0}),c(d,{src:"https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/"+n,id:s}),r.appendChild(d),Ue.media.appendChild(r),e.SC||a(E.urls.soundcloud.api);var p=e.setInterval(function(){e.SC&&d.loaded&&(e.clearInterval(p),ie.call(d))},50)}}function ae(){Ue.supported.full&&(We(),Ye()),Z(U("iframe"))}function se(t,n){Ue.embed=new e.YT.Player(n.id,{videoId:t,playerVars:{autoplay:E.autoplay?1:0,controls:Ue.supported.full?0:1,rel:0,showinfo:0,iv_load_policy:3,cc_load_policy:E.captions.defaultActive?1:0,cc_lang_pref:"en",wmode:"transparent",modestbranding:1,disablekb:1,origin:"*"},events:{onError:function(e){A(Ue.container,"error",!0,{code:e.data,embed:e.target})},onReady:function(t){var n=t.target;Ue.media.play=function(){n.playVideo(),Ue.media.paused=!1},Ue.media.pause=function(){n.pauseVideo(),Ue.media.paused=!0},Ue.media.stop=function(){n.stopVideo(),Ue.media.paused=!0},Ue.media.duration=n.getDuration(),Ue.media.paused=!0,Ue.media.currentTime=0,Ue.media.muted=n.isMuted(),E.title=n.getVideoData().title,Ue.supported.full&&Ue.media.querySelector("iframe").setAttribute("tabindex","-1"),ae(),A(Ue.media,"timeupdate"),A(Ue.media,"durationchange"),e.clearInterval(Xe.buffering),Xe.buffering=e.setInterval(function(){Ue.media.buffered=n.getVideoLoadedFraction(),(null===Ue.media.lastBuffered||Ue.media.lastBuffered<Ue.media.buffered)&&A(Ue.media,"progress"),Ue.media.lastBuffered=Ue.media.buffered,1===Ue.media.buffered&&(e.clearInterval(Xe.buffering),A(Ue.media,"canplaythrough"))},200)},onStateChange:function(t){var n=t.target;switch(e.clearInterval(Xe.playing),t.data){case 0:Ue.media.paused=!0,A(Ue.media,"ended");break;case 1:Ue.media.paused=!1,Ue.media.seeking&&A(Ue.media,"seeked"),Ue.media.seeking=!1,A(Ue.media,"play"),A(Ue.media,"playing"),Xe.playing=e.setInterval(function(){Ue.media.currentTime=n.getCurrentTime(),A(Ue.media,"timeupdate")},100),Ue.media.duration!==n.getDuration()&&(Ue.media.duration=n.getDuration(),A(Ue.media,"durationchange"));break;case 2:Ue.media.paused=!0,A(Ue.media,"pause")}A(Ue.container,"statechange",!1,{code:t.data})}}})}function oe(t,n){Ue.embed=new e.Vimeo.Player(n,{id:parseInt(t),loop:E.loop,autoplay:E.autoplay,byline:!1,portrait:!1,title:!1}),Ue.media.play=function(){Ue.embed.play(),Ue.media.paused=!1},Ue.media.pause=function(){Ue.embed.pause(),Ue.media.paused=!0},Ue.media.stop=function(){Ue.embed.stop(),Ue.media.paused=!0},Ue.media.paused=!0,Ue.media.currentTime=0,ae(),Ue.embed.getCurrentTime().then(function(e){Ue.media.currentTime=e,A(Ue.media,"timeupdate")}),Ue.embed.getDuration().then(function(e){Ue.media.duration=e,A(Ue.media,"durationchange")}),Ue.embed.on("loaded",function(){O.htmlElement(Ue.embed.element)&&Ue.supported.full&&Ue.embed.element.setAttribute("tabindex","-1")}),Ue.embed.on("play",function(){Ue.media.paused=!1,A(Ue.media,"play"),A(Ue.media,"playing")}),Ue.embed.on("pause",function(){Ue.media.paused=!0,A(Ue.media,"pause")}),Ue.embed.on("timeupdate",function(e){Ue.media.seeking=!1,Ue.media.currentTime=e.seconds,A(Ue.media,"timeupdate")}),Ue.embed.on("progress",function(e){Ue.media.buffered=e.percent,A(Ue.media,"progress"),1===parseInt(e.percent)&&A(Ue.media,"canplaythrough")}),Ue.embed.on("seeked",function(){Ue.media.seeking=!1,A(Ue.media,"seeked"),A(Ue.media,"play")}),Ue.embed.on("ended",function(){Ue.media.paused=!0,A(Ue.media,"ended")})}function ie(){Ue.embed=e.SC.Widget(this),Ue.embed.bind(e.SC.Widget.Events.READY,function(){Ue.media.play=function(){Ue.embed.play(),Ue.media.paused=!1},Ue.media.pause=function(){Ue.embed.pause(),Ue.media.paused=!0},Ue.media.stop=function(){Ue.embed.seekTo(0),Ue.embed.pause(),Ue.media.paused=!0},Ue.media.paused=!0,Ue.media.currentTime=0,Ue.embed.getDuration(function(e){Ue.media.duration=e/1e3,ae()}),Ue.embed.getPosition(function(e){Ue.media.currentTime=e,A(Ue.media,"timeupdate")}),Ue.embed.bind(e.SC.Widget.Events.PLAY,function(){Ue.media.paused=!1,A(Ue.media,"play"),A(Ue.media,"playing")}),Ue.embed.bind(e.SC.Widget.Events.PAUSE,function(){Ue.media.paused=!0,A(Ue.media,"pause")}),Ue.embed.bind(e.SC.Widget.Events.PLAY_PROGRESS,function(e){Ue.media.seeking=!1,Ue.media.currentTime=e.currentPosition/1e3,A(Ue.media,"timeupdate")}),Ue.embed.bind(e.SC.Widget.Events.LOAD_PROGRESS,function(e){Ue.media.buffered=e.loadProgress,A(Ue.media,"progress"),1===parseInt(e.loadProgress)&&A(Ue.media,"canplaythrough")}),Ue.embed.bind(e.SC.Widget.Events.FINISH,function(){Ue.media.paused=!0,A(Ue.media,"ended")})})}function le(){"play"in Ue.media&&Ue.media.play()}function ue(){"pause"in Ue.media&&Ue.media.pause()}function ce(e){return O.boolean(e)||(e=Ue.media.paused),e?le():ue(),e}function de(e){O.number(e)||(e=E.seekTime),me(Ue.media.currentTime-e)}function pe(e){O.number(e)||(e=E.seekTime),me(Ue.media.currentTime+e)}function me(e){var t=0,n=Ue.media.paused,r=fe();O.number(e)?t=e:O.object(e)&&s(["input","change"],e.type)&&(t=e.target.value/e.target.max*r),t<0?t=0:t>r&&(t=r),Ne(t);try{Ue.media.currentTime=t.toFixed(4)}catch(e){}if(s(E.types.embed,Ue.type)){switch(Ue.type){case"youtube":Ue.embed.seekTo(t);break;case"vimeo":Ue.embed.setCurrentTime(t.toFixed(0));break;case"soundcloud":Ue.embed.seekTo(1e3*t)}n&&ue(),A(Ue.media,"timeupdate"),Ue.media.seeking=!0,A(Ue.media,"seeking")}Je("Seeking to "+Ue.media.currentTime+" seconds"),W(t)}function fe(){var e=parseInt(E.duration),t=0;return null===Ue.media.duration||isNaN(Ue.media.duration)||(t=Ue.media.duration),isNaN(e)?t:e}function ye(){m(Ue.container,E.classes.playing,!Ue.media.paused),m(Ue.container,E.classes.stopped,Ue.media.paused),Me(Ue.media.paused)}function be(){P={x:e.pageXOffset||0,y:e.pageYOffset||0}}function ve(){e.scrollTo(P.x,P.y)}function ge(e){var n=N.supportsFullScreen;if(n){if(!e||e.type!==N.fullScreenEventName)return N.isFullScreen(Ue.container)?N.cancelFullScreen():(be(),N.requestFullScreen(Ue.container)),void(Ue.isFullscreen=N.isFullScreen(Ue.container));Ue.isFullscreen=N.isFullScreen(Ue.container)}else Ue.isFullscreen=!Ue.isFullscreen,t.body.style.overflow=Ue.isFullscreen?"hidden":"";m(Ue.container,E.classes.fullscreen.active,Ue.isFullscreen),$(Ue.isFullscreen),Ue.buttons&&Ue.buttons.fullscreen&&k(Ue.buttons.fullscreen,Ue.isFullscreen),A(Ue.container,Ue.isFullscreen?"enterfullscreen":"exitfullscreen",!0),!Ue.isFullscreen&&n&&ve()}function he(e){if(O.boolean(e)||(e=!Ue.media.muted),k(Ue.buttons.mute,e),Ue.media.muted=e,0===Ue.media.volume&&ke(E.volume),s(E.types.embed,Ue.type)){switch(Ue.type){case"youtube":Ue.embed[Ue.media.muted?"mute":"unMute"]();break;case"vimeo":case"soundcloud":Ue.embed.setVolume(Ue.media.muted?0:parseFloat(E.volume/E.volumeMax))}A(Ue.media,"volumechange")}}function ke(e){var t=E.volumeMax,n=E.volumeMin;if(O.undefined(e)&&(e=Ue.storage.volume),(null===e||isNaN(e))&&(e=E.volume),e>t&&(e=t),e<n&&(e=n),Ue.media.volume=parseFloat(e/t),Ue.volume.display&&(Ue.volume.display.value=e),s(E.types.embed,Ue.type)){switch(Ue.type){case"youtube":Ue.embed.setVolume(100*Ue.media.volume);break;case"vimeo":case"soundcloud":Ue.embed.setVolume(Ue.media.volume)}A(Ue.media,"volumechange")}0===e?Ue.media.muted=!0:Ue.media.muted&&e>0&&he()}function we(e){var t=Ue.media.muted?0:Ue.media.volume*E.volumeMax;O.number(e)||(e=E.volumeStep),ke(t+e)}function xe(e){var t=Ue.media.muted?0:Ue.media.volume*E.volumeMax;O.number(e)||(e=E.volumeStep),ke(t-e)}function Te(){var e=Ue.media.muted?0:Ue.media.volume*E.volumeMax;Ue.supported.full&&(Ue.volume.input&&(Ue.volume.input.value=e),Ue.volume.display&&(Ue.volume.display.value=e)),te({volume:e}),m(Ue.container,E.classes.muted,0===e),Ue.supported.full&&Ue.buttons.mute&&k(Ue.buttons.mute,0===e)}function Se(e){Ue.supported.full&&Ue.buttons.captions&&(O.boolean(e)||(e=Ue.container.className.indexOf(E.classes.captions.active)===-1),Ue.captionsEnabled=e,k(Ue.buttons.captions,Ue.captionsEnabled),m(Ue.container,E.classes.captions.active,Ue.captionsEnabled),A(Ue.container,Ue.captionsEnabled?"captionsenabled":"captionsdisabled",!0),te({captionsEnabled:Ue.captionsEnabled}))}function _e(e){var t="waiting"===e.type;clearTimeout(Xe.loading),Xe.loading=setTimeout(function(){m(Ue.container,E.classes.loading,t),Me(t)},t?250:0)}function Ee(e){if(Ue.supported.full){var t=Ue.progress.played,n=0,r=fe();if(e)switch(e.type){case"timeupdate":case"seeking":if(Ue.controls.pressed)return;n=w(Ue.media.currentTime,r),"timeupdate"===e.type&&Ue.buttons.seek&&(Ue.buttons.seek.value=n);break;case"playing":case"progress":t=Ue.progress.buffer,n=function(){var e=Ue.media.buffered;return e&&e.length?w(e.end(0),r):O.number(e)?100*e:0}()}Ce(t,n)}}function Ce(e,t){if(Ue.supported.full){if(O.undefined(t)&&(t=0),O.undefined(e)){if(!Ue.progress||!Ue.progress.buffer)return;e=Ue.progress.buffer}O.htmlElement(e)?e.value=t:e&&(e.bar&&(e.bar.value=t),e.text&&(e.text.innerHTML=t))}}function Fe(e,t){if(t){isNaN(e)&&(e=0),Ue.secs=parseInt(e%60),Ue.mins=parseInt(e/60%60),Ue.hours=parseInt(e/60/60%60);var n=parseInt(fe()/60/60%60)>0;Ue.secs=("0"+Ue.secs).slice(-2),Ue.mins=("0"+Ue.mins).slice(-2),t.innerHTML=(n?Ue.hours+":":"")+Ue.mins+":"+Ue.secs}}function Ae(){if(Ue.supported.full){var e=fe()||0;!Ue.duration&&E.displayDuration&&Ue.media.paused&&Fe(e,Ue.currentTime),Ue.duration&&Fe(e,Ue.duration),Pe()}}function Ie(e){Fe(Ue.media.currentTime,Ue.currentTime),e&&"timeupdate"===e.type&&Ue.media.seeking||Ee(e)}function Ne(e){O.number(e)||(e=0);var t=fe(),n=w(e,t);Ue.progress&&Ue.progress.played&&(Ue.progress.played.value=n),Ue.buttons&&Ue.buttons.seek&&(Ue.buttons.seek.value=n)}function Pe(e){var t=fe();if(E.tooltips.seek&&Ue.progress.container&&0!==t){var n=Ue.progress.container.getBoundingClientRect(),r=0,a=E.classes.tooltip+"--visible";if(e)r=100/n.width*(e.pageX-n.left);else{if(!f(Ue.progress.tooltip,a))return;r=Ue.progress.tooltip.style.left.replace("%","")}r<0?r=0:r>100&&(r=100),Fe(t/100*r,Ue.progress.tooltip),Ue.progress.tooltip.style.left=r+"%",e&&s(["mouseenter","mouseleave"],e.type)&&m(Ue.progress.tooltip,a,"mouseenter"===e.type)}}function Me(t){if(E.hideControls&&"audio"!==Ue.type){var n=0,r=!1,a=t,o=f(Ue.container,E.classes.loading);if(O.boolean(t)||(t&&t.type?(r="enterfullscreen"===t.type,a=s(["mousemove","touchstart","mouseenter","focus"],t.type),s(["mousemove","touchmove"],t.type)&&(n=2e3),"focus"===t.type&&(n=3e3)):a=f(Ue.container,E.classes.hideControls)),e.clearTimeout(Xe.hover),a||Ue.media.paused||o){if(m(Ue.container,E.classes.hideControls,!1),Ue.media.paused||o)return;Ue.browser.isTouch&&(n=3e3)}a&&Ue.media.paused||(Xe.hover=e.setTimeout(function(){(!Ue.controls.pressed&&!Ue.controls.hover||r)&&m(Ue.container,E.classes.hideControls,!0)},n))}}function Oe(e){if(!O.undefined(e))return void Le(e);var t;switch(Ue.type){case"youtube":t=Ue.embed.getVideoUrl();break;case"vimeo":Ue.embed.getVideoUrl.then(function(e){t=e});break;case"soundcloud":Ue.embed.getCurrentSound(function(e){t=e.permalink_url});break;default:t=Ue.media.currentSrc}return t||""}function Le(e){function n(){if(Ue.embed=null,l(Ue.media),"video"===Ue.type&&Ue.videoContainer&&l(Ue.videoContainer),Ue.container&&Ue.container.removeAttribute("class"),"type"in e&&(Ue.type=e.type,"video"===Ue.type)){var n=e.sources[0];"type"in n&&s(E.types.embed,n.type)&&(Ue.type=n.type)}switch(Ue.supported=F(Ue.type),Ue.type){case"video":Ue.media=t.createElement("video");break;case"audio":Ue.media=t.createElement("audio");break;case"youtube":case"vimeo":case"soundcloud":Ue.media=t.createElement("div"),Ue.embedId=e.sources[0].src}u(Ue.container,Ue.media),O.boolean(e.autoplay)&&(E.autoplay=e.autoplay),s(E.types.html5,Ue.type)&&(E.crossorigin&&Ue.media.setAttribute("crossorigin",""),E.autoplay&&Ue.media.setAttribute("autoplay",""),"poster"in e&&Ue.media.setAttribute("poster",e.poster),E.loop&&Ue.media.setAttribute("loop","")),m(Ue.container,E.classes.fullscreen.active,Ue.isFullscreen),m(Ue.container,E.classes.captions.active,Ue.captionsEnabled),K(),s(E.types.html5,Ue.type)&&J("source",e.sources),ne(),s(E.types.html5,Ue.type)&&("tracks"in e&&J("track",e.tracks),Ue.media.load()),(s(E.types.html5,Ue.type)||s(E.types.embed,Ue.type)&&!Ue.supported.full)&&(We(),Ye()),E.title=e.title,Z()}return O.object(e)&&"sources"in e&&e.sources.length?(m(Ue.container,E.classes.ready,!1),ue(),Ne(),Ce(),qe(),void De(n,!1)):void ze("Invalid source format")}function je(e){"video"===Ue.type&&Ue.media.setAttribute("poster",e)}function Ve(){function n(){var e=ce(),t=Ue.buttons[e?"play":"pause"],n=Ue.buttons[e?"pause":"play"];if(n=n&&n.length>1?n[n.length-1]:n[0]){var r=f(t,E.classes.tabFocus);setTimeout(function(){n.focus(),r&&(m(t,E.classes.tabFocus,!1),m(n,E.classes.tabFocus,!0))},100)}}function r(){var e=t.activeElement;return e=e&&e!==t.body?t.querySelector(":focus"):null}function a(e){return e.keyCode?e.keyCode:e.which}function o(e){for(var t in Ue.buttons){var n=Ue.buttons[t];if(O.nodeList(n))for(var r=0;r<n.length;r++)m(n[r],E.classes.tabFocus,n[r]===e);else m(n,E.classes.tabFocus,n===e)}}function i(e){function t(){var e=Ue.media.duration;O.number(e)&&me(e/10*(n-48))}var n=a(e),r="keydown"===e.type,o=r&&n===u;if(O.number(n))if(r){var i=[48,49,50,51,52,53,54,56,57,32,75,38,40,77,39,37,70,67];switch(s(i,n)&&(e.preventDefault(),e.stopPropagation()),n){case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:o||t();break;case 32:case 75:o||ce();break;case 38:we();break;case 40:xe();break;case 77:o||he();break;case 39:pe();break;case 37:de();break;case 70:ge();break;case 67:o||Se()}!N.supportsFullScreen&&Ue.isFullscreen&&27===n&&ge(),u=n}else u=null}var l=Ue.browser.isIE?"change":"input";if(E.keyboardShorcuts.focused){var u=null;E.keyboardShorcuts.global&&g(e,"keydown keyup",function(e){var t=a(e),n=r(),o=[48,49,50,51,52,53,54,56,57,75,77,70,67],l=I().length;1!==l||!s(o,t)||O.htmlElement(n)&&y(n,E.selectors.editable)||i(e)}),g(Ue.container,"keydown keyup",i)}g(e,"keyup",function(e){var t=a(e),n=r();9===t&&o(n)}),g(t.body,"click",function(){m(U("."+E.classes.tabFocus),E.classes.tabFocus,!1)});for(var c in Ue.buttons){var d=Ue.buttons[c];g(d,"blur",function(){m(d,"tab-focus",!1);
|
2
|
+
})}b(Ue.buttons.play,"click",E.listeners.play,n),b(Ue.buttons.pause,"click",E.listeners.pause,n),b(Ue.buttons.restart,"click",E.listeners.restart,me),b(Ue.buttons.rewind,"click",E.listeners.rewind,de),b(Ue.buttons.forward,"click",E.listeners.forward,pe),b(Ue.buttons.seek,l,E.listeners.seek,me),b(Ue.volume.input,l,E.listeners.volume,function(){ke(Ue.volume.input.value)}),b(Ue.buttons.mute,"click",E.listeners.mute,he),b(Ue.buttons.fullscreen,"click",E.listeners.fullscreen,ge),N.supportsFullScreen&&g(t,N.fullScreenEventName,ge),g(Ue.buttons.captions,"click",Se),g(Ue.progress.container,"mouseenter mouseleave mousemove",Pe),E.hideControls&&(g(Ue.container,"mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen",Me),g(Ue.controls,"mouseenter mouseleave",function(e){Ue.controls.hover="mouseenter"===e.type}),g(Ue.controls,"mousedown mouseup touchstart touchend touchcancel",function(e){Ue.controls.pressed=s(["mousedown","touchstart"],e.type)}),g(Ue.controls,"focus blur",Me,!0)),g(Ue.volume.input,"wheel",function(e){e.preventDefault();var t=e.webkitDirectionInvertedFromDevice,n=E.volumeStep/5;(e.deltaY<0||e.deltaX>0)&&(t?xe(n):we(n)),(e.deltaY>0||e.deltaX<0)&&(t?we(n):xe(n))})}function Re(){if(g(Ue.media,"timeupdate seeking",Ie),g(Ue.media,"timeupdate",W),g(Ue.media,"durationchange loadedmetadata",Ae),g(Ue.media,"ended",function(){"video"===Ue.type&&E.showPosterOnEnd&&("video"===Ue.type&&H(),me(),Ue.media.load())}),g(Ue.media,"progress playing",Ee),g(Ue.media,"volumechange",Te),g(Ue.media,"play pause ended",ye),g(Ue.media,"waiting canplay seeked",_e),E.clickToPlay&&"audio"!==Ue.type){var e=U("."+E.classes.videoWrapper);if(!e)return;e.style.cursor="pointer",g(e,"click",function(){E.hideControls&&Ue.browser.isTouch&&!Ue.media.paused||(Ue.media.paused?le():Ue.media.ended?(me(),le()):ue())})}E.disableContextMenu&&g(Ue.media,"contextmenu",function(e){e.preventDefault()}),g(Ue.media,E.events.concat(["keyup","keydown"]).join(" "),function(e){A(Ue.container,e.type,!0)})}function qe(){if(s(E.types.html5,Ue.type)){for(var e=Ue.media.querySelectorAll("source"),t=0;t<e.length;t++)l(e[t]);Ue.media.setAttribute("src","https://cdn.selz.com/plyr/blank.mp4"),Ue.media.load(),Je("Cancelled network requests")}}function De(n,r){function a(){clearTimeout(Xe.cleanUp),O.boolean(r)||(r=!0),O.function(n)&&n.call($e),r&&(Ue.init=!1,Ue.container.parentNode.replaceChild($e,Ue.container),t.body.style.overflow="",A($e,"destroyed",!0))}if(!Ue.init)return null;switch(Ue.type){case"youtube":e.clearInterval(Xe.buffering),e.clearInterval(Xe.playing),Ue.embed.destroy(),a();break;case"vimeo":Ue.embed.unload().then(a),Xe.cleanUp=e.setTimeout(a,200);break;case"video":case"audio":Q(!0),a()}}function He(){if(Ue.init)return null;if(N=_(),Ue.browser=n(),O.htmlElement(Ue.media)){ee();var e=v.tagName.toLowerCase();"div"===e?(Ue.type=v.getAttribute("data-type"),Ue.embedId=v.getAttribute("data-video-id"),v.removeAttribute("data-type"),v.removeAttribute("data-video-id")):(Ue.type=e,E.crossorigin=null!==v.getAttribute("crossorigin"),E.autoplay=E.autoplay||null!==v.getAttribute("autoplay"),E.loop=E.loop||null!==v.getAttribute("loop")),Ue.supported=F(Ue.type),Ue.supported.basic&&(Ue.container=i(v,t.createElement("div")),Ue.container.setAttribute("tabindex",0),K(),Je(""+Ue.browser.name+" "+Ue.browser.version),ne(),(s(E.types.html5,Ue.type)||s(E.types.embed,Ue.type)&&!Ue.supported.full)&&(We(),Ye(),Z()),Ue.init=!0)}}function We(){if(!Ue.supported.full)return ze("Basic support only",Ue.type),l(U(E.selectors.controls.wrapper)),l(U(E.selectors.buttons.play)),void Q(!0);var e=!B(E.selectors.controls.wrapper).length;e&&z(),G()&&(e&&Ve(),Re(),Q(),q(),D(),ke(),Te(),Ie(),ye())}function Ye(){e.setTimeout(function(){A(Ue.media,"ready")},0),m(Ue.media,M.classes.setup,!0),m(Ue.container,E.classes.ready,!0),Ue.media.plyr=Be,E.autoplay&&le()}var Be,Ue=this,Xe={};Ue.media=v;var $e=v.cloneNode(!0),Je=function(){j("log",arguments)},ze=function(){j("warn",arguments)};return Je("Config",E),Be={getOriginal:function(){return $e},getContainer:function(){return Ue.container},getEmbed:function(){return Ue.embed},getMedia:function(){return Ue.media},getType:function(){return Ue.type},getDuration:fe,getCurrentTime:function(){return Ue.media.currentTime},getVolume:function(){return Ue.media.volume},isMuted:function(){return Ue.media.muted},isReady:function(){return f(Ue.container,E.classes.ready)},isLoading:function(){return f(Ue.container,E.classes.loading)},isPaused:function(){return Ue.media.paused},on:function(e,t){return g(Ue.container,e,t),this},play:le,pause:ue,stop:function(){ue(),me()},restart:me,rewind:de,forward:pe,seek:me,source:Oe,poster:je,setVolume:ke,togglePlay:ce,toggleMute:he,toggleCaptions:Se,toggleFullscreen:ge,toggleControls:Me,isFullscreen:function(){return Ue.isFullscreen||!1},support:function(e){return r(Ue,e)},destroy:De},He(),Ue.init?Be:null}function C(e,n){var r=new XMLHttpRequest;if(!O.string(n)||!O.htmlElement(t.querySelector("#"+n))){var a=t.createElement("div");a.setAttribute("hidden",""),O.string(n)&&a.setAttribute("id",n),t.body.insertBefore(a,t.body.childNodes[0]),"withCredentials"in r&&(r.open("GET",e,!0),r.onload=function(){a.innerHTML=r.responseText},r.send())}}function F(e){var r=n(),a=r.isIE&&r.version<=9,s=r.isIos,o=r.isIphone,i=!!t.createElement("audio").canPlayType,l=!!t.createElement("video").canPlayType,u=!1,c=!1;switch(e){case"video":u=l,c=u&&!a&&!o;break;case"audio":u=i,c=u&&!a;break;case"vimeo":u=!0,c=!a&&!s;break;case"youtube":u=!0,c=!a&&!s,s&&!o&&r.version>=10&&(c=!0);break;case"soundcloud":u=!0,c=!a&&!o;break;default:u=i&&l,c=u&&!a}return{basic:u,full:c}}function A(e,n){function r(e,t){f(t,M.classes.hook)||a.push({target:e,media:t})}var a=[],s=[],o=[M.selectors.html5,M.selectors.embed].join(",");if(O.string(e)?e=t.querySelectorAll(e):O.htmlElement(e)?e=[e]:O.nodeList(e)||O.array(e)||O.string(e)||(O.undefined(n)&&O.object(e)&&(n=e),e=t.querySelectorAll(o)),O.nodeList(e)&&(e=Array.prototype.slice.call(e)),!F().basic||!e.length)return!1;for(var i=0;i<e.length;i++){var l=e[i],u=l.querySelectorAll(o);if(u.length)for(var c=0;c<u.length;c++)r(l,u[c]);else y(l,o)&&r(l,l)}return a.forEach(function(e){var t=e.target,r=e.media,a=!1;r===t&&(a=!0);var o={};try{o=JSON.parse(t.getAttribute("data-plyr"))}catch(e){}var i=x({},M,n,o);if(!i.enabled)return null;var l=new E(r,i);if(O.object(l)){if(i.debug){var u=i.events.concat(["setup","statechange","enterfullscreen","exitfullscreen","captionsenabled","captionsdisabled"]);g(l.getContainer(),u.join(" "),function(e){console.log([i.logPrefix,"event:",e.type].join(" "),e.detail.plyr)})}h(l.getContainer(),"setup",!0,{plyr:l}),s.push(l)}}),s}function I(e){if(O.string(e)?e=t.querySelector(e):O.undefined(e)&&(e=t.body),O.htmlElement(e)){var n=e.querySelectorAll("."+M.classes.setup),r=[];return Array.prototype.slice.call(n).forEach(function(e){O.object(e.plyr)&&r.push(e.plyr)}),r}return[]}var N,P={x:0,y:0},M={enabled:!0,debug:!1,autoplay:!1,loop:!1,seekTime:10,volume:10,volumeMin:0,volumeMax:10,volumeStep:1,duration:null,displayDuration:!0,loadSprite:!0,iconPrefix:"plyr",iconUrl:"https://cdn.plyr.io/2.0.10/plyr.svg",clickToPlay:!0,hideControls:!0,showPosterOnEnd:!1,disableContextMenu:!0,keyboardShorcuts:{focused:!0,global:!1},tooltips:{controls:!1,seek:!0},selectors:{html5:"video, audio",embed:"[data-type]",editable:"input, textarea, select, [contenteditable]",container:".plyr",controls:{container:null,wrapper:".plyr__controls"},labels:"[data-plyr]",buttons:{seek:'[data-plyr="seek"]',play:'[data-plyr="play"]',pause:'[data-plyr="pause"]',restart:'[data-plyr="restart"]',rewind:'[data-plyr="rewind"]',forward:'[data-plyr="fast-forward"]',mute:'[data-plyr="mute"]',captions:'[data-plyr="captions"]',fullscreen:'[data-plyr="fullscreen"]'},volume:{input:'[data-plyr="volume"]',display:".plyr__volume--display"},progress:{container:".plyr__progress",buffer:".plyr__progress--buffer",played:".plyr__progress--played"},captions:".plyr__captions",currentTime:".plyr__time--current",duration:".plyr__time--duration"},classes:{setup:"plyr--setup",ready:"plyr--ready",videoWrapper:"plyr__video-wrapper",embedWrapper:"plyr__video-embed",type:"plyr--{0}",stopped:"plyr--stopped",playing:"plyr--playing",muted:"plyr--muted",loading:"plyr--loading",hover:"plyr--hover",tooltip:"plyr__tooltip",hidden:"plyr__sr-only",hideControls:"plyr--hide-controls",isIos:"plyr--is-ios",isTouch:"plyr--is-touch",captions:{enabled:"plyr--captions-enabled",active:"plyr--captions-active"},fullscreen:{enabled:"plyr--fullscreen-enabled",active:"plyr--fullscreen-active"},tabFocus:"tab-focus"},captions:{defaultActive:!1},fullscreen:{enabled:!0,fallback:!0,allowAudio:!1},storage:{enabled:!0,key:"plyr"},controls:["play-large","play","progress","current-time","mute","volume","captions","fullscreen"],i18n:{restart:"Restart",rewind:"Rewind {seektime} secs",play:"Play",pause:"Pause",forward:"Forward {seektime} secs",played:"played",buffered:"buffered",currentTime:"Current time",duration:"Duration",volume:"Volume",toggleMute:"Toggle Mute",toggleCaptions:"Toggle Captions",toggleFullscreen:"Toggle Fullscreen",frameTitle:"Player for {title}"},types:{embed:["youtube","vimeo","soundcloud"],html5:["video","audio"]},urls:{vimeo:{api:"https://player.vimeo.com/api/player.js"},youtube:{api:"https://www.youtube.com/iframe_api"},soundcloud:{api:"https://w.soundcloud.com/player/api.js"}},listeners:{seek:null,play:null,pause:null,restart:null,rewind:null,forward:null,mute:null,volume:null,captions:null,fullscreen:null},events:["ready","ended","progress","stalled","playing","waiting","canplay","canplaythrough","loadstart","loadeddata","loadedmetadata","timeupdate","volumechange","play","pause","error","seeking","seeked","emptied"],logPrefix:"[Plyr]"},O={object:function(e){return null!==e&&"object"==typeof e},array:function(e){return null!==e&&"object"==typeof e&&e.constructor===Array},number:function(e){return null!==e&&("number"==typeof e&&!isNaN(e-0)||"object"==typeof e&&e.constructor===Number)},string:function(e){return null!==e&&("string"==typeof e||"object"==typeof e&&e.constructor===String)},boolean:function(e){return null!==e&&"boolean"==typeof e},nodeList:function(e){return null!==e&&e instanceof NodeList},htmlElement:function(e){return null!==e&&e instanceof HTMLElement},function:function(e){return null!==e&&"function"==typeof e},undefined:function(e){return null!==e&&"undefined"==typeof e}},L={supported:function(){if(!("localStorage"in e))return!1;try{e.localStorage.setItem("___test","OK");var t=e.localStorage.getItem("___test");return e.localStorage.removeItem("___test"),"OK"===t}catch(e){return!1}return!1}()};return{setup:A,supported:F,loadSprite:C,get:I}}),function(){function e(e,t){t=t||{bubbles:!1,cancelable:!1,detail:void 0};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,t.bubbles,t.cancelable,t.detail),n}"function"!=typeof window.CustomEvent&&(e.prototype=window.Event.prototype,window.CustomEvent=e)}();
|