rdoroshenko_mediaelement_rails 0.4.0
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.
- data/.gitignore +9 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/README.md +48 -0
- data/Rakefile +12 -0
- data/app/assets/images/mediaelement_rails/background.png +0 -0
- data/app/assets/images/mediaelement_rails/bigplay.png +0 -0
- data/app/assets/images/mediaelement_rails/controls-ted.png +0 -0
- data/app/assets/images/mediaelement_rails/controls-wmp-bg.png +0 -0
- data/app/assets/images/mediaelement_rails/controls-wmp.png +0 -0
- data/app/assets/images/mediaelement_rails/controls.png +0 -0
- data/app/assets/images/mediaelement_rails/loading.gif +0 -0
- data/app/assets/javascripts/mediaelement_rails/index.js +3 -0
- data/app/assets/javascripts/mediaelement_rails/mediaelement.js +1544 -0
- data/app/assets/javascripts/mediaelement_rails/mediaelementplayer.js +2757 -0
- data/app/assets/javascripts/mediaelement_rails/rails.js.erb +5 -0
- data/app/assets/plugins/mediaelement_rails/flashmediaelement.swf +0 -0
- data/app/assets/plugins/mediaelement_rails/silverlightmediaelement.xap +0 -0
- data/app/assets/stylesheets/mediaelement_rails/index.css +1 -0
- data/app/assets/stylesheets/mediaelement_rails/mediaelementplayer.css.erb +801 -0
- data/app/assets/stylesheets/mediaelement_rails/mejs-skins.css.erb +283 -0
- data/lib/mediaelement_rails.rb +5 -0
- data/lib/mediaelement_rails/engine.rb +11 -0
- data/lib/mediaelement_rails/version.rb +3 -0
- data/mediaelement_rails.gemspec +28 -0
- data/mediaelement_rails.thor +83 -0
- data/script/rails +5 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/mediaelement-and-player.js +1 -0
- data/test/dummy/app/assets/javascripts/mediaelement-without-player.js +1 -0
- data/test/dummy/app/assets/stylesheets/player-skins.css +3 -0
- data/test/dummy/app/assets/stylesheets/player.css +3 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/mailers/.gitkeep +0 -0
- data/test/dummy/app/models/.gitkeep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +42 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +24 -0
- data/test/dummy/config/environments/production.rb +51 -0
- data/test/dummy/config/environments/test.rb +34 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +12 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/db/.gitkeep +0 -0
- data/test/dummy/lib/assets/.gitkeep +0 -0
- data/test/dummy/log/.gitkeep +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/integration/assets_test.rb +76 -0
- data/test/test_helper.rb +11 -0
- data/vendor/.gitkeep +0 -0
- metadata +235 -0
@@ -0,0 +1,2757 @@
|
|
1
|
+
/*!
|
2
|
+
* MediaElementPlayer
|
3
|
+
* http://mediaelementjs.com/
|
4
|
+
*
|
5
|
+
* Creates a controller bar for HTML5 <video> add <audio> tags
|
6
|
+
* using jQuery and MediaElement.js (HTML5 Flash/Silverlight wrapper)
|
7
|
+
*
|
8
|
+
* Copyright 2010-2012, John Dyer (http://j.hn/)
|
9
|
+
* Dual licensed under the MIT or GPL Version 2 licenses.
|
10
|
+
*
|
11
|
+
*/
|
12
|
+
if (typeof jQuery != 'undefined') {
|
13
|
+
mejs.$ = jQuery;
|
14
|
+
} else if (typeof ender != 'undefined') {
|
15
|
+
mejs.$ = ender;
|
16
|
+
}
|
17
|
+
(function ($) {
|
18
|
+
|
19
|
+
// default player values
|
20
|
+
mejs.MepDefaults = {
|
21
|
+
// url to poster (to fix iOS 3.x)
|
22
|
+
poster: '',
|
23
|
+
// default if the <video width> is not specified
|
24
|
+
defaultVideoWidth: 480,
|
25
|
+
// default if the <video height> is not specified
|
26
|
+
defaultVideoHeight: 270,
|
27
|
+
// if set, overrides <video width>
|
28
|
+
videoWidth: -1,
|
29
|
+
// if set, overrides <video height>
|
30
|
+
videoHeight: -1,
|
31
|
+
// default if the user doesn't specify
|
32
|
+
defaultAudioWidth: 400,
|
33
|
+
// default if the user doesn't specify
|
34
|
+
defaultAudioHeight: 30,
|
35
|
+
|
36
|
+
// default amount to move back when back key is pressed
|
37
|
+
defaultSeekBackwardInterval: function(media) {
|
38
|
+
return (media.duration * 0.05);
|
39
|
+
},
|
40
|
+
// default amount to move forward when forward key is pressed
|
41
|
+
defaultSeekForwardInterval: function(media) {
|
42
|
+
return (media.duration * 0.05);
|
43
|
+
},
|
44
|
+
|
45
|
+
// width of audio player
|
46
|
+
audioWidth: -1,
|
47
|
+
// height of audio player
|
48
|
+
audioHeight: -1,
|
49
|
+
// initial volume when the player starts (overrided by user cookie)
|
50
|
+
startVolume: 0.8,
|
51
|
+
// useful for <audio> player loops
|
52
|
+
loop: false,
|
53
|
+
// resize to media dimensions
|
54
|
+
enableAutosize: true,
|
55
|
+
// forces the hour marker (##:00:00)
|
56
|
+
alwaysShowHours: false,
|
57
|
+
|
58
|
+
// show framecount in timecode (##:00:00:00)
|
59
|
+
showTimecodeFrameCount: false,
|
60
|
+
// used when showTimecodeFrameCount is set to true
|
61
|
+
framesPerSecond: 25,
|
62
|
+
|
63
|
+
// automatically calculate the width of the progress bar based on the sizes of other elements
|
64
|
+
autosizeProgress : true,
|
65
|
+
// Hide controls when playing and mouse is not over the video
|
66
|
+
alwaysShowControls: false,
|
67
|
+
// force iPad's native controls
|
68
|
+
iPadUseNativeControls: false,
|
69
|
+
// force iPhone's native controls
|
70
|
+
iPhoneUseNativeControls: false,
|
71
|
+
// force Android's native controls
|
72
|
+
AndroidUseNativeControls: false,
|
73
|
+
// features to show
|
74
|
+
features: ['playpause','current','progress','duration','tracks','volume','fullscreen'],
|
75
|
+
// only for dynamic
|
76
|
+
isVideo: true,
|
77
|
+
|
78
|
+
// turns keyboard support on and off for this instance
|
79
|
+
enableKeyboard: true,
|
80
|
+
|
81
|
+
// whenthis player starts, it will pause other players
|
82
|
+
pauseOtherPlayers: true,
|
83
|
+
|
84
|
+
// array of keyboard actions such as play pause
|
85
|
+
keyActions: [
|
86
|
+
{
|
87
|
+
keys: [
|
88
|
+
32, // SPACE
|
89
|
+
179 // GOOGLE play/pause button
|
90
|
+
],
|
91
|
+
action: function(player, media) {
|
92
|
+
if (media.paused || media.ended) {
|
93
|
+
media.play();
|
94
|
+
} else {
|
95
|
+
media.pause();
|
96
|
+
}
|
97
|
+
}
|
98
|
+
},
|
99
|
+
{
|
100
|
+
keys: [38], // UP
|
101
|
+
action: function(player, media) {
|
102
|
+
var newVolume = Math.min(media.volume + 0.1, 1);
|
103
|
+
media.setVolume(newVolume);
|
104
|
+
}
|
105
|
+
},
|
106
|
+
{
|
107
|
+
keys: [40], // DOWN
|
108
|
+
action: function(player, media) {
|
109
|
+
var newVolume = Math.max(media.volume - 0.1, 0);
|
110
|
+
media.setVolume(newVolume);
|
111
|
+
}
|
112
|
+
},
|
113
|
+
{
|
114
|
+
keys: [
|
115
|
+
37, // LEFT
|
116
|
+
227 // Google TV rewind
|
117
|
+
],
|
118
|
+
action: function(player, media) {
|
119
|
+
if (!isNaN(media.duration) && media.duration > 0) {
|
120
|
+
if (player.isVideo) {
|
121
|
+
player.showControls();
|
122
|
+
player.startControlsTimer();
|
123
|
+
}
|
124
|
+
|
125
|
+
// 5%
|
126
|
+
var newTime = Math.max(media.currentTime - player.options.defaultSeekBackwardInterval(media), 0);
|
127
|
+
media.setCurrentTime(newTime);
|
128
|
+
}
|
129
|
+
}
|
130
|
+
},
|
131
|
+
{
|
132
|
+
keys: [
|
133
|
+
39, // RIGHT
|
134
|
+
228 // Google TV forward
|
135
|
+
],
|
136
|
+
action: function(player, media) {
|
137
|
+
if (!isNaN(media.duration) && media.duration > 0) {
|
138
|
+
if (player.isVideo) {
|
139
|
+
player.showControls();
|
140
|
+
player.startControlsTimer();
|
141
|
+
}
|
142
|
+
|
143
|
+
// 5%
|
144
|
+
var newTime = Math.min(media.currentTime + player.options.defaultSeekForwardInterval(media), media.duration);
|
145
|
+
media.setCurrentTime(newTime);
|
146
|
+
}
|
147
|
+
}
|
148
|
+
},
|
149
|
+
{
|
150
|
+
keys: [70], // f
|
151
|
+
action: function(player, media) {
|
152
|
+
if (typeof player.enterFullScreen != 'undefined') {
|
153
|
+
if (player.isFullScreen) {
|
154
|
+
player.exitFullScreen();
|
155
|
+
} else {
|
156
|
+
player.enterFullScreen();
|
157
|
+
}
|
158
|
+
}
|
159
|
+
}
|
160
|
+
}
|
161
|
+
]
|
162
|
+
};
|
163
|
+
|
164
|
+
mejs.mepIndex = 0;
|
165
|
+
|
166
|
+
mejs.players = [];
|
167
|
+
|
168
|
+
// wraps a MediaElement object in player controls
|
169
|
+
mejs.MediaElementPlayer = function(node, o) {
|
170
|
+
// enforce object, even without "new" (via John Resig)
|
171
|
+
if ( !(this instanceof mejs.MediaElementPlayer) ) {
|
172
|
+
return new mejs.MediaElementPlayer(node, o);
|
173
|
+
}
|
174
|
+
|
175
|
+
var t = this;
|
176
|
+
|
177
|
+
// these will be reset after the MediaElement.success fires
|
178
|
+
t.$media = t.$node = $(node);
|
179
|
+
t.node = t.media = t.$media[0];
|
180
|
+
|
181
|
+
// check for existing player
|
182
|
+
if (typeof t.node.player != 'undefined') {
|
183
|
+
return t.node.player;
|
184
|
+
} else {
|
185
|
+
// attach player to DOM node for reference
|
186
|
+
t.node.player = t;
|
187
|
+
}
|
188
|
+
|
189
|
+
|
190
|
+
// try to get options from data-mejsoptions
|
191
|
+
if (typeof o == 'undefined') {
|
192
|
+
o = t.$node.data('mejsoptions');
|
193
|
+
}
|
194
|
+
|
195
|
+
// extend default options
|
196
|
+
t.options = $.extend({},mejs.MepDefaults,o);
|
197
|
+
|
198
|
+
// add to player array (for focus events)
|
199
|
+
mejs.players.push(t);
|
200
|
+
|
201
|
+
// start up
|
202
|
+
t.init();
|
203
|
+
|
204
|
+
return t;
|
205
|
+
};
|
206
|
+
|
207
|
+
// actual player
|
208
|
+
mejs.MediaElementPlayer.prototype = {
|
209
|
+
|
210
|
+
hasFocus: false,
|
211
|
+
|
212
|
+
controlsAreVisible: true,
|
213
|
+
|
214
|
+
init: function() {
|
215
|
+
|
216
|
+
var
|
217
|
+
t = this,
|
218
|
+
mf = mejs.MediaFeatures,
|
219
|
+
// options for MediaElement (shim)
|
220
|
+
meOptions = $.extend(true, {}, t.options, {
|
221
|
+
success: function(media, domNode) { t.meReady(media, domNode); },
|
222
|
+
error: function(e) { t.handleError(e);}
|
223
|
+
}),
|
224
|
+
tagName = t.media.tagName.toLowerCase();
|
225
|
+
|
226
|
+
t.isDynamic = (tagName !== 'audio' && tagName !== 'video');
|
227
|
+
|
228
|
+
if (t.isDynamic) {
|
229
|
+
// get video from src or href?
|
230
|
+
t.isVideo = t.options.isVideo;
|
231
|
+
} else {
|
232
|
+
t.isVideo = (tagName !== 'audio' && t.options.isVideo);
|
233
|
+
}
|
234
|
+
|
235
|
+
// use native controls in iPad, iPhone, and Android
|
236
|
+
if ((mf.isiPad && t.options.iPadUseNativeControls) || (mf.isiPhone && t.options.iPhoneUseNativeControls)) {
|
237
|
+
|
238
|
+
// add controls and stop
|
239
|
+
t.$media.attr('controls', 'controls');
|
240
|
+
|
241
|
+
// attempt to fix iOS 3 bug
|
242
|
+
//t.$media.removeAttr('poster');
|
243
|
+
// no Issue found on iOS3 -ttroxell
|
244
|
+
|
245
|
+
// override Apple's autoplay override for iPads
|
246
|
+
if (mf.isiPad && t.media.getAttribute('autoplay') !== null) {
|
247
|
+
t.media.load();
|
248
|
+
t.media.play();
|
249
|
+
}
|
250
|
+
|
251
|
+
} else if (mf.isAndroid && t.AndroidUseNativeControls) {
|
252
|
+
|
253
|
+
// leave default player
|
254
|
+
|
255
|
+
} else {
|
256
|
+
|
257
|
+
// DESKTOP: use MediaElementPlayer controls
|
258
|
+
|
259
|
+
// remove native controls
|
260
|
+
t.$media.removeAttr('controls');
|
261
|
+
|
262
|
+
// unique ID
|
263
|
+
t.id = 'mep_' + mejs.mepIndex++;
|
264
|
+
|
265
|
+
// build container
|
266
|
+
t.container =
|
267
|
+
$('<div id="' + t.id + '" class="mejs-container">'+
|
268
|
+
'<div class="mejs-inner">'+
|
269
|
+
'<div class="mejs-mediaelement"></div>'+
|
270
|
+
'<div class="mejs-layers"></div>'+
|
271
|
+
'<div class="mejs-controls"></div>'+
|
272
|
+
'<div class="mejs-clear"></div>'+
|
273
|
+
'</div>' +
|
274
|
+
'</div>')
|
275
|
+
.addClass(t.$media[0].className)
|
276
|
+
.insertBefore(t.$media);
|
277
|
+
|
278
|
+
// add classes for user and content
|
279
|
+
t.container.addClass(
|
280
|
+
(mf.isAndroid ? 'mejs-android ' : '') +
|
281
|
+
(mf.isiOS ? 'mejs-ios ' : '') +
|
282
|
+
(mf.isiPad ? 'mejs-ipad ' : '') +
|
283
|
+
(mf.isiPhone ? 'mejs-iphone ' : '') +
|
284
|
+
(t.isVideo ? 'mejs-video ' : 'mejs-audio ')
|
285
|
+
);
|
286
|
+
|
287
|
+
|
288
|
+
// move the <video/video> tag into the right spot
|
289
|
+
if (mf.isiOS) {
|
290
|
+
|
291
|
+
// sadly, you can't move nodes in iOS, so we have to destroy and recreate it!
|
292
|
+
var $newMedia = t.$media.clone();
|
293
|
+
|
294
|
+
t.container.find('.mejs-mediaelement').append($newMedia);
|
295
|
+
|
296
|
+
t.$media.remove();
|
297
|
+
t.$node = t.$media = $newMedia;
|
298
|
+
t.node = t.media = $newMedia[0]
|
299
|
+
|
300
|
+
} else {
|
301
|
+
|
302
|
+
// normal way of moving it into place (doesn't work on iOS)
|
303
|
+
t.container.find('.mejs-mediaelement').append(t.$media);
|
304
|
+
}
|
305
|
+
|
306
|
+
// find parts
|
307
|
+
t.controls = t.container.find('.mejs-controls');
|
308
|
+
t.layers = t.container.find('.mejs-layers');
|
309
|
+
|
310
|
+
// determine the size
|
311
|
+
|
312
|
+
/* size priority:
|
313
|
+
(1) videoWidth (forced),
|
314
|
+
(2) style="width;height;"
|
315
|
+
(3) width attribute,
|
316
|
+
(4) defaultVideoWidth (for unspecified cases)
|
317
|
+
*/
|
318
|
+
|
319
|
+
var tagType = (t.isVideo ? 'video' : 'audio'),
|
320
|
+
capsTagName = tagType.substring(0,1).toUpperCase() + tagType.substring(1);
|
321
|
+
|
322
|
+
|
323
|
+
if (t.options[tagType + 'Width'] > 0 || t.options[tagType + 'Width'].toString().indexOf('%') > -1) {
|
324
|
+
t.width = t.options[tagType + 'Width'];
|
325
|
+
} else if (t.media.style.width !== '' && t.media.style.width !== null) {
|
326
|
+
t.width = t.media.style.width;
|
327
|
+
} else if (t.media.getAttribute('width') !== null) {
|
328
|
+
t.width = t.$media.attr('width');
|
329
|
+
} else {
|
330
|
+
t.width = t.options['default' + capsTagName + 'Width'];
|
331
|
+
}
|
332
|
+
|
333
|
+
if (t.options[tagType + 'Height'] > 0 || t.options[tagType + 'Height'].toString().indexOf('%') > -1) {
|
334
|
+
t.height = t.options[tagType + 'Height'];
|
335
|
+
} else if (t.media.style.height !== '' && t.media.style.height !== null) {
|
336
|
+
t.height = t.media.style.height;
|
337
|
+
} else if (t.$media[0].getAttribute('height') !== null) {
|
338
|
+
t.height = t.$media.attr('height');
|
339
|
+
} else {
|
340
|
+
t.height = t.options['default' + capsTagName + 'Height'];
|
341
|
+
}
|
342
|
+
|
343
|
+
// set the size, while we wait for the plugins to load below
|
344
|
+
t.setPlayerSize(t.width, t.height);
|
345
|
+
|
346
|
+
// create MediaElementShim
|
347
|
+
meOptions.pluginWidth = t.height;
|
348
|
+
meOptions.pluginHeight = t.width;
|
349
|
+
}
|
350
|
+
|
351
|
+
|
352
|
+
|
353
|
+
// create MediaElement shim
|
354
|
+
mejs.MediaElement(t.$media[0], meOptions);
|
355
|
+
},
|
356
|
+
|
357
|
+
showControls: function(doAnimation) {
|
358
|
+
var t = this;
|
359
|
+
|
360
|
+
doAnimation = typeof doAnimation == 'undefined' || doAnimation;
|
361
|
+
|
362
|
+
if (t.controlsAreVisible)
|
363
|
+
return;
|
364
|
+
|
365
|
+
if (doAnimation) {
|
366
|
+
t.controls
|
367
|
+
.css('visibility','visible')
|
368
|
+
.stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
|
369
|
+
|
370
|
+
// any additional controls people might add and want to hide
|
371
|
+
t.container.find('.mejs-control')
|
372
|
+
.css('visibility','visible')
|
373
|
+
.stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
|
374
|
+
|
375
|
+
} else {
|
376
|
+
t.controls
|
377
|
+
.css('visibility','visible')
|
378
|
+
.css('display','block');
|
379
|
+
|
380
|
+
// any additional controls people might add and want to hide
|
381
|
+
t.container.find('.mejs-control')
|
382
|
+
.css('visibility','visible')
|
383
|
+
.css('display','block');
|
384
|
+
|
385
|
+
t.controlsAreVisible = true;
|
386
|
+
}
|
387
|
+
|
388
|
+
t.setControlsSize();
|
389
|
+
|
390
|
+
},
|
391
|
+
|
392
|
+
hideControls: function(doAnimation) {
|
393
|
+
var t = this;
|
394
|
+
|
395
|
+
doAnimation = typeof doAnimation == 'undefined' || doAnimation;
|
396
|
+
|
397
|
+
if (!t.controlsAreVisible)
|
398
|
+
return;
|
399
|
+
|
400
|
+
if (doAnimation) {
|
401
|
+
// fade out main controls
|
402
|
+
t.controls.stop(true, true).fadeOut(200, function() {
|
403
|
+
$(this)
|
404
|
+
.css('visibility','hidden')
|
405
|
+
.css('display','block');
|
406
|
+
|
407
|
+
t.controlsAreVisible = false;
|
408
|
+
});
|
409
|
+
|
410
|
+
// any additional controls people might add and want to hide
|
411
|
+
t.container.find('.mejs-control').stop(true, true).fadeOut(200, function() {
|
412
|
+
$(this)
|
413
|
+
.css('visibility','hidden')
|
414
|
+
.css('display','block');
|
415
|
+
});
|
416
|
+
} else {
|
417
|
+
|
418
|
+
// hide main controls
|
419
|
+
t.controls
|
420
|
+
.css('visibility','hidden')
|
421
|
+
.css('display','block');
|
422
|
+
|
423
|
+
// hide others
|
424
|
+
t.container.find('.mejs-control')
|
425
|
+
.css('visibility','hidden')
|
426
|
+
.css('display','block');
|
427
|
+
|
428
|
+
t.controlsAreVisible = false;
|
429
|
+
}
|
430
|
+
},
|
431
|
+
|
432
|
+
controlsTimer: null,
|
433
|
+
|
434
|
+
startControlsTimer: function(timeout) {
|
435
|
+
|
436
|
+
var t = this;
|
437
|
+
|
438
|
+
timeout = typeof timeout != 'undefined' ? timeout : 1500;
|
439
|
+
|
440
|
+
t.killControlsTimer('start');
|
441
|
+
|
442
|
+
t.controlsTimer = setTimeout(function() {
|
443
|
+
//console.log('timer fired');
|
444
|
+
t.hideControls();
|
445
|
+
t.killControlsTimer('hide');
|
446
|
+
}, timeout);
|
447
|
+
},
|
448
|
+
|
449
|
+
killControlsTimer: function(src) {
|
450
|
+
|
451
|
+
var t = this;
|
452
|
+
|
453
|
+
if (t.controlsTimer !== null) {
|
454
|
+
clearTimeout(t.controlsTimer);
|
455
|
+
delete t.controlsTimer;
|
456
|
+
t.controlsTimer = null;
|
457
|
+
}
|
458
|
+
},
|
459
|
+
|
460
|
+
controlsEnabled: true,
|
461
|
+
|
462
|
+
disableControls: function() {
|
463
|
+
var t= this;
|
464
|
+
|
465
|
+
t.killControlsTimer();
|
466
|
+
t.hideControls(false);
|
467
|
+
this.controlsEnabled = false;
|
468
|
+
},
|
469
|
+
|
470
|
+
enableControls: function() {
|
471
|
+
var t= this;
|
472
|
+
|
473
|
+
t.showControls(false);
|
474
|
+
|
475
|
+
t.controlsEnabled = true;
|
476
|
+
},
|
477
|
+
|
478
|
+
|
479
|
+
// Sets up all controls and events
|
480
|
+
meReady: function(media, domNode) {
|
481
|
+
|
482
|
+
|
483
|
+
var t = this,
|
484
|
+
mf = mejs.MediaFeatures,
|
485
|
+
autoplayAttr = domNode.getAttribute('autoplay'),
|
486
|
+
autoplay = !(typeof autoplayAttr == 'undefined' || autoplayAttr === null || autoplayAttr === 'false'),
|
487
|
+
featureIndex,
|
488
|
+
feature;
|
489
|
+
|
490
|
+
// make sure it can't create itself again if a plugin reloads
|
491
|
+
if (t.created)
|
492
|
+
return;
|
493
|
+
else
|
494
|
+
t.created = true;
|
495
|
+
|
496
|
+
t.media = media;
|
497
|
+
t.domNode = domNode;
|
498
|
+
|
499
|
+
if (!(mf.isAndroid && t.options.AndroidUseNativeControls) && !(mf.isiPad && t.options.iPadUseNativeControls) && !(mf.isiPhone && t.options.iPhoneUseNativeControls)) {
|
500
|
+
|
501
|
+
// two built in features
|
502
|
+
t.buildposter(t, t.controls, t.layers, t.media);
|
503
|
+
t.buildkeyboard(t, t.controls, t.layers, t.media);
|
504
|
+
t.buildoverlays(t, t.controls, t.layers, t.media);
|
505
|
+
|
506
|
+
// grab for use by features
|
507
|
+
t.findTracks();
|
508
|
+
|
509
|
+
// add user-defined features/controls
|
510
|
+
for (featureIndex in t.options.features) {
|
511
|
+
feature = t.options.features[featureIndex];
|
512
|
+
if (t['build' + feature]) {
|
513
|
+
try {
|
514
|
+
t['build' + feature](t, t.controls, t.layers, t.media);
|
515
|
+
} catch (e) {
|
516
|
+
// TODO: report control error
|
517
|
+
//throw e;
|
518
|
+
//console.log('error building ' + feature);
|
519
|
+
//console.log(e);
|
520
|
+
}
|
521
|
+
}
|
522
|
+
}
|
523
|
+
|
524
|
+
t.container.trigger('controlsready');
|
525
|
+
|
526
|
+
// reset all layers and controls
|
527
|
+
t.setPlayerSize(t.width, t.height);
|
528
|
+
t.setControlsSize();
|
529
|
+
|
530
|
+
|
531
|
+
// controls fade
|
532
|
+
if (t.isVideo) {
|
533
|
+
|
534
|
+
if (mejs.MediaFeatures.hasTouch) {
|
535
|
+
|
536
|
+
// for touch devices (iOS, Android)
|
537
|
+
// show/hide without animation on touch
|
538
|
+
|
539
|
+
t.$media.bind('touchstart', function() {
|
540
|
+
|
541
|
+
|
542
|
+
// toggle controls
|
543
|
+
if (t.controlsAreVisible) {
|
544
|
+
t.hideControls(false);
|
545
|
+
} else {
|
546
|
+
if (t.controlsEnabled) {
|
547
|
+
t.showControls(false);
|
548
|
+
}
|
549
|
+
}
|
550
|
+
});
|
551
|
+
|
552
|
+
} else {
|
553
|
+
// click controls
|
554
|
+
var clickElement = (t.media.pluginType == 'native') ? t.$media : $(t.media.pluginElement);
|
555
|
+
|
556
|
+
// click to play/pause
|
557
|
+
clickElement.click(function() {
|
558
|
+
if (media.paused) {
|
559
|
+
media.play();
|
560
|
+
} else {
|
561
|
+
media.pause();
|
562
|
+
}
|
563
|
+
});
|
564
|
+
|
565
|
+
|
566
|
+
// show/hide controls
|
567
|
+
t.container
|
568
|
+
.bind('mouseenter mouseover', function () {
|
569
|
+
if (t.controlsEnabled) {
|
570
|
+
if (!t.options.alwaysShowControls) {
|
571
|
+
t.killControlsTimer('enter');
|
572
|
+
t.showControls();
|
573
|
+
t.startControlsTimer(2500);
|
574
|
+
}
|
575
|
+
}
|
576
|
+
})
|
577
|
+
.bind('mousemove', function() {
|
578
|
+
if (t.controlsEnabled) {
|
579
|
+
if (!t.controlsAreVisible) {
|
580
|
+
t.showControls();
|
581
|
+
}
|
582
|
+
//t.killControlsTimer('move');
|
583
|
+
if (!t.options.alwaysShowControls) {
|
584
|
+
t.startControlsTimer(2500);
|
585
|
+
}
|
586
|
+
}
|
587
|
+
})
|
588
|
+
.bind('mouseleave', function () {
|
589
|
+
if (t.controlsEnabled) {
|
590
|
+
if (!t.media.paused && !t.options.alwaysShowControls) {
|
591
|
+
t.startControlsTimer(1000);
|
592
|
+
}
|
593
|
+
}
|
594
|
+
});
|
595
|
+
}
|
596
|
+
|
597
|
+
// check for autoplay
|
598
|
+
if (autoplay && !t.options.alwaysShowControls) {
|
599
|
+
t.hideControls();
|
600
|
+
}
|
601
|
+
|
602
|
+
// resizer
|
603
|
+
if (t.options.enableAutosize) {
|
604
|
+
t.media.addEventListener('loadedmetadata', function(e) {
|
605
|
+
// if the <video height> was not set and the options.videoHeight was not set
|
606
|
+
// then resize to the real dimensions
|
607
|
+
if (t.options.videoHeight <= 0 && t.domNode.getAttribute('height') === null && !isNaN(e.target.videoHeight)) {
|
608
|
+
t.setPlayerSize(e.target.videoWidth, e.target.videoHeight);
|
609
|
+
t.setControlsSize();
|
610
|
+
t.media.setVideoSize(e.target.videoWidth, e.target.videoHeight);
|
611
|
+
}
|
612
|
+
}, false);
|
613
|
+
}
|
614
|
+
}
|
615
|
+
|
616
|
+
// EVENTS
|
617
|
+
|
618
|
+
// FOCUS: when a video starts playing, it takes focus from other players (possibily pausing them)
|
619
|
+
media.addEventListener('play', function() {
|
620
|
+
|
621
|
+
// go through all other players
|
622
|
+
for (var i=0, il=mejs.players.length; i<il; i++) {
|
623
|
+
var p = mejs.players[i];
|
624
|
+
if (p.id != t.id && t.options.pauseOtherPlayers && !p.paused && !p.ended) {
|
625
|
+
p.pause();
|
626
|
+
}
|
627
|
+
p.hasFocus = false;
|
628
|
+
}
|
629
|
+
|
630
|
+
t.hasFocus = true;
|
631
|
+
},false);
|
632
|
+
|
633
|
+
|
634
|
+
// ended for all
|
635
|
+
t.media.addEventListener('ended', function (e) {
|
636
|
+
try{
|
637
|
+
t.media.setCurrentTime(0);
|
638
|
+
} catch (exp) {
|
639
|
+
|
640
|
+
}
|
641
|
+
t.media.pause();
|
642
|
+
|
643
|
+
if (t.setProgressRail)
|
644
|
+
t.setProgressRail();
|
645
|
+
if (t.setCurrentRail)
|
646
|
+
t.setCurrentRail();
|
647
|
+
|
648
|
+
if (t.options.loop) {
|
649
|
+
t.media.play();
|
650
|
+
} else if (!t.options.alwaysShowControls && t.controlsEnabled) {
|
651
|
+
t.showControls();
|
652
|
+
}
|
653
|
+
}, false);
|
654
|
+
|
655
|
+
// resize on the first play
|
656
|
+
t.media.addEventListener('loadedmetadata', function(e) {
|
657
|
+
if (t.updateDuration) {
|
658
|
+
t.updateDuration();
|
659
|
+
}
|
660
|
+
if (t.updateCurrent) {
|
661
|
+
t.updateCurrent();
|
662
|
+
}
|
663
|
+
|
664
|
+
if (!t.isFullScreen) {
|
665
|
+
t.setPlayerSize(t.width, t.height);
|
666
|
+
t.setControlsSize();
|
667
|
+
}
|
668
|
+
}, false);
|
669
|
+
|
670
|
+
|
671
|
+
// webkit has trouble doing this without a delay
|
672
|
+
setTimeout(function () {
|
673
|
+
t.setPlayerSize(t.width, t.height);
|
674
|
+
t.setControlsSize();
|
675
|
+
}, 50);
|
676
|
+
|
677
|
+
// adjust controls whenever window sizes (used to be in fullscreen only)
|
678
|
+
$(window).resize(function() {
|
679
|
+
|
680
|
+
// don't resize for fullscreen mode
|
681
|
+
if ( !(t.isFullScreen || (mejs.MediaFeatures.hasTrueNativeFullScreen && document.webkitIsFullScreen)) ) {
|
682
|
+
t.setPlayerSize(t.width, t.height);
|
683
|
+
}
|
684
|
+
|
685
|
+
// always adjust controls
|
686
|
+
t.setControlsSize();
|
687
|
+
});
|
688
|
+
|
689
|
+
// TEMP: needs to be moved somewhere else
|
690
|
+
if (t.media.pluginType == 'youtube') {
|
691
|
+
t.container.find('.mejs-overlay-play').hide();
|
692
|
+
}
|
693
|
+
}
|
694
|
+
|
695
|
+
// force autoplay for HTML5
|
696
|
+
if (autoplay && media.pluginType == 'native') {
|
697
|
+
media.load();
|
698
|
+
media.play();
|
699
|
+
}
|
700
|
+
|
701
|
+
|
702
|
+
if (t.options.success) {
|
703
|
+
|
704
|
+
if (typeof t.options.success == 'string') {
|
705
|
+
window[t.options.success](t.media, t.domNode, t);
|
706
|
+
} else {
|
707
|
+
t.options.success(t.media, t.domNode, t);
|
708
|
+
}
|
709
|
+
}
|
710
|
+
},
|
711
|
+
|
712
|
+
handleError: function(e) {
|
713
|
+
var t = this;
|
714
|
+
|
715
|
+
t.controls.hide();
|
716
|
+
|
717
|
+
// Tell user that the file cannot be played
|
718
|
+
if (t.options.error) {
|
719
|
+
t.options.error(e);
|
720
|
+
}
|
721
|
+
},
|
722
|
+
|
723
|
+
setPlayerSize: function(width,height) {
|
724
|
+
var t = this;
|
725
|
+
|
726
|
+
if (typeof width != 'undefined')
|
727
|
+
t.width = width;
|
728
|
+
|
729
|
+
if (typeof height != 'undefined')
|
730
|
+
t.height = height;
|
731
|
+
|
732
|
+
// detect 100% mode
|
733
|
+
if (t.height.toString().indexOf('%') > 0) {
|
734
|
+
|
735
|
+
// do we have the native dimensions yet?
|
736
|
+
var
|
737
|
+
nativeWidth = (t.media.videoWidth && t.media.videoWidth > 0) ? t.media.videoWidth : t.options.defaultVideoWidth,
|
738
|
+
nativeHeight = (t.media.videoHeight && t.media.videoHeight > 0) ? t.media.videoHeight : t.options.defaultVideoHeight,
|
739
|
+
parentWidth = t.container.parent().width(),
|
740
|
+
newHeight = parseInt(parentWidth * nativeHeight/nativeWidth, 10);
|
741
|
+
|
742
|
+
if (t.container.parent()[0].tagName.toLowerCase() === 'body') { // && t.container.siblings().count == 0) {
|
743
|
+
parentWidth = $(window).width();
|
744
|
+
newHeight = $(window).height();
|
745
|
+
}
|
746
|
+
|
747
|
+
if ( newHeight != 0 ) {
|
748
|
+
// set outer container size
|
749
|
+
t.container
|
750
|
+
.width(parentWidth)
|
751
|
+
.height(newHeight);
|
752
|
+
|
753
|
+
// set native <video>
|
754
|
+
t.$media
|
755
|
+
.width('100%')
|
756
|
+
.height('100%');
|
757
|
+
|
758
|
+
// set shims
|
759
|
+
t.container.find('object, embed, iframe')
|
760
|
+
.width('100%')
|
761
|
+
.height('100%');
|
762
|
+
|
763
|
+
// if shim is ready, send the size to the embeded plugin
|
764
|
+
if (t.isVideo) {
|
765
|
+
if (t.media.setVideoSize) {
|
766
|
+
t.media.setVideoSize(parentWidth, newHeight);
|
767
|
+
}
|
768
|
+
}
|
769
|
+
|
770
|
+
// set the layers
|
771
|
+
t.layers.children('.mejs-layer')
|
772
|
+
.width('100%')
|
773
|
+
.height('100%');
|
774
|
+
}
|
775
|
+
|
776
|
+
|
777
|
+
} else {
|
778
|
+
|
779
|
+
t.container
|
780
|
+
.width(t.width)
|
781
|
+
.height(t.height);
|
782
|
+
|
783
|
+
t.layers.children('.mejs-layer')
|
784
|
+
.width(t.width)
|
785
|
+
.height(t.height);
|
786
|
+
|
787
|
+
}
|
788
|
+
},
|
789
|
+
|
790
|
+
setControlsSize: function() {
|
791
|
+
var t = this,
|
792
|
+
usedWidth = 0,
|
793
|
+
railWidth = 0,
|
794
|
+
rail = t.controls.find('.mejs-time-rail'),
|
795
|
+
total = t.controls.find('.mejs-time-total'),
|
796
|
+
current = t.controls.find('.mejs-time-current'),
|
797
|
+
loaded = t.controls.find('.mejs-time-loaded'),
|
798
|
+
others = rail.siblings();
|
799
|
+
|
800
|
+
|
801
|
+
// allow the size to come from custom CSS
|
802
|
+
if (t.options && !t.options.autosizeProgress) {
|
803
|
+
// Also, frontends devs can be more flexible
|
804
|
+
// due the opportunity of absolute positioning.
|
805
|
+
railWidth = parseInt(rail.css('width'));
|
806
|
+
}
|
807
|
+
|
808
|
+
// attempt to autosize
|
809
|
+
if (railWidth === 0 || !railWidth) {
|
810
|
+
|
811
|
+
// find the size of all the other controls besides the rail
|
812
|
+
others.each(function() {
|
813
|
+
if ($(this).css('position') != 'absolute') {
|
814
|
+
usedWidth += $(this).outerWidth(true);
|
815
|
+
}
|
816
|
+
});
|
817
|
+
|
818
|
+
// fit the rail into the remaining space
|
819
|
+
railWidth = t.controls.width() - usedWidth - (rail.outerWidth(true) - rail.width());
|
820
|
+
}
|
821
|
+
|
822
|
+
// outer area
|
823
|
+
rail.width(railWidth);
|
824
|
+
// dark space
|
825
|
+
total.width(railWidth - (total.outerWidth(true) - total.width()));
|
826
|
+
|
827
|
+
if (t.setProgressRail)
|
828
|
+
t.setProgressRail();
|
829
|
+
if (t.setCurrentRail)
|
830
|
+
t.setCurrentRail();
|
831
|
+
},
|
832
|
+
|
833
|
+
|
834
|
+
buildposter: function(player, controls, layers, media) {
|
835
|
+
var t = this,
|
836
|
+
poster =
|
837
|
+
$('<div class="mejs-poster mejs-layer">' +
|
838
|
+
'</div>')
|
839
|
+
.appendTo(layers),
|
840
|
+
posterUrl = player.$media.attr('poster');
|
841
|
+
|
842
|
+
// prioriy goes to option (this is useful if you need to support iOS 3.x (iOS completely fails with poster)
|
843
|
+
if (player.options.poster !== '') {
|
844
|
+
posterUrl = player.options.poster;
|
845
|
+
}
|
846
|
+
|
847
|
+
// second, try the real poster
|
848
|
+
if (posterUrl !== '' && posterUrl != null) {
|
849
|
+
t.setPoster(posterUrl);
|
850
|
+
} else {
|
851
|
+
poster.hide();
|
852
|
+
}
|
853
|
+
|
854
|
+
media.addEventListener('play',function() {
|
855
|
+
poster.hide();
|
856
|
+
}, false);
|
857
|
+
},
|
858
|
+
|
859
|
+
setPoster: function(url) {
|
860
|
+
var t = this,
|
861
|
+
posterDiv = t.container.find('.mejs-poster'),
|
862
|
+
posterImg = posterDiv.find('img');
|
863
|
+
|
864
|
+
if (posterImg.length == 0) {
|
865
|
+
posterImg = $('<img width="100%" height="100%" />').appendTo(posterDiv);
|
866
|
+
}
|
867
|
+
|
868
|
+
posterImg.attr('src', url);
|
869
|
+
},
|
870
|
+
|
871
|
+
buildoverlays: function(player, controls, layers, media) {
|
872
|
+
if (!player.isVideo)
|
873
|
+
return;
|
874
|
+
|
875
|
+
var
|
876
|
+
loading =
|
877
|
+
$('<div class="mejs-overlay mejs-layer">'+
|
878
|
+
'<div class="mejs-overlay-loading"><span></span></div>'+
|
879
|
+
'</div>')
|
880
|
+
.hide() // start out hidden
|
881
|
+
.appendTo(layers),
|
882
|
+
error =
|
883
|
+
$('<div class="mejs-overlay mejs-layer">'+
|
884
|
+
'<div class="mejs-overlay-error"></div>'+
|
885
|
+
'</div>')
|
886
|
+
.hide() // start out hidden
|
887
|
+
.appendTo(layers),
|
888
|
+
// this needs to come last so it's on top
|
889
|
+
bigPlay =
|
890
|
+
$('<div class="mejs-overlay mejs-layer mejs-overlay-play">'+
|
891
|
+
'<div class="mejs-overlay-button"></div>'+
|
892
|
+
'</div>')
|
893
|
+
.appendTo(layers)
|
894
|
+
.click(function() {
|
895
|
+
if (media.paused) {
|
896
|
+
media.play();
|
897
|
+
} else {
|
898
|
+
media.pause();
|
899
|
+
}
|
900
|
+
});
|
901
|
+
|
902
|
+
/*
|
903
|
+
if (mejs.MediaFeatures.isiOS || mejs.MediaFeatures.isAndroid) {
|
904
|
+
bigPlay.remove();
|
905
|
+
loading.remove();
|
906
|
+
}
|
907
|
+
*/
|
908
|
+
|
909
|
+
|
910
|
+
// show/hide big play button
|
911
|
+
media.addEventListener('play',function() {
|
912
|
+
bigPlay.hide();
|
913
|
+
loading.hide();
|
914
|
+
controls.find('.mejs-time-buffering').hide();
|
915
|
+
error.hide();
|
916
|
+
}, false);
|
917
|
+
|
918
|
+
media.addEventListener('playing', function() {
|
919
|
+
bigPlay.hide();
|
920
|
+
loading.hide();
|
921
|
+
controls.find('.mejs-time-buffering').hide();
|
922
|
+
error.hide();
|
923
|
+
}, false);
|
924
|
+
|
925
|
+
media.addEventListener('seeking', function() {
|
926
|
+
loading.show();
|
927
|
+
controls.find('.mejs-time-buffering').show();
|
928
|
+
}, false);
|
929
|
+
|
930
|
+
media.addEventListener('seeked', function() {
|
931
|
+
loading.hide();
|
932
|
+
controls.find('.mejs-time-buffering').hide();
|
933
|
+
}, false);
|
934
|
+
|
935
|
+
media.addEventListener('pause',function() {
|
936
|
+
if (!mejs.MediaFeatures.isiPhone) {
|
937
|
+
bigPlay.show();
|
938
|
+
}
|
939
|
+
}, false);
|
940
|
+
|
941
|
+
media.addEventListener('waiting', function() {
|
942
|
+
loading.show();
|
943
|
+
controls.find('.mejs-time-buffering').show();
|
944
|
+
}, false);
|
945
|
+
|
946
|
+
|
947
|
+
// show/hide loading
|
948
|
+
media.addEventListener('loadeddata',function() {
|
949
|
+
// for some reason Chrome is firing this event
|
950
|
+
//if (mejs.MediaFeatures.isChrome && media.getAttribute && media.getAttribute('preload') === 'none')
|
951
|
+
// return;
|
952
|
+
|
953
|
+
loading.show();
|
954
|
+
controls.find('.mejs-time-buffering').show();
|
955
|
+
}, false);
|
956
|
+
media.addEventListener('canplay',function() {
|
957
|
+
loading.hide();
|
958
|
+
controls.find('.mejs-time-buffering').hide();
|
959
|
+
}, false);
|
960
|
+
|
961
|
+
// error handling
|
962
|
+
media.addEventListener('error',function() {
|
963
|
+
loading.hide();
|
964
|
+
controls.find('.mejs-time-buffering').hide();
|
965
|
+
error.show();
|
966
|
+
error.find('mejs-overlay-error').html("Error loading this resource");
|
967
|
+
}, false);
|
968
|
+
},
|
969
|
+
|
970
|
+
buildkeyboard: function(player, controls, layers, media) {
|
971
|
+
|
972
|
+
var t = this;
|
973
|
+
|
974
|
+
// listen for key presses
|
975
|
+
$(document).keydown(function(e) {
|
976
|
+
|
977
|
+
if (player.hasFocus && player.options.enableKeyboard) {
|
978
|
+
|
979
|
+
// find a matching key
|
980
|
+
for (var i=0, il=player.options.keyActions.length; i<il; i++) {
|
981
|
+
var keyAction = player.options.keyActions[i];
|
982
|
+
|
983
|
+
for (var j=0, jl=keyAction.keys.length; j<jl; j++) {
|
984
|
+
if (e.keyCode == keyAction.keys[j]) {
|
985
|
+
e.preventDefault();
|
986
|
+
keyAction.action(player, media, e.keyCode);
|
987
|
+
return false;
|
988
|
+
}
|
989
|
+
}
|
990
|
+
}
|
991
|
+
}
|
992
|
+
|
993
|
+
return true;
|
994
|
+
});
|
995
|
+
|
996
|
+
// check if someone clicked outside a player region, then kill its focus
|
997
|
+
$(document).click(function(event) {
|
998
|
+
if ($(event.target).closest('.mejs-container').length == 0) {
|
999
|
+
player.hasFocus = false;
|
1000
|
+
}
|
1001
|
+
});
|
1002
|
+
|
1003
|
+
},
|
1004
|
+
|
1005
|
+
findTracks: function() {
|
1006
|
+
var t = this,
|
1007
|
+
tracktags = t.$media.find('track');
|
1008
|
+
|
1009
|
+
// store for use by plugins
|
1010
|
+
t.tracks = [];
|
1011
|
+
tracktags.each(function(index, track) {
|
1012
|
+
|
1013
|
+
track = $(track);
|
1014
|
+
|
1015
|
+
t.tracks.push({
|
1016
|
+
srclang: track.attr('srclang').toLowerCase(),
|
1017
|
+
src: track.attr('src'),
|
1018
|
+
kind: track.attr('kind'),
|
1019
|
+
label: track.attr('label') || '',
|
1020
|
+
entries: [],
|
1021
|
+
isLoaded: false
|
1022
|
+
});
|
1023
|
+
});
|
1024
|
+
},
|
1025
|
+
changeSkin: function(className) {
|
1026
|
+
this.container[0].className = 'mejs-container ' + className;
|
1027
|
+
this.setPlayerSize(this.width, this.height);
|
1028
|
+
this.setControlsSize();
|
1029
|
+
},
|
1030
|
+
play: function() {
|
1031
|
+
this.media.play();
|
1032
|
+
},
|
1033
|
+
pause: function() {
|
1034
|
+
this.media.pause();
|
1035
|
+
},
|
1036
|
+
load: function() {
|
1037
|
+
this.media.load();
|
1038
|
+
},
|
1039
|
+
setMuted: function(muted) {
|
1040
|
+
this.media.setMuted(muted);
|
1041
|
+
},
|
1042
|
+
setCurrentTime: function(time) {
|
1043
|
+
this.media.setCurrentTime(time);
|
1044
|
+
},
|
1045
|
+
getCurrentTime: function() {
|
1046
|
+
return this.media.currentTime;
|
1047
|
+
},
|
1048
|
+
setVolume: function(volume) {
|
1049
|
+
this.media.setVolume(volume);
|
1050
|
+
},
|
1051
|
+
getVolume: function() {
|
1052
|
+
return this.media.volume;
|
1053
|
+
},
|
1054
|
+
setSrc: function(src) {
|
1055
|
+
this.media.setSrc(src);
|
1056
|
+
},
|
1057
|
+
remove: function() {
|
1058
|
+
var t = this;
|
1059
|
+
|
1060
|
+
if (t.media.pluginType === 'flash') {
|
1061
|
+
t.media.remove();
|
1062
|
+
} else if (t.media.pluginType === 'native') {
|
1063
|
+
t.$media.prop('controls', true);
|
1064
|
+
}
|
1065
|
+
|
1066
|
+
// grab video and put it back in place
|
1067
|
+
if (!t.isDynamic) {
|
1068
|
+
t.$node.insertBefore(t.container)
|
1069
|
+
}
|
1070
|
+
|
1071
|
+
t.container.remove();
|
1072
|
+
}
|
1073
|
+
};
|
1074
|
+
|
1075
|
+
// turn into jQuery plugin
|
1076
|
+
if (typeof jQuery != 'undefined') {
|
1077
|
+
jQuery.fn.mediaelementplayer = function (options) {
|
1078
|
+
return this.each(function () {
|
1079
|
+
new mejs.MediaElementPlayer(this, options);
|
1080
|
+
});
|
1081
|
+
};
|
1082
|
+
}
|
1083
|
+
|
1084
|
+
$(document).ready(function() {
|
1085
|
+
// auto enable using JSON attribute
|
1086
|
+
$('.mejs-player').mediaelementplayer();
|
1087
|
+
});
|
1088
|
+
|
1089
|
+
// push out to window
|
1090
|
+
window.MediaElementPlayer = mejs.MediaElementPlayer;
|
1091
|
+
|
1092
|
+
})(mejs.$);
|
1093
|
+
|
1094
|
+
(function($) {
|
1095
|
+
|
1096
|
+
$.extend(mejs.MepDefaults, {
|
1097
|
+
playpauseText: 'Play/Pause'
|
1098
|
+
});
|
1099
|
+
|
1100
|
+
// PLAY/pause BUTTON
|
1101
|
+
$.extend(MediaElementPlayer.prototype, {
|
1102
|
+
buildplaypause: function(player, controls, layers, media) {
|
1103
|
+
var
|
1104
|
+
t = this,
|
1105
|
+
play =
|
1106
|
+
$('<div class="mejs-button mejs-playpause-button mejs-play" >' +
|
1107
|
+
'<button type="button" aria-controls="' + t.id + '" title="' + t.options.playpauseText + '"></button>' +
|
1108
|
+
'</div>')
|
1109
|
+
.appendTo(controls)
|
1110
|
+
.click(function(e) {
|
1111
|
+
e.preventDefault();
|
1112
|
+
|
1113
|
+
if (media.paused) {
|
1114
|
+
media.play();
|
1115
|
+
} else {
|
1116
|
+
media.pause();
|
1117
|
+
}
|
1118
|
+
|
1119
|
+
return false;
|
1120
|
+
});
|
1121
|
+
|
1122
|
+
media.addEventListener('play',function() {
|
1123
|
+
play.removeClass('mejs-play').addClass('mejs-pause');
|
1124
|
+
}, false);
|
1125
|
+
media.addEventListener('playing',function() {
|
1126
|
+
play.removeClass('mejs-play').addClass('mejs-pause');
|
1127
|
+
}, false);
|
1128
|
+
|
1129
|
+
|
1130
|
+
media.addEventListener('pause',function() {
|
1131
|
+
play.removeClass('mejs-pause').addClass('mejs-play');
|
1132
|
+
}, false);
|
1133
|
+
media.addEventListener('paused',function() {
|
1134
|
+
play.removeClass('mejs-pause').addClass('mejs-play');
|
1135
|
+
}, false);
|
1136
|
+
}
|
1137
|
+
});
|
1138
|
+
|
1139
|
+
})(mejs.$);
|
1140
|
+
(function($) {
|
1141
|
+
|
1142
|
+
$.extend(mejs.MepDefaults, {
|
1143
|
+
stopText: 'Stop'
|
1144
|
+
});
|
1145
|
+
|
1146
|
+
// STOP BUTTON
|
1147
|
+
$.extend(MediaElementPlayer.prototype, {
|
1148
|
+
buildstop: function(player, controls, layers, media) {
|
1149
|
+
var t = this,
|
1150
|
+
stop =
|
1151
|
+
$('<div class="mejs-button mejs-stop-button mejs-stop">' +
|
1152
|
+
'<button type="button" aria-controls="' + t.id + '" title="' + t.options.stopText + '"></button>' +
|
1153
|
+
'</div>')
|
1154
|
+
.appendTo(controls)
|
1155
|
+
.click(function() {
|
1156
|
+
if (!media.paused) {
|
1157
|
+
media.pause();
|
1158
|
+
}
|
1159
|
+
if (media.currentTime > 0) {
|
1160
|
+
media.setCurrentTime(0);
|
1161
|
+
controls.find('.mejs-time-current').width('0px');
|
1162
|
+
controls.find('.mejs-time-handle').css('left', '0px');
|
1163
|
+
controls.find('.mejs-time-float-current').html( mejs.Utility.secondsToTimeCode(0) );
|
1164
|
+
controls.find('.mejs-currenttime').html( mejs.Utility.secondsToTimeCode(0) );
|
1165
|
+
layers.find('.mejs-poster').show();
|
1166
|
+
}
|
1167
|
+
});
|
1168
|
+
}
|
1169
|
+
});
|
1170
|
+
|
1171
|
+
})(mejs.$);
|
1172
|
+
(function($) {
|
1173
|
+
// progress/loaded bar
|
1174
|
+
$.extend(MediaElementPlayer.prototype, {
|
1175
|
+
buildprogress: function(player, controls, layers, media) {
|
1176
|
+
|
1177
|
+
$('<div class="mejs-time-rail">'+
|
1178
|
+
'<span class="mejs-time-total">'+
|
1179
|
+
'<span class="mejs-time-buffering"></span>'+
|
1180
|
+
'<span class="mejs-time-loaded"></span>'+
|
1181
|
+
'<span class="mejs-time-current"></span>'+
|
1182
|
+
'<span class="mejs-time-handle"></span>'+
|
1183
|
+
'<span class="mejs-time-float">' +
|
1184
|
+
'<span class="mejs-time-float-current">00:00</span>' +
|
1185
|
+
'<span class="mejs-time-float-corner"></span>' +
|
1186
|
+
'</span>'+
|
1187
|
+
'</span>'+
|
1188
|
+
'</div>')
|
1189
|
+
.appendTo(controls);
|
1190
|
+
controls.find('.mejs-time-buffering').hide();
|
1191
|
+
|
1192
|
+
var
|
1193
|
+
t = this,
|
1194
|
+
total = controls.find('.mejs-time-total'),
|
1195
|
+
loaded = controls.find('.mejs-time-loaded'),
|
1196
|
+
current = controls.find('.mejs-time-current'),
|
1197
|
+
handle = controls.find('.mejs-time-handle'),
|
1198
|
+
timefloat = controls.find('.mejs-time-float'),
|
1199
|
+
timefloatcurrent = controls.find('.mejs-time-float-current'),
|
1200
|
+
handleMouseMove = function (e) {
|
1201
|
+
// mouse position relative to the object
|
1202
|
+
var x = e.pageX,
|
1203
|
+
offset = total.offset(),
|
1204
|
+
width = total.outerWidth(),
|
1205
|
+
percentage = 0,
|
1206
|
+
newTime = 0,
|
1207
|
+
pos = x - offset.left;
|
1208
|
+
|
1209
|
+
|
1210
|
+
if (x > offset.left && x <= width + offset.left && media.duration) {
|
1211
|
+
percentage = ((x - offset.left) / width);
|
1212
|
+
newTime = (percentage <= 0.02) ? 0 : percentage * media.duration;
|
1213
|
+
|
1214
|
+
// seek to where the mouse is
|
1215
|
+
if (mouseIsDown) {
|
1216
|
+
media.setCurrentTime(newTime);
|
1217
|
+
}
|
1218
|
+
|
1219
|
+
// position floating time box
|
1220
|
+
if (!mejs.MediaFeatures.hasTouch) {
|
1221
|
+
timefloat.css('left', pos);
|
1222
|
+
timefloatcurrent.html( mejs.Utility.secondsToTimeCode(newTime) );
|
1223
|
+
timefloat.show();
|
1224
|
+
}
|
1225
|
+
}
|
1226
|
+
},
|
1227
|
+
mouseIsDown = false,
|
1228
|
+
mouseIsOver = false;
|
1229
|
+
|
1230
|
+
// handle clicks
|
1231
|
+
//controls.find('.mejs-time-rail').delegate('span', 'click', handleMouseMove);
|
1232
|
+
total
|
1233
|
+
.bind('mousedown', function (e) {
|
1234
|
+
// only handle left clicks
|
1235
|
+
if (e.which === 1) {
|
1236
|
+
mouseIsDown = true;
|
1237
|
+
handleMouseMove(e);
|
1238
|
+
$(document)
|
1239
|
+
.bind('mousemove.dur', function(e) {
|
1240
|
+
handleMouseMove(e);
|
1241
|
+
})
|
1242
|
+
.bind('mouseup.dur', function (e) {
|
1243
|
+
mouseIsDown = false;
|
1244
|
+
timefloat.hide();
|
1245
|
+
$(document).unbind('.dur');
|
1246
|
+
});
|
1247
|
+
return false;
|
1248
|
+
}
|
1249
|
+
})
|
1250
|
+
.bind('mouseenter', function(e) {
|
1251
|
+
mouseIsOver = true;
|
1252
|
+
$(document).bind('mousemove.dur', function(e) {
|
1253
|
+
handleMouseMove(e);
|
1254
|
+
});
|
1255
|
+
if (!mejs.MediaFeatures.hasTouch) {
|
1256
|
+
timefloat.show();
|
1257
|
+
}
|
1258
|
+
})
|
1259
|
+
.bind('mouseleave',function(e) {
|
1260
|
+
mouseIsOver = false;
|
1261
|
+
if (!mouseIsDown) {
|
1262
|
+
$(document).unbind('.dur');
|
1263
|
+
timefloat.hide();
|
1264
|
+
}
|
1265
|
+
});
|
1266
|
+
|
1267
|
+
// loading
|
1268
|
+
media.addEventListener('progress', function (e) {
|
1269
|
+
player.setProgressRail(e);
|
1270
|
+
player.setCurrentRail(e);
|
1271
|
+
}, false);
|
1272
|
+
|
1273
|
+
// current time
|
1274
|
+
media.addEventListener('timeupdate', function(e) {
|
1275
|
+
player.setProgressRail(e);
|
1276
|
+
player.setCurrentRail(e);
|
1277
|
+
}, false);
|
1278
|
+
|
1279
|
+
|
1280
|
+
// store for later use
|
1281
|
+
t.loaded = loaded;
|
1282
|
+
t.total = total;
|
1283
|
+
t.current = current;
|
1284
|
+
t.handle = handle;
|
1285
|
+
},
|
1286
|
+
setProgressRail: function(e) {
|
1287
|
+
|
1288
|
+
var
|
1289
|
+
t = this,
|
1290
|
+
target = (e != undefined) ? e.target : t.media,
|
1291
|
+
percent = null;
|
1292
|
+
|
1293
|
+
// newest HTML5 spec has buffered array (FF4, Webkit)
|
1294
|
+
if (target && target.buffered && target.buffered.length > 0 && target.buffered.end && target.duration) {
|
1295
|
+
// TODO: account for a real array with multiple values (only Firefox 4 has this so far)
|
1296
|
+
percent = target.buffered.end(0) / target.duration;
|
1297
|
+
}
|
1298
|
+
// Some browsers (e.g., FF3.6 and Safari 5) cannot calculate target.bufferered.end()
|
1299
|
+
// to be anything other than 0. If the byte count is available we use this instead.
|
1300
|
+
// Browsers that support the else if do not seem to have the bufferedBytes value and
|
1301
|
+
// should skip to there. Tested in Safari 5, Webkit head, FF3.6, Chrome 6, IE 7/8.
|
1302
|
+
else if (target && target.bytesTotal != undefined && target.bytesTotal > 0 && target.bufferedBytes != undefined) {
|
1303
|
+
percent = target.bufferedBytes / target.bytesTotal;
|
1304
|
+
}
|
1305
|
+
// Firefox 3 with an Ogg file seems to go this way
|
1306
|
+
else if (e && e.lengthComputable && e.total != 0) {
|
1307
|
+
percent = e.loaded/e.total;
|
1308
|
+
}
|
1309
|
+
|
1310
|
+
// finally update the progress bar
|
1311
|
+
if (percent !== null) {
|
1312
|
+
percent = Math.min(1, Math.max(0, percent));
|
1313
|
+
// update loaded bar
|
1314
|
+
if (t.loaded && t.total) {
|
1315
|
+
t.loaded.width(t.total.width() * percent);
|
1316
|
+
}
|
1317
|
+
}
|
1318
|
+
},
|
1319
|
+
setCurrentRail: function() {
|
1320
|
+
|
1321
|
+
var t = this;
|
1322
|
+
|
1323
|
+
if (t.media.currentTime != undefined && t.media.duration) {
|
1324
|
+
|
1325
|
+
// update bar and handle
|
1326
|
+
if (t.total && t.handle) {
|
1327
|
+
var
|
1328
|
+
newWidth = t.total.width() * t.media.currentTime / t.media.duration,
|
1329
|
+
handlePos = newWidth - (t.handle.outerWidth(true) / 2);
|
1330
|
+
|
1331
|
+
t.current.width(newWidth);
|
1332
|
+
t.handle.css('left', handlePos);
|
1333
|
+
}
|
1334
|
+
}
|
1335
|
+
|
1336
|
+
}
|
1337
|
+
});
|
1338
|
+
})(mejs.$);
|
1339
|
+
(function($) {
|
1340
|
+
|
1341
|
+
// options
|
1342
|
+
$.extend(mejs.MepDefaults, {
|
1343
|
+
duration: -1,
|
1344
|
+
timeAndDurationSeparator: ' <span> | </span> '
|
1345
|
+
});
|
1346
|
+
|
1347
|
+
|
1348
|
+
// current and duration 00:00 / 00:00
|
1349
|
+
$.extend(MediaElementPlayer.prototype, {
|
1350
|
+
buildcurrent: function(player, controls, layers, media) {
|
1351
|
+
var t = this;
|
1352
|
+
|
1353
|
+
$('<div class="mejs-time">'+
|
1354
|
+
'<span class="mejs-currenttime">' + (player.options.alwaysShowHours ? '00:' : '')
|
1355
|
+
+ (player.options.showTimecodeFrameCount? '00:00:00':'00:00')+ '</span>'+
|
1356
|
+
'</div>')
|
1357
|
+
.appendTo(controls);
|
1358
|
+
|
1359
|
+
t.currenttime = t.controls.find('.mejs-currenttime');
|
1360
|
+
|
1361
|
+
media.addEventListener('timeupdate',function() {
|
1362
|
+
player.updateCurrent();
|
1363
|
+
}, false);
|
1364
|
+
},
|
1365
|
+
|
1366
|
+
|
1367
|
+
buildduration: function(player, controls, layers, media) {
|
1368
|
+
var t = this;
|
1369
|
+
|
1370
|
+
if (controls.children().last().find('.mejs-currenttime').length > 0) {
|
1371
|
+
$(t.options.timeAndDurationSeparator +
|
1372
|
+
'<span class="mejs-duration">' +
|
1373
|
+
(t.options.duration > 0 ?
|
1374
|
+
mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25) :
|
1375
|
+
((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
|
1376
|
+
) +
|
1377
|
+
'</span>')
|
1378
|
+
.appendTo(controls.find('.mejs-time'));
|
1379
|
+
} else {
|
1380
|
+
|
1381
|
+
// add class to current time
|
1382
|
+
controls.find('.mejs-currenttime').parent().addClass('mejs-currenttime-container');
|
1383
|
+
|
1384
|
+
$('<div class="mejs-time mejs-duration-container">'+
|
1385
|
+
'<span class="mejs-duration">' +
|
1386
|
+
(t.options.duration > 0 ?
|
1387
|
+
mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25) :
|
1388
|
+
((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
|
1389
|
+
) +
|
1390
|
+
'</span>' +
|
1391
|
+
'</div>')
|
1392
|
+
.appendTo(controls);
|
1393
|
+
}
|
1394
|
+
|
1395
|
+
t.durationD = t.controls.find('.mejs-duration');
|
1396
|
+
|
1397
|
+
media.addEventListener('timeupdate',function() {
|
1398
|
+
player.updateDuration();
|
1399
|
+
}, false);
|
1400
|
+
},
|
1401
|
+
|
1402
|
+
updateCurrent: function() {
|
1403
|
+
var t = this;
|
1404
|
+
|
1405
|
+
if (t.currenttime) {
|
1406
|
+
t.currenttime.html(mejs.Utility.secondsToTimeCode(t.media.currentTime, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
|
1407
|
+
}
|
1408
|
+
},
|
1409
|
+
|
1410
|
+
updateDuration: function() {
|
1411
|
+
var t = this;
|
1412
|
+
|
1413
|
+
if (t.media.duration && t.durationD) {
|
1414
|
+
t.durationD.html(mejs.Utility.secondsToTimeCode(t.media.duration, t.options.alwaysShowHours, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
|
1415
|
+
}
|
1416
|
+
}
|
1417
|
+
});
|
1418
|
+
|
1419
|
+
})(mejs.$);
|
1420
|
+
(function($) {
|
1421
|
+
|
1422
|
+
$.extend(mejs.MepDefaults, {
|
1423
|
+
muteText: 'Mute Toggle',
|
1424
|
+
hideVolumeOnTouchDevices: true,
|
1425
|
+
|
1426
|
+
audioVolume: 'horizontal',
|
1427
|
+
videoVolume: 'vertical'
|
1428
|
+
});
|
1429
|
+
|
1430
|
+
$.extend(MediaElementPlayer.prototype, {
|
1431
|
+
buildvolume: function(player, controls, layers, media) {
|
1432
|
+
|
1433
|
+
// Android and iOS don't support volume controls
|
1434
|
+
if (mejs.MediaFeatures.hasTouch && this.options.hideVolumeOnTouchDevices)
|
1435
|
+
return;
|
1436
|
+
|
1437
|
+
var t = this,
|
1438
|
+
mode = (t.isVideo) ? t.options.videoVolume : t.options.audioVolume,
|
1439
|
+
mute = (mode == 'horizontal') ?
|
1440
|
+
|
1441
|
+
// horizontal version
|
1442
|
+
$('<div class="mejs-button mejs-volume-button mejs-mute">'+
|
1443
|
+
'<button type="button" aria-controls="' + t.id + '" title="' + t.options.muteText + '"></button>'+
|
1444
|
+
'</div>' +
|
1445
|
+
'<div class="mejs-horizontal-volume-slider">'+ // outer background
|
1446
|
+
'<div class="mejs-horizontal-volume-total"></div>'+ // line background
|
1447
|
+
'<div class="mejs-horizontal-volume-current"></div>'+ // current volume
|
1448
|
+
'<div class="mejs-horizontal-volume-handle"></div>'+ // handle
|
1449
|
+
'</div>'
|
1450
|
+
)
|
1451
|
+
.appendTo(controls) :
|
1452
|
+
|
1453
|
+
// vertical version
|
1454
|
+
$('<div class="mejs-button mejs-volume-button mejs-mute">'+
|
1455
|
+
'<button type="button" aria-controls="' + t.id + '" title="' + t.options.muteText + '"></button>'+
|
1456
|
+
'<div class="mejs-volume-slider">'+ // outer background
|
1457
|
+
'<div class="mejs-volume-total"></div>'+ // line background
|
1458
|
+
'<div class="mejs-volume-current"></div>'+ // current volume
|
1459
|
+
'<div class="mejs-volume-handle"></div>'+ // handle
|
1460
|
+
'</div>'+
|
1461
|
+
'</div>')
|
1462
|
+
.appendTo(controls),
|
1463
|
+
volumeSlider = t.container.find('.mejs-volume-slider, .mejs-horizontal-volume-slider'),
|
1464
|
+
volumeTotal = t.container.find('.mejs-volume-total, .mejs-horizontal-volume-total'),
|
1465
|
+
volumeCurrent = t.container.find('.mejs-volume-current, .mejs-horizontal-volume-current'),
|
1466
|
+
volumeHandle = t.container.find('.mejs-volume-handle, .mejs-horizontal-volume-handle'),
|
1467
|
+
|
1468
|
+
positionVolumeHandle = function(volume, secondTry) {
|
1469
|
+
|
1470
|
+
if (!volumeSlider.is(':visible') && typeof secondTry != 'undefined') {
|
1471
|
+
volumeSlider.show();
|
1472
|
+
positionVolumeHandle(volume, true);
|
1473
|
+
volumeSlider.hide()
|
1474
|
+
return;
|
1475
|
+
}
|
1476
|
+
|
1477
|
+
// correct to 0-1
|
1478
|
+
volume = Math.max(0,volume);
|
1479
|
+
volume = Math.min(volume,1);
|
1480
|
+
|
1481
|
+
// ajust mute button style
|
1482
|
+
if (volume == 0) {
|
1483
|
+
mute.removeClass('mejs-mute').addClass('mejs-unmute');
|
1484
|
+
} else {
|
1485
|
+
mute.removeClass('mejs-unmute').addClass('mejs-mute');
|
1486
|
+
}
|
1487
|
+
|
1488
|
+
// position slider
|
1489
|
+
if (mode == 'vertical') {
|
1490
|
+
var
|
1491
|
+
|
1492
|
+
// height of the full size volume slider background
|
1493
|
+
totalHeight = volumeTotal.height(),
|
1494
|
+
|
1495
|
+
// top/left of full size volume slider background
|
1496
|
+
totalPosition = volumeTotal.position(),
|
1497
|
+
|
1498
|
+
// the new top position based on the current volume
|
1499
|
+
// 70% volume on 100px height == top:30px
|
1500
|
+
newTop = totalHeight - (totalHeight * volume);
|
1501
|
+
|
1502
|
+
// handle
|
1503
|
+
volumeHandle.css('top', totalPosition.top + newTop - (volumeHandle.height() / 2));
|
1504
|
+
|
1505
|
+
// show the current visibility
|
1506
|
+
volumeCurrent.height(totalHeight - newTop );
|
1507
|
+
volumeCurrent.css('top', totalPosition.top + newTop);
|
1508
|
+
} else {
|
1509
|
+
var
|
1510
|
+
|
1511
|
+
// height of the full size volume slider background
|
1512
|
+
totalWidth = volumeTotal.width(),
|
1513
|
+
|
1514
|
+
// top/left of full size volume slider background
|
1515
|
+
totalPosition = volumeTotal.position(),
|
1516
|
+
|
1517
|
+
// the new left position based on the current volume
|
1518
|
+
newLeft = totalWidth * volume;
|
1519
|
+
|
1520
|
+
// handle
|
1521
|
+
volumeHandle.css('left', totalPosition.left + newLeft - (volumeHandle.width() / 2));
|
1522
|
+
|
1523
|
+
// rezize the current part of the volume bar
|
1524
|
+
volumeCurrent.width( newLeft );
|
1525
|
+
}
|
1526
|
+
},
|
1527
|
+
handleVolumeMove = function(e) {
|
1528
|
+
|
1529
|
+
var volume = null,
|
1530
|
+
totalOffset = volumeTotal.offset();
|
1531
|
+
|
1532
|
+
// calculate the new volume based on the moust position
|
1533
|
+
if (mode == 'vertical') {
|
1534
|
+
|
1535
|
+
var
|
1536
|
+
railHeight = volumeTotal.height(),
|
1537
|
+
totalTop = parseInt(volumeTotal.css('top').replace(/px/,''),10),
|
1538
|
+
newY = e.pageY - totalOffset.top;
|
1539
|
+
|
1540
|
+
volume = (railHeight - newY) / railHeight;
|
1541
|
+
|
1542
|
+
// the controls just hide themselves (usually when mouse moves too far up)
|
1543
|
+
if (totalOffset.top == 0 || totalOffset.left == 0)
|
1544
|
+
return;
|
1545
|
+
|
1546
|
+
} else {
|
1547
|
+
var
|
1548
|
+
railWidth = volumeTotal.width(),
|
1549
|
+
newX = e.pageX - totalOffset.left;
|
1550
|
+
|
1551
|
+
volume = newX / railWidth;
|
1552
|
+
}
|
1553
|
+
|
1554
|
+
// ensure the volume isn't outside 0-1
|
1555
|
+
volume = Math.max(0,volume);
|
1556
|
+
volume = Math.min(volume,1);
|
1557
|
+
|
1558
|
+
// position the slider and handle
|
1559
|
+
positionVolumeHandle(volume);
|
1560
|
+
|
1561
|
+
// set the media object (this will trigger the volumechanged event)
|
1562
|
+
if (volume == 0) {
|
1563
|
+
media.setMuted(true);
|
1564
|
+
} else {
|
1565
|
+
media.setMuted(false);
|
1566
|
+
}
|
1567
|
+
media.setVolume(volume);
|
1568
|
+
},
|
1569
|
+
mouseIsDown = false,
|
1570
|
+
mouseIsOver = false;
|
1571
|
+
|
1572
|
+
// SLIDER
|
1573
|
+
|
1574
|
+
mute
|
1575
|
+
.hover(function() {
|
1576
|
+
volumeSlider.show();
|
1577
|
+
mouseIsOver = true;
|
1578
|
+
}, function() {
|
1579
|
+
mouseIsOver = false;
|
1580
|
+
|
1581
|
+
if (!mouseIsDown && mode == 'vertical') {
|
1582
|
+
volumeSlider.hide();
|
1583
|
+
}
|
1584
|
+
});
|
1585
|
+
|
1586
|
+
volumeSlider
|
1587
|
+
.bind('mouseover', function() {
|
1588
|
+
mouseIsOver = true;
|
1589
|
+
})
|
1590
|
+
.bind('mousedown', function (e) {
|
1591
|
+
handleVolumeMove(e);
|
1592
|
+
$(document)
|
1593
|
+
.bind('mousemove.vol', function(e) {
|
1594
|
+
handleVolumeMove(e);
|
1595
|
+
})
|
1596
|
+
.bind('mouseup.vol', function () {
|
1597
|
+
mouseIsDown = false;
|
1598
|
+
$(document).unbind('.vol');
|
1599
|
+
|
1600
|
+
if (!mouseIsOver && mode == 'vertical') {
|
1601
|
+
volumeSlider.hide();
|
1602
|
+
}
|
1603
|
+
});
|
1604
|
+
mouseIsDown = true;
|
1605
|
+
|
1606
|
+
return false;
|
1607
|
+
});
|
1608
|
+
|
1609
|
+
|
1610
|
+
// MUTE button
|
1611
|
+
mute.find('button').click(function() {
|
1612
|
+
media.setMuted( !media.muted );
|
1613
|
+
});
|
1614
|
+
|
1615
|
+
// listen for volume change events from other sources
|
1616
|
+
media.addEventListener('volumechange', function(e) {
|
1617
|
+
if (!mouseIsDown) {
|
1618
|
+
if (media.muted) {
|
1619
|
+
positionVolumeHandle(0);
|
1620
|
+
mute.removeClass('mejs-mute').addClass('mejs-unmute');
|
1621
|
+
} else {
|
1622
|
+
positionVolumeHandle(media.volume);
|
1623
|
+
mute.removeClass('mejs-unmute').addClass('mejs-mute');
|
1624
|
+
}
|
1625
|
+
}
|
1626
|
+
}, false);
|
1627
|
+
|
1628
|
+
if (t.container.is(':visible')) {
|
1629
|
+
// set initial volume
|
1630
|
+
positionVolumeHandle(player.options.startVolume);
|
1631
|
+
|
1632
|
+
// shim gets the startvolume as a parameter, but we have to set it on the native <video> and <audio> elements
|
1633
|
+
if (media.pluginType === 'native') {
|
1634
|
+
media.setVolume(player.options.startVolume);
|
1635
|
+
}
|
1636
|
+
}
|
1637
|
+
}
|
1638
|
+
});
|
1639
|
+
|
1640
|
+
})(mejs.$);
|
1641
|
+
|
1642
|
+
(function($) {
|
1643
|
+
|
1644
|
+
$.extend(mejs.MepDefaults, {
|
1645
|
+
usePluginFullScreen: true,
|
1646
|
+
newWindowCallback: function() { return '';},
|
1647
|
+
fullscreenText: 'Fullscreen'
|
1648
|
+
});
|
1649
|
+
|
1650
|
+
$.extend(MediaElementPlayer.prototype, {
|
1651
|
+
|
1652
|
+
isFullScreen: false,
|
1653
|
+
|
1654
|
+
isNativeFullScreen: false,
|
1655
|
+
|
1656
|
+
docStyleOverflow: null,
|
1657
|
+
|
1658
|
+
isInIframe: false,
|
1659
|
+
|
1660
|
+
buildfullscreen: function(player, controls, layers, media) {
|
1661
|
+
|
1662
|
+
if (!player.isVideo)
|
1663
|
+
return;
|
1664
|
+
|
1665
|
+
player.isInIframe = (window.location != window.parent.location);
|
1666
|
+
|
1667
|
+
// native events
|
1668
|
+
if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
|
1669
|
+
|
1670
|
+
// chrome doesn't alays fire this in an iframe
|
1671
|
+
var target = null;
|
1672
|
+
|
1673
|
+
if (mejs.MediaFeatures.hasMozNativeFullScreen) {
|
1674
|
+
target = $(document);
|
1675
|
+
} else {
|
1676
|
+
target = player.container;
|
1677
|
+
}
|
1678
|
+
|
1679
|
+
target.bind(mejs.MediaFeatures.fullScreenEventName, function(e) {
|
1680
|
+
|
1681
|
+
if (mejs.MediaFeatures.isFullScreen()) {
|
1682
|
+
player.isNativeFullScreen = true;
|
1683
|
+
// reset the controls once we are fully in full screen
|
1684
|
+
player.setControlsSize();
|
1685
|
+
} else {
|
1686
|
+
player.isNativeFullScreen = false;
|
1687
|
+
// when a user presses ESC
|
1688
|
+
// make sure to put the player back into place
|
1689
|
+
player.exitFullScreen();
|
1690
|
+
}
|
1691
|
+
});
|
1692
|
+
}
|
1693
|
+
|
1694
|
+
var t = this,
|
1695
|
+
normalHeight = 0,
|
1696
|
+
normalWidth = 0,
|
1697
|
+
container = player.container,
|
1698
|
+
fullscreenBtn =
|
1699
|
+
$('<div class="mejs-button mejs-fullscreen-button">' +
|
1700
|
+
'<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
|
1701
|
+
'</div>')
|
1702
|
+
.appendTo(controls);
|
1703
|
+
|
1704
|
+
if (t.media.pluginType === 'native' || (!t.options.usePluginFullScreen && !mejs.MediaFeatures.isFirefox)) {
|
1705
|
+
|
1706
|
+
fullscreenBtn.click(function() {
|
1707
|
+
var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;
|
1708
|
+
|
1709
|
+
if (isFullScreen) {
|
1710
|
+
player.exitFullScreen();
|
1711
|
+
} else {
|
1712
|
+
player.enterFullScreen();
|
1713
|
+
}
|
1714
|
+
});
|
1715
|
+
|
1716
|
+
} else {
|
1717
|
+
|
1718
|
+
var hideTimeout = null,
|
1719
|
+
supportsPointerEvents = (function() {
|
1720
|
+
// TAKEN FROM MODERNIZR
|
1721
|
+
var element = document.createElement('x'),
|
1722
|
+
documentElement = document.documentElement,
|
1723
|
+
getComputedStyle = window.getComputedStyle,
|
1724
|
+
supports;
|
1725
|
+
if(!('pointerEvents' in element.style)){
|
1726
|
+
return false;
|
1727
|
+
}
|
1728
|
+
element.style.pointerEvents = 'auto';
|
1729
|
+
element.style.pointerEvents = 'x';
|
1730
|
+
documentElement.appendChild(element);
|
1731
|
+
supports = getComputedStyle &&
|
1732
|
+
getComputedStyle(element, '').pointerEvents === 'auto';
|
1733
|
+
documentElement.removeChild(element);
|
1734
|
+
return !!supports;
|
1735
|
+
})();
|
1736
|
+
|
1737
|
+
//console.log('supportsPointerEvents', supportsPointerEvents);
|
1738
|
+
|
1739
|
+
if (supportsPointerEvents && !mejs.MediaFeatures.isOpera) { // opera doesn't allow this :(
|
1740
|
+
|
1741
|
+
// allows clicking through the fullscreen button and controls down directly to Flash
|
1742
|
+
|
1743
|
+
/*
|
1744
|
+
When a user puts his mouse over the fullscreen button, the controls are disabled
|
1745
|
+
So we put a div over the video and another one on iether side of the fullscreen button
|
1746
|
+
that caputre mouse movement
|
1747
|
+
and restore the controls once the mouse moves outside of the fullscreen button
|
1748
|
+
*/
|
1749
|
+
|
1750
|
+
var fullscreenIsDisabled = false,
|
1751
|
+
restoreControls = function() {
|
1752
|
+
if (fullscreenIsDisabled) {
|
1753
|
+
// hide the hovers
|
1754
|
+
videoHoverDiv.hide();
|
1755
|
+
controlsLeftHoverDiv.hide();
|
1756
|
+
controlsRightHoverDiv.hide();
|
1757
|
+
|
1758
|
+
// restore the control bar
|
1759
|
+
fullscreenBtn.css('pointer-events', '');
|
1760
|
+
t.controls.css('pointer-events', '');
|
1761
|
+
|
1762
|
+
// store for later
|
1763
|
+
fullscreenIsDisabled = false;
|
1764
|
+
}
|
1765
|
+
},
|
1766
|
+
videoHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
|
1767
|
+
controlsLeftHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
|
1768
|
+
controlsRightHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
|
1769
|
+
positionHoverDivs = function() {
|
1770
|
+
var style = {position: 'absolute', top: 0, left: 0}; //, backgroundColor: '#f00'};
|
1771
|
+
videoHoverDiv.css(style);
|
1772
|
+
controlsLeftHoverDiv.css(style);
|
1773
|
+
controlsRightHoverDiv.css(style);
|
1774
|
+
|
1775
|
+
// over video, but not controls
|
1776
|
+
videoHoverDiv
|
1777
|
+
.width( t.container.width() )
|
1778
|
+
.height( t.container.height() - t.controls.height() );
|
1779
|
+
|
1780
|
+
// over controls, but not the fullscreen button
|
1781
|
+
var fullScreenBtnOffset = fullscreenBtn.offset().left - t.container.offset().left;
|
1782
|
+
fullScreenBtnWidth = fullscreenBtn.outerWidth(true);
|
1783
|
+
|
1784
|
+
controlsLeftHoverDiv
|
1785
|
+
.width( fullScreenBtnOffset )
|
1786
|
+
.height( t.controls.height() )
|
1787
|
+
.css({top: t.container.height() - t.controls.height()});
|
1788
|
+
|
1789
|
+
// after the fullscreen button
|
1790
|
+
controlsRightHoverDiv
|
1791
|
+
.width( t.container.width() - fullScreenBtnOffset - fullScreenBtnWidth )
|
1792
|
+
.height( t.controls.height() )
|
1793
|
+
.css({top: t.container.height() - t.controls.height(),
|
1794
|
+
left: fullScreenBtnOffset + fullScreenBtnWidth});
|
1795
|
+
};
|
1796
|
+
|
1797
|
+
$(document).resize(function() {
|
1798
|
+
positionHoverDivs();
|
1799
|
+
});
|
1800
|
+
|
1801
|
+
// on hover, kill the fullscreen button's HTML handling, allowing clicks down to Flash
|
1802
|
+
fullscreenBtn
|
1803
|
+
.mouseover(function() {
|
1804
|
+
|
1805
|
+
if (!t.isFullScreen) {
|
1806
|
+
|
1807
|
+
var buttonPos = fullscreenBtn.offset(),
|
1808
|
+
containerPos = player.container.offset();
|
1809
|
+
|
1810
|
+
// move the button in Flash into place
|
1811
|
+
media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);
|
1812
|
+
|
1813
|
+
// allows click through
|
1814
|
+
fullscreenBtn.css('pointer-events', 'none');
|
1815
|
+
t.controls.css('pointer-events', 'none');
|
1816
|
+
|
1817
|
+
// show the divs that will restore things
|
1818
|
+
videoHoverDiv.show();
|
1819
|
+
controlsRightHoverDiv.show();
|
1820
|
+
controlsLeftHoverDiv.show();
|
1821
|
+
positionHoverDivs();
|
1822
|
+
|
1823
|
+
fullscreenIsDisabled = true;
|
1824
|
+
}
|
1825
|
+
|
1826
|
+
});
|
1827
|
+
|
1828
|
+
// restore controls anytime the user enters or leaves fullscreen
|
1829
|
+
media.addEventListener('fullscreenchange', function(e) {
|
1830
|
+
restoreControls();
|
1831
|
+
});
|
1832
|
+
|
1833
|
+
|
1834
|
+
// the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events
|
1835
|
+
// so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button
|
1836
|
+
/*
|
1837
|
+
$(document).mousemove(function(e) {
|
1838
|
+
|
1839
|
+
// if the mouse is anywhere but the fullsceen button, then restore it all
|
1840
|
+
if (fullscreenIsDisabled) {
|
1841
|
+
|
1842
|
+
var fullscreenBtnPos = fullscreenBtn.offset();
|
1843
|
+
|
1844
|
+
|
1845
|
+
if (e.pageY < fullscreenBtnPos.top || e.pageY > fullscreenBtnPos.top + fullscreenBtn.outerHeight(true) ||
|
1846
|
+
e.pageX < fullscreenBtnPos.left || e.pageX > fullscreenBtnPos.left + fullscreenBtn.outerWidth(true)
|
1847
|
+
) {
|
1848
|
+
|
1849
|
+
fullscreenBtn.css('pointer-events', '');
|
1850
|
+
t.controls.css('pointer-events', '');
|
1851
|
+
|
1852
|
+
fullscreenIsDisabled = false;
|
1853
|
+
}
|
1854
|
+
}
|
1855
|
+
});
|
1856
|
+
*/
|
1857
|
+
|
1858
|
+
|
1859
|
+
} else {
|
1860
|
+
|
1861
|
+
// the hover state will show the fullscreen button in Flash to hover up and click
|
1862
|
+
|
1863
|
+
fullscreenBtn
|
1864
|
+
.mouseover(function() {
|
1865
|
+
|
1866
|
+
if (hideTimeout !== null) {
|
1867
|
+
clearTimeout(hideTimeout);
|
1868
|
+
delete hideTimeout;
|
1869
|
+
}
|
1870
|
+
|
1871
|
+
var buttonPos = fullscreenBtn.offset(),
|
1872
|
+
containerPos = player.container.offset();
|
1873
|
+
|
1874
|
+
media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, true);
|
1875
|
+
|
1876
|
+
})
|
1877
|
+
.mouseout(function() {
|
1878
|
+
|
1879
|
+
if (hideTimeout !== null) {
|
1880
|
+
clearTimeout(hideTimeout);
|
1881
|
+
delete hideTimeout;
|
1882
|
+
}
|
1883
|
+
|
1884
|
+
hideTimeout = setTimeout(function() {
|
1885
|
+
media.hideFullscreenButton();
|
1886
|
+
}, 1500);
|
1887
|
+
|
1888
|
+
|
1889
|
+
});
|
1890
|
+
}
|
1891
|
+
}
|
1892
|
+
|
1893
|
+
player.fullscreenBtn = fullscreenBtn;
|
1894
|
+
|
1895
|
+
$(document).bind('keydown',function (e) {
|
1896
|
+
if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
|
1897
|
+
player.exitFullScreen();
|
1898
|
+
}
|
1899
|
+
});
|
1900
|
+
|
1901
|
+
},
|
1902
|
+
enterFullScreen: function() {
|
1903
|
+
|
1904
|
+
var t = this;
|
1905
|
+
|
1906
|
+
// firefox+flash can't adjust plugin sizes without resetting :(
|
1907
|
+
if (t.media.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || t.options.usePluginFullScreen)) {
|
1908
|
+
//t.media.setFullscreen(true);
|
1909
|
+
//player.isFullScreen = true;
|
1910
|
+
return;
|
1911
|
+
}
|
1912
|
+
|
1913
|
+
// store overflow
|
1914
|
+
docStyleOverflow = document.documentElement.style.overflow;
|
1915
|
+
// set it to not show scroll bars so 100% will work
|
1916
|
+
document.documentElement.style.overflow = 'hidden';
|
1917
|
+
|
1918
|
+
// store sizing
|
1919
|
+
normalHeight = t.container.height();
|
1920
|
+
normalWidth = t.container.width();
|
1921
|
+
|
1922
|
+
// attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)
|
1923
|
+
if (t.media.pluginType === 'native') {
|
1924
|
+
if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
|
1925
|
+
|
1926
|
+
mejs.MediaFeatures.requestFullScreen(t.container[0]);
|
1927
|
+
//return;
|
1928
|
+
|
1929
|
+
if (t.isInIframe) {
|
1930
|
+
// sometimes exiting from fullscreen doesn't work
|
1931
|
+
// notably in Chrome <iframe>. Fixed in version 17
|
1932
|
+
setTimeout(function checkFullscreen() {
|
1933
|
+
|
1934
|
+
if (t.isNativeFullScreen) {
|
1935
|
+
|
1936
|
+
// check if the video is suddenly not really fullscreen
|
1937
|
+
if ($(window).width() !== screen.width) {
|
1938
|
+
// manually exit
|
1939
|
+
t.exitFullScreen();
|
1940
|
+
} else {
|
1941
|
+
// test again
|
1942
|
+
setTimeout(checkFullscreen, 500);
|
1943
|
+
}
|
1944
|
+
}
|
1945
|
+
|
1946
|
+
|
1947
|
+
}, 500);
|
1948
|
+
}
|
1949
|
+
|
1950
|
+
} else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {
|
1951
|
+
t.media.webkitEnterFullscreen();
|
1952
|
+
return;
|
1953
|
+
}
|
1954
|
+
}
|
1955
|
+
|
1956
|
+
// check for iframe launch
|
1957
|
+
if (t.isInIframe) {
|
1958
|
+
var url = t.options.newWindowCallback(this);
|
1959
|
+
|
1960
|
+
|
1961
|
+
if (url !== '') {
|
1962
|
+
|
1963
|
+
// launch immediately
|
1964
|
+
if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
|
1965
|
+
t.pause();
|
1966
|
+
window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
|
1967
|
+
return;
|
1968
|
+
} else {
|
1969
|
+
setTimeout(function() {
|
1970
|
+
if (!t.isNativeFullScreen) {
|
1971
|
+
t.pause();
|
1972
|
+
window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
|
1973
|
+
}
|
1974
|
+
}, 250);
|
1975
|
+
}
|
1976
|
+
}
|
1977
|
+
|
1978
|
+
}
|
1979
|
+
|
1980
|
+
// full window code
|
1981
|
+
|
1982
|
+
|
1983
|
+
|
1984
|
+
// make full size
|
1985
|
+
t.container
|
1986
|
+
.addClass('mejs-container-fullscreen')
|
1987
|
+
.width('100%')
|
1988
|
+
.height('100%');
|
1989
|
+
//.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});
|
1990
|
+
|
1991
|
+
// Only needed for safari 5.1 native full screen, can cause display issues elsewhere
|
1992
|
+
// Actually, it seems to be needed for IE8, too
|
1993
|
+
//if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
|
1994
|
+
setTimeout(function() {
|
1995
|
+
t.container.css({width: '100%', height: '100%'});
|
1996
|
+
t.setControlsSize();
|
1997
|
+
}, 500);
|
1998
|
+
//}
|
1999
|
+
|
2000
|
+
if (t.pluginType === 'native') {
|
2001
|
+
t.$media
|
2002
|
+
.width('100%')
|
2003
|
+
.height('100%');
|
2004
|
+
} else {
|
2005
|
+
t.container.find('object, embed, iframe')
|
2006
|
+
.width('100%')
|
2007
|
+
.height('100%');
|
2008
|
+
|
2009
|
+
//if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
|
2010
|
+
t.media.setVideoSize($(window).width(),$(window).height());
|
2011
|
+
//}
|
2012
|
+
}
|
2013
|
+
|
2014
|
+
t.layers.children('div')
|
2015
|
+
.width('100%')
|
2016
|
+
.height('100%');
|
2017
|
+
|
2018
|
+
if (t.fullscreenBtn) {
|
2019
|
+
t.fullscreenBtn
|
2020
|
+
.removeClass('mejs-fullscreen')
|
2021
|
+
.addClass('mejs-unfullscreen');
|
2022
|
+
}
|
2023
|
+
|
2024
|
+
t.setControlsSize();
|
2025
|
+
t.isFullScreen = true;
|
2026
|
+
},
|
2027
|
+
|
2028
|
+
exitFullScreen: function() {
|
2029
|
+
|
2030
|
+
var t = this;
|
2031
|
+
|
2032
|
+
// firefox can't adjust plugins
|
2033
|
+
if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
|
2034
|
+
t.media.setFullscreen(false);
|
2035
|
+
//player.isFullScreen = false;
|
2036
|
+
return;
|
2037
|
+
}
|
2038
|
+
|
2039
|
+
// come outo of native fullscreen
|
2040
|
+
if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {
|
2041
|
+
mejs.MediaFeatures.cancelFullScreen();
|
2042
|
+
}
|
2043
|
+
|
2044
|
+
// restore scroll bars to document
|
2045
|
+
document.documentElement.style.overflow = docStyleOverflow;
|
2046
|
+
|
2047
|
+
t.container
|
2048
|
+
.removeClass('mejs-container-fullscreen')
|
2049
|
+
.width(normalWidth)
|
2050
|
+
.height(normalHeight);
|
2051
|
+
//.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});
|
2052
|
+
|
2053
|
+
if (t.pluginType === 'native') {
|
2054
|
+
t.$media
|
2055
|
+
.width(normalWidth)
|
2056
|
+
.height(normalHeight);
|
2057
|
+
} else {
|
2058
|
+
t.container.find('object embed')
|
2059
|
+
.width(normalWidth)
|
2060
|
+
.height(normalHeight);
|
2061
|
+
|
2062
|
+
t.media.setVideoSize(normalWidth, normalHeight);
|
2063
|
+
}
|
2064
|
+
|
2065
|
+
t.layers.children('div')
|
2066
|
+
.width(normalWidth)
|
2067
|
+
.height(normalHeight);
|
2068
|
+
|
2069
|
+
t.fullscreenBtn
|
2070
|
+
.removeClass('mejs-unfullscreen')
|
2071
|
+
.addClass('mejs-fullscreen');
|
2072
|
+
|
2073
|
+
t.setControlsSize();
|
2074
|
+
t.isFullScreen = false;
|
2075
|
+
}
|
2076
|
+
});
|
2077
|
+
|
2078
|
+
})(mejs.$);
|
2079
|
+
|
2080
|
+
(function($) {
|
2081
|
+
|
2082
|
+
// add extra default options
|
2083
|
+
$.extend(mejs.MepDefaults, {
|
2084
|
+
// this will automatically turn on a <track>
|
2085
|
+
startLanguage: '',
|
2086
|
+
|
2087
|
+
tracksText: 'Captions/Subtitles'
|
2088
|
+
});
|
2089
|
+
|
2090
|
+
$.extend(MediaElementPlayer.prototype, {
|
2091
|
+
|
2092
|
+
hasChapters: false,
|
2093
|
+
|
2094
|
+
buildtracks: function(player, controls, layers, media) {
|
2095
|
+
if (!player.isVideo)
|
2096
|
+
return;
|
2097
|
+
|
2098
|
+
if (player.tracks.length == 0)
|
2099
|
+
return;
|
2100
|
+
|
2101
|
+
var t= this, i, options = '';
|
2102
|
+
|
2103
|
+
player.chapters =
|
2104
|
+
$('<div class="mejs-chapters mejs-layer"></div>')
|
2105
|
+
.prependTo(layers).hide();
|
2106
|
+
player.captions =
|
2107
|
+
$('<div class="mejs-captions-layer mejs-layer"><div class="mejs-captions-position"><span class="mejs-captions-text"></span></div></div>')
|
2108
|
+
.prependTo(layers).hide();
|
2109
|
+
player.captionsText = player.captions.find('.mejs-captions-text');
|
2110
|
+
player.captionsButton =
|
2111
|
+
$('<div class="mejs-button mejs-captions-button">'+
|
2112
|
+
'<button type="button" aria-controls="' + t.id + '" title="' + t.options.tracksText + '"></button>'+
|
2113
|
+
'<div class="mejs-captions-selector">'+
|
2114
|
+
'<ul>'+
|
2115
|
+
'<li>'+
|
2116
|
+
'<input type="radio" name="' + player.id + '_captions" id="' + player.id + '_captions_none" value="none" checked="checked" />' +
|
2117
|
+
'<label for="' + player.id + '_captions_none">None</label>'+
|
2118
|
+
'</li>' +
|
2119
|
+
'</ul>'+
|
2120
|
+
'</div>'+
|
2121
|
+
'</div>')
|
2122
|
+
.appendTo(controls)
|
2123
|
+
|
2124
|
+
// hover
|
2125
|
+
.hover(function() {
|
2126
|
+
$(this).find('.mejs-captions-selector').css('visibility','visible');
|
2127
|
+
}, function() {
|
2128
|
+
$(this).find('.mejs-captions-selector').css('visibility','hidden');
|
2129
|
+
})
|
2130
|
+
|
2131
|
+
// handle clicks to the language radio buttons
|
2132
|
+
.delegate('input[type=radio]','click',function() {
|
2133
|
+
lang = this.value;
|
2134
|
+
|
2135
|
+
if (lang == 'none') {
|
2136
|
+
player.selectedTrack = null;
|
2137
|
+
} else {
|
2138
|
+
for (i=0; i<player.tracks.length; i++) {
|
2139
|
+
if (player.tracks[i].srclang == lang) {
|
2140
|
+
player.selectedTrack = player.tracks[i];
|
2141
|
+
player.captions.attr('lang', player.selectedTrack.srclang);
|
2142
|
+
player.displayCaptions();
|
2143
|
+
break;
|
2144
|
+
}
|
2145
|
+
}
|
2146
|
+
}
|
2147
|
+
});
|
2148
|
+
//.bind('mouseenter', function() {
|
2149
|
+
// player.captionsButton.find('.mejs-captions-selector').css('visibility','visible')
|
2150
|
+
//});
|
2151
|
+
|
2152
|
+
if (!player.options.alwaysShowControls) {
|
2153
|
+
// move with controls
|
2154
|
+
player.container
|
2155
|
+
.bind('mouseenter', function () {
|
2156
|
+
// push captions above controls
|
2157
|
+
player.container.find('.mejs-captions-position').addClass('mejs-captions-position-hover');
|
2158
|
+
|
2159
|
+
})
|
2160
|
+
.bind('mouseleave', function () {
|
2161
|
+
if (!media.paused) {
|
2162
|
+
// move back to normal place
|
2163
|
+
player.container.find('.mejs-captions-position').removeClass('mejs-captions-position-hover');
|
2164
|
+
}
|
2165
|
+
});
|
2166
|
+
} else {
|
2167
|
+
player.container.find('.mejs-captions-position').addClass('mejs-captions-position-hover');
|
2168
|
+
}
|
2169
|
+
|
2170
|
+
player.trackToLoad = -1;
|
2171
|
+
player.selectedTrack = null;
|
2172
|
+
player.isLoadingTrack = false;
|
2173
|
+
|
2174
|
+
|
2175
|
+
|
2176
|
+
// add to list
|
2177
|
+
for (i=0; i<player.tracks.length; i++) {
|
2178
|
+
if (player.tracks[i].kind == 'subtitles') {
|
2179
|
+
player.addTrackButton(player.tracks[i].srclang, player.tracks[i].label);
|
2180
|
+
}
|
2181
|
+
}
|
2182
|
+
|
2183
|
+
player.loadNextTrack();
|
2184
|
+
|
2185
|
+
|
2186
|
+
media.addEventListener('timeupdate',function(e) {
|
2187
|
+
player.displayCaptions();
|
2188
|
+
}, false);
|
2189
|
+
|
2190
|
+
media.addEventListener('loadedmetadata', function(e) {
|
2191
|
+
player.displayChapters();
|
2192
|
+
}, false);
|
2193
|
+
|
2194
|
+
player.container.hover(
|
2195
|
+
function () {
|
2196
|
+
// chapters
|
2197
|
+
if (player.hasChapters) {
|
2198
|
+
player.chapters.css('visibility','visible');
|
2199
|
+
player.chapters.fadeIn(200).height(player.chapters.find('.mejs-chapter').outerHeight());
|
2200
|
+
}
|
2201
|
+
},
|
2202
|
+
function () {
|
2203
|
+
if (player.hasChapters && !media.paused) {
|
2204
|
+
player.chapters.fadeOut(200, function() {
|
2205
|
+
$(this).css('visibility','hidden');
|
2206
|
+
$(this).css('display','block');
|
2207
|
+
});
|
2208
|
+
}
|
2209
|
+
});
|
2210
|
+
|
2211
|
+
// check for autoplay
|
2212
|
+
if (player.node.getAttribute('autoplay') !== null) {
|
2213
|
+
player.chapters.css('visibility','hidden');
|
2214
|
+
}
|
2215
|
+
},
|
2216
|
+
|
2217
|
+
loadNextTrack: function() {
|
2218
|
+
var t = this;
|
2219
|
+
|
2220
|
+
t.trackToLoad++;
|
2221
|
+
if (t.trackToLoad < t.tracks.length) {
|
2222
|
+
t.isLoadingTrack = true;
|
2223
|
+
t.loadTrack(t.trackToLoad);
|
2224
|
+
} else {
|
2225
|
+
// add done?
|
2226
|
+
t.isLoadingTrack = false;
|
2227
|
+
}
|
2228
|
+
},
|
2229
|
+
|
2230
|
+
loadTrack: function(index){
|
2231
|
+
var
|
2232
|
+
t = this,
|
2233
|
+
track = t.tracks[index],
|
2234
|
+
after = function() {
|
2235
|
+
|
2236
|
+
track.isLoaded = true;
|
2237
|
+
|
2238
|
+
// create button
|
2239
|
+
//t.addTrackButton(track.srclang);
|
2240
|
+
t.enableTrackButton(track.srclang, track.label);
|
2241
|
+
|
2242
|
+
t.loadNextTrack();
|
2243
|
+
|
2244
|
+
};
|
2245
|
+
|
2246
|
+
if (track.isTranslation) {
|
2247
|
+
|
2248
|
+
// translate the first track
|
2249
|
+
mejs.TrackFormatParser.translateTrackText(t.tracks[0].entries, t.tracks[0].srclang, track.srclang, t.options.googleApiKey, function(newOne) {
|
2250
|
+
|
2251
|
+
// store the new translation
|
2252
|
+
track.entries = newOne;
|
2253
|
+
|
2254
|
+
after();
|
2255
|
+
});
|
2256
|
+
|
2257
|
+
} else {
|
2258
|
+
$.ajax({
|
2259
|
+
url: track.src,
|
2260
|
+
success: function(d) {
|
2261
|
+
|
2262
|
+
// parse the loaded file
|
2263
|
+
track.entries = mejs.TrackFormatParser.parse(d);
|
2264
|
+
after();
|
2265
|
+
|
2266
|
+
if (track.kind == 'chapters' && t.media.duration > 0) {
|
2267
|
+
t.drawChapters(track);
|
2268
|
+
}
|
2269
|
+
},
|
2270
|
+
error: function() {
|
2271
|
+
t.loadNextTrack();
|
2272
|
+
}
|
2273
|
+
});
|
2274
|
+
}
|
2275
|
+
},
|
2276
|
+
|
2277
|
+
enableTrackButton: function(lang, label) {
|
2278
|
+
var t = this;
|
2279
|
+
|
2280
|
+
if (label === '') {
|
2281
|
+
label = mejs.language.codes[lang] || lang;
|
2282
|
+
}
|
2283
|
+
|
2284
|
+
t.captionsButton
|
2285
|
+
.find('input[value=' + lang + ']')
|
2286
|
+
.prop('disabled',false)
|
2287
|
+
.siblings('label')
|
2288
|
+
.html( label );
|
2289
|
+
|
2290
|
+
// auto select
|
2291
|
+
if (t.options.startLanguage == lang) {
|
2292
|
+
$('#' + t.id + '_captions_' + lang).click();
|
2293
|
+
}
|
2294
|
+
|
2295
|
+
t.adjustLanguageBox();
|
2296
|
+
},
|
2297
|
+
|
2298
|
+
addTrackButton: function(lang, label) {
|
2299
|
+
var t = this;
|
2300
|
+
if (label === '') {
|
2301
|
+
label = mejs.language.codes[lang] || lang;
|
2302
|
+
}
|
2303
|
+
|
2304
|
+
t.captionsButton.find('ul').append(
|
2305
|
+
$('<li>'+
|
2306
|
+
'<input type="radio" name="' + t.id + '_captions" id="' + t.id + '_captions_' + lang + '" value="' + lang + '" disabled="disabled" />' +
|
2307
|
+
'<label for="' + t.id + '_captions_' + lang + '">' + label + ' (loading)' + '</label>'+
|
2308
|
+
'</li>')
|
2309
|
+
);
|
2310
|
+
|
2311
|
+
t.adjustLanguageBox();
|
2312
|
+
|
2313
|
+
// remove this from the dropdownlist (if it exists)
|
2314
|
+
t.container.find('.mejs-captions-translations option[value=' + lang + ']').remove();
|
2315
|
+
},
|
2316
|
+
|
2317
|
+
adjustLanguageBox:function() {
|
2318
|
+
var t = this;
|
2319
|
+
// adjust the size of the outer box
|
2320
|
+
t.captionsButton.find('.mejs-captions-selector').height(
|
2321
|
+
t.captionsButton.find('.mejs-captions-selector ul').outerHeight(true) +
|
2322
|
+
t.captionsButton.find('.mejs-captions-translations').outerHeight(true)
|
2323
|
+
);
|
2324
|
+
},
|
2325
|
+
|
2326
|
+
displayCaptions: function() {
|
2327
|
+
|
2328
|
+
if (typeof this.tracks == 'undefined')
|
2329
|
+
return;
|
2330
|
+
|
2331
|
+
var
|
2332
|
+
t = this,
|
2333
|
+
i,
|
2334
|
+
track = t.selectedTrack;
|
2335
|
+
|
2336
|
+
if (track != null && track.isLoaded) {
|
2337
|
+
for (i=0; i<track.entries.times.length; i++) {
|
2338
|
+
if (t.media.currentTime >= track.entries.times[i].start && t.media.currentTime <= track.entries.times[i].stop){
|
2339
|
+
t.captionsText.html(track.entries.text[i]);
|
2340
|
+
t.captions.show().height(0);
|
2341
|
+
return; // exit out if one is visible;
|
2342
|
+
}
|
2343
|
+
}
|
2344
|
+
t.captions.hide();
|
2345
|
+
} else {
|
2346
|
+
t.captions.hide();
|
2347
|
+
}
|
2348
|
+
},
|
2349
|
+
|
2350
|
+
displayChapters: function() {
|
2351
|
+
var
|
2352
|
+
t = this,
|
2353
|
+
i;
|
2354
|
+
|
2355
|
+
for (i=0; i<t.tracks.length; i++) {
|
2356
|
+
if (t.tracks[i].kind == 'chapters' && t.tracks[i].isLoaded) {
|
2357
|
+
t.drawChapters(t.tracks[i]);
|
2358
|
+
t.hasChapters = true;
|
2359
|
+
break;
|
2360
|
+
}
|
2361
|
+
}
|
2362
|
+
},
|
2363
|
+
|
2364
|
+
drawChapters: function(chapters) {
|
2365
|
+
var
|
2366
|
+
t = this,
|
2367
|
+
i,
|
2368
|
+
dur,
|
2369
|
+
//width,
|
2370
|
+
//left,
|
2371
|
+
percent = 0,
|
2372
|
+
usedPercent = 0;
|
2373
|
+
|
2374
|
+
t.chapters.empty();
|
2375
|
+
|
2376
|
+
for (i=0; i<chapters.entries.times.length; i++) {
|
2377
|
+
dur = chapters.entries.times[i].stop - chapters.entries.times[i].start;
|
2378
|
+
percent = Math.floor(dur / t.media.duration * 100);
|
2379
|
+
if (percent + usedPercent > 100 || // too large
|
2380
|
+
i == chapters.entries.times.length-1 && percent + usedPercent < 100) // not going to fill it in
|
2381
|
+
{
|
2382
|
+
percent = 100 - usedPercent;
|
2383
|
+
}
|
2384
|
+
//width = Math.floor(t.width * dur / t.media.duration);
|
2385
|
+
//left = Math.floor(t.width * chapters.entries.times[i].start / t.media.duration);
|
2386
|
+
//if (left + width > t.width) {
|
2387
|
+
// width = t.width - left;
|
2388
|
+
//}
|
2389
|
+
|
2390
|
+
t.chapters.append( $(
|
2391
|
+
'<div class="mejs-chapter" rel="' + chapters.entries.times[i].start + '" style="left: ' + usedPercent.toString() + '%;width: ' + percent.toString() + '%;">' +
|
2392
|
+
'<div class="mejs-chapter-block' + ((i==chapters.entries.times.length-1) ? ' mejs-chapter-block-last' : '') + '">' +
|
2393
|
+
'<span class="ch-title">' + chapters.entries.text[i] + '</span>' +
|
2394
|
+
'<span class="ch-time">' + mejs.Utility.secondsToTimeCode(chapters.entries.times[i].start) + '–' + mejs.Utility.secondsToTimeCode(chapters.entries.times[i].stop) + '</span>' +
|
2395
|
+
'</div>' +
|
2396
|
+
'</div>'));
|
2397
|
+
usedPercent += percent;
|
2398
|
+
}
|
2399
|
+
|
2400
|
+
t.chapters.find('div.mejs-chapter').click(function() {
|
2401
|
+
t.media.setCurrentTime( parseFloat( $(this).attr('rel') ) );
|
2402
|
+
if (t.media.paused) {
|
2403
|
+
t.media.play();
|
2404
|
+
}
|
2405
|
+
});
|
2406
|
+
|
2407
|
+
t.chapters.show();
|
2408
|
+
}
|
2409
|
+
});
|
2410
|
+
|
2411
|
+
|
2412
|
+
|
2413
|
+
mejs.language = {
|
2414
|
+
codes: {
|
2415
|
+
af:'Afrikaans',
|
2416
|
+
sq:'Albanian',
|
2417
|
+
ar:'Arabic',
|
2418
|
+
be:'Belarusian',
|
2419
|
+
bg:'Bulgarian',
|
2420
|
+
ca:'Catalan',
|
2421
|
+
zh:'Chinese',
|
2422
|
+
'zh-cn':'Chinese Simplified',
|
2423
|
+
'zh-tw':'Chinese Traditional',
|
2424
|
+
hr:'Croatian',
|
2425
|
+
cs:'Czech',
|
2426
|
+
da:'Danish',
|
2427
|
+
nl:'Dutch',
|
2428
|
+
en:'English',
|
2429
|
+
et:'Estonian',
|
2430
|
+
tl:'Filipino',
|
2431
|
+
fi:'Finnish',
|
2432
|
+
fr:'French',
|
2433
|
+
gl:'Galician',
|
2434
|
+
de:'German',
|
2435
|
+
el:'Greek',
|
2436
|
+
ht:'Haitian Creole',
|
2437
|
+
iw:'Hebrew',
|
2438
|
+
hi:'Hindi',
|
2439
|
+
hu:'Hungarian',
|
2440
|
+
is:'Icelandic',
|
2441
|
+
id:'Indonesian',
|
2442
|
+
ga:'Irish',
|
2443
|
+
it:'Italian',
|
2444
|
+
ja:'Japanese',
|
2445
|
+
ko:'Korean',
|
2446
|
+
lv:'Latvian',
|
2447
|
+
lt:'Lithuanian',
|
2448
|
+
mk:'Macedonian',
|
2449
|
+
ms:'Malay',
|
2450
|
+
mt:'Maltese',
|
2451
|
+
no:'Norwegian',
|
2452
|
+
fa:'Persian',
|
2453
|
+
pl:'Polish',
|
2454
|
+
pt:'Portuguese',
|
2455
|
+
//'pt-pt':'Portuguese (Portugal)',
|
2456
|
+
ro:'Romanian',
|
2457
|
+
ru:'Russian',
|
2458
|
+
sr:'Serbian',
|
2459
|
+
sk:'Slovak',
|
2460
|
+
sl:'Slovenian',
|
2461
|
+
es:'Spanish',
|
2462
|
+
sw:'Swahili',
|
2463
|
+
sv:'Swedish',
|
2464
|
+
tl:'Tagalog',
|
2465
|
+
th:'Thai',
|
2466
|
+
tr:'Turkish',
|
2467
|
+
uk:'Ukrainian',
|
2468
|
+
vi:'Vietnamese',
|
2469
|
+
cy:'Welsh',
|
2470
|
+
yi:'Yiddish'
|
2471
|
+
}
|
2472
|
+
};
|
2473
|
+
|
2474
|
+
/*
|
2475
|
+
Parses WebVVT format which should be formatted as
|
2476
|
+
================================
|
2477
|
+
WEBVTT
|
2478
|
+
|
2479
|
+
1
|
2480
|
+
00:00:01,1 --> 00:00:05,000
|
2481
|
+
A line of text
|
2482
|
+
|
2483
|
+
2
|
2484
|
+
00:01:15,1 --> 00:02:05,000
|
2485
|
+
A second line of text
|
2486
|
+
|
2487
|
+
===============================
|
2488
|
+
|
2489
|
+
Adapted from: http://www.delphiki.com/html5/playr
|
2490
|
+
*/
|
2491
|
+
mejs.TrackFormatParser = {
|
2492
|
+
// match start "chapter-" (or anythingelse)
|
2493
|
+
pattern_identifier: /^([a-zA-z]+-)?[0-9]+$/,
|
2494
|
+
pattern_timecode: /^([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/,
|
2495
|
+
|
2496
|
+
split2: function (text, regex) {
|
2497
|
+
// normal version for compliant browsers
|
2498
|
+
// see below for IE fix
|
2499
|
+
return text.split(regex);
|
2500
|
+
},
|
2501
|
+
parse: function(trackText) {
|
2502
|
+
var
|
2503
|
+
i = 0,
|
2504
|
+
lines = this.split2(trackText, /\r?\n/),
|
2505
|
+
entries = {text:[], times:[]},
|
2506
|
+
timecode,
|
2507
|
+
text;
|
2508
|
+
|
2509
|
+
for(; i<lines.length; i++) {
|
2510
|
+
// check for the line number
|
2511
|
+
if (this.pattern_identifier.exec(lines[i])){
|
2512
|
+
// skip to the next line where the start --> end time code should be
|
2513
|
+
i++;
|
2514
|
+
timecode = this.pattern_timecode.exec(lines[i]);
|
2515
|
+
|
2516
|
+
if (timecode && i<lines.length){
|
2517
|
+
i++;
|
2518
|
+
// grab all the (possibly multi-line) text that follows
|
2519
|
+
text = lines[i];
|
2520
|
+
i++;
|
2521
|
+
while(lines[i] !== '' && i<lines.length){
|
2522
|
+
text = text + '\n' + lines[i];
|
2523
|
+
i++;
|
2524
|
+
}
|
2525
|
+
|
2526
|
+
// Text is in a different array so I can use .join
|
2527
|
+
entries.text.push(text);
|
2528
|
+
entries.times.push(
|
2529
|
+
{
|
2530
|
+
start: mejs.Utility.timeCodeToSeconds(timecode[1]),
|
2531
|
+
stop: mejs.Utility.timeCodeToSeconds(timecode[3]),
|
2532
|
+
settings: timecode[5]
|
2533
|
+
});
|
2534
|
+
}
|
2535
|
+
}
|
2536
|
+
}
|
2537
|
+
|
2538
|
+
return entries;
|
2539
|
+
}
|
2540
|
+
};
|
2541
|
+
|
2542
|
+
// test for browsers with bad String.split method.
|
2543
|
+
if ('x\n\ny'.split(/\n/gi).length != 3) {
|
2544
|
+
// add super slow IE8 and below version
|
2545
|
+
mejs.TrackFormatParser.split2 = function(text, regex) {
|
2546
|
+
var
|
2547
|
+
parts = [],
|
2548
|
+
chunk = '',
|
2549
|
+
i;
|
2550
|
+
|
2551
|
+
for (i=0; i<text.length; i++) {
|
2552
|
+
chunk += text.substring(i,i+1);
|
2553
|
+
if (regex.test(chunk)) {
|
2554
|
+
parts.push(chunk.replace(regex, ''));
|
2555
|
+
chunk = '';
|
2556
|
+
}
|
2557
|
+
}
|
2558
|
+
parts.push(chunk);
|
2559
|
+
return parts;
|
2560
|
+
}
|
2561
|
+
}
|
2562
|
+
|
2563
|
+
})(mejs.$);
|
2564
|
+
|
2565
|
+
/*
|
2566
|
+
* ContextMenu Plugin
|
2567
|
+
*
|
2568
|
+
*
|
2569
|
+
*/
|
2570
|
+
|
2571
|
+
(function($) {
|
2572
|
+
|
2573
|
+
$.extend(mejs.MepDefaults,
|
2574
|
+
{ 'contextMenuItems': [
|
2575
|
+
// demo of a fullscreen option
|
2576
|
+
{
|
2577
|
+
render: function(player) {
|
2578
|
+
|
2579
|
+
// check for fullscreen plugin
|
2580
|
+
if (typeof player.enterFullScreen == 'undefined')
|
2581
|
+
return null;
|
2582
|
+
|
2583
|
+
if (player.isFullScreen) {
|
2584
|
+
return "Turn off Fullscreen";
|
2585
|
+
} else {
|
2586
|
+
return "Go Fullscreen";
|
2587
|
+
}
|
2588
|
+
},
|
2589
|
+
click: function(player) {
|
2590
|
+
if (player.isFullScreen) {
|
2591
|
+
player.exitFullScreen();
|
2592
|
+
} else {
|
2593
|
+
player.enterFullScreen();
|
2594
|
+
}
|
2595
|
+
}
|
2596
|
+
}
|
2597
|
+
,
|
2598
|
+
// demo of a mute/unmute button
|
2599
|
+
{
|
2600
|
+
render: function(player) {
|
2601
|
+
if (player.media.muted) {
|
2602
|
+
return "Unmute";
|
2603
|
+
} else {
|
2604
|
+
return "Mute";
|
2605
|
+
}
|
2606
|
+
},
|
2607
|
+
click: function(player) {
|
2608
|
+
if (player.media.muted) {
|
2609
|
+
player.setMuted(false);
|
2610
|
+
} else {
|
2611
|
+
player.setMuted(true);
|
2612
|
+
}
|
2613
|
+
}
|
2614
|
+
},
|
2615
|
+
// separator
|
2616
|
+
{
|
2617
|
+
isSeparator: true
|
2618
|
+
}
|
2619
|
+
,
|
2620
|
+
// demo of simple download video
|
2621
|
+
{
|
2622
|
+
render: function(player) {
|
2623
|
+
return "Download Video";
|
2624
|
+
},
|
2625
|
+
click: function(player) {
|
2626
|
+
window.location.href = player.media.currentSrc;
|
2627
|
+
}
|
2628
|
+
}
|
2629
|
+
]}
|
2630
|
+
);
|
2631
|
+
|
2632
|
+
|
2633
|
+
$.extend(MediaElementPlayer.prototype, {
|
2634
|
+
buildcontextmenu: function(player, controls, layers, media) {
|
2635
|
+
|
2636
|
+
// create context menu
|
2637
|
+
player.contextMenu = $('<div class="mejs-contextmenu"></div>')
|
2638
|
+
.appendTo($('body'))
|
2639
|
+
.hide();
|
2640
|
+
|
2641
|
+
// create events for showing context menu
|
2642
|
+
player.container.bind('contextmenu', function(e) {
|
2643
|
+
if (player.isContextMenuEnabled) {
|
2644
|
+
e.preventDefault();
|
2645
|
+
player.renderContextMenu(e.clientX-1, e.clientY-1);
|
2646
|
+
return false;
|
2647
|
+
}
|
2648
|
+
});
|
2649
|
+
player.container.bind('click', function() {
|
2650
|
+
player.contextMenu.hide();
|
2651
|
+
});
|
2652
|
+
player.contextMenu.bind('mouseleave', function() {
|
2653
|
+
|
2654
|
+
//console.log('context hover out');
|
2655
|
+
player.startContextMenuTimer();
|
2656
|
+
|
2657
|
+
});
|
2658
|
+
},
|
2659
|
+
|
2660
|
+
isContextMenuEnabled: true,
|
2661
|
+
enableContextMenu: function() {
|
2662
|
+
this.isContextMenuEnabled = true;
|
2663
|
+
},
|
2664
|
+
disableContextMenu: function() {
|
2665
|
+
this.isContextMenuEnabled = false;
|
2666
|
+
},
|
2667
|
+
|
2668
|
+
contextMenuTimeout: null,
|
2669
|
+
startContextMenuTimer: function() {
|
2670
|
+
//console.log('startContextMenuTimer');
|
2671
|
+
|
2672
|
+
var t = this;
|
2673
|
+
|
2674
|
+
t.killContextMenuTimer();
|
2675
|
+
|
2676
|
+
t.contextMenuTimer = setTimeout(function() {
|
2677
|
+
t.hideContextMenu();
|
2678
|
+
t.killContextMenuTimer();
|
2679
|
+
}, 750);
|
2680
|
+
},
|
2681
|
+
killContextMenuTimer: function() {
|
2682
|
+
var timer = this.contextMenuTimer;
|
2683
|
+
|
2684
|
+
//console.log('killContextMenuTimer', timer);
|
2685
|
+
|
2686
|
+
if (timer != null) {
|
2687
|
+
clearTimeout(timer);
|
2688
|
+
delete timer;
|
2689
|
+
timer = null;
|
2690
|
+
}
|
2691
|
+
},
|
2692
|
+
|
2693
|
+
hideContextMenu: function() {
|
2694
|
+
this.contextMenu.hide();
|
2695
|
+
},
|
2696
|
+
|
2697
|
+
renderContextMenu: function(x,y) {
|
2698
|
+
|
2699
|
+
// alway re-render the items so that things like "turn fullscreen on" and "turn fullscreen off" are always written correctly
|
2700
|
+
var t = this,
|
2701
|
+
html = '',
|
2702
|
+
items = t.options.contextMenuItems;
|
2703
|
+
|
2704
|
+
for (var i=0, il=items.length; i<il; i++) {
|
2705
|
+
|
2706
|
+
if (items[i].isSeparator) {
|
2707
|
+
html += '<div class="mejs-contextmenu-separator"></div>';
|
2708
|
+
} else {
|
2709
|
+
|
2710
|
+
var rendered = items[i].render(t);
|
2711
|
+
|
2712
|
+
// render can return null if the item doesn't need to be used at the moment
|
2713
|
+
if (rendered != null) {
|
2714
|
+
html += '<div class="mejs-contextmenu-item" data-itemindex="' + i + '" id="element-' + (Math.random()*1000000) + '">' + rendered + '</div>';
|
2715
|
+
}
|
2716
|
+
}
|
2717
|
+
}
|
2718
|
+
|
2719
|
+
// position and show the context menu
|
2720
|
+
t.contextMenu
|
2721
|
+
.empty()
|
2722
|
+
.append($(html))
|
2723
|
+
.css({top:y, left:x})
|
2724
|
+
.show();
|
2725
|
+
|
2726
|
+
// bind events
|
2727
|
+
t.contextMenu.find('.mejs-contextmenu-item').each(function() {
|
2728
|
+
|
2729
|
+
// which one is this?
|
2730
|
+
var $dom = $(this),
|
2731
|
+
itemIndex = parseInt( $dom.data('itemindex'), 10 ),
|
2732
|
+
item = t.options.contextMenuItems[itemIndex];
|
2733
|
+
|
2734
|
+
// bind extra functionality?
|
2735
|
+
if (typeof item.show != 'undefined')
|
2736
|
+
item.show( $dom , t);
|
2737
|
+
|
2738
|
+
// bind click action
|
2739
|
+
$dom.click(function() {
|
2740
|
+
// perform click action
|
2741
|
+
if (typeof item.click != 'undefined')
|
2742
|
+
item.click(t);
|
2743
|
+
|
2744
|
+
// close
|
2745
|
+
t.contextMenu.hide();
|
2746
|
+
});
|
2747
|
+
});
|
2748
|
+
|
2749
|
+
// stop the controls from hiding
|
2750
|
+
setTimeout(function() {
|
2751
|
+
t.killControlsTimer('rev3');
|
2752
|
+
}, 100);
|
2753
|
+
|
2754
|
+
}
|
2755
|
+
});
|
2756
|
+
|
2757
|
+
})(mejs.$);
|