gyorgy@0
|
1 /*!
|
gyorgy@0
|
2 * MediaElement.js
|
gyorgy@0
|
3 * HTML5 <video> and <audio> shim and player
|
gyorgy@0
|
4 * http://mediaelementjs.com/
|
gyorgy@0
|
5 *
|
gyorgy@0
|
6 * Creates a JavaScript object that mimics HTML5 MediaElement API
|
gyorgy@0
|
7 * for browsers that don't understand HTML5 or can't play the provided codec
|
gyorgy@0
|
8 * Can play MP4 (H.264), Ogg, WebM, FLV, WMV, WMA, ACC, and MP3
|
gyorgy@0
|
9 *
|
gyorgy@0
|
10 * Copyright 2010-2011, John Dyer (http://j.hn)
|
gyorgy@0
|
11 * Dual licensed under the MIT or GPL Version 2 licenses.
|
gyorgy@0
|
12 *
|
gyorgy@0
|
13 */
|
gyorgy@0
|
14 // Namespace
|
gyorgy@0
|
15 var mejs = mejs || {};
|
gyorgy@0
|
16
|
gyorgy@0
|
17 // version number
|
gyorgy@0
|
18 mejs.version = '2.1.9';
|
gyorgy@0
|
19
|
gyorgy@0
|
20 // player number (for missing, same id attr)
|
gyorgy@0
|
21 mejs.meIndex = 0;
|
gyorgy@0
|
22
|
gyorgy@0
|
23 // media types accepted by plugins
|
gyorgy@0
|
24 mejs.plugins = {
|
gyorgy@0
|
25 silverlight: [
|
gyorgy@0
|
26 {version: [3,0], types: ['video/mp4','video/m4v','video/mov','video/wmv','audio/wma','audio/m4a','audio/mp3','audio/wav','audio/mpeg']}
|
gyorgy@0
|
27 ],
|
gyorgy@0
|
28 flash: [
|
gyorgy@0
|
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']}
|
gyorgy@0
|
30 //,{version: [11,0], types: ['video/webm']} // for future reference
|
gyorgy@0
|
31 ]
|
gyorgy@0
|
32 };
|
gyorgy@0
|
33
|
gyorgy@0
|
34 /*
|
gyorgy@0
|
35 Utility methods
|
gyorgy@0
|
36 */
|
gyorgy@0
|
37 mejs.Utility = {
|
gyorgy@0
|
38 encodeUrl: function(url) {
|
gyorgy@0
|
39 return encodeURIComponent(url); //.replace(/\?/gi,'%3F').replace(/=/gi,'%3D').replace(/&/gi,'%26');
|
gyorgy@0
|
40 },
|
gyorgy@0
|
41 escapeHTML: function(s) {
|
gyorgy@0
|
42 return s.toString().split('&').join('&').split('<').join('<').split('"').join('"');
|
gyorgy@0
|
43 },
|
gyorgy@0
|
44 absolutizeUrl: function(url) {
|
gyorgy@0
|
45 var el = document.createElement('div');
|
gyorgy@0
|
46 el.innerHTML = '<a href="' + this.escapeHTML(url) + '">x</a>';
|
gyorgy@0
|
47 return el.firstChild.href;
|
gyorgy@0
|
48 },
|
gyorgy@0
|
49 getScriptPath: function(scriptNames) {
|
gyorgy@0
|
50 var
|
gyorgy@0
|
51 i = 0,
|
gyorgy@0
|
52 j,
|
gyorgy@0
|
53 path = '',
|
gyorgy@0
|
54 name = '',
|
gyorgy@0
|
55 script,
|
gyorgy@0
|
56 scripts = document.getElementsByTagName('script');
|
gyorgy@0
|
57
|
gyorgy@0
|
58 for (; i < scripts.length; i++) {
|
gyorgy@0
|
59 script = scripts[i].src;
|
gyorgy@0
|
60 for (j = 0; j < scriptNames.length; j++) {
|
gyorgy@0
|
61 name = scriptNames[j];
|
gyorgy@0
|
62 if (script.indexOf(name) > -1) {
|
gyorgy@0
|
63 path = script.substring(0, script.indexOf(name));
|
gyorgy@0
|
64 break;
|
gyorgy@0
|
65 }
|
gyorgy@0
|
66 }
|
gyorgy@0
|
67 if (path !== '') {
|
gyorgy@0
|
68 break;
|
gyorgy@0
|
69 }
|
gyorgy@0
|
70 }
|
gyorgy@0
|
71 return path;
|
gyorgy@0
|
72 },
|
gyorgy@0
|
73 secondsToTimeCode: function(seconds,forceHours) {
|
gyorgy@0
|
74 seconds = Math.round(seconds);
|
gyorgy@0
|
75 var hours,
|
gyorgy@0
|
76 minutes = Math.floor(seconds / 60);
|
gyorgy@0
|
77 if (minutes >= 60) {
|
gyorgy@0
|
78 hours = Math.floor(minutes / 60);
|
gyorgy@0
|
79 minutes = minutes % 60;
|
gyorgy@0
|
80 }
|
gyorgy@0
|
81 hours = hours === undefined ? "00" : (hours >= 10) ? hours : "0" + hours;
|
gyorgy@0
|
82 minutes = (minutes >= 10) ? minutes : "0" + minutes;
|
gyorgy@0
|
83 seconds = Math.floor(seconds % 60);
|
gyorgy@0
|
84 seconds = (seconds >= 10) ? seconds : "0" + seconds;
|
gyorgy@0
|
85 return ((hours > 0 || forceHours === true) ? hours + ":" :'') + minutes + ":" + seconds;
|
gyorgy@0
|
86 },
|
gyorgy@0
|
87 timeCodeToSeconds: function(timecode){
|
gyorgy@0
|
88 var tab = timecode.split(':');
|
gyorgy@0
|
89 return tab[0]*60*60 + tab[1]*60 + parseFloat(tab[2].replace(',','.'));
|
gyorgy@0
|
90 }
|
gyorgy@0
|
91 };
|
gyorgy@0
|
92
|
gyorgy@0
|
93
|
gyorgy@0
|
94 // Core detector, plugins are added below
|
gyorgy@0
|
95 mejs.PluginDetector = {
|
gyorgy@0
|
96
|
gyorgy@0
|
97 // main public function to test a plug version number PluginDetector.hasPluginVersion('flash',[9,0,125]);
|
gyorgy@0
|
98 hasPluginVersion: function(plugin, v) {
|
gyorgy@0
|
99 var pv = this.plugins[plugin];
|
gyorgy@0
|
100 v[1] = v[1] || 0;
|
gyorgy@0
|
101 v[2] = v[2] || 0;
|
gyorgy@0
|
102 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;
|
gyorgy@0
|
103 },
|
gyorgy@0
|
104
|
gyorgy@0
|
105 // cached values
|
gyorgy@0
|
106 nav: window.navigator,
|
gyorgy@0
|
107 ua: window.navigator.userAgent.toLowerCase(),
|
gyorgy@0
|
108
|
gyorgy@0
|
109 // stored version numbers
|
gyorgy@0
|
110 plugins: [],
|
gyorgy@0
|
111
|
gyorgy@0
|
112 // runs detectPlugin() and stores the version number
|
gyorgy@0
|
113 addPlugin: function(p, pluginName, mimeType, activeX, axDetect) {
|
gyorgy@0
|
114 this.plugins[p] = this.detectPlugin(pluginName, mimeType, activeX, axDetect);
|
gyorgy@0
|
115 },
|
gyorgy@0
|
116
|
gyorgy@0
|
117 // get the version number from the mimetype (all but IE) or ActiveX (IE)
|
gyorgy@0
|
118 detectPlugin: function(pluginName, mimeType, activeX, axDetect) {
|
gyorgy@0
|
119
|
gyorgy@0
|
120 var version = [0,0,0],
|
gyorgy@0
|
121 description,
|
gyorgy@0
|
122 i,
|
gyorgy@0
|
123 ax;
|
gyorgy@0
|
124
|
gyorgy@0
|
125 // Firefox, Webkit, Opera
|
gyorgy@0
|
126 if (typeof(this.nav.plugins) != 'undefined' && typeof this.nav.plugins[pluginName] == 'object') {
|
gyorgy@0
|
127 description = this.nav.plugins[pluginName].description;
|
gyorgy@0
|
128 if (description && !(typeof this.nav.mimeTypes != 'undefined' && this.nav.mimeTypes[mimeType] && !this.nav.mimeTypes[mimeType].enabledPlugin)) {
|
gyorgy@0
|
129 version = description.replace(pluginName, '').replace(/^\s+/,'').replace(/\sr/gi,'.').split('.');
|
gyorgy@0
|
130 for (i=0; i<version.length; i++) {
|
gyorgy@0
|
131 version[i] = parseInt(version[i].match(/\d+/), 10);
|
gyorgy@0
|
132 }
|
gyorgy@0
|
133 }
|
gyorgy@0
|
134 // Internet Explorer / ActiveX
|
gyorgy@0
|
135 } else if (typeof(window.ActiveXObject) != 'undefined') {
|
gyorgy@0
|
136 try {
|
gyorgy@0
|
137 ax = new ActiveXObject(activeX);
|
gyorgy@0
|
138 if (ax) {
|
gyorgy@0
|
139 version = axDetect(ax);
|
gyorgy@0
|
140 }
|
gyorgy@0
|
141 }
|
gyorgy@0
|
142 catch (e) { }
|
gyorgy@0
|
143 }
|
gyorgy@0
|
144 return version;
|
gyorgy@0
|
145 }
|
gyorgy@0
|
146 };
|
gyorgy@0
|
147
|
gyorgy@0
|
148 // Add Flash detection
|
gyorgy@0
|
149 mejs.PluginDetector.addPlugin('flash','Shockwave Flash','application/x-shockwave-flash','ShockwaveFlash.ShockwaveFlash', function(ax) {
|
gyorgy@0
|
150 // adapted from SWFObject
|
gyorgy@0
|
151 var version = [],
|
gyorgy@0
|
152 d = ax.GetVariable("$version");
|
gyorgy@0
|
153 if (d) {
|
gyorgy@0
|
154 d = d.split(" ")[1].split(",");
|
gyorgy@0
|
155 version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
|
gyorgy@0
|
156 }
|
gyorgy@0
|
157 return version;
|
gyorgy@0
|
158 });
|
gyorgy@0
|
159
|
gyorgy@0
|
160 // Add Silverlight detection
|
gyorgy@0
|
161 mejs.PluginDetector.addPlugin('silverlight','Silverlight Plug-In','application/x-silverlight-2','AgControl.AgControl', function (ax) {
|
gyorgy@0
|
162 // Silverlight cannot report its version number to IE
|
gyorgy@0
|
163 // but it does have a isVersionSupported function, so we have to loop through it to get a version number.
|
gyorgy@0
|
164 // adapted from http://www.silverlightversion.com/
|
gyorgy@0
|
165 var v = [0,0,0,0],
|
gyorgy@0
|
166 loopMatch = function(ax, v, i, n) {
|
gyorgy@0
|
167 while(ax.isVersionSupported(v[0]+ "."+ v[1] + "." + v[2] + "." + v[3])){
|
gyorgy@0
|
168 v[i]+=n;
|
gyorgy@0
|
169 }
|
gyorgy@0
|
170 v[i] -= n;
|
gyorgy@0
|
171 };
|
gyorgy@0
|
172 loopMatch(ax, v, 0, 1);
|
gyorgy@0
|
173 loopMatch(ax, v, 1, 1);
|
gyorgy@0
|
174 loopMatch(ax, v, 2, 10000); // the third place in the version number is usually 5 digits (4.0.xxxxx)
|
gyorgy@0
|
175 loopMatch(ax, v, 2, 1000);
|
gyorgy@0
|
176 loopMatch(ax, v, 2, 100);
|
gyorgy@0
|
177 loopMatch(ax, v, 2, 10);
|
gyorgy@0
|
178 loopMatch(ax, v, 2, 1);
|
gyorgy@0
|
179 loopMatch(ax, v, 3, 1);
|
gyorgy@0
|
180
|
gyorgy@0
|
181 return v;
|
gyorgy@0
|
182 });
|
gyorgy@0
|
183 // add adobe acrobat
|
gyorgy@0
|
184 /*
|
gyorgy@0
|
185 PluginDetector.addPlugin('acrobat','Adobe Acrobat','application/pdf','AcroPDF.PDF', function (ax) {
|
gyorgy@0
|
186 var version = [],
|
gyorgy@0
|
187 d = ax.GetVersions().split(',')[0].split('=')[1].split('.');
|
gyorgy@0
|
188
|
gyorgy@0
|
189 if (d) {
|
gyorgy@0
|
190 version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
|
gyorgy@0
|
191 }
|
gyorgy@0
|
192 return version;
|
gyorgy@0
|
193 });
|
gyorgy@0
|
194 */
|
gyorgy@0
|
195 // necessary detection (fixes for <IE9)
|
gyorgy@0
|
196 mejs.MediaFeatures = {
|
gyorgy@0
|
197 init: function() {
|
gyorgy@0
|
198 var
|
gyorgy@0
|
199 nav = mejs.PluginDetector.nav,
|
gyorgy@0
|
200 ua = mejs.PluginDetector.ua.toLowerCase(),
|
gyorgy@0
|
201 i,
|
gyorgy@0
|
202 v,
|
gyorgy@0
|
203 html5Elements = ['source','track','audio','video'];
|
gyorgy@0
|
204
|
gyorgy@0
|
205 // detect browsers (only the ones that have some kind of quirk we need to work around)
|
gyorgy@0
|
206 this.isiPad = (ua.match(/ipad/i) !== null);
|
gyorgy@0
|
207 this.isiPhone = (ua.match(/iphone/i) !== null);
|
gyorgy@0
|
208 this.isAndroid = (ua.match(/android/i) !== null);
|
gyorgy@0
|
209 this.isBustedAndroid = (ua.match(/android 2\.[12]/) !== null);
|
gyorgy@0
|
210 this.isIE = (nav.appName.toLowerCase().indexOf("microsoft") != -1);
|
gyorgy@0
|
211 this.isChrome = (ua.match(/chrome/gi) !== null);
|
gyorgy@0
|
212 this.isFirefox = (ua.match(/firefox/gi) !== null);
|
gyorgy@0
|
213
|
gyorgy@0
|
214 // create HTML5 media elements for IE before 9, get a <video> element for fullscreen detection
|
gyorgy@0
|
215 for (i=0; i<html5Elements.length; i++) {
|
gyorgy@0
|
216 v = document.createElement(html5Elements[i]);
|
gyorgy@0
|
217 }
|
gyorgy@0
|
218
|
gyorgy@0
|
219 // detect native JavaScript fullscreen (Safari only, Chrome fails)
|
gyorgy@0
|
220 this.hasNativeFullScreen = (typeof v.webkitRequestFullScreen !== 'undefined');
|
gyorgy@0
|
221 if (this.isChrome) {
|
gyorgy@0
|
222 this.hasNativeFullScreen = false;
|
gyorgy@0
|
223 }
|
gyorgy@0
|
224 // OS X 10.5 can't do this even if it says it can :(
|
gyorgy@0
|
225 if (this.hasNativeFullScreen && ua.match(/mac os x 10_5/i)) {
|
gyorgy@0
|
226 this.hasNativeFullScreen = false;
|
gyorgy@0
|
227 }
|
gyorgy@0
|
228 }
|
gyorgy@0
|
229 };
|
gyorgy@0
|
230 mejs.MediaFeatures.init();
|
gyorgy@0
|
231
|
gyorgy@0
|
232
|
gyorgy@0
|
233 /*
|
gyorgy@0
|
234 extension methods to <video> or <audio> object to bring it into parity with PluginMediaElement (see below)
|
gyorgy@0
|
235 */
|
gyorgy@0
|
236 mejs.HtmlMediaElement = {
|
gyorgy@0
|
237 pluginType: 'native',
|
gyorgy@0
|
238 isFullScreen: false,
|
gyorgy@0
|
239
|
gyorgy@0
|
240 setCurrentTime: function (time) {
|
gyorgy@0
|
241 this.currentTime = time;
|
gyorgy@0
|
242 },
|
gyorgy@0
|
243
|
gyorgy@0
|
244 setMuted: function (muted) {
|
gyorgy@0
|
245 this.muted = muted;
|
gyorgy@0
|
246 },
|
gyorgy@0
|
247
|
gyorgy@0
|
248 setVolume: function (volume) {
|
gyorgy@0
|
249 this.volume = volume;
|
gyorgy@0
|
250 },
|
gyorgy@0
|
251
|
gyorgy@0
|
252 // for parity with the plugin versions
|
gyorgy@0
|
253 stop: function () {
|
gyorgy@0
|
254 this.pause();
|
gyorgy@0
|
255 },
|
gyorgy@0
|
256
|
gyorgy@0
|
257 // This can be a url string
|
gyorgy@0
|
258 // or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
|
gyorgy@0
|
259 setSrc: function (url) {
|
gyorgy@0
|
260 if (typeof url == 'string') {
|
gyorgy@0
|
261 this.src = url;
|
gyorgy@0
|
262 } else {
|
gyorgy@0
|
263 var i, media;
|
gyorgy@0
|
264
|
gyorgy@0
|
265 for (i=0; i<url.length; i++) {
|
gyorgy@0
|
266 media = url[i];
|
gyorgy@0
|
267 if (this.canPlayType(media.type)) {
|
gyorgy@0
|
268 this.src = media.src;
|
gyorgy@0
|
269 }
|
gyorgy@0
|
270 }
|
gyorgy@0
|
271 }
|
gyorgy@0
|
272 },
|
gyorgy@0
|
273
|
gyorgy@0
|
274 setVideoSize: function (width, height) {
|
gyorgy@0
|
275 this.width = width;
|
gyorgy@0
|
276 this.height = height;
|
gyorgy@0
|
277 }
|
gyorgy@0
|
278 };
|
gyorgy@0
|
279
|
gyorgy@0
|
280 /*
|
gyorgy@0
|
281 Mimics the <video/audio> element by calling Flash's External Interface or Silverlights [ScriptableMember]
|
gyorgy@0
|
282 */
|
gyorgy@0
|
283 mejs.PluginMediaElement = function (pluginid, pluginType, mediaUrl) {
|
gyorgy@0
|
284 this.id = pluginid;
|
gyorgy@0
|
285 this.pluginType = pluginType;
|
gyorgy@0
|
286 this.src = mediaUrl;
|
gyorgy@0
|
287 this.events = {};
|
gyorgy@0
|
288 };
|
gyorgy@0
|
289
|
gyorgy@0
|
290 // JavaScript values and ExternalInterface methods that match HTML5 video properties methods
|
gyorgy@0
|
291 // http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/fl/video/FLVPlayback.html
|
gyorgy@0
|
292 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
|
gyorgy@0
|
293 mejs.PluginMediaElement.prototype = {
|
gyorgy@0
|
294
|
gyorgy@0
|
295 // special
|
gyorgy@0
|
296 pluginElement: null,
|
gyorgy@0
|
297 pluginType: '',
|
gyorgy@0
|
298 isFullScreen: false,
|
gyorgy@0
|
299
|
gyorgy@0
|
300 // not implemented :(
|
gyorgy@0
|
301 playbackRate: -1,
|
gyorgy@0
|
302 defaultPlaybackRate: -1,
|
gyorgy@0
|
303 seekable: [],
|
gyorgy@0
|
304 played: [],
|
gyorgy@0
|
305
|
gyorgy@0
|
306 // HTML5 read-only properties
|
gyorgy@0
|
307 paused: true,
|
gyorgy@0
|
308 ended: false,
|
gyorgy@0
|
309 seeking: false,
|
gyorgy@0
|
310 duration: 0,
|
gyorgy@0
|
311 error: null,
|
gyorgy@0
|
312
|
gyorgy@0
|
313 // HTML5 get/set properties, but only set (updated by event handlers)
|
gyorgy@0
|
314 muted: false,
|
gyorgy@0
|
315 volume: 1,
|
gyorgy@0
|
316 currentTime: 0,
|
gyorgy@0
|
317
|
gyorgy@0
|
318 // HTML5 methods
|
gyorgy@0
|
319 play: function () {
|
gyorgy@0
|
320 if (this.pluginApi != null) {
|
gyorgy@0
|
321 this.pluginApi.playMedia();
|
gyorgy@0
|
322 this.paused = false;
|
gyorgy@0
|
323 }
|
gyorgy@0
|
324 },
|
gyorgy@0
|
325 load: function () {
|
gyorgy@0
|
326 if (this.pluginApi != null) {
|
gyorgy@0
|
327 this.pluginApi.loadMedia();
|
gyorgy@0
|
328 this.paused = false;
|
gyorgy@0
|
329 }
|
gyorgy@0
|
330 },
|
gyorgy@0
|
331 pause: function () {
|
gyorgy@0
|
332 if (this.pluginApi != null) {
|
gyorgy@0
|
333 this.pluginApi.pauseMedia();
|
gyorgy@0
|
334 this.paused = true;
|
gyorgy@0
|
335 }
|
gyorgy@0
|
336 },
|
gyorgy@0
|
337 stop: function () {
|
gyorgy@0
|
338 if (this.pluginApi != null) {
|
gyorgy@0
|
339 this.pluginApi.stopMedia();
|
gyorgy@0
|
340 this.paused = true;
|
gyorgy@0
|
341 }
|
gyorgy@0
|
342 },
|
gyorgy@0
|
343 canPlayType: function(type) {
|
gyorgy@0
|
344 var i,
|
gyorgy@0
|
345 j,
|
gyorgy@0
|
346 pluginInfo,
|
gyorgy@0
|
347 pluginVersions = mejs.plugins[this.pluginType];
|
gyorgy@0
|
348
|
gyorgy@0
|
349 for (i=0; i<pluginVersions.length; i++) {
|
gyorgy@0
|
350 pluginInfo = pluginVersions[i];
|
gyorgy@0
|
351
|
gyorgy@0
|
352 // test if user has the correct plugin version
|
gyorgy@0
|
353 if (mejs.PluginDetector.hasPluginVersion(this.pluginType, pluginInfo.version)) {
|
gyorgy@0
|
354
|
gyorgy@0
|
355 // test for plugin playback types
|
gyorgy@0
|
356 for (j=0; j<pluginInfo.types.length; j++) {
|
gyorgy@0
|
357 // find plugin that can play the type
|
gyorgy@0
|
358 if (type == pluginInfo.types[j]) {
|
gyorgy@0
|
359 return true;
|
gyorgy@0
|
360 }
|
gyorgy@0
|
361 }
|
gyorgy@0
|
362 }
|
gyorgy@0
|
363 }
|
gyorgy@0
|
364
|
gyorgy@0
|
365 return false;
|
gyorgy@0
|
366 },
|
gyorgy@0
|
367
|
gyorgy@0
|
368 // custom methods since not all JavaScript implementations support get/set
|
gyorgy@0
|
369
|
gyorgy@0
|
370 // This can be a url string
|
gyorgy@0
|
371 // or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
|
gyorgy@0
|
372 setSrc: function (url) {
|
gyorgy@0
|
373 if (typeof url == 'string') {
|
gyorgy@0
|
374 this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(url));
|
gyorgy@0
|
375 this.src = mejs.Utility.absolutizeUrl(url);
|
gyorgy@0
|
376 } else {
|
gyorgy@0
|
377 var i, media;
|
gyorgy@0
|
378
|
gyorgy@0
|
379 for (i=0; i<url.length; i++) {
|
gyorgy@0
|
380 media = url[i];
|
gyorgy@0
|
381 if (this.canPlayType(media.type)) {
|
gyorgy@0
|
382 this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(media.src));
|
gyorgy@0
|
383 this.src = mejs.Utility.absolutizeUrl(url);
|
gyorgy@0
|
384 }
|
gyorgy@0
|
385 }
|
gyorgy@0
|
386 }
|
gyorgy@0
|
387
|
gyorgy@0
|
388 },
|
gyorgy@0
|
389 setCurrentTime: function (time) {
|
gyorgy@0
|
390 if (this.pluginApi != null) {
|
gyorgy@0
|
391 this.pluginApi.setCurrentTime(time);
|
gyorgy@0
|
392 this.currentTime = time;
|
gyorgy@0
|
393 }
|
gyorgy@0
|
394 },
|
gyorgy@0
|
395 setVolume: function (volume) {
|
gyorgy@0
|
396 if (this.pluginApi != null) {
|
gyorgy@0
|
397 this.pluginApi.setVolume(volume);
|
gyorgy@0
|
398 this.volume = volume;
|
gyorgy@0
|
399 }
|
gyorgy@0
|
400 },
|
gyorgy@0
|
401 setMuted: function (muted) {
|
gyorgy@0
|
402 if (this.pluginApi != null) {
|
gyorgy@0
|
403 this.pluginApi.setMuted(muted);
|
gyorgy@0
|
404 this.muted = muted;
|
gyorgy@0
|
405 }
|
gyorgy@0
|
406 },
|
gyorgy@0
|
407
|
gyorgy@0
|
408 // additional non-HTML5 methods
|
gyorgy@0
|
409 setVideoSize: function (width, height) {
|
gyorgy@0
|
410 if ( this.pluginElement.style) {
|
gyorgy@0
|
411 this.pluginElement.style.width = width + 'px';
|
gyorgy@0
|
412 this.pluginElement.style.height = height + 'px';
|
gyorgy@0
|
413 }
|
gyorgy@0
|
414 if (this.pluginApi != null) {
|
gyorgy@0
|
415 this.pluginApi.setVideoSize(width, height);
|
gyorgy@0
|
416 }
|
gyorgy@0
|
417 },
|
gyorgy@0
|
418
|
gyorgy@0
|
419 setFullscreen: function (fullscreen) {
|
gyorgy@0
|
420 if (this.pluginApi != null) {
|
gyorgy@0
|
421 this.pluginApi.setFullscreen(fullscreen);
|
gyorgy@0
|
422 }
|
gyorgy@0
|
423 },
|
gyorgy@0
|
424
|
gyorgy@0
|
425 // start: fake events
|
gyorgy@0
|
426 addEventListener: function (eventName, callback, bubble) {
|
gyorgy@0
|
427 this.events[eventName] = this.events[eventName] || [];
|
gyorgy@0
|
428 this.events[eventName].push(callback);
|
gyorgy@0
|
429 },
|
gyorgy@0
|
430 removeEventListener: function (eventName, callback) {
|
gyorgy@0
|
431 if (!eventName) { this.events = {}; return true; }
|
gyorgy@0
|
432 var callbacks = this.events[eventName];
|
gyorgy@0
|
433 if (!callbacks) return true;
|
gyorgy@0
|
434 if (!callback) { this.events[eventName] = []; return true; }
|
gyorgy@0
|
435 for (i = 0; i < callbacks.length; i++) {
|
gyorgy@0
|
436 if (callbacks[i] === callback) {
|
gyorgy@0
|
437 this.events[eventName].splice(i, 1);
|
gyorgy@0
|
438 return true;
|
gyorgy@0
|
439 }
|
gyorgy@0
|
440 }
|
gyorgy@0
|
441 return false;
|
gyorgy@0
|
442 },
|
gyorgy@0
|
443 dispatchEvent: function (eventName) {
|
gyorgy@0
|
444 var i,
|
gyorgy@0
|
445 args,
|
gyorgy@0
|
446 callbacks = this.events[eventName];
|
gyorgy@0
|
447
|
gyorgy@0
|
448 if (callbacks) {
|
gyorgy@0
|
449 args = Array.prototype.slice.call(arguments, 1);
|
gyorgy@0
|
450 for (i = 0; i < callbacks.length; i++) {
|
gyorgy@0
|
451 callbacks[i].apply(null, args);
|
gyorgy@0
|
452 }
|
gyorgy@0
|
453 }
|
gyorgy@0
|
454 }
|
gyorgy@0
|
455 // end: fake events
|
gyorgy@0
|
456 };
|
gyorgy@0
|
457
|
gyorgy@0
|
458
|
gyorgy@0
|
459 // Handles calls from Flash/Silverlight and reports them as native <video/audio> events and properties
|
gyorgy@0
|
460 mejs.MediaPluginBridge = {
|
gyorgy@0
|
461
|
gyorgy@0
|
462 pluginMediaElements:{},
|
gyorgy@0
|
463 htmlMediaElements:{},
|
gyorgy@0
|
464
|
gyorgy@0
|
465 registerPluginElement: function (id, pluginMediaElement, htmlMediaElement) {
|
gyorgy@0
|
466 this.pluginMediaElements[id] = pluginMediaElement;
|
gyorgy@0
|
467 this.htmlMediaElements[id] = htmlMediaElement;
|
gyorgy@0
|
468 },
|
gyorgy@0
|
469
|
gyorgy@0
|
470 // when Flash/Silverlight is ready, it calls out to this method
|
gyorgy@0
|
471 initPlugin: function (id) {
|
gyorgy@0
|
472
|
gyorgy@0
|
473 var pluginMediaElement = this.pluginMediaElements[id],
|
gyorgy@0
|
474 htmlMediaElement = this.htmlMediaElements[id];
|
gyorgy@0
|
475
|
gyorgy@0
|
476 // find the javascript bridge
|
gyorgy@0
|
477 switch (pluginMediaElement.pluginType) {
|
gyorgy@0
|
478 case "flash":
|
gyorgy@0
|
479 pluginMediaElement.pluginElement = pluginMediaElement.pluginApi = document.getElementById(id);
|
gyorgy@0
|
480 break;
|
gyorgy@0
|
481 case "silverlight":
|
gyorgy@0
|
482 pluginMediaElement.pluginElement = document.getElementById(pluginMediaElement.id);
|
gyorgy@0
|
483 pluginMediaElement.pluginApi = pluginMediaElement.pluginElement.Content.MediaElementJS;
|
gyorgy@0
|
484 break;
|
gyorgy@0
|
485 }
|
gyorgy@0
|
486
|
gyorgy@0
|
487 if (pluginMediaElement.pluginApi != null && pluginMediaElement.success) {
|
gyorgy@0
|
488 pluginMediaElement.success(pluginMediaElement, htmlMediaElement);
|
gyorgy@0
|
489 }
|
gyorgy@0
|
490 },
|
gyorgy@0
|
491
|
gyorgy@0
|
492 // receives events from Flash/Silverlight and sends them out as HTML5 media events
|
gyorgy@0
|
493 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
|
gyorgy@0
|
494 fireEvent: function (id, eventName, values) {
|
gyorgy@0
|
495
|
gyorgy@0
|
496 var
|
gyorgy@0
|
497 e,
|
gyorgy@0
|
498 i,
|
gyorgy@0
|
499 bufferedTime,
|
gyorgy@0
|
500 pluginMediaElement = this.pluginMediaElements[id];
|
gyorgy@0
|
501
|
gyorgy@0
|
502 pluginMediaElement.ended = false;
|
gyorgy@0
|
503 pluginMediaElement.paused = true;
|
gyorgy@0
|
504
|
gyorgy@0
|
505 // fake event object to mimic real HTML media event.
|
gyorgy@0
|
506 e = {
|
gyorgy@0
|
507 type: eventName,
|
gyorgy@0
|
508 target: pluginMediaElement
|
gyorgy@0
|
509 };
|
gyorgy@0
|
510
|
gyorgy@0
|
511 // attach all values to element and event object
|
gyorgy@0
|
512 for (i in values) {
|
gyorgy@0
|
513 pluginMediaElement[i] = values[i];
|
gyorgy@0
|
514 e[i] = values[i];
|
gyorgy@0
|
515 }
|
gyorgy@0
|
516
|
gyorgy@0
|
517 // fake the newer W3C buffered TimeRange (loaded and total have been removed)
|
gyorgy@0
|
518 bufferedTime = values.bufferedTime || 0;
|
gyorgy@0
|
519
|
gyorgy@0
|
520 e.target.buffered = e.buffered = {
|
gyorgy@0
|
521 start: function(index) {
|
gyorgy@0
|
522 return 0;
|
gyorgy@0
|
523 },
|
gyorgy@0
|
524 end: function (index) {
|
gyorgy@0
|
525 return bufferedTime;
|
gyorgy@0
|
526 },
|
gyorgy@0
|
527 length: 1
|
gyorgy@0
|
528 };
|
gyorgy@0
|
529
|
gyorgy@0
|
530 pluginMediaElement.dispatchEvent(e.type, e);
|
gyorgy@0
|
531 }
|
gyorgy@0
|
532 };
|
gyorgy@0
|
533
|
gyorgy@0
|
534 /*
|
gyorgy@0
|
535 Default options
|
gyorgy@0
|
536 */
|
gyorgy@0
|
537 mejs.MediaElementDefaults = {
|
gyorgy@0
|
538 // allows testing on HTML5, flash, silverlight
|
gyorgy@0
|
539 // auto: attempts to detect what the browser can do
|
gyorgy@0
|
540 // native: forces HTML5 playback
|
gyorgy@0
|
541 // shim: disallows HTML5, will attempt either Flash or Silverlight
|
gyorgy@0
|
542 // none: forces fallback view
|
gyorgy@0
|
543 mode: 'auto',
|
gyorgy@0
|
544 // remove or reorder to change plugin priority and availability
|
gyorgy@0
|
545 plugins: ['flash','silverlight'],
|
gyorgy@0
|
546 // shows debug errors on screen
|
gyorgy@0
|
547 enablePluginDebug: false,
|
gyorgy@0
|
548 // overrides the type specified, useful for dynamic instantiation
|
gyorgy@0
|
549 type: '',
|
gyorgy@0
|
550 // path to Flash and Silverlight plugins
|
gyorgy@0
|
551 pluginPath: mejs.Utility.getScriptPath(['mediaelement.js','mediaelement.min.js','mediaelement-and-player.js','mediaelement-and-player.min.js']),
|
gyorgy@0
|
552 // name of flash file
|
gyorgy@0
|
553 flashName: 'flashmediaelement.swf',
|
gyorgy@0
|
554 // turns on the smoothing filter in Flash
|
gyorgy@0
|
555 enablePluginSmoothing: false,
|
gyorgy@0
|
556 // name of silverlight file
|
gyorgy@0
|
557 silverlightName: 'silverlightmediaelement.xap',
|
gyorgy@0
|
558 // default if the <video width> is not specified
|
gyorgy@0
|
559 defaultVideoWidth: 480,
|
gyorgy@0
|
560 // default if the <video height> is not specified
|
gyorgy@0
|
561 defaultVideoHeight: 270,
|
gyorgy@0
|
562 // overrides <video width>
|
gyorgy@0
|
563 pluginWidth: -1,
|
gyorgy@0
|
564 // overrides <video height>
|
gyorgy@0
|
565 pluginHeight: -1,
|
gyorgy@0
|
566 // rate in milliseconds for Flash and Silverlight to fire the timeupdate event
|
gyorgy@0
|
567 // larger number is less accurate, but less strain on plugin->JavaScript bridge
|
gyorgy@0
|
568 timerRate: 250,
|
gyorgy@0
|
569 success: function () { },
|
gyorgy@0
|
570 error: function () { }
|
gyorgy@0
|
571 };
|
gyorgy@0
|
572
|
gyorgy@0
|
573 /*
|
gyorgy@0
|
574 Determines if a browser supports the <video> or <audio> element
|
gyorgy@0
|
575 and returns either the native element or a Flash/Silverlight version that
|
gyorgy@0
|
576 mimics HTML5 MediaElement
|
gyorgy@0
|
577 */
|
gyorgy@0
|
578 mejs.MediaElement = function (el, o) {
|
gyorgy@0
|
579 return mejs.HtmlMediaElementShim.create(el,o);
|
gyorgy@0
|
580 };
|
gyorgy@0
|
581
|
gyorgy@0
|
582 mejs.HtmlMediaElementShim = {
|
gyorgy@0
|
583
|
gyorgy@0
|
584 create: function(el, o) {
|
gyorgy@0
|
585 var
|
gyorgy@0
|
586 options = mejs.MediaElementDefaults,
|
gyorgy@0
|
587 htmlMediaElement = (typeof(el) == 'string') ? document.getElementById(el) : el,
|
gyorgy@0
|
588 isVideo = (htmlMediaElement.tagName.toLowerCase() == 'video'),
|
gyorgy@0
|
589 supportsMediaTag = (typeof(htmlMediaElement.canPlayType) != 'undefined'),
|
gyorgy@0
|
590 playback = {method:'', url:''},
|
gyorgy@0
|
591 poster = htmlMediaElement.getAttribute('poster'),
|
gyorgy@0
|
592 autoplay = htmlMediaElement.getAttribute('autoplay'),
|
gyorgy@0
|
593 preload = htmlMediaElement.getAttribute('preload'),
|
gyorgy@0
|
594 controls = htmlMediaElement.getAttribute('controls'),
|
gyorgy@0
|
595 prop;
|
gyorgy@0
|
596
|
gyorgy@0
|
597 // extend options
|
gyorgy@0
|
598 for (prop in o) {
|
gyorgy@0
|
599 options[prop] = o[prop];
|
gyorgy@0
|
600 }
|
gyorgy@0
|
601
|
gyorgy@0
|
602 // check for real poster
|
gyorgy@0
|
603 poster = (typeof poster == 'undefined' || poster === null) ? '' : poster;
|
gyorgy@0
|
604 preload = (typeof preload == 'undefined' || preload === null || preload === 'false') ? 'none' : preload;
|
gyorgy@0
|
605 autoplay = !(typeof autoplay == 'undefined' || autoplay === null || autoplay === 'false');
|
gyorgy@0
|
606 controls = !(typeof controls == 'undefined' || controls === null || controls === 'false');
|
gyorgy@0
|
607
|
gyorgy@0
|
608 // test for HTML5 and plugin capabilities
|
gyorgy@0
|
609 playback = this.determinePlayback(htmlMediaElement, options, isVideo, supportsMediaTag);
|
gyorgy@0
|
610
|
gyorgy@0
|
611 if (playback.method == 'native') {
|
gyorgy@0
|
612 // second fix for android
|
gyorgy@0
|
613 if (mejs.MediaFeatures.isBustedAndroid) {
|
gyorgy@0
|
614 htmlMediaElement.src = playback.url;
|
gyorgy@0
|
615 htmlMediaElement.addEventListener('click', function() {
|
gyorgy@0
|
616 htmlMediaElement.play();
|
gyorgy@0
|
617 }, true);
|
gyorgy@0
|
618 }
|
gyorgy@0
|
619
|
gyorgy@0
|
620 // add methods to native HTMLMediaElement
|
gyorgy@0
|
621 return this.updateNative( htmlMediaElement, options, autoplay, preload, playback);
|
gyorgy@0
|
622 } else if (playback.method !== '') {
|
gyorgy@0
|
623 // create plugin to mimic HTMLMediaElement
|
gyorgy@0
|
624 return this.createPlugin( htmlMediaElement, options, isVideo, playback.method, (playback.url !== null) ? mejs.Utility.absolutizeUrl(playback.url) : '', poster, autoplay, preload, controls);
|
gyorgy@0
|
625 } else {
|
gyorgy@0
|
626 // boo, no HTML5, no Flash, no Silverlight.
|
gyorgy@0
|
627 this.createErrorMessage( htmlMediaElement, options, (playback.url !== null) ? mejs.Utility.absolutizeUrl(playback.url) : '', poster );
|
gyorgy@0
|
628 }
|
gyorgy@0
|
629 },
|
gyorgy@0
|
630
|
gyorgy@0
|
631 determinePlayback: function(htmlMediaElement, options, isVideo, supportsMediaTag) {
|
gyorgy@0
|
632 var
|
gyorgy@0
|
633 mediaFiles = [],
|
gyorgy@0
|
634 i,
|
gyorgy@0
|
635 j,
|
gyorgy@0
|
636 k,
|
gyorgy@0
|
637 l,
|
gyorgy@0
|
638 n,
|
gyorgy@0
|
639 type,
|
gyorgy@0
|
640 result = { method: '', url: ''},
|
gyorgy@0
|
641 src = htmlMediaElement.getAttribute('src'),
|
gyorgy@0
|
642 pluginName,
|
gyorgy@0
|
643 pluginVersions,
|
gyorgy@0
|
644 pluginInfo;
|
gyorgy@0
|
645
|
gyorgy@0
|
646 // clean up src attr
|
gyorgy@0
|
647 if (src == 'undefined' || src == '' || src === null)
|
gyorgy@0
|
648 src = null;
|
gyorgy@0
|
649
|
gyorgy@0
|
650 // STEP 1: Get URL and type from <video src> or <source src>
|
gyorgy@0
|
651
|
gyorgy@0
|
652 // supplied type overrides all HTML
|
gyorgy@0
|
653 if (typeof (options.type) != 'undefined' && options.type !== '') {
|
gyorgy@0
|
654 mediaFiles.push({type:options.type, url:src});
|
gyorgy@0
|
655
|
gyorgy@0
|
656 // test for src attribute first
|
gyorgy@0
|
657 } else if (src !== null) {
|
gyorgy@0
|
658 type = this.checkType(src, htmlMediaElement.getAttribute('type'), isVideo);
|
gyorgy@0
|
659 mediaFiles.push({type:type, url:src});
|
gyorgy@0
|
660
|
gyorgy@0
|
661 // then test for <source> elements
|
gyorgy@0
|
662 } else {
|
gyorgy@0
|
663 // test <source> types to see if they are usable
|
gyorgy@0
|
664 for (i = 0; i < htmlMediaElement.childNodes.length; i++) {
|
gyorgy@0
|
665 n = htmlMediaElement.childNodes[i];
|
gyorgy@0
|
666 if (n.nodeType == 1 && n.tagName.toLowerCase() == 'source') {
|
gyorgy@0
|
667 src = n.getAttribute('src');
|
gyorgy@0
|
668 type = this.checkType(src, n.getAttribute('type'), isVideo);
|
gyorgy@0
|
669 mediaFiles.push({type:type, url:src});
|
gyorgy@0
|
670 }
|
gyorgy@0
|
671 }
|
gyorgy@0
|
672 }
|
gyorgy@0
|
673
|
gyorgy@0
|
674 // STEP 2: Test for playback method
|
gyorgy@0
|
675
|
gyorgy@0
|
676 // special case for Android which sadly doesn't implement the canPlayType function (always returns '')
|
gyorgy@0
|
677 if (mejs.MediaFeatures.isBustedAndroid) {
|
gyorgy@0
|
678 htmlMediaElement.canPlayType = function(type) {
|
gyorgy@0
|
679 return (type.match(/video\/(mp4|m4v)/gi) !== null) ? 'maybe' : '';
|
gyorgy@0
|
680 };
|
gyorgy@0
|
681 }
|
gyorgy@0
|
682
|
gyorgy@0
|
683
|
gyorgy@0
|
684 // test for native playback first
|
gyorgy@0
|
685 if (supportsMediaTag && (options.mode === 'auto' || options.mode === 'native')) {
|
gyorgy@0
|
686 for (i=0; i<mediaFiles.length; i++) {
|
gyorgy@0
|
687 // normal check
|
gyorgy@0
|
688 if (htmlMediaElement.canPlayType(mediaFiles[i].type).replace(/no/, '') !== ''
|
gyorgy@0
|
689 // special case for Mac/Safari 5.0.3 which answers '' to canPlayType('audio/mp3') but 'maybe' to canPlayType('audio/mpeg')
|
gyorgy@0
|
690 || htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/mp3/,'mpeg')).replace(/no/, '') !== '') {
|
gyorgy@0
|
691 result.method = 'native';
|
gyorgy@0
|
692 result.url = mediaFiles[i].url;
|
gyorgy@0
|
693 return result;
|
gyorgy@0
|
694 }
|
gyorgy@0
|
695 }
|
gyorgy@0
|
696 }
|
gyorgy@0
|
697
|
gyorgy@0
|
698 // if native playback didn't work, then test plugins
|
gyorgy@0
|
699 if (options.mode === 'auto' || options.mode === 'shim') {
|
gyorgy@0
|
700 for (i=0; i<mediaFiles.length; i++) {
|
gyorgy@0
|
701 type = mediaFiles[i].type;
|
gyorgy@0
|
702
|
gyorgy@0
|
703 // test all plugins in order of preference [silverlight, flash]
|
gyorgy@0
|
704 for (j=0; j<options.plugins.length; j++) {
|
gyorgy@0
|
705
|
gyorgy@0
|
706 pluginName = options.plugins[j];
|
gyorgy@0
|
707
|
gyorgy@0
|
708 // test version of plugin (for future features)
|
gyorgy@0
|
709 pluginVersions = mejs.plugins[pluginName];
|
gyorgy@0
|
710 for (k=0; k<pluginVersions.length; k++) {
|
gyorgy@0
|
711 pluginInfo = pluginVersions[k];
|
gyorgy@0
|
712
|
gyorgy@0
|
713 // test if user has the correct plugin version
|
gyorgy@0
|
714 if (mejs.PluginDetector.hasPluginVersion(pluginName, pluginInfo.version)) {
|
gyorgy@0
|
715
|
gyorgy@0
|
716 // test for plugin playback types
|
gyorgy@0
|
717 for (l=0; l<pluginInfo.types.length; l++) {
|
gyorgy@0
|
718 // find plugin that can play the type
|
gyorgy@0
|
719 if (type == pluginInfo.types[l]) {
|
gyorgy@0
|
720 result.method = pluginName;
|
gyorgy@0
|
721 result.url = mediaFiles[i].url;
|
gyorgy@0
|
722 return result;
|
gyorgy@0
|
723 }
|
gyorgy@0
|
724 }
|
gyorgy@0
|
725 }
|
gyorgy@0
|
726 }
|
gyorgy@0
|
727 }
|
gyorgy@0
|
728 }
|
gyorgy@0
|
729 }
|
gyorgy@0
|
730
|
gyorgy@0
|
731 // what if there's nothing to play? just grab the first available
|
gyorgy@0
|
732 if (result.method === '') {
|
gyorgy@0
|
733 result.url = mediaFiles[0].url;
|
gyorgy@0
|
734 }
|
gyorgy@0
|
735
|
gyorgy@0
|
736 return result;
|
gyorgy@0
|
737 },
|
gyorgy@0
|
738
|
gyorgy@0
|
739 checkType: function(url, type, isVideo) {
|
gyorgy@0
|
740 var ext;
|
gyorgy@0
|
741
|
gyorgy@0
|
742 // if no type is supplied, fake it with the extension
|
gyorgy@0
|
743 if (url && !type) {
|
gyorgy@0
|
744 ext = url.substring(url.lastIndexOf('.') + 1);
|
gyorgy@0
|
745 return ((isVideo) ? 'video' : 'audio') + '/' + ext;
|
gyorgy@0
|
746 } else {
|
gyorgy@0
|
747 // only return the mime part of the type in case the attribute contains the codec
|
gyorgy@0
|
748 // see http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#the-source-element
|
gyorgy@0
|
749 // `video/mp4; codecs="avc1.42E01E, mp4a.40.2"` becomes `video/mp4`
|
gyorgy@0
|
750
|
gyorgy@0
|
751 if (type && ~type.indexOf(';')) {
|
gyorgy@0
|
752 return type.substr(0, type.indexOf(';'));
|
gyorgy@0
|
753 } else {
|
gyorgy@0
|
754 return type;
|
gyorgy@0
|
755 }
|
gyorgy@0
|
756 }
|
gyorgy@0
|
757 },
|
gyorgy@0
|
758
|
gyorgy@0
|
759 createErrorMessage: function(htmlMediaElement, options, downloadUrl, poster) {
|
gyorgy@0
|
760 var errorContainer = document.createElement('div');
|
gyorgy@0
|
761 errorContainer.className = 'me-cannotplay';
|
gyorgy@0
|
762
|
gyorgy@0
|
763 try {
|
gyorgy@0
|
764 errorContainer.style.width = htmlMediaElement.width + 'px';
|
gyorgy@0
|
765 errorContainer.style.height = htmlMediaElement.height + 'px';
|
gyorgy@0
|
766 } catch (e) {}
|
gyorgy@0
|
767
|
gyorgy@0
|
768 errorContainer.innerHTML = (poster !== '') ?
|
gyorgy@0
|
769 '<a href="' + downloadUrl + '"><img src="' + poster + '" /></a>' :
|
gyorgy@0
|
770 '<a href="' + downloadUrl + '"><span>Download File</span></a>';
|
gyorgy@0
|
771
|
gyorgy@0
|
772 htmlMediaElement.parentNode.insertBefore(errorContainer, htmlMediaElement);
|
gyorgy@0
|
773 htmlMediaElement.style.display = 'none';
|
gyorgy@0
|
774
|
gyorgy@0
|
775 options.error(htmlMediaElement);
|
gyorgy@0
|
776 },
|
gyorgy@0
|
777
|
gyorgy@0
|
778 createPlugin:function(htmlMediaElement, options, isVideo, pluginType, mediaUrl, poster, autoplay, preload, controls) {
|
gyorgy@0
|
779 var width = 1,
|
gyorgy@0
|
780 height = 1,
|
gyorgy@0
|
781 pluginid = 'me_' + pluginType + '_' + (mejs.meIndex++),
|
gyorgy@0
|
782 pluginMediaElement = new mejs.PluginMediaElement(pluginid, pluginType, mediaUrl),
|
gyorgy@0
|
783 container = document.createElement('div'),
|
gyorgy@0
|
784 specialIEContainer,
|
gyorgy@0
|
785 node,
|
gyorgy@0
|
786 initVars;
|
gyorgy@0
|
787
|
gyorgy@0
|
788 // check for placement inside a <p> tag (sometimes WYSIWYG editors do this)
|
gyorgy@0
|
789 node = htmlMediaElement.parentNode;
|
gyorgy@0
|
790 while (node !== null && node.tagName.toLowerCase() != 'body') {
|
gyorgy@0
|
791 if (node.parentNode.tagName.toLowerCase() == 'p') {
|
gyorgy@0
|
792 node.parentNode.parentNode.insertBefore(node, node.parentNode);
|
gyorgy@0
|
793 break;
|
gyorgy@0
|
794 }
|
gyorgy@0
|
795 node = node.parentNode;
|
gyorgy@0
|
796 }
|
gyorgy@0
|
797
|
gyorgy@0
|
798 if (isVideo) {
|
gyorgy@0
|
799 width = (options.videoWidth > 0) ? options.videoWidth : (htmlMediaElement.getAttribute('width') !== null) ? htmlMediaElement.getAttribute('width') : options.defaultVideoWidth;
|
gyorgy@0
|
800 height = (options.videoHeight > 0) ? options.videoHeight : (htmlMediaElement.getAttribute('height') !== null) ? htmlMediaElement.getAttribute('height') : options.defaultVideoHeight;
|
gyorgy@0
|
801 } else {
|
gyorgy@0
|
802 if (options.enablePluginDebug) {
|
gyorgy@0
|
803 width = 320;
|
gyorgy@0
|
804 height = 240;
|
gyorgy@0
|
805 }
|
gyorgy@0
|
806 }
|
gyorgy@0
|
807
|
gyorgy@0
|
808 // register plugin
|
gyorgy@0
|
809 pluginMediaElement.success = options.success;
|
gyorgy@0
|
810 mejs.MediaPluginBridge.registerPluginElement(pluginid, pluginMediaElement, htmlMediaElement);
|
gyorgy@0
|
811
|
gyorgy@0
|
812 // add container (must be added to DOM before inserting HTML for IE)
|
gyorgy@0
|
813 container.className = 'me-plugin';
|
gyorgy@0
|
814 htmlMediaElement.parentNode.insertBefore(container, htmlMediaElement);
|
gyorgy@0
|
815
|
gyorgy@0
|
816 // flash/silverlight vars
|
gyorgy@0
|
817 initVars = [
|
gyorgy@0
|
818 'id=' + pluginid,
|
gyorgy@0
|
819 'isvideo=' + ((isVideo) ? "true" : "false"),
|
gyorgy@0
|
820 'autoplay=' + ((autoplay) ? "true" : "false"),
|
gyorgy@0
|
821 'preload=' + preload,
|
gyorgy@0
|
822 'width=' + width,
|
gyorgy@0
|
823 'startvolume=' + options.startVolume,
|
gyorgy@0
|
824 'timerrate=' + options.timerRate,
|
gyorgy@0
|
825 'height=' + height];
|
gyorgy@0
|
826
|
gyorgy@0
|
827 if (mediaUrl !== null) {
|
gyorgy@0
|
828 if (pluginType == 'flash') {
|
gyorgy@0
|
829 initVars.push('file=' + mejs.Utility.encodeUrl(mediaUrl));
|
gyorgy@0
|
830 } else {
|
gyorgy@0
|
831 initVars.push('file=' + mediaUrl);
|
gyorgy@0
|
832 }
|
gyorgy@0
|
833 }
|
gyorgy@0
|
834 if (options.enablePluginDebug) {
|
gyorgy@0
|
835 initVars.push('debug=true');
|
gyorgy@0
|
836 }
|
gyorgy@0
|
837 if (options.enablePluginSmoothing) {
|
gyorgy@0
|
838 initVars.push('smoothing=true');
|
gyorgy@0
|
839 }
|
gyorgy@0
|
840 if (controls) {
|
gyorgy@0
|
841 initVars.push('controls=true'); // shows controls in the plugin if desired
|
gyorgy@0
|
842 }
|
gyorgy@0
|
843
|
gyorgy@0
|
844 switch (pluginType) {
|
gyorgy@0
|
845 case 'silverlight':
|
gyorgy@0
|
846 container.innerHTML =
|
gyorgy@0
|
847 '<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="' + pluginid + '" name="' + pluginid + '" width="' + width + '" height="' + height + '">' +
|
gyorgy@0
|
848 '<param name="initParams" value="' + initVars.join(',') + '" />' +
|
gyorgy@0
|
849 '<param name="windowless" value="true" />' +
|
gyorgy@0
|
850 '<param name="background" value="black" />' +
|
gyorgy@0
|
851 '<param name="minRuntimeVersion" value="3.0.0.0" />' +
|
gyorgy@0
|
852 '<param name="autoUpgrade" value="true" />' +
|
gyorgy@0
|
853 '<param name="source" value="' + options.pluginPath + options.silverlightName + '" />' +
|
gyorgy@0
|
854 '</object>';
|
gyorgy@0
|
855 break;
|
gyorgy@0
|
856
|
gyorgy@0
|
857 case 'flash':
|
gyorgy@0
|
858
|
gyorgy@0
|
859 if (mejs.MediaFeatures.isIE) {
|
gyorgy@0
|
860 specialIEContainer = document.createElement('div');
|
gyorgy@0
|
861 container.appendChild(specialIEContainer);
|
gyorgy@0
|
862 specialIEContainer.outerHTML =
|
gyorgy@0
|
863 '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
|
gyorgy@0
|
864 'id="' + pluginid + '" width="' + width + '" height="' + height + '">' +
|
gyorgy@0
|
865 '<param name="movie" value="' + options.pluginPath + options.flashName + '?x=' + (new Date()) + '" />' +
|
gyorgy@0
|
866 '<param name="flashvars" value="' + initVars.join('&') + '" />' +
|
gyorgy@0
|
867 '<param name="quality" value="high" />' +
|
gyorgy@0
|
868 '<param name="bgcolor" value="#000000" />' +
|
gyorgy@0
|
869 '<param name="wmode" value="transparent" />' +
|
gyorgy@0
|
870 '<param name="allowScriptAccess" value="always" />' +
|
gyorgy@0
|
871 '<param name="allowFullScreen" value="true" />' +
|
gyorgy@0
|
872 '</object>';
|
gyorgy@0
|
873
|
gyorgy@0
|
874 } else {
|
gyorgy@0
|
875
|
gyorgy@0
|
876 container.innerHTML =
|
gyorgy@0
|
877 '<embed id="' + pluginid + '" name="' + pluginid + '" ' +
|
gyorgy@0
|
878 'play="true" ' +
|
gyorgy@0
|
879 'loop="false" ' +
|
gyorgy@0
|
880 'quality="high" ' +
|
gyorgy@0
|
881 'bgcolor="#000000" ' +
|
gyorgy@0
|
882 'wmode="transparent" ' +
|
gyorgy@0
|
883 'allowScriptAccess="always" ' +
|
gyorgy@0
|
884 'allowFullScreen="true" ' +
|
gyorgy@0
|
885 'type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" ' +
|
gyorgy@0
|
886 'src="' + options.pluginPath + options.flashName + '" ' +
|
gyorgy@0
|
887 'flashvars="' + initVars.join('&') + '" ' +
|
gyorgy@0
|
888 'width="' + width + '" ' +
|
gyorgy@0
|
889 'height="' + height + '"></embed>';
|
gyorgy@0
|
890 }
|
gyorgy@0
|
891 break;
|
gyorgy@0
|
892 }
|
gyorgy@0
|
893 // hide original element
|
gyorgy@0
|
894 htmlMediaElement.style.display = 'none';
|
gyorgy@0
|
895
|
gyorgy@0
|
896 // FYI: options.success will be fired by the MediaPluginBridge
|
gyorgy@0
|
897
|
gyorgy@0
|
898 return pluginMediaElement;
|
gyorgy@0
|
899 },
|
gyorgy@0
|
900
|
gyorgy@0
|
901 updateNative: function(htmlMediaElement, options, autoplay, preload, playback) {
|
gyorgy@0
|
902 // add methods to video object to bring it into parity with Flash Object
|
gyorgy@0
|
903 for (var m in mejs.HtmlMediaElement) {
|
gyorgy@0
|
904 htmlMediaElement[m] = mejs.HtmlMediaElement[m];
|
gyorgy@0
|
905 }
|
gyorgy@0
|
906
|
gyorgy@0
|
907 /*
|
gyorgy@0
|
908 Chrome now supports preload="none"
|
gyorgy@0
|
909 if (mejs.MediaFeatures.isChrome) {
|
gyorgy@0
|
910
|
gyorgy@0
|
911 // special case to enforce preload attribute (Chrome doesn't respect this)
|
gyorgy@0
|
912 if (preload === 'none' && !autoplay) {
|
gyorgy@0
|
913
|
gyorgy@0
|
914 // forces the browser to stop loading (note: fails in IE9)
|
gyorgy@0
|
915 htmlMediaElement.src = '';
|
gyorgy@0
|
916 htmlMediaElement.load();
|
gyorgy@0
|
917 htmlMediaElement.canceledPreload = true;
|
gyorgy@0
|
918
|
gyorgy@0
|
919 htmlMediaElement.addEventListener('play',function() {
|
gyorgy@0
|
920 if (htmlMediaElement.canceledPreload) {
|
gyorgy@0
|
921 htmlMediaElement.src = playback.url;
|
gyorgy@0
|
922 htmlMediaElement.load();
|
gyorgy@0
|
923 htmlMediaElement.play();
|
gyorgy@0
|
924 htmlMediaElement.canceledPreload = false;
|
gyorgy@0
|
925 }
|
gyorgy@0
|
926 }, false);
|
gyorgy@0
|
927 // for some reason Chrome forgets how to autoplay sometimes.
|
gyorgy@0
|
928 } else if (autoplay) {
|
gyorgy@0
|
929 htmlMediaElement.load();
|
gyorgy@0
|
930 htmlMediaElement.play();
|
gyorgy@0
|
931 }
|
gyorgy@0
|
932 }
|
gyorgy@0
|
933 */
|
gyorgy@0
|
934
|
gyorgy@0
|
935 // fire success code
|
gyorgy@0
|
936 options.success(htmlMediaElement, htmlMediaElement);
|
gyorgy@0
|
937
|
gyorgy@0
|
938 return htmlMediaElement;
|
gyorgy@0
|
939 }
|
gyorgy@0
|
940 };
|
gyorgy@0
|
941
|
gyorgy@0
|
942 window.mejs = mejs;
|
gyorgy@0
|
943 window.MediaElement = mejs.MediaElement;
|
gyorgy@0
|
944
|
gyorgy@0
|
945 /*!
|
gyorgy@0
|
946 * MediaElementPlayer
|
gyorgy@0
|
947 * http://mediaelementjs.com/
|
gyorgy@0
|
948 *
|
gyorgy@0
|
949 * Creates a controller bar for HTML5 <video> add <audio> tags
|
gyorgy@0
|
950 * using jQuery and MediaElement.js (HTML5 Flash/Silverlight wrapper)
|
gyorgy@0
|
951 *
|
gyorgy@0
|
952 * Copyright 2010-2011, John Dyer (http://j.hn/)
|
gyorgy@0
|
953 * Dual licensed under the MIT or GPL Version 2 licenses.
|
gyorgy@0
|
954 *
|
gyorgy@0
|
955 */
|
gyorgy@0
|
956 if (typeof jQuery != 'undefined') {
|
gyorgy@0
|
957 mejs.$ = jQuery;
|
gyorgy@0
|
958 } else if (typeof ender != 'undefined') {
|
gyorgy@0
|
959 mejs.$ = ender;
|
gyorgy@0
|
960 }
|
gyorgy@0
|
961 (function ($) {
|
gyorgy@0
|
962
|
gyorgy@0
|
963 // default player values
|
gyorgy@0
|
964 mejs.MepDefaults = {
|
gyorgy@0
|
965 // url to poster (to fix iOS 3.x)
|
gyorgy@0
|
966 poster: '',
|
gyorgy@0
|
967 // default if the <video width> is not specified
|
gyorgy@0
|
968 defaultVideoWidth: 480,
|
gyorgy@0
|
969 // default if the <video height> is not specified
|
gyorgy@0
|
970 defaultVideoHeight: 270,
|
gyorgy@0
|
971 // if set, overrides <video width>
|
gyorgy@0
|
972 videoWidth: -1,
|
gyorgy@0
|
973 // if set, overrides <video height>
|
gyorgy@0
|
974 videoHeight: -1,
|
gyorgy@0
|
975 // width of audio player
|
gyorgy@0
|
976 audioWidth: 400,
|
gyorgy@0
|
977 // height of audio player
|
gyorgy@0
|
978 audioHeight: 30,
|
gyorgy@0
|
979 // initial volume when the player starts (overrided by user cookie)
|
gyorgy@0
|
980 startVolume: 0.8,
|
gyorgy@0
|
981 // useful for <audio> player loops
|
gyorgy@0
|
982 loop: false,
|
gyorgy@0
|
983 // resize to media dimensions
|
gyorgy@0
|
984 enableAutosize: true,
|
gyorgy@0
|
985 // forces the hour marker (##:00:00)
|
gyorgy@0
|
986 alwaysShowHours: false,
|
gyorgy@0
|
987 // Hide controls when playing and mouse is not over the video
|
gyorgy@0
|
988 alwaysShowControls: false,
|
gyorgy@0
|
989 // force iPad's native controls
|
gyorgy@0
|
990 iPadUseNativeControls: true,
|
gyorgy@0
|
991 // features to show
|
gyorgy@0
|
992 features: ['playpause','current','progress','duration','tracks','volume','fullscreen']
|
gyorgy@0
|
993 };
|
gyorgy@0
|
994
|
gyorgy@0
|
995 mejs.mepIndex = 0;
|
gyorgy@0
|
996
|
gyorgy@0
|
997 // wraps a MediaElement object in player controls
|
gyorgy@0
|
998 mejs.MediaElementPlayer = function(node, o) {
|
gyorgy@0
|
999 // enforce object, even without "new" (via John Resig)
|
gyorgy@0
|
1000 if ( !(this instanceof mejs.MediaElementPlayer) ) {
|
gyorgy@0
|
1001 return new mejs.MediaElementPlayer(node, o);
|
gyorgy@0
|
1002 }
|
gyorgy@0
|
1003
|
gyorgy@0
|
1004 var
|
gyorgy@0
|
1005 t = this,
|
gyorgy@0
|
1006 mf = mejs.MediaFeatures;
|
gyorgy@0
|
1007
|
gyorgy@0
|
1008 // create options
|
gyorgy@0
|
1009 t.options = $.extend({},mejs.MepDefaults,o);
|
gyorgy@0
|
1010
|
gyorgy@0
|
1011 // these will be reset after the MediaElement.success fires
|
gyorgy@0
|
1012 t.$media = t.$node = $(node);
|
gyorgy@0
|
1013 t.node = t.media = t.$media[0];
|
gyorgy@0
|
1014
|
gyorgy@0
|
1015 // check for existing player
|
gyorgy@0
|
1016 if (typeof t.node.player != 'undefined') {
|
gyorgy@0
|
1017 return t.node.player;
|
gyorgy@0
|
1018 } else {
|
gyorgy@0
|
1019 // attach player to DOM node for reference
|
gyorgy@0
|
1020 t.node.player = t;
|
gyorgy@0
|
1021 }
|
gyorgy@0
|
1022
|
gyorgy@0
|
1023 t.isVideo = (t.media.tagName.toLowerCase() === 'video');
|
gyorgy@0
|
1024
|
gyorgy@0
|
1025 /* FUTURE WORK = create player without existing <video> or <audio> node
|
gyorgy@0
|
1026
|
gyorgy@0
|
1027 // if not a video or audio tag, then we'll dynamically create it
|
gyorgy@0
|
1028 if (tagName == 'video' || tagName == 'audio') {
|
gyorgy@0
|
1029 t.$media = $($node);
|
gyorgy@0
|
1030 } else if (o.tagName !== '' && o.src !== '') {
|
gyorgy@0
|
1031 // create a new node
|
gyorgy@0
|
1032 if (o.mode == 'auto' || o.mode == 'native') {
|
gyorgy@0
|
1033
|
gyorgy@0
|
1034 $media = $(o.tagName);
|
gyorgy@0
|
1035 if (typeof o.src == 'string') {
|
gyorgy@0
|
1036 $media.attr('src',o.src);
|
gyorgy@0
|
1037 } else if (typeof o.src == 'object') {
|
gyorgy@0
|
1038 // create source nodes
|
gyorgy@0
|
1039 for (var x in o.src) {
|
gyorgy@0
|
1040 $media.append($('<source src="' + o.src[x].src + '" type="' + o.src[x].type + '" />'));
|
gyorgy@0
|
1041 }
|
gyorgy@0
|
1042 }
|
gyorgy@0
|
1043 if (o.type != '') {
|
gyorgy@0
|
1044 $media.attr('type',o.type);
|
gyorgy@0
|
1045 }
|
gyorgy@0
|
1046 if (o.poster != '') {
|
gyorgy@0
|
1047 $media.attr('poster',o.poster);
|
gyorgy@0
|
1048 }
|
gyorgy@0
|
1049 if (o.videoWidth > 0) {
|
gyorgy@0
|
1050 $media.attr('width',o.videoWidth);
|
gyorgy@0
|
1051 }
|
gyorgy@0
|
1052 if (o.videoHeight > 0) {
|
gyorgy@0
|
1053 $media.attr('height',o.videoHeight);
|
gyorgy@0
|
1054 }
|
gyorgy@0
|
1055
|
gyorgy@0
|
1056 $node.clear();
|
gyorgy@0
|
1057 $node.append($media);
|
gyorgy@0
|
1058 t.$media = $media;
|
gyorgy@0
|
1059 } else if (o.mode == 'shim') {
|
gyorgy@0
|
1060 $media = $();
|
gyorgy@0
|
1061 // doesn't want a media node
|
gyorgy@0
|
1062 // let MediaElement object handle this
|
gyorgy@0
|
1063 }
|
gyorgy@0
|
1064 } else {
|
gyorgy@0
|
1065 // fail?
|
gyorgy@0
|
1066 return;
|
gyorgy@0
|
1067 }
|
gyorgy@0
|
1068 */
|
gyorgy@0
|
1069
|
gyorgy@0
|
1070 t.init();
|
gyorgy@0
|
1071
|
gyorgy@0
|
1072 return t;
|
gyorgy@0
|
1073 };
|
gyorgy@0
|
1074
|
gyorgy@0
|
1075 // actual player
|
gyorgy@0
|
1076 mejs.MediaElementPlayer.prototype = {
|
gyorgy@0
|
1077 init: function() {
|
gyorgy@0
|
1078
|
gyorgy@0
|
1079 var
|
gyorgy@0
|
1080 t = this,
|
gyorgy@0
|
1081 mf = mejs.MediaFeatures,
|
gyorgy@0
|
1082 // options for MediaElement (shim)
|
gyorgy@0
|
1083 meOptions = $.extend(true, {}, t.options, {
|
gyorgy@0
|
1084 success: function(media, domNode) { t.meReady(media, domNode); },
|
gyorgy@0
|
1085 error: function(e) { t.handleError(e);}
|
gyorgy@0
|
1086 });
|
gyorgy@0
|
1087
|
gyorgy@0
|
1088
|
gyorgy@0
|
1089 // use native controls in iPad, iPhone, and Android
|
gyorgy@0
|
1090 if ((mf.isiPad && t.options.iPadUseNativeControls) || mf.isiPhone) {
|
gyorgy@0
|
1091 // add controls and stop
|
gyorgy@0
|
1092 t.$media.attr('controls', 'controls');
|
gyorgy@0
|
1093
|
gyorgy@0
|
1094 // attempt to fix iOS 3 bug
|
gyorgy@0
|
1095 t.$media.removeAttr('poster');
|
gyorgy@0
|
1096
|
gyorgy@0
|
1097 // override Apple's autoplay override for iPads
|
gyorgy@0
|
1098 if (mf.isiPad && t.media.getAttribute('autoplay') !== null) {
|
gyorgy@0
|
1099 t.media.load();
|
gyorgy@0
|
1100 t.media.play();
|
gyorgy@0
|
1101 }
|
gyorgy@0
|
1102
|
gyorgy@0
|
1103 } else if (mf.isAndroid && t.isVideo) {
|
gyorgy@0
|
1104
|
gyorgy@0
|
1105 // leave default player
|
gyorgy@0
|
1106
|
gyorgy@0
|
1107 } else {
|
gyorgy@0
|
1108
|
gyorgy@0
|
1109 // DESKTOP: use MediaElementPlayer controls
|
gyorgy@0
|
1110
|
gyorgy@0
|
1111 // remove native controls
|
gyorgy@0
|
1112 t.$media.removeAttr('controls');
|
gyorgy@0
|
1113
|
gyorgy@0
|
1114 // unique ID
|
gyorgy@0
|
1115 t.id = 'mep_' + mejs.mepIndex++;
|
gyorgy@0
|
1116
|
gyorgy@0
|
1117 // build container
|
gyorgy@0
|
1118 t.container =
|
gyorgy@0
|
1119 $('<div id="' + t.id + '" class="mejs-container">'+
|
gyorgy@0
|
1120 '<div class="mejs-inner">'+
|
gyorgy@0
|
1121 '<div class="mejs-mediaelement"></div>'+
|
gyorgy@0
|
1122 '<div class="mejs-layers"></div>'+
|
gyorgy@0
|
1123 '<div class="mejs-controls"></div>'+
|
gyorgy@0
|
1124 '<div class="mejs-clear"></div>'+
|
gyorgy@0
|
1125 '</div>' +
|
gyorgy@0
|
1126 '</div>')
|
gyorgy@0
|
1127 .addClass(t.$media[0].className)
|
gyorgy@0
|
1128 .insertBefore(t.$media);
|
gyorgy@0
|
1129
|
gyorgy@0
|
1130 // move the <video/video> tag into the right spot
|
gyorgy@0
|
1131 t.container.find('.mejs-mediaelement').append(t.$media);
|
gyorgy@0
|
1132
|
gyorgy@0
|
1133 // find parts
|
gyorgy@0
|
1134 t.controls = t.container.find('.mejs-controls');
|
gyorgy@0
|
1135 t.layers = t.container.find('.mejs-layers');
|
gyorgy@0
|
1136
|
gyorgy@0
|
1137 // determine the size
|
gyorgy@0
|
1138 if (t.isVideo) {
|
gyorgy@0
|
1139 // priority = videoWidth (forced), width attribute, defaultVideoWidth
|
gyorgy@0
|
1140 t.width = (t.options.videoWidth > 0) ? t.options.videoWidth : (t.$media[0].getAttribute('width') !== null) ? t.$media.attr('width') : t.options.defaultVideoWidth;
|
gyorgy@0
|
1141 t.height = (t.options.videoHeight > 0) ? t.options.videoHeight : (t.$media[0].getAttribute('height') !== null) ? t.$media.attr('height') : t.options.defaultVideoHeight;
|
gyorgy@0
|
1142 } else {
|
gyorgy@0
|
1143 t.width = t.options.audioWidth;
|
gyorgy@0
|
1144 t.height = t.options.audioHeight;
|
gyorgy@0
|
1145 }
|
gyorgy@0
|
1146
|
gyorgy@0
|
1147 // set the size, while we wait for the plugins to load below
|
gyorgy@0
|
1148 t.setPlayerSize(t.width, t.height);
|
gyorgy@0
|
1149
|
gyorgy@0
|
1150 // create MediaElementShim
|
gyorgy@0
|
1151 meOptions.pluginWidth = t.height;
|
gyorgy@0
|
1152 meOptions.pluginHeight = t.width;
|
gyorgy@0
|
1153 }
|
gyorgy@0
|
1154
|
gyorgy@0
|
1155 // create MediaElement shim
|
gyorgy@0
|
1156 mejs.MediaElement(t.$media[0], meOptions);
|
gyorgy@0
|
1157 },
|
gyorgy@0
|
1158
|
gyorgy@0
|
1159 // Sets up all controls and events
|
gyorgy@0
|
1160 meReady: function(media, domNode) {
|
gyorgy@0
|
1161
|
gyorgy@0
|
1162
|
gyorgy@0
|
1163 var t = this,
|
gyorgy@0
|
1164 mf = mejs.MediaFeatures,
|
gyorgy@0
|
1165 f,
|
gyorgy@0
|
1166 feature;
|
gyorgy@0
|
1167
|
gyorgy@0
|
1168 // make sure it can't create itself again if a plugin reloads
|
gyorgy@0
|
1169 if (t.created)
|
gyorgy@0
|
1170 return;
|
gyorgy@0
|
1171 else
|
gyorgy@0
|
1172 t.created = true;
|
gyorgy@0
|
1173
|
gyorgy@0
|
1174 t.media = media;
|
gyorgy@0
|
1175 t.domNode = domNode;
|
gyorgy@0
|
1176
|
gyorgy@0
|
1177 if (!mf.isiPhone && !mf.isAndroid && !(mf.isiPad && t.options.iPadUseNativeControls)) {
|
gyorgy@0
|
1178
|
gyorgy@0
|
1179 // two built in features
|
gyorgy@0
|
1180 t.buildposter(t, t.controls, t.layers, t.media);
|
gyorgy@0
|
1181 t.buildoverlays(t, t.controls, t.layers, t.media);
|
gyorgy@0
|
1182
|
gyorgy@0
|
1183 // grab for use by features
|
gyorgy@0
|
1184 t.findTracks();
|
gyorgy@0
|
1185
|
gyorgy@0
|
1186 // add user-defined features/controls
|
gyorgy@0
|
1187 for (f in t.options.features) {
|
gyorgy@0
|
1188 feature = t.options.features[f];
|
gyorgy@0
|
1189 if (t['build' + feature]) {
|
gyorgy@0
|
1190 try {
|
gyorgy@0
|
1191 t['build' + feature](t, t.controls, t.layers, t.media);
|
gyorgy@0
|
1192 } catch (e) {
|
gyorgy@0
|
1193 // TODO: report control error
|
gyorgy@0
|
1194 //throw e;
|
gyorgy@0
|
1195 }
|
gyorgy@0
|
1196 }
|
gyorgy@0
|
1197 }
|
gyorgy@0
|
1198
|
gyorgy@0
|
1199 t.container.trigger('controlsready');
|
gyorgy@0
|
1200
|
gyorgy@0
|
1201 // reset all layers and controls
|
gyorgy@0
|
1202 t.setPlayerSize(t.width, t.height);
|
gyorgy@0
|
1203 t.setControlsSize();
|
gyorgy@0
|
1204
|
gyorgy@0
|
1205
|
gyorgy@0
|
1206 // controls fade
|
gyorgy@0
|
1207 if (t.isVideo) {
|
gyorgy@0
|
1208 // show/hide controls
|
gyorgy@0
|
1209 t.container
|
gyorgy@0
|
1210 .bind('mouseenter', function () {
|
gyorgy@0
|
1211 if (!t.options.alwaysShowControls) {
|
gyorgy@0
|
1212 t.controls.css('visibility','visible');
|
gyorgy@0
|
1213 t.controls.stop(true, true).fadeIn(200);
|
gyorgy@0
|
1214 }
|
gyorgy@0
|
1215 })
|
gyorgy@0
|
1216 .bind('mouseleave', function () {
|
gyorgy@0
|
1217 if (!t.media.paused && !t.options.alwaysShowControls) {
|
gyorgy@0
|
1218 t.controls.stop(true, true).fadeOut(200, function() {
|
gyorgy@0
|
1219 $(this).css('visibility','hidden');
|
gyorgy@0
|
1220 $(this).css('display','block');
|
gyorgy@0
|
1221 });
|
gyorgy@0
|
1222 }
|
gyorgy@0
|
1223 });
|
gyorgy@0
|
1224
|
gyorgy@0
|
1225 // check for autoplay
|
gyorgy@0
|
1226 if (t.domNode.getAttribute('autoplay') !== null && !t.options.alwaysShowControls) {
|
gyorgy@0
|
1227 t.controls.css('visibility','hidden');
|
gyorgy@0
|
1228 }
|
gyorgy@0
|
1229
|
gyorgy@0
|
1230 // resizer
|
gyorgy@0
|
1231 if (t.options.enableAutosize) {
|
gyorgy@0
|
1232 t.media.addEventListener('loadedmetadata', function(e) {
|
gyorgy@0
|
1233 // if the <video height> was not set and the options.videoHeight was not set
|
gyorgy@0
|
1234 // then resize to the real dimensions
|
gyorgy@0
|
1235 if (t.options.videoHeight <= 0 && t.domNode.getAttribute('height') === null && !isNaN(e.target.videoHeight)) {
|
gyorgy@0
|
1236 t.setPlayerSize(e.target.videoWidth, e.target.videoHeight);
|
gyorgy@0
|
1237 t.setControlsSize();
|
gyorgy@0
|
1238 t.media.setVideoSize(e.target.videoWidth, e.target.videoHeight);
|
gyorgy@0
|
1239 }
|
gyorgy@0
|
1240 }, false);
|
gyorgy@0
|
1241 }
|
gyorgy@0
|
1242 }
|
gyorgy@0
|
1243
|
gyorgy@0
|
1244 // ended for all
|
gyorgy@0
|
1245 t.media.addEventListener('ended', function (e) {
|
gyorgy@0
|
1246 t.media.setCurrentTime(0);
|
gyorgy@0
|
1247 t.media.pause();
|
gyorgy@0
|
1248
|
gyorgy@0
|
1249 if (t.setProgressRail)
|
gyorgy@0
|
1250 t.setProgressRail();
|
gyorgy@0
|
1251 if (t.setCurrentRail)
|
gyorgy@0
|
1252 t.setCurrentRail();
|
gyorgy@0
|
1253
|
gyorgy@0
|
1254 if (t.options.loop) {
|
gyorgy@0
|
1255 t.media.play();
|
gyorgy@0
|
1256 } else if (!t.options.alwaysShowControls) {
|
gyorgy@0
|
1257 t.controls.css('visibility','visible');
|
gyorgy@0
|
1258 }
|
gyorgy@0
|
1259 }, true);
|
gyorgy@0
|
1260
|
gyorgy@0
|
1261 // resize on the first play
|
gyorgy@0
|
1262 t.media.addEventListener('loadedmetadata', function(e) {
|
gyorgy@0
|
1263 if (t.updateDuration) {
|
gyorgy@0
|
1264 t.updateDuration();
|
gyorgy@0
|
1265 }
|
gyorgy@0
|
1266 if (t.updateCurrent) {
|
gyorgy@0
|
1267 t.updateCurrent();
|
gyorgy@0
|
1268 }
|
gyorgy@0
|
1269
|
gyorgy@0
|
1270 t.setControlsSize();
|
gyorgy@0
|
1271 }, true);
|
gyorgy@0
|
1272
|
gyorgy@0
|
1273
|
gyorgy@0
|
1274 // webkit has trouble doing this without a delay
|
gyorgy@0
|
1275 setTimeout(function () {
|
gyorgy@0
|
1276 t.setControlsSize();
|
gyorgy@0
|
1277 t.setPlayerSize(t.width, t.height);
|
gyorgy@0
|
1278 }, 50);
|
gyorgy@0
|
1279
|
gyorgy@0
|
1280 }
|
gyorgy@0
|
1281
|
gyorgy@0
|
1282
|
gyorgy@0
|
1283 if (t.options.success) {
|
gyorgy@0
|
1284 t.options.success(t.media, t.domNode);
|
gyorgy@0
|
1285 }
|
gyorgy@0
|
1286 },
|
gyorgy@0
|
1287
|
gyorgy@0
|
1288 handleError: function(e) {
|
gyorgy@0
|
1289 // Tell user that the file cannot be played
|
gyorgy@0
|
1290 if (this.options.error) {
|
gyorgy@0
|
1291 this.options.error(e);
|
gyorgy@0
|
1292 }
|
gyorgy@0
|
1293 },
|
gyorgy@0
|
1294
|
gyorgy@0
|
1295 setPlayerSize: function(width,height) {
|
gyorgy@0
|
1296 var t = this;
|
gyorgy@0
|
1297
|
gyorgy@0
|
1298 // ie9 appears to need this (jQuery bug?)
|
gyorgy@0
|
1299 t.width = parseInt(width, 10);
|
gyorgy@0
|
1300 t.height = parseInt(height, 10);
|
gyorgy@0
|
1301
|
gyorgy@0
|
1302 t.container
|
gyorgy@0
|
1303 .width(t.width)
|
gyorgy@0
|
1304 .height(t.height);
|
gyorgy@0
|
1305
|
gyorgy@0
|
1306 t.layers.children('.mejs-layer')
|
gyorgy@0
|
1307 .width(t.width)
|
gyorgy@0
|
1308 .height(t.height);
|
gyorgy@0
|
1309 },
|
gyorgy@0
|
1310
|
gyorgy@0
|
1311 setControlsSize: function() {
|
gyorgy@0
|
1312 var t = this,
|
gyorgy@0
|
1313 usedWidth = 0,
|
gyorgy@0
|
1314 railWidth = 0,
|
gyorgy@0
|
1315 rail = t.controls.find('.mejs-time-rail'),
|
gyorgy@0
|
1316 total = t.controls.find('.mejs-time-total'),
|
gyorgy@0
|
1317 current = t.controls.find('.mejs-time-current'),
|
gyorgy@0
|
1318 loaded = t.controls.find('.mejs-time-loaded');
|
gyorgy@0
|
1319 others = rail.siblings();
|
gyorgy@0
|
1320
|
gyorgy@0
|
1321 // find the size of all the other controls besides the rail
|
gyorgy@0
|
1322 others.each(function() {
|
gyorgy@0
|
1323 if ($(this).css('position') != 'absolute') {
|
gyorgy@0
|
1324 usedWidth += $(this).outerWidth(true);
|
gyorgy@0
|
1325 }
|
gyorgy@0
|
1326 });
|
gyorgy@0
|
1327 // fit the rail into the remaining space
|
gyorgy@0
|
1328 railWidth = t.controls.width() - usedWidth - (rail.outerWidth(true) - rail.outerWidth(false));
|
gyorgy@0
|
1329
|
gyorgy@0
|
1330 // outer area
|
gyorgy@0
|
1331 rail.width(railWidth);
|
gyorgy@0
|
1332 // dark space
|
gyorgy@0
|
1333 total.width(railWidth - (total.outerWidth(true) - total.width()));
|
gyorgy@0
|
1334
|
gyorgy@0
|
1335 if (t.setProgressRail)
|
gyorgy@0
|
1336 t.setProgressRail();
|
gyorgy@0
|
1337 if (t.setCurrentRail)
|
gyorgy@0
|
1338 t.setCurrentRail();
|
gyorgy@0
|
1339 },
|
gyorgy@0
|
1340
|
gyorgy@0
|
1341
|
gyorgy@0
|
1342 buildposter: function(player, controls, layers, media) {
|
gyorgy@0
|
1343 var poster =
|
gyorgy@0
|
1344 $('<div class="mejs-poster mejs-layer">'+
|
gyorgy@0
|
1345 '<img />'+
|
gyorgy@0
|
1346 '</div>')
|
gyorgy@0
|
1347 .appendTo(layers),
|
gyorgy@0
|
1348 posterUrl = player.$media.attr('poster'),
|
gyorgy@0
|
1349 posterImg = poster.find('img').width(player.width).height(player.height);
|
gyorgy@0
|
1350
|
gyorgy@0
|
1351 // prioriy goes to option (this is useful if you need to support iOS 3.x (iOS completely fails with poster)
|
gyorgy@0
|
1352 if (player.options.poster != '') {
|
gyorgy@0
|
1353 posterImg.attr('src',player.options.poster);
|
gyorgy@0
|
1354 // second, try the real poster
|
gyorgy@0
|
1355 } else if (posterUrl !== '' && posterUrl != null) {
|
gyorgy@0
|
1356 posterImg.attr('src',posterUrl);
|
gyorgy@0
|
1357 } else {
|
gyorgy@0
|
1358 poster.remove();
|
gyorgy@0
|
1359 }
|
gyorgy@0
|
1360
|
gyorgy@0
|
1361 media.addEventListener('play',function() {
|
gyorgy@0
|
1362 poster.hide();
|
gyorgy@0
|
1363 }, false);
|
gyorgy@0
|
1364 },
|
gyorgy@0
|
1365
|
gyorgy@0
|
1366 buildoverlays: function(player, controls, layers, media) {
|
gyorgy@0
|
1367 if (!player.isVideo)
|
gyorgy@0
|
1368 return;
|
gyorgy@0
|
1369
|
gyorgy@0
|
1370 var
|
gyorgy@0
|
1371 loading =
|
gyorgy@0
|
1372 $('<div class="mejs-overlay mejs-layer">'+
|
gyorgy@0
|
1373 '<div class="mejs-overlay-loading"><span></span></div>'+
|
gyorgy@0
|
1374 '</div>')
|
gyorgy@0
|
1375 .hide() // start out hidden
|
gyorgy@0
|
1376 .appendTo(layers),
|
gyorgy@0
|
1377 error =
|
gyorgy@0
|
1378 $('<div class="mejs-overlay mejs-layer">'+
|
gyorgy@0
|
1379 '<div class="mejs-overlay-error"></div>'+
|
gyorgy@0
|
1380 '</div>')
|
gyorgy@0
|
1381 .hide() // start out hidden
|
gyorgy@0
|
1382 .appendTo(layers),
|
gyorgy@0
|
1383
|
gyorgy@0
|
1384 // this needs to come last so it's on top
|
gyorgy@0
|
1385 bigPlay =
|
gyorgy@0
|
1386 $('<div class="mejs-overlay mejs-layer mejs-overlay-play">'+
|
gyorgy@0
|
1387 '<div class="mejs-overlay-button"></div>'+
|
gyorgy@0
|
1388 '</div>')
|
gyorgy@0
|
1389 .appendTo(layers)
|
gyorgy@0
|
1390 .click(function() {
|
gyorgy@0
|
1391 if (media.paused) {
|
gyorgy@0
|
1392 media.play();
|
gyorgy@0
|
1393 } else {
|
gyorgy@0
|
1394 media.pause();
|
gyorgy@0
|
1395 }
|
gyorgy@0
|
1396 });
|
gyorgy@0
|
1397
|
gyorgy@0
|
1398
|
gyorgy@0
|
1399 // show/hide big play button
|
gyorgy@0
|
1400 media.addEventListener('play',function() {
|
gyorgy@0
|
1401 bigPlay.hide();
|
gyorgy@0
|
1402 error.hide();
|
gyorgy@0
|
1403 }, false);
|
gyorgy@0
|
1404 media.addEventListener('pause',function() {
|
gyorgy@0
|
1405 bigPlay.show();
|
gyorgy@0
|
1406 }, false);
|
gyorgy@0
|
1407
|
gyorgy@0
|
1408 // show/hide loading
|
gyorgy@0
|
1409 media.addEventListener('loadstart',function() {
|
gyorgy@0
|
1410 // for some reason Chrome is firing this event
|
gyorgy@0
|
1411 if (mejs.MediaFeatures.isChrome && media.getAttribute && media.getAttribute('preload') === 'none')
|
gyorgy@0
|
1412 return;
|
gyorgy@0
|
1413
|
gyorgy@0
|
1414 loading.show();
|
gyorgy@0
|
1415 }, false);
|
gyorgy@0
|
1416 media.addEventListener('canplay',function() {
|
gyorgy@0
|
1417 loading.hide();
|
gyorgy@0
|
1418 }, false);
|
gyorgy@0
|
1419
|
gyorgy@0
|
1420 // error handling
|
gyorgy@0
|
1421 media.addEventListener('error',function() {
|
gyorgy@0
|
1422 loading.hide();
|
gyorgy@0
|
1423 error.show();
|
gyorgy@0
|
1424 error.find('mejs-overlay-error').html("Error loading this resource");
|
gyorgy@0
|
1425 }, false);
|
gyorgy@0
|
1426 },
|
gyorgy@0
|
1427
|
gyorgy@0
|
1428 findTracks: function() {
|
gyorgy@0
|
1429 var t = this,
|
gyorgy@0
|
1430 tracktags = t.$media.find('track');
|
gyorgy@0
|
1431
|
gyorgy@0
|
1432 // store for use by plugins
|
gyorgy@0
|
1433 t.tracks = [];
|
gyorgy@0
|
1434 tracktags.each(function() {
|
gyorgy@0
|
1435 t.tracks.push({
|
gyorgy@0
|
1436 srclang: $(this).attr('srclang').toLowerCase(),
|
gyorgy@0
|
1437 src: $(this).attr('src'),
|
gyorgy@0
|
1438 kind: $(this).attr('kind'),
|
gyorgy@0
|
1439 entries: [],
|
gyorgy@0
|
1440 isLoaded: false
|
gyorgy@0
|
1441 });
|
gyorgy@0
|
1442 });
|
gyorgy@0
|
1443 },
|
gyorgy@0
|
1444 changeSkin: function(className) {
|
gyorgy@0
|
1445 this.container[0].className = 'mejs-container ' + className;
|
gyorgy@0
|
1446 this.setPlayerSize();
|
gyorgy@0
|
1447 this.setControlsSize();
|
gyorgy@0
|
1448 },
|
gyorgy@0
|
1449 play: function() {
|
gyorgy@0
|
1450 this.media.play();
|
gyorgy@0
|
1451 },
|
gyorgy@0
|
1452 pause: function() {
|
gyorgy@0
|
1453 this.media.pause();
|
gyorgy@0
|
1454 },
|
gyorgy@0
|
1455 load: function() {
|
gyorgy@0
|
1456 this.media.load();
|
gyorgy@0
|
1457 },
|
gyorgy@0
|
1458 setMuted: function(muted) {
|
gyorgy@0
|
1459 this.media.setMuted(muted);
|
gyorgy@0
|
1460 },
|
gyorgy@0
|
1461 setCurrentTime: function(time) {
|
gyorgy@0
|
1462 this.media.setCurrentTime(time);
|
gyorgy@0
|
1463 },
|
gyorgy@0
|
1464 getCurrentTime: function() {
|
gyorgy@0
|
1465 return this.media.currentTime;
|
gyorgy@0
|
1466 },
|
gyorgy@0
|
1467 setVolume: function(volume) {
|
gyorgy@0
|
1468 this.media.setVolume(volume);
|
gyorgy@0
|
1469 },
|
gyorgy@0
|
1470 getVolume: function() {
|
gyorgy@0
|
1471 return this.media.volume;
|
gyorgy@0
|
1472 },
|
gyorgy@0
|
1473 setSrc: function(src) {
|
gyorgy@0
|
1474 this.media.setSrc(src);
|
gyorgy@0
|
1475 }
|
gyorgy@0
|
1476 };
|
gyorgy@0
|
1477
|
gyorgy@0
|
1478 // turn into jQuery plugin
|
gyorgy@0
|
1479 if (typeof jQuery != 'undefined') {
|
gyorgy@0
|
1480 jQuery.fn.mediaelementplayer = function (options) {
|
gyorgy@0
|
1481 return this.each(function () {
|
gyorgy@0
|
1482 new mejs.MediaElementPlayer(this, options);
|
gyorgy@0
|
1483 });
|
gyorgy@0
|
1484 };
|
gyorgy@0
|
1485 }
|
gyorgy@0
|
1486
|
gyorgy@0
|
1487 // push out to window
|
gyorgy@0
|
1488 window.MediaElementPlayer = mejs.MediaElementPlayer;
|
gyorgy@0
|
1489
|
gyorgy@0
|
1490 })(mejs.$);
|
gyorgy@0
|
1491 (function($) {
|
gyorgy@0
|
1492 // PLAY/pause BUTTON
|
gyorgy@0
|
1493 MediaElementPlayer.prototype.buildplaypause = function(player, controls, layers, media) {
|
gyorgy@0
|
1494 var play =
|
gyorgy@0
|
1495 $('<div class="mejs-button mejs-playpause-button mejs-play" type="button">' +
|
gyorgy@0
|
1496 '<button type="button"></button>' +
|
gyorgy@0
|
1497 '</div>')
|
gyorgy@0
|
1498 .appendTo(controls)
|
gyorgy@0
|
1499 .click(function(e) {
|
gyorgy@0
|
1500 e.preventDefault();
|
gyorgy@0
|
1501
|
gyorgy@0
|
1502 if (media.paused) {
|
gyorgy@0
|
1503 media.play();
|
gyorgy@0
|
1504 } else {
|
gyorgy@0
|
1505 media.pause();
|
gyorgy@0
|
1506 }
|
gyorgy@0
|
1507
|
gyorgy@0
|
1508 return false;
|
gyorgy@0
|
1509 });
|
gyorgy@0
|
1510
|
gyorgy@0
|
1511 media.addEventListener('play',function() {
|
gyorgy@0
|
1512 play.removeClass('mejs-play').addClass('mejs-pause');
|
gyorgy@0
|
1513 }, false);
|
gyorgy@0
|
1514 media.addEventListener('playing',function() {
|
gyorgy@0
|
1515 play.removeClass('mejs-play').addClass('mejs-pause');
|
gyorgy@0
|
1516 }, false);
|
gyorgy@0
|
1517
|
gyorgy@0
|
1518
|
gyorgy@0
|
1519 media.addEventListener('pause',function() {
|
gyorgy@0
|
1520 play.removeClass('mejs-pause').addClass('mejs-play');
|
gyorgy@0
|
1521 }, false);
|
gyorgy@0
|
1522 media.addEventListener('paused',function() {
|
gyorgy@0
|
1523 play.removeClass('mejs-pause').addClass('mejs-play');
|
gyorgy@0
|
1524 }, false);
|
gyorgy@0
|
1525 }
|
gyorgy@0
|
1526
|
gyorgy@0
|
1527 })(mejs.$);
|
gyorgy@0
|
1528 (function($) {
|
gyorgy@0
|
1529 // STOP BUTTON
|
gyorgy@0
|
1530 MediaElementPlayer.prototype.buildstop = function(player, controls, layers, media) {
|
gyorgy@0
|
1531 var stop =
|
gyorgy@0
|
1532 $('<div class="mejs-button mejs-stop-button mejs-stop">' +
|
gyorgy@0
|
1533 '<button type="button"></button>' +
|
gyorgy@0
|
1534 '</div>')
|
gyorgy@0
|
1535 .appendTo(controls)
|
gyorgy@0
|
1536 .click(function() {
|
gyorgy@0
|
1537 if (!media.paused) {
|
gyorgy@0
|
1538 media.pause();
|
gyorgy@0
|
1539 }
|
gyorgy@0
|
1540 if (media.currentTime > 0) {
|
gyorgy@0
|
1541 media.setCurrentTime(0);
|
gyorgy@0
|
1542 controls.find('.mejs-time-current').width('0px');
|
gyorgy@0
|
1543 controls.find('.mejs-time-handle').css('left', '0px');
|
gyorgy@0
|
1544 controls.find('.mejs-time-float-current').html( mejs.Utility.secondsToTimeCode(0) );
|
gyorgy@0
|
1545 controls.find('.mejs-currenttime').html( mejs.Utility.secondsToTimeCode(0) );
|
gyorgy@0
|
1546 layers.find('.mejs-poster').show();
|
gyorgy@0
|
1547 }
|
gyorgy@0
|
1548 });
|
gyorgy@0
|
1549 }
|
gyorgy@0
|
1550
|
gyorgy@0
|
1551 })(mejs.$);
|
gyorgy@0
|
1552 (function($) {
|
gyorgy@0
|
1553 // progress/loaded bar
|
gyorgy@0
|
1554 MediaElementPlayer.prototype.buildprogress = function(player, controls, layers, media) {
|
gyorgy@0
|
1555
|
gyorgy@0
|
1556 $('<div class="mejs-time-rail">'+
|
gyorgy@0
|
1557 '<span class="mejs-time-total">'+
|
gyorgy@0
|
1558 '<span class="mejs-time-loaded"></span>'+
|
gyorgy@0
|
1559 '<span class="mejs-time-current"></span>'+
|
gyorgy@0
|
1560 '<span class="mejs-time-handle"></span>'+
|
gyorgy@0
|
1561 '<span class="mejs-time-float">' +
|
gyorgy@0
|
1562 '<span class="mejs-time-float-current">00:00</span>' +
|
gyorgy@0
|
1563 '<span class="mejs-time-float-corner"></span>' +
|
gyorgy@0
|
1564 '</span>'+
|
gyorgy@0
|
1565 '</span>'+
|
gyorgy@0
|
1566 '</div>')
|
gyorgy@0
|
1567 .appendTo(controls);
|
gyorgy@0
|
1568
|
gyorgy@0
|
1569 var
|
gyorgy@0
|
1570 t = this,
|
gyorgy@0
|
1571 total = controls.find('.mejs-time-total'),
|
gyorgy@0
|
1572 loaded = controls.find('.mejs-time-loaded'),
|
gyorgy@0
|
1573 current = controls.find('.mejs-time-current'),
|
gyorgy@0
|
1574 handle = controls.find('.mejs-time-handle'),
|
gyorgy@0
|
1575 timefloat = controls.find('.mejs-time-float'),
|
gyorgy@0
|
1576 timefloatcurrent = controls.find('.mejs-time-float-current'),
|
gyorgy@0
|
1577 handleMouseMove = function (e) {
|
gyorgy@0
|
1578 // mouse position relative to the object
|
gyorgy@0
|
1579 var x = e.pageX,
|
gyorgy@0
|
1580 offset = total.offset(),
|
gyorgy@0
|
1581 width = total.outerWidth(),
|
gyorgy@0
|
1582 percentage = 0,
|
gyorgy@0
|
1583 newTime = 0;
|
gyorgy@0
|
1584
|
gyorgy@0
|
1585
|
gyorgy@0
|
1586 if (x > offset.left && x <= width + offset.left && media.duration) {
|
gyorgy@0
|
1587 percentage = ((x - offset.left) / width);
|
gyorgy@0
|
1588 newTime = (percentage <= 0.02) ? 0 : percentage * media.duration;
|
gyorgy@0
|
1589
|
gyorgy@0
|
1590 // seek to where the mouse is
|
gyorgy@0
|
1591 if (mouseIsDown) {
|
gyorgy@0
|
1592 media.setCurrentTime(newTime);
|
gyorgy@0
|
1593 }
|
gyorgy@0
|
1594
|
gyorgy@0
|
1595 // position floating time box
|
gyorgy@0
|
1596 var pos = x - offset.left;
|
gyorgy@0
|
1597 timefloat.css('left', pos);
|
gyorgy@0
|
1598 timefloatcurrent.html( mejs.Utility.secondsToTimeCode(newTime) );
|
gyorgy@0
|
1599 }
|
gyorgy@0
|
1600 },
|
gyorgy@0
|
1601 mouseIsDown = false,
|
gyorgy@0
|
1602 mouseIsOver = false;
|
gyorgy@0
|
1603
|
gyorgy@0
|
1604 // handle clicks
|
gyorgy@0
|
1605 //controls.find('.mejs-time-rail').delegate('span', 'click', handleMouseMove);
|
gyorgy@0
|
1606 total
|
gyorgy@0
|
1607 .bind('mousedown', function (e) {
|
gyorgy@0
|
1608 mouseIsDown = true;
|
gyorgy@0
|
1609 handleMouseMove(e);
|
gyorgy@0
|
1610 return false;
|
gyorgy@0
|
1611 });
|
gyorgy@0
|
1612
|
gyorgy@0
|
1613 controls.find('.mejs-time-rail')
|
gyorgy@0
|
1614 .bind('mouseenter', function(e) {
|
gyorgy@0
|
1615 mouseIsOver = true;
|
gyorgy@0
|
1616 })
|
gyorgy@0
|
1617 .bind('mouseleave',function(e) {
|
gyorgy@0
|
1618 mouseIsOver = false;
|
gyorgy@0
|
1619 });
|
gyorgy@0
|
1620
|
gyorgy@0
|
1621 $(document)
|
gyorgy@0
|
1622 .bind('mouseup', function (e) {
|
gyorgy@0
|
1623 mouseIsDown = false;
|
gyorgy@0
|
1624 //handleMouseMove(e);
|
gyorgy@0
|
1625 })
|
gyorgy@0
|
1626 .bind('mousemove', function (e) {
|
gyorgy@0
|
1627 if (mouseIsDown || mouseIsOver) {
|
gyorgy@0
|
1628 handleMouseMove(e);
|
gyorgy@0
|
1629 }
|
gyorgy@0
|
1630 });
|
gyorgy@0
|
1631
|
gyorgy@0
|
1632 // loading
|
gyorgy@0
|
1633 media.addEventListener('progress', function (e) {
|
gyorgy@0
|
1634 player.setProgressRail(e);
|
gyorgy@0
|
1635 player.setCurrentRail(e);
|
gyorgy@0
|
1636 }, false);
|
gyorgy@0
|
1637
|
gyorgy@0
|
1638 // current time
|
gyorgy@0
|
1639 media.addEventListener('timeupdate', function(e) {
|
gyorgy@0
|
1640 player.setProgressRail(e);
|
gyorgy@0
|
1641 player.setCurrentRail(e);
|
gyorgy@0
|
1642 }, false);
|
gyorgy@0
|
1643
|
gyorgy@0
|
1644
|
gyorgy@0
|
1645 // store for later use
|
gyorgy@0
|
1646 t.loaded = loaded;
|
gyorgy@0
|
1647 t.total = total;
|
gyorgy@0
|
1648 t.current = current;
|
gyorgy@0
|
1649 t.handle = handle;
|
gyorgy@0
|
1650 }
|
gyorgy@0
|
1651 MediaElementPlayer.prototype.setProgressRail = function(e) {
|
gyorgy@0
|
1652
|
gyorgy@0
|
1653 var
|
gyorgy@0
|
1654 t = this,
|
gyorgy@0
|
1655 target = (e != undefined) ? e.target : t.media,
|
gyorgy@0
|
1656 percent = null;
|
gyorgy@0
|
1657
|
gyorgy@0
|
1658 // newest HTML5 spec has buffered array (FF4, Webkit)
|
gyorgy@0
|
1659 if (target && target.buffered && target.buffered.length > 0 && target.buffered.end && target.duration) {
|
gyorgy@0
|
1660 // TODO: account for a real array with multiple values (only Firefox 4 has this so far)
|
gyorgy@0
|
1661 percent = target.buffered.end(0) / target.duration;
|
gyorgy@0
|
1662 }
|
gyorgy@0
|
1663 // Some browsers (e.g., FF3.6 and Safari 5) cannot calculate target.bufferered.end()
|
gyorgy@0
|
1664 // to be anything other than 0. If the byte count is available we use this instead.
|
gyorgy@0
|
1665 // Browsers that support the else if do not seem to have the bufferedBytes value and
|
gyorgy@0
|
1666 // should skip to there. Tested in Safari 5, Webkit head, FF3.6, Chrome 6, IE 7/8.
|
gyorgy@0
|
1667 else if (target && target.bytesTotal != undefined && target.bytesTotal > 0 && target.bufferedBytes != undefined) {
|
gyorgy@0
|
1668 percent = target.bufferedBytes / target.bytesTotal;
|
gyorgy@0
|
1669 }
|
gyorgy@0
|
1670 // Firefox 3 with an Ogg file seems to go this way
|
gyorgy@0
|
1671 else if (e && e.lengthComputable && e.total != 0) {
|
gyorgy@0
|
1672 percent = e.loaded/e.total;
|
gyorgy@0
|
1673 }
|
gyorgy@0
|
1674
|
gyorgy@0
|
1675 // finally update the progress bar
|
gyorgy@0
|
1676 if (percent !== null) {
|
gyorgy@0
|
1677 percent = Math.min(1, Math.max(0, percent));
|
gyorgy@0
|
1678 // update loaded bar
|
gyorgy@0
|
1679 if (t.loaded && t.total) {
|
gyorgy@0
|
1680 t.loaded.width(t.total.width() * percent);
|
gyorgy@0
|
1681 }
|
gyorgy@0
|
1682 }
|
gyorgy@0
|
1683 }
|
gyorgy@0
|
1684 MediaElementPlayer.prototype.setCurrentRail = function() {
|
gyorgy@0
|
1685
|
gyorgy@0
|
1686 var t = this;
|
gyorgy@0
|
1687
|
gyorgy@0
|
1688 if (t.media.currentTime != undefined && t.media.duration) {
|
gyorgy@0
|
1689
|
gyorgy@0
|
1690 // update bar and handle
|
gyorgy@0
|
1691 if (t.total && t.handle) {
|
gyorgy@0
|
1692 var
|
gyorgy@0
|
1693 newWidth = t.total.width() * t.media.currentTime / t.media.duration,
|
gyorgy@0
|
1694 handlePos = newWidth - (t.handle.outerWidth(true) / 2);
|
gyorgy@0
|
1695
|
gyorgy@0
|
1696 t.current.width(newWidth);
|
gyorgy@0
|
1697 t.handle.css('left', handlePos);
|
gyorgy@0
|
1698 }
|
gyorgy@0
|
1699 }
|
gyorgy@0
|
1700
|
gyorgy@0
|
1701 }
|
gyorgy@0
|
1702
|
gyorgy@0
|
1703 })(mejs.$);
|
gyorgy@0
|
1704 (function($) {
|
gyorgy@0
|
1705 // current and duration 00:00 / 00:00
|
gyorgy@0
|
1706 MediaElementPlayer.prototype.buildcurrent = function(player, controls, layers, media) {
|
gyorgy@0
|
1707 var t = this;
|
gyorgy@0
|
1708
|
gyorgy@0
|
1709 $('<div class="mejs-time">'+
|
gyorgy@0
|
1710 '<span class="mejs-currenttime">' + (player.options.alwaysShowHours ? '00:' : '') + '00:00</span>'+
|
gyorgy@0
|
1711 '</div>')
|
gyorgy@0
|
1712 .appendTo(controls);
|
gyorgy@0
|
1713
|
gyorgy@0
|
1714 t.currenttime = t.controls.find('.mejs-currenttime');
|
gyorgy@0
|
1715
|
gyorgy@0
|
1716 media.addEventListener('timeupdate',function() {
|
gyorgy@0
|
1717 player.updateCurrent();
|
gyorgy@0
|
1718 }, false);
|
gyorgy@0
|
1719 };
|
gyorgy@0
|
1720
|
gyorgy@0
|
1721 MediaElementPlayer.prototype.buildduration = function(player, controls, layers, media) {
|
gyorgy@0
|
1722 var t = this;
|
gyorgy@0
|
1723
|
gyorgy@0
|
1724 if (controls.children().last().find('.mejs-currenttime').length > 0) {
|
gyorgy@0
|
1725 $(' <span> | </span> '+
|
gyorgy@0
|
1726 '<span class="mejs-duration">' + (player.options.alwaysShowHours ? '00:' : '') + '00:00</span>')
|
gyorgy@0
|
1727 .appendTo(controls.find('.mejs-time'));
|
gyorgy@0
|
1728 } else {
|
gyorgy@0
|
1729
|
gyorgy@0
|
1730 // add class to current time
|
gyorgy@0
|
1731 controls.find('.mejs-currenttime').parent().addClass('mejs-currenttime-container');
|
gyorgy@0
|
1732
|
gyorgy@0
|
1733 $('<div class="mejs-time mejs-duration-container">'+
|
gyorgy@0
|
1734 '<span class="mejs-duration">' + (player.options.alwaysShowHours ? '00:' : '') + '00:00</span>'+
|
gyorgy@0
|
1735 '</div>')
|
gyorgy@0
|
1736 .appendTo(controls);
|
gyorgy@0
|
1737 }
|
gyorgy@0
|
1738
|
gyorgy@0
|
1739 t.durationD = t.controls.find('.mejs-duration');
|
gyorgy@0
|
1740
|
gyorgy@0
|
1741 media.addEventListener('timeupdate',function() {
|
gyorgy@0
|
1742 player.updateDuration();
|
gyorgy@0
|
1743 }, false);
|
gyorgy@0
|
1744 };
|
gyorgy@0
|
1745
|
gyorgy@0
|
1746 MediaElementPlayer.prototype.updateCurrent = function() {
|
gyorgy@0
|
1747 var t = this;
|
gyorgy@0
|
1748
|
gyorgy@0
|
1749 if (t.currenttime) {
|
gyorgy@0
|
1750 t.currenttime.html(mejs.Utility.secondsToTimeCode(t.media.currentTime | 0, t.options.alwaysShowHours || t.media.duration > 3600 ));
|
gyorgy@0
|
1751 }
|
gyorgy@0
|
1752 }
|
gyorgy@0
|
1753 MediaElementPlayer.prototype.updateDuration = function() {
|
gyorgy@0
|
1754 var t = this;
|
gyorgy@0
|
1755
|
gyorgy@0
|
1756 if (t.media.duration && t.durationD) {
|
gyorgy@0
|
1757 t.durationD.html(mejs.Utility.secondsToTimeCode(t.media.duration, t.options.alwaysShowHours));
|
gyorgy@0
|
1758 }
|
gyorgy@0
|
1759 };
|
gyorgy@0
|
1760
|
gyorgy@0
|
1761 })(mejs.$);
|
gyorgy@0
|
1762 (function($) {
|
gyorgy@0
|
1763 MediaElementPlayer.prototype.buildvolume = function(player, controls, layers, media) {
|
gyorgy@0
|
1764 var mute =
|
gyorgy@0
|
1765 $('<div class="mejs-button mejs-volume-button mejs-mute">'+
|
gyorgy@0
|
1766 '<button type="button"></button>'+
|
gyorgy@0
|
1767 '<div class="mejs-volume-slider">'+ // outer background
|
gyorgy@0
|
1768 '<div class="mejs-volume-total"></div>'+ // line background
|
gyorgy@0
|
1769 '<div class="mejs-volume-current"></div>'+ // current volume
|
gyorgy@0
|
1770 '<div class="mejs-volume-handle"></div>'+ // handle
|
gyorgy@0
|
1771 '</div>'+
|
gyorgy@0
|
1772 '</div>')
|
gyorgy@0
|
1773 .appendTo(controls),
|
gyorgy@0
|
1774 volumeSlider = mute.find('.mejs-volume-slider'),
|
gyorgy@0
|
1775 volumeTotal = mute.find('.mejs-volume-total'),
|
gyorgy@0
|
1776 volumeCurrent = mute.find('.mejs-volume-current'),
|
gyorgy@0
|
1777 volumeHandle = mute.find('.mejs-volume-handle'),
|
gyorgy@0
|
1778
|
gyorgy@0
|
1779 positionVolumeHandle = function(volume) {
|
gyorgy@0
|
1780
|
gyorgy@0
|
1781 var
|
gyorgy@0
|
1782 top = volumeTotal.height() - (volumeTotal.height() * volume);
|
gyorgy@0
|
1783
|
gyorgy@0
|
1784 // handle
|
gyorgy@0
|
1785 volumeHandle.css('top', top - (volumeHandle.height() / 2));
|
gyorgy@0
|
1786
|
gyorgy@0
|
1787 // show the current visibility
|
gyorgy@0
|
1788 volumeCurrent.height(volumeTotal.height() - top + parseInt(volumeTotal.css('top').replace(/px/,''),10));
|
gyorgy@0
|
1789 volumeCurrent.css('top', top);
|
gyorgy@0
|
1790 },
|
gyorgy@0
|
1791 handleVolumeMove = function(e) {
|
gyorgy@0
|
1792 var
|
gyorgy@0
|
1793 railHeight = volumeTotal.height(),
|
gyorgy@0
|
1794 totalOffset = volumeTotal.offset(),
|
gyorgy@0
|
1795 totalTop = parseInt(volumeTotal.css('top').replace(/px/,''),10),
|
gyorgy@0
|
1796 newY = e.pageY - totalOffset.top,
|
gyorgy@0
|
1797 volume = (railHeight - newY) / railHeight
|
gyorgy@0
|
1798
|
gyorgy@0
|
1799 // TODO: handle vertical and horizontal CSS
|
gyorgy@0
|
1800 // only allow it to move within the rail
|
gyorgy@0
|
1801 if (newY < 0)
|
gyorgy@0
|
1802 newY = 0;
|
gyorgy@0
|
1803 else if (newY > railHeight)
|
gyorgy@0
|
1804 newY = railHeight;
|
gyorgy@0
|
1805
|
gyorgy@0
|
1806 // move the handle to match the mouse
|
gyorgy@0
|
1807 volumeHandle.css('top', newY - (volumeHandle.height() / 2) + totalTop );
|
gyorgy@0
|
1808
|
gyorgy@0
|
1809 // show the current visibility
|
gyorgy@0
|
1810 volumeCurrent.height(railHeight-newY);
|
gyorgy@0
|
1811 volumeCurrent.css('top',newY+totalTop);
|
gyorgy@0
|
1812
|
gyorgy@0
|
1813 // set mute status
|
gyorgy@0
|
1814 if (volume == 0) {
|
gyorgy@0
|
1815 media.setMuted(true);
|
gyorgy@0
|
1816 mute.removeClass('mejs-mute').addClass('mejs-unmute');
|
gyorgy@0
|
1817 } else {
|
gyorgy@0
|
1818 media.setMuted(false);
|
gyorgy@0
|
1819 mute.removeClass('mejs-unmute').addClass('mejs-mute');
|
gyorgy@0
|
1820 }
|
gyorgy@0
|
1821
|
gyorgy@0
|
1822 volume = Math.max(0,volume);
|
gyorgy@0
|
1823 volume = Math.min(volume,1);
|
gyorgy@0
|
1824
|
gyorgy@0
|
1825 // set the volume
|
gyorgy@0
|
1826 media.setVolume(volume);
|
gyorgy@0
|
1827 },
|
gyorgy@0
|
1828 mouseIsDown = false;
|
gyorgy@0
|
1829
|
gyorgy@0
|
1830 // SLIDER
|
gyorgy@0
|
1831 volumeSlider
|
gyorgy@0
|
1832 .bind('mousedown', function (e) {
|
gyorgy@0
|
1833 handleVolumeMove(e);
|
gyorgy@0
|
1834 mouseIsDown = true;
|
gyorgy@0
|
1835 return false;
|
gyorgy@0
|
1836 });
|
gyorgy@0
|
1837 $(document)
|
gyorgy@0
|
1838 .bind('mouseup', function (e) {
|
gyorgy@0
|
1839 mouseIsDown = false;
|
gyorgy@0
|
1840 })
|
gyorgy@0
|
1841 .bind('mousemove', function (e) {
|
gyorgy@0
|
1842 if (mouseIsDown) {
|
gyorgy@0
|
1843 handleVolumeMove(e);
|
gyorgy@0
|
1844 }
|
gyorgy@0
|
1845 });
|
gyorgy@0
|
1846
|
gyorgy@0
|
1847
|
gyorgy@0
|
1848 // MUTE button
|
gyorgy@0
|
1849 mute.find('button').click(function() {
|
gyorgy@0
|
1850 if (media.muted) {
|
gyorgy@0
|
1851 media.setMuted(false);
|
gyorgy@0
|
1852 mute.removeClass('mejs-unmute').addClass('mejs-mute');
|
gyorgy@0
|
1853 positionVolumeHandle(1);
|
gyorgy@0
|
1854 } else {
|
gyorgy@0
|
1855 media.setMuted(true);
|
gyorgy@0
|
1856 mute.removeClass('mejs-mute').addClass('mejs-unmute');
|
gyorgy@0
|
1857 positionVolumeHandle(0);
|
gyorgy@0
|
1858 }
|
gyorgy@0
|
1859 });
|
gyorgy@0
|
1860
|
gyorgy@0
|
1861 // listen for volume change events from other sources
|
gyorgy@0
|
1862 media.addEventListener('volumechange', function(e) {
|
gyorgy@0
|
1863 if (!mouseIsDown) {
|
gyorgy@0
|
1864 positionVolumeHandle(e.target.volume);
|
gyorgy@0
|
1865 }
|
gyorgy@0
|
1866 }, true);
|
gyorgy@0
|
1867
|
gyorgy@0
|
1868 // set initial volume
|
gyorgy@0
|
1869 positionVolumeHandle(player.options.startVolume);
|
gyorgy@0
|
1870
|
gyorgy@0
|
1871 // shim gets the startvolume as a parameter, but we have to set it on the native <video> and <audio> elements
|
gyorgy@0
|
1872 if (media.pluginType === 'native') {
|
gyorgy@0
|
1873 media.setVolume(player.options.startVolume);
|
gyorgy@0
|
1874 }
|
gyorgy@0
|
1875 }
|
gyorgy@0
|
1876
|
gyorgy@0
|
1877 })(mejs.$);
|
gyorgy@0
|
1878
|
gyorgy@0
|
1879 (function($) {
|
gyorgy@0
|
1880 mejs.MediaElementDefaults.forcePluginFullScreen = false;
|
gyorgy@0
|
1881
|
gyorgy@0
|
1882 MediaElementPlayer.prototype.isFullScreen = false;
|
gyorgy@0
|
1883 MediaElementPlayer.prototype.buildfullscreen = function(player, controls, layers, media) {
|
gyorgy@0
|
1884
|
gyorgy@0
|
1885 if (!player.isVideo)
|
gyorgy@0
|
1886 return;
|
gyorgy@0
|
1887
|
gyorgy@0
|
1888 // native events
|
gyorgy@0
|
1889 if (mejs.MediaFeatures.hasNativeFullScreen) {
|
gyorgy@0
|
1890 player.container.bind('webkitfullscreenchange', function(e) {
|
gyorgy@0
|
1891
|
gyorgy@0
|
1892 if (document.webkitIsFullScreen) {
|
gyorgy@0
|
1893 // reset the controls once we are fully in full screen
|
gyorgy@0
|
1894 player.setControlsSize();
|
gyorgy@0
|
1895 } else {
|
gyorgy@0
|
1896 // when a user presses ESC
|
gyorgy@0
|
1897 // make sure to put the player back into place
|
gyorgy@0
|
1898 player.exitFullScreen();
|
gyorgy@0
|
1899 }
|
gyorgy@0
|
1900 });
|
gyorgy@0
|
1901 }
|
gyorgy@0
|
1902
|
gyorgy@0
|
1903 var
|
gyorgy@0
|
1904 normalHeight = 0,
|
gyorgy@0
|
1905 normalWidth = 0,
|
gyorgy@0
|
1906 container = player.container,
|
gyorgy@0
|
1907 docElement = document.documentElement,
|
gyorgy@0
|
1908 docStyleOverflow,
|
gyorgy@0
|
1909 parentWindow = window.parent,
|
gyorgy@0
|
1910 parentiframes,
|
gyorgy@0
|
1911 iframe,
|
gyorgy@0
|
1912 fullscreenBtn =
|
gyorgy@0
|
1913 $('<div class="mejs-button mejs-fullscreen-button"><button type="button"></button></div>')
|
gyorgy@0
|
1914 .appendTo(controls)
|
gyorgy@0
|
1915 .click(function() {
|
gyorgy@0
|
1916 var isFullScreen = (mejs.MediaFeatures.hasNativeFullScreen) ?
|
gyorgy@0
|
1917 document.webkitIsFullScreen :
|
gyorgy@0
|
1918 player.isFullScreen;
|
gyorgy@0
|
1919
|
gyorgy@0
|
1920 if (isFullScreen) {
|
gyorgy@0
|
1921 player.exitFullScreen();
|
gyorgy@0
|
1922 } else {
|
gyorgy@0
|
1923 player.enterFullScreen();
|
gyorgy@0
|
1924 }
|
gyorgy@0
|
1925 });
|
gyorgy@0
|
1926
|
gyorgy@0
|
1927 player.enterFullScreen = function() {
|
gyorgy@0
|
1928
|
gyorgy@0
|
1929 // firefox can't adjust plugin sizes without resetting :(
|
gyorgy@0
|
1930 if (player.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || player.options.forcePluginFullScreen)) {
|
gyorgy@0
|
1931 media.setFullscreen(true);
|
gyorgy@0
|
1932 //player.isFullScreen = true;
|
gyorgy@0
|
1933 return;
|
gyorgy@0
|
1934 }
|
gyorgy@0
|
1935
|
gyorgy@0
|
1936 // attempt to set fullscreen
|
gyorgy@0
|
1937 if (mejs.MediaFeatures.hasNativeFullScreen) {
|
gyorgy@0
|
1938 player.container[0].webkitRequestFullScreen();
|
gyorgy@0
|
1939 }
|
gyorgy@0
|
1940
|
gyorgy@0
|
1941 // store overflow
|
gyorgy@0
|
1942 docStyleOverflow = docElement.style.overflow;
|
gyorgy@0
|
1943 // set it to not show scroll bars so 100% will work
|
gyorgy@0
|
1944 docElement.style.overflow = 'hidden';
|
gyorgy@0
|
1945
|
gyorgy@0
|
1946 // store
|
gyorgy@0
|
1947 normalHeight = player.container.height();
|
gyorgy@0
|
1948 normalWidth = player.container.width();
|
gyorgy@0
|
1949
|
gyorgy@0
|
1950 // make full size
|
gyorgy@0
|
1951 container
|
gyorgy@0
|
1952 .addClass('mejs-container-fullscreen')
|
gyorgy@0
|
1953 .width('100%')
|
gyorgy@0
|
1954 .height('100%')
|
gyorgy@0
|
1955 .css('z-index', 1000);
|
gyorgy@0
|
1956 //.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});
|
gyorgy@0
|
1957
|
gyorgy@0
|
1958 if (player.pluginType === 'native') {
|
gyorgy@0
|
1959 player.$media
|
gyorgy@0
|
1960 .width('100%')
|
gyorgy@0
|
1961 .height('100%');
|
gyorgy@0
|
1962 } else {
|
gyorgy@0
|
1963 container.find('object embed')
|
gyorgy@0
|
1964 .width('100%')
|
gyorgy@0
|
1965 .height('100%');
|
gyorgy@0
|
1966 player.media.setVideoSize($(window).width(),$(window).height());
|
gyorgy@0
|
1967 }
|
gyorgy@0
|
1968
|
gyorgy@0
|
1969 layers.children('div')
|
gyorgy@0
|
1970 .width('100%')
|
gyorgy@0
|
1971 .height('100%');
|
gyorgy@0
|
1972
|
gyorgy@0
|
1973 fullscreenBtn
|
gyorgy@0
|
1974 .removeClass('mejs-fullscreen')
|
gyorgy@0
|
1975 .addClass('mejs-unfullscreen');
|
gyorgy@0
|
1976
|
gyorgy@0
|
1977 player.setControlsSize();
|
gyorgy@0
|
1978 player.isFullScreen = true;
|
gyorgy@0
|
1979 };
|
gyorgy@0
|
1980 player.exitFullScreen = function() {
|
gyorgy@0
|
1981
|
gyorgy@0
|
1982 // firefox can't adjust plugins
|
gyorgy@0
|
1983 if (player.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
|
gyorgy@0
|
1984 media.setFullscreen(false);
|
gyorgy@0
|
1985 //player.isFullScreen = false;
|
gyorgy@0
|
1986 return;
|
gyorgy@0
|
1987 }
|
gyorgy@0
|
1988
|
gyorgy@0
|
1989 // come outo of native fullscreen
|
gyorgy@0
|
1990 if (mejs.MediaFeatures.hasNativeFullScreen && document.webkitIsFullScreen) {
|
gyorgy@0
|
1991 document.webkitCancelFullScreen();
|
gyorgy@0
|
1992 }
|
gyorgy@0
|
1993
|
gyorgy@0
|
1994 // restore scroll bars to document
|
gyorgy@0
|
1995 docElement.style.overflow = docStyleOverflow;
|
gyorgy@0
|
1996
|
gyorgy@0
|
1997 container
|
gyorgy@0
|
1998 .removeClass('mejs-container-fullscreen')
|
gyorgy@0
|
1999 .width(normalWidth)
|
gyorgy@0
|
2000 .height(normalHeight)
|
gyorgy@0
|
2001 .css('z-index', 1);
|
gyorgy@0
|
2002 //.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});
|
gyorgy@0
|
2003
|
gyorgy@0
|
2004 if (player.pluginType === 'native') {
|
gyorgy@0
|
2005 player.$media
|
gyorgy@0
|
2006 .width(normalWidth)
|
gyorgy@0
|
2007 .height(normalHeight);
|
gyorgy@0
|
2008 } else {
|
gyorgy@0
|
2009 container.find('object embed')
|
gyorgy@0
|
2010 .width(normalWidth)
|
gyorgy@0
|
2011 .height(normalHeight);
|
gyorgy@0
|
2012
|
gyorgy@0
|
2013 player.media.setVideoSize(normalWidth, normalHeight);
|
gyorgy@0
|
2014 }
|
gyorgy@0
|
2015
|
gyorgy@0
|
2016 layers.children('div')
|
gyorgy@0
|
2017 .width(normalWidth)
|
gyorgy@0
|
2018 .height(normalHeight);
|
gyorgy@0
|
2019
|
gyorgy@0
|
2020 fullscreenBtn
|
gyorgy@0
|
2021 .removeClass('mejs-unfullscreen')
|
gyorgy@0
|
2022 .addClass('mejs-fullscreen');
|
gyorgy@0
|
2023
|
gyorgy@0
|
2024 player.setControlsSize();
|
gyorgy@0
|
2025 player.isFullScreen = false;
|
gyorgy@0
|
2026 };
|
gyorgy@0
|
2027
|
gyorgy@0
|
2028 $(window).bind('resize',function (e) {
|
gyorgy@0
|
2029 player.setControlsSize();
|
gyorgy@0
|
2030 });
|
gyorgy@0
|
2031
|
gyorgy@0
|
2032 $(document).bind('keydown',function (e) {
|
gyorgy@0
|
2033 if (player.isFullScreen && e.keyCode == 27) {
|
gyorgy@0
|
2034 player.exitFullScreen();
|
gyorgy@0
|
2035 }
|
gyorgy@0
|
2036 });
|
gyorgy@0
|
2037
|
gyorgy@0
|
2038 }
|
gyorgy@0
|
2039
|
gyorgy@0
|
2040 })(mejs.$);
|
gyorgy@0
|
2041 (function($) {
|
gyorgy@0
|
2042
|
gyorgy@0
|
2043 // add extra default options
|
gyorgy@0
|
2044 $.extend(mejs.MepDefaults, {
|
gyorgy@0
|
2045 // this will automatically turn on a <track>
|
gyorgy@0
|
2046 startLanguage: '',
|
gyorgy@0
|
2047 // a list of languages to auto-translate via Google
|
gyorgy@0
|
2048 translations: [],
|
gyorgy@0
|
2049 // a dropdownlist of automatic translations
|
gyorgy@0
|
2050 translationSelector: false,
|
gyorgy@0
|
2051 // key for tranlsations
|
gyorgy@0
|
2052 googleApiKey: ''
|
gyorgy@0
|
2053 });
|
gyorgy@0
|
2054
|
gyorgy@0
|
2055 $.extend(MediaElementPlayer.prototype, {
|
gyorgy@0
|
2056
|
gyorgy@0
|
2057 buildtracks: function(player, controls, layers, media) {
|
gyorgy@0
|
2058 if (!player.isVideo)
|
gyorgy@0
|
2059 return;
|
gyorgy@0
|
2060
|
gyorgy@0
|
2061 if (player.tracks.length == 0)
|
gyorgy@0
|
2062 return;
|
gyorgy@0
|
2063
|
gyorgy@0
|
2064 var i, options = '';
|
gyorgy@0
|
2065
|
gyorgy@0
|
2066 player.chapters =
|
gyorgy@0
|
2067 $('<div class="mejs-chapters mejs-layer"></div>')
|
gyorgy@0
|
2068 .prependTo(layers).hide();
|
gyorgy@0
|
2069 player.captions =
|
gyorgy@0
|
2070 $('<div class="mejs-captions-layer mejs-layer"><div class="mejs-captions-position"><span class="mejs-captions-text"></span></div></div>')
|
gyorgy@0
|
2071 .prependTo(layers).hide();
|
gyorgy@0
|
2072 player.captionsText = player.captions.find('.mejs-captions-text');
|
gyorgy@0
|
2073 player.captionsButton =
|
gyorgy@0
|
2074 $('<div class="mejs-button mejs-captions-button">'+
|
gyorgy@0
|
2075 '<button type="button" ></button>'+
|
gyorgy@0
|
2076 '<div class="mejs-captions-selector">'+
|
gyorgy@0
|
2077 '<ul>'+
|
gyorgy@0
|
2078 '<li>'+
|
gyorgy@0
|
2079 '<input type="radio" name="' + player.id + '_captions" id="' + player.id + '_captions_none" value="none" checked="checked" />' +
|
gyorgy@0
|
2080 '<label for="' + player.id + '_captions_none">None</label>'+
|
gyorgy@0
|
2081 '</li>' +
|
gyorgy@0
|
2082 '</ul>'+
|
gyorgy@0
|
2083 '</div>'+
|
gyorgy@0
|
2084 '</button>')
|
gyorgy@0
|
2085 .appendTo(controls)
|
gyorgy@0
|
2086 // handle clicks to the language radio buttons
|
gyorgy@0
|
2087 .delegate('input[type=radio]','click',function() {
|
gyorgy@0
|
2088 lang = this.value;
|
gyorgy@0
|
2089
|
gyorgy@0
|
2090 if (lang == 'none') {
|
gyorgy@0
|
2091 player.selectedTrack = null;
|
gyorgy@0
|
2092 } else {
|
gyorgy@0
|
2093 for (i=0; i<player.tracks.length; i++) {
|
gyorgy@0
|
2094 if (player.tracks[i].srclang == lang) {
|
gyorgy@0
|
2095 player.selectedTrack = player.tracks[i];
|
gyorgy@0
|
2096 player.captions.attr('lang', player.selectedTrack.srclang);
|
gyorgy@0
|
2097 player.displayCaptions();
|
gyorgy@0
|
2098 break;
|
gyorgy@0
|
2099 }
|
gyorgy@0
|
2100 }
|
gyorgy@0
|
2101 }
|
gyorgy@0
|
2102 });
|
gyorgy@0
|
2103 //.bind('mouseenter', function() {
|
gyorgy@0
|
2104 // player.captionsButton.find('.mejs-captions-selector').css('visibility','visible')
|
gyorgy@0
|
2105 //});
|
gyorgy@0
|
2106
|
gyorgy@0
|
2107 if (!player.options.alwaysShowControls) {
|
gyorgy@0
|
2108 // move with controls
|
gyorgy@0
|
2109 player.container
|
gyorgy@0
|
2110 .bind('mouseenter', function () {
|
gyorgy@0
|
2111 // push captions above controls
|
gyorgy@0
|
2112 player.container.find('.mejs-captions-position').addClass('mejs-captions-position-hover');
|
gyorgy@0
|
2113
|
gyorgy@0
|
2114 })
|
gyorgy@0
|
2115 .bind('mouseleave', function () {
|
gyorgy@0
|
2116 if (!media.paused) {
|
gyorgy@0
|
2117 // move back to normal place
|
gyorgy@0
|
2118 player.container.find('.mejs-captions-position').removeClass('mejs-captions-position-hover');
|
gyorgy@0
|
2119 }
|
gyorgy@0
|
2120 });
|
gyorgy@0
|
2121 } else {
|
gyorgy@0
|
2122 player.container.find('.mejs-captions-position').addClass('mejs-captions-position-hover');
|
gyorgy@0
|
2123 }
|
gyorgy@0
|
2124
|
gyorgy@0
|
2125 player.trackToLoad = -1;
|
gyorgy@0
|
2126 player.selectedTrack = null;
|
gyorgy@0
|
2127 player.isLoadingTrack = false;
|
gyorgy@0
|
2128
|
gyorgy@0
|
2129 // add user-defined translations
|
gyorgy@0
|
2130 if (player.tracks.length > 0 && player.options.translations.length > 0) {
|
gyorgy@0
|
2131 for (i=0; i<player.options.translations.length; i++) {
|
gyorgy@0
|
2132 player.tracks.push({
|
gyorgy@0
|
2133 srclang: player.options.translations[i].toLowerCase(),
|
gyorgy@0
|
2134 src: null,
|
gyorgy@0
|
2135 kind: 'subtitles',
|
gyorgy@0
|
2136 entries: [],
|
gyorgy@0
|
2137 isLoaded: false,
|
gyorgy@0
|
2138 isTranslation: true
|
gyorgy@0
|
2139 });
|
gyorgy@0
|
2140 }
|
gyorgy@0
|
2141 }
|
gyorgy@0
|
2142
|
gyorgy@0
|
2143 // add to list
|
gyorgy@0
|
2144 for (i=0; i<player.tracks.length; i++) {
|
gyorgy@0
|
2145 if (player.tracks[i].kind == 'subtitles') {
|
gyorgy@0
|
2146 player.addTrackButton(player.tracks[i].srclang, player.tracks[i].isTranslation);
|
gyorgy@0
|
2147 }
|
gyorgy@0
|
2148 }
|
gyorgy@0
|
2149
|
gyorgy@0
|
2150 player.loadNextTrack();
|
gyorgy@0
|
2151
|
gyorgy@0
|
2152
|
gyorgy@0
|
2153 media.addEventListener('timeupdate',function(e) {
|
gyorgy@0
|
2154 player.displayCaptions();
|
gyorgy@0
|
2155 }, false);
|
gyorgy@0
|
2156
|
gyorgy@0
|
2157 media.addEventListener('loadedmetadata', function(e) {
|
gyorgy@0
|
2158 player.displayChapters();
|
gyorgy@0
|
2159 }, false);
|
gyorgy@0
|
2160
|
gyorgy@0
|
2161 player.container.hover(
|
gyorgy@0
|
2162 function () {
|
gyorgy@0
|
2163 // chapters
|
gyorgy@0
|
2164 player.chapters.css('visibility','visible');
|
gyorgy@0
|
2165 player.chapters.fadeIn(200);
|
gyorgy@0
|
2166 },
|
gyorgy@0
|
2167 function () {
|
gyorgy@0
|
2168 if (!media.paused) {
|
gyorgy@0
|
2169 player.chapters.fadeOut(200, function() {
|
gyorgy@0
|
2170 $(this).css('visibility','hidden');
|
gyorgy@0
|
2171 $(this).css('display','block');
|
gyorgy@0
|
2172 });
|
gyorgy@0
|
2173 }
|
gyorgy@0
|
2174 });
|
gyorgy@0
|
2175
|
gyorgy@0
|
2176 // check for autoplay
|
gyorgy@0
|
2177 if (player.node.getAttribute('autoplay') !== null) {
|
gyorgy@0
|
2178 player.chapters.css('visibility','hidden');
|
gyorgy@0
|
2179 }
|
gyorgy@0
|
2180
|
gyorgy@0
|
2181 // auto selector
|
gyorgy@0
|
2182 if (player.options.translationSelector) {
|
gyorgy@0
|
2183 for (i in mejs.language.codes) {
|
gyorgy@0
|
2184 options += '<option value="' + i + '">' + mejs.language.codes[i] + '</option>';
|
gyorgy@0
|
2185 }
|
gyorgy@0
|
2186 player.container.find('.mejs-captions-selector ul').before($(
|
gyorgy@0
|
2187 '<select class="mejs-captions-translations">' +
|
gyorgy@0
|
2188 '<option value="">--Add Translation--</option>' +
|
gyorgy@0
|
2189 options +
|
gyorgy@0
|
2190 '</select>'
|
gyorgy@0
|
2191 ));
|
gyorgy@0
|
2192 // add clicks
|
gyorgy@0
|
2193 player.container.find('.mejs-captions-translations').change(function() {
|
gyorgy@0
|
2194 var
|
gyorgy@0
|
2195 option = $(this);
|
gyorgy@0
|
2196 lang = option.val();
|
gyorgy@0
|
2197 // add this language to the tracks list
|
gyorgy@0
|
2198 if (lang != '') {
|
gyorgy@0
|
2199 player.tracks.push({
|
gyorgy@0
|
2200 srclang: lang,
|
gyorgy@0
|
2201 src: null,
|
gyorgy@0
|
2202 entries: [],
|
gyorgy@0
|
2203 isLoaded: false,
|
gyorgy@0
|
2204 isTranslation: true
|
gyorgy@0
|
2205 });
|
gyorgy@0
|
2206
|
gyorgy@0
|
2207 if (!player.isLoadingTrack) {
|
gyorgy@0
|
2208 player.trackToLoad--;
|
gyorgy@0
|
2209 player.addTrackButton(lang,true);
|
gyorgy@0
|
2210 player.options.startLanguage = lang;
|
gyorgy@0
|
2211 player.loadNextTrack();
|
gyorgy@0
|
2212 }
|
gyorgy@0
|
2213 }
|
gyorgy@0
|
2214 });
|
gyorgy@0
|
2215 }
|
gyorgy@0
|
2216
|
gyorgy@0
|
2217 },
|
gyorgy@0
|
2218
|
gyorgy@0
|
2219 loadNextTrack: function() {
|
gyorgy@0
|
2220 var t = this;
|
gyorgy@0
|
2221
|
gyorgy@0
|
2222 t.trackToLoad++;
|
gyorgy@0
|
2223 if (t.trackToLoad < t.tracks.length) {
|
gyorgy@0
|
2224 t.isLoadingTrack = true;
|
gyorgy@0
|
2225 t.loadTrack(t.trackToLoad);
|
gyorgy@0
|
2226 } else {
|
gyorgy@0
|
2227 // add done?
|
gyorgy@0
|
2228 t.isLoadingTrack = false;
|
gyorgy@0
|
2229 }
|
gyorgy@0
|
2230 },
|
gyorgy@0
|
2231
|
gyorgy@0
|
2232 loadTrack: function(index){
|
gyorgy@0
|
2233 var
|
gyorgy@0
|
2234 t = this,
|
gyorgy@0
|
2235 track = t.tracks[index],
|
gyorgy@0
|
2236 after = function() {
|
gyorgy@0
|
2237
|
gyorgy@0
|
2238 track.isLoaded = true;
|
gyorgy@0
|
2239
|
gyorgy@0
|
2240 // create button
|
gyorgy@0
|
2241 //t.addTrackButton(track.srclang);
|
gyorgy@0
|
2242 t.enableTrackButton(track.srclang);
|
gyorgy@0
|
2243
|
gyorgy@0
|
2244 t.loadNextTrack();
|
gyorgy@0
|
2245
|
gyorgy@0
|
2246 };
|
gyorgy@0
|
2247
|
gyorgy@0
|
2248 if (track.isTranslation) {
|
gyorgy@0
|
2249
|
gyorgy@0
|
2250 // translate the first track
|
gyorgy@0
|
2251 mejs.TrackFormatParser.translateTrackText(t.tracks[0].entries, t.tracks[0].srclang, track.srclang, t.options.googleApiKey, function(newOne) {
|
gyorgy@0
|
2252
|
gyorgy@0
|
2253 // store the new translation
|
gyorgy@0
|
2254 track.entries = newOne;
|
gyorgy@0
|
2255
|
gyorgy@0
|
2256 after();
|
gyorgy@0
|
2257 });
|
gyorgy@0
|
2258
|
gyorgy@0
|
2259 } else {
|
gyorgy@0
|
2260 $.ajax({
|
gyorgy@0
|
2261 url: track.src,
|
gyorgy@0
|
2262 success: function(d) {
|
gyorgy@0
|
2263
|
gyorgy@0
|
2264 // parse the loaded file
|
gyorgy@0
|
2265 track.entries = mejs.TrackFormatParser.parse(d);
|
gyorgy@0
|
2266 after();
|
gyorgy@0
|
2267
|
gyorgy@0
|
2268 if (track.kind == 'chapters' && t.media.duration > 0) {
|
gyorgy@0
|
2269 t.drawChapters(track);
|
gyorgy@0
|
2270 }
|
gyorgy@0
|
2271 },
|
gyorgy@0
|
2272 error: function() {
|
gyorgy@0
|
2273 t.loadNextTrack();
|
gyorgy@0
|
2274 }
|
gyorgy@0
|
2275 });
|
gyorgy@0
|
2276 }
|
gyorgy@0
|
2277 },
|
gyorgy@0
|
2278
|
gyorgy@0
|
2279 enableTrackButton: function(lang) {
|
gyorgy@0
|
2280 var t = this;
|
gyorgy@0
|
2281
|
gyorgy@0
|
2282 t.captionsButton
|
gyorgy@0
|
2283 .find('input[value=' + lang + ']')
|
gyorgy@0
|
2284 .prop('disabled',false)
|
gyorgy@0
|
2285 .siblings('label')
|
gyorgy@0
|
2286 .html( mejs.language.codes[lang] || lang );
|
gyorgy@0
|
2287
|
gyorgy@0
|
2288 // auto select
|
gyorgy@0
|
2289 if (t.options.startLanguage == lang) {
|
gyorgy@0
|
2290 $('#' + t.id + '_captions_' + lang).click();
|
gyorgy@0
|
2291 }
|
gyorgy@0
|
2292
|
gyorgy@0
|
2293 t.adjustLanguageBox();
|
gyorgy@0
|
2294 },
|
gyorgy@0
|
2295
|
gyorgy@0
|
2296 addTrackButton: function(lang, isTranslation) {
|
gyorgy@0
|
2297 var t = this,
|
gyorgy@0
|
2298 l = mejs.language.codes[lang] || lang;
|
gyorgy@0
|
2299
|
gyorgy@0
|
2300 t.captionsButton.find('ul').append(
|
gyorgy@0
|
2301 $('<li>'+
|
gyorgy@0
|
2302 '<input type="radio" name="' + t.id + '_captions" id="' + t.id + '_captions_' + lang + '" value="' + lang + '" disabled="disabled" />' +
|
gyorgy@0
|
2303 '<label for="' + t.id + '_captions_' + lang + '">' + l + ((isTranslation) ? ' (translating)' : ' (loading)') + '</label>'+
|
gyorgy@0
|
2304 '</li>')
|
gyorgy@0
|
2305 );
|
gyorgy@0
|
2306
|
gyorgy@0
|
2307 t.adjustLanguageBox();
|
gyorgy@0
|
2308
|
gyorgy@0
|
2309 // remove this from the dropdownlist (if it exists)
|
gyorgy@0
|
2310 t.container.find('.mejs-captions-translations option[value=' + lang + ']').remove();
|
gyorgy@0
|
2311 },
|
gyorgy@0
|
2312
|
gyorgy@0
|
2313 adjustLanguageBox:function() {
|
gyorgy@0
|
2314 var t = this;
|
gyorgy@0
|
2315 // adjust the size of the outer box
|
gyorgy@0
|
2316 t.captionsButton.find('.mejs-captions-selector').height(
|
gyorgy@0
|
2317 t.captionsButton.find('.mejs-captions-selector ul').outerHeight(true) +
|
gyorgy@0
|
2318 t.captionsButton.find('.mejs-captions-translations').outerHeight(true)
|
gyorgy@0
|
2319 );
|
gyorgy@0
|
2320 },
|
gyorgy@0
|
2321
|
gyorgy@0
|
2322 displayCaptions: function() {
|
gyorgy@0
|
2323
|
gyorgy@0
|
2324 if (typeof this.tracks == 'undefined')
|
gyorgy@0
|
2325 return;
|
gyorgy@0
|
2326
|
gyorgy@0
|
2327 var
|
gyorgy@0
|
2328 t = this,
|
gyorgy@0
|
2329 i,
|
gyorgy@0
|
2330 track = t.selectedTrack;
|
gyorgy@0
|
2331
|
gyorgy@0
|
2332 if (track != null && track.isLoaded) {
|
gyorgy@0
|
2333 for (i=0; i<track.entries.times.length; i++) {
|
gyorgy@0
|
2334 if (t.media.currentTime >= track.entries.times[i].start && t.media.currentTime <= track.entries.times[i].stop){
|
gyorgy@0
|
2335 t.captionsText.html(track.entries.text[i]);
|
gyorgy@0
|
2336 t.captions.show();
|
gyorgy@0
|
2337 return; // exit out if one is visible;
|
gyorgy@0
|
2338 }
|
gyorgy@0
|
2339 }
|
gyorgy@0
|
2340 t.captions.hide();
|
gyorgy@0
|
2341 } else {
|
gyorgy@0
|
2342 t.captions.hide();
|
gyorgy@0
|
2343 }
|
gyorgy@0
|
2344 },
|
gyorgy@0
|
2345
|
gyorgy@0
|
2346 displayChapters: function() {
|
gyorgy@0
|
2347 var
|
gyorgy@0
|
2348 t = this,
|
gyorgy@0
|
2349 i;
|
gyorgy@0
|
2350
|
gyorgy@0
|
2351 for (i=0; i<t.tracks.length; i++) {
|
gyorgy@0
|
2352 if (t.tracks[i].kind == 'chapters' && t.tracks[i].isLoaded) {
|
gyorgy@0
|
2353 t.drawChapters(t.tracks[i]);
|
gyorgy@0
|
2354 break;
|
gyorgy@0
|
2355 }
|
gyorgy@0
|
2356 }
|
gyorgy@0
|
2357 },
|
gyorgy@0
|
2358
|
gyorgy@0
|
2359 drawChapters: function(chapters) {
|
gyorgy@0
|
2360 var
|
gyorgy@0
|
2361 t = this,
|
gyorgy@0
|
2362 i,
|
gyorgy@0
|
2363 dur,
|
gyorgy@0
|
2364 //width,
|
gyorgy@0
|
2365 //left,
|
gyorgy@0
|
2366 percent = 0,
|
gyorgy@0
|
2367 usedPercent = 0;
|
gyorgy@0
|
2368
|
gyorgy@0
|
2369 t.chapters.empty();
|
gyorgy@0
|
2370
|
gyorgy@0
|
2371 for (i=0; i<chapters.entries.times.length; i++) {
|
gyorgy@0
|
2372 dur = chapters.entries.times[i].stop - chapters.entries.times[i].start;
|
gyorgy@0
|
2373 percent = Math.floor(dur / t.media.duration * 100);
|
gyorgy@0
|
2374 if (percent + usedPercent > 100 || // too large
|
gyorgy@0
|
2375 i == chapters.entries.times.length-1 && percent + usedPercent < 100) // not going to fill it in
|
gyorgy@0
|
2376 {
|
gyorgy@0
|
2377 percent = 100 - usedPercent;
|
gyorgy@0
|
2378 }
|
gyorgy@0
|
2379 //width = Math.floor(t.width * dur / t.media.duration);
|
gyorgy@0
|
2380 //left = Math.floor(t.width * chapters.entries.times[i].start / t.media.duration);
|
gyorgy@0
|
2381 //if (left + width > t.width) {
|
gyorgy@0
|
2382 // width = t.width - left;
|
gyorgy@0
|
2383 //}
|
gyorgy@0
|
2384
|
gyorgy@0
|
2385 t.chapters.append( $(
|
gyorgy@0
|
2386 '<div class="mejs-chapter" rel="' + chapters.entries.times[i].start + '" style="left: ' + usedPercent.toString() + '%;width: ' + percent.toString() + '%;">' +
|
gyorgy@0
|
2387 '<div class="mejs-chapter-block' + ((i==chapters.entries.times.length-1) ? ' mejs-chapter-block-last' : '') + '">' +
|
gyorgy@0
|
2388 '<span class="ch-title">' + chapters.entries.text[i] + '</span>' +
|
gyorgy@0
|
2389 '<span class="ch-time">' + mejs.Utility.secondsToTimeCode(chapters.entries.times[i].start) + '–' + mejs.Utility.secondsToTimeCode(chapters.entries.times[i].stop) + '</span>' +
|
gyorgy@0
|
2390 '</div>' +
|
gyorgy@0
|
2391 '</div>'));
|
gyorgy@0
|
2392 usedPercent += percent;
|
gyorgy@0
|
2393 }
|
gyorgy@0
|
2394
|
gyorgy@0
|
2395 t.chapters.find('div.mejs-chapter').click(function() {
|
gyorgy@0
|
2396 t.media.setCurrentTime( parseFloat( $(this).attr('rel') ) );
|
gyorgy@0
|
2397 if (t.media.paused) {
|
gyorgy@0
|
2398 t.media.play();
|
gyorgy@0
|
2399 }
|
gyorgy@0
|
2400 });
|
gyorgy@0
|
2401
|
gyorgy@0
|
2402 t.chapters.show();
|
gyorgy@0
|
2403 }
|
gyorgy@0
|
2404 });
|
gyorgy@0
|
2405
|
gyorgy@0
|
2406
|
gyorgy@0
|
2407
|
gyorgy@0
|
2408 mejs.language = {
|
gyorgy@0
|
2409 codes: {
|
gyorgy@0
|
2410 af:'Afrikaans',
|
gyorgy@0
|
2411 sq:'Albanian',
|
gyorgy@0
|
2412 ar:'Arabic',
|
gyorgy@0
|
2413 be:'Belarusian',
|
gyorgy@0
|
2414 bg:'Bulgarian',
|
gyorgy@0
|
2415 ca:'Catalan',
|
gyorgy@0
|
2416 zh:'Chinese',
|
gyorgy@0
|
2417 'zh-cn':'Chinese Simplified',
|
gyorgy@0
|
2418 'zh-tw':'Chinese Traditional',
|
gyorgy@0
|
2419 hr:'Croatian',
|
gyorgy@0
|
2420 cs:'Czech',
|
gyorgy@0
|
2421 da:'Danish',
|
gyorgy@0
|
2422 nl:'Dutch',
|
gyorgy@0
|
2423 en:'English',
|
gyorgy@0
|
2424 et:'Estonian',
|
gyorgy@0
|
2425 tl:'Filipino',
|
gyorgy@0
|
2426 fi:'Finnish',
|
gyorgy@0
|
2427 fr:'French',
|
gyorgy@0
|
2428 gl:'Galician',
|
gyorgy@0
|
2429 de:'German',
|
gyorgy@0
|
2430 el:'Greek',
|
gyorgy@0
|
2431 ht:'Haitian Creole',
|
gyorgy@0
|
2432 iw:'Hebrew',
|
gyorgy@0
|
2433 hi:'Hindi',
|
gyorgy@0
|
2434 hu:'Hungarian',
|
gyorgy@0
|
2435 is:'Icelandic',
|
gyorgy@0
|
2436 id:'Indonesian',
|
gyorgy@0
|
2437 ga:'Irish',
|
gyorgy@0
|
2438 it:'Italian',
|
gyorgy@0
|
2439 ja:'Japanese',
|
gyorgy@0
|
2440 ko:'Korean',
|
gyorgy@0
|
2441 lv:'Latvian',
|
gyorgy@0
|
2442 lt:'Lithuanian',
|
gyorgy@0
|
2443 mk:'Macedonian',
|
gyorgy@0
|
2444 ms:'Malay',
|
gyorgy@0
|
2445 mt:'Maltese',
|
gyorgy@0
|
2446 no:'Norwegian',
|
gyorgy@0
|
2447 fa:'Persian',
|
gyorgy@0
|
2448 pl:'Polish',
|
gyorgy@0
|
2449 pt:'Portuguese',
|
gyorgy@0
|
2450 //'pt-pt':'Portuguese (Portugal)',
|
gyorgy@0
|
2451 ro:'Romanian',
|
gyorgy@0
|
2452 ru:'Russian',
|
gyorgy@0
|
2453 sr:'Serbian',
|
gyorgy@0
|
2454 sk:'Slovak',
|
gyorgy@0
|
2455 sl:'Slovenian',
|
gyorgy@0
|
2456 es:'Spanish',
|
gyorgy@0
|
2457 sw:'Swahili',
|
gyorgy@0
|
2458 sv:'Swedish',
|
gyorgy@0
|
2459 tl:'Tagalog',
|
gyorgy@0
|
2460 th:'Thai',
|
gyorgy@0
|
2461 tr:'Turkish',
|
gyorgy@0
|
2462 uk:'Ukrainian',
|
gyorgy@0
|
2463 vi:'Vietnamese',
|
gyorgy@0
|
2464 cy:'Welsh',
|
gyorgy@0
|
2465 yi:'Yiddish'
|
gyorgy@0
|
2466 }
|
gyorgy@0
|
2467 };
|
gyorgy@0
|
2468
|
gyorgy@0
|
2469 /*
|
gyorgy@0
|
2470 Parses WebVVT format which should be formatted as
|
gyorgy@0
|
2471 ================================
|
gyorgy@0
|
2472 WEBVTT
|
gyorgy@0
|
2473
|
gyorgy@0
|
2474 1
|
gyorgy@0
|
2475 00:00:01,1 --> 00:00:05,000
|
gyorgy@0
|
2476 A line of text
|
gyorgy@0
|
2477
|
gyorgy@0
|
2478 2
|
gyorgy@0
|
2479 00:01:15,1 --> 00:02:05,000
|
gyorgy@0
|
2480 A second line of text
|
gyorgy@0
|
2481
|
gyorgy@0
|
2482 ===============================
|
gyorgy@0
|
2483
|
gyorgy@0
|
2484 Adapted from: http://www.delphiki.com/html5/playr
|
gyorgy@0
|
2485 */
|
gyorgy@0
|
2486 mejs.TrackFormatParser = {
|
gyorgy@0
|
2487 pattern_identifier: /^[0-9]+$/,
|
gyorgy@0
|
2488 pattern_timecode: /^([0-9]{2}:[0-9]{2}:[0-9]{2}(,[0-9]{1,3})?) --\> ([0-9]{2}:[0-9]{2}:[0-9]{2}(,[0-9]{3})?)(.*)$/,
|
gyorgy@0
|
2489
|
gyorgy@0
|
2490 split2: function (text, regex) {
|
gyorgy@0
|
2491 // normal version for compliant browsers
|
gyorgy@0
|
2492 // see below for IE fix
|
gyorgy@0
|
2493 return text.split(regex);
|
gyorgy@0
|
2494 },
|
gyorgy@0
|
2495 parse: function(trackText) {
|
gyorgy@0
|
2496 var
|
gyorgy@0
|
2497 i = 0,
|
gyorgy@0
|
2498 lines = this.split2(trackText, /\r?\n/),
|
gyorgy@0
|
2499 entries = {text:[], times:[]},
|
gyorgy@0
|
2500 timecode,
|
gyorgy@0
|
2501 text;
|
gyorgy@0
|
2502
|
gyorgy@0
|
2503 for(; i<lines.length; i++) {
|
gyorgy@0
|
2504 // check for the line number
|
gyorgy@0
|
2505 if (this.pattern_identifier.exec(lines[i])){
|
gyorgy@0
|
2506 // skip to the next line where the start --> end time code should be
|
gyorgy@0
|
2507 i++;
|
gyorgy@0
|
2508 timecode = this.pattern_timecode.exec(lines[i]);
|
gyorgy@0
|
2509 if (timecode && i<lines.length){
|
gyorgy@0
|
2510 i++;
|
gyorgy@0
|
2511 // grab all the (possibly multi-line) text that follows
|
gyorgy@0
|
2512 text = lines[i];
|
gyorgy@0
|
2513 i++;
|
gyorgy@0
|
2514 while(lines[i] !== '' && i<lines.length){
|
gyorgy@0
|
2515 text = text + '\n' + lines[i];
|
gyorgy@0
|
2516 i++;
|
gyorgy@0
|
2517 }
|
gyorgy@0
|
2518
|
gyorgy@0
|
2519 // Text is in a different array so I can use .join
|
gyorgy@0
|
2520 entries.text.push(text);
|
gyorgy@0
|
2521 entries.times.push(
|
gyorgy@0
|
2522 {
|
gyorgy@0
|
2523 start: mejs.Utility.timeCodeToSeconds(timecode[1]),
|
gyorgy@0
|
2524 stop: mejs.Utility.timeCodeToSeconds(timecode[3]),
|
gyorgy@0
|
2525 settings: timecode[5]
|
gyorgy@0
|
2526 });
|
gyorgy@0
|
2527 }
|
gyorgy@0
|
2528 }
|
gyorgy@0
|
2529 }
|
gyorgy@0
|
2530
|
gyorgy@0
|
2531 return entries;
|
gyorgy@0
|
2532 },
|
gyorgy@0
|
2533
|
gyorgy@0
|
2534 translateTrackText: function(trackData, fromLang, toLang, googleApiKey, callback) {
|
gyorgy@0
|
2535
|
gyorgy@0
|
2536 var
|
gyorgy@0
|
2537 entries = {text:[], times:[]},
|
gyorgy@0
|
2538 lines,
|
gyorgy@0
|
2539 i
|
gyorgy@0
|
2540
|
gyorgy@0
|
2541 this.translateText( trackData.text.join(' <a></a>'), fromLang, toLang, googleApiKey, function(result) {
|
gyorgy@0
|
2542 // split on separators
|
gyorgy@0
|
2543 lines = result.split('<a></a>');
|
gyorgy@0
|
2544
|
gyorgy@0
|
2545 // create new entries
|
gyorgy@0
|
2546 for (i=0;i<trackData.text.length; i++) {
|
gyorgy@0
|
2547 // add translated line
|
gyorgy@0
|
2548 entries.text[i] = lines[i];
|
gyorgy@0
|
2549 // copy existing times
|
gyorgy@0
|
2550 entries.times[i] = {
|
gyorgy@0
|
2551 start: trackData.times[i].start,
|
gyorgy@0
|
2552 stop: trackData.times[i].stop,
|
gyorgy@0
|
2553 settings: trackData.times[i].settings
|
gyorgy@0
|
2554 };
|
gyorgy@0
|
2555 }
|
gyorgy@0
|
2556
|
gyorgy@0
|
2557 callback(entries);
|
gyorgy@0
|
2558 });
|
gyorgy@0
|
2559 },
|
gyorgy@0
|
2560
|
gyorgy@0
|
2561 translateText: function(text, fromLang, toLang, googleApiKey, callback) {
|
gyorgy@0
|
2562
|
gyorgy@0
|
2563 var
|
gyorgy@0
|
2564 separatorIndex,
|
gyorgy@0
|
2565 chunks = [],
|
gyorgy@0
|
2566 chunk,
|
gyorgy@0
|
2567 maxlength = 1000,
|
gyorgy@0
|
2568 result = '',
|
gyorgy@0
|
2569 nextChunk= function() {
|
gyorgy@0
|
2570 if (chunks.length > 0) {
|
gyorgy@0
|
2571 chunk = chunks.shift();
|
gyorgy@0
|
2572 mejs.TrackFormatParser.translateChunk(chunk, fromLang, toLang, googleApiKey, function(r) {
|
gyorgy@0
|
2573 if (r != 'undefined') {
|
gyorgy@0
|
2574 result += r;
|
gyorgy@0
|
2575 }
|
gyorgy@0
|
2576 nextChunk();
|
gyorgy@0
|
2577 });
|
gyorgy@0
|
2578 } else {
|
gyorgy@0
|
2579 callback(result);
|
gyorgy@0
|
2580 }
|
gyorgy@0
|
2581 };
|
gyorgy@0
|
2582
|
gyorgy@0
|
2583 // split into chunks
|
gyorgy@0
|
2584 while (text.length > 0) {
|
gyorgy@0
|
2585 if (text.length > maxlength) {
|
gyorgy@0
|
2586 separatorIndex = text.lastIndexOf('.', maxlength);
|
gyorgy@0
|
2587 chunks.push(text.substring(0, separatorIndex));
|
gyorgy@0
|
2588 text = text.substring(separatorIndex+1);
|
gyorgy@0
|
2589 } else {
|
gyorgy@0
|
2590 chunks.push(text);
|
gyorgy@0
|
2591 text = '';
|
gyorgy@0
|
2592 }
|
gyorgy@0
|
2593 }
|
gyorgy@0
|
2594
|
gyorgy@0
|
2595 // start handling the chunks
|
gyorgy@0
|
2596 nextChunk();
|
gyorgy@0
|
2597 },
|
gyorgy@0
|
2598 translateChunk: function(text, fromLang, toLang, googleApiKey, callback) {
|
gyorgy@0
|
2599
|
gyorgy@0
|
2600 var data = {
|
gyorgy@0
|
2601 q: text,
|
gyorgy@0
|
2602 langpair: fromLang + '|' + toLang,
|
gyorgy@0
|
2603 v: '1.0'
|
gyorgy@0
|
2604 };
|
gyorgy@0
|
2605 if (googleApiKey !== '' && googleApiKey !== null) {
|
gyorgy@0
|
2606 data.key = googleApiKey;
|
gyorgy@0
|
2607 }
|
gyorgy@0
|
2608
|
gyorgy@0
|
2609 $.ajax({
|
gyorgy@0
|
2610 url: 'https://ajax.googleapis.com/ajax/services/language/translate', // 'https://www.google.com/uds/Gtranslate', //'https://ajax.googleapis.com/ajax/services/language/translate', //
|
gyorgy@0
|
2611 data: data,
|
gyorgy@0
|
2612 type: 'GET',
|
gyorgy@0
|
2613 dataType: 'jsonp',
|
gyorgy@0
|
2614 success: function(d) {
|
gyorgy@0
|
2615 callback(d.responseData.translatedText);
|
gyorgy@0
|
2616 },
|
gyorgy@0
|
2617 error: function(e) {
|
gyorgy@0
|
2618 callback(null);
|
gyorgy@0
|
2619 }
|
gyorgy@0
|
2620 });
|
gyorgy@0
|
2621 }
|
gyorgy@0
|
2622 };
|
gyorgy@0
|
2623 // test for browsers with bad String.split method.
|
gyorgy@0
|
2624 if ('x\n\ny'.split(/\n/gi).length != 3) {
|
gyorgy@0
|
2625 // add super slow IE8 and below version
|
gyorgy@0
|
2626 mejs.TrackFormatParser.split2 = function(text, regex) {
|
gyorgy@0
|
2627 var
|
gyorgy@0
|
2628 parts = [],
|
gyorgy@0
|
2629 chunk = '',
|
gyorgy@0
|
2630 i;
|
gyorgy@0
|
2631
|
gyorgy@0
|
2632 for (i=0; i<text.length; i++) {
|
gyorgy@0
|
2633 chunk += text.substring(i,i+1);
|
gyorgy@0
|
2634 if (regex.test(chunk)) {
|
gyorgy@0
|
2635 parts.push(chunk.replace(regex, ''));
|
gyorgy@0
|
2636 chunk = '';
|
gyorgy@0
|
2637 }
|
gyorgy@0
|
2638 }
|
gyorgy@0
|
2639 parts.push(chunk);
|
gyorgy@0
|
2640 return parts;
|
gyorgy@0
|
2641 }
|
gyorgy@0
|
2642 }
|
gyorgy@0
|
2643
|
gyorgy@0
|
2644 })(mejs.$);
|
gyorgy@0
|
2645
|
gyorgy@0
|
2646
|