rdoroshenko_mediaelement_rails 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2011 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# MediaelementRails #
|
2
|
+
|
3
|
+
This neat project brings the cool [MediaElement.js](http://mediaelementjs.com/) (HTML5/Flash/Silverlight video player) to the Rails asset pipeline.
|
4
|
+
|
5
|
+
## All you have to do is: ##
|
6
|
+
|
7
|
+
Add the gem to the list of required gems in your `Gemfile`:
|
8
|
+
|
9
|
+
``` ruby
|
10
|
+
# ...
|
11
|
+
gem "mediaelement_rails"
|
12
|
+
# ...
|
13
|
+
```
|
14
|
+
|
15
|
+
### Javascript ###
|
16
|
+
|
17
|
+
Load the Mediaelement Javascript in your `application.js`:
|
18
|
+
|
19
|
+
``` javascript
|
20
|
+
//= require mediaelement_rails
|
21
|
+
```
|
22
|
+
|
23
|
+
### And CSS ###
|
24
|
+
|
25
|
+
Load the Mediaelement CSS in your `application.css`:
|
26
|
+
|
27
|
+
``` css
|
28
|
+
/*
|
29
|
+
*= require mediaelement_rails
|
30
|
+
* and optionally:
|
31
|
+
*= require mediaelement_rails/mejs-skins
|
32
|
+
*/
|
33
|
+
```
|
34
|
+
|
35
|
+
## Wanna use MediaElement (not the player) only? ##
|
36
|
+
|
37
|
+
This is easy as hell too!
|
38
|
+
Don't include any CSS and include the following in your `application.js` to get it working:
|
39
|
+
|
40
|
+
``` javascript
|
41
|
+
//= require mediaelement_rails/rails
|
42
|
+
```
|
43
|
+
|
44
|
+
## Anything else I should know? ##
|
45
|
+
|
46
|
+
Nothing special! This project includes all assets you might need.
|
47
|
+
|
48
|
+
This project rocks and uses MIT-LICENSE.
|
data/Rakefile
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,1544 @@
|
|
1
|
+
/*!
|
2
|
+
* MediaElement.js
|
3
|
+
* HTML5 <video> and <audio> shim and player
|
4
|
+
* http://mediaelementjs.com/
|
5
|
+
*
|
6
|
+
* Creates a JavaScript object that mimics HTML5 MediaElement API
|
7
|
+
* for browsers that don't understand HTML5 or can't play the provided codec
|
8
|
+
* Can play MP4 (H.264), Ogg, WebM, FLV, WMV, WMA, ACC, and MP3
|
9
|
+
*
|
10
|
+
* Copyright 2010-2012, John Dyer (http://j.hn)
|
11
|
+
* Dual licensed under the MIT or GPL Version 2 licenses.
|
12
|
+
*
|
13
|
+
*/
|
14
|
+
// Namespace
|
15
|
+
var mejs = mejs || {};
|
16
|
+
|
17
|
+
// version number
|
18
|
+
mejs.version = '2.9.1';
|
19
|
+
|
20
|
+
// player number (for missing, same id attr)
|
21
|
+
mejs.meIndex = 0;
|
22
|
+
|
23
|
+
// media types accepted by plugins
|
24
|
+
mejs.plugins = {
|
25
|
+
silverlight: [
|
26
|
+
{version: [3,0], types: ['video/mp4','video/m4v','video/mov','video/wmv','audio/wma','audio/m4a','audio/mp3','audio/wav','audio/mpeg']}
|
27
|
+
],
|
28
|
+
flash: [
|
29
|
+
{version: [9,0,124], types: ['video/mp4','video/m4v','video/mov','video/flv','video/x-flv','audio/flv','audio/x-flv','audio/mp3','audio/m4a','audio/mpeg', 'video/youtube', 'video/x-youtube']}
|
30
|
+
//,{version: [12,0], types: ['video/webm']} // for future reference (hopefully!)
|
31
|
+
],
|
32
|
+
youtube: [
|
33
|
+
{version: null, types: ['video/youtube', 'video/x-youtube']}
|
34
|
+
],
|
35
|
+
vimeo: [
|
36
|
+
{version: null, types: ['video/vimeo']}
|
37
|
+
]
|
38
|
+
};
|
39
|
+
|
40
|
+
/*
|
41
|
+
Utility methods
|
42
|
+
*/
|
43
|
+
mejs.Utility = {
|
44
|
+
encodeUrl: function(url) {
|
45
|
+
return encodeURIComponent(url); //.replace(/\?/gi,'%3F').replace(/=/gi,'%3D').replace(/&/gi,'%26');
|
46
|
+
},
|
47
|
+
escapeHTML: function(s) {
|
48
|
+
return s.toString().split('&').join('&').split('<').join('<').split('"').join('"');
|
49
|
+
},
|
50
|
+
absolutizeUrl: function(url) {
|
51
|
+
var el = document.createElement('div');
|
52
|
+
el.innerHTML = '<a href="' + this.escapeHTML(url) + '">x</a>';
|
53
|
+
return el.firstChild.href;
|
54
|
+
},
|
55
|
+
getScriptPath: function(scriptNames) {
|
56
|
+
var
|
57
|
+
i = 0,
|
58
|
+
j,
|
59
|
+
path = '',
|
60
|
+
name = '',
|
61
|
+
script,
|
62
|
+
scripts = document.getElementsByTagName('script'),
|
63
|
+
il = scripts.length,
|
64
|
+
jl = scriptNames.length;
|
65
|
+
|
66
|
+
for (; i < il; i++) {
|
67
|
+
script = scripts[i].src;
|
68
|
+
for (j = 0; j < jl; j++) {
|
69
|
+
name = scriptNames[j];
|
70
|
+
if (script.indexOf(name) > -1) {
|
71
|
+
path = script.substring(0, script.indexOf(name));
|
72
|
+
break;
|
73
|
+
}
|
74
|
+
}
|
75
|
+
if (path !== '') {
|
76
|
+
break;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
return path;
|
80
|
+
},
|
81
|
+
secondsToTimeCode: function(time, forceHours, showFrameCount, fps) {
|
82
|
+
//add framecount
|
83
|
+
if (typeof showFrameCount == 'undefined') {
|
84
|
+
showFrameCount=false;
|
85
|
+
} else if(typeof fps == 'undefined') {
|
86
|
+
fps = 25;
|
87
|
+
}
|
88
|
+
|
89
|
+
var hours = Math.floor(time / 3600) % 24,
|
90
|
+
minutes = Math.floor(time / 60) % 60,
|
91
|
+
seconds = Math.floor(time % 60),
|
92
|
+
frames = Math.floor(((time % 1)*fps).toFixed(3)),
|
93
|
+
result =
|
94
|
+
( (forceHours || hours > 0) ? (hours < 10 ? '0' + hours : hours) + ':' : '')
|
95
|
+
+ (minutes < 10 ? '0' + minutes : minutes) + ':'
|
96
|
+
+ (seconds < 10 ? '0' + seconds : seconds)
|
97
|
+
+ ((showFrameCount) ? ':' + (frames < 10 ? '0' + frames : frames) : '');
|
98
|
+
|
99
|
+
return result;
|
100
|
+
},
|
101
|
+
|
102
|
+
timeCodeToSeconds: function(hh_mm_ss_ff, forceHours, showFrameCount, fps){
|
103
|
+
if (typeof showFrameCount == 'undefined') {
|
104
|
+
showFrameCount=false;
|
105
|
+
} else if(typeof fps == 'undefined') {
|
106
|
+
fps = 25;
|
107
|
+
}
|
108
|
+
|
109
|
+
var tc_array = hh_mm_ss_ff.split(":"),
|
110
|
+
tc_hh = parseInt(tc_array[0], 10),
|
111
|
+
tc_mm = parseInt(tc_array[1], 10),
|
112
|
+
tc_ss = parseInt(tc_array[2], 10),
|
113
|
+
tc_ff = 0,
|
114
|
+
tc_in_seconds = 0;
|
115
|
+
|
116
|
+
if (showFrameCount) {
|
117
|
+
tc_ff = parseInt(tc_array[3])/fps;
|
118
|
+
}
|
119
|
+
|
120
|
+
tc_in_seconds = ( tc_hh * 3600 ) + ( tc_mm * 60 ) + tc_ss + tc_ff;
|
121
|
+
|
122
|
+
return tc_in_seconds;
|
123
|
+
},
|
124
|
+
|
125
|
+
/* borrowed from SWFObject: http://code.google.com/p/swfobject/source/browse/trunk/swfobject/src/swfobject.js#474 */
|
126
|
+
removeSwf: function(id) {
|
127
|
+
var obj = document.getElementById(id);
|
128
|
+
if (obj && obj.nodeName == "OBJECT") {
|
129
|
+
if (mejs.MediaFeatures.isIE) {
|
130
|
+
obj.style.display = "none";
|
131
|
+
(function(){
|
132
|
+
if (obj.readyState == 4) {
|
133
|
+
mejs.Utility.removeObjectInIE(id);
|
134
|
+
} else {
|
135
|
+
setTimeout(arguments.callee, 10);
|
136
|
+
}
|
137
|
+
})();
|
138
|
+
} else {
|
139
|
+
obj.parentNode.removeChild(obj);
|
140
|
+
}
|
141
|
+
}
|
142
|
+
},
|
143
|
+
removeObjectInIE: function(id) {
|
144
|
+
var obj = document.getElementById(id);
|
145
|
+
if (obj) {
|
146
|
+
for (var i in obj) {
|
147
|
+
if (typeof obj[i] == "function") {
|
148
|
+
obj[i] = null;
|
149
|
+
}
|
150
|
+
}
|
151
|
+
obj.parentNode.removeChild(obj);
|
152
|
+
}
|
153
|
+
}
|
154
|
+
};
|
155
|
+
|
156
|
+
|
157
|
+
// Core detector, plugins are added below
|
158
|
+
mejs.PluginDetector = {
|
159
|
+
|
160
|
+
// main public function to test a plug version number PluginDetector.hasPluginVersion('flash',[9,0,125]);
|
161
|
+
hasPluginVersion: function(plugin, v) {
|
162
|
+
var pv = this.plugins[plugin];
|
163
|
+
v[1] = v[1] || 0;
|
164
|
+
v[2] = v[2] || 0;
|
165
|
+
return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
|
166
|
+
},
|
167
|
+
|
168
|
+
// cached values
|
169
|
+
nav: window.navigator,
|
170
|
+
ua: window.navigator.userAgent.toLowerCase(),
|
171
|
+
|
172
|
+
// stored version numbers
|
173
|
+
plugins: [],
|
174
|
+
|
175
|
+
// runs detectPlugin() and stores the version number
|
176
|
+
addPlugin: function(p, pluginName, mimeType, activeX, axDetect) {
|
177
|
+
this.plugins[p] = this.detectPlugin(pluginName, mimeType, activeX, axDetect);
|
178
|
+
},
|
179
|
+
|
180
|
+
// get the version number from the mimetype (all but IE) or ActiveX (IE)
|
181
|
+
detectPlugin: function(pluginName, mimeType, activeX, axDetect) {
|
182
|
+
|
183
|
+
var version = [0,0,0],
|
184
|
+
description,
|
185
|
+
i,
|
186
|
+
ax;
|
187
|
+
|
188
|
+
// Firefox, Webkit, Opera
|
189
|
+
if (typeof(this.nav.plugins) != 'undefined' && typeof this.nav.plugins[pluginName] == 'object') {
|
190
|
+
description = this.nav.plugins[pluginName].description;
|
191
|
+
if (description && !(typeof this.nav.mimeTypes != 'undefined' && this.nav.mimeTypes[mimeType] && !this.nav.mimeTypes[mimeType].enabledPlugin)) {
|
192
|
+
version = description.replace(pluginName, '').replace(/^\s+/,'').replace(/\sr/gi,'.').split('.');
|
193
|
+
for (i=0; i<version.length; i++) {
|
194
|
+
version[i] = parseInt(version[i].match(/\d+/), 10);
|
195
|
+
}
|
196
|
+
}
|
197
|
+
// Internet Explorer / ActiveX
|
198
|
+
} else if (typeof(window.ActiveXObject) != 'undefined') {
|
199
|
+
try {
|
200
|
+
ax = new ActiveXObject(activeX);
|
201
|
+
if (ax) {
|
202
|
+
version = axDetect(ax);
|
203
|
+
}
|
204
|
+
}
|
205
|
+
catch (e) { }
|
206
|
+
}
|
207
|
+
return version;
|
208
|
+
}
|
209
|
+
};
|
210
|
+
|
211
|
+
// Add Flash detection
|
212
|
+
mejs.PluginDetector.addPlugin('flash','Shockwave Flash','application/x-shockwave-flash','ShockwaveFlash.ShockwaveFlash', function(ax) {
|
213
|
+
// adapted from SWFObject
|
214
|
+
var version = [],
|
215
|
+
d = ax.GetVariable("$version");
|
216
|
+
if (d) {
|
217
|
+
d = d.split(" ")[1].split(",");
|
218
|
+
version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
|
219
|
+
}
|
220
|
+
return version;
|
221
|
+
});
|
222
|
+
|
223
|
+
// Add Silverlight detection
|
224
|
+
mejs.PluginDetector.addPlugin('silverlight','Silverlight Plug-In','application/x-silverlight-2','AgControl.AgControl', function (ax) {
|
225
|
+
// Silverlight cannot report its version number to IE
|
226
|
+
// but it does have a isVersionSupported function, so we have to loop through it to get a version number.
|
227
|
+
// adapted from http://www.silverlightversion.com/
|
228
|
+
var v = [0,0,0,0],
|
229
|
+
loopMatch = function(ax, v, i, n) {
|
230
|
+
while(ax.isVersionSupported(v[0]+ "."+ v[1] + "." + v[2] + "." + v[3])){
|
231
|
+
v[i]+=n;
|
232
|
+
}
|
233
|
+
v[i] -= n;
|
234
|
+
};
|
235
|
+
loopMatch(ax, v, 0, 1);
|
236
|
+
loopMatch(ax, v, 1, 1);
|
237
|
+
loopMatch(ax, v, 2, 10000); // the third place in the version number is usually 5 digits (4.0.xxxxx)
|
238
|
+
loopMatch(ax, v, 2, 1000);
|
239
|
+
loopMatch(ax, v, 2, 100);
|
240
|
+
loopMatch(ax, v, 2, 10);
|
241
|
+
loopMatch(ax, v, 2, 1);
|
242
|
+
loopMatch(ax, v, 3, 1);
|
243
|
+
|
244
|
+
return v;
|
245
|
+
});
|
246
|
+
// add adobe acrobat
|
247
|
+
/*
|
248
|
+
PluginDetector.addPlugin('acrobat','Adobe Acrobat','application/pdf','AcroPDF.PDF', function (ax) {
|
249
|
+
var version = [],
|
250
|
+
d = ax.GetVersions().split(',')[0].split('=')[1].split('.');
|
251
|
+
|
252
|
+
if (d) {
|
253
|
+
version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
|
254
|
+
}
|
255
|
+
return version;
|
256
|
+
});
|
257
|
+
*/
|
258
|
+
// necessary detection (fixes for <IE9)
|
259
|
+
mejs.MediaFeatures = {
|
260
|
+
init: function() {
|
261
|
+
var
|
262
|
+
t = this,
|
263
|
+
d = document,
|
264
|
+
nav = mejs.PluginDetector.nav,
|
265
|
+
ua = mejs.PluginDetector.ua.toLowerCase(),
|
266
|
+
i,
|
267
|
+
v,
|
268
|
+
html5Elements = ['source','track','audio','video'];
|
269
|
+
|
270
|
+
// detect browsers (only the ones that have some kind of quirk we need to work around)
|
271
|
+
t.isiPad = (ua.match(/ipad/i) !== null);
|
272
|
+
t.isiPhone = (ua.match(/iphone/i) !== null);
|
273
|
+
t.isiOS = t.isiPhone || t.isiPad;
|
274
|
+
t.isAndroid = (ua.match(/android/i) !== null);
|
275
|
+
t.isBustedAndroid = (ua.match(/android 2\.[12]/) !== null);
|
276
|
+
t.isIE = (nav.appName.toLowerCase().indexOf("microsoft") != -1);
|
277
|
+
t.isChrome = (ua.match(/chrome/gi) !== null);
|
278
|
+
t.isFirefox = (ua.match(/firefox/gi) !== null);
|
279
|
+
t.isWebkit = (ua.match(/webkit/gi) !== null);
|
280
|
+
t.isGecko = (ua.match(/gecko/gi) !== null) && !t.isWebkit;
|
281
|
+
t.isOpera = (ua.match(/opera/gi) !== null);
|
282
|
+
t.hasTouch = ('ontouchstart' in window);
|
283
|
+
|
284
|
+
// create HTML5 media elements for IE before 9, get a <video> element for fullscreen detection
|
285
|
+
for (i=0; i<html5Elements.length; i++) {
|
286
|
+
v = document.createElement(html5Elements[i]);
|
287
|
+
}
|
288
|
+
|
289
|
+
t.supportsMediaTag = (typeof v.canPlayType !== 'undefined' || t.isBustedAndroid);
|
290
|
+
|
291
|
+
// detect native JavaScript fullscreen (Safari/Firefox only, Chrome still fails)
|
292
|
+
|
293
|
+
// iOS
|
294
|
+
t.hasSemiNativeFullScreen = (typeof v.webkitEnterFullscreen !== 'undefined');
|
295
|
+
|
296
|
+
// Webkit/firefox
|
297
|
+
t.hasWebkitNativeFullScreen = (typeof v.webkitRequestFullScreen !== 'undefined');
|
298
|
+
t.hasMozNativeFullScreen = (typeof v.mozRequestFullScreen !== 'undefined');
|
299
|
+
|
300
|
+
t.hasTrueNativeFullScreen = (t.hasWebkitNativeFullScreen || t.hasMozNativeFullScreen);
|
301
|
+
t.nativeFullScreenEnabled = t.hasTrueNativeFullScreen;
|
302
|
+
if (t.hasMozNativeFullScreen) {
|
303
|
+
t.nativeFullScreenEnabled = v.mozFullScreenEnabled;
|
304
|
+
}
|
305
|
+
|
306
|
+
|
307
|
+
if (this.isChrome) {
|
308
|
+
t.hasSemiNativeFullScreen = false;
|
309
|
+
}
|
310
|
+
|
311
|
+
if (t.hasTrueNativeFullScreen) {
|
312
|
+
t.fullScreenEventName = (t.hasWebkitNativeFullScreen) ? 'webkitfullscreenchange' : 'mozfullscreenchange';
|
313
|
+
|
314
|
+
|
315
|
+
t.isFullScreen = function() {
|
316
|
+
if (v.mozRequestFullScreen) {
|
317
|
+
return d.mozFullScreen;
|
318
|
+
} else if (v.webkitRequestFullScreen) {
|
319
|
+
return d.webkitIsFullScreen;
|
320
|
+
}
|
321
|
+
}
|
322
|
+
|
323
|
+
t.requestFullScreen = function(el) {
|
324
|
+
|
325
|
+
if (t.hasWebkitNativeFullScreen) {
|
326
|
+
el.webkitRequestFullScreen();
|
327
|
+
} else if (t.hasMozNativeFullScreen) {
|
328
|
+
el.mozRequestFullScreen();
|
329
|
+
}
|
330
|
+
}
|
331
|
+
|
332
|
+
t.cancelFullScreen = function() {
|
333
|
+
if (t.hasWebkitNativeFullScreen) {
|
334
|
+
document.webkitCancelFullScreen();
|
335
|
+
} else if (t.hasMozNativeFullScreen) {
|
336
|
+
document.mozCancelFullScreen();
|
337
|
+
}
|
338
|
+
}
|
339
|
+
|
340
|
+
}
|
341
|
+
|
342
|
+
|
343
|
+
// OS X 10.5 can't do this even if it says it can :(
|
344
|
+
if (t.hasSemiNativeFullScreen && ua.match(/mac os x 10_5/i)) {
|
345
|
+
t.hasNativeFullScreen = false;
|
346
|
+
t.hasSemiNativeFullScreen = false;
|
347
|
+
}
|
348
|
+
|
349
|
+
}
|
350
|
+
};
|
351
|
+
mejs.MediaFeatures.init();
|
352
|
+
|
353
|
+
|
354
|
+
/*
|
355
|
+
extension methods to <video> or <audio> object to bring it into parity with PluginMediaElement (see below)
|
356
|
+
*/
|
357
|
+
mejs.HtmlMediaElement = {
|
358
|
+
pluginType: 'native',
|
359
|
+
isFullScreen: false,
|
360
|
+
|
361
|
+
setCurrentTime: function (time) {
|
362
|
+
this.currentTime = time;
|
363
|
+
},
|
364
|
+
|
365
|
+
setMuted: function (muted) {
|
366
|
+
this.muted = muted;
|
367
|
+
},
|
368
|
+
|
369
|
+
setVolume: function (volume) {
|
370
|
+
this.volume = volume;
|
371
|
+
},
|
372
|
+
|
373
|
+
// for parity with the plugin versions
|
374
|
+
stop: function () {
|
375
|
+
this.pause();
|
376
|
+
},
|
377
|
+
|
378
|
+
// This can be a url string
|
379
|
+
// or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
|
380
|
+
setSrc: function (url) {
|
381
|
+
|
382
|
+
// Fix for IE9 which can't set .src when there are <source> elements. Awesome, right?
|
383
|
+
var
|
384
|
+
existingSources = this.getElementsByTagName('source');
|
385
|
+
while (existingSources.length > 0){
|
386
|
+
this.removeChild(existingSources[0]);
|
387
|
+
}
|
388
|
+
|
389
|
+
if (typeof url == 'string') {
|
390
|
+
this.src = url;
|
391
|
+
} else {
|
392
|
+
var i, media;
|
393
|
+
|
394
|
+
for (i=0; i<url.length; i++) {
|
395
|
+
media = url[i];
|
396
|
+
if (this.canPlayType(media.type)) {
|
397
|
+
this.src = media.src;
|
398
|
+
}
|
399
|
+
}
|
400
|
+
}
|
401
|
+
},
|
402
|
+
|
403
|
+
setVideoSize: function (width, height) {
|
404
|
+
this.width = width;
|
405
|
+
this.height = height;
|
406
|
+
}
|
407
|
+
};
|
408
|
+
|
409
|
+
/*
|
410
|
+
Mimics the <video/audio> element by calling Flash's External Interface or Silverlights [ScriptableMember]
|
411
|
+
*/
|
412
|
+
mejs.PluginMediaElement = function (pluginid, pluginType, mediaUrl) {
|
413
|
+
this.id = pluginid;
|
414
|
+
this.pluginType = pluginType;
|
415
|
+
this.src = mediaUrl;
|
416
|
+
this.events = {};
|
417
|
+
};
|
418
|
+
|
419
|
+
// JavaScript values and ExternalInterface methods that match HTML5 video properties methods
|
420
|
+
// http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/fl/video/FLVPlayback.html
|
421
|
+
// http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
|
422
|
+
mejs.PluginMediaElement.prototype = {
|
423
|
+
|
424
|
+
// special
|
425
|
+
pluginElement: null,
|
426
|
+
pluginType: '',
|
427
|
+
isFullScreen: false,
|
428
|
+
|
429
|
+
// not implemented :(
|
430
|
+
playbackRate: -1,
|
431
|
+
defaultPlaybackRate: -1,
|
432
|
+
seekable: [],
|
433
|
+
played: [],
|
434
|
+
|
435
|
+
// HTML5 read-only properties
|
436
|
+
paused: true,
|
437
|
+
ended: false,
|
438
|
+
seeking: false,
|
439
|
+
duration: 0,
|
440
|
+
error: null,
|
441
|
+
tagName: '',
|
442
|
+
|
443
|
+
// HTML5 get/set properties, but only set (updated by event handlers)
|
444
|
+
muted: false,
|
445
|
+
volume: 1,
|
446
|
+
currentTime: 0,
|
447
|
+
|
448
|
+
// HTML5 methods
|
449
|
+
play: function () {
|
450
|
+
if (this.pluginApi != null) {
|
451
|
+
if (this.pluginType == 'youtube') {
|
452
|
+
this.pluginApi.playVideo();
|
453
|
+
} else {
|
454
|
+
this.pluginApi.playMedia();
|
455
|
+
}
|
456
|
+
this.paused = false;
|
457
|
+
}
|
458
|
+
},
|
459
|
+
load: function () {
|
460
|
+
if (this.pluginApi != null) {
|
461
|
+
if (this.pluginType == 'youtube') {
|
462
|
+
} else {
|
463
|
+
this.pluginApi.loadMedia();
|
464
|
+
}
|
465
|
+
|
466
|
+
this.paused = false;
|
467
|
+
}
|
468
|
+
},
|
469
|
+
pause: function () {
|
470
|
+
if (this.pluginApi != null) {
|
471
|
+
if (this.pluginType == 'youtube') {
|
472
|
+
this.pluginApi.pauseVideo();
|
473
|
+
} else {
|
474
|
+
this.pluginApi.pauseMedia();
|
475
|
+
}
|
476
|
+
|
477
|
+
|
478
|
+
this.paused = true;
|
479
|
+
}
|
480
|
+
},
|
481
|
+
stop: function () {
|
482
|
+
if (this.pluginApi != null) {
|
483
|
+
if (this.pluginType == 'youtube') {
|
484
|
+
this.pluginApi.stopVideo();
|
485
|
+
} else {
|
486
|
+
this.pluginApi.stopMedia();
|
487
|
+
}
|
488
|
+
this.paused = true;
|
489
|
+
}
|
490
|
+
},
|
491
|
+
canPlayType: function(type) {
|
492
|
+
var i,
|
493
|
+
j,
|
494
|
+
pluginInfo,
|
495
|
+
pluginVersions = mejs.plugins[this.pluginType];
|
496
|
+
|
497
|
+
for (i=0; i<pluginVersions.length; i++) {
|
498
|
+
pluginInfo = pluginVersions[i];
|
499
|
+
|
500
|
+
// test if user has the correct plugin version
|
501
|
+
if (mejs.PluginDetector.hasPluginVersion(this.pluginType, pluginInfo.version)) {
|
502
|
+
|
503
|
+
// test for plugin playback types
|
504
|
+
for (j=0; j<pluginInfo.types.length; j++) {
|
505
|
+
// find plugin that can play the type
|
506
|
+
if (type == pluginInfo.types[j]) {
|
507
|
+
return true;
|
508
|
+
}
|
509
|
+
}
|
510
|
+
}
|
511
|
+
}
|
512
|
+
|
513
|
+
return false;
|
514
|
+
},
|
515
|
+
|
516
|
+
positionFullscreenButton: function(x,y,visibleAndAbove) {
|
517
|
+
if (this.pluginApi != null && this.pluginApi.positionFullscreenButton) {
|
518
|
+
this.pluginApi.positionFullscreenButton(x,y,visibleAndAbove);
|
519
|
+
}
|
520
|
+
},
|
521
|
+
|
522
|
+
hideFullscreenButton: function() {
|
523
|
+
if (this.pluginApi != null && this.pluginApi.hideFullscreenButton) {
|
524
|
+
this.pluginApi.hideFullscreenButton();
|
525
|
+
}
|
526
|
+
},
|
527
|
+
|
528
|
+
|
529
|
+
// custom methods since not all JavaScript implementations support get/set
|
530
|
+
|
531
|
+
// This can be a url string
|
532
|
+
// or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
|
533
|
+
setSrc: function (url) {
|
534
|
+
if (typeof url == 'string') {
|
535
|
+
this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(url));
|
536
|
+
this.src = mejs.Utility.absolutizeUrl(url);
|
537
|
+
} else {
|
538
|
+
var i, media;
|
539
|
+
|
540
|
+
for (i=0; i<url.length; i++) {
|
541
|
+
media = url[i];
|
542
|
+
if (this.canPlayType(media.type)) {
|
543
|
+
this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(media.src));
|
544
|
+
this.src = mejs.Utility.absolutizeUrl(url);
|
545
|
+
}
|
546
|
+
}
|
547
|
+
}
|
548
|
+
|
549
|
+
},
|
550
|
+
setCurrentTime: function (time) {
|
551
|
+
if (this.pluginApi != null) {
|
552
|
+
if (this.pluginType == 'youtube') {
|
553
|
+
this.pluginApi.seekTo(time);
|
554
|
+
} else {
|
555
|
+
this.pluginApi.setCurrentTime(time);
|
556
|
+
}
|
557
|
+
|
558
|
+
|
559
|
+
|
560
|
+
this.currentTime = time;
|
561
|
+
}
|
562
|
+
},
|
563
|
+
setVolume: function (volume) {
|
564
|
+
if (this.pluginApi != null) {
|
565
|
+
// same on YouTube and MEjs
|
566
|
+
if (this.pluginType == 'youtube') {
|
567
|
+
this.pluginApi.setVolume(volume * 100);
|
568
|
+
} else {
|
569
|
+
this.pluginApi.setVolume(volume);
|
570
|
+
}
|
571
|
+
this.volume = volume;
|
572
|
+
}
|
573
|
+
},
|
574
|
+
setMuted: function (muted) {
|
575
|
+
if (this.pluginApi != null) {
|
576
|
+
if (this.pluginType == 'youtube') {
|
577
|
+
if (muted) {
|
578
|
+
this.pluginApi.mute();
|
579
|
+
} else {
|
580
|
+
this.pluginApi.unMute();
|
581
|
+
}
|
582
|
+
this.muted = muted;
|
583
|
+
this.dispatchEvent('volumechange');
|
584
|
+
} else {
|
585
|
+
this.pluginApi.setMuted(muted);
|
586
|
+
}
|
587
|
+
this.muted = muted;
|
588
|
+
}
|
589
|
+
},
|
590
|
+
|
591
|
+
// additional non-HTML5 methods
|
592
|
+
setVideoSize: function (width, height) {
|
593
|
+
|
594
|
+
//if (this.pluginType == 'flash' || this.pluginType == 'silverlight') {
|
595
|
+
if ( this.pluginElement.style) {
|
596
|
+
this.pluginElement.style.width = width + 'px';
|
597
|
+
this.pluginElement.style.height = height + 'px';
|
598
|
+
}
|
599
|
+
if (this.pluginApi != null && this.pluginApi.setVideoSize) {
|
600
|
+
this.pluginApi.setVideoSize(width, height);
|
601
|
+
}
|
602
|
+
//}
|
603
|
+
},
|
604
|
+
|
605
|
+
setFullscreen: function (fullscreen) {
|
606
|
+
if (this.pluginApi != null && this.pluginApi.setFullscreen) {
|
607
|
+
this.pluginApi.setFullscreen(fullscreen);
|
608
|
+
}
|
609
|
+
},
|
610
|
+
|
611
|
+
enterFullScreen: function() {
|
612
|
+
if (this.pluginApi != null && this.pluginApi.setFullscreen) {
|
613
|
+
this.setFullscreen(true);
|
614
|
+
}
|
615
|
+
|
616
|
+
},
|
617
|
+
|
618
|
+
exitFullScreen: function() {
|
619
|
+
if (this.pluginApi != null && this.pluginApi.setFullscreen) {
|
620
|
+
this.setFullscreen(false);
|
621
|
+
}
|
622
|
+
},
|
623
|
+
|
624
|
+
// start: fake events
|
625
|
+
addEventListener: function (eventName, callback, bubble) {
|
626
|
+
this.events[eventName] = this.events[eventName] || [];
|
627
|
+
this.events[eventName].push(callback);
|
628
|
+
},
|
629
|
+
removeEventListener: function (eventName, callback) {
|
630
|
+
if (!eventName) { this.events = {}; return true; }
|
631
|
+
var callbacks = this.events[eventName];
|
632
|
+
if (!callbacks) return true;
|
633
|
+
if (!callback) { this.events[eventName] = []; return true; }
|
634
|
+
for (i = 0; i < callbacks.length; i++) {
|
635
|
+
if (callbacks[i] === callback) {
|
636
|
+
this.events[eventName].splice(i, 1);
|
637
|
+
return true;
|
638
|
+
}
|
639
|
+
}
|
640
|
+
return false;
|
641
|
+
},
|
642
|
+
dispatchEvent: function (eventName) {
|
643
|
+
var i,
|
644
|
+
args,
|
645
|
+
callbacks = this.events[eventName];
|
646
|
+
|
647
|
+
if (callbacks) {
|
648
|
+
args = Array.prototype.slice.call(arguments, 1);
|
649
|
+
for (i = 0; i < callbacks.length; i++) {
|
650
|
+
callbacks[i].apply(null, args);
|
651
|
+
}
|
652
|
+
}
|
653
|
+
},
|
654
|
+
// end: fake events
|
655
|
+
|
656
|
+
// fake DOM attribute methods
|
657
|
+
attributes: {},
|
658
|
+
hasAttribute: function(name){
|
659
|
+
return (name in this.attributes);
|
660
|
+
},
|
661
|
+
removeAttribute: function(name){
|
662
|
+
delete this.attributes[name];
|
663
|
+
},
|
664
|
+
getAttribute: function(name){
|
665
|
+
if (this.hasAttribute(name)) {
|
666
|
+
return this.attributes[name];
|
667
|
+
}
|
668
|
+
return '';
|
669
|
+
},
|
670
|
+
setAttribute: function(name, value){
|
671
|
+
this.attributes[name] = value;
|
672
|
+
},
|
673
|
+
|
674
|
+
remove: function() {
|
675
|
+
mejs.Utility.removeSwf(this.pluginElement.id);
|
676
|
+
}
|
677
|
+
};
|
678
|
+
|
679
|
+
// Handles calls from Flash/Silverlight and reports them as native <video/audio> events and properties
|
680
|
+
mejs.MediaPluginBridge = {
|
681
|
+
|
682
|
+
pluginMediaElements:{},
|
683
|
+
htmlMediaElements:{},
|
684
|
+
|
685
|
+
registerPluginElement: function (id, pluginMediaElement, htmlMediaElement) {
|
686
|
+
this.pluginMediaElements[id] = pluginMediaElement;
|
687
|
+
this.htmlMediaElements[id] = htmlMediaElement;
|
688
|
+
},
|
689
|
+
|
690
|
+
// when Flash/Silverlight is ready, it calls out to this method
|
691
|
+
initPlugin: function (id) {
|
692
|
+
|
693
|
+
var pluginMediaElement = this.pluginMediaElements[id],
|
694
|
+
htmlMediaElement = this.htmlMediaElements[id];
|
695
|
+
|
696
|
+
if (pluginMediaElement) {
|
697
|
+
// find the javascript bridge
|
698
|
+
switch (pluginMediaElement.pluginType) {
|
699
|
+
case "flash":
|
700
|
+
pluginMediaElement.pluginElement = pluginMediaElement.pluginApi = document.getElementById(id);
|
701
|
+
break;
|
702
|
+
case "silverlight":
|
703
|
+
pluginMediaElement.pluginElement = document.getElementById(pluginMediaElement.id);
|
704
|
+
pluginMediaElement.pluginApi = pluginMediaElement.pluginElement.Content.MediaElementJS;
|
705
|
+
break;
|
706
|
+
}
|
707
|
+
|
708
|
+
if (pluginMediaElement.pluginApi != null && pluginMediaElement.success) {
|
709
|
+
pluginMediaElement.success(pluginMediaElement, htmlMediaElement);
|
710
|
+
}
|
711
|
+
}
|
712
|
+
},
|
713
|
+
|
714
|
+
// receives events from Flash/Silverlight and sends them out as HTML5 media events
|
715
|
+
// http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
|
716
|
+
fireEvent: function (id, eventName, values) {
|
717
|
+
|
718
|
+
var
|
719
|
+
e,
|
720
|
+
i,
|
721
|
+
bufferedTime,
|
722
|
+
pluginMediaElement = this.pluginMediaElements[id];
|
723
|
+
|
724
|
+
pluginMediaElement.ended = false;
|
725
|
+
pluginMediaElement.paused = true;
|
726
|
+
|
727
|
+
// fake event object to mimic real HTML media event.
|
728
|
+
e = {
|
729
|
+
type: eventName,
|
730
|
+
target: pluginMediaElement
|
731
|
+
};
|
732
|
+
|
733
|
+
// attach all values to element and event object
|
734
|
+
for (i in values) {
|
735
|
+
pluginMediaElement[i] = values[i];
|
736
|
+
e[i] = values[i];
|
737
|
+
}
|
738
|
+
|
739
|
+
// fake the newer W3C buffered TimeRange (loaded and total have been removed)
|
740
|
+
bufferedTime = values.bufferedTime || 0;
|
741
|
+
|
742
|
+
e.target.buffered = e.buffered = {
|
743
|
+
start: function(index) {
|
744
|
+
return 0;
|
745
|
+
},
|
746
|
+
end: function (index) {
|
747
|
+
return bufferedTime;
|
748
|
+
},
|
749
|
+
length: 1
|
750
|
+
};
|
751
|
+
|
752
|
+
pluginMediaElement.dispatchEvent(e.type, e);
|
753
|
+
}
|
754
|
+
};
|
755
|
+
|
756
|
+
/*
|
757
|
+
Default options
|
758
|
+
*/
|
759
|
+
mejs.MediaElementDefaults = {
|
760
|
+
// allows testing on HTML5, flash, silverlight
|
761
|
+
// auto: attempts to detect what the browser can do
|
762
|
+
// auto_plugin: prefer plugins and then attempt native HTML5
|
763
|
+
// native: forces HTML5 playback
|
764
|
+
// shim: disallows HTML5, will attempt either Flash or Silverlight
|
765
|
+
// none: forces fallback view
|
766
|
+
mode: 'auto',
|
767
|
+
// remove or reorder to change plugin priority and availability
|
768
|
+
plugins: ['flash','silverlight','youtube','vimeo'],
|
769
|
+
// shows debug errors on screen
|
770
|
+
enablePluginDebug: false,
|
771
|
+
// overrides the type specified, useful for dynamic instantiation
|
772
|
+
type: '',
|
773
|
+
// path to Flash and Silverlight plugins
|
774
|
+
pluginPath: mejs.Utility.getScriptPath(['mediaelement.js','mediaelement.min.js','mediaelement-and-player.js','mediaelement-and-player.min.js']),
|
775
|
+
// name of flash file
|
776
|
+
flashName: 'flashmediaelement.swf',
|
777
|
+
// turns on the smoothing filter in Flash
|
778
|
+
enablePluginSmoothing: false,
|
779
|
+
// name of silverlight file
|
780
|
+
silverlightName: 'silverlightmediaelement.xap',
|
781
|
+
// default if the <video width> is not specified
|
782
|
+
defaultVideoWidth: 480,
|
783
|
+
// default if the <video height> is not specified
|
784
|
+
defaultVideoHeight: 270,
|
785
|
+
// overrides <video width>
|
786
|
+
pluginWidth: -1,
|
787
|
+
// overrides <video height>
|
788
|
+
pluginHeight: -1,
|
789
|
+
// additional plugin variables in 'key=value' form
|
790
|
+
pluginVars: [],
|
791
|
+
// rate in milliseconds for Flash and Silverlight to fire the timeupdate event
|
792
|
+
// larger number is less accurate, but less strain on plugin->JavaScript bridge
|
793
|
+
timerRate: 250,
|
794
|
+
// initial volume for player
|
795
|
+
startVolume: 0.8,
|
796
|
+
success: function () { },
|
797
|
+
error: function () { }
|
798
|
+
};
|
799
|
+
|
800
|
+
/*
|
801
|
+
Determines if a browser supports the <video> or <audio> element
|
802
|
+
and returns either the native element or a Flash/Silverlight version that
|
803
|
+
mimics HTML5 MediaElement
|
804
|
+
*/
|
805
|
+
mejs.MediaElement = function (el, o) {
|
806
|
+
return mejs.HtmlMediaElementShim.create(el,o);
|
807
|
+
};
|
808
|
+
|
809
|
+
mejs.HtmlMediaElementShim = {
|
810
|
+
|
811
|
+
create: function(el, o) {
|
812
|
+
var
|
813
|
+
options = mejs.MediaElementDefaults,
|
814
|
+
htmlMediaElement = (typeof(el) == 'string') ? document.getElementById(el) : el,
|
815
|
+
tagName = htmlMediaElement.tagName.toLowerCase(),
|
816
|
+
isMediaTag = (tagName === 'audio' || tagName === 'video'),
|
817
|
+
src = (isMediaTag) ? htmlMediaElement.getAttribute('src') : htmlMediaElement.getAttribute('href'),
|
818
|
+
poster = htmlMediaElement.getAttribute('poster'),
|
819
|
+
autoplay = htmlMediaElement.getAttribute('autoplay'),
|
820
|
+
preload = htmlMediaElement.getAttribute('preload'),
|
821
|
+
controls = htmlMediaElement.getAttribute('controls'),
|
822
|
+
playback,
|
823
|
+
prop;
|
824
|
+
|
825
|
+
// extend options
|
826
|
+
for (prop in o) {
|
827
|
+
options[prop] = o[prop];
|
828
|
+
}
|
829
|
+
|
830
|
+
// clean up attributes
|
831
|
+
src = (typeof src == 'undefined' || src === null || src == '') ? null : src;
|
832
|
+
poster = (typeof poster == 'undefined' || poster === null) ? '' : poster;
|
833
|
+
preload = (typeof preload == 'undefined' || preload === null || preload === 'false') ? 'none' : preload;
|
834
|
+
autoplay = !(typeof autoplay == 'undefined' || autoplay === null || autoplay === 'false');
|
835
|
+
controls = !(typeof controls == 'undefined' || controls === null || controls === 'false');
|
836
|
+
|
837
|
+
// test for HTML5 and plugin capabilities
|
838
|
+
playback = this.determinePlayback(htmlMediaElement, options, mejs.MediaFeatures.supportsMediaTag, isMediaTag, src);
|
839
|
+
playback.url = (playback.url !== null) ? mejs.Utility.absolutizeUrl(playback.url) : '';
|
840
|
+
|
841
|
+
if (playback.method == 'native') {
|
842
|
+
// second fix for android
|
843
|
+
if (mejs.MediaFeatures.isBustedAndroid) {
|
844
|
+
htmlMediaElement.src = playback.url;
|
845
|
+
htmlMediaElement.addEventListener('click', function() {
|
846
|
+
htmlMediaElement.play();
|
847
|
+
}, false);
|
848
|
+
}
|
849
|
+
|
850
|
+
// add methods to native HTMLMediaElement
|
851
|
+
return this.updateNative(playback, options, autoplay, preload);
|
852
|
+
} else if (playback.method !== '') {
|
853
|
+
// create plugin to mimic HTMLMediaElement
|
854
|
+
|
855
|
+
return this.createPlugin( playback, options, poster, autoplay, preload, controls);
|
856
|
+
} else {
|
857
|
+
// boo, no HTML5, no Flash, no Silverlight.
|
858
|
+
this.createErrorMessage( playback, options, poster );
|
859
|
+
|
860
|
+
return this;
|
861
|
+
}
|
862
|
+
},
|
863
|
+
|
864
|
+
determinePlayback: function(htmlMediaElement, options, supportsMediaTag, isMediaTag, src) {
|
865
|
+
var
|
866
|
+
mediaFiles = [],
|
867
|
+
i,
|
868
|
+
j,
|
869
|
+
k,
|
870
|
+
l,
|
871
|
+
n,
|
872
|
+
type,
|
873
|
+
result = { method: '', url: '', htmlMediaElement: htmlMediaElement, isVideo: (htmlMediaElement.tagName.toLowerCase() != 'audio')},
|
874
|
+
pluginName,
|
875
|
+
pluginVersions,
|
876
|
+
pluginInfo,
|
877
|
+
dummy;
|
878
|
+
|
879
|
+
// STEP 1: Get URL and type from <video src> or <source src>
|
880
|
+
|
881
|
+
// supplied type overrides <video type> and <source type>
|
882
|
+
if (typeof options.type != 'undefined' && options.type !== '') {
|
883
|
+
|
884
|
+
// accept either string or array of types
|
885
|
+
if (typeof options.type == 'string') {
|
886
|
+
mediaFiles.push({type:options.type, url:src});
|
887
|
+
} else {
|
888
|
+
|
889
|
+
for (i=0; i<options.type.length; i++) {
|
890
|
+
mediaFiles.push({type:options.type[i], url:src});
|
891
|
+
}
|
892
|
+
}
|
893
|
+
|
894
|
+
// test for src attribute first
|
895
|
+
} else if (src !== null) {
|
896
|
+
type = this.formatType(src, htmlMediaElement.getAttribute('type'));
|
897
|
+
mediaFiles.push({type:type, url:src});
|
898
|
+
|
899
|
+
// then test for <source> elements
|
900
|
+
} else {
|
901
|
+
// test <source> types to see if they are usable
|
902
|
+
for (i = 0; i < htmlMediaElement.childNodes.length; i++) {
|
903
|
+
n = htmlMediaElement.childNodes[i];
|
904
|
+
if (n.nodeType == 1 && n.tagName.toLowerCase() == 'source') {
|
905
|
+
src = n.getAttribute('src');
|
906
|
+
type = this.formatType(src, n.getAttribute('type'));
|
907
|
+
mediaFiles.push({type:type, url:src});
|
908
|
+
}
|
909
|
+
}
|
910
|
+
}
|
911
|
+
|
912
|
+
// in the case of dynamicly created players
|
913
|
+
// check for audio types
|
914
|
+
if (!isMediaTag && mediaFiles.length > 0 && mediaFiles[0].url !== null && this.getTypeFromFile(mediaFiles[0].url).indexOf('audio') > -1) {
|
915
|
+
result.isVideo = false;
|
916
|
+
}
|
917
|
+
|
918
|
+
|
919
|
+
// STEP 2: Test for playback method
|
920
|
+
|
921
|
+
// special case for Android which sadly doesn't implement the canPlayType function (always returns '')
|
922
|
+
if (mejs.MediaFeatures.isBustedAndroid) {
|
923
|
+
htmlMediaElement.canPlayType = function(type) {
|
924
|
+
return (type.match(/video\/(mp4|m4v)/gi) !== null) ? 'maybe' : '';
|
925
|
+
};
|
926
|
+
}
|
927
|
+
|
928
|
+
|
929
|
+
// test for native playback first
|
930
|
+
if (supportsMediaTag && (options.mode === 'auto' || options.mode === 'auto_plugin' || options.mode === 'native')) {
|
931
|
+
|
932
|
+
if (!isMediaTag) {
|
933
|
+
|
934
|
+
// create a real HTML5 Media Element
|
935
|
+
dummy = document.createElement( result.isVideo ? 'video' : 'audio');
|
936
|
+
htmlMediaElement.parentNode.insertBefore(dummy, htmlMediaElement);
|
937
|
+
htmlMediaElement.style.display = 'none';
|
938
|
+
|
939
|
+
// use this one from now on
|
940
|
+
result.htmlMediaElement = htmlMediaElement = dummy;
|
941
|
+
}
|
942
|
+
|
943
|
+
for (i=0; i<mediaFiles.length; i++) {
|
944
|
+
// normal check
|
945
|
+
if (htmlMediaElement.canPlayType(mediaFiles[i].type).replace(/no/, '') !== ''
|
946
|
+
// special case for Mac/Safari 5.0.3 which answers '' to canPlayType('audio/mp3') but 'maybe' to canPlayType('audio/mpeg')
|
947
|
+
|| htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/mp3/,'mpeg')).replace(/no/, '') !== '') {
|
948
|
+
result.method = 'native';
|
949
|
+
result.url = mediaFiles[i].url;
|
950
|
+
break;
|
951
|
+
}
|
952
|
+
}
|
953
|
+
|
954
|
+
if (result.method === 'native') {
|
955
|
+
if (result.url !== null) {
|
956
|
+
htmlMediaElement.src = result.url;
|
957
|
+
}
|
958
|
+
|
959
|
+
// if `auto_plugin` mode, then cache the native result but try plugins.
|
960
|
+
if (options.mode !== 'auto_plugin') {
|
961
|
+
return result;
|
962
|
+
}
|
963
|
+
}
|
964
|
+
}
|
965
|
+
|
966
|
+
// if native playback didn't work, then test plugins
|
967
|
+
if (options.mode === 'auto' || options.mode === 'auto_plugin' || options.mode === 'shim') {
|
968
|
+
for (i=0; i<mediaFiles.length; i++) {
|
969
|
+
type = mediaFiles[i].type;
|
970
|
+
|
971
|
+
// test all plugins in order of preference [silverlight, flash]
|
972
|
+
for (j=0; j<options.plugins.length; j++) {
|
973
|
+
|
974
|
+
pluginName = options.plugins[j];
|
975
|
+
|
976
|
+
// test version of plugin (for future features)
|
977
|
+
pluginVersions = mejs.plugins[pluginName];
|
978
|
+
|
979
|
+
for (k=0; k<pluginVersions.length; k++) {
|
980
|
+
pluginInfo = pluginVersions[k];
|
981
|
+
|
982
|
+
// test if user has the correct plugin version
|
983
|
+
|
984
|
+
// for youtube/vimeo
|
985
|
+
if (pluginInfo.version == null ||
|
986
|
+
|
987
|
+
mejs.PluginDetector.hasPluginVersion(pluginName, pluginInfo.version)) {
|
988
|
+
|
989
|
+
// test for plugin playback types
|
990
|
+
for (l=0; l<pluginInfo.types.length; l++) {
|
991
|
+
// find plugin that can play the type
|
992
|
+
if (type == pluginInfo.types[l]) {
|
993
|
+
result.method = pluginName;
|
994
|
+
result.url = mediaFiles[i].url;
|
995
|
+
return result;
|
996
|
+
}
|
997
|
+
}
|
998
|
+
}
|
999
|
+
}
|
1000
|
+
}
|
1001
|
+
}
|
1002
|
+
}
|
1003
|
+
|
1004
|
+
// at this point, being in 'auto_plugin' mode implies that we tried plugins but failed.
|
1005
|
+
// if we have native support then return that.
|
1006
|
+
if (options.mode === 'auto_plugin' && result.method === 'native') {
|
1007
|
+
return result;
|
1008
|
+
}
|
1009
|
+
|
1010
|
+
// what if there's nothing to play? just grab the first available
|
1011
|
+
if (result.method === '' && mediaFiles.length > 0) {
|
1012
|
+
result.url = mediaFiles[0].url;
|
1013
|
+
}
|
1014
|
+
|
1015
|
+
return result;
|
1016
|
+
},
|
1017
|
+
|
1018
|
+
formatType: function(url, type) {
|
1019
|
+
var ext;
|
1020
|
+
|
1021
|
+
// if no type is supplied, fake it with the extension
|
1022
|
+
if (url && !type) {
|
1023
|
+
return this.getTypeFromFile(url);
|
1024
|
+
} else {
|
1025
|
+
// only return the mime part of the type in case the attribute contains the codec
|
1026
|
+
// see http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#the-source-element
|
1027
|
+
// `video/mp4; codecs="avc1.42E01E, mp4a.40.2"` becomes `video/mp4`
|
1028
|
+
|
1029
|
+
if (type && ~type.indexOf(';')) {
|
1030
|
+
return type.substr(0, type.indexOf(';'));
|
1031
|
+
} else {
|
1032
|
+
return type;
|
1033
|
+
}
|
1034
|
+
}
|
1035
|
+
},
|
1036
|
+
|
1037
|
+
getTypeFromFile: function(url) {
|
1038
|
+
var ext = url.substring(url.lastIndexOf('.') + 1);
|
1039
|
+
return (/(mp4|m4v|ogg|ogv|webm|webmv|flv|wmv|mpeg|mov)/gi.test(ext) ? 'video' : 'audio') + '/' + this.getTypeFromExtension(ext);
|
1040
|
+
},
|
1041
|
+
|
1042
|
+
getTypeFromExtension: function(ext) {
|
1043
|
+
var ext_types = {
|
1044
|
+
'mp4': ['mp4','m4v'],
|
1045
|
+
'ogg': ['ogg','ogv','oga'],
|
1046
|
+
'webm': ['webm','webmv','webma']
|
1047
|
+
};
|
1048
|
+
var r = ext;
|
1049
|
+
$.each(ext_types, function(key, value) {
|
1050
|
+
if (value.indexOf(ext) > -1) {
|
1051
|
+
r = key;
|
1052
|
+
return;
|
1053
|
+
}
|
1054
|
+
});
|
1055
|
+
return r;
|
1056
|
+
},
|
1057
|
+
|
1058
|
+
createErrorMessage: function(playback, options, poster) {
|
1059
|
+
var
|
1060
|
+
htmlMediaElement = playback.htmlMediaElement,
|
1061
|
+
errorContainer = document.createElement('div');
|
1062
|
+
|
1063
|
+
errorContainer.className = 'me-cannotplay';
|
1064
|
+
|
1065
|
+
try {
|
1066
|
+
errorContainer.style.width = htmlMediaElement.width + 'px';
|
1067
|
+
errorContainer.style.height = htmlMediaElement.height + 'px';
|
1068
|
+
} catch (e) {}
|
1069
|
+
|
1070
|
+
errorContainer.innerHTML = (poster !== '') ?
|
1071
|
+
'<a href="' + playback.url + '"><img src="' + poster + '" width="100%" height="100%" /></a>' :
|
1072
|
+
'<a href="' + playback.url + '"><span>Download File</span></a>';
|
1073
|
+
|
1074
|
+
htmlMediaElement.parentNode.insertBefore(errorContainer, htmlMediaElement);
|
1075
|
+
htmlMediaElement.style.display = 'none';
|
1076
|
+
|
1077
|
+
options.error(htmlMediaElement);
|
1078
|
+
},
|
1079
|
+
|
1080
|
+
createPlugin:function(playback, options, poster, autoplay, preload, controls) {
|
1081
|
+
var
|
1082
|
+
htmlMediaElement = playback.htmlMediaElement,
|
1083
|
+
width = 1,
|
1084
|
+
height = 1,
|
1085
|
+
pluginid = 'me_' + playback.method + '_' + (mejs.meIndex++),
|
1086
|
+
pluginMediaElement = new mejs.PluginMediaElement(pluginid, playback.method, playback.url),
|
1087
|
+
container = document.createElement('div'),
|
1088
|
+
specialIEContainer,
|
1089
|
+
node,
|
1090
|
+
initVars;
|
1091
|
+
|
1092
|
+
// copy tagName from html media element
|
1093
|
+
pluginMediaElement.tagName = htmlMediaElement.tagName
|
1094
|
+
|
1095
|
+
// copy attributes from html media element to plugin media element
|
1096
|
+
for (var i = 0; i < htmlMediaElement.attributes.length; i++) {
|
1097
|
+
var attribute = htmlMediaElement.attributes[i];
|
1098
|
+
if (attribute.specified == true) {
|
1099
|
+
pluginMediaElement.setAttribute(attribute.name, attribute.value);
|
1100
|
+
}
|
1101
|
+
}
|
1102
|
+
|
1103
|
+
// check for placement inside a <p> tag (sometimes WYSIWYG editors do this)
|
1104
|
+
node = htmlMediaElement.parentNode;
|
1105
|
+
while (node !== null && node.tagName.toLowerCase() != 'body') {
|
1106
|
+
if (node.parentNode.tagName.toLowerCase() == 'p') {
|
1107
|
+
node.parentNode.parentNode.insertBefore(node, node.parentNode);
|
1108
|
+
break;
|
1109
|
+
}
|
1110
|
+
node = node.parentNode;
|
1111
|
+
}
|
1112
|
+
|
1113
|
+
if (playback.isVideo) {
|
1114
|
+
width = (options.videoWidth > 0) ? options.videoWidth : (htmlMediaElement.getAttribute('width') !== null) ? htmlMediaElement.getAttribute('width') : options.defaultVideoWidth;
|
1115
|
+
height = (options.videoHeight > 0) ? options.videoHeight : (htmlMediaElement.getAttribute('height') !== null) ? htmlMediaElement.getAttribute('height') : options.defaultVideoHeight;
|
1116
|
+
|
1117
|
+
// in case of '%' make sure it's encoded
|
1118
|
+
width = mejs.Utility.encodeUrl(width);
|
1119
|
+
height = mejs.Utility.encodeUrl(height);
|
1120
|
+
|
1121
|
+
} else {
|
1122
|
+
if (options.enablePluginDebug) {
|
1123
|
+
width = 320;
|
1124
|
+
height = 240;
|
1125
|
+
}
|
1126
|
+
}
|
1127
|
+
|
1128
|
+
// register plugin
|
1129
|
+
pluginMediaElement.success = options.success;
|
1130
|
+
mejs.MediaPluginBridge.registerPluginElement(pluginid, pluginMediaElement, htmlMediaElement);
|
1131
|
+
|
1132
|
+
// add container (must be added to DOM before inserting HTML for IE)
|
1133
|
+
container.className = 'me-plugin';
|
1134
|
+
container.id = pluginid + '_container';
|
1135
|
+
|
1136
|
+
if (playback.isVideo) {
|
1137
|
+
htmlMediaElement.parentNode.insertBefore(container, htmlMediaElement);
|
1138
|
+
} else {
|
1139
|
+
document.body.insertBefore(container, document.body.childNodes[0]);
|
1140
|
+
}
|
1141
|
+
|
1142
|
+
// flash/silverlight vars
|
1143
|
+
initVars = [
|
1144
|
+
'id=' + pluginid,
|
1145
|
+
'isvideo=' + ((playback.isVideo) ? "true" : "false"),
|
1146
|
+
'autoplay=' + ((autoplay) ? "true" : "false"),
|
1147
|
+
'preload=' + preload,
|
1148
|
+
'width=' + width,
|
1149
|
+
'startvolume=' + options.startVolume,
|
1150
|
+
'timerrate=' + options.timerRate,
|
1151
|
+
'height=' + height];
|
1152
|
+
|
1153
|
+
if (playback.url !== null) {
|
1154
|
+
if (playback.method == 'flash') {
|
1155
|
+
initVars.push('file=' + mejs.Utility.encodeUrl(playback.url));
|
1156
|
+
} else {
|
1157
|
+
initVars.push('file=' + playback.url);
|
1158
|
+
}
|
1159
|
+
}
|
1160
|
+
if (options.enablePluginDebug) {
|
1161
|
+
initVars.push('debug=true');
|
1162
|
+
}
|
1163
|
+
if (options.enablePluginSmoothing) {
|
1164
|
+
initVars.push('smoothing=true');
|
1165
|
+
}
|
1166
|
+
if (controls) {
|
1167
|
+
initVars.push('controls=true'); // shows controls in the plugin if desired
|
1168
|
+
}
|
1169
|
+
if (options.pluginVars) {
|
1170
|
+
initVars = initVars.concat(options.pluginVars);
|
1171
|
+
}
|
1172
|
+
|
1173
|
+
switch (playback.method) {
|
1174
|
+
case 'silverlight':
|
1175
|
+
container.innerHTML =
|
1176
|
+
'<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="' + pluginid + '" name="' + pluginid + '" width="' + width + '" height="' + height + '">' +
|
1177
|
+
'<param name="initParams" value="' + initVars.join(',') + '" />' +
|
1178
|
+
'<param name="windowless" value="true" />' +
|
1179
|
+
'<param name="background" value="black" />' +
|
1180
|
+
'<param name="minRuntimeVersion" value="3.0.0.0" />' +
|
1181
|
+
'<param name="autoUpgrade" value="true" />' +
|
1182
|
+
'<param name="source" value="' + options.pluginPath + options.silverlightName + '" />' +
|
1183
|
+
'</object>';
|
1184
|
+
break;
|
1185
|
+
|
1186
|
+
case 'flash':
|
1187
|
+
|
1188
|
+
if (mejs.MediaFeatures.isIE) {
|
1189
|
+
specialIEContainer = document.createElement('div');
|
1190
|
+
container.appendChild(specialIEContainer);
|
1191
|
+
specialIEContainer.outerHTML =
|
1192
|
+
'<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
|
1193
|
+
'id="' + pluginid + '" width="' + width + '" height="' + height + '">' +
|
1194
|
+
'<param name="movie" value="' + options.pluginPath + options.flashName + '?x=' + (new Date()) + '" />' +
|
1195
|
+
'<param name="flashvars" value="' + initVars.join('&') + '" />' +
|
1196
|
+
'<param name="quality" value="high" />' +
|
1197
|
+
'<param name="bgcolor" value="#000000" />' +
|
1198
|
+
'<param name="wmode" value="transparent" />' +
|
1199
|
+
'<param name="allowScriptAccess" value="always" />' +
|
1200
|
+
'<param name="allowFullScreen" value="true" />' +
|
1201
|
+
'</object>';
|
1202
|
+
|
1203
|
+
} else {
|
1204
|
+
|
1205
|
+
container.innerHTML =
|
1206
|
+
'<embed id="' + pluginid + '" name="' + pluginid + '" ' +
|
1207
|
+
'play="true" ' +
|
1208
|
+
'loop="false" ' +
|
1209
|
+
'quality="high" ' +
|
1210
|
+
'bgcolor="#000000" ' +
|
1211
|
+
'wmode="transparent" ' +
|
1212
|
+
'allowScriptAccess="always" ' +
|
1213
|
+
'allowFullScreen="true" ' +
|
1214
|
+
'type="application/x-shockwave-flash" pluginspage="//www.macromedia.com/go/getflashplayer" ' +
|
1215
|
+
'src="' + options.pluginPath + options.flashName + '" ' +
|
1216
|
+
'flashvars="' + initVars.join('&') + '" ' +
|
1217
|
+
'width="' + width + '" ' +
|
1218
|
+
'height="' + height + '"></embed>';
|
1219
|
+
}
|
1220
|
+
break;
|
1221
|
+
|
1222
|
+
case 'youtube':
|
1223
|
+
|
1224
|
+
|
1225
|
+
var
|
1226
|
+
videoId = playback.url.substr(playback.url.lastIndexOf('=')+1);
|
1227
|
+
youtubeSettings = {
|
1228
|
+
container: container,
|
1229
|
+
containerId: container.id,
|
1230
|
+
pluginMediaElement: pluginMediaElement,
|
1231
|
+
pluginId: pluginid,
|
1232
|
+
videoId: videoId,
|
1233
|
+
height: height,
|
1234
|
+
width: width
|
1235
|
+
};
|
1236
|
+
|
1237
|
+
if (mejs.PluginDetector.hasPluginVersion('flash', [10,0,0]) ) {
|
1238
|
+
mejs.YouTubeApi.createFlash(youtubeSettings);
|
1239
|
+
} else {
|
1240
|
+
mejs.YouTubeApi.enqueueIframe(youtubeSettings);
|
1241
|
+
}
|
1242
|
+
|
1243
|
+
break;
|
1244
|
+
|
1245
|
+
// DEMO Code. Does NOT work.
|
1246
|
+
case 'vimeo':
|
1247
|
+
//console.log('vimeoid');
|
1248
|
+
|
1249
|
+
pluginMediaElement.vimeoid = playback.url.substr(playback.url.lastIndexOf('/')+1);
|
1250
|
+
|
1251
|
+
container.innerHTML =
|
1252
|
+
'<object width="' + width + '" height="' + height + '">' +
|
1253
|
+
'<param name="allowfullscreen" value="true" />' +
|
1254
|
+
'<param name="allowscriptaccess" value="always" />' +
|
1255
|
+
'<param name="flashvars" value="api=1" />' +
|
1256
|
+
'<param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=' + pluginMediaElement.vimeoid + '&server=vimeo.com&show_title=0&show_byline=0&show_portrait=0&color=00adef&fullscreen=1&autoplay=0&loop=0" />' +
|
1257
|
+
'<embed src="//vimeo.com/moogaloop.swf?api=1&clip_id=' + pluginMediaElement.vimeoid + '&server=vimeo.com&show_title=0&show_byline=0&show_portrait=0&color=00adef&fullscreen=1&autoplay=0&loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="' + width + '" height="' + height + '"></embed>' +
|
1258
|
+
'</object>';
|
1259
|
+
|
1260
|
+
break;
|
1261
|
+
}
|
1262
|
+
// hide original element
|
1263
|
+
htmlMediaElement.style.display = 'none';
|
1264
|
+
|
1265
|
+
// FYI: options.success will be fired by the MediaPluginBridge
|
1266
|
+
|
1267
|
+
return pluginMediaElement;
|
1268
|
+
},
|
1269
|
+
|
1270
|
+
updateNative: function(playback, options, autoplay, preload) {
|
1271
|
+
|
1272
|
+
var htmlMediaElement = playback.htmlMediaElement,
|
1273
|
+
m;
|
1274
|
+
|
1275
|
+
|
1276
|
+
// add methods to video object to bring it into parity with Flash Object
|
1277
|
+
for (m in mejs.HtmlMediaElement) {
|
1278
|
+
htmlMediaElement[m] = mejs.HtmlMediaElement[m];
|
1279
|
+
}
|
1280
|
+
|
1281
|
+
/*
|
1282
|
+
Chrome now supports preload="none"
|
1283
|
+
if (mejs.MediaFeatures.isChrome) {
|
1284
|
+
|
1285
|
+
// special case to enforce preload attribute (Chrome doesn't respect this)
|
1286
|
+
if (preload === 'none' && !autoplay) {
|
1287
|
+
|
1288
|
+
// forces the browser to stop loading (note: fails in IE9)
|
1289
|
+
htmlMediaElement.src = '';
|
1290
|
+
htmlMediaElement.load();
|
1291
|
+
htmlMediaElement.canceledPreload = true;
|
1292
|
+
|
1293
|
+
htmlMediaElement.addEventListener('play',function() {
|
1294
|
+
if (htmlMediaElement.canceledPreload) {
|
1295
|
+
htmlMediaElement.src = playback.url;
|
1296
|
+
htmlMediaElement.load();
|
1297
|
+
htmlMediaElement.play();
|
1298
|
+
htmlMediaElement.canceledPreload = false;
|
1299
|
+
}
|
1300
|
+
}, false);
|
1301
|
+
// for some reason Chrome forgets how to autoplay sometimes.
|
1302
|
+
} else if (autoplay) {
|
1303
|
+
htmlMediaElement.load();
|
1304
|
+
htmlMediaElement.play();
|
1305
|
+
}
|
1306
|
+
}
|
1307
|
+
*/
|
1308
|
+
|
1309
|
+
// fire success code
|
1310
|
+
options.success(htmlMediaElement, htmlMediaElement);
|
1311
|
+
|
1312
|
+
return htmlMediaElement;
|
1313
|
+
}
|
1314
|
+
};
|
1315
|
+
|
1316
|
+
/*
|
1317
|
+
- test on IE (object vs. embed)
|
1318
|
+
- determine when to use iframe (Firefox, Safari, Mobile) vs. Flash (Chrome, IE)
|
1319
|
+
- fullscreen?
|
1320
|
+
*/
|
1321
|
+
|
1322
|
+
// YouTube Flash and Iframe API
|
1323
|
+
mejs.YouTubeApi = {
|
1324
|
+
isIframeStarted: false,
|
1325
|
+
isIframeLoaded: false,
|
1326
|
+
loadIframeApi: function() {
|
1327
|
+
if (!this.isIframeStarted) {
|
1328
|
+
var tag = document.createElement('script');
|
1329
|
+
tag.src = "http://www.youtube.com/player_api";
|
1330
|
+
var firstScriptTag = document.getElementsByTagName('script')[0];
|
1331
|
+
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
|
1332
|
+
this.isIframeStarted = true;
|
1333
|
+
}
|
1334
|
+
},
|
1335
|
+
iframeQueue: [],
|
1336
|
+
enqueueIframe: function(yt) {
|
1337
|
+
|
1338
|
+
if (this.isLoaded) {
|
1339
|
+
this.createIframe(yt);
|
1340
|
+
} else {
|
1341
|
+
this.loadIframeApi();
|
1342
|
+
this.iframeQueue.push(yt);
|
1343
|
+
}
|
1344
|
+
},
|
1345
|
+
createIframe: function(settings) {
|
1346
|
+
|
1347
|
+
var
|
1348
|
+
pluginMediaElement = settings.pluginMediaElement,
|
1349
|
+
player = new YT.Player(settings.containerId, {
|
1350
|
+
height: settings.height,
|
1351
|
+
width: settings.width,
|
1352
|
+
videoId: settings.videoId,
|
1353
|
+
playerVars: {controls:0},
|
1354
|
+
events: {
|
1355
|
+
'onReady': function() {
|
1356
|
+
|
1357
|
+
// hook up iframe object to MEjs
|
1358
|
+
settings.pluginMediaElement.pluginApi = player;
|
1359
|
+
|
1360
|
+
// init mejs
|
1361
|
+
mejs.MediaPluginBridge.initPlugin(settings.pluginId);
|
1362
|
+
|
1363
|
+
// create timer
|
1364
|
+
setInterval(function() {
|
1365
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
|
1366
|
+
}, 250);
|
1367
|
+
},
|
1368
|
+
'onStateChange': function(e) {
|
1369
|
+
|
1370
|
+
mejs.YouTubeApi.handleStateChange(e.data, player, pluginMediaElement);
|
1371
|
+
|
1372
|
+
}
|
1373
|
+
}
|
1374
|
+
});
|
1375
|
+
},
|
1376
|
+
|
1377
|
+
createEvent: function (player, pluginMediaElement, eventName) {
|
1378
|
+
var obj = {
|
1379
|
+
type: eventName,
|
1380
|
+
target: pluginMediaElement
|
1381
|
+
};
|
1382
|
+
|
1383
|
+
if (player && player.getDuration) {
|
1384
|
+
|
1385
|
+
// time
|
1386
|
+
pluginMediaElement.currentTime = obj.currentTime = player.getCurrentTime();
|
1387
|
+
pluginMediaElement.duration = obj.duration = player.getDuration();
|
1388
|
+
|
1389
|
+
// state
|
1390
|
+
obj.paused = pluginMediaElement.paused;
|
1391
|
+
obj.ended = pluginMediaElement.ended;
|
1392
|
+
|
1393
|
+
// sound
|
1394
|
+
obj.muted = player.isMuted();
|
1395
|
+
obj.volume = player.getVolume() / 100;
|
1396
|
+
|
1397
|
+
// progress
|
1398
|
+
obj.bytesTotal = player.getVideoBytesTotal();
|
1399
|
+
obj.bufferedBytes = player.getVideoBytesLoaded();
|
1400
|
+
|
1401
|
+
// fake the W3C buffered TimeRange
|
1402
|
+
var bufferedTime = obj.bufferedBytes / obj.bytesTotal * obj.duration;
|
1403
|
+
|
1404
|
+
obj.target.buffered = obj.buffered = {
|
1405
|
+
start: function(index) {
|
1406
|
+
return 0;
|
1407
|
+
},
|
1408
|
+
end: function (index) {
|
1409
|
+
return bufferedTime;
|
1410
|
+
},
|
1411
|
+
length: 1
|
1412
|
+
};
|
1413
|
+
|
1414
|
+
}
|
1415
|
+
|
1416
|
+
// send event up the chain
|
1417
|
+
pluginMediaElement.dispatchEvent(obj.type, obj);
|
1418
|
+
},
|
1419
|
+
|
1420
|
+
iFrameReady: function() {
|
1421
|
+
|
1422
|
+
this.isLoaded = true;
|
1423
|
+
this.isIframeLoaded = true;
|
1424
|
+
|
1425
|
+
while (this.iframeQueue.length > 0) {
|
1426
|
+
var settings = this.iframeQueue.pop();
|
1427
|
+
this.createIframe(settings);
|
1428
|
+
}
|
1429
|
+
},
|
1430
|
+
|
1431
|
+
// FLASH!
|
1432
|
+
flashPlayers: {},
|
1433
|
+
createFlash: function(settings) {
|
1434
|
+
|
1435
|
+
this.flashPlayers[settings.pluginId] = settings;
|
1436
|
+
|
1437
|
+
/*
|
1438
|
+
settings.container.innerHTML =
|
1439
|
+
'<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="//www.youtube.com/apiplayer?enablejsapi=1&playerapiid=' + settings.pluginId + '&version=3&autoplay=0&controls=0&modestbranding=1&loop=0" ' +
|
1440
|
+
'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; ">' +
|
1441
|
+
'<param name="allowScriptAccess" value="always">' +
|
1442
|
+
'<param name="wmode" value="transparent">' +
|
1443
|
+
'</object>';
|
1444
|
+
*/
|
1445
|
+
|
1446
|
+
var specialIEContainer,
|
1447
|
+
youtubeUrl = 'http://www.youtube.com/apiplayer?enablejsapi=1&playerapiid=' + settings.pluginId + '&version=3&autoplay=0&controls=0&modestbranding=1&loop=0';
|
1448
|
+
|
1449
|
+
if (mejs.MediaFeatures.isIE) {
|
1450
|
+
|
1451
|
+
specialIEContainer = document.createElement('div');
|
1452
|
+
settings.container.appendChild(specialIEContainer);
|
1453
|
+
specialIEContainer.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
|
1454
|
+
'id="' + settings.pluginId + '" width="' + settings.width + '" height="' + settings.height + '">' +
|
1455
|
+
'<param name="movie" value="' + youtubeUrl + '" />' +
|
1456
|
+
'<param name="wmode" value="transparent" />' +
|
1457
|
+
'<param name="allowScriptAccess" value="always" />' +
|
1458
|
+
'<param name="allowFullScreen" value="true" />' +
|
1459
|
+
'</object>';
|
1460
|
+
} else {
|
1461
|
+
settings.container.innerHTML =
|
1462
|
+
'<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="' + youtubeUrl + '" ' +
|
1463
|
+
'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; ">' +
|
1464
|
+
'<param name="allowScriptAccess" value="always">' +
|
1465
|
+
'<param name="wmode" value="transparent">' +
|
1466
|
+
'</object>';
|
1467
|
+
}
|
1468
|
+
|
1469
|
+
},
|
1470
|
+
|
1471
|
+
flashReady: function(id) {
|
1472
|
+
var
|
1473
|
+
settings = this.flashPlayers[id],
|
1474
|
+
player = document.getElementById(id),
|
1475
|
+
pluginMediaElement = settings.pluginMediaElement;
|
1476
|
+
|
1477
|
+
// hook up and return to MediaELementPlayer.success
|
1478
|
+
pluginMediaElement.pluginApi =
|
1479
|
+
pluginMediaElement.pluginElement = player;
|
1480
|
+
mejs.MediaPluginBridge.initPlugin(id);
|
1481
|
+
|
1482
|
+
// load the youtube video
|
1483
|
+
player.cueVideoById(settings.videoId);
|
1484
|
+
|
1485
|
+
var callbackName = settings.containerId + '_callback'
|
1486
|
+
|
1487
|
+
window[callbackName] = function(e) {
|
1488
|
+
mejs.YouTubeApi.handleStateChange(e, player, pluginMediaElement);
|
1489
|
+
}
|
1490
|
+
|
1491
|
+
player.addEventListener('onStateChange', callbackName);
|
1492
|
+
|
1493
|
+
setInterval(function() {
|
1494
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
|
1495
|
+
}, 250);
|
1496
|
+
},
|
1497
|
+
|
1498
|
+
handleStateChange: function(youTubeState, player, pluginMediaElement) {
|
1499
|
+
switch (youTubeState) {
|
1500
|
+
case -1: // not started
|
1501
|
+
pluginMediaElement.paused = true;
|
1502
|
+
pluginMediaElement.ended = true;
|
1503
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'loadedmetadata');
|
1504
|
+
//createYouTubeEvent(player, pluginMediaElement, 'loadeddata');
|
1505
|
+
break;
|
1506
|
+
case 0:
|
1507
|
+
pluginMediaElement.paused = false;
|
1508
|
+
pluginMediaElement.ended = true;
|
1509
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'ended');
|
1510
|
+
break;
|
1511
|
+
case 1:
|
1512
|
+
pluginMediaElement.paused = false;
|
1513
|
+
pluginMediaElement.ended = false;
|
1514
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'play');
|
1515
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'playing');
|
1516
|
+
break;
|
1517
|
+
case 2:
|
1518
|
+
pluginMediaElement.paused = true;
|
1519
|
+
pluginMediaElement.ended = false;
|
1520
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'pause');
|
1521
|
+
break;
|
1522
|
+
case 3: // buffering
|
1523
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'progress');
|
1524
|
+
break;
|
1525
|
+
case 5:
|
1526
|
+
// cued?
|
1527
|
+
break;
|
1528
|
+
|
1529
|
+
}
|
1530
|
+
|
1531
|
+
}
|
1532
|
+
}
|
1533
|
+
// IFRAME
|
1534
|
+
function onYouTubePlayerAPIReady() {
|
1535
|
+
mejs.YouTubeApi.iFrameReady();
|
1536
|
+
}
|
1537
|
+
// FLASH
|
1538
|
+
function onYouTubePlayerReady(id) {
|
1539
|
+
mejs.YouTubeApi.flashReady(id);
|
1540
|
+
}
|
1541
|
+
|
1542
|
+
window.mejs = mejs;
|
1543
|
+
window.MediaElement = mejs.MediaElement;
|
1544
|
+
|