PageSourceSearch

http://cyclo-arc.fr/plugins/auto/mediaspip_player/javascript/mediaspip_player.js?1758133031

js cyclo-arc.fr collected 2026-10-08 23:16:29 UTC 50,466 bytes, 1,216 lines download raw bytes

1/**
2 * 
3 * MediaSPIP player
4 * 
5 * Player html5 pour les balises <audio> et <video>
6 * avec fallback vers version flash pour flv/mp4/mp3/aac
7 * 
8 * $version : 1.3.3
9 * © GNU/GPL v3 - kent1 (http://kent1.info - [email protected])
10 * cf : http://www.mediaspip.net/technical-documentation/plugins-used-by-mediaspip/html5-player-video-sound-media/
11 * 
12 * Remplace les controles des lecteurs html5 par défaut des navigateurs
13 * Remplace la balise <video> par un lecteur flash si on ne peut jouer le media :
14 * - sur Firefox si seulement la version mp4 ou flv est disponible et pas de version ogv ou ogg
15 * - sur Safari si seulement la version flv disponible et pas la mp4
16 * - sur IE dans tous les cas
17 * 
18 * Plugins jQuery compatibles et utilisés:
19 * - jQuery UI slider : http://jqueryui.com/slider/ (pour que les barres de progressions et de volume soient des sliders)
20 * - jQuery cookies : https://github.com/carhartl/jquery-cookie (Pour l'option qui garde en mémoire le niveau de volume)
21 * - jQuery mousewheel : https://github.com/brandonaaron/jquery-mousewheel (Diminue et augmente le volume lors d'un mousewheel sur le lecteur) 
22 * 
23 * Options : 
24 * - autoplay boolean true/false : lit automatiquement la video ou le son (défaut : false)
25 * - autoload boolean true/false : précharge automatiquement la video ou le son (défaut : true)
26 * - minwidth int : La largeur minimale
27 * - movieSize string 'adapt' uniquement pour l'instant :
28 * 	- "adapt" fais prendre la largeur du bloc parent à la vidéo
29 * - cookie_volume boolean true/false : met dans un cookie ms_volume le niveau de volume 
30 *   et dans html_volume_muted la valeur 'muted' si on a désactivé le son
31 *   play / pause / autres changements d'état... (defaut : true)
32 * - volume int : un int représentant un pourcentage de volume
33 * - volume_bloque boolean : bloquer le niveau de volume
34 * - volume_slider_orientation vertical|horizontal : permet de définir l'orientation du slider de volume (défaut vertical)
35 * - muted boolean : true si muted à l'initialisation, false sinon
36 * - muted_bloque boolean : true pour rendre impossible le changement de mute
37 * - boutons_caches array : un tableau des boutons à ne pas afficher ['fullscreen','volume','loop','time_remaining','time_elapsed','play_pause','progress_bar']
38 * - messages bool : si false, n'affiche pas les messages au dessus du player lors d'actions utilisateur
39 */
40
41(function($) {
42
43	/**
44	 * Vérifier si on a accès à l'API fullscreen de html5
45	 * http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/
46	 */
47	var fullScreenApi = {
48			supportsFullScreen: false,
49			isFullScreen: function() { return false; },
50			requestFullScreen: function() {},
51			cancelFullScreen: function() {},
52			fullScreenEventName: '',
53			prefix: ''
54	},browserPrefixes = 'webkit moz o ms khtml'.split(' ');
55
56	if (typeof document.cancelFullScreen != 'undefined') {
57		// check for native support
58		fullScreenApi.supportsFullScreen = true;
59	} else {
60		// check for fullscreen support by vendor prefix
61		for (var i = 0, il = browserPrefixes.length; i < il; i++ ) {
62			fullScreenApi.prefix = browserPrefixes[i];
63			if (typeof document[fullScreenApi.prefix + 'CancelFullScreen' ] != 'undefined' ) {
64				fullScreenApi.supportsFullScreen = true;
65				break;
66			}
67		}
68	}
69	// update methods to do something useful
70	if (fullScreenApi.supportsFullScreen) {
71		fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange';
72		fullScreenApi.isFullScreen = function() {
73			switch (this.prefix) {
74				case '':
75					return document.fullScreen;
76				case 'webkit':
77					return document.webkitIsFullScreen;
78				default:
79					return document[this.prefix + 'FullScreen'];
80			}
81		};
82		fullScreenApi.requestFullScreen = function(el) {
83			return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen']();
84		};
85		fullScreenApi.cancelFullScreen = function(el) {
86			return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen']();
87		};
88	}
89
90	window.fullScreenApi = fullScreenApi;
91
92	var slider = (typeof($.ui) == 'object') && (typeof($.ui.slider) == 'function'),
93		cookies = (typeof($.cookie) == 'function'),
94		stop_message_timeout = false,
95		error_message = false,
96		UA = navigator.userAgent,
97		IS_IE = /MSIE/.test(UA),
98		IS_IPAD = /iPad|MeeGo/.test(UA),
99		IS_IPHONE = /iP(hone|od)/i.test(UA),
100		IS_ANDROID = /Android/.test(UA),
101		IS_MOBILE = IS_IPAD || IS_ANDROID || IS_IPHONE;
102	
103	/**
104	 * Fonction d'initialisation du lecteur sur une balise <audio> ou <video>
105	 *
106	 * Exemple d'appel :
107	 * $('video').ms_player_init();
108	 */
109	$.extend($.fn, {
110		ms_player_init : function(options){
111			/**
112			 * Si c'est iTruc, cela ne fonctionne pas => on sort direct et on laisse la balise html5 faire ce qu'elle peut
113			 */
114			if(IS_IPHONE || IS_ANDROID){ return;}
115
116			var defaults = {
117				autoplay:false, // Lire automatiquement au chargement
118				autoload:true, // Précharger automatiquement au chargement
119				minwidth:null, // Largeur minimale
120				movieSize:'adapt',
121				ratio:null,
122				volume:100, // Niveau de volume au chargement
123				volume_bloque:false, // bloque le niveau de volume
124				volume_slider_orientation:'horizontal', // Si on a les sliders, orientation du slider de volume
125				volume_mousewheel:true,
126				muted:false, // Le lecteur n'est pas mute par défaut
127				muted_bloque:false, // On autorise le switch mute/unmute sur le lecteur
128				cookie_volume:false, // Garder le niveau de volume de l'utilisateur dans un cookie
129				messages:true, // Affiche ou non les messages sur le lecteur
130				boutons_caches:[]
131			};
132
133			options = $.extend(defaults, options);
134
135			var media = $(this), id = media[0], playable = false;
136
137			if(media.is(':hidden')) media.show();
138			if(media.is('audio')) options.movieSize = null;
139
140			/**
141			 * Test si le navigateur dispose du support des balises <video> ou <audio>
142			 */
143			if(typeof(id) != "undefined" && typeof(id.canPlayType) != "undefined"){
144				id.isFullScreen = id.has_html5_cover = false;
145				id.options = options;
146				
147				media.children('source').each(function(){
148					if(!$(this).attr('type').match('flv') && id.canPlayType($(this).attr('type')) !== ''){
149						if(($(this).attr('type').match('video/ogg') || $(this).attr('type').match('video/webm')) && /Safari/i.test(navigator.userAgent) && !/Chrome/i.test(navigator.userAgent)){
150							playable = false;
151						}else{
152							playable = true;
153							return false;
154						}
155					}
156				});
157				/**
158				 * Si le navigateur ne peut pas :
159				 * - Utiliser correctement les balises <audio> et <video>
160				 * - Jouer une des sources disponibles
161				 *
162				 * On essaie de faire un fallback en flash (mp3/flv/mp4/aac)
163				 */
164				if(!playable && (typeof($.fn.ms_test_fallback) == 'function'))
165					media.ms_test_fallback(options);
166				else{
167					var	wrapper = false,
168						control = false,
169						controls = false,
170						class_wrapper = '',
171						styles = ' style="',
172						style = true,
173						bloc_messages = '',
174						height = options.height,
175						width = options.width;
176					
177					id.mediacanplay = id.isFullScreen = id.slider_control = id.slider_volume = id.has_metadas = id.has_to_play = false;
178					id.percent_loaded = 0;
179					id.messages = options.messages;
180					id.type = (media.is('video')) ? 'video' : 'audio';
181
182					if(slider) id.slider = true;
183
184					if(typeof(media.attr('loop')) == 'string'){
185						class_wrapper += 'loop';
186						id.loop = true;
187					}
188					else id.loop = false;
189
190					if(typeof(media.attr('muted')) == 'string') id.muted = true;
191
192					if(!width){
193						if(media.attr('width')) width = media.attr('width');
194						else if(media.width() > 0) width = media.width();
195					}
196
197					if(!height){
198						if(media.attr('height')) height = media.attr('height');
199						else if(media.height() > 0) height = media.height();
200					}
201
202					if(id.controls) id.addcontrols = true;
203					id.controls = false;
204					class_wrapper += ' loading no_metadata';
205
206					if(media.prev().is('img'))
207						media.prev().wrap('<div class="html5_cover"></div>');
208
209					if(id.addcontrols){
210						media.wrap('<div class="media_wrapper '+id.type+' '+class_wrapper+'"></div>');
211						if(media.parents('.media_wrapper').prev().is('.html5_cover')){
212							var cover_html = media.parents('.media_wrapper').prev().html();
213							media.parents('.media_wrapper').prepend(cover_html);
214							media.parents('.media_wrapper').find('img').click(function(){
215								media.ms_play_pause();
216							});
217							media.parents('.media_wrapper').prev().detach();
218							if(media.parents('.media_wrapper').height() > 200)
219								id.has_html5_cover = true;
220						}
221						if(id.type == 'video' || id.has_html5_cover)
222							controls = '<div class="ms_splash"></div><div class="ms-waiting"><em> </em><em> </em><em> </em></div>';
223						else
224							controls = '';
225
226						controls += '<div class="controls small">';
227						if($.inArray('play_pause',options.boutons_caches) == '-1')
228						controls += '<div class="buttons_left">'
229								+'<span class="play_pause_button" title="'+ms_player_lang.bouton_loading+'"></span>'
230							+'</div>';
231						
232						if($.inArray('progress_bar',options.boutons_caches) == '-1'){
233							controls += '<div class="progress_bar">';
234							controls += ($.inArray('time_elapsed',options.boutons_caches) == '-1') ? '<em class="elapsed_time" title="'+ms_player_lang.info_ecoule+'"></em>' : '';
235							controls += '<div class="progress_back">'
236										+'<div class="progress_loading_wrapper">'
237											+'<div class="progress_loading_stripes"></div>'
238										+'</div>'
239										+'<div class="progress_buffered"></div>'
240										+'<div class="progress_elapsed_time"></div>'
241										+'<span class="progress_indicator"></span>'
242									+'</div>';
243							controls += ($.inArray('time_remaining',options.boutons_caches) == '-1') ? '<em class="remaining_time remaining" title="'+ms_player_lang.info_restant+'"></em>' : '';
244							controls += '</div>';
245						}
246
247						controls += '<div class="buttons_right">';
248						controls += ($.inArray('volume',options.boutons_caches) == '-1') ? '<span class="volume_button '+ (id.muted ? 'muted' : '') +'" title="'+ms_player_lang.bouton_volume+' ('+Math.floor(id.volume*100)+'%)"></span>' : '';
249
250						/**
251						 * Si on a les sliders, on ajoute une div ici pour avoir un slider de volume
252						 */
253						controls += (slider && $.inArray('volume',options.boutons_caches) == '-1') ? '<span class="volume_slider_container '+options.volume_slider_orientation+'"><span class="volume_slider"></span></span>' : '';
254						controls += (media.is('video') && $.inArray('fullscreen',o
254ptions.boutons_caches) == '-1') ? '<span class="fullwindow_button" title="'+ms_player_lang.bouton_fullscreen+'"></span>' : '';
255						controls += ($.inArray('loop',options.boutons_caches) == '-1') ? '<span class="loop_button" title="'+ms_player_lang.bouton_loop+'"></span>' : '';
256						controls +='</div>';
257						wrapper = media.parent();
258						wrapper.append(controls);
259						control = wrapper.find('.controls');
260					}
261
262					if(id.type == 'video'){
263						if(options.height)
264							media.parent().height(height);
265						if(options.width && options.width != '100%')
266							media.parent().width(width);
267						else if(options.width && options.width != '100%')
268							media.parent().css({width:'auto'}).removeAttr('width');
269						else if(options.width && options.width == '100%')
270							id.options.movieSize = options.movieSize = 'adapt';
271					}else
272						media.parent().width(width);
273
274					if(!wrapper) wrapper = media.parent();
275
276					if(id.type == 'video' && !height){
277						height = media.parents('.media_wrapper').find('.controls').height();
278						media.parents('.media_wrapper').height(height);
279					}
280
281					if(wrapper){
282						if(options.minwidth && media.width() > options.minwidth) wrapper.width(options.minwidth);
283
284						if(wrapper.height() < 100) options.messages = false;
285
286						if(id.addcontrols && options.messages){
287							bloc_messages = '<div class="messages" style="display:none"></div>';
288							wrapper.append(bloc_messages);
289						}
290					}
291
292					if(control){
293						var elapsed_time = control.find('.elapsed_time'),
294							remaining_time = control.find('.remaining_time'),
295							progress_indicator = control.find('.progress_indicator'),
296							progress_elapse = control.find('.progress_elapsed_time');
297						media.ms_resize_controls();
298					}
299					
300					//if(!IS_IPAD){
301						media.bind("loadedmetadata",function(e){
302							id.has_metadatas = true;
303							media.ms_start('loadedmetadata');
304							if(wrapper) wrapper.removeClass('no_metadata').removeClass('loading').addClass('has_metadata');
305							if(id.has_to_play) media.ms_buttons();
306							/**
307							 * Cas d'un stream audio (Radio)
308							 */
309							if(id.duration == 'Infinity'){
310								id.isstream = true;
311								control.find('.progress_back').detach();
312								remaining_time.addClass('total_time').attr('title','').html(ms_player_lang.info_streaming);
313							}
314							media.ms_resize_controls();
315						}).bind("error", function(e){
316							if (id.error) {
317								switch (id.error.code) {
318									case 1:
319										error_message = ms_player_lang.statut_error_stopped;
320										break;
321									case 2:
322										error_message = ms_player_lang.statut_error_network;
323										break;
324									case 3:
325										error_message = ms_player_lang.statut_error_broken;
326										break;
327									case 4:
328										error_message = ms_player_lang.statut_error;
329										break;
330									default:
331										error_message = ms_player_lang.statut_error;
332										break;
333								}
334								if(options.messages && error_message) media.ms_messages('error',error_message);
335								wrapper.removeClass('loading').addClass('player_error').find('.play_pause_button').attr('title',ms_player_lang.info_erreur);
336							}
337						}).bind("timeupdate", function(e){
338							if(id.addcontrols){
339								if(id.percent_loaded != 100) media.ms_update_loaded(e);
340
341								var percent_time = ms_anything_to_percent(id.currentTime,id.duration);
342								if(remaining_time.is('.remaining') && (id.duration != 'Infinity'))
343									remaining_time.text('-'+ms_second_to_time(id.duration - id.currentTime));
344
345								elapsed_time.text(ms_second_to_time(id.currentTime));
346								if(slider && (typeof(id.slider_control) == 'object')){
347									progress_elapse.css('width',percent_time+'%');
348									id.slider_control.slider("value", percent_time);
349								}else
350									progress_indicator.css('left',percent_time+'%');
351
352								media.ms_resize_controls();
353							}
354						}).bind("seeking",function(e){
355							if(id.addcontrols) wrapper.addClass('seeking').find('.play_pause_button').attr('title',ms_player_lang.bouton_seeking);
356						}).bind("seeked",function(e){
357							if(id.addcontrols){
358								wrapper.removeClass('seeking');
359								if(id.paused)
360									wrapper.find('.play_pause_button').removeClass('pause').attr('title',ms_player_lang.bouton_pause);
361								else
362									wrapper.find('.play_pause_button').addClass('pause').attr('title',ms_player_lang.bouton_lire);
363							}
364						}).bind("progress", function(e){
365							if(id.addcontrols && id.percent_loaded != 100) media.ms_update_loaded(e);
366						}).bind("pause", function(e){
367							if(id.addcontrols) media.ms_buttons();
368						}).bind("play", function(e){
369							if(id.preload == 'none') id.preload = false;// Fix pour chromium
370							if(id.addcontrols){
371								if(id.percent_loaded != 100) media.ms_update_loaded(e);
372								media.ms_buttons();
373							}
374						}).bind("ended", function(e){
375							if(id.addcontrols){
376								if(!id.loop){
377									wrapper.addClass('ended').find('.play_pause_button').removeClass('pause').attr('title',ms_player_lang.bouton_lire);
378									id.paused = true;
379								}else{
380									id.currentTime = 0;
381									id.play();
382								}
383							}
384						}).bind("loadeddata", function(e){
385							if(id.addcontrols) media.ms_update_loaded(e);
386						}).bind("volumechange", function(e){
387							media.ms_volume(false);
388						}).click(function(){
389							if(id.addcontrols) media.ms_play_pause();
390						}).dblclick(function(e){
391							if(id.addcontrols) media.ms_fullscreen();
392							e.preventDefault();
393							e.stopPropagation();
394						});
395
396						document.addEventListener(fullScreenApi.fullScreenEventName, function(e){
397							if(id.isFullScreen && !fullScreenApi.isFullScreen())
398								media.ms_fullscreen();
399							media.ms_resize_controls();
400						}, true);
401
402						media.parent().find('.ms_splash').click(function(){
403							if((id.paused || id.ended) && $(this).is(':visible')){
404								wrapper.removeClass('paused').removeClass('ended');
405								if(!id.has_metadatas)
406									wrapper.addClass('loading');
407								media.ms_play_pause();
408							}
409						});
410
411						if(wrapper){
412							var stop_timeout = false,
413								last_moved=0,
414								clientx = 0,
415								clienty = 0;
416							wrapper.mousemove(function(e){
417								if(id.isFullScreen && !id.paused){
418									if ((e.timeStamp - last_moved > 1000) && ((e.clientX != clientx) || (e.clientY != clienty))) {
419										wrapper.addClass('hover');
420										clearTimeout(stop_timeout);
421										var full_onmousestop = function() { wrapper.removeClass('hover'); };
422										stop_timeout = setTimeout(full_onmousestop, 1500);
423										last_moved = e.timeStamp;
424										clientx = e.clientX;
425										clienty = e.clientY;
426									}
427								}
428							});
429						}
430
431						/**
432						 * Les actions sur les éléments des controles :
433						 *
434						 * - Le switch Play/Pause sur le click du bouton adéquat
435						 * - Seek lors d'un click sur la barre de progression
436						 * - Le switch Mute/Unmute sur le click du bouton de volume
437						 * - Le switch fullscreen/normal screen sur le bouton adéquat
438						 */
439						if(id.addcontrols){
440							control.find('.play_pause_button').click(function(){
441								media.ms_play_pause();
442							});
443
444							control.find('.progress_back').click(function(e){
445								if(!slider)
446									media.ms_seek_to(e.clientX,slider);
447							});
448
449							if($.inArray('volume',options.boutons_caches) == '-1' && !options.muted_bloque){
450								control.find('.volume_button').click(function(e){
451									media.ms_volume(true);
452								});
453							}
454
455							if($.inArray('fullscreen',options.boutons_caches) == '-1'){
456								control.find('.fullwindow_button').click(function(e){
457									media.ms_fullscreen();
458								});
459							}
460
461							if($.inArray('loop',options.boutons_caches) == '-1'){
462								control.find('.loop_button').click(function(e){
463									media.ms_loop();
464								});
465							}
466							remaining_time.click(function(e){
467								if(!id.isstream){
468									if($(this).is('.remaining')){
469										$(this).removeClass('remaining').addClass('total_time')
470											.attr('title',ms_player_lang.info_total)
471											.html(ms_second_to_time(id.duration));
472									}else{
473										$(this).removeClass('total_time').addClass('remaining')
474											.attr('title',ms_player_lang.info_restant)
475											.html('-'+ms_second_to_time(id.duration - id.currentTime));
476									}
477									media.ms_resize_controls();
478								}
479							});
480						}
481						/**
482						 * Fonction modifiant le niveau de volume au scroll sur le lecteur
483						 * Cette action fonctionne au scroll au hover du lecteur.
484						 * Nécessite le plugin jQuery mousewheel :
485						 * http://github.com/brandonaaron/jquery-mousewheel
486						 *
487						 * - bloque l'évènement normal du scroll (descendre dans la page);
488						 * - baisse le volume de 10% lors d'un scroll bas avec la souris;
489						 * - augmente le volume de 10% lors d'un scroll haut avec la souris;
490						 * - si le volume est "muted", l'action ne fait rien sur le volume;
491						 */
492						if(id.addcontrols && wrapper && !options.volume_bloque && typeof($.fn.mousewheel) != "undefined" && options.volume_mousewheel){
493							wrapper.mousewheel(function(event, delta) {
494								if(!id.muted && id.duration){
495									var volume_new = Math.round((id.volume + parseFloat((delta > 0) ? '0.1' : '-0.1'))*10)/10;
496									if((volume_new <= 1) && (volume_new >= 0)) id.volume = volume_new;
497								}
498								event.preventDefault();
499							});
500						}
501					}
502					media.ms_start('canplay');
503				//}
504			}else
505				media.ms_test_fallback(options);
506			this.trigger('ms_init');
507		},
508		ms_start : function(action){
509			var media = $(this),
510				id = media[0],
511				options = id.options,
512				wrapper = media.parent(),
513				control = id.addcontrols ? wrapper.find('.controls') : false,
514				elapsed_time = id.addcontrols ? control.find('.elapsed_time') : false,
515				remaining_time = id.addcontrols ? control.find('.remaining_time') : false;
516
517			if(!id.mediacanplay || action == 'loadedmetadata'){
518				if(wrapper.hasClass('player_error'))
519					wrapper.removeClass('player_error').addClass('loading');
520
521				id.mediacanplay = true;
522
523				var width_wrapper = media.width(), parent_width = wrapper.parent().width();
524				if(id.videoHeight && id.videoWidth){
525					id.has_metadatas = true;
526					if(wrapper.hasClass('loading'))
527						wrapper.removeClass('loading').removeClass('no_metadata').addClass('has_metadata');
528					id.ratio = id.videoWidth/id.videoHeight;
529				}
530				else if(options.ratio) id.ratio = options.ratio;
531				else id.ratio = media.width()/media.height();
532
533				if(options.movieSize == 'adapt' && !id.isFullScreen && (!media.hasClass('noresize') || (options.movieSize != 'noresize'))){
534					/**
535					 * En mode adapt :
536					 * - on dimensionne la largeur à 100%
537					 * - on dimensionne la hauteur à un ratio correspondant au ratio réel de la vidéo 
538					 * par rapport à la largeur du bloc parent
539					 */
540					width_wrapper = parent_width;
541					if(id.videoHeight && id.videoWidth){
542						var ratio = (width_wrapper/id.videoWidth),
543							height_final = (id.videoHeight*ratio).toFixed();
544						id.ratio = (id.videoWidth/id.videoHeight);
545					}else
546						var height_final = width_wrapper/id.ratio;
547
548					if(id.type == 'video' && wrapper.height() != height_final){
549						wrapper.css({width:'auto'}).animate({height:height_final+'px'},'fast',function(){
550							media.animate({height:'100%',width:'100%'},'fast').removeAttr('height').removeAttr('width').ms_resize_controls();
551						}).removeAttr('width');
552					}else{
553						wrapper.css({width:'auto'}).removeAttr('width');
554						media.animate({width:'100%'},'fast').ms_resize_controls();
555					}
556					media.removeAttr('height');
557					var handler_media_resize = function(){
558						if(!id.isFullScreen){
559							wrapper.css({width:'auto'}).css({height:(wrapper.width()/id.ratio)+'px'});
560							media.ms_resize_controls();
561						}
562					};
563					$(window).unbind('resize',handler_media_resize).bind('resize',handler_media_resize);
564				}else if(!media.hasClass('noresize') && (options.movieSize != 'noresize')){
565					/**
566					 * En mode normal, on redimentionne la hauteur de la vidéo en fonction 
567					 * du ratio réel récupéré des métadonnées
568					 */
569					if(!options.height){
570						media.removeAttr('height');
571						if(id.type == 'video'){
572							wrapper.height(media.width()/id.ratio);
573							media.animate({height:'100%',width:'100%'},'fast').removeAttr('height').removeAttr('width').ms_resize_controls();
574						}
575					}else if(id.type == 'video'){
576						wrapper.add(media).width(media.height()*id.ratio).removeAttr('width');
577						media.animate({width:'100%'},'fast')
578						media.removeAttr('height');
579					}
580				}
581
582				if(id.addcontrols){
583					if(wrapper.hasClass('loading'))
584						wrapper.removeClass('loading').addClass('paused').find('.play_pause_button').attr('title',ms_player_lang.bouton_lire);
585
586					if(remaining_time && remaining_time.is('.remaining') && (id.duration != 'Infinity') && !isNaN(id.duration))
587						remaining_time.text('-'+ms_second_to_time(id.duration));
588
589					elapsed_time.text(ms_second_to_time(id.currentTime));
590
591					try {
592						arg.buffer = id.buffered.end(null);
593					} catch (ignored) {}
594
595					if((id.networkState == 2) && id.duration && !isNaN(id.duration) && id.buffer)
596						control.find('.progress_buffered').css('width', ms_anything_to_percent(id.buffered.end(0),id.duration)+'%');
597
598					if(slider){
599						var replay = false;
600						control.find('.progress_indicator').hide();
601						control.find('.progress_back').unbind('click');
602						id.slider_control = control.find('.progress_back').slider({
603							min: 0,
604							max: 100,
605							range: "min",
606							slide: function(event,ui){
607								/**
608								 * - On change les valeurs de temps
609								 * - On fait avancer la barre de lecture sans lancer la lecture
610								 */
611								control.find('.progress_elapsed_time').css('width',ui.value+'%');
612								if(remaining_time.is('.remaining') && (id.duration != 'Infinity'))
613									remaining_time.text('-'+ms_percent_to_time((100 - ui.value),id.duration));
614								elapsed_time.text(ms_percent_to_time(ui.value,id.duration));
615							},
616							stop: function(event,ui){
617								/**
618								 * On saute la lecture au bon endroit ?
619								 */
620								media.ms_seek_to(event.clientX,true,false);
621							}
622						});
623
624						if($.inArray('volume',options.boutons_caches) == '-1'){
625							id.slider_volume = control.find('.volume_slider').slider({
626								value: Math.floor(id.volume*100),
627								orientation: options.volume_slider_orientation,
628								min:0,
629								max:100,
630								disabled: (options.volume_bloque || id.muted) ? true : false,
631								range: "min",
632								slide: function(event,ui){
633									/**
634									 * On change le volume
635									 */
636									var volume_new = ui.value/100;
637									if((volume_new <= 1) && (volume_new >= 0)) id.volume = volume_new;
638								},
639								stop: function(event,ui){
640									/**
641									 * On change le volume et on le sauvegarde dans le cookie si nécessaire
642									 */
643									var volume_new = ui.value/100;
644									if((volume_new <= 1) && (volume_new >= 0)) id.volume = volume_new;
645								}
646							});
647						}
648					}
649					id.volume = Math.floor(parseInt(options.volume)/100);
650
651					if(!options.volume_bloque && !options.volume && cookies && options.cookie_volume){
652						var volume_cookie = parseFloat($.cookie('ms_volume'));
653						if((volume_cookie >= 0) && (volume_cookie <= 1))
654							id.volume = volume_cookie;
655						if(($.cookie('ms_volume_muted') == 'muted') && !id.muted)
656							media.ms_volume(true);
657					}
658				}
659			}
660			if(id.addcontrols){
661				if(options.autoplay && id.mediacanplay){
662					wrapper.removeClass('paused').find('.play_pause_button').addClass('pause').attr('title',ms_player_lang.bouton_pause);
663					id.play();
664				}
665				wrapper.attr("tabindex",-1).hover(function(){$(this).focus();}).unbind('keydown').keydown(function(e) {
666					$(this).unbind('keyup').keyup(function(e){e.stopPropagation();e.preventDefault();}).ms_activate_keys(e);
667				});
668				/**
669				 * Il se peut que la vidéo soit déjà chargée, donc ne passera pas par loadedmetadata
670				 */
671				if(id.duration && wrapper.is('.no_metadata'))
672					wrapper.removeClass('no_metadata').removeClass('loading').addClass('has_metadata');
673				media.ms_resize_controls();
674			}
675
676			this.trigger('ms_start');
677		},
678		ms_buttons : function(){
679			var media = $(this),
680				id = media[0],
681				wrapper = media.parent('.media_wrapper');
682			if(id.addcontrols){
683				if(id.paused){
684					wrapper.removeClass('loading').addClass('paused').find('.play_pause_button').removeClass('pause').attr('title',ms_player_lang.bouton_lire);
685					media.ms_messages('pause',ms_player_lang.statut_pause);
686				}
687				else if (id.ended){
688					wrapper.removeClass('loading').removeClass('paused').removeClass('ended').find('.play_pause_button').addClass('pause').attr('title',ms_player_lang.bouton_pause);
689					id.currentTime = id.startTime ? id.startTime : '0';
690					if(!id.options.volume_bloque && cookies && id.options.cookie_volume){
691						var volume_cookie = parseFloat($.cookie('ms_volume'));
692						if((volume_cookie >= 0) && (volume_cookie <= 1))
693							id.volume = volume_cookie;
694						if($.cookie('ms_volume_muted') == 'muted')
695							id.muted = true;
696					}
697				}
698				else{
699					// On a déjà les metadonnées
700					if(id.has_metadatas){
701						wrapper.removeClass('loading').removeClass('paused').removeClass('ended').find('.play_pause_button').addClass('pause').attr('title',ms_player_lang.bouton_pause);
702						media.ms_messages('play',ms_player_lang.statut_play);
703					}else{
704						wrapper.addClass('loading');
705						id.has_to_play = true;
706					}
707					if(!id.options.volume_bloque && cookies && id.options.cookie_volume){
708						var volume_cookie = parseFloat($.cookie('ms_volume'));
709						if((volume_cookie >= 0) && (volume_cookie <= 1))
710							id.volume = volume_cookie;
711						if($.cookie('ms_volume_muted') == 'muted')
712							id.muted = true;
713					}
714				}
715			}
716		},
717		ms_play_pause : function(){
718			var id = $(this)[0];
719			if(id.addcontrols && id.mediacanplay && !id.seeking){
720				if(id.paused || id.ended){
721					id.play();
722					$(this).parent().removeClass('paused').removeClass('ended');
723					this.trigger('ms_play');
724				}else{
725					id.pause();
726					$(this).parent().addClass('paused');
727					this.trigger('ms_pause');
728				}
729			}
730		},
731		/**
732		 * Fonction de modification du volume
733		 * 
734		 * Paramètres :
735		 * - mute boolean (true/false) : signifie si le media est muted ou pas;
736		 */
737		ms_volume : function(mute){
738			var media = $(this),
739				id = media[0],
740				controls = media.parent().find('.controls'),
741				options = id.options;
742			if(id.addcontrols && id.mediacanplay){
743				if(mute){
744					if(id.muted){
745						media.ms_messages('mute',ms_player_lang.statut_unmute);
746						var volume_title = ms_player_lang.bouton_volume+' ('+Math.floor(id.volume*100)+'%)';
747						controls.find('.volume_button').removeClass('muted').attr('title',volume_title);
748						id.muted = false;
749						if(id.slider && (typeof(id.slider_volume) == 'object'))
750							id.slider_volume.slider('value',(id.volume*100)).slider((options.volume_bloque) ? 'disable' : 'enable');
751						if(cookies && options.cookie_volume)
752							$.cookie('ms_volume_muted',null);
753					}else{
754						media.ms_messages('mute',ms_player_lang.statut_mute);
755						controls.find('.volume_button').addClass('muted').attr('title',ms_player_lang.bouton_volume_muted);
756						id.muted = true;
757						if(id.slider && (typeof(id.slider_volume) == 'object'))
758							id.slider_volume.slider('disable');
759						if(cookies && options.cookie_volume)
760							$.cookie('ms_volume_muted','muted');
761					}
762				}else if(!id.muted){
763					var volume = id.volume,
764						sound_button = controls.find('.volume_button'),
765						class_remove = (controls.length > 0) ? sound_button.attr('class').match('volume_button_[0-9]{1,3}') : null;
766					if(options.volume_bloque && options.volume) volume = id.volume = (options.volume) ? id.volume : options.volume;
767					
768					if((volume <= 0.66) && (volume > 0.33)){
769						if(class_remove !== null) sound_button.removeClass(class_remove[0]);
770						sound_button.addClass('volume_button_66');
771					}else if((volume <= 1) && (volume > 0.66)){
772						if(class_remove !== null) sound_button.removeClass(class_remove[0]);
773						sound_button.addClass('volume_button_100');
774					}else if((volume <= 0.33) && (volume > 0)){
775						if(class_remove !== null) sound_button.removeClass(class_remove[0]);
776						sound_button.addClass('volume_button_33');
777					}else if(volume === 0){
778						if(class_remove !== null) sound_button.removeClass(class_remove[0]);
779						sound_button.addClass('volume_button_0');
780					}
781					var volume_title = ms_player_lang.bouton_volume+' ('+Math.floor(id.volume*100)+'%)';
782					controls.find('.volume_button').attr('title',volume_title);
783					if(id.slider && (typeof(id.slider_volume) == 'object')){
784						id.slider_volume.slider('value',(id.volume*100));
785						id.slider_volume.slider((options.volume_bloque) ? 'disable' : 'enable');
786					}
787					media.ms_messages('volume',volume_title);
788
789					if(cookies && options.cookie_volume)
790						$.cookie('ms_volume', id.volume);
791				}
792			}
793		},
794		/**
795		 * Fonction de saut d'un point à un autre dans le média
796		 * Utilisée lors d'un click sur la barre de progression
797		 *
798		 * Prends deux arguments :
799		 * - La position du curseur de la souris lors du click sur la barre de progression
800		 * - slider : si on a ou non les sliders d'activé
801		 */
802		ms_seek_to : function(cursor_position){
803			if(!$(this)[0].controls){
804				var media = $(this),
805					id = media[0],
806					was_playing = false,
807					controls = media.parent().find('.controls'),
808					progress = controls.find('.progress_back'),
809					percent = Math.floor(((parseInt(cursor_position)-parseInt(progress.offset().left))/ parseInt(progress.width())) * 100),
810					time = Math.floor((id.duration * percent) / 100),
811					time_affiche = ms_second_to_time(time);
812
813				if(typeof(id.slider_control) != "object"){
814					controls.find('.progress_elapsed_time').css('width',percent+'%');
815					controls.find('.progress_indicator').css('left',percent+'%');
816				}
817
818				if(id.currentTime > time)
819					media.ms_messages('seek_back',ms_player_lang.statut_seek_back+' '+time_affiche);
820				else
821					media.ms_messages('seek_to',ms_player_lang.statut_seek_to+' '+time_affiche);
822
823				id.currentTime = time;
824			}
825		},
826		/**
827		 * ms_seek_to_percent
828		 * 
829		 * On seek à X% de la video ou du son
830		 * 
831		 * Paramètres : 
832		 * - percent int : le pourcentage;
833		 * - slider boolean true/false : le slider si présents;
834		 * - update_slider boolean true/false : doit on mettre à jour le slider (pas utile quand on vient du slider justement);
835		 */
836		ms_seek_to_percent : function(percent,update_slider){
837			if($(this)[0].controls) return;
838			var media = $(this),
839				id = media[0],
840				duration = id.duration, 
841				currenttime = id.currentTime;
842
843			if(((currenttime === duration) && (percent === 100)) || ((currenttime === 0) && (percent === 0)))
844				return false;
845
846			var time = (percent === 0) ? 0 : ((duration * percent) / 100),
847				time_affiche = ms_second_to_time(time);
848
849			if(currenttime > time)
850				media.ms_messages('seek_back',ms_player_lang.statut_seek_back+' '+time_affiche);
851			else
852				media.ms_messages('seek_to',ms_player_lang.statut_seek_to+' '+time_affiche);
853
854			id.currentTime = time;
855
856			if(typeof(id.slider_control) != "object"){
857				var controls = media.parent().find('.controls');
858				controls.find('.progress_elapsed_time').css('width',percent+'%');
859				controls.find('.progress_indicator').css('left',percent+'%');
860			}else if(update_slider)
861				id.slider_control.slider("value", percent);
862		},
863		/**
864		 * Activer ou désactiver la boucle (mode loop)
865		 */
866		ms_loop : function(){
867			var media = $(this),
868				id = media[0],
869				wrapper = media.parent();
870			if(id.controls) return;
871			if(!id.loop && !wrapper.hasClass('loop')){
872				media.attr('title',ms_player_lang.bouton_loop_looped).ms_messages('loop',ms_player_lang.statut_loop);
873				wrapper.addClass('loop');
874				if (typeof(id.loop) == 'boolean') id.loop = true;
875			}else{
876				media.attr('title',ms_player_lang.bouton_loop).removeAttr('loop').ms_messages('unloop',ms_player_lang.statut_unloop);
877				wrapper.removeClass('loop');
878				if (typeof(id.loop) == 'boolean') id.loop = false;
879			}
880		},
881		ms_fullscreen : function(){
882			if($(this)[0].controls) return;
883			var media = $(this), id = media[0], wrapper = media.parent(), id_wrapper = wrapper[0];
884			if(id.mediacanplay){
885				if(!id.isFullScreen){
886					id.videoOrigWidth = media.width();
887					id.videoOrigHeight = media.height();
888					id_wrapper.origWidth = wrapper.width();
889					id_wrapper.origHeight = wrapper.height();
890					id.isFullScreen = true;
891					if (fullScreenApi.supportsFullScreen)
892						media.ms_fullscreen_resize();
893					else{
894						$('body').css({'overflow' : 'hidden', '-moz-user-select' : 'none'});
895						media.ms_fullscreen_resize();
896						var handler_fullscreen_resize = function(){ media.ms_fullscreen_resize(); };
897						$(window).unbind('resize',handler_fullscreen_resize).bind('resize',handler_fullscreen_resize);
898					}
899				}else{
900					if (fullScreenApi.supportsFullScreen) {
901						(fullScreenApi.prefix === '') ? document.cancelFullScreen() : document[fullScreenApi.prefix + 'CancelFullScreen']();
902						var handler_resize = function(){
903							wrapper.css({width:id_wrapper.origWidth,height:id_wrapper.origHeight}).removeClass('media_wrapper_full');
904							media.ms_resize_controls();
905						};
906						wrapper.bind('ms_fullscreen_resize',handler_resize);
907					}else{
908						var handler_resize = function(){
909							wrapper.removeClass('media_wrapper_full').animate({width:id_wrapper.origWidth+'px',height:id_wrapper.origHeight+'px',left:'0',top:'0'},500,function(){
910								media.ms_resize_controls();
911							});
912						};
913						wrapper.bind('ms_fullscreen_resize',handler_resize);
914						var media_handler_resize = function(){
915							media.animate({width:id.videoOrigWidth+'px',height:id.videoOrigHeight+'px',left:'0',top:'0'},500,function(){
916								media.ms_resize_controls();
917							});
918						};
919						media.bind('ms_fullscreen_resize',media_handler_resize);
920						$('body').css({'overflow' : 'inherit', '-moz-user-select' : 'inherit'});
921						$(window).unbind('resize');
922					}
923					wrapper.add(media).trigger('ms_fullscreen_resize');
924					wrapper.unbind('ms_fullscreen_resize',handler_resize);
925					media.unbind('ms_fullscreen_resize',media_handler_resize);
926					wrapper.find('.controls').addClass('small').find('span.fullwindow_button').attr('title',ms_player_lang.bouton_fullscreen);
927					id.isFullScreen = false;
928				}
929			}
930		},
931		ms_fullscreen_resize : function(){
932			if($(this)[0].controls) return;
933			var media = $(this), id = media[0], wrapper = media.parent(), id_wrapper = wrapper[0];
934
935			wrapper.css({width:'100%',height:'100%',left:'0',top:'0'}).addClass('media_wrapper_full').find('.controls').removeClass('small')
936				.find('span.fullwindow_button').attr('title',ms_player_lang.bouton_fullscreen_full);
937
938			if (fullScreenApi.supportsFullScreen) {
939				(fullScreenApi.prefix === '') ? id_wrapper.requestFullScreen() : id_wrapper[fullScreenApi.prefix + 'RequestFullScreen']();
940			}else{
941				var window_width = window.innerWidth,
942					window_height = window.innerHeight,
943					ratio = (window_height/id.videoHeight),
944					width_final = (id.videoWidth*ratio).toFixed();
945				if(width_final > window_width){
946					var ratio = (window_width/id.videoWidth),
947						height_final = (id.videoHeight*ratio).toFixed(),
948						top = ((window_height-height_final)/2).toFixed();
949					media.css({position:'absolute',width:window_width+'px',height:height_final+'px',top:top+'px',left:'0'});
950				}else{
951					var left = ((window_width-width_final)/2).toFixed();
952					media.css({position:'auto',width:width_final+'px',height:window_height+'px',left:left+'px',top:'0'});
953				}
954			}
955			media.ms_resize_controls();
956		},
957
958		/**
959		 * Change dynamiquement la taille de la barre de progression et de son conteneur
960		 * en fonction de la taille du lecteur.
961		 * 
962		 * @param force boolean true / false : permet d'éviter de boucle lorsque la taille du lecteur est petite
963		 * 
964		 * La largeur du conteneur de la barre de progession correspond à :
965		 * - La largeur du lecteur
966		 * - Moins la largeur des boutons de gauche (inclus leurs padding, leurs marges, et leurs bordure droite et gauche)
967		 * - Moins la largeur des boutons de droite (inclus leurs padding, leurs marges, et leurs bordure droite et gauche)
968		 * - Moins les marges, padding et margin css de la barre de progression elle-même
969		 *
970		 * La largeur de la barre de progression elle-même correspond à :
971		 * - La largeur de son conteneur
972		 * - Moins la largeur de l'indication de temps ecoulé (inclus ses margins, padding et bordures droite et gauche)
973		 * - Moins la largeur de l'indication de temps restant (inclus ses margins, padding et bordures droite et gauche)
974		 * 
975		 * Si on a un petit lecteur, que l'on a le slider de volume et que celui-ci est horizontal, on le force à passer vertical
976		 * 
977		 */
978		ms_resize_controls : function(force){
979			if($(this)[0].controls || !$(this)[0].addcontrols) return;
980			var media = $(this), id = media[0], wrapper = media.parent(), 
981				id_wrapper = wrapper[0], controls = wrapper.find('.controls'),
982				play_width = controls.find('.buttons_left').outerWidth()+parseFloat(controls.find('.buttons_left').css('margin-left'))+parseFloat(controls.find('.buttons_left').css('margin-right')),
983				sound_width = controls.find('.buttons_right').outerWidth()+parseFloat(controls.find('.buttons_right').css('margin-left'))+parseFloat(controls.find('.buttons_right').css('margin-right')),
984				progresswidth = parseFloat(controls.width())-parseFloat(play_width)-parseFloat(sound_width) - parseFloat(controls.find('.progress_bar').css('border-left-width')) - parseFloat(controls.find('.progress_bar').css('border-right-width'))-parseFloat(controls.find('.progress_bar').css('margin-right')) - parseFloat(controls.find('.progress_bar').css('margin-left')) - parseFloat(controls.find('.progress_bar').css('padding-right')) - parseFloat(controls.find('.progress_bar').css('padding-left')) -1;
985
986			controls.find('.progress_bar').width(progresswidth);
987
988			var remaining_width = controls.find(".remaining_time").outerWidth()+parseFloat(controls.find('.remaining_time').css('margin-left'))+parseFloat(controls.find('.remaining_time').css('margin-right')),
989				elapsed_width = controls.find(".elapsed_time").outerWidth()+parseFloat(controls.find('.elapsed_time').css('margin-left'))+parseFloat(controls.find('.elapsed_time').css('margin-right'));
990
991			if((controls.find(".remaining_time").size() == 0) || controls.find(".remaining_time").is(':hidden')) remaining_width = 0;
992			if((controls.find(".elapsed_time").size() == 0) || controls.find(".elapsed_time").is(':hidden')) elapsed_width = 0;
993
994			var progressback_width = progresswidth - elapsed_width - remaining_width - parseFloat(controls.find('.progress_back').css('border-left-width')) - parseFloat(controls.find('.progress_back').css('border-right-width'))-parseFloat(controls.find('.progress_back').css('margin-right')) - parseFloat(controls.find('.progress_back').css('margin-left')) - parseFloat(controls.find('.progress_back').css('padding-right')) - parseFloat(controls.find('.progress_back').css('padding-left'))-2;
995			if(slider && progressback_width < 0 && !force){
996				if(id.slider && (typeof(id.slider_volume) == 'object')){
997					id.slider_volume.slider('option',{'orientation':'vertical'});
998					controls.find('.volume_slider_container').removeClass('horizontal').addClass('vertical');
999				}
1000				media.ms_resize_controls(true);
1001			}else{
1002				if(controls.find('.remaining_time').is(':hidden') && controls.find('.loop_button').is(':visible') && progressback_width < 30){
1003					controls.find('.loop_button').hide();
1004					controls.ms_resize_controls(true);
1005				}
1006				else if(controls.find('.remaining_time').is(':visible') && progressback_width < 30){
1007					controls.find('.remaining_time').hide();
1008					media.ms_resize_controls(true);
1009				}else if(controls.find('.remaining_time').is(':hidden') && progressback_width < 30){
1010					controls.find('.progress_back').hide();
1011					return;
1012				}
1013				controls.find('.progress_back').width(progressback_width);
1014			}
1015		},
1016		/**
1017		 * Modifie le message dans la boite de message si présente
1018		 * 
1019		 * @param type string : type de message (utilisé comme class sur le span entourant le message)
1020		 * @param message string : le contenu du message 
1021		 */
1022		ms_messages : function(type,message,force){
1023			var media = $(this),
1024				id = media[0],
1025				wrapper = $(this).is('.media_wrapper') ? $(this) : $(this).parents('.media_wrapper');
1026
1027			if((!id.options.messages || id.controls) && !force) return;
1028
1029			var messages = wrapper.find('.messages'),
1030				message = (type == 'error') ? '<span>'+message+'</span>' : '<span class="'+type+'">'+message+'</span>';
1031
1032			var fade_play = function() {
1033				if(!messages.is('.error')) messages.fadeOut(function(){ $(this).html(''); });
1034			};
1035			if(type == 'error') messages.addClass('error');
1036			else if(messages.is('.error')) return;
1037
1038			messages.html(message);
1039			if(messages.is(':hidden')){
1040				messages.fadeIn('normal',function(){
1041					if(type != 'error') stop_message_timeout = setTimeout(fade_play, 1500);
1042				});
1043			}else{
1044				clearTimeout(stop_message_timeout);
1045				if(type != 'error')  stop_message_timeout = setTimeout(fade_play, 1500);
1046			}
1047		},
1048		/**
1049		 * La fonction de test de fallback en flash 
1050		 * 
1051		 * Si le navigateur ne sait pas lire le media en html5,
1052		 * on regarde si on a une fonction de fallback flash et dans ce cas on l'utilise.
1053		 */
1054		ms_test_fallback : function(options){
1055			var media = $(this);
1056			if(typeof($.fn.ms_fallback_flash) == 'function'){
1057				if(IS_IE)
1058					var sources = media.parent().children("source");
1059				else
1060					var sources = media.children("source");
1061				$.each(sources, function(index, value){
1062					var source = $(this);
1063					if((source.attr('type').match('video/x-flv'))||(source.attr('type').match('video/mp4'))||(source.attr('type').match('audio/mpeg'))||(source.attr('type').match('audio/mp4'))){
1064						var defaults_flash = {
1065							flowurl:options.flowurl,
1066							flasherror:options.flasherror ? options.flasherror : '',
1067							autoplay:options.autoplay,
1068							autoload:options.autoload,
1069							wmode : 'transparent',
1070							poster : media.attr('poster'),
1071							sources : $(this),
1072							loop : (typeof(media.attr('loop')) == 'undefined') ? false : true
1073						};
1074						var options_flash = $.extend(options,defaults_flash);
1075						media.ms_fallback_flash(options_flash);
1076						return false;// On s'arrête au premier élément qui nous convient
1077					}
1078				});
1079			}
1080		},
1081		ms_update_loaded : function(e){
1082			var media = $(this), id = media[0], percent_loaded = null;
1083			if(id.controls) return;
1084			else if(id.buffered && id.buffered.length)
1085				id.percent_loaded = percent_loaded = ms_anything_to_percent(id.buffered.end(0),id.duration);
1086			else if((typeof(e.loaded) != 'undefined') && (typeof(e.total) != 'undefined'))
1087				id.percent_loaded = percent_loaded = ms_anything_to_percent(e.loaded,e.total);
1088			if(percent_loaded !== null)
1089				media.parent().find('.progress_buffered').css('width',percent_loaded+'%');
1090		},
1091		/**
1092		 * Quelques évènements à la pression de touches sur le clavier
1093		 * -* esc : sort du fullscreen
1094		 * -* f : passe en fullscreen sur la video en lecture ou sur celle en hover/focus
1095		 * -* l : active ou désactive la lecture en boucle
1096		 * -* space : lance la lecture d'une vidéo ou la met en pause
1097		 * -* flèches haut et bas : augmente ou baisse le volume
1098		 * -* flèches gauche et droite : recule ou avance la lecture de 5%
1099		 */
1100		ms_activate_keys : function(e){
1101			if($(this)[0].controls) return;
1102			var media = $(this), meta_key_pressed = e.ctrlKey || e.metaKey || e.altKey || e.shiftKey;
1103			if(!meta_key_pressed){
1104				switch (e.keyCode) {
1105					case 27 :
1106						/**
1107						 * Touche esc : sort du mode fullscreen (uniquement sur videos)
1108						 */
1109						e.preventDefault();
1110						if (!fullScreenApi.supportsFullScreen && media.find('video')[0].isFullScreen)
1111							media.find('video').ms_fullscreen();
1112						break;
1113					case 70 :
1114						/**
1115						 * Touche f
1116						 * Active le fullscreen sur la video en lecture ou la video en hover/focus (uniquement sur videos)
1117						 */
1118						if(!media.find('video')[0].isFullScreen && ($('input:focus,textarea:focus').size() === 0)){
1119							media.find('video').ms_fullscreen();
1120							e.preventDefault();
1121						}
1122						break;
1123					case 76 :
1124						/**
1125						 * Touche l
1126						 * Active ou désactive le mode boucle (loop) sur le média en cours de lecture
1127						 */
1128						if(media.find('video,audio')[0].isFullScreen || $('input:focus,textarea:focus').size() === 0){
1129							media.find('video,audio').ms_loop();
1130							e.preventDefault();
1131						}
1132						break;
1133					case 77 :
1134						/**
1135						 * Touche M : mute ou unmute
1136						 */
1137						if(media.find('video,audio')[0].isFullScreen || $('input:focus,textarea:focus').size() === 0){
1138							media.find('video,audio').ms_volume(true);
1139							e.preventDefault();
1140						}
1141						break;
1142					case 32 :
1143						 /**
1144						  * Touche Space : lance la lecture ou met le media en pause
1145						  */
1146						if(media.find('video,audio')[0].isFullScreen || ($('input:focus,textarea:focus').size() === 0)){
1147							media.find('video,audio').ms_play_pause();
1148							e.preventDefault();
1149						}
1150						break;
1151					case 38 : case 40 :
1152						/**
1153						 * Touches Up (38) et Down (40)
1154						 * Baisse ou augmente de 10% le volume de la video en cours de lecture
1155						 */
1156						if(media.find('video,audio')[0].duration && (media.find('video,audio')[0].isFullScreen||($('input:focus,textarea:focus').size() === 0))){
1157							if(!media.find('video,audio')[0].muted){
1158								var delta  = (e.keyCode == 38) ? 1 : -1,
1159									volume = media.find('video,audio')[0].volume,
1160									volume_diff = (delta > 0) ? '0.1' : '-0.1',
1161									volume_new = Math.round((volume + parseFloat(volume_diff))*10)/10;
1162								if((volume_new <= 1) && (volume_new >= 0))
1163									media.find('video,audio')[0].volume = volume_new;
1164							}
1165							e.preventDefault();
1166							e.stopPropagation();
1167						}
1168						break;
1169					case 37 : case 39 :
1170						/**
1171						 * Gauche (37) et droite (39)
1172						 * Avance ou recule de 5% la video en cours de lecture
1173						 * Il faut également modifier la valeur de la barre
1174						 */
1175						if(media.find('video,audio')[0].duration && (media.find('video,audio')[0].isFullScreen||($('input:focus,textarea:focus,select:focus').size() === 0))){
1176							var pourcent_actuel = ((media.find('video,audio')[0].currentTime / media.find('video,audio')[0].duration) * 100);
1177							if(e.keyCode == 37)
1178								var new_percent = (pourcent_actuel >= 5) ? (pourcent_actuel - 5) : 0;
1179							else
1180								var new_percent = (pourcent_actuel > 95) ? 100 : (pourcent_actuel + 5);
1181							media.find('video,audio').ms_seek_to_percent(new_percent,true);
1182							e.preventDefault();
1183							e.stopPropagation();
1184						}
1185						break;
1186				}
1187			}
1188		}
1189	});
1190})(jQuery);
1191
1192/**
1193 * Converti un nombre de secondes en une heure lisible hh:mm:ss
1194 *
1195 * @param seconds int Le nombre de secondes
1196 * @return
1197 */
1198function ms_second_to_time(seconds){
1199	if(seconds === 0) return '00:00';
1200	var uTime = Math.round(seconds*Math.pow(10,0))/Math.pow(10,0),
1201		hours = Math.floor(uTime/3600);
1202	hours = (hours >0) ? (hours<10?'0'+hours:hours)+':' : '';
1203	var minutes = (Math.floor(uTime/60)%60);
1204	minutes= minutes<10?'0'+minutes:minutes;
1205	seconds = (uTime%60);
1206	seconds = seconds<10?'0'+seconds:seconds;
1207	return hours+minutes+':'+seconds;
1208}
1209
1210function ms_percent_to_time(percent,total){
1211	return ms_second_to_time(Math.ceil((total * percent) / 100));
1212}
1213
1214function ms_anything_to_percent(current,total){
1215	return Math.ceil((current / total) * 100);
1216}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.