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
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
|
+
|