rsence-pre 3.0.0.10 → 3.0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/client/conf/client_pkg.yaml +17 -1
- data/client/ext/Rakefile +42 -12
- data/client/js/comm/transporter/transporter.js +1 -0
- data/client/js/controls/numerictextcontrol/numerictextcontrol.coffee +10 -11
- data/client/js/controls/searchfield/themes/default/searchfield.css +56 -91
- data/client/js/controls/searchfield/themes/default/searchfield.html +10 -10
- data/client/js/controls/textcontrol/textcontrol.coffee +71 -65
- data/client/js/core/elem/elem.coffee +5 -0
- data/client/js/datetime/datepicker/datepicker.coffee +1 -0
- data/client/js/datetime/momentjs/momentjs.js +12 -4
- data/client/js/foundation/control/eventresponder/eventresponder.js +14 -0
- data/client/js/foundation/json_renderer/json_renderer.js +12 -12
- data/client/js/foundation/view/view.js +13 -4
- data/client/js/lists/radiobuttonlist/radiobuttonlist.js +9 -8
- data/client/js/media/mediaelement/mediaelement.js +1890 -0
- data/client/js/media/mediaelement_defaults/mediaelement_defaults.coffee +1 -0
- data/client/js/media/mediaelement_resources/mediaelement_resources.js +1 -0
- data/client/js/media/mediaelement_resources/themes/mejs/flashmediaelement.swf +0 -0
- data/client/js/media/mediaelement_resources/themes/mejs/mediaelement_resources.css +0 -0
- data/client/js/media/mediaelement_resources/themes/mejs/mediaelement_resources.html +0 -0
- data/client/js/media/mediaelement_resources/themes/mejs/silverlightmediaelement.xap +0 -0
- data/client/js/menus/combobox/combobox.coffee +6 -1
- data/client/js/menus/menuitem/themes/default/menuitem.css +5 -8
- data/client/js/menus/minimenu/minimenu.js +2 -2
- data/client/js/menus/minimenu/themes/default/minimenu.css +6 -22
- data/client/js/menus/minimenuitem/themes/default/minimenuitem.css +5 -8
- data/client/js/menus/popupmenu/themes/default/popupmenu.css +6 -27
- data/plugins/client_pkg/lib/client_pkg_build.rb +5 -1
- metadata +8 -1
@@ -0,0 +1,1890 @@
|
|
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-2013, John Dyer (http://j.hn)
|
11
|
+
* License: MIT
|
12
|
+
*
|
13
|
+
*/
|
14
|
+
// Namespace
|
15
|
+
var mejs = mejs || {};
|
16
|
+
|
17
|
+
// version number
|
18
|
+
mejs.version = '2.12.0';
|
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/rtmp','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', 'audio/youtube', 'audio/x-youtube']}
|
34
|
+
],
|
35
|
+
vimeo: [
|
36
|
+
{version: null, types: ['video/vimeo', 'video/x-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
|
+
codePath = '',
|
60
|
+
testname = '',
|
61
|
+
slashPos,
|
62
|
+
filenamePos,
|
63
|
+
scriptUrl,
|
64
|
+
scriptPath,
|
65
|
+
scriptFilename,
|
66
|
+
scripts = document.getElementsByTagName('script'),
|
67
|
+
il = scripts.length,
|
68
|
+
jl = scriptNames.length;
|
69
|
+
|
70
|
+
// go through all <script> tags
|
71
|
+
for (; i < il; i++) {
|
72
|
+
scriptUrl = scripts[i].src;
|
73
|
+
slashPos = scriptUrl.lastIndexOf('/');
|
74
|
+
if (slashPos > -1) {
|
75
|
+
scriptFilename = scriptUrl.substring(slashPos + 1);
|
76
|
+
scriptPath = scriptUrl.substring(0, slashPos + 1);
|
77
|
+
} else {
|
78
|
+
scriptFilename = scriptUrl;
|
79
|
+
scriptPath = '';
|
80
|
+
}
|
81
|
+
|
82
|
+
// see if any <script> tags have a file name that matches the
|
83
|
+
for (j = 0; j < jl; j++) {
|
84
|
+
testname = scriptNames[j];
|
85
|
+
filenamePos = scriptFilename.indexOf(testname);
|
86
|
+
if (filenamePos > -1) {
|
87
|
+
codePath = scriptPath;
|
88
|
+
break;
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
// if we found a path, then break and return it
|
93
|
+
if (codePath !== '') {
|
94
|
+
break;
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
// send the best path back
|
99
|
+
return codePath;
|
100
|
+
},
|
101
|
+
secondsToTimeCode: function(time, forceHours, showFrameCount, fps) {
|
102
|
+
//add framecount
|
103
|
+
if (typeof showFrameCount == 'undefined') {
|
104
|
+
showFrameCount=false;
|
105
|
+
} else if(typeof fps == 'undefined') {
|
106
|
+
fps = 25;
|
107
|
+
}
|
108
|
+
|
109
|
+
var hours = Math.floor(time / 3600) % 24,
|
110
|
+
minutes = Math.floor(time / 60) % 60,
|
111
|
+
seconds = Math.floor(time % 60),
|
112
|
+
frames = Math.floor(((time % 1)*fps).toFixed(3)),
|
113
|
+
result =
|
114
|
+
( (forceHours || hours > 0) ? (hours < 10 ? '0' + hours : hours) + ':' : '')
|
115
|
+
+ (minutes < 10 ? '0' + minutes : minutes) + ':'
|
116
|
+
+ (seconds < 10 ? '0' + seconds : seconds)
|
117
|
+
+ ((showFrameCount) ? ':' + (frames < 10 ? '0' + frames : frames) : '');
|
118
|
+
|
119
|
+
return result;
|
120
|
+
},
|
121
|
+
|
122
|
+
timeCodeToSeconds: function(hh_mm_ss_ff, forceHours, showFrameCount, fps){
|
123
|
+
if (typeof showFrameCount == 'undefined') {
|
124
|
+
showFrameCount=false;
|
125
|
+
} else if(typeof fps == 'undefined') {
|
126
|
+
fps = 25;
|
127
|
+
}
|
128
|
+
|
129
|
+
var tc_array = hh_mm_ss_ff.split(":"),
|
130
|
+
tc_hh = parseInt(tc_array[0], 10),
|
131
|
+
tc_mm = parseInt(tc_array[1], 10),
|
132
|
+
tc_ss = parseInt(tc_array[2], 10),
|
133
|
+
tc_ff = 0,
|
134
|
+
tc_in_seconds = 0;
|
135
|
+
|
136
|
+
if (showFrameCount) {
|
137
|
+
tc_ff = parseInt(tc_array[3])/fps;
|
138
|
+
}
|
139
|
+
|
140
|
+
tc_in_seconds = ( tc_hh * 3600 ) + ( tc_mm * 60 ) + tc_ss + tc_ff;
|
141
|
+
|
142
|
+
return tc_in_seconds;
|
143
|
+
},
|
144
|
+
|
145
|
+
|
146
|
+
convertSMPTEtoSeconds: function (SMPTE) {
|
147
|
+
if (typeof SMPTE != 'string')
|
148
|
+
return false;
|
149
|
+
|
150
|
+
SMPTE = SMPTE.replace(',', '.');
|
151
|
+
|
152
|
+
var secs = 0,
|
153
|
+
decimalLen = (SMPTE.indexOf('.') != -1) ? SMPTE.split('.')[1].length : 0,
|
154
|
+
multiplier = 1;
|
155
|
+
|
156
|
+
SMPTE = SMPTE.split(':').reverse();
|
157
|
+
|
158
|
+
for (var i = 0; i < SMPTE.length; i++) {
|
159
|
+
multiplier = 1;
|
160
|
+
if (i > 0) {
|
161
|
+
multiplier = Math.pow(60, i);
|
162
|
+
}
|
163
|
+
secs += Number(SMPTE[i]) * multiplier;
|
164
|
+
}
|
165
|
+
return Number(secs.toFixed(decimalLen));
|
166
|
+
},
|
167
|
+
|
168
|
+
/* borrowed from SWFObject: http://code.google.com/p/swfobject/source/browse/trunk/swfobject/src/swfobject.js#474 */
|
169
|
+
removeSwf: function(id) {
|
170
|
+
var obj = document.getElementById(id);
|
171
|
+
if (obj && /object|embed/i.test(obj.nodeName)) {
|
172
|
+
if (mejs.MediaFeatures.isIE) {
|
173
|
+
obj.style.display = "none";
|
174
|
+
(function(){
|
175
|
+
if (obj.readyState == 4) {
|
176
|
+
mejs.Utility.removeObjectInIE(id);
|
177
|
+
} else {
|
178
|
+
setTimeout(arguments.callee, 10);
|
179
|
+
}
|
180
|
+
})();
|
181
|
+
} else {
|
182
|
+
obj.parentNode.removeChild(obj);
|
183
|
+
}
|
184
|
+
}
|
185
|
+
},
|
186
|
+
removeObjectInIE: function(id) {
|
187
|
+
var obj = document.getElementById(id);
|
188
|
+
if (obj) {
|
189
|
+
for (var i in obj) {
|
190
|
+
if (typeof obj[i] == "function") {
|
191
|
+
obj[i] = null;
|
192
|
+
}
|
193
|
+
}
|
194
|
+
obj.parentNode.removeChild(obj);
|
195
|
+
}
|
196
|
+
}
|
197
|
+
};
|
198
|
+
|
199
|
+
|
200
|
+
// Core detector, plugins are added below
|
201
|
+
mejs.PluginDetector = {
|
202
|
+
|
203
|
+
// main public function to test a plug version number PluginDetector.hasPluginVersion('flash',[9,0,125]);
|
204
|
+
hasPluginVersion: function(plugin, v) {
|
205
|
+
var pv = this.plugins[plugin];
|
206
|
+
v[1] = v[1] || 0;
|
207
|
+
v[2] = v[2] || 0;
|
208
|
+
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;
|
209
|
+
},
|
210
|
+
|
211
|
+
// cached values
|
212
|
+
nav: window.navigator,
|
213
|
+
ua: window.navigator.userAgent.toLowerCase(),
|
214
|
+
|
215
|
+
// stored version numbers
|
216
|
+
plugins: [],
|
217
|
+
|
218
|
+
// runs detectPlugin() and stores the version number
|
219
|
+
addPlugin: function(p, pluginName, mimeType, activeX, axDetect) {
|
220
|
+
this.plugins[p] = this.detectPlugin(pluginName, mimeType, activeX, axDetect);
|
221
|
+
},
|
222
|
+
|
223
|
+
// get the version number from the mimetype (all but IE) or ActiveX (IE)
|
224
|
+
detectPlugin: function(pluginName, mimeType, activeX, axDetect) {
|
225
|
+
|
226
|
+
var version = [0,0,0],
|
227
|
+
description,
|
228
|
+
i,
|
229
|
+
ax;
|
230
|
+
|
231
|
+
// Firefox, Webkit, Opera
|
232
|
+
if (typeof(this.nav.plugins) != 'undefined' && typeof this.nav.plugins[pluginName] == 'object') {
|
233
|
+
description = this.nav.plugins[pluginName].description;
|
234
|
+
if (description && !(typeof this.nav.mimeTypes != 'undefined' && this.nav.mimeTypes[mimeType] && !this.nav.mimeTypes[mimeType].enabledPlugin)) {
|
235
|
+
version = description.replace(pluginName, '').replace(/^\s+/,'').replace(/\sr/gi,'.').split('.');
|
236
|
+
for (i=0; i<version.length; i++) {
|
237
|
+
version[i] = parseInt(version[i].match(/\d+/), 10);
|
238
|
+
}
|
239
|
+
}
|
240
|
+
// Internet Explorer / ActiveX
|
241
|
+
} else if (typeof(window.ActiveXObject) != 'undefined') {
|
242
|
+
try {
|
243
|
+
ax = new ActiveXObject(activeX);
|
244
|
+
if (ax) {
|
245
|
+
version = axDetect(ax);
|
246
|
+
}
|
247
|
+
}
|
248
|
+
catch (e) { }
|
249
|
+
}
|
250
|
+
return version;
|
251
|
+
}
|
252
|
+
};
|
253
|
+
|
254
|
+
// Add Flash detection
|
255
|
+
mejs.PluginDetector.addPlugin('flash','Shockwave Flash','application/x-shockwave-flash','ShockwaveFlash.ShockwaveFlash', function(ax) {
|
256
|
+
// adapted from SWFObject
|
257
|
+
var version = [],
|
258
|
+
d = ax.GetVariable("$version");
|
259
|
+
if (d) {
|
260
|
+
d = d.split(" ")[1].split(",");
|
261
|
+
version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
|
262
|
+
}
|
263
|
+
return version;
|
264
|
+
});
|
265
|
+
|
266
|
+
// Add Silverlight detection
|
267
|
+
mejs.PluginDetector.addPlugin('silverlight','Silverlight Plug-In','application/x-silverlight-2','AgControl.AgControl', function (ax) {
|
268
|
+
// Silverlight cannot report its version number to IE
|
269
|
+
// but it does have a isVersionSupported function, so we have to loop through it to get a version number.
|
270
|
+
// adapted from http://www.silverlightversion.com/
|
271
|
+
var v = [0,0,0,0],
|
272
|
+
loopMatch = function(ax, v, i, n) {
|
273
|
+
while(ax.isVersionSupported(v[0]+ "."+ v[1] + "." + v[2] + "." + v[3])){
|
274
|
+
v[i]+=n;
|
275
|
+
}
|
276
|
+
v[i] -= n;
|
277
|
+
};
|
278
|
+
loopMatch(ax, v, 0, 1);
|
279
|
+
loopMatch(ax, v, 1, 1);
|
280
|
+
loopMatch(ax, v, 2, 10000); // the third place in the version number is usually 5 digits (4.0.xxxxx)
|
281
|
+
loopMatch(ax, v, 2, 1000);
|
282
|
+
loopMatch(ax, v, 2, 100);
|
283
|
+
loopMatch(ax, v, 2, 10);
|
284
|
+
loopMatch(ax, v, 2, 1);
|
285
|
+
loopMatch(ax, v, 3, 1);
|
286
|
+
|
287
|
+
return v;
|
288
|
+
});
|
289
|
+
// add adobe acrobat
|
290
|
+
/*
|
291
|
+
PluginDetector.addPlugin('acrobat','Adobe Acrobat','application/pdf','AcroPDF.PDF', function (ax) {
|
292
|
+
var version = [],
|
293
|
+
d = ax.GetVersions().split(',')[0].split('=')[1].split('.');
|
294
|
+
|
295
|
+
if (d) {
|
296
|
+
version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
|
297
|
+
}
|
298
|
+
return version;
|
299
|
+
});
|
300
|
+
*/
|
301
|
+
// necessary detection (fixes for <IE9)
|
302
|
+
mejs.MediaFeatures = {
|
303
|
+
init: function() {
|
304
|
+
var
|
305
|
+
t = this,
|
306
|
+
d = document,
|
307
|
+
nav = mejs.PluginDetector.nav,
|
308
|
+
ua = mejs.PluginDetector.ua.toLowerCase(),
|
309
|
+
i,
|
310
|
+
v,
|
311
|
+
html5Elements = ['source','track','audio','video'];
|
312
|
+
|
313
|
+
// detect browsers (only the ones that have some kind of quirk we need to work around)
|
314
|
+
t.isiPad = (ua.match(/ipad/i) !== null);
|
315
|
+
t.isiPhone = (ua.match(/iphone/i) !== null);
|
316
|
+
t.isiOS = t.isiPhone || t.isiPad;
|
317
|
+
t.isAndroid = (ua.match(/android/i) !== null);
|
318
|
+
t.isBustedAndroid = (ua.match(/android 2\.[12]/) !== null);
|
319
|
+
t.isBustedNativeHTTPS = (location.protocol === 'https:' && (ua.match(/android [12]\./) !== null || ua.match(/macintosh.* version.* safari/) !== null));
|
320
|
+
t.isIE = (nav.appName.toLowerCase().indexOf("microsoft") != -1);
|
321
|
+
t.isChrome = (ua.match(/chrome/gi) !== null);
|
322
|
+
t.isFirefox = (ua.match(/firefox/gi) !== null);
|
323
|
+
t.isWebkit = (ua.match(/webkit/gi) !== null);
|
324
|
+
t.isGecko = (ua.match(/gecko/gi) !== null) && !t.isWebkit;
|
325
|
+
t.isOpera = (ua.match(/opera/gi) !== null);
|
326
|
+
t.hasTouch = ('ontouchstart' in window);
|
327
|
+
|
328
|
+
// borrowed from Modernizr
|
329
|
+
t.svg = !! document.createElementNS &&
|
330
|
+
!! document.createElementNS('http://www.w3.org/2000/svg','svg').createSVGRect;
|
331
|
+
|
332
|
+
// create HTML5 media elements for IE before 9, get a <video> element for fullscreen detection
|
333
|
+
for (i=0; i<html5Elements.length; i++) {
|
334
|
+
v = document.createElement(html5Elements[i]);
|
335
|
+
}
|
336
|
+
|
337
|
+
t.supportsMediaTag = (typeof v.canPlayType !== 'undefined' || t.isBustedAndroid);
|
338
|
+
|
339
|
+
// Fix for IE9 on Windows 7N / Windows 7KN (Media Player not installer)
|
340
|
+
try{
|
341
|
+
v.canPlayType("video/mp4");
|
342
|
+
}catch(e){
|
343
|
+
t.supportsMediaTag = false;
|
344
|
+
}
|
345
|
+
|
346
|
+
// detect native JavaScript fullscreen (Safari/Firefox only, Chrome still fails)
|
347
|
+
|
348
|
+
// iOS
|
349
|
+
t.hasSemiNativeFullScreen = (typeof v.webkitEnterFullscreen !== 'undefined');
|
350
|
+
|
351
|
+
// Webkit/firefox
|
352
|
+
t.hasWebkitNativeFullScreen = (typeof v.webkitRequestFullScreen !== 'undefined');
|
353
|
+
t.hasMozNativeFullScreen = (typeof v.mozRequestFullScreen !== 'undefined');
|
354
|
+
|
355
|
+
t.hasTrueNativeFullScreen = (t.hasWebkitNativeFullScreen || t.hasMozNativeFullScreen);
|
356
|
+
t.nativeFullScreenEnabled = t.hasTrueNativeFullScreen;
|
357
|
+
if (t.hasMozNativeFullScreen) {
|
358
|
+
t.nativeFullScreenEnabled = v.mozFullScreenEnabled;
|
359
|
+
}
|
360
|
+
|
361
|
+
|
362
|
+
if (this.isChrome) {
|
363
|
+
t.hasSemiNativeFullScreen = false;
|
364
|
+
}
|
365
|
+
|
366
|
+
if (t.hasTrueNativeFullScreen) {
|
367
|
+
t.fullScreenEventName = (t.hasWebkitNativeFullScreen) ? 'webkitfullscreenchange' : 'mozfullscreenchange';
|
368
|
+
|
369
|
+
|
370
|
+
t.isFullScreen = function() {
|
371
|
+
if (v.mozRequestFullScreen) {
|
372
|
+
return d.mozFullScreen;
|
373
|
+
} else if (v.webkitRequestFullScreen) {
|
374
|
+
return d.webkitIsFullScreen;
|
375
|
+
}
|
376
|
+
}
|
377
|
+
|
378
|
+
t.requestFullScreen = function(el) {
|
379
|
+
|
380
|
+
if (t.hasWebkitNativeFullScreen) {
|
381
|
+
el.webkitRequestFullScreen();
|
382
|
+
} else if (t.hasMozNativeFullScreen) {
|
383
|
+
el.mozRequestFullScreen();
|
384
|
+
}
|
385
|
+
}
|
386
|
+
|
387
|
+
t.cancelFullScreen = function() {
|
388
|
+
if (t.hasWebkitNativeFullScreen) {
|
389
|
+
document.webkitCancelFullScreen();
|
390
|
+
} else if (t.hasMozNativeFullScreen) {
|
391
|
+
document.mozCancelFullScreen();
|
392
|
+
}
|
393
|
+
}
|
394
|
+
|
395
|
+
}
|
396
|
+
|
397
|
+
|
398
|
+
// OS X 10.5 can't do this even if it says it can :(
|
399
|
+
if (t.hasSemiNativeFullScreen && ua.match(/mac os x 10_5/i)) {
|
400
|
+
t.hasNativeFullScreen = false;
|
401
|
+
t.hasSemiNativeFullScreen = false;
|
402
|
+
}
|
403
|
+
|
404
|
+
}
|
405
|
+
};
|
406
|
+
mejs.MediaFeatures.init();
|
407
|
+
|
408
|
+
/*
|
409
|
+
extension methods to <video> or <audio> object to bring it into parity with PluginMediaElement (see below)
|
410
|
+
*/
|
411
|
+
mejs.HtmlMediaElement = {
|
412
|
+
pluginType: 'native',
|
413
|
+
isFullScreen: false,
|
414
|
+
|
415
|
+
setCurrentTime: function (time) {
|
416
|
+
this.currentTime = time;
|
417
|
+
},
|
418
|
+
|
419
|
+
setMuted: function (muted) {
|
420
|
+
this.muted = muted;
|
421
|
+
},
|
422
|
+
|
423
|
+
setVolume: function (volume) {
|
424
|
+
this.volume = volume;
|
425
|
+
},
|
426
|
+
|
427
|
+
// for parity with the plugin versions
|
428
|
+
stop: function () {
|
429
|
+
this.pause();
|
430
|
+
},
|
431
|
+
|
432
|
+
// This can be a url string
|
433
|
+
// or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
|
434
|
+
setSrc: function (url) {
|
435
|
+
|
436
|
+
// Fix for IE9 which can't set .src when there are <source> elements. Awesome, right?
|
437
|
+
var
|
438
|
+
existingSources = this.getElementsByTagName('source');
|
439
|
+
while (existingSources.length > 0){
|
440
|
+
this.removeChild(existingSources[0]);
|
441
|
+
}
|
442
|
+
|
443
|
+
if (typeof url == 'string') {
|
444
|
+
this.src = url;
|
445
|
+
} else {
|
446
|
+
var i, media;
|
447
|
+
|
448
|
+
for (i=0; i<url.length; i++) {
|
449
|
+
media = url[i];
|
450
|
+
if (this.canPlayType(media.type)) {
|
451
|
+
this.src = media.src;
|
452
|
+
break;
|
453
|
+
}
|
454
|
+
}
|
455
|
+
}
|
456
|
+
},
|
457
|
+
|
458
|
+
setVideoSize: function (width, height) {
|
459
|
+
this.width = width;
|
460
|
+
this.height = height;
|
461
|
+
}
|
462
|
+
};
|
463
|
+
|
464
|
+
/*
|
465
|
+
Mimics the <video/audio> element by calling Flash's External Interface or Silverlights [ScriptableMember]
|
466
|
+
*/
|
467
|
+
mejs.PluginMediaElement = function (pluginid, pluginType, mediaUrl) {
|
468
|
+
this.id = pluginid;
|
469
|
+
this.pluginType = pluginType;
|
470
|
+
this.src = mediaUrl;
|
471
|
+
this.events = {};
|
472
|
+
this.attributes = {};
|
473
|
+
};
|
474
|
+
|
475
|
+
// JavaScript values and ExternalInterface methods that match HTML5 video properties methods
|
476
|
+
// http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/fl/video/FLVPlayback.html
|
477
|
+
// http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
|
478
|
+
mejs.PluginMediaElement.prototype = {
|
479
|
+
|
480
|
+
// special
|
481
|
+
pluginElement: null,
|
482
|
+
pluginType: '',
|
483
|
+
isFullScreen: false,
|
484
|
+
|
485
|
+
// not implemented :(
|
486
|
+
playbackRate: -1,
|
487
|
+
defaultPlaybackRate: -1,
|
488
|
+
seekable: [],
|
489
|
+
played: [],
|
490
|
+
|
491
|
+
// HTML5 read-only properties
|
492
|
+
paused: true,
|
493
|
+
ended: false,
|
494
|
+
seeking: false,
|
495
|
+
duration: 0,
|
496
|
+
error: null,
|
497
|
+
tagName: '',
|
498
|
+
|
499
|
+
// HTML5 get/set properties, but only set (updated by event handlers)
|
500
|
+
muted: false,
|
501
|
+
volume: 1,
|
502
|
+
currentTime: 0,
|
503
|
+
|
504
|
+
// HTML5 methods
|
505
|
+
play: function () {
|
506
|
+
if (this.pluginApi != null) {
|
507
|
+
if (this.pluginType == 'youtube') {
|
508
|
+
this.pluginApi.playVideo();
|
509
|
+
} else {
|
510
|
+
this.pluginApi.playMedia();
|
511
|
+
}
|
512
|
+
this.paused = false;
|
513
|
+
}
|
514
|
+
},
|
515
|
+
load: function () {
|
516
|
+
if (this.pluginApi != null) {
|
517
|
+
if (this.pluginType == 'youtube') {
|
518
|
+
} else {
|
519
|
+
this.pluginApi.loadMedia();
|
520
|
+
}
|
521
|
+
|
522
|
+
this.paused = false;
|
523
|
+
}
|
524
|
+
},
|
525
|
+
pause: function () {
|
526
|
+
if (this.pluginApi != null) {
|
527
|
+
if (this.pluginType == 'youtube') {
|
528
|
+
this.pluginApi.pauseVideo();
|
529
|
+
} else {
|
530
|
+
this.pluginApi.pauseMedia();
|
531
|
+
}
|
532
|
+
|
533
|
+
|
534
|
+
this.paused = true;
|
535
|
+
}
|
536
|
+
},
|
537
|
+
stop: function () {
|
538
|
+
if (this.pluginApi != null) {
|
539
|
+
if (this.pluginType == 'youtube') {
|
540
|
+
this.pluginApi.stopVideo();
|
541
|
+
} else {
|
542
|
+
this.pluginApi.stopMedia();
|
543
|
+
}
|
544
|
+
this.paused = true;
|
545
|
+
}
|
546
|
+
},
|
547
|
+
canPlayType: function(type) {
|
548
|
+
var i,
|
549
|
+
j,
|
550
|
+
pluginInfo,
|
551
|
+
pluginVersions = mejs.plugins[this.pluginType];
|
552
|
+
|
553
|
+
for (i=0; i<pluginVersions.length; i++) {
|
554
|
+
pluginInfo = pluginVersions[i];
|
555
|
+
|
556
|
+
// test if user has the correct plugin version
|
557
|
+
if (mejs.PluginDetector.hasPluginVersion(this.pluginType, pluginInfo.version)) {
|
558
|
+
|
559
|
+
// test for plugin playback types
|
560
|
+
for (j=0; j<pluginInfo.types.length; j++) {
|
561
|
+
// find plugin that can play the type
|
562
|
+
if (type == pluginInfo.types[j]) {
|
563
|
+
return 'probably';
|
564
|
+
}
|
565
|
+
}
|
566
|
+
}
|
567
|
+
}
|
568
|
+
|
569
|
+
return '';
|
570
|
+
},
|
571
|
+
|
572
|
+
positionFullscreenButton: function(x,y,visibleAndAbove) {
|
573
|
+
if (this.pluginApi != null && this.pluginApi.positionFullscreenButton) {
|
574
|
+
this.pluginApi.positionFullscreenButton(Math.floor(x),Math.floor(y),visibleAndAbove);
|
575
|
+
}
|
576
|
+
},
|
577
|
+
|
578
|
+
hideFullscreenButton: function() {
|
579
|
+
if (this.pluginApi != null && this.pluginApi.hideFullscreenButton) {
|
580
|
+
this.pluginApi.hideFullscreenButton();
|
581
|
+
}
|
582
|
+
},
|
583
|
+
|
584
|
+
|
585
|
+
// custom methods since not all JavaScript implementations support get/set
|
586
|
+
|
587
|
+
// This can be a url string
|
588
|
+
// or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
|
589
|
+
setSrc: function (url) {
|
590
|
+
if (typeof url == 'string') {
|
591
|
+
this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(url));
|
592
|
+
this.src = mejs.Utility.absolutizeUrl(url);
|
593
|
+
} else {
|
594
|
+
var i, media;
|
595
|
+
|
596
|
+
for (i=0; i<url.length; i++) {
|
597
|
+
media = url[i];
|
598
|
+
if (this.canPlayType(media.type)) {
|
599
|
+
this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(media.src));
|
600
|
+
this.src = mejs.Utility.absolutizeUrl(url);
|
601
|
+
break;
|
602
|
+
}
|
603
|
+
}
|
604
|
+
}
|
605
|
+
|
606
|
+
},
|
607
|
+
setCurrentTime: function (time) {
|
608
|
+
if (this.pluginApi != null) {
|
609
|
+
if (this.pluginType == 'youtube') {
|
610
|
+
this.pluginApi.seekTo(time);
|
611
|
+
} else {
|
612
|
+
this.pluginApi.setCurrentTime(time);
|
613
|
+
}
|
614
|
+
|
615
|
+
|
616
|
+
|
617
|
+
this.currentTime = time;
|
618
|
+
}
|
619
|
+
},
|
620
|
+
setVolume: function (volume) {
|
621
|
+
if (this.pluginApi != null) {
|
622
|
+
// same on YouTube and MEjs
|
623
|
+
if (this.pluginType == 'youtube') {
|
624
|
+
this.pluginApi.setVolume(volume * 100);
|
625
|
+
} else {
|
626
|
+
this.pluginApi.setVolume(volume);
|
627
|
+
}
|
628
|
+
this.volume = volume;
|
629
|
+
}
|
630
|
+
},
|
631
|
+
setMuted: function (muted) {
|
632
|
+
if (this.pluginApi != null) {
|
633
|
+
if (this.pluginType == 'youtube') {
|
634
|
+
if (muted) {
|
635
|
+
this.pluginApi.mute();
|
636
|
+
} else {
|
637
|
+
this.pluginApi.unMute();
|
638
|
+
}
|
639
|
+
this.muted = muted;
|
640
|
+
this.dispatchEvent('volumechange');
|
641
|
+
} else {
|
642
|
+
this.pluginApi.setMuted(muted);
|
643
|
+
}
|
644
|
+
this.muted = muted;
|
645
|
+
}
|
646
|
+
},
|
647
|
+
|
648
|
+
// additional non-HTML5 methods
|
649
|
+
setVideoSize: function (width, height) {
|
650
|
+
|
651
|
+
//if (this.pluginType == 'flash' || this.pluginType == 'silverlight') {
|
652
|
+
if ( this.pluginElement.style) {
|
653
|
+
this.pluginElement.style.width = width + 'px';
|
654
|
+
this.pluginElement.style.height = height + 'px';
|
655
|
+
}
|
656
|
+
if (this.pluginApi != null && this.pluginApi.setVideoSize) {
|
657
|
+
this.pluginApi.setVideoSize(width, height);
|
658
|
+
}
|
659
|
+
//}
|
660
|
+
},
|
661
|
+
|
662
|
+
setFullscreen: function (fullscreen) {
|
663
|
+
if (this.pluginApi != null && this.pluginApi.setFullscreen) {
|
664
|
+
this.pluginApi.setFullscreen(fullscreen);
|
665
|
+
}
|
666
|
+
},
|
667
|
+
|
668
|
+
enterFullScreen: function() {
|
669
|
+
if (this.pluginApi != null && this.pluginApi.setFullscreen) {
|
670
|
+
this.setFullscreen(true);
|
671
|
+
}
|
672
|
+
|
673
|
+
},
|
674
|
+
|
675
|
+
exitFullScreen: function() {
|
676
|
+
if (this.pluginApi != null && this.pluginApi.setFullscreen) {
|
677
|
+
this.setFullscreen(false);
|
678
|
+
}
|
679
|
+
},
|
680
|
+
|
681
|
+
// start: fake events
|
682
|
+
addEventListener: function (eventName, callback, bubble) {
|
683
|
+
this.events[eventName] = this.events[eventName] || [];
|
684
|
+
this.events[eventName].push(callback);
|
685
|
+
},
|
686
|
+
removeEventListener: function (eventName, callback) {
|
687
|
+
if (!eventName) { this.events = {}; return true; }
|
688
|
+
var callbacks = this.events[eventName];
|
689
|
+
if (!callbacks) return true;
|
690
|
+
if (!callback) { this.events[eventName] = []; return true; }
|
691
|
+
for (i = 0; i < callbacks.length; i++) {
|
692
|
+
if (callbacks[i] === callback) {
|
693
|
+
this.events[eventName].splice(i, 1);
|
694
|
+
return true;
|
695
|
+
}
|
696
|
+
}
|
697
|
+
return false;
|
698
|
+
},
|
699
|
+
dispatchEvent: function (eventName) {
|
700
|
+
var i,
|
701
|
+
args,
|
702
|
+
callbacks = this.events[eventName];
|
703
|
+
|
704
|
+
if (callbacks) {
|
705
|
+
args = Array.prototype.slice.call(arguments, 1);
|
706
|
+
for (i = 0; i < callbacks.length; i++) {
|
707
|
+
callbacks[i].apply(null, args);
|
708
|
+
}
|
709
|
+
}
|
710
|
+
},
|
711
|
+
// end: fake events
|
712
|
+
|
713
|
+
// fake DOM attribute methods
|
714
|
+
hasAttribute: function(name){
|
715
|
+
return (name in this.attributes);
|
716
|
+
},
|
717
|
+
removeAttribute: function(name){
|
718
|
+
delete this.attributes[name];
|
719
|
+
},
|
720
|
+
getAttribute: function(name){
|
721
|
+
if (this.hasAttribute(name)) {
|
722
|
+
return this.attributes[name];
|
723
|
+
}
|
724
|
+
return '';
|
725
|
+
},
|
726
|
+
setAttribute: function(name, value){
|
727
|
+
this.attributes[name] = value;
|
728
|
+
},
|
729
|
+
|
730
|
+
remove: function() {
|
731
|
+
mejs.Utility.removeSwf(this.pluginElement.id);
|
732
|
+
mejs.MediaPluginBridge.unregisterPluginElement(this.pluginElement.id);
|
733
|
+
}
|
734
|
+
};
|
735
|
+
|
736
|
+
// Handles calls from Flash/Silverlight and reports them as native <video/audio> events and properties
|
737
|
+
mejs.MediaPluginBridge = {
|
738
|
+
|
739
|
+
pluginMediaElements:{},
|
740
|
+
htmlMediaElements:{},
|
741
|
+
|
742
|
+
registerPluginElement: function (id, pluginMediaElement, htmlMediaElement) {
|
743
|
+
this.pluginMediaElements[id] = pluginMediaElement;
|
744
|
+
this.htmlMediaElements[id] = htmlMediaElement;
|
745
|
+
},
|
746
|
+
|
747
|
+
unregisterPluginElement: function (id) {
|
748
|
+
delete this.pluginMediaElements[id];
|
749
|
+
delete this.htmlMediaElements[id];
|
750
|
+
},
|
751
|
+
|
752
|
+
// when Flash/Silverlight is ready, it calls out to this method
|
753
|
+
initPlugin: function (id) {
|
754
|
+
|
755
|
+
var pluginMediaElement = this.pluginMediaElements[id],
|
756
|
+
htmlMediaElement = this.htmlMediaElements[id];
|
757
|
+
|
758
|
+
if (pluginMediaElement) {
|
759
|
+
// find the javascript bridge
|
760
|
+
switch (pluginMediaElement.pluginType) {
|
761
|
+
case "flash":
|
762
|
+
pluginMediaElement.pluginElement = pluginMediaElement.pluginApi = document.getElementById(id);
|
763
|
+
break;
|
764
|
+
case "silverlight":
|
765
|
+
pluginMediaElement.pluginElement = document.getElementById(pluginMediaElement.id);
|
766
|
+
pluginMediaElement.pluginApi = pluginMediaElement.pluginElement.Content.MediaElementJS;
|
767
|
+
break;
|
768
|
+
}
|
769
|
+
|
770
|
+
if (pluginMediaElement.pluginApi != null && pluginMediaElement.success) {
|
771
|
+
pluginMediaElement.success(pluginMediaElement, htmlMediaElement);
|
772
|
+
}
|
773
|
+
}
|
774
|
+
},
|
775
|
+
|
776
|
+
// receives events from Flash/Silverlight and sends them out as HTML5 media events
|
777
|
+
// http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
|
778
|
+
fireEvent: function (id, eventName, values) {
|
779
|
+
|
780
|
+
var
|
781
|
+
e,
|
782
|
+
i,
|
783
|
+
bufferedTime,
|
784
|
+
pluginMediaElement = this.pluginMediaElements[id];
|
785
|
+
|
786
|
+
// fake event object to mimic real HTML media event.
|
787
|
+
e = {
|
788
|
+
type: eventName,
|
789
|
+
target: pluginMediaElement
|
790
|
+
};
|
791
|
+
|
792
|
+
// attach all values to element and event object
|
793
|
+
for (i in values) {
|
794
|
+
pluginMediaElement[i] = values[i];
|
795
|
+
e[i] = values[i];
|
796
|
+
}
|
797
|
+
|
798
|
+
// fake the newer W3C buffered TimeRange (loaded and total have been removed)
|
799
|
+
bufferedTime = values.bufferedTime || 0;
|
800
|
+
|
801
|
+
e.target.buffered = e.buffered = {
|
802
|
+
start: function(index) {
|
803
|
+
return 0;
|
804
|
+
},
|
805
|
+
end: function (index) {
|
806
|
+
return bufferedTime;
|
807
|
+
},
|
808
|
+
length: 1
|
809
|
+
};
|
810
|
+
|
811
|
+
pluginMediaElement.dispatchEvent(e.type, e);
|
812
|
+
}
|
813
|
+
};
|
814
|
+
|
815
|
+
/*
|
816
|
+
Default options
|
817
|
+
*/
|
818
|
+
mejs.MediaElementDefaults = {
|
819
|
+
// allows testing on HTML5, flash, silverlight
|
820
|
+
// auto: attempts to detect what the browser can do
|
821
|
+
// auto_plugin: prefer plugins and then attempt native HTML5
|
822
|
+
// native: forces HTML5 playback
|
823
|
+
// shim: disallows HTML5, will attempt either Flash or Silverlight
|
824
|
+
// none: forces fallback view
|
825
|
+
mode: 'auto',
|
826
|
+
// remove or reorder to change plugin priority and availability
|
827
|
+
plugins: ['flash','silverlight','youtube','vimeo'],
|
828
|
+
// shows debug errors on screen
|
829
|
+
enablePluginDebug: false,
|
830
|
+
// overrides the type specified, useful for dynamic instantiation
|
831
|
+
type: '',
|
832
|
+
// path to Flash and Silverlight plugins
|
833
|
+
pluginPath: mejs.Utility.getScriptPath(['mediaelement.js','mediaelement.min.js','mediaelement-and-player.js','mediaelement-and-player.min.js']),
|
834
|
+
// name of flash file
|
835
|
+
flashName: 'flashmediaelement.swf',
|
836
|
+
// streamer for RTMP streaming
|
837
|
+
flashStreamer: '',
|
838
|
+
// turns on the smoothing filter in Flash
|
839
|
+
enablePluginSmoothing: false,
|
840
|
+
// enabled pseudo-streaming (seek) on .mp4 files
|
841
|
+
enablePseudoStreaming: false,
|
842
|
+
// start query parameter sent to server for pseudo-streaming
|
843
|
+
pseudoStreamingStartQueryParam: 'start',
|
844
|
+
// name of silverlight file
|
845
|
+
silverlightName: 'silverlightmediaelement.xap',
|
846
|
+
// default if the <video width> is not specified
|
847
|
+
defaultVideoWidth: 480,
|
848
|
+
// default if the <video height> is not specified
|
849
|
+
defaultVideoHeight: 270,
|
850
|
+
// overrides <video width>
|
851
|
+
pluginWidth: -1,
|
852
|
+
// overrides <video height>
|
853
|
+
pluginHeight: -1,
|
854
|
+
// additional plugin variables in 'key=value' form
|
855
|
+
pluginVars: [],
|
856
|
+
// rate in milliseconds for Flash and Silverlight to fire the timeupdate event
|
857
|
+
// larger number is less accurate, but less strain on plugin->JavaScript bridge
|
858
|
+
timerRate: 250,
|
859
|
+
// initial volume for player
|
860
|
+
startVolume: 0.8,
|
861
|
+
success: function () { },
|
862
|
+
error: function () { }
|
863
|
+
};
|
864
|
+
|
865
|
+
/*
|
866
|
+
Determines if a browser supports the <video> or <audio> element
|
867
|
+
and returns either the native element or a Flash/Silverlight version that
|
868
|
+
mimics HTML5 MediaElement
|
869
|
+
*/
|
870
|
+
mejs.MediaElement = function (el, o) {
|
871
|
+
return mejs.HtmlMediaElementShim.create(el,o);
|
872
|
+
};
|
873
|
+
|
874
|
+
mejs.HtmlMediaElementShim = {
|
875
|
+
|
876
|
+
create: function(el, o) {
|
877
|
+
var
|
878
|
+
options = mejs.MediaElementDefaults,
|
879
|
+
htmlMediaElement = (typeof(el) == 'string') ? document.getElementById(el) : el,
|
880
|
+
tagName = htmlMediaElement.tagName.toLowerCase(),
|
881
|
+
isMediaTag = (tagName === 'audio' || tagName === 'video'),
|
882
|
+
src = (isMediaTag) ? htmlMediaElement.getAttribute('src') : htmlMediaElement.getAttribute('href'),
|
883
|
+
poster = htmlMediaElement.getAttribute('poster'),
|
884
|
+
autoplay = htmlMediaElement.getAttribute('autoplay'),
|
885
|
+
preload = htmlMediaElement.getAttribute('preload'),
|
886
|
+
controls = htmlMediaElement.getAttribute('controls'),
|
887
|
+
playback,
|
888
|
+
prop;
|
889
|
+
|
890
|
+
// extend options
|
891
|
+
for (prop in o) {
|
892
|
+
options[prop] = o[prop];
|
893
|
+
}
|
894
|
+
|
895
|
+
// clean up attributes
|
896
|
+
src = (typeof src == 'undefined' || src === null || src == '') ? null : src;
|
897
|
+
poster = (typeof poster == 'undefined' || poster === null) ? '' : poster;
|
898
|
+
preload = (typeof preload == 'undefined' || preload === null || preload === 'false') ? 'none' : preload;
|
899
|
+
autoplay = !(typeof autoplay == 'undefined' || autoplay === null || autoplay === 'false');
|
900
|
+
controls = !(typeof controls == 'undefined' || controls === null || controls === 'false');
|
901
|
+
|
902
|
+
// test for HTML5 and plugin capabilities
|
903
|
+
playback = this.determinePlayback(htmlMediaElement, options, mejs.MediaFeatures.supportsMediaTag, isMediaTag, src);
|
904
|
+
playback.url = (playback.url !== null) ? mejs.Utility.absolutizeUrl(playback.url) : '';
|
905
|
+
|
906
|
+
if (playback.method == 'native') {
|
907
|
+
// second fix for android
|
908
|
+
if (mejs.MediaFeatures.isBustedAndroid) {
|
909
|
+
htmlMediaElement.src = playback.url;
|
910
|
+
htmlMediaElement.addEventListener('click', function() {
|
911
|
+
htmlMediaElement.play();
|
912
|
+
}, false);
|
913
|
+
}
|
914
|
+
|
915
|
+
// add methods to native HTMLMediaElement
|
916
|
+
return this.updateNative(playback, options, autoplay, preload);
|
917
|
+
} else if (playback.method !== '') {
|
918
|
+
// create plugin to mimic HTMLMediaElement
|
919
|
+
|
920
|
+
return this.createPlugin( playback, options, poster, autoplay, preload, controls);
|
921
|
+
} else {
|
922
|
+
// boo, no HTML5, no Flash, no Silverlight.
|
923
|
+
this.createErrorMessage( playback, options, poster );
|
924
|
+
|
925
|
+
return this;
|
926
|
+
}
|
927
|
+
},
|
928
|
+
|
929
|
+
determinePlayback: function(htmlMediaElement, options, supportsMediaTag, isMediaTag, src) {
|
930
|
+
var
|
931
|
+
mediaFiles = [],
|
932
|
+
i,
|
933
|
+
j,
|
934
|
+
k,
|
935
|
+
l,
|
936
|
+
n,
|
937
|
+
type,
|
938
|
+
result = { method: '', url: '', htmlMediaElement: htmlMediaElement, isVideo: (htmlMediaElement.tagName.toLowerCase() != 'audio')},
|
939
|
+
pluginName,
|
940
|
+
pluginVersions,
|
941
|
+
pluginInfo,
|
942
|
+
dummy,
|
943
|
+
media;
|
944
|
+
|
945
|
+
// STEP 1: Get URL and type from <video src> or <source src>
|
946
|
+
|
947
|
+
// supplied type overrides <video type> and <source type>
|
948
|
+
if (typeof options.type != 'undefined' && options.type !== '') {
|
949
|
+
|
950
|
+
// accept either string or array of types
|
951
|
+
if (typeof options.type == 'string') {
|
952
|
+
mediaFiles.push({type:options.type, url:src});
|
953
|
+
} else {
|
954
|
+
|
955
|
+
for (i=0; i<options.type.length; i++) {
|
956
|
+
mediaFiles.push({type:options.type[i], url:src});
|
957
|
+
}
|
958
|
+
}
|
959
|
+
|
960
|
+
// test for src attribute first
|
961
|
+
} else if (src !== null) {
|
962
|
+
type = this.formatType(src, htmlMediaElement.getAttribute('type'));
|
963
|
+
mediaFiles.push({type:type, url:src});
|
964
|
+
|
965
|
+
// then test for <source> elements
|
966
|
+
} else {
|
967
|
+
// test <source> types to see if they are usable
|
968
|
+
for (i = 0; i < htmlMediaElement.childNodes.length; i++) {
|
969
|
+
n = htmlMediaElement.childNodes[i];
|
970
|
+
if (n.nodeType == 1 && n.tagName.toLowerCase() == 'source') {
|
971
|
+
src = n.getAttribute('src');
|
972
|
+
type = this.formatType(src, n.getAttribute('type'));
|
973
|
+
media = n.getAttribute('media');
|
974
|
+
|
975
|
+
if (!media || !window.matchMedia || (window.matchMedia && window.matchMedia(media).matches)) {
|
976
|
+
mediaFiles.push({type:type, url:src});
|
977
|
+
}
|
978
|
+
}
|
979
|
+
}
|
980
|
+
}
|
981
|
+
|
982
|
+
// in the case of dynamicly created players
|
983
|
+
// check for audio types
|
984
|
+
if (!isMediaTag && mediaFiles.length > 0 && mediaFiles[0].url !== null && this.getTypeFromFile(mediaFiles[0].url).indexOf('audio') > -1) {
|
985
|
+
result.isVideo = false;
|
986
|
+
}
|
987
|
+
|
988
|
+
|
989
|
+
// STEP 2: Test for playback method
|
990
|
+
|
991
|
+
// special case for Android which sadly doesn't implement the canPlayType function (always returns '')
|
992
|
+
if (mejs.MediaFeatures.isBustedAndroid) {
|
993
|
+
htmlMediaElement.canPlayType = function(type) {
|
994
|
+
return (type.match(/video\/(mp4|m4v)/gi) !== null) ? 'maybe' : '';
|
995
|
+
};
|
996
|
+
}
|
997
|
+
|
998
|
+
|
999
|
+
// test for native playback first
|
1000
|
+
if (supportsMediaTag && (options.mode === 'auto' || options.mode === 'auto_plugin' || options.mode === 'native') && !(mejs.MediaFeatures.isBustedNativeHTTPS)) {
|
1001
|
+
|
1002
|
+
if (!isMediaTag) {
|
1003
|
+
|
1004
|
+
// create a real HTML5 Media Element
|
1005
|
+
dummy = document.createElement( result.isVideo ? 'video' : 'audio');
|
1006
|
+
htmlMediaElement.parentNode.insertBefore(dummy, htmlMediaElement);
|
1007
|
+
htmlMediaElement.style.display = 'none';
|
1008
|
+
|
1009
|
+
// use this one from now on
|
1010
|
+
result.htmlMediaElement = htmlMediaElement = dummy;
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
for (i=0; i<mediaFiles.length; i++) {
|
1014
|
+
// normal check
|
1015
|
+
if (htmlMediaElement.canPlayType(mediaFiles[i].type).replace(/no/, '') !== ''
|
1016
|
+
// special case for Mac/Safari 5.0.3 which answers '' to canPlayType('audio/mp3') but 'maybe' to canPlayType('audio/mpeg')
|
1017
|
+
|| htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/mp3/,'mpeg')).replace(/no/, '') !== '') {
|
1018
|
+
result.method = 'native';
|
1019
|
+
result.url = mediaFiles[i].url;
|
1020
|
+
break;
|
1021
|
+
}
|
1022
|
+
}
|
1023
|
+
|
1024
|
+
if (result.method === 'native') {
|
1025
|
+
if (result.url !== null) {
|
1026
|
+
htmlMediaElement.src = result.url;
|
1027
|
+
}
|
1028
|
+
|
1029
|
+
// if `auto_plugin` mode, then cache the native result but try plugins.
|
1030
|
+
if (options.mode !== 'auto_plugin') {
|
1031
|
+
return result;
|
1032
|
+
}
|
1033
|
+
}
|
1034
|
+
}
|
1035
|
+
|
1036
|
+
// if native playback didn't work, then test plugins
|
1037
|
+
if (options.mode === 'auto' || options.mode === 'auto_plugin' || options.mode === 'shim') {
|
1038
|
+
for (i=0; i<mediaFiles.length; i++) {
|
1039
|
+
type = mediaFiles[i].type;
|
1040
|
+
|
1041
|
+
// test all plugins in order of preference [silverlight, flash]
|
1042
|
+
for (j=0; j<options.plugins.length; j++) {
|
1043
|
+
|
1044
|
+
pluginName = options.plugins[j];
|
1045
|
+
|
1046
|
+
// test version of plugin (for future features)
|
1047
|
+
pluginVersions = mejs.plugins[pluginName];
|
1048
|
+
|
1049
|
+
for (k=0; k<pluginVersions.length; k++) {
|
1050
|
+
pluginInfo = pluginVersions[k];
|
1051
|
+
|
1052
|
+
// test if user has the correct plugin version
|
1053
|
+
|
1054
|
+
// for youtube/vimeo
|
1055
|
+
if (pluginInfo.version == null ||
|
1056
|
+
|
1057
|
+
mejs.PluginDetector.hasPluginVersion(pluginName, pluginInfo.version)) {
|
1058
|
+
|
1059
|
+
// test for plugin playback types
|
1060
|
+
for (l=0; l<pluginInfo.types.length; l++) {
|
1061
|
+
// find plugin that can play the type
|
1062
|
+
if (type == pluginInfo.types[l]) {
|
1063
|
+
result.method = pluginName;
|
1064
|
+
result.url = mediaFiles[i].url;
|
1065
|
+
return result;
|
1066
|
+
}
|
1067
|
+
}
|
1068
|
+
}
|
1069
|
+
}
|
1070
|
+
}
|
1071
|
+
}
|
1072
|
+
}
|
1073
|
+
|
1074
|
+
// at this point, being in 'auto_plugin' mode implies that we tried plugins but failed.
|
1075
|
+
// if we have native support then return that.
|
1076
|
+
if (options.mode === 'auto_plugin' && result.method === 'native') {
|
1077
|
+
return result;
|
1078
|
+
}
|
1079
|
+
|
1080
|
+
// what if there's nothing to play? just grab the first available
|
1081
|
+
if (result.method === '' && mediaFiles.length > 0) {
|
1082
|
+
result.url = mediaFiles[0].url;
|
1083
|
+
}
|
1084
|
+
|
1085
|
+
return result;
|
1086
|
+
},
|
1087
|
+
|
1088
|
+
formatType: function(url, type) {
|
1089
|
+
var ext;
|
1090
|
+
|
1091
|
+
// if no type is supplied, fake it with the extension
|
1092
|
+
if (url && !type) {
|
1093
|
+
return this.getTypeFromFile(url);
|
1094
|
+
} else {
|
1095
|
+
// only return the mime part of the type in case the attribute contains the codec
|
1096
|
+
// see http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#the-source-element
|
1097
|
+
// `video/mp4; codecs="avc1.42E01E, mp4a.40.2"` becomes `video/mp4`
|
1098
|
+
|
1099
|
+
if (type && ~type.indexOf(';')) {
|
1100
|
+
return type.substr(0, type.indexOf(';'));
|
1101
|
+
} else {
|
1102
|
+
return type;
|
1103
|
+
}
|
1104
|
+
}
|
1105
|
+
},
|
1106
|
+
|
1107
|
+
getTypeFromFile: function(url) {
|
1108
|
+
url = url.split('?')[0];
|
1109
|
+
var ext = url.substring(url.lastIndexOf('.') + 1).toLowerCase();
|
1110
|
+
return (/(mp4|m4v|ogg|ogv|webm|webmv|flv|wmv|mpeg|mov)/gi.test(ext) ? 'video' : 'audio') + '/' + this.getTypeFromExtension(ext);
|
1111
|
+
},
|
1112
|
+
|
1113
|
+
getTypeFromExtension: function(ext) {
|
1114
|
+
|
1115
|
+
switch (ext) {
|
1116
|
+
case 'mp4':
|
1117
|
+
case 'm4v':
|
1118
|
+
return 'mp4';
|
1119
|
+
case 'webm':
|
1120
|
+
case 'webma':
|
1121
|
+
case 'webmv':
|
1122
|
+
return 'webm';
|
1123
|
+
case 'ogg':
|
1124
|
+
case 'oga':
|
1125
|
+
case 'ogv':
|
1126
|
+
return 'ogg';
|
1127
|
+
default:
|
1128
|
+
return ext;
|
1129
|
+
}
|
1130
|
+
},
|
1131
|
+
|
1132
|
+
createErrorMessage: function(playback, options, poster) {
|
1133
|
+
var
|
1134
|
+
htmlMediaElement = playback.htmlMediaElement,
|
1135
|
+
errorContainer = document.createElement('div');
|
1136
|
+
|
1137
|
+
errorContainer.className = 'me-cannotplay';
|
1138
|
+
|
1139
|
+
try {
|
1140
|
+
errorContainer.style.width = htmlMediaElement.width + 'px';
|
1141
|
+
errorContainer.style.height = htmlMediaElement.height + 'px';
|
1142
|
+
} catch (e) {}
|
1143
|
+
|
1144
|
+
if (options.customError) {
|
1145
|
+
errorContainer.innerHTML = options.customError;
|
1146
|
+
} else {
|
1147
|
+
errorContainer.innerHTML = (poster !== '') ?
|
1148
|
+
'<a href="' + playback.url + '"><img src="' + poster + '" width="100%" height="100%" /></a>' :
|
1149
|
+
'<a href="' + playback.url + '"><span>' + mejs.i18n.t('Download File') + '</span></a>';
|
1150
|
+
}
|
1151
|
+
|
1152
|
+
htmlMediaElement.parentNode.insertBefore(errorContainer, htmlMediaElement);
|
1153
|
+
htmlMediaElement.style.display = 'none';
|
1154
|
+
|
1155
|
+
options.error(htmlMediaElement);
|
1156
|
+
},
|
1157
|
+
|
1158
|
+
createPlugin:function(playback, options, poster, autoplay, preload, controls) {
|
1159
|
+
var
|
1160
|
+
htmlMediaElement = playback.htmlMediaElement,
|
1161
|
+
width = 1,
|
1162
|
+
height = 1,
|
1163
|
+
pluginid = 'me_' + playback.method + '_' + (mejs.meIndex++),
|
1164
|
+
pluginMediaElement = new mejs.PluginMediaElement(pluginid, playback.method, playback.url),
|
1165
|
+
container = document.createElement('div'),
|
1166
|
+
specialIEContainer,
|
1167
|
+
node,
|
1168
|
+
initVars;
|
1169
|
+
|
1170
|
+
// copy tagName from html media element
|
1171
|
+
pluginMediaElement.tagName = htmlMediaElement.tagName
|
1172
|
+
|
1173
|
+
// copy attributes from html media element to plugin media element
|
1174
|
+
for (var i = 0; i < htmlMediaElement.attributes.length; i++) {
|
1175
|
+
var attribute = htmlMediaElement.attributes[i];
|
1176
|
+
if (attribute.specified == true) {
|
1177
|
+
pluginMediaElement.setAttribute(attribute.name, attribute.value);
|
1178
|
+
}
|
1179
|
+
}
|
1180
|
+
|
1181
|
+
// check for placement inside a <p> tag (sometimes WYSIWYG editors do this)
|
1182
|
+
node = htmlMediaElement.parentNode;
|
1183
|
+
while (node !== null && node.tagName.toLowerCase() != 'body') {
|
1184
|
+
if (node.parentNode.tagName.toLowerCase() == 'p') {
|
1185
|
+
node.parentNode.parentNode.insertBefore(node, node.parentNode);
|
1186
|
+
break;
|
1187
|
+
}
|
1188
|
+
node = node.parentNode;
|
1189
|
+
}
|
1190
|
+
|
1191
|
+
if (playback.isVideo) {
|
1192
|
+
width = (options.pluginWidth > 0) ? options.pluginWidth : (options.videoWidth > 0) ? options.videoWidth : (htmlMediaElement.getAttribute('width') !== null) ? htmlMediaElement.getAttribute('width') : options.defaultVideoWidth;
|
1193
|
+
height = (options.pluginHeight > 0) ? options.pluginHeight : (options.videoHeight > 0) ? options.videoHeight : (htmlMediaElement.getAttribute('height') !== null) ? htmlMediaElement.getAttribute('height') : options.defaultVideoHeight;
|
1194
|
+
|
1195
|
+
// in case of '%' make sure it's encoded
|
1196
|
+
width = mejs.Utility.encodeUrl(width);
|
1197
|
+
height = mejs.Utility.encodeUrl(height);
|
1198
|
+
|
1199
|
+
} else {
|
1200
|
+
if (options.enablePluginDebug) {
|
1201
|
+
width = 320;
|
1202
|
+
height = 240;
|
1203
|
+
}
|
1204
|
+
}
|
1205
|
+
|
1206
|
+
// register plugin
|
1207
|
+
pluginMediaElement.success = options.success;
|
1208
|
+
mejs.MediaPluginBridge.registerPluginElement(pluginid, pluginMediaElement, htmlMediaElement);
|
1209
|
+
|
1210
|
+
// add container (must be added to DOM before inserting HTML for IE)
|
1211
|
+
container.className = 'me-plugin';
|
1212
|
+
container.id = pluginid + '_container';
|
1213
|
+
|
1214
|
+
if (playback.isVideo) {
|
1215
|
+
htmlMediaElement.parentNode.insertBefore(container, htmlMediaElement);
|
1216
|
+
} else {
|
1217
|
+
document.body.insertBefore(container, document.body.childNodes[0]);
|
1218
|
+
}
|
1219
|
+
|
1220
|
+
// flash/silverlight vars
|
1221
|
+
initVars = [
|
1222
|
+
'id=' + pluginid,
|
1223
|
+
'isvideo=' + ((playback.isVideo) ? "true" : "false"),
|
1224
|
+
'autoplay=' + ((autoplay) ? "true" : "false"),
|
1225
|
+
'preload=' + preload,
|
1226
|
+
'width=' + width,
|
1227
|
+
'startvolume=' + options.startVolume,
|
1228
|
+
'timerrate=' + options.timerRate,
|
1229
|
+
'flashstreamer=' + options.flashStreamer,
|
1230
|
+
'height=' + height,
|
1231
|
+
'pseudostreamstart=' + options.pseudoStreamingStartQueryParam];
|
1232
|
+
|
1233
|
+
if (playback.url !== null) {
|
1234
|
+
if (playback.method == 'flash') {
|
1235
|
+
initVars.push('file=' + mejs.Utility.encodeUrl(playback.url));
|
1236
|
+
} else {
|
1237
|
+
initVars.push('file=' + playback.url);
|
1238
|
+
}
|
1239
|
+
}
|
1240
|
+
if (options.enablePluginDebug) {
|
1241
|
+
initVars.push('debug=true');
|
1242
|
+
}
|
1243
|
+
if (options.enablePluginSmoothing) {
|
1244
|
+
initVars.push('smoothing=true');
|
1245
|
+
}
|
1246
|
+
if (options.enablePseudoStreaming) {
|
1247
|
+
initVars.push('pseudostreaming=true');
|
1248
|
+
}
|
1249
|
+
if (controls) {
|
1250
|
+
initVars.push('controls=true'); // shows controls in the plugin if desired
|
1251
|
+
}
|
1252
|
+
if (options.pluginVars) {
|
1253
|
+
initVars = initVars.concat(options.pluginVars);
|
1254
|
+
}
|
1255
|
+
|
1256
|
+
switch (playback.method) {
|
1257
|
+
case 'silverlight':
|
1258
|
+
container.innerHTML =
|
1259
|
+
'<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="' + pluginid + '" name="' + pluginid + '" width="' + width + '" height="' + height + '" class="mejs-shim">' +
|
1260
|
+
'<param name="initParams" value="' + initVars.join(',') + '" />' +
|
1261
|
+
'<param name="windowless" value="true" />' +
|
1262
|
+
'<param name="background" value="black" />' +
|
1263
|
+
'<param name="minRuntimeVersion" value="3.0.0.0" />' +
|
1264
|
+
'<param name="autoUpgrade" value="true" />' +
|
1265
|
+
'<param name="source" value="' + options.pluginPath + options.silverlightName + '" />' +
|
1266
|
+
'</object>';
|
1267
|
+
break;
|
1268
|
+
|
1269
|
+
case 'flash':
|
1270
|
+
|
1271
|
+
if (mejs.MediaFeatures.isIE) {
|
1272
|
+
specialIEContainer = document.createElement('div');
|
1273
|
+
container.appendChild(specialIEContainer);
|
1274
|
+
specialIEContainer.outerHTML =
|
1275
|
+
'<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
|
1276
|
+
'id="' + pluginid + '" width="' + width + '" height="' + height + '" class="mejs-shim">' +
|
1277
|
+
'<param name="movie" value="' + options.pluginPath + options.flashName + '?x=' + (new Date()) + '" />' +
|
1278
|
+
'<param name="flashvars" value="' + initVars.join('&') + '" />' +
|
1279
|
+
'<param name="quality" value="high" />' +
|
1280
|
+
'<param name="bgcolor" value="#000000" />' +
|
1281
|
+
'<param name="wmode" value="transparent" />' +
|
1282
|
+
'<param name="allowScriptAccess" value="always" />' +
|
1283
|
+
'<param name="allowFullScreen" value="true" />' +
|
1284
|
+
'</object>';
|
1285
|
+
|
1286
|
+
} else {
|
1287
|
+
|
1288
|
+
container.innerHTML =
|
1289
|
+
'<embed id="' + pluginid + '" name="' + pluginid + '" ' +
|
1290
|
+
'play="true" ' +
|
1291
|
+
'loop="false" ' +
|
1292
|
+
'quality="high" ' +
|
1293
|
+
'bgcolor="#000000" ' +
|
1294
|
+
'wmode="transparent" ' +
|
1295
|
+
'allowScriptAccess="always" ' +
|
1296
|
+
'allowFullScreen="true" ' +
|
1297
|
+
'type="application/x-shockwave-flash" pluginspage="//www.macromedia.com/go/getflashplayer" ' +
|
1298
|
+
'src="' + options.pluginPath + options.flashName + '" ' +
|
1299
|
+
'flashvars="' + initVars.join('&') + '" ' +
|
1300
|
+
'width="' + width + '" ' +
|
1301
|
+
'height="' + height + '" ' +
|
1302
|
+
'class="mejs-shim"></embed>';
|
1303
|
+
}
|
1304
|
+
break;
|
1305
|
+
|
1306
|
+
case 'youtube':
|
1307
|
+
|
1308
|
+
|
1309
|
+
var
|
1310
|
+
videoId = playback.url.substr(playback.url.lastIndexOf('=')+1);
|
1311
|
+
youtubeSettings = {
|
1312
|
+
container: container,
|
1313
|
+
containerId: container.id,
|
1314
|
+
pluginMediaElement: pluginMediaElement,
|
1315
|
+
pluginId: pluginid,
|
1316
|
+
videoId: videoId,
|
1317
|
+
height: height,
|
1318
|
+
width: width
|
1319
|
+
};
|
1320
|
+
|
1321
|
+
if (mejs.PluginDetector.hasPluginVersion('flash', [10,0,0]) ) {
|
1322
|
+
mejs.YouTubeApi.createFlash(youtubeSettings);
|
1323
|
+
} else {
|
1324
|
+
mejs.YouTubeApi.enqueueIframe(youtubeSettings);
|
1325
|
+
}
|
1326
|
+
|
1327
|
+
break;
|
1328
|
+
|
1329
|
+
// DEMO Code. Does NOT work.
|
1330
|
+
case 'vimeo':
|
1331
|
+
//console.log('vimeoid');
|
1332
|
+
|
1333
|
+
pluginMediaElement.vimeoid = playback.url.substr(playback.url.lastIndexOf('/')+1);
|
1334
|
+
|
1335
|
+
container.innerHTML ='<iframe src="http://player.vimeo.com/video/' + pluginMediaElement.vimeoid + '?portrait=0&byline=0&title=0" width="' + width +'" height="' + height +'" frameborder="0" class="mejs-shim"></iframe>';
|
1336
|
+
|
1337
|
+
/*
|
1338
|
+
container.innerHTML =
|
1339
|
+
'<object width="' + width + '" height="' + height + '" class="mejs-shim">' +
|
1340
|
+
'<param name="allowfullscreen" value="true" />' +
|
1341
|
+
'<param name="allowscriptaccess" value="always" />' +
|
1342
|
+
'<param name="flashvars" value="api=1" />' +
|
1343
|
+
'<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" />' +
|
1344
|
+
'<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 + '" class="mejs-shim"></embed>' +
|
1345
|
+
'</object>';
|
1346
|
+
*/
|
1347
|
+
|
1348
|
+
break;
|
1349
|
+
}
|
1350
|
+
// hide original element
|
1351
|
+
htmlMediaElement.style.display = 'none';
|
1352
|
+
|
1353
|
+
// FYI: options.success will be fired by the MediaPluginBridge
|
1354
|
+
|
1355
|
+
return pluginMediaElement;
|
1356
|
+
},
|
1357
|
+
|
1358
|
+
updateNative: function(playback, options, autoplay, preload) {
|
1359
|
+
|
1360
|
+
var htmlMediaElement = playback.htmlMediaElement,
|
1361
|
+
m;
|
1362
|
+
|
1363
|
+
|
1364
|
+
// add methods to video object to bring it into parity with Flash Object
|
1365
|
+
for (m in mejs.HtmlMediaElement) {
|
1366
|
+
htmlMediaElement[m] = mejs.HtmlMediaElement[m];
|
1367
|
+
}
|
1368
|
+
|
1369
|
+
/*
|
1370
|
+
Chrome now supports preload="none"
|
1371
|
+
if (mejs.MediaFeatures.isChrome) {
|
1372
|
+
|
1373
|
+
// special case to enforce preload attribute (Chrome doesn't respect this)
|
1374
|
+
if (preload === 'none' && !autoplay) {
|
1375
|
+
|
1376
|
+
// forces the browser to stop loading (note: fails in IE9)
|
1377
|
+
htmlMediaElement.src = '';
|
1378
|
+
htmlMediaElement.load();
|
1379
|
+
htmlMediaElement.canceledPreload = true;
|
1380
|
+
|
1381
|
+
htmlMediaElement.addEventListener('play',function() {
|
1382
|
+
if (htmlMediaElement.canceledPreload) {
|
1383
|
+
htmlMediaElement.src = playback.url;
|
1384
|
+
htmlMediaElement.load();
|
1385
|
+
htmlMediaElement.play();
|
1386
|
+
htmlMediaElement.canceledPreload = false;
|
1387
|
+
}
|
1388
|
+
}, false);
|
1389
|
+
// for some reason Chrome forgets how to autoplay sometimes.
|
1390
|
+
} else if (autoplay) {
|
1391
|
+
htmlMediaElement.load();
|
1392
|
+
htmlMediaElement.play();
|
1393
|
+
}
|
1394
|
+
}
|
1395
|
+
*/
|
1396
|
+
|
1397
|
+
// fire success code
|
1398
|
+
options.success(htmlMediaElement, htmlMediaElement);
|
1399
|
+
|
1400
|
+
return htmlMediaElement;
|
1401
|
+
}
|
1402
|
+
};
|
1403
|
+
|
1404
|
+
/*
|
1405
|
+
- test on IE (object vs. embed)
|
1406
|
+
- determine when to use iframe (Firefox, Safari, Mobile) vs. Flash (Chrome, IE)
|
1407
|
+
- fullscreen?
|
1408
|
+
*/
|
1409
|
+
|
1410
|
+
// YouTube Flash and Iframe API
|
1411
|
+
mejs.YouTubeApi = {
|
1412
|
+
isIframeStarted: false,
|
1413
|
+
isIframeLoaded: false,
|
1414
|
+
loadIframeApi: function() {
|
1415
|
+
if (!this.isIframeStarted) {
|
1416
|
+
var tag = document.createElement('script');
|
1417
|
+
tag.src = "//www.youtube.com/player_api";
|
1418
|
+
var firstScriptTag = document.getElementsByTagName('script')[0];
|
1419
|
+
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
|
1420
|
+
this.isIframeStarted = true;
|
1421
|
+
}
|
1422
|
+
},
|
1423
|
+
iframeQueue: [],
|
1424
|
+
enqueueIframe: function(yt) {
|
1425
|
+
|
1426
|
+
if (this.isLoaded) {
|
1427
|
+
this.createIframe(yt);
|
1428
|
+
} else {
|
1429
|
+
this.loadIframeApi();
|
1430
|
+
this.iframeQueue.push(yt);
|
1431
|
+
}
|
1432
|
+
},
|
1433
|
+
createIframe: function(settings) {
|
1434
|
+
|
1435
|
+
var
|
1436
|
+
pluginMediaElement = settings.pluginMediaElement,
|
1437
|
+
player = new YT.Player(settings.containerId, {
|
1438
|
+
height: settings.height,
|
1439
|
+
width: settings.width,
|
1440
|
+
videoId: settings.videoId,
|
1441
|
+
playerVars: {controls:0},
|
1442
|
+
events: {
|
1443
|
+
'onReady': function() {
|
1444
|
+
|
1445
|
+
// hook up iframe object to MEjs
|
1446
|
+
settings.pluginMediaElement.pluginApi = player;
|
1447
|
+
|
1448
|
+
// init mejs
|
1449
|
+
mejs.MediaPluginBridge.initPlugin(settings.pluginId);
|
1450
|
+
|
1451
|
+
// create timer
|
1452
|
+
setInterval(function() {
|
1453
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
|
1454
|
+
}, 250);
|
1455
|
+
},
|
1456
|
+
'onStateChange': function(e) {
|
1457
|
+
|
1458
|
+
mejs.YouTubeApi.handleStateChange(e.data, player, pluginMediaElement);
|
1459
|
+
|
1460
|
+
}
|
1461
|
+
}
|
1462
|
+
});
|
1463
|
+
},
|
1464
|
+
|
1465
|
+
createEvent: function (player, pluginMediaElement, eventName) {
|
1466
|
+
var obj = {
|
1467
|
+
type: eventName,
|
1468
|
+
target: pluginMediaElement
|
1469
|
+
};
|
1470
|
+
|
1471
|
+
if (player && player.getDuration) {
|
1472
|
+
|
1473
|
+
// time
|
1474
|
+
pluginMediaElement.currentTime = obj.currentTime = player.getCurrentTime();
|
1475
|
+
pluginMediaElement.duration = obj.duration = player.getDuration();
|
1476
|
+
|
1477
|
+
// state
|
1478
|
+
obj.paused = pluginMediaElement.paused;
|
1479
|
+
obj.ended = pluginMediaElement.ended;
|
1480
|
+
|
1481
|
+
// sound
|
1482
|
+
obj.muted = player.isMuted();
|
1483
|
+
obj.volume = player.getVolume() / 100;
|
1484
|
+
|
1485
|
+
// progress
|
1486
|
+
obj.bytesTotal = player.getVideoBytesTotal();
|
1487
|
+
obj.bufferedBytes = player.getVideoBytesLoaded();
|
1488
|
+
|
1489
|
+
// fake the W3C buffered TimeRange
|
1490
|
+
var bufferedTime = obj.bufferedBytes / obj.bytesTotal * obj.duration;
|
1491
|
+
|
1492
|
+
obj.target.buffered = obj.buffered = {
|
1493
|
+
start: function(index) {
|
1494
|
+
return 0;
|
1495
|
+
},
|
1496
|
+
end: function (index) {
|
1497
|
+
return bufferedTime;
|
1498
|
+
},
|
1499
|
+
length: 1
|
1500
|
+
};
|
1501
|
+
|
1502
|
+
}
|
1503
|
+
|
1504
|
+
// send event up the chain
|
1505
|
+
pluginMediaElement.dispatchEvent(obj.type, obj);
|
1506
|
+
},
|
1507
|
+
|
1508
|
+
iFrameReady: function() {
|
1509
|
+
|
1510
|
+
this.isLoaded = true;
|
1511
|
+
this.isIframeLoaded = true;
|
1512
|
+
|
1513
|
+
while (this.iframeQueue.length > 0) {
|
1514
|
+
var settings = this.iframeQueue.pop();
|
1515
|
+
this.createIframe(settings);
|
1516
|
+
}
|
1517
|
+
},
|
1518
|
+
|
1519
|
+
// FLASH!
|
1520
|
+
flashPlayers: {},
|
1521
|
+
createFlash: function(settings) {
|
1522
|
+
|
1523
|
+
this.flashPlayers[settings.pluginId] = settings;
|
1524
|
+
|
1525
|
+
/*
|
1526
|
+
settings.container.innerHTML =
|
1527
|
+
'<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" ' +
|
1528
|
+
'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; " class="mejs-shim">' +
|
1529
|
+
'<param name="allowScriptAccess" value="always">' +
|
1530
|
+
'<param name="wmode" value="transparent">' +
|
1531
|
+
'</object>';
|
1532
|
+
*/
|
1533
|
+
|
1534
|
+
var specialIEContainer,
|
1535
|
+
youtubeUrl = '//www.youtube.com/apiplayer?enablejsapi=1&playerapiid=' + settings.pluginId + '&version=3&autoplay=0&controls=0&modestbranding=1&loop=0';
|
1536
|
+
|
1537
|
+
if (mejs.MediaFeatures.isIE) {
|
1538
|
+
|
1539
|
+
specialIEContainer = document.createElement('div');
|
1540
|
+
settings.container.appendChild(specialIEContainer);
|
1541
|
+
specialIEContainer.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
|
1542
|
+
'id="' + settings.pluginId + '" width="' + settings.width + '" height="' + settings.height + '" class="mejs-shim">' +
|
1543
|
+
'<param name="movie" value="' + youtubeUrl + '" />' +
|
1544
|
+
'<param name="wmode" value="transparent" />' +
|
1545
|
+
'<param name="allowScriptAccess" value="always" />' +
|
1546
|
+
'<param name="allowFullScreen" value="true" />' +
|
1547
|
+
'</object>';
|
1548
|
+
} else {
|
1549
|
+
settings.container.innerHTML =
|
1550
|
+
'<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="' + youtubeUrl + '" ' +
|
1551
|
+
'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; " class="mejs-shim">' +
|
1552
|
+
'<param name="allowScriptAccess" value="always">' +
|
1553
|
+
'<param name="wmode" value="transparent">' +
|
1554
|
+
'</object>';
|
1555
|
+
}
|
1556
|
+
|
1557
|
+
},
|
1558
|
+
|
1559
|
+
flashReady: function(id) {
|
1560
|
+
var
|
1561
|
+
settings = this.flashPlayers[id],
|
1562
|
+
player = document.getElementById(id),
|
1563
|
+
pluginMediaElement = settings.pluginMediaElement;
|
1564
|
+
|
1565
|
+
// hook up and return to MediaELementPlayer.success
|
1566
|
+
pluginMediaElement.pluginApi =
|
1567
|
+
pluginMediaElement.pluginElement = player;
|
1568
|
+
mejs.MediaPluginBridge.initPlugin(id);
|
1569
|
+
|
1570
|
+
// load the youtube video
|
1571
|
+
player.cueVideoById(settings.videoId);
|
1572
|
+
|
1573
|
+
var callbackName = settings.containerId + '_callback';
|
1574
|
+
|
1575
|
+
window[callbackName] = function(e) {
|
1576
|
+
mejs.YouTubeApi.handleStateChange(e, player, pluginMediaElement);
|
1577
|
+
}
|
1578
|
+
|
1579
|
+
player.addEventListener('onStateChange', callbackName);
|
1580
|
+
|
1581
|
+
setInterval(function() {
|
1582
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
|
1583
|
+
}, 250);
|
1584
|
+
},
|
1585
|
+
|
1586
|
+
handleStateChange: function(youTubeState, player, pluginMediaElement) {
|
1587
|
+
switch (youTubeState) {
|
1588
|
+
case -1: // not started
|
1589
|
+
pluginMediaElement.paused = true;
|
1590
|
+
pluginMediaElement.ended = true;
|
1591
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'loadedmetadata');
|
1592
|
+
//createYouTubeEvent(player, pluginMediaElement, 'loadeddata');
|
1593
|
+
break;
|
1594
|
+
case 0:
|
1595
|
+
pluginMediaElement.paused = false;
|
1596
|
+
pluginMediaElement.ended = true;
|
1597
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'ended');
|
1598
|
+
break;
|
1599
|
+
case 1:
|
1600
|
+
pluginMediaElement.paused = false;
|
1601
|
+
pluginMediaElement.ended = false;
|
1602
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'play');
|
1603
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'playing');
|
1604
|
+
break;
|
1605
|
+
case 2:
|
1606
|
+
pluginMediaElement.paused = true;
|
1607
|
+
pluginMediaElement.ended = false;
|
1608
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'pause');
|
1609
|
+
break;
|
1610
|
+
case 3: // buffering
|
1611
|
+
mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'progress');
|
1612
|
+
break;
|
1613
|
+
case 5:
|
1614
|
+
// cued?
|
1615
|
+
break;
|
1616
|
+
|
1617
|
+
}
|
1618
|
+
|
1619
|
+
}
|
1620
|
+
}
|
1621
|
+
// IFRAME
|
1622
|
+
function onYouTubePlayerAPIReady() {
|
1623
|
+
mejs.YouTubeApi.iFrameReady();
|
1624
|
+
}
|
1625
|
+
// FLASH
|
1626
|
+
function onYouTubePlayerReady(id) {
|
1627
|
+
mejs.YouTubeApi.flashReady(id);
|
1628
|
+
}
|
1629
|
+
|
1630
|
+
window.mejs = mejs;
|
1631
|
+
window.MediaElement = mejs.MediaElement;
|
1632
|
+
|
1633
|
+
/*!
|
1634
|
+
* Adds Internationalization and localization to objects.
|
1635
|
+
*
|
1636
|
+
* What is the concept beyond i18n?
|
1637
|
+
* http://en.wikipedia.org/wiki/Internationalization_and_localization
|
1638
|
+
*
|
1639
|
+
*
|
1640
|
+
* This file both i18n methods and locale which is used to translate
|
1641
|
+
* strings into other languages.
|
1642
|
+
*
|
1643
|
+
* Default translations are not available, you have to add them
|
1644
|
+
* through locale objects which are named exactly as the langcode
|
1645
|
+
* they stand for. The default language is always english (en).
|
1646
|
+
*
|
1647
|
+
*
|
1648
|
+
* Wrapper built to be able to attach the i18n object to
|
1649
|
+
* other objects without changing more than one line.
|
1650
|
+
*
|
1651
|
+
*
|
1652
|
+
* LICENSE:
|
1653
|
+
*
|
1654
|
+
* The i18n file uses methods from the Drupal project (drupal.js):
|
1655
|
+
* - i18n.methods.t() (modified)
|
1656
|
+
* - i18n.methods.checkPlain() (full copy)
|
1657
|
+
* - i18n.methods.formatString() (full copy)
|
1658
|
+
*
|
1659
|
+
* The Drupal project is (like mediaelementjs) licensed under GPLv2.
|
1660
|
+
* - http://drupal.org/licensing/faq/#q1
|
1661
|
+
* - https://github.com/johndyer/mediaelement
|
1662
|
+
* - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
1663
|
+
*
|
1664
|
+
*
|
1665
|
+
* @author
|
1666
|
+
* Tim Latz (latz.tim@gmail.com)
|
1667
|
+
*
|
1668
|
+
* @see
|
1669
|
+
* me-i18n-locale.js
|
1670
|
+
*
|
1671
|
+
* @params
|
1672
|
+
* - context - document, iframe ..
|
1673
|
+
* - exports - CommonJS, window ..
|
1674
|
+
*
|
1675
|
+
*/
|
1676
|
+
;(function(context, exports, undefined) {
|
1677
|
+
"use strict";
|
1678
|
+
var i18n = {
|
1679
|
+
"locale": {
|
1680
|
+
"strings" : {}
|
1681
|
+
},
|
1682
|
+
"methods" : {}
|
1683
|
+
};
|
1684
|
+
// start i18n
|
1685
|
+
|
1686
|
+
|
1687
|
+
/**
|
1688
|
+
* Get the current browser's language
|
1689
|
+
*
|
1690
|
+
* @see: i18n.methods.t()
|
1691
|
+
*/
|
1692
|
+
i18n.locale.getLanguage = function () {
|
1693
|
+
return i18n.locale || {
|
1694
|
+
"language" : navigator.language
|
1695
|
+
};
|
1696
|
+
};
|
1697
|
+
|
1698
|
+
/**
|
1699
|
+
* Store the language the locale object was initialized with
|
1700
|
+
*/
|
1701
|
+
i18n.locale.INIT_LANGUAGE = i18n.locale.getLanguage();
|
1702
|
+
|
1703
|
+
|
1704
|
+
/**
|
1705
|
+
* Encode special characters in a plain-text string for display as HTML.
|
1706
|
+
*/
|
1707
|
+
i18n.methods.checkPlain = function (str) {
|
1708
|
+
var character, regex,
|
1709
|
+
replace = {
|
1710
|
+
'&': '&',
|
1711
|
+
'"': '"',
|
1712
|
+
'<': '<',
|
1713
|
+
'>': '>'
|
1714
|
+
};
|
1715
|
+
str = String(str);
|
1716
|
+
for (character in replace) {
|
1717
|
+
if (replace.hasOwnProperty(character)) {
|
1718
|
+
regex = new RegExp(character, 'g');
|
1719
|
+
str = str.replace(regex, replace[character]);
|
1720
|
+
}
|
1721
|
+
}
|
1722
|
+
return str;
|
1723
|
+
};
|
1724
|
+
|
1725
|
+
/**
|
1726
|
+
* Replace placeholders with sanitized values in a string.
|
1727
|
+
*
|
1728
|
+
* @param str
|
1729
|
+
* A string with placeholders.
|
1730
|
+
* @param args
|
1731
|
+
* An object of replacements pairs to make. Incidences of any key in this
|
1732
|
+
* array are replaced with the corresponding value. Based on the first
|
1733
|
+
* character of the key, the value is escaped and/or themed:
|
1734
|
+
* - !variable: inserted as is
|
1735
|
+
* - @variable: escape plain text to HTML (i18n.methods.checkPlain)
|
1736
|
+
* - %variable: escape text and theme as a placeholder for user-submitted
|
1737
|
+
* content (checkPlain + <em class="placeholder" > )
|
1738
|
+
*
|
1739
|
+
* @see i18n.methods.t()
|
1740
|
+
*/
|
1741
|
+
i18n.methods.formatString = function(str, args) {
|
1742
|
+
// Transform arguments before inserting them.
|
1743
|
+
for (var key in args) {
|
1744
|
+
switch (key.charAt(0)) {
|
1745
|
+
// Escaped only.
|
1746
|
+
case '@':
|
1747
|
+
args[key] = i18n.methods.checkPlain(args[key]);
|
1748
|
+
break;
|
1749
|
+
// Pass-through.
|
1750
|
+
case '!':
|
1751
|
+
break;
|
1752
|
+
// Escaped and placeholder.
|
1753
|
+
case '%':
|
1754
|
+
default:
|
1755
|
+
args[key] = '<em class="placeholder">' + i18n.methods.checkPlain(args[key]) + '</em>';
|
1756
|
+
break;
|
1757
|
+
}
|
1758
|
+
str = str.replace(key, args[key]);
|
1759
|
+
}
|
1760
|
+
return str;
|
1761
|
+
};
|
1762
|
+
|
1763
|
+
/**
|
1764
|
+
* Translate strings to the page language or a given language.
|
1765
|
+
*
|
1766
|
+
* See the documentation of the server-side t() function for further details.
|
1767
|
+
*
|
1768
|
+
* @param str
|
1769
|
+
* A string containing the English string to translate.
|
1770
|
+
* @param args
|
1771
|
+
* An object of replacements pairs to make after translation. Incidences
|
1772
|
+
* of any key in this array are replaced with the corresponding value.
|
1773
|
+
* See i18n.methods.formatString().
|
1774
|
+
*
|
1775
|
+
* @param options
|
1776
|
+
* - 'context' (defaults to the default context): The context the source string
|
1777
|
+
* belongs to.
|
1778
|
+
*
|
1779
|
+
* @return
|
1780
|
+
* The translated string.
|
1781
|
+
*/
|
1782
|
+
i18n.methods.t = function (str, args, options) {
|
1783
|
+
|
1784
|
+
// Fetch the localized version of the string.
|
1785
|
+
if (i18n.locale.strings && i18n.locale.strings[options.context] && i18n.locale.strings[options.context][str]) {
|
1786
|
+
str = i18n.locale.strings[options.context][str];
|
1787
|
+
}
|
1788
|
+
|
1789
|
+
if (args) {
|
1790
|
+
str = i18n.methods.formatString(str, args);
|
1791
|
+
}
|
1792
|
+
return str;
|
1793
|
+
};
|
1794
|
+
|
1795
|
+
|
1796
|
+
/**
|
1797
|
+
* Wrapper for i18n.methods.t()
|
1798
|
+
*
|
1799
|
+
* @see i18n.methods.t()
|
1800
|
+
* @throws InvalidArgumentException
|
1801
|
+
*/
|
1802
|
+
i18n.t = function(str, args, options) {
|
1803
|
+
|
1804
|
+
if (typeof str === 'string' && str.length > 0) {
|
1805
|
+
|
1806
|
+
// check every time due languge can change for
|
1807
|
+
// different reasons (translation, lang switcher ..)
|
1808
|
+
var lang = i18n.locale.getLanguage();
|
1809
|
+
|
1810
|
+
options = options || {
|
1811
|
+
"context" : lang.language
|
1812
|
+
};
|
1813
|
+
|
1814
|
+
return i18n.methods.t(str, args, options);
|
1815
|
+
}
|
1816
|
+
else {
|
1817
|
+
throw {
|
1818
|
+
"name" : 'InvalidArgumentException',
|
1819
|
+
"message" : 'First argument is either not a string or empty.'
|
1820
|
+
}
|
1821
|
+
}
|
1822
|
+
};
|
1823
|
+
|
1824
|
+
// end i18n
|
1825
|
+
exports.i18n = i18n;
|
1826
|
+
}(document, mejs));
|
1827
|
+
|
1828
|
+
;(function(exports, undefined) {
|
1829
|
+
|
1830
|
+
"use strict";
|
1831
|
+
|
1832
|
+
if ( mejs.i18n.locale.language && mejs.i18n.locale.strings ) {
|
1833
|
+
exports[mejs.i18n.locale.language] = mejs.i18n.locale.strings;
|
1834
|
+
}
|
1835
|
+
|
1836
|
+
}(mejs.i18n.locale.strings));
|
1837
|
+
|
1838
|
+
/*!
|
1839
|
+
* This is a i18n.locale language object.
|
1840
|
+
*
|
1841
|
+
*<de> German translation by Tim Latz, latz.tim@gmail.com
|
1842
|
+
*
|
1843
|
+
* @author
|
1844
|
+
* Tim Latz (latz.tim@gmail.com)
|
1845
|
+
*
|
1846
|
+
* @see
|
1847
|
+
* me-i18n.js
|
1848
|
+
*
|
1849
|
+
* @params
|
1850
|
+
* - exports - CommonJS, window ..
|
1851
|
+
*/
|
1852
|
+
;(function(exports, undefined) {
|
1853
|
+
|
1854
|
+
"use strict";
|
1855
|
+
|
1856
|
+
exports.de = {
|
1857
|
+
"Fullscreen" : "Vollbild",
|
1858
|
+
"Go Fullscreen" : "Vollbild an",
|
1859
|
+
"Turn off Fullscreen" : "Vollbild aus",
|
1860
|
+
"Close" : "Schließen"
|
1861
|
+
};
|
1862
|
+
|
1863
|
+
}(mejs.i18n.locale.strings));
|
1864
|
+
/*!
|
1865
|
+
* This is a i18n.locale language object.
|
1866
|
+
*
|
1867
|
+
*<de> Traditional chinese translation by Tim Latz, latz.tim@gmail.com
|
1868
|
+
*
|
1869
|
+
* @author
|
1870
|
+
* Tim Latz (latz.tim@gmail.com)
|
1871
|
+
*
|
1872
|
+
* @see
|
1873
|
+
* me-i18n.js
|
1874
|
+
*
|
1875
|
+
* @params
|
1876
|
+
* - exports - CommonJS, window ..
|
1877
|
+
*/
|
1878
|
+
;(function(exports, undefined) {
|
1879
|
+
|
1880
|
+
"use strict";
|
1881
|
+
|
1882
|
+
exports.zh = {
|
1883
|
+
"Fullscreen" : "全螢幕",
|
1884
|
+
"Go Fullscreen" : "全屏模式",
|
1885
|
+
"Turn off Fullscreen" : "退出全屏模式",
|
1886
|
+
"Close" : "關閉"
|
1887
|
+
};
|
1888
|
+
|
1889
|
+
}(mejs.i18n.locale.strings));
|
1890
|
+
|