2 * jQuery UI NS-Video 1.0.0 beta
4 * Copyright 2011, Călin-Andrei Burloiu
5 * Dual licensed under the MIT or GPL Version 2 licenses.
6 * http://jquery.org/license
13 (function( $, undefined ) {
15 $.widget( "ui.nsvideo", {
16 version: "1.0.0 beta",
25 refreshInterval: 0.1, // seconds
35 .addClass( "ui-widget ui-widget-content ui-corner-all" );
37 widget.$videoContainer = $('<div class="ui-nsvideo-nsplugin"></div>')
38 .appendTo(widget.element);
39 widget.$progressContainer = $('<div class="ui-nsvideo-progress-container ui-widget-content ui-corner-top"></div>')
40 .appendTo(widget.element);
41 widget.$progress = $('<div class="ui-nsvideo-progress"></div>')
42 .appendTo(widget.$progressContainer);
43 widget.$loadedProgress = $('<div class="ui-nsvideo-loaded-progress"></div>')
44 .appendTo(widget.$progress);
45 widget.$controls = $('<div class="ui-nsvideo-controls ui-widget-content ui-corner-bottom"></div>')
46 .appendTo(widget.element);
50 // Time progress slider with load progress also
51 widget.$loadedProgress
52 // TODO an object that inherits progressbar should be used in order to customize min value.
61 slide: function(event, ui) {
62 widget.videoPlugin('crtTime', [ui.value]);
67 $('<button class="ui-nsvideo-play ui-nsvideo-button ui-nsvideo-control-left">Play / Pause</button>')
68 .appendTo(widget.$controls)
71 icons: { primary: "ui-icon-play" }
74 widget.videoPlugin('togglePlay');
77 // Time information (current and total)
78 widget.$time = $('<div class="ui-nsvideo-time ui-nsvideo-text ui-nsvideo-control-left">--:-- / --:--</div>')
79 .appendTo(widget.$controls);
82 $('<button class="ui-nsvideo-fullscreen ui-nsvideo-button ui-nsvideo-control-right">Full Screen</button>')
83 .appendTo(widget.$controls)
86 icons: { primary: "ui-icon-arrow-4-diag" }
89 widget.videoPlugin('fullscreen');
92 // Video format buttonset
93 if (typeof widget.options.src == 'object')
95 var $formats = $('<form><div class="ui-nsvideo-formats ui-nsvideo-control-right"></div></form>')
96 .appendTo(widget.$controls);
97 $formats = $('.ui-nsvideo-formats', $formats[0]);
98 $.each(widget.options.src, function(index, value) {
99 id = widget.element.attr('id') + '-format-' + index;
100 definition = value.res.substring(value.res.indexOf('x')+1)+'p';
101 $('<input type="radio" id="' + id + '" name="format" />')
103 .attr('checked', (index == widget.options.srcIndex))
105 widget.videoPlugin('pause');
106 widget.srcIndex(index);
108 $('<label for="' + id + '">' + definition + '</label>')
112 $formats.buttonset();
116 $('<div class="ui-nsvideo-volume ui-nsvideo-control-right"></div>')
117 .appendTo(widget.$controls)
122 slide: function(event, ui) {
123 widget.videoPlugin('volume', [ui.value]);
128 $('<button class="ui-nsvideo-mute ui-nsvideo-button ui-nsvideo-control-right">Mute</button>')
129 .appendTo(widget.$controls)
132 icons: { primary: "ui-icon-volume-on" }
135 widget.videoPlugin('toggleMute');
138 // Status information
139 if (widget.options.showStatus)
141 widget.$stateText = $('<div class="ui-nsvideo-text ui-nsvideo-control-right">...</div>')
142 .appendTo(widget.$controls)
143 .css('cursor', 'pointer')
145 widget.videoPlugin('refreshAll');
150 $('<div class="ui-helper-clearfix"></div>')
151 .appendTo(widget.$controls);
153 // Initialize video plugin
154 widget.$video.ready(function() {
155 //widget.videoPlugin('init');
159 _destroy: function() {
163 _setOption: function( key, value ) {
165 if ( key === "TODO" ) {
169 this._super( "_setOption", key, value );
172 _leadingZeros: function(number, length) {
180 for (var i=0; i<length; i++)
186 while (str.length < length)
197 // Select video source.
198 // If src option is string, that's the source.
199 // If src is an object, there is a list of associative arrays, each
200 // one having the mandatory keys "src" and "res" (resolution).
201 var src = widget.crtSrc();
205 widget.$videoContainer.html('');
207 var width = widget.options.width;
208 var height = widget.options.height;
211 if (widget.options.type == 'ns-html5'
212 || widget.options.type == 'html5')
214 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"' : '') + '>'
215 +'Error: Your browser does not support HTML5 or the video format!'
217 .appendTo(widget.$videoContainer)
220 widget.html5.pause();
226 widget.html5.pause();
228 timeupdate: function() {
229 widget.html5.refreshTime();
231 progress: function() {
232 widget.html5.refreshLoadedProgress();
234 loadedmetadata: function() {
235 widget.html5.refreshTime();
236 widget.html5.refreshVolume();
237 widget._setWidgetWidth();
242 volumechange: function() {
243 widget.html5.refreshVolume();
248 else if (widget.options.type == 'ns-vlc'
249 || widget.options.type == 'vlc')
252 if (widget.options.type == 'ns-vlc')
253 embedType = 'application/x-ns-stream';
255 embedType = 'application/x-vlc-plugin';
257 if (navigator.appName == "Netscape")
259 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 + '" />')
260 .appendTo(widget.$videoContainer);
264 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="">'
265 + '<param name="Src" value="' + src + '" />'
266 + '<param name="ShowDisplay" value="True" />'
267 + '<param name="Loop" value="False" />'
268 + '<param name="AutoPlay" value="' + (widget.options.autoplay ? 'True' : 'False') + '" />'
269 + '<param name="Toolbar" value="False" />'
271 .appendTo(widget.$videoContainer);
275 widget.$video.css('position', 'relative');
277 // Adjust video size for auto-resizing within ranges minWidth and
279 if (widget.options.minWidth != 0 && widget.options.maxWidth != 0
280 && typeof widget.options.src == 'object'
281 && (typeof widget.options.src[ widget.options.srcIndex ].res)
283 && (typeof widget.options.src[ widget.options.srcIndex ].dar)
286 var resolution = widget.options.src[ widget.options.srcIndex ].res;
287 var dar = widget.options.src[ widget.options.srcIndex ].dar;
289 dar.substring(0, dar.indexOf(':')));
291 dar.substring(dar.indexOf(':') + 1));
292 var videoHeight = parseInt(
293 resolution.substring(resolution.indexOf('x') + 1));
294 var videoWidth = Math.round(videoHeight * darL / darR);
295 // Video width must be between minWidth and maxWidth pixels.
296 if (videoWidth > widget.options.maxWidth)
298 videoHeight = Math.round(widget.options.maxWidth / videoWidth
300 videoWidth = widget.options.maxWidth;
302 else if (videoWidth < widget.options.minWidth)
304 videoHeight = Math.round(widget.options.minWidth / videoWidth
306 videoWidth = widget.options.minWidth;
308 console.log(videoWidth + ' ' + videoHeight);
309 widget.$video.css('width', videoWidth);
310 widget.$video.css('height', videoHeight);
313 widget._setWidgetWidth();
316 _setWidgetWidth: function() {
317 if (widget.$video.width() < 640)
319 widget.element.css('width',
321 widget.$video.css('left',
322 Math.round(widget.$videoContainer.width()/2
323 - widget.$video.width()/2)
328 widget.element.css('width',
329 widget.$video.width() + 8 + 'px');
330 widget.$video.css('left', '0');
334 setPlayButton: function() {
335 $('button.ui-nsvideo-play', widget.element[0])
336 .button('option', 'icons', { primary: "ui-icon-play" })
339 setPauseButton: function() {
340 $('button.ui-nsvideo-play', widget.element[0])
341 .button('option', 'icons', { primary: "ui-icon-pause" })
344 setMuteButton: function() {
345 $('button.ui-nsvideo-mute', widget.element[0])
346 .button('option', 'icons', { primary: "ui-icon-volume-off" })
349 setUnmuteButton: function() {
350 $('button.ui-nsvideo-mute', widget.element[0])
351 .button('option', 'icons', { primary: "ui-icon-volume-on" })
354 setTimeText: function(text) {
355 //$('.ui-nsvideo-time', widget.element[0])
359 setVolumeSlider: function(vol) {
360 $('.ui-nsvideo-volume', widget.element[0])
361 .slider('value', vol);
363 setProgressSlider: function(prog) {
364 $('.ui-nsvideo-progress', widget.element[0])
365 .slider('value', prog);
367 setLoadedProgressSlider: function(prog) {
368 $('.ui-nsvideo-loaded-progress', widget.element[0])
369 .progressbar('value', prog);
372 videoPlugin: function(method, args) {
373 if (typeof args == 'undefined')
375 var videoPlugin = null;
377 if (this.options.type.indexOf('html5') != -1)
379 videoPlugin = this.html5;
381 else if (this.options.type.indexOf('vlc') != -1)
383 videoPlugin = this.vlc;
387 return videoPlugin[method].apply(this, args);
392 srcIndex: function(srcIndex) {
395 if (typeof srcIndex == 'undefined')
396 return widget.options.srcIndex;
398 widget.options.srcIndex = srcIndex;
406 type: function(type) {
409 if (typeof type == 'undefined')
410 return widget.options.type;
412 widget.options.type = type;
415 // Initialize video plugin
416 widget.$video.ready(function() {
417 widget.videoPlugin('init');
427 if (typeof widget.options.src == 'string')
428 src = widget.options.src;
429 else if (typeof widget.options.src == 'object')
431 if (typeof widget.options.srcIndex == 'undefined')
434 if (typeof widget.options.src[ widget.options.srcIndex ].src
438 src = widget.options.src[ widget.options.srcIndex ].src;
441 if (widget.options.type == 'ns-html5')
442 src = 'tribe://' + src;
452 //widget.html5.refreshAll();
454 //if (widget.options.autoplay)
455 // widget.html5.play();
458 togglePlay: function() {
459 if (widget.$video[0].paused)
465 widget.html5.pause();
470 if (widget.$video[0].paused)
471 widget.$video[0].play();
473 widget.setPauseButton();
479 if (!widget.$video[0].paused)
480 widget.$video[0].pause();
482 widget.setPlayButton();
487 toggleMute: function() {
488 if (!widget.$video[0].muted)
494 widget.html5.unmute();
499 if (!widget.$video[0].muted)
500 widget.$video[0].muted = true;
502 widget.setMuteButton();
508 if (widget.$video[0].muted)
509 widget.$video[0].muted = false;
511 widget.setUnmuteButton();
517 * Volume value is expressed in percents.
519 volume: function(vol) {
520 if (typeof vol == 'undefined')
521 return Math.round(widget.$video[0].volume * 100);
523 widget.html5.unmute();
524 widget.$video[0].volume = vol / 100;
530 * Seek position is a value between 0 and 1000.
532 crtTime: function(pos) {
534 if (typeof pos == 'undefined')
536 var crtTime = widget.$video[0].currentTime;
537 var totTime = widget.$video[0].duration;
538 if (isNaN(totTime) || totTime == 0)
541 return Math.round(crtTime / totTime * 1000.0);
545 widget.$video[0].currentTime =
546 pos / 1000 * widget.$video[0].duration;
549 refreshAll: function() {
550 widget.html5.refreshState();
551 widget.html5.refreshVolume();
552 widget.html5.refreshLoadedProgress();
553 widget.$time.html('--:-- / --:--');
554 widget.$stateText.html('...');
555 widget.html5.refreshTime();
558 refreshTime: function() {
559 if (widget.$video[0].seeking)
562 var crtTime = widget.$video[0].currentTime;
563 var totTime = widget.$video[0].duration;
565 // Refresh only at refreshInterval seconds to save CPU time.
566 var delta = crtTime - widget.html5.lastTime;
567 if (typeof widget.html5.lastTime !== "undefined"
568 && delta >= 0 && delta < widget.options.refreshInterval)
570 widget.html5.lastTime = crtTime;
572 // Current time string
573 var crtH = Math.floor(crtTime / 3600);
574 var crtM = Math.floor((crtTime / 60) % 60);
575 var crtS = Math.floor(crtTime % 60);
577 (crtH == 0 ? '' : (widget._leadingZeros(crtH) + ':'))
578 + widget._leadingZeros(crtM) + ':' + widget._leadingZeros(crtS);
581 var totH = Math.floor(totTime / 3600);
582 var totM = Math.floor((totTime / 60) % 60);
583 var totS = Math.floor(totTime % 60);
585 (totH == 0 || isNaN(totH) ? '' : (widget._leadingZeros(totH) + ':'))
586 + widget._leadingZeros(totM) + ':' + widget._leadingZeros(totS);
588 widget.setTimeText('' + strCrtTime + ' / ' + strTotTime);
590 // Update time progress slider.
591 widget.html5.refreshProgress();
596 refreshState: function() {
597 // TODO refresh HTML5 plugin state
602 refreshVolume: function() {
605 if (widget.$video[0].muted)
608 vol = Math.floor(widget.$video[0].volume * 100);
610 widget.setVolumeSlider(vol);
615 refreshProgress: function() {
616 widget.setProgressSlider(widget.html5.crtTime());
622 * Supported for Firefox 4.0 or later.
624 refreshLoadedProgress: function() {
625 // Return if buffering status not available in browser.
626 if (typeof widget.$video[0].buffered == 'undefined'
627 || widget.$video[0].buffered.length === 0)
630 var loadedTime = widget.$video[0].buffered.end(0);
631 var totTime = widget.$video[0].duration;
633 if (isNaN(totTime) || totTime == 0)
636 percent = Math.floor(loadedTime / totTime * 100);
638 widget.setLoadedProgressSlider(percent);
643 fullscreen: function() {
644 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.');
653 IDLE_CLOSE: [0, "Idle / Close"],
654 OPENING: [1, "Opening..."],
655 BUFFERING: [2, "Buffering..."],
656 PLAYING: [3, "Playing..."],
657 PAUSED: [4, "Paused"],
658 STOPPING: [5, "Stopping..."],
663 if (widget.options.autoplay)
665 widget.vlc.refreshAll();
668 togglePlay: function() {
669 if (! widget.$video[0].playlist.isPlaying)
680 if (! widget.$video[0].playlist.isPlaying)
681 widget.$video[0].playlist.play();
683 widget.setPauseButton();
685 // Schedule information refreshment at refreshInterval seconds.
686 if (! widget.vlc.timerHandle)
687 widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler,
688 widget.options.refreshInterval * 1000);
690 widget.vlc.refreshState();
696 if (widget.$video[0].playlist.isPlaying)
697 widget.$video[0].playlist.togglePause();
699 widget.setPlayButton();
701 // Cancel information refreshment scheduling.
702 clearTimeout(widget.vlc.timerHandle);
703 widget.vlc.timerHandle = null;
705 widget.vlc.refreshState();
710 toggleMute: function() {
711 if (! widget.$video[0].audio.mute)
722 if (! widget.$video[0].audio.mute)
723 widget.$video[0].audio.toggleMute();
725 widget.setMuteButton();
727 widget.vlc.refreshVolume();
733 if (widget.$video[0].audio.mute)
734 widget.$video[0].audio.toggleMute();
736 widget.setUnmuteButton();
738 widget.vlc.refreshVolume();
744 * Volume value is expressed in percents.
746 volume: function(vol) {
747 if (typeof vol == 'undefined')
748 return Math.round(widget.$video[0].audio.volume);
751 widget.$video[0].audio.volume = vol;
757 * Seek position is a value between 0 and 1000.
759 crtTime: function(pos) {
761 if (typeof pos == 'undefined')
763 var crtTime = widget.$video[0].input.time;
764 var totTime = widget.$video[0].input.length;
765 if (isNaN(totTime) || totTime == 0)
768 return Math.round(crtTime / totTime * 1000.0);
772 widget.$video[0].input.time =
773 pos / 1000 * widget.$video[0].input.length;
775 widget.vlc.refreshState();
779 * Timeout callback called at refreshInterval during playing in order
780 * to refresh information.
782 refreshHandler: function() {
783 if (widget.$video[0].input.state
784 == widget.vlc.STATES.PLAYING[0])
786 widget.vlc.refreshTime();
787 widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler,
788 widget.options.refreshInterval * 1000);
793 widget.vlc.refreshState();
796 refreshAll: function() {
797 widget.vlc.refreshState();
798 widget.vlc.refreshVolume();
799 widget.vlc.refreshLoadedProgress();
802 widget.vlc.refreshTime();
805 widget.$time.html('--:-- / --:--');
809 refreshTime: function() {
810 // TODO while seeking (maybe not necessary for VLC)
811 // if (widget.$video[0].seeking)
814 // Time values in seconds.
815 var crtTime = widget.$video[0].input.time / 1000.0;
816 var totTime = widget.$video[0].input.length / 1000.0;
817 //var crtTime = widget.$video[0].input.position * totTime;
819 // Current time string
820 var crtH = Math.floor(crtTime / 3600);
821 var crtM = Math.floor((crtTime / 60) % 60);
822 var crtS = Math.floor(crtTime % 60);
824 (crtH == 0 ? '' : (widget._leadingZeros(crtH) + ':'))
825 + widget._leadingZeros(crtM) + ':' + widget._leadingZeros(crtS);
828 var totH = Math.floor(totTime / 3600);
829 var totM = Math.floor((totTime / 60) % 60);
830 var totS = Math.floor(totTime % 60);
832 (totH == 0 || isNaN(totH) ? '' : (widget._leadingZeros(totH) + ':'))
833 + widget._leadingZeros(totM) + ':' + widget._leadingZeros(totS);
835 widget.setTimeText('' + strCrtTime + ' / ' + strTotTime);
837 // Update time progress slider.
838 widget.vlc.refreshProgress();
843 _state: function(code) {
845 $.each(widget.vlc.STATES, function(index, value) {
846 if ('' + code == '' + value[0])
856 refreshState: function() {
858 .html(widget.vlc._state(widget.$video[0].input.state)[1]);
861 refreshVolume: function() {
864 if (widget.$video[0].audio.mute)
867 vol = Math.floor(widget.$video[0].audio.volume);
869 widget.setVolumeSlider(vol);
874 refreshProgress: function() {
875 widget.setProgressSlider(widget.vlc.crtTime());
881 * Not supported for VLC.
883 refreshLoadedProgress: function() {
884 // TODO Currently not possible through VLC API.
889 fullscreen: function() {
890 widget.$video[0].video.toggleFullscreen();