uploading works, but AV info is not automatically detected and video activation featu...
[living-lab-site.git] / js / jquery.ui.nsvideo.js
1 /*
2  * jQuery UI NS-Video 1.0.0 beta
3  *
4  * Copyright 2011, Călin-Andrei Burloiu
5  * Dual licensed under the MIT or GPL Version 2 licenses.
6  * http://jquery.org/license
7  *
8  *
9  * Depends:
10  *   jquery.ui.core.js
11  *   jquery.ui.widget.js
12  */
13 (function( $, undefined ) {
14
15 $.widget( "ui.nsvideo", {
16         version: "1.0.0 beta",
17         options: {
18                 type: 'ns-html5',
19                 srcIndex: 0,
20                 width: 0,
21                 height: 0,
22                 minWidth: 0,
23                 maxWidth: 0,
24                 showState: true,
25                 refreshInterval: 0.1,   // seconds
26                 autoplay: false,
27                 initialDuration: "--:--"
28         },
29         
30         _create: function() {
31                 widget = this;
32                 
33                 widget.element
34                         .addClass( "ui-widget ui-widget-content ui-corner-all" );
35                 
36                 widget.$videoContainer = $('<div class="ui-nsvideo-nsplugin"></div>')
37                         .appendTo(widget.element);
38                 widget.$progressContainer = $('<div class="ui-nsvideo-progress-container ui-widget-content ui-corner-top"></div>')
39                         .appendTo(widget.element);
40                 widget.$progress = $('<div class="ui-nsvideo-progress"></div>')
41                         .appendTo(widget.$progressContainer);
42                 widget.$loadedProgress = $('<div class="ui-nsvideo-loaded-progress"></div>')
43                         .appendTo(widget.$progress);
44                 widget.$controls = $('<div class="ui-nsvideo-controls ui-widget-content ui-corner-bottom"></div>')
45                         .appendTo(widget.element);
46                 
47                 widget.video();
48                 
49                 // Time progress slider with load progress also
50                 widget.$loadedProgress
51                         // TODO an object that inherits progressbar should be used in order to customize min value.
52                         .progressbar({
53                                 value: 0
54                         });
55                 widget.$progress
56                         .slider({
57                                         value: 0,
58                                         min: 0,
59                                         max: 1000,
60                                         slide: function(event, ui) {
61                                                 widget.videoPlugin('crtTime', [ui.value]);
62                                                 widget.videoPlugin('refreshTime');
63                                                 widget.videoPlugin('refreshState');
64                                         }
65                         });
66                 
67                 // Play / Pause
68                 $('<button class="ui-nsvideo-play ui-nsvideo-button ui-nsvideo-control-left">Play / Pause</button>')
69                         .appendTo(widget.$controls)
70                         .button({
71                                 text: false,
72                                 icons: { primary: "ui-icon-play" }
73                         })
74                         .click(function() {
75                                 widget.videoPlugin('togglePlay');
76                         });
77                 
78                 // Time information (current and total)
79                 widget.$time = $('<div class="ui-nsvideo-time ui-nsvideo-text ui-nsvideo-control-left">00:00 / ' + widget.options.initialDuration + '</div>')
80                         .appendTo(widget.$controls);
81                         
82                 // Full screen
83                 $('<button class="ui-nsvideo-fullscreen ui-nsvideo-button ui-nsvideo-control-right">Full Screen</button>')
84                         .appendTo(widget.$controls)
85                         .button({
86                                 text: false,
87                                 icons: { primary: "ui-icon-arrow-4-diag" }
88                         })
89                         .click(function() {
90                                 widget.videoPlugin('fullscreen');
91                         });
92
93                 // Video format buttonset
94                 if (typeof widget.options.src == 'object')
95                 {
96                         var $formats = $('<form><div class="ui-nsvideo-formats ui-nsvideo-control-right"></div></form>')
97                                 .appendTo(widget.$controls);
98                         $formats = $('.ui-nsvideo-formats', $formats[0]);
99                         $.each(widget.options.src, function(index, value) {
100                                 var id = widget.element.attr('id') + '-format-' + index;
101                                 var definition = value.res.substring(value.res.indexOf('x')+1)+'p';
102                                 $('<input type="radio" id="' + id + '" name="format" />')
103                                         .appendTo($formats)
104                                         .attr('checked', (index == widget.options.srcIndex))
105                                         .click(function() {
106                                                 widget.videoPlugin('pause');
107                                                 widget.srcIndex(index);
108                                         });
109                                 $('<label for="' + id + '">' + definition + '</label>')
110                                         .appendTo($formats);
111                         });
112                         
113                         $formats.buttonset();
114                 }
115                 
116                 // Volume
117                 $('<div class="ui-nsvideo-volume ui-nsvideo-control-right"></div>')
118                         .appendTo(widget.$controls)
119                         .slider({
120                                 range: "min",
121                                 min: 0,
122                                 max: 100,
123                                 slide: function(event, ui) {
124                                         widget.videoPlugin('volume', [ui.value]);
125                                 }
126                         });
127                 
128                 // Toggle Mute
129                 $('<button class="ui-nsvideo-mute ui-nsvideo-button ui-nsvideo-control-right">Mute</button>')
130                         .appendTo(widget.$controls)
131                         .button({
132                                 text: false,
133                                 icons: { primary: "ui-icon-volume-on" }
134                         })
135                         .click(function() {
136                                 widget.videoPlugin('toggleMute');
137                         });
138                         
139                 // Status information
140                 widget.$stateText = $('<div class="ui-nsvideo-text ui-nsvideo-control-right">...</div>')
141                         .appendTo(widget.$controls)
142                         .css('cursor', 'pointer')
143                         .click(function() {
144                                 widget.videoPlugin('refreshAll');
145                         });
146                 if (! widget.options.showState)
147                         widget.$stateText.hide();
148                 
149                 // Clear fix helper
150                 $('<div class="ui-helper-clearfix"></div>')
151                         .appendTo(widget.$controls);
152         },
153
154         _destroy: function() {
155                 
156         },
157
158         _setOption: function( key, value ) {
159                 // TODO
160                 if ( key === "TODO" ) {
161                         
162                 }
163
164                 this._super( "_setOption", key, value );
165         },
166         
167         _leadingZeros: function(number, length) {
168                 if (!length)
169                         length = 2;
170                 
171                 var str = '';
172                 
173                 if (isNaN(number))
174                 {
175                         for (var i=0; i<length; i++)
176                                 str += '-';
177                         return str;
178                 }
179                 
180                 str += number;
181                 while (str.length < length) 
182                 {
183                         str = '0' + str;
184                 }
185
186                 return str;
187         },
188         
189         video: function() {
190                 var widget = this;
191                 
192                 // Select video source.
193                 // If src option is string, that's the source.
194                 // If src is an object, there is a list of associative arrays, each
195                 // one having the mandatory keys "src" and "res" (resolution).
196                 var src = widget.crtSrc();
197                 if (src == null)
198                         return widget;
199                 
200                 widget.$videoContainer.html('');
201                 
202                 // Install buttons or not supported message if required
203                 if (typeof $.fn.nsinstall == 'function')
204                 {
205                         widget.$installContainer = $('<div class="container-install-in-widget"></div>')
206                                 .appendTo(widget.$videoContainer);
207                         widget.$installContainer
208                                 .nsinstall({
209                                         type: widget.options.type,
210                                         hideIfAlreadyInstalled: true
211                                 });
212                         if (widget.$installContainer.nsinstall('option', 'error')
213                                         == 'already installed')
214                                 widget.$installContainer.hide();
215                 }
216                 
217                 var width = widget.options.width;
218                 var height = widget.options.height;
219                 
220                 // HTML5
221                 if (widget.options.type == 'ns-html5'
222                         || widget.options.type == 'html5')
223                 {
224                         widget.$video = $('<video id="' + widget.element.attr('id') + '-video" src="' + src + '"' + (width == 0 ? '' : ' width="' + width + '"') + (height == 0 ? '' : ' height="' + height + '"') + ' preload="auto"' + (widget.options.autoplay ? ' autoplay="autoplay"' : '') + '>'
225                                 +'Error: Your browser does not support HTML5 or the video format!'
226                         +'</video>')
227                                 .appendTo(widget.$videoContainer)
228                                 .bind({
229                                         ended: function() {
230                                                 widget.html5.pause();
231                                                 widget.html5.refreshState();
232                                         },
233                                         play: function() {
234                                                 widget.html5.play();
235                                                 widget.html5.refreshState();
236                                         },
237                                         pause: function() {
238                                                 widget.html5.pause();
239                                                 widget.html5.refreshState();
240                                         },
241                                         timeupdate: function() {
242                                                 widget.html5.refreshTime();
243                                         },
244                                         progress: function() {
245                                                 widget.html5.refreshLoadedProgress();
246                                         },
247                                         loadedmetadata: function() {
248                                                 widget.html5.refreshTime();
249                                                 widget.html5.refreshVolume();
250                                                 widget.html5.refreshState();
251                                                 widget._setWidgetWidth();
252                                                 
253                                                 if (widget.$video[0].error != 3
254                                                                 && widget.$video[0].error != 4)
255                                                         widget.$installContainer.hide();
256                                         },
257                                         seeked: function() {
258                                                 widget.html5.play();
259                                                 widget.html5.refreshState();
260                                         },
261                                         volumechange: function() {
262                                                 widget.html5.refreshVolume();
263                                         },
264                                         
265                                         loadstart: function() {
266                                                 widget.html5.refreshState();
267                                         },
268                                         suspend: function() {
269                                                 widget.html5.refreshState();
270                                         },
271                                         abort: function() {
272                                                 widget.html5.refreshState();
273                                         },
274                                         error: function() {
275                                                 widget.html5.refreshState();
276                                         },
277                                         emptied: function() {
278                                                 widget.html5.refreshState();
279                                         },
280                                         stalled: function() {
281                                                 widget.html5.refreshState();
282                                         },
283                                         loadeddata: function() {
284                                                 widget.html5.refreshState();
285                                         },
286                                         waiting: function() {
287                                                 widget.html5.refreshState();
288                                         },
289                                         seeking: function() {
290                                                 widget.html5.refreshState();
291                                         }
292                                 });
293                 }
294                 // VLC
295                 else if (widget.options.type == 'ns-vlc'
296                         || widget.options.type == 'vlc')
297                 {
298                         var embedType;
299                         if (widget.options.type == 'ns-vlc')
300                                 embedType = 'application/x-ns-stream';
301                         else
302                                 embedType = 'application/x-vlc-plugin';
303                         
304                         if (navigator.appName == "Netscape")
305                         {
306                                 widget.$video = $('<embed type="' + embedType + '" name="vlcVideo" id="' + widget.element.attr('id') + '-video" autoplay="' + (widget.options.autoplay ? 'yes' : 'no') + '" loop="no" width="' + (width == 0 ? '640' : width) + '" height="' + (height == 0 ? '480' : height) + '" target="' + src + '" />')
307                                         .appendTo(widget.$videoContainer);
308                         }
309                         else
310                         {
311                                 widget.$video = $('<object classid="clsid:1800B8AF-4E33-43C0-AFC7-894433C13538" width="' + (width == 0 ? '640' : width) + '" height="' + (height == 0 ? '480' : height) + '" id="' + widget.element.attr('id') + '-video" name="vlcVideo" events="True" target="">'
312                                                 + '<param name="Src" value="' + src + '" />'
313                                                 + '<param name="ShowDisplay" value="True" />'
314                                                 + '<param name="Loop" value="False" />'
315                                                 + '<param name="AutoPlay" value="' + (widget.options.autoplay ? 'True' : 'False') + '" />'
316                                                 + '<param name="Toolbar" value="False" />'
317                                         + '</object>')
318                                         .appendTo(widget.$videoContainer);
319                         }
320                 }
321                 
322                 //  BUG: this if is because of a NS-VLC bug.
323                 if (widget.options.type != 'ns-vlc')
324                         widget.$video.css('position', 'relative');
325                 
326                 // Adjust video size for auto-resizing within ranges minWidth and
327                 // maxWidth.
328                 if ( (width == 0 || height == 0)
329                         && (widget.options.minWidth != 0 && widget.options.maxWidth != 0
330                                 || this.options.type.indexOf('vlc') != -1) )
331                 {
332                         widget.adjustVideoSizeFromMeta();
333                 }
334                 
335                 // Initialize video plugin
336                 widget.$video.ready(function() {
337                         widget.videoPlugin('init');
338                 });
339                 
340                 widget._setWidgetWidth();
341         },
342         
343         adjustVideoSizeFromMeta: function() {
344                 var widget = this;
345                 
346                 if (typeof widget.options.src == 'object'
347                         && (typeof widget.options.src[ widget.options.srcIndex ].res)
348                                 != 'undefined'
349                         && (typeof widget.options.src[ widget.options.srcIndex ].dar)
350                                 != 'undefined')
351                 {
352                         var resolution = widget.options.src[ widget.options.srcIndex ].res;
353                         var dar = widget.options.src[ widget.options.srcIndex ].dar;
354                         var darL = parseInt(
355                                 dar.substring(0, dar.indexOf(':')));
356                         var darR = parseInt(
357                                 dar.substring(dar.indexOf(':') + 1));
358                         var videoHeight = parseInt(
359                                 resolution.substring(resolution.indexOf('x') + 1));
360                         var videoWidth = Math.round(videoHeight * darL / darR);
361                         
362                         // Video width must be between minWidth and maxWidth pixels.
363                         if (widget.options.minWidth != 0 && widget.options.maxWidth != 0)
364                         {
365                                 if (videoWidth > widget.options.maxWidth)
366                                 {
367                                         videoHeight = Math.round(widget.options.maxWidth / videoWidth
368                                                 * videoHeight);
369                                         videoWidth = widget.options.maxWidth;
370                                 }
371                                 else if (videoWidth < widget.options.minWidth)
372                                 {
373                                         videoHeight = Math.round(widget.options.minWidth / videoWidth
374                                                 * videoHeight);
375                                         videoWidth = widget.options.minWidth;
376                                 }
377                         }
378                         
379                         widget.$video.css('width', videoWidth);
380                         widget.$video.css('height', videoHeight);
381                 }
382         },
383         
384         _setWidgetWidth: function() {
385         var widget = this;
386         
387                 if (widget.$video.width() < 640)
388                 {
389                         widget.element.css('width',
390                                                         640 + 8 + 'px');
391                         widget.$video.css('left', 
392                                 Math.round(widget.$videoContainer.width()/2 
393                                 - widget.$video.width()/2)
394                                 + 'px');
395                 }
396                 else
397                 {
398                         widget.element.css('width',
399                                                         widget.$video.width() + 8 + 'px');
400                         widget.$video.css('left', '0');
401                 }
402                 
403                 this._trigger('resize');
404         },
405         
406         setPlayButton: function() {
407                 $('button.ui-nsvideo-play', widget.element[0])
408                         .button('option', 'icons', { primary: "ui-icon-play" })
409                         .button('refresh');
410         },
411         setPauseButton: function() {
412                 $('button.ui-nsvideo-play', widget.element[0])
413                         .button('option', 'icons', { primary: "ui-icon-pause" })
414                         .button('refresh');
415         },
416         setMuteButton: function() {
417                 $('button.ui-nsvideo-mute', widget.element[0])
418                         .button('option', 'icons', { primary: "ui-icon-volume-off" })
419                         .button('refresh');
420         },
421         setUnmuteButton: function() {
422                 $('button.ui-nsvideo-mute', widget.element[0])
423                         .button('option', 'icons', { primary: "ui-icon-volume-on" })
424                         .button('refresh');
425         },
426         setTimeText: function(text) {
427                 //$('.ui-nsvideo-time', widget.element[0])
428                 this.$time
429                         .html(text);
430         },
431         setVolumeSlider: function(vol) {
432                 $('.ui-nsvideo-volume', widget.element[0])
433                         .slider('value', vol);
434         },
435         setProgressSlider: function(prog) {
436                 $('.ui-nsvideo-progress', widget.element[0])
437                         .slider('value', prog);
438         },
439         setLoadedProgressSlider: function(prog) {
440                 $('.ui-nsvideo-loaded-progress', widget.element[0])
441                         .progressbar('value', prog);
442         },
443         
444         videoPlugin: function(method, args) {
445                 if (typeof args == 'undefined')
446                         args = [];
447                 var videoPlugin = null;
448                 
449                 if (this.options.type.indexOf('html5') != -1)
450                 {
451                         videoPlugin = this.html5;
452                 }
453                 else if (this.options.type.indexOf('vlc') != -1)
454                 {
455                         videoPlugin = this.vlc;
456                 }
457                 
458                 if (videoPlugin)
459                         return videoPlugin[method].apply(this, args);
460                 
461                 return null;
462         },
463         
464         srcIndex: function(srcIndex) {
465                 var widget = this;
466                 
467                 if (typeof srcIndex == 'undefined')
468                         return widget.options.srcIndex;
469                 
470                 widget.options.srcIndex = srcIndex;
471                 
472                 // Refresh.
473                 widget.video();
474                 
475                 return widget;
476         },
477         
478         type: function(type) {
479                 var widget = this;
480                 
481                 if (typeof type == 'undefined')
482                         return widget.options.type;
483                 
484                 widget.videoPlugin('pause');
485                 if (widget.vlc.timerHandle)
486                         clearTimeout(widget.vlc.timerHandle);
487                 
488                 widget.options.type = type;
489                 widget.video();
490                 
491                 // Initialize video plugin
492                 widget.$video.ready(function() {
493                         widget.videoPlugin('init');
494                 });
495                 
496                 return widget;
497         },
498         
499         crtSrc: function() {
500                 var src;
501                 var widget = this;
502                 
503                 if (typeof widget.options.src == 'string')
504                         src = widget.options.src;
505                 else if (typeof widget.options.src == 'object')
506                 {
507                         if (typeof widget.options.srcIndex == 'undefined')
508                                 return null;
509                         
510                         if (typeof widget.options.src[ widget.options.srcIndex ].src
511                                 == 'undefined')
512                                 return null;
513                         
514                         src = widget.options.src[ widget.options.srcIndex ].src;
515                 }
516                 
517                 if (widget.options.type == 'ns-html5')
518                         src = 'tribe://' + src;
519                 
520                 return src;
521         },
522         
523         html5: {
524                 widget: this,
525                 //lastTime: null,
526                 
527                 ERR_STATES: {
528                         MEDIA_ERR_ABORTED: [1, "error: aborted"],
529                         MEDIA_ERR_NETWORK: [2, "network error"],
530                         MEDIA_ERR_DECODE: [3, "decode error"],
531                         MEDIA_ERR_SRC_NOT_SUPPORTED: [4, "error: source not supported"]
532                 },
533                 
534                 NETWORK_STATES: {
535                         NETWORK_EMPTY: [0, "no data from network"],
536                         NETWORK_IDLE: [1, ""],
537                         NETWORK_LOADING: [2, "loading..."],
538                         NETWORK_LOADED: [3, "loading completed"],
539                         NETWORK_NO_SOURCE: [4, "network: no source"]
540                 },
541                 
542                 READY_STATES: {
543                         HAVE_NOTHING: [0, "please wait..."],
544                         HAVE_METADATA: [1, ""],
545                         HAVE_CURRENT_DATA: [2, ""],
546                         HAVE_FUTURE_DATA: [3, ""],
547                         HAVE_ENOUGH_DATA: [4, "have enough data"]
548                 },
549                 
550                 init: function() {
551                         //widget.html5.refreshAll();
552                         
553                         widget.html5.refreshState();
554                         
555                         //if (widget.options.autoplay)
556                         //      widget.html5.play();
557                 },
558                 
559                 togglePlay: function() {
560                         if (widget.$video[0].paused)
561                         {
562                                 widget.html5.play();
563                         }
564                         else
565                         {
566                                 widget.html5.pause();
567                         }
568                 },
569
570                 play: function() {
571                         if (widget.$video[0].paused)
572                                 widget.$video[0].play();
573                         
574                         widget.setPauseButton();
575                         
576                         return widget;
577                 },
578                 
579                 pause: function() {
580                         if (!widget.$video[0].paused)
581                                 widget.$video[0].pause();
582                         
583                         widget.setPlayButton();
584
585                         return widget;
586                 },
587                 
588                 toggleMute: function() {
589                         if (!widget.$video[0].muted)
590                         {
591                                 widget.html5.mute();
592                         }
593                         else
594                         {
595                                 widget.html5.unmute();
596                         }
597                 },
598                   
599                 mute: function() {
600                         if (!widget.$video[0].muted)
601                                 widget.$video[0].muted = true;
602                         
603                         widget.setMuteButton();
604                         
605                         return widget;
606                 },
607                 
608                 unmute: function() {
609                         if (widget.$video[0].muted)
610                                 widget.$video[0].muted = false;
611                         
612                         widget.setUnmuteButton();
613                         
614                         return widget;
615                 },
616                 
617                 /**
618                 * Volume value is expressed in percents.
619                 */
620                 volume: function(vol) {
621                         if (typeof vol == 'undefined')
622                                 return Math.round(widget.$video[0].volume * 100);
623                         
624                         widget.html5.unmute();
625                         widget.$video[0].volume = vol / 100;
626                         
627                         return widget;
628                 },
629                 
630                 /**
631                  * Seek position is a value between 0 and 1000.
632                  */
633                 crtTime: function(pos) {
634                         // getter
635                         if (typeof pos == 'undefined')
636                         {
637                                 var crtTime = widget.$video[0].currentTime;
638                                 var totTime = widget.$video[0].duration;
639                                 if (isNaN(totTime) || totTime == 0)
640                                         return 0;
641                                 else
642                                         return Math.round(crtTime / totTime * 1000.0);
643                         }
644                         
645                         // setter
646                         widget.$video[0].currentTime = 
647                                 pos / 1000 * widget.$video[0].duration;
648                 },
649                   
650                 refreshAll: function() {
651                         widget.html5.refreshState();
652                         widget.html5.refreshVolume();
653                         widget.html5.refreshLoadedProgress();
654                         widget.html5.refreshTime();
655                 },
656                 
657                 refreshTime: function() {
658                         if (widget.$video[0].seeking)
659                                 return widget;
660                         
661                         var crtTime = widget.$video[0].currentTime;
662                         var totTime = widget.$video[0].duration;
663                         
664                         // Refresh only at refreshInterval seconds to save CPU time.
665                         var delta = crtTime - widget.html5.lastTime;
666                         if (typeof widget.html5.lastTime !== "undefined"
667                                 && delta >= 0 && delta < widget.options.refreshInterval)
668                                 return widget;
669                         widget.html5.lastTime = crtTime;
670                         
671                         // Current time string
672                         var crtH = Math.floor(crtTime / 3600);
673                         var crtM = Math.floor((crtTime / 60) % 60);
674                         var crtS = Math.floor(crtTime % 60);
675                         var strCrtTime = 
676                                 (crtH == 0 ? '' : (widget._leadingZeros(crtH) + ':'))
677                                 + widget._leadingZeros(crtM) + ':' + widget._leadingZeros(crtS);
678                                 
679                         // Total time string
680                         var totH = Math.floor(totTime / 3600);
681                         var totM = Math.floor((totTime / 60) % 60);
682                         var totS = Math.floor(totTime % 60);
683                         var strTotTime = 
684                                 (totH == 0 || isNaN(totH) ? '' : (widget._leadingZeros(totH) + ':'))
685                                 + widget._leadingZeros(totM) + ':' + widget._leadingZeros(totS);
686                         
687                         widget.setTimeText('' + strCrtTime + ' / ' + strTotTime);
688                         
689                         // Update time progress slider.
690                         widget.html5.refreshProgress();
691                         
692                         return widget;
693                 },
694                 
695                 _state: function(type, code) {
696                         var r;
697                         $.each(widget.html5[type + '_STATES'], function(index, value) {
698                                 if ('' + code == '' + value[0])
699                                 {
700                                         r = value;
701                                         return false;
702                                 }
703                         });
704                         
705                         return r;
706                 },
707                 
708                 refreshState: function() {
709             var widget = this;
710             
711                         var err = "";
712                         var normal = "";
713                         var network = "";
714                         var ready = "";
715                         var state = "";
716                         
717                         if (widget.$video[0].error)
718                                 err = widget.html5._state('ERR',
719                                                                                   widget.$video[0].error.code)[1];
720                           
721                         if (! widget.$video[0].paused)
722                                 normal = "playing...";
723                         else
724                         {
725                                 normal = "paused";
726                         }
727                         if (widget.$video[0].seeking)
728                                 normal = "seeking";
729                         if (widget.$video[0].ended)
730                                 normal = "ended";
731                         
732                         network = widget.html5._state('NETWORK',
733                                                                         widget.$video[0].networkState)[1]; 
734                         
735                         ready = widget.html5._state('READY',
736                                                                         widget.$video[0].readyState)[1];
737                         
738                         if (err !== "")
739                                 state = err;
740                         else
741                         {
742                                 state = normal;
743                                 
744                                 if (normal !== "" && (network !== "" || ready !== "") )
745                                         state += ' / ';
746                                 
747                                 if (network !== "")
748                                         state += network;
749                                 
750                                 if (network !== "" && ready !== "")
751                                         state += ' / ';
752                                 
753                                 if (ready !== "")
754                                         state += ready;
755                         }
756                         
757                         widget.$stateText
758                                 .html(state);
759                         
760                         return widget;
761                 },
762
763                 refreshVolume: function() {
764                         var vol;
765                         
766                         if (widget.$video[0].muted)
767                                 vol = 0;
768                         else
769                                 vol = Math.floor(widget.$video[0].volume * 100);
770                         
771                         widget.setVolumeSlider(vol);
772                         
773                         return widget;
774                 },
775                 
776                 refreshProgress: function() {
777                         widget.setProgressSlider(widget.html5.crtTime());
778                         
779                         return widget;
780                 },
781                 
782                 /**
783                 * Supported for Firefox 4.0 or later.
784                 */
785                 refreshLoadedProgress: function() {
786                         // Return if buffering status not available in browser.
787                         if (typeof widget.$video[0].buffered == 'undefined'
788                                 || widget.$video[0].buffered.length === 0)
789                                 return widget;
790                         
791                         var loadedTime = widget.$video[0].buffered.end(0);
792                         var totTime = widget.$video[0].duration;
793                         var percent;
794                         if (isNaN(totTime) || totTime == 0)
795                                 percent = 0
796                         else
797                                 percent = Math.floor(loadedTime / totTime * 100);
798                         
799                         widget.setLoadedProgressSlider(percent);
800                         
801                         return widget;
802                 },
803
804                 fullscreen: function() {
805                         alert('Your web browser does not support switching to full screen in HTML5 mode with this button. You can switch to full screen manually by right clicking on the video and choosing "Full Screen" from the popup menu.');
806                 }
807         },
808         
809         vlc: {
810                 widget: this,
811                 timerHandle: null,
812                 idleRefreshInterval: 1, // seconds
813                 
814                 STATES: {
815                         IDLE: [0, "idle"],
816                         OPENING: [1, "opening..."],
817                         BUFFERING: [2, "buffering..."],
818                         PLAYING: [3, "playing..."],
819                         PAUSED: [4, "paused"],
820                         STOPPING: [5, "stopping..."],
821                         ENDED: [6, "ended"],
822                         ERROR: [7, "error!"]
823                 },
824                 
825                 init: function() {
826                         if (widget.options.autoplay)
827                                 widget.vlc.play();
828                         widget.vlc.refreshAll();
829                 },
830                 
831                 togglePlay: function() {
832                         if (! widget.$video[0].playlist.isPlaying)
833                         {
834                                 widget.vlc.play();
835                         }
836                         else
837                         {
838                                 widget.vlc.pause();
839                         }
840                 },
841                 
842                 play: function() {
843                         if(typeof widget.$video[0].playlist.isPlaying == 'undefined')
844                                 return widget;
845                         
846                         widget.$installContainer.hide();
847                         
848                         if (! widget.$video[0].playlist.isPlaying)
849                                 widget.$video[0].playlist.play();
850                         
851                         widget.setPauseButton();
852                         
853                         // Schedule information refreshment at refreshInterval seconds.
854                         if (! widget.vlc.timerHandle)
855                                 widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler, 
856                                                                                 widget.options.refreshInterval * 1000);
857                                 
858                         widget.vlc.refreshState();
859                         
860                         return widget;
861                 },
862                 
863                 pause: function() {
864                         if (typeof widget.$video[0].playlist === 'undefined')
865                                 return widget;
866                         
867                         if (widget.$video[0].playlist.isPlaying)
868                                 widget.$video[0].playlist.togglePause();
869                         
870                         widget.setPlayButton();
871                         
872                         // Cancel information refreshment scheduling.
873                         clearTimeout(widget.vlc.timerHandle);
874                         widget.vlc.timerHandle = null;
875                         
876                         widget.vlc.refreshState();
877
878                         return widget;
879                 },
880                 
881                 toggleMute: function() {
882                         if (! widget.$video[0].audio.mute)
883                         {
884                                 widget.vlc.mute();
885                         }
886                         else
887                         {
888                                 widget.vlc.unmute();
889                         }
890                 },
891                   
892                 mute: function() {
893                         if (! widget.$video[0].audio.mute)
894                                 widget.$video[0].audio.toggleMute();
895                         
896                         widget.setMuteButton();
897                         
898                         widget.vlc.refreshVolume();
899                         
900                         return widget;
901                 },
902                 
903                 unmute: function() {
904                         if (widget.$video[0].audio.mute)
905                                 widget.$video[0].audio.toggleMute();
906                         
907                         widget.setUnmuteButton();
908                         
909                         widget.vlc.refreshVolume();
910                         
911                         return widget;
912                 },
913                 
914                 /**
915                 * Volume value is expressed in percents.
916                 */
917                 volume: function(vol) {
918                         if (typeof vol == 'undefined')
919                                 return Math.round(widget.$video[0].audio.volume);
920                         
921                         widget.vlc.unmute();
922                         widget.$video[0].audio.volume = vol;
923                         
924                         return widget;
925                 },
926                 
927                 /**
928                  * Seek position is a value between 0 and 1000.
929                  */
930                 crtTime: function(pos) {
931                         // getter
932                         if (typeof pos == 'undefined')
933                         {
934                                 var crtTime = widget.$video[0].input.time;
935                                 var totTime = widget.$video[0].input.length;
936                                 if (isNaN(totTime) || totTime == 0)
937                                         return 0;
938                                 else
939                                         return Math.round(crtTime / totTime * 1000.0);
940                         }
941                         
942                         // setter
943                         widget.$video[0].input.time = 
944                                 pos / 1000 * widget.$video[0].input.length;
945                                 
946                         widget.vlc.refreshState();
947                 },
948                 
949                 /**
950                  * Timeout callback called at refreshInterval during playing in order
951                  * to refresh information.
952                  */
953                 refreshHandler: function() {
954                         if (widget.$video[0].input.state
955                                 == widget.vlc.STATES.PLAYING[0])
956                         {
957                                 widget.vlc.refreshTime();
958                                 widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler, 
959                                                                                 widget.options.refreshInterval * 1000);
960                         }
961                         else
962                         {
963                                 if (widget.$video[0].input.state == widget.vlc.STATES.ENDED[0])
964                                 {
965                                         widget.vlc.pause();
966                                         try {
967                                                 widget.$video[0].playlist.stop();
968                                         } catch(e) {
969                                                 console.log('Exception: ' + e);
970                                         }
971                                 }
972                                 
973                                 widget.vlc.refreshTime();
974                                 widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler, 
975                                                                                 widget.vlc.idleRefreshInterval * 1000);
976                         }
977                         
978                         widget.vlc.refreshState();
979                 },
980                 
981                 refreshAll: function() {
982                         widget.vlc.refreshState();
983                         widget.vlc.refreshVolume();
984                         widget.vlc.refreshLoadedProgress();
985                         
986                         try {
987                                 widget.vlc.refreshTime();
988                         } catch(e) {
989                                 console.log('Exception: ' + e);
990                                 widget.$time.html('00:00 / ' + widget.options.initialDuration);
991                         }
992                 },
993                 
994                 refreshTime: function() {
995                         // TODO while seeking (maybe not necessary for VLC)
996 //                      if (widget.$video[0].seeking)
997 //                              return widget;
998                         
999                         // Time values in seconds.
1000                         var crtTime = widget.$video[0].input.time / 1000.0;
1001                         var totTime = widget.$video[0].input.length / 1000.0;
1002                         //var crtTime = widget.$video[0].input.position * totTime;
1003                         
1004                         // Current time string
1005                         var crtH = Math.floor(crtTime / 3600);
1006                         var crtM = Math.floor((crtTime / 60) % 60);
1007                         var crtS = Math.floor(crtTime % 60);
1008                         var strCrtTime = 
1009                                 (crtH == 0 ? '' : (widget._leadingZeros(crtH) + ':'))
1010                                 + widget._leadingZeros(crtM) + ':' + widget._leadingZeros(crtS);
1011                                 
1012                         // Total time string
1013                         var totH = Math.floor(totTime / 3600);
1014                         var totM = Math.floor((totTime / 60) % 60);
1015                         var totS = Math.floor(totTime % 60);
1016                         var strTotTime = 
1017                                 (totH == 0 || isNaN(totH) ? '' : (widget._leadingZeros(totH) + ':'))
1018                                 + widget._leadingZeros(totM) + ':' + widget._leadingZeros(totS);
1019                         
1020                         widget.setTimeText('' + strCrtTime + ' / ' + strTotTime);
1021                         
1022                         // Update time progress slider.
1023                         widget.vlc.refreshProgress();
1024                         
1025                         return widget;
1026                 },
1027                 
1028                 _state: function(code) {
1029                         var r;
1030                         $.each(widget.vlc.STATES, function(index, value) {
1031                                 if ('' + code == '' + value[0])
1032                                 {
1033                                         r = value;
1034                                         return false;
1035                                 }
1036                         });
1037                         
1038                         return r;
1039                 },
1040                 
1041                 refreshState: function() {
1042                         widget.$stateText
1043                                 .html(widget.vlc._state(widget.$video[0].input.state)[1]);
1044                                 
1045                         return widget;
1046                 },
1047
1048                 refreshVolume: function() {
1049                         var vol;
1050                         
1051                         if (widget.$video[0].audio.mute)
1052                                 vol = 0;
1053                         else
1054                                 vol = Math.floor(widget.$video[0].audio.volume);
1055                         
1056                         widget.setVolumeSlider(vol);
1057                         
1058                         return widget;
1059                 },
1060                 
1061                 refreshProgress: function() {
1062                         widget.setProgressSlider(widget.vlc.crtTime());
1063                         
1064                         return widget;
1065                 },
1066                 
1067                 /**
1068                 * Not supported for VLC.
1069                 */
1070                 refreshLoadedProgress: function() {
1071                         // TODO Currently not possible through VLC API.
1072                         
1073                         return widget;
1074                 },
1075
1076                 fullscreen: function() {
1077                         widget.$video[0].video.toggleFullscreen();
1078                 }
1079         }
1080 });
1081
1082 })( jQuery );