fe65927c10e41060e01850cfd28363c47905ecc0
[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                 var 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                 if (widget.$video.width() < 640)
386                 {
387                         widget.element.css('width',
388                                                         640 + 8 + 'px');
389                         widget.$video.css('left', 
390                                 Math.round(widget.$videoContainer.width()/2 
391                                 - widget.$video.width()/2)
392                                 + 'px');
393                 }
394                 else
395                 {
396                         widget.element.css('width',
397                                                         widget.$video.width() + 8 + 'px');
398                         widget.$video.css('left', '0');
399                 }
400                 
401                 this._trigger('resize');
402         },
403         
404         setPlayButton: function() {
405                 $('button.ui-nsvideo-play', widget.element[0])
406                         .button('option', 'icons', { primary: "ui-icon-play" })
407                         .button('refresh');
408         },
409         setPauseButton: function() {
410                 $('button.ui-nsvideo-play', widget.element[0])
411                         .button('option', 'icons', { primary: "ui-icon-pause" })
412                         .button('refresh');
413         },
414         setMuteButton: function() {
415                 $('button.ui-nsvideo-mute', widget.element[0])
416                         .button('option', 'icons', { primary: "ui-icon-volume-off" })
417                         .button('refresh');
418         },
419         setUnmuteButton: function() {
420                 $('button.ui-nsvideo-mute', widget.element[0])
421                         .button('option', 'icons', { primary: "ui-icon-volume-on" })
422                         .button('refresh');
423         },
424         setTimeText: function(text) {
425                 //$('.ui-nsvideo-time', widget.element[0])
426                 this.$time
427                         .html(text);
428         },
429         setVolumeSlider: function(vol) {
430                 $('.ui-nsvideo-volume', widget.element[0])
431                         .slider('value', vol);
432         },
433         setProgressSlider: function(prog) {
434                 $('.ui-nsvideo-progress', widget.element[0])
435                         .slider('value', prog);
436         },
437         setLoadedProgressSlider: function(prog) {
438                 $('.ui-nsvideo-loaded-progress', widget.element[0])
439                         .progressbar('value', prog);
440         },
441         
442         videoPlugin: function(method, args) {
443                 if (typeof args == 'undefined')
444                         args = [];
445                 var videoPlugin = null;
446                 
447                 if (this.options.type.indexOf('html5') != -1)
448                 {
449                         videoPlugin = this.html5;
450                 }
451                 else if (this.options.type.indexOf('vlc') != -1)
452                 {
453                         videoPlugin = this.vlc;
454                 }
455                 
456                 if (videoPlugin)
457                         return videoPlugin[method].apply(this, args);
458                 
459                 return null;
460         },
461         
462         srcIndex: function(srcIndex) {
463                 var widget = this;
464                 
465                 if (typeof srcIndex == 'undefined')
466                         return widget.options.srcIndex;
467                 
468                 widget.options.srcIndex = srcIndex;
469                 
470                 // Refresh.
471                 widget.video();
472                 
473                 return widget;
474         },
475         
476         type: function(type) {
477                 var widget = this;
478                 
479                 if (typeof type == 'undefined')
480                         return widget.options.type;
481                 
482                 widget.videoPlugin('pause');
483                 if (widget.vlc.timerHandle)
484                         clearTimeout(widget.vlc.timerHandle);
485                 
486                 widget.options.type = type;
487                 widget.video();
488                 
489                 // Initialize video plugin
490                 widget.$video.ready(function() {
491                         widget.videoPlugin('init');
492                 });
493                 
494                 return widget;
495         },
496         
497         crtSrc: function() {
498                 var src;
499                 var widget = this;
500                 
501                 if (typeof widget.options.src == 'string')
502                         src = widget.options.src;
503                 else if (typeof widget.options.src == 'object')
504                 {
505                         if (typeof widget.options.srcIndex == 'undefined')
506                                 return null;
507                         
508                         if (typeof widget.options.src[ widget.options.srcIndex ].src
509                                 == 'undefined')
510                                 return null;
511                         
512                         src = widget.options.src[ widget.options.srcIndex ].src;
513                 }
514                 
515                 if (widget.options.type == 'ns-html5')
516                         src = 'tribe://' + src;
517                 
518                 return src;
519         },
520         
521         html5: {
522                 widget: this,
523                 //lastTime: null,
524                 
525                 ERR_STATES: {
526                         MEDIA_ERR_ABORTED: [1, "error: aborted"],
527                         MEDIA_ERR_NETWORK: [2, "network error"],
528                         MEDIA_ERR_DECODE: [3, "decode error"],
529                         MEDIA_ERR_SRC_NOT_SUPPORTED: [4, "error: source not supported"]
530                 },
531                 
532                 NETWORK_STATES: {
533                         NETWORK_EMPTY: [0, "no data from network"],
534                         NETWORK_IDLE: [1, ""],
535                         NETWORK_LOADING: [2, "loading..."],
536                         NETWORK_LOADED: [3, "loading completed"],
537                         NETWORK_NO_SOURCE: [4, "network: no source"]
538                 },
539                 
540                 READY_STATES: {
541                         HAVE_NOTHING: [0, "please wait..."],
542                         HAVE_METADATA: [1, ""],
543                         HAVE_CURRENT_DATA: [2, ""],
544                         HAVE_FUTURE_DATA: [3, ""],
545                         HAVE_ENOUGH_DATA: [4, "have enough data"]
546                 },
547                 
548                 init: function() {
549                         //widget.html5.refreshAll();
550                         
551                         widget.html5.refreshState();
552                         
553                         //if (widget.options.autoplay)
554                         //      widget.html5.play();
555                 },
556                 
557                 togglePlay: function() {
558                         if (widget.$video[0].paused)
559                         {
560                                 widget.html5.play();
561                         }
562                         else
563                         {
564                                 widget.html5.pause();
565                         }
566                 },
567
568                 play: function() {
569                         if (widget.$video[0].paused)
570                                 widget.$video[0].play();
571                         
572                         widget.setPauseButton();
573                         
574                         return widget;
575                 },
576                 
577                 pause: function() {
578                         if (!widget.$video[0].paused)
579                                 widget.$video[0].pause();
580                         
581                         widget.setPlayButton();
582
583                         return widget;
584                 },
585                 
586                 toggleMute: function() {
587                         if (!widget.$video[0].muted)
588                         {
589                                 widget.html5.mute();
590                         }
591                         else
592                         {
593                                 widget.html5.unmute();
594                         }
595                 },
596                   
597                 mute: function() {
598                         if (!widget.$video[0].muted)
599                                 widget.$video[0].muted = true;
600                         
601                         widget.setMuteButton();
602                         
603                         return widget;
604                 },
605                 
606                 unmute: function() {
607                         if (widget.$video[0].muted)
608                                 widget.$video[0].muted = false;
609                         
610                         widget.setUnmuteButton();
611                         
612                         return widget;
613                 },
614                 
615                 /**
616                 * Volume value is expressed in percents.
617                 */
618                 volume: function(vol) {
619                         if (typeof vol == 'undefined')
620                                 return Math.round(widget.$video[0].volume * 100);
621                         
622                         widget.html5.unmute();
623                         widget.$video[0].volume = vol / 100;
624                         
625                         return widget;
626                 },
627                 
628                 /**
629                  * Seek position is a value between 0 and 1000.
630                  */
631                 crtTime: function(pos) {
632                         // getter
633                         if (typeof pos == 'undefined')
634                         {
635                                 var crtTime = widget.$video[0].currentTime;
636                                 var totTime = widget.$video[0].duration;
637                                 if (isNaN(totTime) || totTime == 0)
638                                         return 0;
639                                 else
640                                         return Math.round(crtTime / totTime * 1000.0);
641                         }
642                         
643                         // setter
644                         widget.$video[0].currentTime = 
645                                 pos / 1000 * widget.$video[0].duration;
646                 },
647                   
648                 refreshAll: function() {
649                         widget.html5.refreshState();
650                         widget.html5.refreshVolume();
651                         widget.html5.refreshLoadedProgress();
652                         widget.html5.refreshTime();
653                 },
654                 
655                 refreshTime: function() {
656                         if (widget.$video[0].seeking)
657                                 return widget;
658                         
659                         var crtTime = widget.$video[0].currentTime;
660                         var totTime = widget.$video[0].duration;
661                         
662                         // Refresh only at refreshInterval seconds to save CPU time.
663                         var delta = crtTime - widget.html5.lastTime;
664                         if (typeof widget.html5.lastTime !== "undefined"
665                                 && delta >= 0 && delta < widget.options.refreshInterval)
666                                 return widget;
667                         widget.html5.lastTime = crtTime;
668                         
669                         // Current time string
670                         var crtH = Math.floor(crtTime / 3600);
671                         var crtM = Math.floor((crtTime / 60) % 60);
672                         var crtS = Math.floor(crtTime % 60);
673                         var strCrtTime = 
674                                 (crtH == 0 ? '' : (widget._leadingZeros(crtH) + ':'))
675                                 + widget._leadingZeros(crtM) + ':' + widget._leadingZeros(crtS);
676                                 
677                         // Total time string
678                         var totH = Math.floor(totTime / 3600);
679                         var totM = Math.floor((totTime / 60) % 60);
680                         var totS = Math.floor(totTime % 60);
681                         var strTotTime = 
682                                 (totH == 0 || isNaN(totH) ? '' : (widget._leadingZeros(totH) + ':'))
683                                 + widget._leadingZeros(totM) + ':' + widget._leadingZeros(totS);
684                         
685                         widget.setTimeText('' + strCrtTime + ' / ' + strTotTime);
686                         
687                         // Update time progress slider.
688                         widget.html5.refreshProgress();
689                         
690                         return widget;
691                 },
692                 
693                 _state: function(type, code) {
694                         var r;
695                         $.each(widget.html5[type + '_STATES'], function(index, value) {
696                                 if ('' + code == '' + value[0])
697                                 {
698                                         r = value;
699                                         return false;
700                                 }
701                         });
702                         
703                         return r;
704                 },
705                 
706                 refreshState: function() {
707                         var err = "";
708                         var normal = "";
709                         var network = "";
710                         var ready = "";
711                         var state = "";
712                         
713                         if (widget.$video[0].error)
714                                 err = widget.html5._state('ERR',
715                                                                                   widget.$video[0].error.code)[1];
716                           
717                         if (! widget.$video[0].paused)
718                                 normal = "playing...";
719                         else
720                         {
721                                 normal = "paused";
722                         }
723                         if (widget.$video[0].seeking)
724                                 normal = "seeking";
725                         if (widget.$video[0].ended)
726                                 normal = "ended";
727                         
728                         network = widget.html5._state('NETWORK',
729                                                                         widget.$video[0].networkState)[1]; 
730                         
731                         ready = widget.html5._state('READY',
732                                                                         widget.$video[0].readyState)[1];
733                         
734                         if (err !== "")
735                                 state = err;
736                         else
737                         {
738                                 state = normal;
739                                 
740                                 if (normal !== "" && (network !== "" || ready !== "") )
741                                         state += ' / ';
742                                 
743                                 if (network !== "")
744                                         state += network;
745                                 
746                                 if (network !== "" && ready !== "")
747                                         state += ' / ';
748                                 
749                                 if (ready !== "")
750                                         state += ready;
751                         }
752                         
753                         widget.$stateText
754                                 .html(state);
755                         
756                         return widget;
757                 },
758
759                 refreshVolume: function() {
760                         var vol;
761                         
762                         if (widget.$video[0].muted)
763                                 vol = 0;
764                         else
765                                 vol = Math.floor(widget.$video[0].volume * 100);
766                         
767                         widget.setVolumeSlider(vol);
768                         
769                         return widget;
770                 },
771                 
772                 refreshProgress: function() {
773                         widget.setProgressSlider(widget.html5.crtTime());
774                         
775                         return widget;
776                 },
777                 
778                 /**
779                 * Supported for Firefox 4.0 or later.
780                 */
781                 refreshLoadedProgress: function() {
782                         // Return if buffering status not available in browser.
783                         if (typeof widget.$video[0].buffered == 'undefined'
784                                 || widget.$video[0].buffered.length === 0)
785                                 return widget;
786                         
787                         var loadedTime = widget.$video[0].buffered.end(0);
788                         var totTime = widget.$video[0].duration;
789                         var percent;
790                         if (isNaN(totTime) || totTime == 0)
791                                 percent = 0
792                         else
793                                 percent = Math.floor(loadedTime / totTime * 100);
794                         
795                         widget.setLoadedProgressSlider(percent);
796                         
797                         return widget;
798                 },
799
800                 fullscreen: function() {
801                         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.');
802                 }
803         },
804         
805         vlc: {
806                 widget: this,
807                 timerHandle: null,
808                 idleRefreshInterval: 1, // seconds
809                 
810                 STATES: {
811                         IDLE: [0, "idle"],
812                         OPENING: [1, "opening..."],
813                         BUFFERING: [2, "buffering..."],
814                         PLAYING: [3, "playing..."],
815                         PAUSED: [4, "paused"],
816                         STOPPING: [5, "stopping..."],
817                         ENDED: [6, "ended"],
818                         ERROR: [7, "error!"]
819                 },
820                 
821                 init: function() {
822                         if (widget.options.autoplay)
823                                 widget.vlc.play();
824                         widget.vlc.refreshAll();
825                 },
826                 
827                 togglePlay: function() {
828                         if (! widget.$video[0].playlist.isPlaying)
829                         {
830                                 widget.vlc.play();
831                         }
832                         else
833                         {
834                                 widget.vlc.pause();
835                         }
836                 },
837                 
838                 play: function() {
839                         if(typeof widget.$video[0].playlist.isPlaying == 'undefined')
840                                 return widget;
841                         
842                         widget.$installContainer.hide();
843                         
844                         if (! widget.$video[0].playlist.isPlaying)
845                                 widget.$video[0].playlist.play();
846                         
847                         widget.setPauseButton();
848                         
849                         // Schedule information refreshment at refreshInterval seconds.
850                         if (! widget.vlc.timerHandle)
851                                 widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler, 
852                                                                                 widget.options.refreshInterval * 1000);
853                                 
854                         widget.vlc.refreshState();
855                         
856                         return widget;
857                 },
858                 
859                 pause: function() {
860                         if (typeof widget.$video[0].playlist === 'undefined')
861                                 return widget;
862                         
863                         if (widget.$video[0].playlist.isPlaying)
864                                 widget.$video[0].playlist.togglePause();
865                         
866                         widget.setPlayButton();
867                         
868                         // Cancel information refreshment scheduling.
869                         clearTimeout(widget.vlc.timerHandle);
870                         widget.vlc.timerHandle = null;
871                         
872                         widget.vlc.refreshState();
873
874                         return widget;
875                 },
876                 
877                 toggleMute: function() {
878                         if (! widget.$video[0].audio.mute)
879                         {
880                                 widget.vlc.mute();
881                         }
882                         else
883                         {
884                                 widget.vlc.unmute();
885                         }
886                 },
887                   
888                 mute: function() {
889                         if (! widget.$video[0].audio.mute)
890                                 widget.$video[0].audio.toggleMute();
891                         
892                         widget.setMuteButton();
893                         
894                         widget.vlc.refreshVolume();
895                         
896                         return widget;
897                 },
898                 
899                 unmute: function() {
900                         if (widget.$video[0].audio.mute)
901                                 widget.$video[0].audio.toggleMute();
902                         
903                         widget.setUnmuteButton();
904                         
905                         widget.vlc.refreshVolume();
906                         
907                         return widget;
908                 },
909                 
910                 /**
911                 * Volume value is expressed in percents.
912                 */
913                 volume: function(vol) {
914                         if (typeof vol == 'undefined')
915                                 return Math.round(widget.$video[0].audio.volume);
916                         
917                         widget.vlc.unmute();
918                         widget.$video[0].audio.volume = vol;
919                         
920                         return widget;
921                 },
922                 
923                 /**
924                  * Seek position is a value between 0 and 1000.
925                  */
926                 crtTime: function(pos) {
927                         // getter
928                         if (typeof pos == 'undefined')
929                         {
930                                 var crtTime = widget.$video[0].input.time;
931                                 var totTime = widget.$video[0].input.length;
932                                 if (isNaN(totTime) || totTime == 0)
933                                         return 0;
934                                 else
935                                         return Math.round(crtTime / totTime * 1000.0);
936                         }
937                         
938                         // setter
939                         widget.$video[0].input.time = 
940                                 pos / 1000 * widget.$video[0].input.length;
941                                 
942                         widget.vlc.refreshState();
943                 },
944                 
945                 /**
946                  * Timeout callback called at refreshInterval during playing in order
947                  * to refresh information.
948                  */
949                 refreshHandler: function() {
950                         if (widget.$video[0].input.state
951                                 == widget.vlc.STATES.PLAYING[0])
952                         {
953                                 widget.vlc.refreshTime();
954                                 widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler, 
955                                                                                 widget.options.refreshInterval * 1000);
956                         }
957                         else
958                         {
959                                 if (widget.$video[0].input.state == widget.vlc.STATES.ENDED[0])
960                                 {
961                                         widget.vlc.pause();
962                                         try {
963                                                 widget.$video[0].playlist.stop();
964                                         } catch(e) {
965                                                 console.log('Exception: ' + e);
966                                         }
967                                 }
968                                 
969                                 widget.vlc.refreshTime();
970                                 widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler, 
971                                                                                 widget.vlc.idleRefreshInterval * 1000);
972                         }
973                         
974                         widget.vlc.refreshState();
975                 },
976                 
977                 refreshAll: function() {
978                         widget.vlc.refreshState();
979                         widget.vlc.refreshVolume();
980                         widget.vlc.refreshLoadedProgress();
981                         
982                         try {
983                                 widget.vlc.refreshTime();
984                         } catch(e) {
985                                 console.log('Exception: ' + e);
986                                 widget.$time.html('00:00 / ' + widget.options.initialDuration);
987                         }
988                 },
989                 
990                 refreshTime: function() {
991                         // TODO while seeking (maybe not necessary for VLC)
992 //                      if (widget.$video[0].seeking)
993 //                              return widget;
994                         
995                         // Time values in seconds.
996                         var crtTime = widget.$video[0].input.time / 1000.0;
997                         var totTime = widget.$video[0].input.length / 1000.0;
998                         //var crtTime = widget.$video[0].input.position * totTime;
999                         
1000                         // Current time string
1001                         var crtH = Math.floor(crtTime / 3600);
1002                         var crtM = Math.floor((crtTime / 60) % 60);
1003                         var crtS = Math.floor(crtTime % 60);
1004                         var strCrtTime = 
1005                                 (crtH == 0 ? '' : (widget._leadingZeros(crtH) + ':'))
1006                                 + widget._leadingZeros(crtM) + ':' + widget._leadingZeros(crtS);
1007                                 
1008                         // Total time string
1009                         var totH = Math.floor(totTime / 3600);
1010                         var totM = Math.floor((totTime / 60) % 60);
1011                         var totS = Math.floor(totTime % 60);
1012                         var strTotTime = 
1013                                 (totH == 0 || isNaN(totH) ? '' : (widget._leadingZeros(totH) + ':'))
1014                                 + widget._leadingZeros(totM) + ':' + widget._leadingZeros(totS);
1015                         
1016                         widget.setTimeText('' + strCrtTime + ' / ' + strTotTime);
1017                         
1018                         // Update time progress slider.
1019                         widget.vlc.refreshProgress();
1020                         
1021                         return widget;
1022                 },
1023                 
1024                 _state: function(code) {
1025                         var r;
1026                         $.each(widget.vlc.STATES, function(index, value) {
1027                                 if ('' + code == '' + value[0])
1028                                 {
1029                                         r = value;
1030                                         return false;
1031                                 }
1032                         });
1033                         
1034                         return r;
1035                 },
1036                 
1037                 refreshState: function() {
1038                         widget.$stateText
1039                                 .html(widget.vlc._state(widget.$video[0].input.state)[1]);
1040                                 
1041                         return widget;
1042                 },
1043
1044                 refreshVolume: function() {
1045                         var vol;
1046                         
1047                         if (widget.$video[0].audio.mute)
1048                                 vol = 0;
1049                         else
1050                                 vol = Math.floor(widget.$video[0].audio.volume);
1051                         
1052                         widget.setVolumeSlider(vol);
1053                         
1054                         return widget;
1055                 },
1056                 
1057                 refreshProgress: function() {
1058                         widget.setProgressSlider(widget.vlc.crtTime());
1059                         
1060                         return widget;
1061                 },
1062                 
1063                 /**
1064                 * Not supported for VLC.
1065                 */
1066                 refreshLoadedProgress: function() {
1067                         // TODO Currently not possible through VLC API.
1068                         
1069                         return widget;
1070                 },
1071
1072                 fullscreen: function() {
1073                         widget.$video[0].video.toggleFullscreen();
1074                 }
1075         }
1076 });
1077
1078 })( jQuery );