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",
22 refreshInterval: 0.1, // seconds
32 .addClass( "ui-widget ui-widget-content ui-corner-all" );
34 widget.$videoContainer = $('<div class="ui-nsvideo-nsplugin"></div>')
35 .appendTo(widget.element);
36 widget.$progressContainer = $('<div class="ui-nsvideo-progress-container ui-widget-content ui-corner-top"></div>')
37 .appendTo(widget.element);
38 widget.$progress = $('<div class="ui-nsvideo-progress"></div>')
39 .appendTo(widget.$progressContainer);
40 widget.$loadedProgress = $('<div class="ui-nsvideo-loaded-progress"></div>')
41 .appendTo(widget.$progress);
42 widget.$controls = $('<div class="ui-nsvideo-controls ui-widget-content ui-corner-bottom"></div>')
43 .appendTo(widget.element);
47 // Time progress slider with load progress also
48 widget.$loadedProgress
49 // TODO an object that inherits progressbar should be used in order to customize min value.
58 slide: function(event, ui) {
59 widget.videoPlugin('crtTime', [ui.value]);
64 $('<button class="ui-nsvideo-play ui-nsvideo-button ui-nsvideo-control-left">Play / Pause</button>')
65 .appendTo(widget.$controls)
68 icons: { primary: "ui-icon-play" }
71 widget.videoPlugin('togglePlay');
74 // Time information (current and total)
75 widget.$time = $('<div class="ui-nsvideo-time ui-nsvideo-text ui-nsvideo-control-left">--:-- / --:--</div>')
76 .appendTo(widget.$controls);
79 $('<button class="ui-nsvideo-fullscreen ui-nsvideo-button ui-nsvideo-control-right">Full Screen</button>')
80 .appendTo(widget.$controls)
83 icons: { primary: "ui-icon-arrow-4-diag" }
86 widget.videoPlugin('fullscreen');
89 // Video definition buttonset
90 if (typeof widget.options.src == 'object')
92 var $definitions = $('<form><div class="ui-nsvideo-definitions ui-nsvideo-control-right"></div></form>')
93 .appendTo(widget.$controls);
94 $definitions = $('.ui-nsvideo-definitions', $definitions[0]);
95 $.each(widget.options.src, function(index, value) {
96 id = widget.element.attr('id') + '-def-' + index;
97 $('<input type="radio" id="' + id + '" name="definition" />')
98 .appendTo($definitions)
99 .attr('checked', (index == widget.options.definition))
101 widget.videoPlugin('pause');
102 widget.definition(index);
104 $('<label for="' + id + '">' + index + '</label>')
105 .appendTo($definitions);
108 $definitions.buttonset();
112 $('<div class="ui-nsvideo-volume ui-nsvideo-control-right"></div>')
113 .appendTo(widget.$controls)
118 slide: function(event, ui) {
119 widget.videoPlugin('volume', [ui.value]);
124 $('<button class="ui-nsvideo-mute ui-nsvideo-button ui-nsvideo-control-right">Mute</button>')
125 .appendTo(widget.$controls)
128 icons: { primary: "ui-icon-volume-on" }
131 widget.videoPlugin('toggleMute');
134 // Status information
135 if (widget.options.showStatus)
137 widget.$stateText = $('<div class="ui-nsvideo-text ui-nsvideo-control-right">...</div>')
138 .appendTo(widget.$controls)
139 .css('cursor', 'pointer')
141 widget.videoPlugin('refreshAll');
146 $('<div class="ui-helper-clearfix"></div>')
147 .appendTo(widget.$controls);
149 // Initialize video plugin
150 widget.$video.ready(function() {
151 widget.videoPlugin('init');
155 _destroy: function() {
159 _setOption: function( key, value ) {
161 if ( key === "TODO" ) {
165 this._super( "_setOption", key, value );
168 _leadingZeros: function(number, length) {
176 for (var i=0; i<length; i++)
182 while (str.length < length)
193 // Select video source.
194 // If src option is string, that's the source.
195 // If src is an object, properties are definitions and values are
197 var src = widget.crtSrc();
201 widget.$videoContainer.html('');
203 var width = widget.options.width;
204 var height = widget.options.height;
207 if (widget.options.type == 'ns-html5'
208 || widget.options.type == 'html5')
210 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"' : '') + '>'
211 +'Error: Your browser does not support HTML5 or the video format!'
213 .appendTo(widget.$videoContainer)
216 widget.html5.pause();
222 widget.html5.pause();
224 timeupdate: function() {
225 widget.html5.refreshTime();
227 progress: function() {
228 widget.html5.refreshLoadedProgress();
230 loadedmetadata: function() {
231 widget.html5.refreshTime();
232 widget.html5.refreshVolume();
233 widget._setWidgetWidth();
238 volumechange: function() {
239 widget.html5.refreshVolume();
244 else if (widget.options.type == 'ns-vlc'
245 || widget.options.type == 'vlc')
248 if (widget.options.type == 'ns-vlc')
249 embedType = 'application/x-ns-stream';
251 embedType = 'application/x-vlc-plugin';
253 if (navigator.appName == "Netscape")
255 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 + '" />')
256 .appendTo(widget.$videoContainer);
260 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="">'
261 + '<param name="Src" value="' + src + '" />'
262 + '<param name="ShowDisplay" value="True" />'
263 + '<param name="Loop" value="False" />'
264 + '<param name="AutoPlay" value="' + (widget.options.autoplay ? 'True' : 'False') + '" />'
265 + '<param name="Toolbar" value="False" />'
267 .appendTo(widget.$videoContainer);
271 widget.$video.css('position', 'relative');
273 widget._setWidgetWidth();
276 _setWidgetWidth: function() {
277 if (widget.$video.width() < 640)
279 widget.element.css('width',
281 widget.$video.css('left',
282 Math.round(widget.$videoContainer.width()/2
283 - widget.$video.width()/2)
287 widget.element.css('width',
288 widget.$video.width + 8 + 'px');
291 setPlayButton: function() {
292 $('button.ui-nsvideo-play', widget.element[0])
293 .button('option', 'icons', { primary: "ui-icon-play" })
296 setPauseButton: function() {
297 $('button.ui-nsvideo-play', widget.element[0])
298 .button('option', 'icons', { primary: "ui-icon-pause" })
301 setMuteButton: function() {
302 $('button.ui-nsvideo-mute', widget.element[0])
303 .button('option', 'icons', { primary: "ui-icon-volume-off" })
306 setUnmuteButton: function() {
307 $('button.ui-nsvideo-mute', widget.element[0])
308 .button('option', 'icons', { primary: "ui-icon-volume-on" })
311 setTimeText: function(text) {
312 //$('.ui-nsvideo-time', widget.element[0])
316 setVolumeSlider: function(vol) {
317 $('.ui-nsvideo-volume', widget.element[0])
318 .slider('value', vol);
320 setProgressSlider: function(prog) {
321 $('.ui-nsvideo-progress', widget.element[0])
322 .slider('value', prog);
324 setLoadedProgressSlider: function(prog) {
325 $('.ui-nsvideo-loaded-progress', widget.element[0])
326 .progressbar('value', prog);
329 videoPlugin: function(method, args) {
330 if (typeof args == 'undefined')
332 var videoPlugin = null;
334 if (this.options.type.indexOf('html5') != -1)
336 videoPlugin = this.html5;
338 else if (this.options.type.indexOf('vlc') != -1)
340 videoPlugin = this.vlc;
344 return videoPlugin[method].apply(this, args);
349 definition: function(def) {
352 if (typeof def == 'undefined')
353 return widget.options.definition;
355 widget.options.definition = def;
361 type: function(type) {
364 if (typeof type == 'undefined')
365 return widget.options.type;
367 widget.options.type = type;
370 // Initialize video plugin
371 widget.$video.ready(function() {
372 widget.videoPlugin('init');
382 if (typeof widget.options.src == 'string')
383 src = widget.options.src;
384 else if (typeof widget.options.src == 'object')
386 if (typeof widget.options.definition == 'undefined')
389 if (typeof widget.options.src[ widget.options.definition ]
393 src = widget.options.src[ widget.options.definition ];
396 if (widget.options.type == 'ns-html5')
397 src = 'tribe://' + src;
407 //widget.html5.refreshAll();
409 //if (widget.options.autoplay)
410 // widget.html5.play();
413 togglePlay: function() {
414 if (widget.$video[0].paused)
420 widget.html5.pause();
425 if (widget.$video[0].paused)
426 widget.$video[0].play();
428 widget.setPauseButton();
434 if (!widget.$video[0].paused)
435 widget.$video[0].pause();
437 widget.setPlayButton();
442 toggleMute: function() {
443 if (!widget.$video[0].muted)
449 widget.html5.unmute();
454 if (!widget.$video[0].muted)
455 widget.$video[0].muted = true;
457 widget.setMuteButton();
463 if (widget.$video[0].muted)
464 widget.$video[0].muted = false;
466 widget.setUnmuteButton();
472 * Volume value is expressed in percents.
474 volume: function(vol) {
475 if (typeof vol == 'undefined')
476 return Math.round(widget.$video[0].volume * 100);
478 widget.html5.unmute();
479 widget.$video[0].volume = vol / 100;
485 * Seek position is a value between 0 and 1000.
487 crtTime: function(pos) {
489 if (typeof pos == 'undefined')
491 var crtTime = widget.$video[0].currentTime;
492 var totTime = widget.$video[0].duration;
493 if (isNaN(totTime) || totTime == 0)
496 return Math.round(crtTime / totTime * 1000.0);
500 widget.$video[0].currentTime =
501 pos / 1000 * widget.$video[0].duration;
504 refreshAll: function() {
505 widget.html5.refreshState();
506 widget.html5.refreshVolume();
507 widget.html5.refreshLoadedProgress();
508 widget.$time.html('--:-- / --:--');
509 widget.$stateText.html('...');
510 widget.html5.refreshTime();
513 refreshTime: function() {
514 if (widget.$video[0].seeking)
517 var crtTime = widget.$video[0].currentTime;
518 var totTime = widget.$video[0].duration;
520 // Refresh only at refreshInterval seconds to save CPU time.
521 var delta = crtTime - widget.html5.lastTime;
522 if (typeof widget.html5.lastTime !== "undefined"
523 && delta >= 0 && delta < widget.options.refreshInterval)
525 widget.html5.lastTime = crtTime;
527 // Current time string
528 var crtH = Math.floor(crtTime / 3600);
529 var crtM = Math.floor((crtTime / 60) % 60);
530 var crtS = Math.floor(crtTime % 60);
532 (crtH == 0 ? '' : (widget._leadingZeros(crtH) + ':'))
533 + widget._leadingZeros(crtM) + ':' + widget._leadingZeros(crtS);
536 var totH = Math.floor(totTime / 3600);
537 var totM = Math.floor((totTime / 60) % 60);
538 var totS = Math.floor(totTime % 60);
540 (totH == 0 || isNaN(totH) ? '' : (widget._leadingZeros(totH) + ':'))
541 + widget._leadingZeros(totM) + ':' + widget._leadingZeros(totS);
543 widget.setTimeText('' + strCrtTime + ' / ' + strTotTime);
545 // Update time progress slider.
546 widget.html5.refreshProgress();
551 refreshState: function() {
552 // TODO refresh HTML5 plugin state
557 refreshVolume: function() {
560 if (widget.$video[0].muted)
563 vol = Math.floor(widget.$video[0].volume * 100);
565 widget.setVolumeSlider(vol);
570 refreshProgress: function() {
571 widget.setProgressSlider(widget.html5.crtTime());
577 * Supported for Firefox 4.0 or later.
579 refreshLoadedProgress: function() {
580 // Return if buffering status not available in browser.
581 if (typeof widget.$video[0].buffered == 'undefined'
582 || widget.$video[0].buffered.length === 0)
585 var loadedTime = widget.$video[0].buffered.end(0);
586 var totTime = widget.$video[0].duration;
588 if (isNaN(totTime) || totTime == 0)
591 percent = Math.floor(loadedTime / totTime * 100);
593 widget.setLoadedProgressSlider(percent);
598 fullscreen: function() {
599 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.');
608 IDLE_CLOSE: [0, "Idle / Close"],
609 OPENING: [1, "Opening..."],
610 BUFFERING: [2, "Buffering..."],
611 PLAYING: [3, "Playing..."],
612 PAUSED: [4, "Paused"],
613 STOPPING: [5, "Stopping..."],
618 if (widget.options.autoplay)
620 widget.vlc.refreshAll();
623 togglePlay: function() {
624 if (! widget.$video[0].playlist.isPlaying)
635 if (! widget.$video[0].playlist.isPlaying)
636 widget.$video[0].playlist.play();
638 widget.setPauseButton();
640 // Schedule information refreshment at refreshInterval seconds.
641 if (! widget.vlc.timerHandle)
642 widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler,
643 widget.options.refreshInterval * 1000);
645 widget.vlc.refreshState();
651 if (widget.$video[0].playlist.isPlaying)
652 widget.$video[0].playlist.togglePause();
654 widget.setPlayButton();
656 // Cancel information refreshment scheduling.
657 clearTimeout(widget.vlc.timerHandle);
658 widget.vlc.timerHandle = null;
660 widget.vlc.refreshState();
665 toggleMute: function() {
666 if (! widget.$video[0].audio.mute)
677 if (! widget.$video[0].audio.mute)
678 widget.$video[0].audio.toggleMute();
680 widget.setMuteButton();
682 widget.vlc.refreshVolume();
688 if (widget.$video[0].audio.mute)
689 widget.$video[0].audio.toggleMute();
691 widget.setUnmuteButton();
693 widget.vlc.refreshVolume();
699 * Volume value is expressed in percents.
701 volume: function(vol) {
702 if (typeof vol == 'undefined')
703 return Math.round(widget.$video[0].audio.volume);
706 widget.$video[0].audio.volume = vol;
712 * Seek position is a value between 0 and 1000.
714 crtTime: function(pos) {
716 if (typeof pos == 'undefined')
718 var crtTime = widget.$video[0].input.time;
719 var totTime = widget.$video[0].input.length;
720 if (isNaN(totTime) || totTime == 0)
723 return Math.round(crtTime / totTime * 1000.0);
727 widget.$video[0].input.time =
728 pos / 1000 * widget.$video[0].input.length;
730 widget.vlc.refreshState();
734 * Timeout callback called at refreshInterval during playing in order
735 * to refresh information.
737 refreshHandler: function() {
738 if (widget.$video[0].input.state
739 == widget.vlc.STATES.PLAYING[0])
741 widget.vlc.refreshTime();
742 widget.vlc.timerHandle = setTimeout(widget.vlc.refreshHandler,
743 widget.options.refreshInterval * 1000);
748 widget.vlc.refreshState();
751 refreshAll: function() {
752 widget.vlc.refreshState();
753 widget.vlc.refreshVolume();
754 widget.vlc.refreshLoadedProgress();
757 widget.vlc.refreshTime();
760 widget.$time.html('--:-- / --:--');
764 refreshTime: function() {
765 // TODO while seeking (maybe not necessary for VLC)
766 // if (widget.$video[0].seeking)
769 // Time values in seconds.
770 var crtTime = widget.$video[0].input.time / 1000.0;
771 var totTime = widget.$video[0].input.length / 1000.0;
772 //var crtTime = widget.$video[0].input.position * totTime;
774 // Current time string
775 var crtH = Math.floor(crtTime / 3600);
776 var crtM = Math.floor((crtTime / 60) % 60);
777 var crtS = Math.floor(crtTime % 60);
779 (crtH == 0 ? '' : (widget._leadingZeros(crtH) + ':'))
780 + widget._leadingZeros(crtM) + ':' + widget._leadingZeros(crtS);
783 var totH = Math.floor(totTime / 3600);
784 var totM = Math.floor((totTime / 60) % 60);
785 var totS = Math.floor(totTime % 60);
787 (totH == 0 || isNaN(totH) ? '' : (widget._leadingZeros(totH) + ':'))
788 + widget._leadingZeros(totM) + ':' + widget._leadingZeros(totS);
790 widget.setTimeText('' + strCrtTime + ' / ' + strTotTime);
792 // Update time progress slider.
793 widget.vlc.refreshProgress();
798 _state: function(code) {
800 $.each(widget.vlc.STATES, function(index, value) {
801 if ('' + code == '' + value[0])
811 refreshState: function() {
813 .html(widget.vlc._state(widget.$video[0].input.state)[1]);
816 refreshVolume: function() {
819 if (widget.$video[0].audio.mute)
822 vol = Math.floor(widget.$video[0].audio.volume);
824 widget.setVolumeSlider(vol);
829 refreshProgress: function() {
830 widget.setProgressSlider(widget.vlc.crtTime());
836 * Not supported for VLC.
838 refreshLoadedProgress: function() {
839 // TODO Currently not possible through VLC API.
844 fullscreen: function() {
845 widget.$video[0].video.toggleFullscreen();