uploading works, but AV info is not automatically detected and video activation featu...
[living-lab-site.git] / js / jquery.ui.nsvideo.js
index 31b7c4c..2d87c07 100644 (file)
@@ -16,17 +16,19 @@ $.widget( "ui.nsvideo", {
        version: "1.0.0 beta",
        options: {
                type: 'ns-html5',
-               width: 320,
-               height: 240,
-               showStatus: true,
+               srcIndex: 0,
+               width: 0,
+               height: 0,
+               minWidth: 0,
+               maxWidth: 0,
+               showState: true,
                refreshInterval: 0.1,   // seconds
-               autoplay: false
+               autoplay: false,
+               initialDuration: "--:--"
        },
-
-       min: 0,
-
+       
        _create: function() {
-               var widget = this;
+               widget = this;
                
                widget.element
                        .addClass( "ui-widget ui-widget-content ui-corner-all" );
@@ -57,6 +59,8 @@ $.widget( "ui.nsvideo", {
                                        max: 1000,
                                        slide: function(event, ui) {
                                                widget.videoPlugin('crtTime', [ui.value]);
+                                               widget.videoPlugin('refreshTime');
+                                               widget.videoPlugin('refreshState');
                                        }
                        });
                
@@ -72,7 +76,7 @@ $.widget( "ui.nsvideo", {
                        });
                
                // Time information (current and total)
-               widget.$time = $('<div class="ui-nsvideo-time ui-nsvideo-text ui-nsvideo-control-left">--:-- / --:--</div>')
+               widget.$time = $('<div class="ui-nsvideo-time ui-nsvideo-text ui-nsvideo-control-left">00:00 / ' + widget.options.initialDuration + '</div>')
                        .appendTo(widget.$controls);
                        
                // Full screen
@@ -86,26 +90,27 @@ $.widget( "ui.nsvideo", {
                                widget.videoPlugin('fullscreen');
                        });
 
-               // Video definition buttonset
+               // Video format buttonset
                if (typeof widget.options.src == 'object')
                {
-                       var $definitions = $('<form><div class="ui-nsvideo-definitions ui-nsvideo-control-right"></div></form>')
+                       var $formats = $('<form><div class="ui-nsvideo-formats ui-nsvideo-control-right"></div></form>')
                                .appendTo(widget.$controls);
-                       $definitions = $('.ui-nsvideo-definitions', $definitions[0]);
+                       $formats = $('.ui-nsvideo-formats', $formats[0]);
                        $.each(widget.options.src, function(index, value) {
-                               id = widget.element.attr('id') + '-def-' + index;
-                               $('<input type="radio" id="' + id + '" name="definition" />')
-                                       .appendTo($definitions)
-                                       .attr('checked', (index == widget.options.definition))
+                               var id = widget.element.attr('id') + '-format-' + index;
+                               var definition = value.res.substring(value.res.indexOf('x')+1)+'p';
+                               $('<input type="radio" id="' + id + '" name="format" />')
+                                       .appendTo($formats)
+                                       .attr('checked', (index == widget.options.srcIndex))
                                        .click(function() {
                                                widget.videoPlugin('pause');
-                                               widget.definition(index);
+                                               widget.srcIndex(index);
                                        });
-                               $('<label for="' + id + '">' + index + '</label>')
-                                       .appendTo($definitions);
+                               $('<label for="' + id + '">' + definition + '</label>')
+                                       .appendTo($formats);
                        });
                        
-                       $definitions.buttonset();
+                       $formats.buttonset();
                }
                
                // Volume
@@ -132,24 +137,18 @@ $.widget( "ui.nsvideo", {
                        });
                        
                // Status information
-               if (widget.options.showStatus)
-               {
-                       widget.$stateText = $('<div class="ui-nsvideo-text ui-nsvideo-control-right">...</div>')
-                               .appendTo(widget.$controls)
-                               .css('cursor', 'pointer')
-                               .click(function() {
-                                       widget.videoPlugin('refreshAll');
-                               });
-               }
+               widget.$stateText = $('<div class="ui-nsvideo-text ui-nsvideo-control-right">...</div>')
+                       .appendTo(widget.$controls)
+                       .css('cursor', 'pointer')
+                       .click(function() {
+                               widget.videoPlugin('refreshAll');
+                       });
+               if (! widget.options.showState)
+                       widget.$stateText.hide();
                
                // Clear fix helper
                $('<div class="ui-helper-clearfix"></div>')
                        .appendTo(widget.$controls);
-                       
-               // Initialize video plugin
-               widget.$video.ready(function() {
-                       widget.videoPlugin('init');
-               });
        },
 
        _destroy: function() {
@@ -188,18 +187,33 @@ $.widget( "ui.nsvideo", {
        },
        
        video: function() {
-               widget = this;
+               var widget = this;
                
                // Select video source.
                // If src option is string, that's the source.
-               // If src is an object, properties are definitions and values are
-               // sources.
+               // If src is an object, there is a list of associative arrays, each
+               // one having the mandatory keys "src" and "res" (resolution).
                var src = widget.crtSrc();
                if (src == null)
                        return widget;
                
                widget.$videoContainer.html('');
                
+               // Install buttons or not supported message if required
+               if (typeof $.fn.nsinstall == 'function')
+               {
+                       widget.$installContainer = $('<div class="container-install-in-widget"></div>')
+                               .appendTo(widget.$videoContainer);
+                       widget.$installContainer
+                               .nsinstall({
+                                       type: widget.options.type,
+                                       hideIfAlreadyInstalled: true
+                               });
+                       if (widget.$installContainer.nsinstall('option', 'error')
+                                       == 'already installed')
+                               widget.$installContainer.hide();
+               }
+               
                var width = widget.options.width;
                var height = widget.options.height;
                
@@ -214,12 +228,15 @@ $.widget( "ui.nsvideo", {
                                .bind({
                                        ended: function() {
                                                widget.html5.pause();
+                                               widget.html5.refreshState();
                                        },
                                        play: function() {
                                                widget.html5.play();
+                                               widget.html5.refreshState();
                                        },
                                        pause: function() {
                                                widget.html5.pause();
+                                               widget.html5.refreshState();
                                        },
                                        timeupdate: function() {
                                                widget.html5.refreshTime();
@@ -230,13 +247,47 @@ $.widget( "ui.nsvideo", {
                                        loadedmetadata: function() {
                                                widget.html5.refreshTime();
                                                widget.html5.refreshVolume();
+                                               widget.html5.refreshState();
                                                widget._setWidgetWidth();
+                                               
+                                               if (widget.$video[0].error != 3
+                                                               && widget.$video[0].error != 4)
+                                                       widget.$installContainer.hide();
                                        },
                                        seeked: function() {
                                                widget.html5.play();
+                                               widget.html5.refreshState();
                                        },
                                        volumechange: function() {
                                                widget.html5.refreshVolume();
+                                       },
+                                       
+                                       loadstart: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       suspend: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       abort: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       error: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       emptied: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       stalled: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       loadeddata: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       waiting: function() {
+                                               widget.html5.refreshState();
+                                       },
+                                       seeking: function() {
+                                               widget.html5.refreshState();
                                        }
                                });
                }
@@ -268,12 +319,71 @@ $.widget( "ui.nsvideo", {
                        }
                }
                
-               widget.$video.css('position', 'relative');
+               //  BUG: this if is because of a NS-VLC bug.
+               if (widget.options.type != 'ns-vlc')
+                       widget.$video.css('position', 'relative');
+               
+               // Adjust video size for auto-resizing within ranges minWidth and
+               // maxWidth.
+               if ( (width == 0 || height == 0)
+                       && (widget.options.minWidth != 0 && widget.options.maxWidth != 0
+                               || this.options.type.indexOf('vlc') != -1) )
+               {
+                       widget.adjustVideoSizeFromMeta();
+               }
+               
+               // Initialize video plugin
+               widget.$video.ready(function() {
+                       widget.videoPlugin('init');
+               });
                
                widget._setWidgetWidth();
        },
        
+       adjustVideoSizeFromMeta: function() {
+               var widget = this;
+               
+               if (typeof widget.options.src == 'object'
+                       && (typeof widget.options.src[ widget.options.srcIndex ].res)
+                               != 'undefined'
+                       && (typeof widget.options.src[ widget.options.srcIndex ].dar)
+                               != 'undefined')
+               {
+                       var resolution = widget.options.src[ widget.options.srcIndex ].res;
+                       var dar = widget.options.src[ widget.options.srcIndex ].dar;
+                       var darL = parseInt(
+                               dar.substring(0, dar.indexOf(':')));
+                       var darR = parseInt(
+                               dar.substring(dar.indexOf(':') + 1));
+                       var videoHeight = parseInt(
+                               resolution.substring(resolution.indexOf('x') + 1));
+                       var videoWidth = Math.round(videoHeight * darL / darR);
+                       
+                       // Video width must be between minWidth and maxWidth pixels.
+                       if (widget.options.minWidth != 0 && widget.options.maxWidth != 0)
+                       {
+                               if (videoWidth > widget.options.maxWidth)
+                               {
+                                       videoHeight = Math.round(widget.options.maxWidth / videoWidth
+                                               * videoHeight);
+                                       videoWidth = widget.options.maxWidth;
+                               }
+                               else if (videoWidth < widget.options.minWidth)
+                               {
+                                       videoHeight = Math.round(widget.options.minWidth / videoWidth
+                                               * videoHeight);
+                                       videoWidth = widget.options.minWidth;
+                               }
+                       }
+                       
+                       widget.$video.css('width', videoWidth);
+                       widget.$video.css('height', videoHeight);
+               }
+       },
+       
        _setWidgetWidth: function() {
+        var widget = this;
+        
                if (widget.$video.width() < 640)
                {
                        widget.element.css('width',
@@ -284,8 +394,13 @@ $.widget( "ui.nsvideo", {
                                + 'px');
                }
                else
+               {
                        widget.element.css('width',
-                                                       widget.$video.width + 8 + 'px');
+                                                       widget.$video.width() + 8 + 'px');
+                       widget.$video.css('left', '0');
+               }
+               
+               this._trigger('resize');
        },
        
        setPlayButton: function() {
@@ -346,13 +461,15 @@ $.widget( "ui.nsvideo", {
                return null;
        },
        
-       definition: function(def) {
+       srcIndex: function(srcIndex) {
                var widget = this;
                
-               if (typeof def == 'undefined')
-                       return widget.options.definition;
+               if (typeof srcIndex == 'undefined')
+                       return widget.options.srcIndex;
                
-               widget.options.definition = def;
+               widget.options.srcIndex = srcIndex;
+               
+               // Refresh.
                widget.video();
                
                return widget;
@@ -364,6 +481,10 @@ $.widget( "ui.nsvideo", {
                if (typeof type == 'undefined')
                        return widget.options.type;
                
+               widget.videoPlugin('pause');
+               if (widget.vlc.timerHandle)
+                       clearTimeout(widget.vlc.timerHandle);
+               
                widget.options.type = type;
                widget.video();
                
@@ -383,14 +504,14 @@ $.widget( "ui.nsvideo", {
                        src = widget.options.src;
                else if (typeof widget.options.src == 'object')
                {
-                       if (typeof widget.options.definition == 'undefined')
+                       if (typeof widget.options.srcIndex == 'undefined')
                                return null;
                        
-                       if (typeof widget.options.src[ widget.options.definition ]
+                       if (typeof widget.options.src[ widget.options.srcIndex ].src
                                == 'undefined')
                                return null;
                        
-                       src = widget.options.src[ widget.options.definition ];
+                       src = widget.options.src[ widget.options.srcIndex ].src;
                }
                
                if (widget.options.type == 'ns-html5')
@@ -403,9 +524,34 @@ $.widget( "ui.nsvideo", {
                widget: this,
                //lastTime: null,
                
+               ERR_STATES: {
+                       MEDIA_ERR_ABORTED: [1, "error: aborted"],
+                       MEDIA_ERR_NETWORK: [2, "network error"],
+                       MEDIA_ERR_DECODE: [3, "decode error"],
+                       MEDIA_ERR_SRC_NOT_SUPPORTED: [4, "error: source not supported"]
+               },
+               
+               NETWORK_STATES: {
+                       NETWORK_EMPTY: [0, "no data from network"],
+                       NETWORK_IDLE: [1, ""],
+                       NETWORK_LOADING: [2, "loading..."],
+                       NETWORK_LOADED: [3, "loading completed"],
+                       NETWORK_NO_SOURCE: [4, "network: no source"]
+               },
+               
+               READY_STATES: {
+                       HAVE_NOTHING: [0, "please wait..."],
+                       HAVE_METADATA: [1, ""],
+                       HAVE_CURRENT_DATA: [2, ""],
+                       HAVE_FUTURE_DATA: [3, ""],
+                       HAVE_ENOUGH_DATA: [4, "have enough data"]
+               },
+               
                init: function() {
                        //widget.html5.refreshAll();
                        
+                       widget.html5.refreshState();
+                       
                        //if (widget.options.autoplay)
                        //      widget.html5.play();
                },
@@ -505,8 +651,6 @@ $.widget( "ui.nsvideo", {
                        widget.html5.refreshState();
                        widget.html5.refreshVolume();
                        widget.html5.refreshLoadedProgress();
-                       widget.$time.html('--:-- / --:--');
-                       widget.$stateText.html('...');
                        widget.html5.refreshTime();
                },
                
@@ -548,8 +692,70 @@ $.widget( "ui.nsvideo", {
                        return widget;
                },
                
+               _state: function(type, code) {
+                       var r;
+                       $.each(widget.html5[type + '_STATES'], function(index, value) {
+                               if ('' + code == '' + value[0])
+                               {
+                                       r = value;
+                                       return false;
+                               }
+                       });
+                       
+                       return r;
+               },
+               
                refreshState: function() {
-                       // TODO refresh HTML5 plugin state
+            var widget = this;
+            
+                       var err = "";
+                       var normal = "";
+                       var network = "";
+                       var ready = "";
+                       var state = "";
+                       
+                       if (widget.$video[0].error)
+                               err = widget.html5._state('ERR',
+                                                                                 widget.$video[0].error.code)[1];
+                         
+                       if (! widget.$video[0].paused)
+                               normal = "playing...";
+                       else
+                       {
+                               normal = "paused";
+                       }
+                       if (widget.$video[0].seeking)
+                               normal = "seeking";
+                       if (widget.$video[0].ended)
+                               normal = "ended";
+                       
+                       network = widget.html5._state('NETWORK',
+                                                                       widget.$video[0].networkState)[1]; 
+                       
+                       ready = widget.html5._state('READY',
+                                                                       widget.$video[0].readyState)[1];
+                       
+                       if (err !== "")
+                               state = err;
+                       else
+                       {
+                               state = normal;
+                               
+                               if (normal !== "" && (network !== "" || ready !== "") )
+                                       state += ' / ';
+                               
+                               if (network !== "")
+                                       state += network;
+                               
+                               if (network !== "" && ready !== "")
+                                       state += ' / ';
+                               
+                               if (ready !== "")
+                                       state += ready;
+                       }
+                       
+                       widget.$stateText
+                               .html(state);
                        
                        return widget;
                },
@@ -603,15 +809,17 @@ $.widget( "ui.nsvideo", {
        vlc: {
                widget: this,
                timerHandle: null,
+               idleRefreshInterval: 1, // seconds
                
                STATES: {
-                       IDLE_CLOSE: [0, "Idle / Close"],
-                       OPENING: [1, "Opening..."],
-                       BUFFERING: [2, "Buffering..."],
-                       PLAYING: [3, "Playing..."],
-                       PAUSED: [4, "Paused"],
-                       STOPPING: [5, "Stopping..."],
-                       ERROR: [6, "Error!"]
+                       IDLE: [0, "idle"],
+                       OPENING: [1, "opening..."],
+                       BUFFERING: [2, "buffering..."],
+                       PLAYING: [3, "playing..."],
+                       PAUSED: [4, "paused"],
+                       STOPPING: [5, "stopping..."],
+                       ENDED: [6, "ended"],
+                       ERROR: [7, "error!"]
                },
                
                init: function() {
@@ -632,6 +840,11 @@ $.widget( "ui.nsvideo", {
                },
                
                play: function() {
+                       if(typeof widget.$video[0].playlist.isPlaying == 'undefined')
+                               return widget;
+                       
+                       widget.$installContainer.hide();
+                       
                        if (! widget.$video[0].playlist.isPlaying)
                                widget.$video[0].playlist.play();
                        
@@ -648,6 +861,9 @@ $.widget( "ui.nsvideo", {
                },
                
                pause: function() {
+                       if (typeof widget.$video[0].playlist === 'undefined')
+                               return widget;
+                       
                        if (widget.$video[0].playlist.isPlaying)
                                widget.$video[0].playlist.togglePause();
                        
@@ -743,7 +959,21 @@ $.widget( "ui.nsvideo", {
                                                                                widget.options.refreshInterval * 1000);
                        }
                        else
-                               widget.vlc.pause();
+                       {
+                               if (widget.$video[0].input.state == widget.vlc.STATES.ENDED[0])
+                               {
+                                       widget.vlc.pause();
+                                       try {
+                                               widget.$video[0].playlist.stop();
+                                       } catch(e) {
+                                               console.log('Exception: ' + e);
+                                       }
+                               }
+                               
+                               widget.vlc.refreshTime();
+                               widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler, 
+                                                                               widget.vlc.idleRefreshInterval * 1000);
+                       }
                        
                        widget.vlc.refreshState();
                },
@@ -756,8 +986,8 @@ $.widget( "ui.nsvideo", {
                        try {
                                widget.vlc.refreshTime();
                        } catch(e) {
-                               console.log(e);
-                               widget.$time.html('--:-- / --:--');
+                               console.log('Exception: ' + e);
+                               widget.$time.html('00:00 / ' + widget.options.initialDuration);
                        }
                },
                
@@ -811,6 +1041,8 @@ $.widget( "ui.nsvideo", {
                refreshState: function() {
                        widget.$stateText
                                .html(widget.vlc._state(widget.$video[0].input.state)[1]);
+                               
+                       return widget;
                },
 
                refreshVolume: function() {