OSDN Git Service

初回コミット(v2.6.17.1)
[magic3/magic3.git] / scripts / jquery / jquery.youtube.player.js
1 /*
2  * jquery.youtube.js v0.1a1 - a jquery youtube player
3  * Copyright (c) 2010 Richard Willis
4  * MIT license  : http://www.opensource.org/licenses/mit-license.php
5  * Project      : http://github.com/badsyntax/jquery-youtube-player
6  * Contact      : willis.rh@gmail.com | badsyntax.co.uk
7  */
8
9 (function($, window, document, undefined){
10
11         $.fn.player = function(method){
12
13                 var pluginName = 'jquery-youtube-player', args = arguments, val = undefined;
14
15                 this.each(function(){
16
17                         // get plugin reference
18                         var obj = $.data( this, pluginName );
19
20                         if ( obj && obj[method]) {
21
22                                 // execute a public method, store the return value
23                                 val = obj[method].apply( obj, Array.prototype.slice.call( args, 1 ) );
24
25                                 // only the 'plugin' public method is allowed to return a value
26                                 val = (method == 'plugin') ? val : undefined;
27                         } 
28                         else if ( !obj && ( typeof method === 'object' || ! method ) ) {
29
30                                 // initiate the plugin
31                                 $.data( this, pluginName, new player(this, method, pluginName) );
32                         }
33                 });
34
35                 // return the value from a method, or the jQuery object
36                 return val || this;
37         }
38
39         // player constuctor
40         function player(element, options, pluginName){
41
42                 var self = this;
43
44                 this._pluginName = pluginName;
45                 
46                 this.element = $( element ).addClass('ui-widget');
47
48                 this.options = $.extend({
49                         width: 425,                     // player width (integer or string)
50                         height: 356,                    // player height (integer or string)
51                         swfobject: window.swfobject,    // swfobject object
52                         playlist: {},                   // playlist object (object literal)
53                         showPlaylist: 1,                // show playlist on plugin init (boolean)
54                         showTime: 1,                    // show current time and duration in toolbar (boolean)
55                         videoThumbs: 0,                 // show videos as thumbnails in the playlist area (boolean) (experimental)
56                         randomStart: 0,                 // show random video on plugin init (boolean)
57                         autoStart: 0,                   // auto play the video after the player as been built (boolean)
58                         autoPlay: 0,                    // auto play the video when loading it via the playlist or toolbar controls (boolean)
59                         repeat: 1,                      // repeat videos (boolean)
60                         repeatPlaylist: 0,              // repeat the playlist (boolean) 
61                         shuffle: 0,                     // shuffle the play list (boolean)
62                         chromeless: 1,                  // chromeless player (boolean)
63                         highDef: 0,                     // high definition quality or normal quality (boolean)
64                         playlistHeight: 5,              // height of the playlist (integer) (N * playlist item height)
65                         playlistBuilder: null,          // custom playlist builder function (null or function) see http://github.com/badsyntax/jquery-youtube-player/wiki/Installation-and-usage#fn9
66                         playlistBuilderClickHandler: null, // custom playlist video click event handler, useful if you want to prevent default click event (null or function)
67                         playlistAnimation: { 
68                                 height: 'show', 
69                                 opacity: 'show' 
70                         },
71                         playlistSpeed: 550,             // speed of playlist show/hide animate
72                         toolbarAppendTo: null,          // element to append the toolbar to (selector or null)
73                         playlistAppendTo: null,         // element to append the playlist to (selector or null)
74                         timeAppendTo: null,             // elemend to append to time to (selector or null)
75                         videoParams: {                  // video <object> params (object literal)
76                                 allowfullscreen: 'true',
77                                 allowScriptAccess: 'always',
78                                 wmode: 'transparent'
79                         },
80                         showToolbar: null,              // show or hide the custom toolbar (null, true or false)
81                         toolbarButtons: {},             // custom toolbar buttons
82                         toolbar: 'play,prev,next,shuffle,repeat,mute,playlistToggle', // comma separated list of toolbar buttons
83                         toolbarAnimation: {
84                                 opacity: 1
85                         },
86                         toolbarSpeed: 500
87                 }, options);
88
89                 if (!this.options.chromeless && this.options.showToolbar != true) this.options.showToolbar = 0;
90
91                 // these initial states are the youtube player states
92                 // button states will be added to this object
93                 this._states = {
94                         'unstarted': -1,
95                         'ended': 0,
96                         'play': 1,
97                         'paused': 2,
98                         'buffering': 3,
99                         'cued': 5
100                 };
101
102                 // munge youtube video id from any url
103                 this._youtubeIdExp = /^[^v]+v.(.{11}).*/;
104                 
105                 // extend the default toolbar buttons with user specified buttons (specified buttons will override default)
106                 this.buttons = $.extend({}, this.defaultToolbarButtons, this.options.toolbarButtons);
107
108                 // convert inks to vidoes
109                 if (this.element.is('a')) {
110
111                         var anchor = this.element;
112
113                         this.element = $('<div class="youtube-player"></div>');
114                         var 
115                                 playerVideo = $('<div class="youtube-player-video"></div>').appendTo(this.element),
116                                 playerObject = $('<div class="youtube-player-object"></div>').appendTo(playerVideo),
117                                 playlist = $('<ol class="youtube-player-playlist"><li></li></ol>')
118                                         .find('li')
119                                         .append( anchor.clone() )
120                                         .end()
121                                         .appendTo(this.element);
122
123                         anchor.after( this.element ).hide();
124                 }
125                 
126                 // store common elements
127                 this.elements = {
128                         player: this.element,
129                         playerVideo: this.element.find('.youtube-player-video'),
130                         playerObject: this.element.find('.youtube-player-object')
131                 };
132
133                 // swfobject will destroy the video object <div>, so we clone it to use it to restore it when destroy()ing the plugin
134                 this.elements.playerObjectClone = this.elements.playerObject.clone();
135
136                 this.keys = { video: 0 };
137
138                 // swfobject requires the video object <div> to have an id set
139                 var id;
140                 do {
141                         id = 'jqueryyoutubeplayer' + Math.floor( Math.random() * 101 ).toString();
142
143                 } while( document.getElementById(id) );
144
145                 this.elements.playerObject[0].id = id;
146
147                 (this.options.swfobject.getFlashPlayerVersion().major >= 8) 
148
149                         && this.loadPlaylist(null, null, null, function(){
150
151                                 // build everything and set event handlers
152                                 self
153                                 ._bindYoutubeEventHandlers()
154                                 ._createToolbar()
155                                 ._createTimeArea()
156                                 ._createPlaylist()
157                                 ._createPlayer();
158                         });
159         }
160
161         // public members
162         player.prototype = {
163                 
164                 _activeStates: [], timer: {}, videoIds: [],
165                 
166                 _trigger : function(scope, callback, arg){
167
168                         var type = typeof callback;
169
170                         arg = arg || [];
171
172                         if ( type === 'string' && this.options[ callback ] && $.isFunction(this.options[ callback ]) ) {
173
174                                 return this.options[ callback ].apply( scope, arg );
175
176                         } else if ( type === 'function' ) {
177
178                                 callback.apply( scope, arg );
179                         }
180                 },
181                 
182                 _bindYoutubeEventHandlers : function(){
183
184                         var self = this;
185                         
186                         function ready(id){
187
188                                 self.youtubePlayer = document.getElementById(id);
189                                                 
190                                 self._trigger(self, 'onPlayerReady', [ id ]);
191
192                                 self.loadVideo(false, true);
193
194                                 self.elements.toolbar.container
195                                         .animate(self.options.toolbarAnimation, self.options.toolbarSpeed, function(){
196
197                                                 self._trigger(self, 'onReady', [ id ]);
198                                         });
199
200                                 self._showPlaylist( self.options.showPlaylist );
201                         
202                                 ( self.keys.play ) && self.playVideo();
203                         }
204
205                         function videoPaused(){
206
207                                 self._trigger(this, 'onVideoPaused', [ self._getVideo() ]);
208                         }
209
210                         function videoEnded(){
211
212                                 self.buttons.play.element && self.buttons.play.element.trigger( 'off' );
213
214                                 if (self.options.repeat) {
215
216                                         self.nextVideo();
217                                 }
218                         }
219
220                         function error(state){
221
222                                 switch(state){
223                                         case 100:
224                                                 msg = 'This video has been removed from Youtube.';
225                                                 break;
226                                         case 101:
227                                         case 150:
228                                                 msg = 'This video does not allow playback outside of Youtube.';
229                                                 break;
230                                         default:
231                                                 msg = 'Unknown error';
232                                 }
233                                 if (self._trigger(this, 'onError', [msg]) === undefined){
234
235                                         alert( 'There was an error loading this video. ' + msg );
236                                 }
237                         }
238                         
239                         function videoCued(){
240
241                                 self._updatePlaylist();
242
243                                 self.elements.toolbar.updateStates();
244                         
245                                 self._trigger(this, 'onVideoCue', arguments);
246                         }
247
248                         function videoBuffer(){
249
250                                 self._trigger(this, 'onBuffer', [ self._getVideo() ]); 
251                         }
252                         
253                         function videoPlay(){
254
255                                 self._updatePlaylist();
256
257                                 self._addState('play');
258
259                                 self.elements.toolbar.updateStates();
260
261                                 self._updateTime();
262
263                                 // update the location hash
264
265                                 self._trigger(this, 'onVideoPlay', [ self._getVideo() ]);
266                         }
267                         
268                         var id = this.elements.playerObject[0].id;
269
270                         window['onytplayerStateChange' + id] = function(state){
271
272                                 // reset the youtube player states every time an event is executed
273                                 self._removeStates([ -1, 0, 1, 2, 3, 5, 100, 101, 150, 9 ]);
274
275                                 // add a new youtube state
276                                 self._addState(state, true);
277
278                                 switch(state) {
279                                         case 0 : videoEnded(); break;
280                                         case 1 : videoPlay(); break;
281                                         case 2 : videoPaused(); break;
282                                         case 3 : videoBuffer(); break;
283                                         case 9 : ready(id); break;
284                                         case 5 : videoCued(); break;
285                                         case 100: case 101: case 150: error( state ); break;
286                                 }
287
288                                 self._trigger(self, 'onYoutubeStateChange', [ state ]);
289                         };
290
291                         if ( !window.onYouTubePlayerReady ){
292                         
293                                 window.onYouTubePlayerReady = function(id){ 
294                         
295                                         var player = document.getElementById(id);
296
297                                         player.addEventListener("onStateChange", 'onytplayerStateChange' + id);
298
299                                         player.addEventListener('onError', 'onytplayerStateChange' + id);
300
301                                         window['onytplayerStateChange' + id](9);
302                                 };
303                         }
304
305                         return this;
306                 },
307
308                 _createPlayer : function(){
309
310                         // set the player dimensions
311                         this.elements.player.width( this.options.width );
312                         this.elements.playerVideo.height( this.options.height );
313
314                         var 
315                                 id = this.options.playlist.videos[this.keys.video].id, 
316                                 apiid = this.elements.playerObject[0].id,
317                                 swfpath = 
318                                         this.options.chromeless 
319                                         ? 'http://www.youtube.com/apiplayer?enablejsapi=1&version=3&playerapiid='+apiid+'&hd=' + this.options.highDef + '&showinfo=0'
320                                         : 'http://www.youtube.com/v/' + id + '?enablejsapi=1&playerapiid='+apiid+'&version=3';
321
322                         this._trigger(this, 'onBeforePlayerBuild');
323
324                         // embed the youtube player
325                         this.options.swfobject.embedSWF( swfpath, this.elements.playerObject[0].id, '100%', '100%', '8', null, null, this.options.videoParams);
326
327                         return this;
328                 },
329
330                 _createToolbar : function(){
331
332                         var self = this;
333
334                         this.elements.toolbar = {
335                                 container: $('<ul />')
336                                         .addClass('youtube-player-toolbar ui-widget ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all')
337                                         .css('opacity', 0),
338                                 updateStates : function(){
339
340                                         self.elements.toolbar.container.find('li').each(function(){
341
342                                                 var button = $(this).removeClass('ui-state-active').data('button');
343
344                                                 if (!button) return true;
345
346                                                 (self._state(button.val)) &&
347                                                 (button.toggle) && 
348                                                 $(this).addClass('ui-state-active');
349
350                                                 (self._state(button.val) && button.toggleButton) && $(this).trigger('on');
351                                         });
352                                 }
353                         };
354
355                         ( this.options.showToolbar != null && !this.options.showToolbar ) 
356                                 && this.elements.toolbar.container.hide();
357
358                         $.each(this.options.toolbar.split(','), function(key, val) {
359
360                                 var button = self.buttons[val];
361
362                                 if (!button || !button.text) return true;
363                                 
364                                 button.val = val;
365
366                                 self._states[val] = self._states[val] || val;
367
368                                 $('<li></li>')
369                                 .addClass('ui-state-default ui-corner-all')
370                                 .append('<span class="ui-icon ' + button.icon + '"></span>')
371                                 .attr('title', button.text)
372                                 .data('button', button)
373                                 .bind('mouseenter mouseleave', function(){
374
375                                         $(this).toggleClass('ui-state-hover'); 
376                                 })
377                                 .bind('off', function(){
378
379                                         var elem = $(this), button = elem.data('button'), toggle = 1;
380                                         
381                                         elem.data('toggle', toggle);
382
383                                         self._removeState(val);
384
385                                         elem.find('.ui-icon')
386                                                 .removeClass( button.toggleButton.icon )
387                                                 .addClass( button.icon )
388                                                 .end()
389                                                 .attr('title', button.text);
390
391                                         self._trigger(self, button.toggleButton.action, [ button ] );
392                                 })
393                                 .bind('on', function(){
394
395                                         var elem = $(this), button = elem.data('button'), toggle = 0;
396                                         
397                                         elem.data('toggle', toggle);
398
399                                         self._addState(val);
400
401                                         elem
402                                         .find('.ui-icon')
403                                                 .removeClass( button.icon )
404                                                 .addClass( button.toggleButton.icon )
405                                         .end()
406                                         .attr('title', button.toggleButton.text)
407
408                                         self._trigger(self, button.action, [ button ] );
409                                 })
410                                 .bind('toggle', function(){
411                                         
412                                         var toggle = $(this).data('toggle');
413
414                                         ( toggle || toggle == undefined) ? $(this).trigger('on') : $(this).trigger('off');
415                                 })
416                                 .click(function(){
417
418                                         var button = $(this).data('button'), 
419                                                 state = self._state(val);
420
421                                         if (button.toggleButton) {
422                                                 
423                                                 $(this).trigger('toggle');
424                                         } else {
425
426                                                 self._trigger(self, button.action, [ button ] );
427
428                                                 ( !button.toggle || ( button.toggle && state ) ) 
429                                                         ? self._removeState(val) 
430                                                         : self._addState(val);
431
432                                                 self.elements.toolbar.updateStates();
433                                         }
434                                 })
435                                 .appendTo(self.elements.toolbar.container);
436                         });
437
438                         (this.options.toolbarAppendTo) ?
439                                 this.elements.toolbar.container.appendTo( this.options.toolbarAppendTo ) :
440                                 this.elements.playerVideo.after( this.elements.toolbar.container );
441
442                         return this;
443                 },
444
445                 _createTimeArea : function(){
446
447                         this.elements.toolbar.time = 
448                                 this.options.timeAppendTo 
449                                 ? $('<span />').appendTo( this.options.timeAppendTo )
450                                 : $('<li />').addClass('youtube-player-time').appendTo( this.elements.toolbar.container );
451
452                         this.elements.toolbar.timeCurrent = $('<span />').html('0:00').appendTo(this.elements.toolbar.time);
453
454                         this.elements.toolbar.timeDuration = $('<span />').appendTo(this.elements.toolbar.time);
455
456                         return this;
457                 },
458
459                 _createPlaylist : function(){
460
461                         var self = this;
462
463                         function videoClickHandler(){
464
465                                 var videoData = $(this).data('video');
466
467                                 if (!videoData) return;
468
469                                 self.keys.video = $.inArray( videoData.id, self.videoIds );
470
471                                 self._removeState('play');
472                                 
473                                 self._updatePlaylist();
474
475                                 self.loadVideo();
476                                 
477                                 self.playVideo();
478                         }
479
480                         function buildPlaylist(){
481
482                                 self.elements.playlist = self.elements.player.find('.youtube-player-playlist').length
483                                         ? self.elements.player.find('.youtube-player-playlist')
484                                         : $('<ol />').addClass('youtube-player-playlist ui-helper-reset');
485                                 
486                                 self.elements.playlistContainer = 
487                                         $('<div />')
488                                         .addClass('youtube-player-playlist-container ui-widget-content ui-corner-all')
489                                         .append( self.elements.playlist );
490                         };
491
492                         this._addVideosToPlaylist = function(cue){
493
494                                 // get this list of vidoes to add to the playlist
495                                 // if cueing, we only want to add 1 video, so we find the last video added to playlist
496                                 var videos = cue 
497                                                 ? [ self.options.playlist.videos[self.options.playlist.videos.length - 1] ] 
498                                                 : self.options.playlist.videos;
499
500                                 (!cue) && self.elements.playlist.empty();
501
502                                 self.videoIds = [];
503
504                                 $.each(videos, function(){
505
506                                         self.videoIds.push(this.id);
507
508                                         $('<li />')
509                                                 .data('video', this)
510                                                 .append( self.options.videoThumbs ? '<img alt="' + this.title + '" title="' + this.title + '" src="http://img.youtube.com/vi/' + this.id + '/2.jpg" />' : this.title)
511                                                 .addClass('ui-state-default')
512                                                 .addClass( self.options.videoThumbs ? 'youtube-player-thumb' : '' )
513                                                 .bind('mouseenter mouseleave', function(){
514
515                                                         $( this ).toggleClass( 'ui-state-hover' );
516                                                 })
517                                                 .appendTo(self.elements.playlist);
518                                 });
519
520                                 self._trigger(self, 'onAfterVideosAddedToPlaylist');
521                         };
522
523                         if (!$.isFunction( this.options.playlistBuilder )) {
524
525                                 buildPlaylist();
526
527                                 this._addVideosToPlaylist();
528                                 
529                                 (this.options.playlistAppendTo) 
530                                         // append playlist to specified element
531                                         ? this.elements.playlistContainer.appendTo( this.options.playlistAppendTo )
532                                         // insert playlist after the toolbar
533                                         : this.elements.toolbar.container.after( this.elements.playlistContainer );
534
535                                 this.options.playlistBuilder = function(){
536                                         return {
537                                                 items: self.elements.playlist.find('li'),
538                                                 container: self.elements.playlistContainer
539                                         }
540                                 };
541                         } 
542
543                         $.each(this.options.playlist.videos, function(){
544
545                                 self.videoIds.push( this.id );
546                         });
547
548                         var playlist = this.options.playlistBuilder.call(this, this.options.playlist.videos);
549
550                         playlist
551                         .items
552                         .click(function(){
553
554                                 self._trigger(this, videoClickHandler, arguments);
555
556                                 self._trigger(self, 'playlistBuilderClickHandler', arguments);
557                         });
558
559                         this.elements.playlistContainer = playlist.container;
560
561                         return this;
562                 },
563                 
564                 _updateTime : function(){
565
566                         if (!this.options.showTime) return;
567
568                         var self = this, duration = Number( this.youtubePlayer.getDuration() );
569
570                         function timeFormat(seconds) {
571
572                                 var m = Math.floor( seconds / 60), s = (seconds % 60).toFixed(0);
573
574                                 return m + ':' + ( s < 10 ? '0' + s : s);
575                         }
576
577                         this.elements.toolbar.timeDuration.html( ' / ' + timeFormat( duration ));
578
579                         this.elements.toolbar.time.fadeIn();
580
581                         this.timeInterval = setInterval(function(){
582
583                                 ( !self.youtubePlayer.getCurrentTime )
584                                         ? clearInterval( self.timeInterval )
585                                         : self.elements.toolbar.timeCurrent.html( timeFormat( self.youtubePlayer.getCurrentTime() ) );
586                         }, 100);
587                 },
588
589                 _removeStates : function(states){
590
591                         var newArray = [];
592                         
593                         $.each(this._activeStates, function(key, value){
594
595                                 ($.inArray(value, states) === -1 
596                                         && $.inArray(value, newArray) === -1) 
597                                         && newArray.push(value);
598                         });
599
600                         this._activeStates = newArray;
601                 },
602                 
603                 _removeState : function(state){
604
605                         state = typeof state === 'string' ? this._states[ state ] : state;
606
607                         this._removeStates([ state  ]);
608                 },
609
610                 _state : function(state, remove){
611
612                         state = this._states[ state ];
613
614                         return $.inArray(state, this._activeStates) !== -1 ? true : false;
615                 },
616
617                 _addState : function(state, stateID){
618
619                         if (stateID) {
620                         
621                                 $.inArray(state, this._activeStates) === -1 
622                                         && this._activeStates.push( state );
623                         
624                         } else {
625
626                                 this._states[ state ] 
627                                         && $.inArray(this._states[ state ], this._activeStates) === -1 
628                                         && this._activeStates.push( this._states[ state ] );
629                         }
630                 },
631                 
632                 _setVideoKey : function(val){
633
634                         this.keys.video = this.options.shuffle ? this.options.randomVideo() : val || 0;
635                 },
636
637                 _getVideo : function(){
638
639                         return this.options.playlist.videos[ this.keys.video ];
640                 },
641
642                 _findVideo : function(id){
643
644                         var index = -1;
645
646                         $.each(this.options.playlist.videos, function(key, val){
647
648                                 if (id == val.id) {
649                                 
650                                         index = key;
651
652                                         return false; // break
653                                 }
654                         });
655
656                         return index;
657                 },
658                 
659                 _getPlaylistData : function(success, error){
660
661                         var self = this, playlist = this.options.playlist;
662
663                         if (playlist.user || playlist.playlist) {
664
665                                 function ajaxSuccess(json){
666
667                                         if (!json) { 
668                                                 error.call( self ); 
669                                                 return; 
670                                         }
671
672                                         // replace playlist ID with json array
673                                         self.options.playlist = {
674                                                 title: json.feed.title.$t,
675                                                 id: playlist,
676                                                 videos: []
677                                         };
678
679                                         $.each(json.feed.entry, function(key, vid){
680                                                 self.options.playlist.videos.push({
681                                                         id: vid.link[0].href.replace(self._youtubeIdExp, '$1'), // munge video id from href
682                                                         title: vid.title.$t
683                                                 });
684                                         });
685
686                                         self.elements.playerObject.fadeOut(180, function(){ success.call( self ); });
687                                 }
688                                 
689                                 var url = playlist.user 
690                                         ? 'http://gdata.youtube.com/feeds/api/videos'
691                                         : 'http://gdata.youtube.com/feeds/api/playlists/' + playlist.playlist;
692
693                                 url += '?callback=?';
694
695                                 var data = { alt: 'json', format: '5' };
696                                 
697                                 if (playlist.user){ data.author = playlist.user; }
698
699                                 this._trigger(this, 'onBeforePlaylistLoaded', [ playlist ]);
700
701                                 $.ajax({
702                                         type: 'GET',
703                                         url: url,
704                                         data: data,
705                                         dataType: 'json',
706                                         error: function(){ 
707                                 
708                                                 self._trigger(self, 'onAfterPlaylistLoaded', [ playlist ]);
709
710                                                 self._trigger(self, error);
711                                         },
712                                         success: function(){
713                                                 
714                                                 self._trigger(self, 'onAfterPlaylistLoaded', [ playlist ]);
715
716                                                 self._trigger(self, ajaxSuccess, arguments);
717                                         }
718                                 });
719
720                                 return;
721
722                         } else if (!playlist.videos){
723
724                                 var videos = this.elements.player.find('.youtube-player-playlist li a');
725
726                                 if (videos.length) {
727                                         
728                                         self.options.playlist.videos = [];
729
730                                         videos.each(function(){
731                                                 self.options.playlist.videos.push({
732                                                         id: this.href.replace(self._youtubeIdExp, '$1'),
733                                                         title: $(this).html(),
734                                                         element: this
735                                                 });
736                                         });
737                                 }
738                         }
739                                         
740                         self._trigger(self, 'onAfterPlaylistLoaded', [ playlist ]);
741
742                         self._trigger(self, success);
743                 },
744
745                 _updatePlaylist : function(){
746
747                         var self = this;
748
749                         (this.elements.playlist) && 
750                                 
751                                 this.elements.playlist
752                                 .find('li')
753                                 .removeClass('ui-state-active')
754                                 .each(function(key){
755
756                                         if ( self.options.playlist.videos[self.keys.video].id == $(this).data('video').id) {
757
758                                                 var height = $( this ).addClass('ui-state-active').outerHeight();
759
760                                                 if ( !self.options.videoThumbs ){
761                                                         
762                                                         var pos = (key * height) - ( Math.floor(self.options.playlistHeight / 2) * height);
763
764                                                         self.elements.playlist.scrollTop( pos );
765                                                 }
766
767                                                 return false;
768                                         }
769                                 });
770                 },
771
772                 _showPlaylist : function(show) {
773
774                         show = show === undefined ? true : show;
775
776                         ( show ) && this.elements.playlistContainer.show();
777
778                         var 
779                                 oldHeight = this.elements.playlist.height(),
780                                 scrollerHeight = this.elements.playlist.css('height', 'auto').height(),
781                                 videoHeight = this.elements.playlist.find('li:first').outerHeight(),
782                                 newHeight = videoHeight * this.options.playlistHeight,
783                                 height = newHeight < scrollerHeight ? newHeight : scrollerHeight;
784                         
785                         ( show ) && this.elements.playlistContainer.hide();
786
787                         if ( !this.elements.playlist.children().length ) {
788
789                                 this.elements.playlistContainer.hide();
790
791                         } else if ( height ) {
792
793                                 this.elements.playlist.height( height );
794
795                                 (this.options.showPlaylist || show)
796
797                                         && this.elements.playlistContainer.animate(this.options.playlistAnimation, this.options.playlistSpeed);
798                         }
799                 },
800
801                 loadVideo : function(video, cue){
802
803                         var self = this;
804
805                         function load(videoID){
806
807                                 ( cue ) 
808                                 ? self.cueVideo(videoID)
809                                 : self.youtubePlayer.loadVideoById(videoID, 0);
810
811                                 self._trigger(self, 'onVideoLoad', [ self._getVideo() ]);
812                         }
813
814                         if (video && video.id) {
815                         
816                                 video = {
817                                         id: video.id,
818                                         title: video.title
819                                 };
820
821                                 this.videoIds = cue ? this.videoIds : [];
822
823                                 if (cue) {
824
825                                         // append video to video list
826                                         this.options.playlist.videos.push(video);
827                                 } else {
828
829                                         // add video to video list only if a title is present
830                                         this.options.playlist.videos = video.title ?  [ video ] : [];
831                                 }
832
833                                 // add video/s to playlist
834                                 this._addVideosToPlaylist(cue);
835
836                                 // update the height of the playlist, but don't explicidly show it
837                                 this._showPlaylist(false);
838
839                                 (!cue) && 
840                                         // load and play the video
841                                         load(video.id);
842
843                         } else if (video) {
844
845                                 // you can't load videos that aren't in the current playlist
846
847                                 var index = this._findVideo( video );
848
849                                 if (index !== -1) {
850
851                                         this.keys.video = index;
852                                         
853                                         load( video );
854                                 }
855
856                         } else {
857
858                                 // try load the next video
859                                 load( this.options.playlist.videos[this.keys.video].id );
860                         }
861                 },
862                 
863                 loadPlaylist: function(playlist, play, show, success){
864                         
865                         if ( playlist ) {
866
867                                 this.options.playlist = playlist;
868                         }
869
870                         this._getPlaylistData(
871                                 function(){ // success
872
873                                         this.keys.video = this.options.randomStart ? this.randomVideo() : 0;
874
875                                         // has the flash object been built?
876                                         if (this.youtubePlayer) {
877
878                                                 // reset the playlist
879                                                 this._addVideosToPlaylist();
880
881                                                 // play or cue the video
882                                                 (play) ? this.loadVideo() : this.cueVideo();
883
884                                                 this._showPlaylist(show);
885                                         }
886
887                                         this._trigger(this, success);
888                                 }, 
889                                 function(){ // error
890
891                                         var msg = 'There was an error loading the playlist.';
892
893                                         this.elements.playerObject.html( msg );
894
895                                         this._trigger(this, 'onError', [msg]);
896                                 }
897                         );
898                 },
899                         
900                 pauseVideo : function(){
901
902                         this.youtubePlayer.pauseVideo();
903                 },
904
905                 shufflePlaylist : function(){
906         
907                         this.randomVideo();
908
909                         this.playVideo();
910                 },
911                 
912                 muteVideo : function(button){
913
914                         this._state('mute') ? this.youtubePlayer.unMute() : this.youtubePlayer.mute();
915                 },
916         
917                 // FIXME
918                 repeat : function(){
919
920                         this.options.repeat = 1;
921                 },
922                                 
923                 playVideo : function(){
924                 
925                         this.youtubePlayer.playVideo();
926                 },
927
928                 cueVideo : function(videoID, startTime){
929
930                         return this.youtubePlayer.cueVideoById( videoID || this.options.playlist.videos[this.keys.video].id, startTime || 0);
931                 },
932
933                 randomVideo : function(){
934
935                         this.keys.video = Math.floor(Math.random() * this.options.playlist.videos.length);
936
937                         return this.keys.video;
938                 },
939                 
940                 prevVideo : function(){
941
942                         if (this.keys.video > 0) {
943
944                                 this._setVideoKey( --this.keys.video );
945
946                         } else if ( this.options.repeatPlaylist ) {
947
948                                 this._setVideoKey( this.videoIds.length - 1 );
949
950                         } else return;
951                         
952                         this.loadVideo(null, this._state('play') || this.options.autoPlay ? false : true);
953                 },
954
955                 nextVideo : function(){
956
957                         if (this.keys.video < this.options.playlist.videos.length-1) {
958                                         
959                                 this._setVideoKey( ++this.keys.video );
960
961                         } else if ( this.options.repeatPlaylist ) {
962
963                                 this._trigger(this, 'onEndPlaylist');
964                                 
965                                 this._setVideoKey( 0 );
966
967                         } else return;
968
969                         this.loadVideo(null, this._state('play') || this.options.autoPlay ? false : true);
970                 },
971                 
972                 playlistToggle : function(button){
973
974                         (this.elements.playlistContainer.find('li').length) &&
975
976                                 this.elements
977                                         .playlistContainer
978                                         .animate({
979                                                 height: 'toggle', 
980                                                 opacity: 'toggle'
981                                         }, this.options.playlistSpeed);
982                 },
983
984                 // return the plugin object
985                 plugin : function(){ return this; },
986
987                 // return an array of current player states
988                 state : function(){
989
990                         var self = this, states = [];
991
992                         $.each(this._activeStates, function(key, val){
993
994                                 $.each(self._states, function(k, v){
995
996                                         (val === v) && states.push(k);
997                                 });
998                         });
999
1000                         return states;
1001                 },
1002
1003                 videos : function(){
1004
1005                         return this.options.playlist.videos;
1006                 },
1007
1008                 videoIndex : function(){
1009
1010                         return this.keys.video;
1011                 },
1012
1013                 destroy: function(){
1014
1015                         clearInterval( this.timeInterval );
1016
1017                         this.element.removeClass('ui-widget').removeAttr('style');
1018
1019                         this.elements.playerVideo.removeAttr('style');
1020
1021                         this.elements.playlistContainer.remove();
1022
1023                         this.elements.toolbar.container.remove();
1024
1025                         this.options.swfobject.removeSWF(this.elements.playerObject[0].id);
1026                         
1027                         this.elements.playerObjectClone.appendTo( this.elements.playerVideo );
1028
1029                         $.removeData( this.element[0], this._pluginName );
1030                 }
1031         };
1032
1033         player.prototype.defaultToolbarButtons = {
1034                 play: { 
1035                         text: 'Play',
1036                         icon: 'ui-icon-play', 
1037                         toggleButton: {
1038                                 text: 'Pause', 
1039                                 icon: 'ui-icon-pause', 
1040                                 action: function(){
1041                                                         
1042                                         this.pauseVideo();
1043                                 }
1044                         },
1045                         action: function(){
1046
1047                                 this.playVideo();
1048                         }
1049                 },
1050                 prev: { 
1051                         text: 'Prev', 
1052                         icon: 'ui-icon-seek-prev',
1053                         action: function(){
1054
1055                                 this.prevVideo();
1056                         }
1057                 },
1058                 next: { 
1059                         text: 'Next', 
1060                         icon: 'ui-icon-seek-next',
1061                         action: function(){
1062                                 
1063                                 this.nextVideo();
1064                         }
1065                 },
1066                 shuffle: { 
1067                         text: 'Shuffle/Random', 
1068                         icon: 'ui-icon-shuffle', 
1069                         toggle: 1,
1070                         action: function(){
1071                                 
1072                                 this.shufflePlaylist();
1073                         }
1074                 },
1075                 repeat: { 
1076                         text: 'Repeat playlist',
1077                         icon: 'ui-icon-refresh', 
1078                         toggle: 1,
1079                         action: function(){
1080                                 
1081                                 this.repeat();
1082                         }
1083                 },
1084                 mute: { 
1085                         text: 'Mute', 
1086                         icon: 'ui-icon-volume-on', 
1087                         toggle: 1,
1088                         action: function(button){
1089
1090                                 this.muteVideo(button);
1091                         }
1092                 },
1093                 playlistToggle: { 
1094                         text: 'Toggle playlist', 
1095                         icon: 'ui-icon-script',
1096                         action: function(){
1097
1098                                 this.playlistToggle();
1099                         }
1100                 }
1101         };
1102
1103 })(this.jQuery, this, document);