]> git.0d.be Git - panikweb.git/blob - panikweb_templates/static/js/audioPlayer.js
player: mark sound as stopped when removed from playlist
[panikweb.git] / panikweb_templates / static / js / audioPlayer.js
1 (function($) {
2         var thePlaylist;
3         $.widget( "panik.playlist", {
4                 /*
5                         sound = {
6                                 source :{
7                                         ogg:"oggURL",
8                                         mp3:"mp3URL"
9                                 },
10                                 emission: "episode.slug",
11                                 episode: "episode.slug",
12                                 id:""
13                         }
14                 */
15                 options: {
16                         playlist: [],
17                         html5audioOptions:{controls:true,preload:"none"},
18                         classes: "",
19                         itemClasses: "",
20                         controlContainer: $('<div>'),
21                         playlistContainer: $('<ol>'),
22                         onLoad: function(){},
23                         onAdd: function(){},
24                         onPlay: function(){},
25                         onUpdate: function(){},
26                 },
27                 _create: function() {
28                 // Initialization logic here
29                         thePlaylist = this;     
30                         this.isActive = false;
31                         this.isLastAdd = false;
32                         this.controlButtons = []
33                         this.debugContainer = $('<pre>').hide();
34                         this.controlContainer = this.options.controlContainer;
35                         this.playlistContainer = this.options.playlistContainer;
36                         this.element.addClass(this.options.classes);    
37                         this.element.append(this.controlContainer);     
38                         this.element.append(this.playlistContainer);
39                         this.element.append(this.debugContainer);
40                         this.playlist = this.options.playlist;
41                         this.buildPlaylistControls();
42                         this.loadPlaylist();
43                         this._update();
44                         this.options.onLoad(this);
45                 },
46
47                 _setOption: function( key, value ) {
48                         this.options[ key ] = value;
49                         this._update();
50                 },
51                 _update: function() {   
52                         this.playlist = [];     
53                         this.playlistContainer.find('audio').each(function(){
54                                 thePlaylist.playlist.push(thePlaylist.jsonifyAudio($(this)));
55                         });
56                         this.debugContainer.text(
57                                 JSON.stringify(this.playlist, null, '\t')
58                         );
59                         this.savePlaylist();
60                         this.options.onUpdate(this);
61                         return this.playlist;
62                 },
63                 _reset: function() {    
64                         this.isActive =false;
65                         this.stopSounds();
66                         this.playlistContainer.find('*').remove();
67                         this._update();
68                 },
69                 savePlaylist: function(){
70                         var JSONPlaylist = JSON.stringify(this.playlist, null, '\t');
71                         if (localStorage !== null && localStorage !== undefined) {
72                                 localStorage['playlist'] = JSON.stringify(this.playlist, null, '\t');
73                         }
74                 },
75                 loadPlaylist: function(){
76                         if (localStorage !== null && localStorage !== undefined) {
77                                 this.playlist = localStorage['playlist']?JSON.parse(localStorage['playlist']):this.playlist;
78                         }
79                         $.each(this.playlist,function(k,v){
80                                 thePlaylist.playlistContainer.append(thePlaylist._htmlifyJsonSound(v));
81                         });
82                         return this.playlist;
83                 },
84                 // Transform HTML5 <audio> to simple JSON object.
85                 jsonifyAudio: function(audio) {
86                         var sound = {
87                                 source :{},
88                                 title: audio.attr('title'),
89                                 sound_id:audio.data('sound-id'),
90                                 url:audio.attr('data-url'),
91                                 focus:audio.attr('data-player-focus')
92                         };
93                         audio.children('source').each(function(){
94                                 sound.source[$(this).attr('type')] = $(this).attr('src');
95                         });
96                         return sound;
97                 },
98                 // Play next sound
99                 setFocus: function(element) {
100                         this.isActive = element;
101                         this.playlistContainer.find('li').each(function(){
102                                 $(this).removeClass('active');
103                                 $(this).find('audio').removeAttr('data-player-focus');
104                         });
105                         this.isActive.addClass('active').find('audio').attr('data-player-focus',true);
106                         this._update();
107                 },
108                 // Transform JSON sound object to HTML container for playlist.
109                 _htmlifyJsonSound: function(sound) {
110                         var container = $('<li>');
111                         var audio = $('<audio>',this.options.html5audioOptions)
112                                 .attr('title',sound.title).hide()
113                                 .attr('data-sound-id', sound.sound_id)
114                                 .attr('data-url',sound.url);
115                         var audio_str = sound.sound_id + ': ' + sound.title;
116                         $.each(sound.source,function(k,v){
117                                 var source = $('<source>',{src:v,type:k});
118                                 audio.append(source);
119                         });
120                         audio.on('play',function(e){
121                                 if (e.originalEvent === undefined) {
122                                         return;
123                                 }
124                                 if (typeof (_paq) == 'object') {
125                                         _paq.push(['trackEvent', 'Audio', 'Play', audio_str]);
126                                 }
127                                 thePlaylist.setFocus(container);
128                                 container.addClass('playing');
129                                 playpause.addClass('icon-pause').removeClass('icon-play');
130                                 thePlaylist.controlButtons['playpause'].removeClass('icon-play').addClass('icon-pause');
131                                 thePlaylist.afterPlay();
132                                 var sound_id = $(e.target).data('sound-id');
133                                 $(document).trigger('panik:play', {'sound_id': sound_id});
134                         }).on('pause',function(e){
135                                 $(this).removeClass('playing');
136                                 playpause.addClass('icon-play').removeClass('icon-pause');
137                                 var sound_id = $(e.target).data('sound-id');
138                                 $(document).trigger('panik:pause', {'sound_id': sound_id});
139                                 thePlaylist.controlButtons['playpause'].removeClass('icon-pause').addClass('icon-play');
140                         }).on('stop',function(event){
141                                 $(this).trigger('pause');
142                                 if($(this)[0].currentTime){$(this)[0].currentTime = 0;}
143                         }).on("ended", function(e){
144                                 if (typeof (_paq) == 'object') {
145                                         _paq.push(['trackEvent', 'Audio', 'End', audio_str]);
146                                 }
147                                 thePlaylist.playNext();
148                         }).on('beforePause',function(){
149                                 return this;
150                         }).on('beforePlay',function(){
151                                 thePlaylist.pauseSounds();
152                                 return this;
153                         }).on('timeupdate', function(event) {
154                                 var position = 1.0 * event.target.currentTime / event.target.duration;
155                                 var sound_id = $(event.target).data('sound-id');
156                                 $(document).trigger('panik:timeupdate',
157                                                 {'sound_id': sound_id, 'position': position});
158                         });
159                         var controls = $('<span>',{'class':'soundControls controls'});
160                         var link = $('<a>',{href:sound.url,'class':'button icon-external-link'});
161                         var remove = $('<button>',{title:"Remove from list",'class':'icon-remove',click:function(){
162                                 audio.trigger('stop');
163                                 container.remove();
164                                 thePlaylist._update();
165                         }});
166                         var stop = $('<button>',{title:"Stop",'class':'icon-stop',click:function(){
167                                 audio.trigger('stop');
168                         }}).hide();
169                         var playpause = $('<button>',{title:"Play/Pause",'class':'icon-play',click:function(){
170                                 
171                                   if (audio[0].paused == false) { audio.trigger('pause');
172                                   } else {
173                                         audio.trigger('beforePlay').trigger('play');
174                                 }
175                         }});
176                         controls.append(playpause).append(stop).append(remove);
177                         var title = $('<a>',{title:"More information",href:sound.url,'class':"button title",html:sound.title});
178                         container.append(controls).append(title).append(audio);
179                         if(sound.focus){thePlaylist.setFocus(container);}
180                         return container;
181                 },
182                 // Create a public method.
183                 registerAudio: function(audio,success) {
184                         var sound_id = audio.data('sound-id');
185                         if (this.playlistContainer.find('[data-sound-id=' + sound_id + ']').length) {
186                                 /* already in playlist */
187                                 return;
188                         }
189                         var audioObj = this.jsonifyAudio(audio);
190                         var htmlAudio = this._htmlifyJsonSound(audioObj);
191                         this.playlistContainer.append(htmlAudio);
192                         this.isLastAdd = htmlAudio;
193                         if(!this.isActive){this.setFocus(this.isLastAdd);}
194                         this.options.onAdd(this);
195                         if(success){success();}
196                         this._update();
197                 },
198                 // Play next sound
199                 bindControl: function(control,audio,element,options) {
200                         element.addClass('loading');
201                         audioID = audio.data('souce-id');
202                         //TODO for controls in page content
203                 },
204                 // Play next sound
205                 registerControl: function(name,options) {
206                         this.controlButtons[name] = $('<button>',options);
207                         this.controlContainer.append(this.controlButtons[name]);
208                 },
209                 // Build controls
210                 buildPlaylistControls: function() {
211                         this.controlContainer.empty();
212                         /*
213                         this.registerControl('toggleList',{class:"icon-list",click:     function(){ 
214                                 thePlaylist.playlistContainer.toggle();
215                         }});
216                         this.registerControl('clearList',{class:"icon-trash",click:     function(){ 
217                                 thePlaylist.playlistContainer.empty();
218                                 thePlaylist._update();
219                         }});
220                         */
221                         this.registerControl('previous',{'class':"icon-step-backward",click:function(){
222                                 thePlaylist.playPrevious();
223                         }});
224                         this.registerControl('stop',{'class':"icon-stop",click: function(){ 
225                                 thePlaylist.stopSounds();
226                         }});
227                         this.registerControl('playpause',{'class':"icon-play playPause",click:  function(){
228                                 thePlaylist.playPauseList();
229                         }});
230                         this.registerControl('next',{'class':"icon-step-forward",click: function(){ 
231                                 thePlaylist.playNext();
232                         }});
233                         return true;
234                 },
235                 // Play next sound
236                 afterPlay: function() {
237                         this.options.onPlay(this);
238                 },
239                 // Play next sound
240                 beforePlay: function() {
241                         this.stopSounds();
242                 },
243                 // Play next sound
244                 getActive: function() {
245                         if(!this.isActive){
246                                 this.isActive = this.playlistContainer.children('li').first();                          
247                         }
248                         return this.isActive;
249                 },
250                 playSoundId: function(sound_id) {
251                         this.playlistContainer.find('audio[data-sound-id="' + sound_id + '"]'
252                                         ).trigger('beforePlay').trigger('play');
253                 },
254                 // Play next sound
255                 playPauseList: function() {
256                         if(this.controlButtons['playpause'].hasClass('icon-play')){
257                                 this.getActive().find('audio').trigger('beforePlay').trigger('play');
258                         }else{
259                                 this.getActive().find('audio').trigger('pause');        
260                         }
261                         return true;
262                 },
263                 // Play next sound
264                 playPrevious: function() {
265                         this.getActive().prev().find('audio').trigger('beforePlay').trigger('play');
266                         return true;
267                 },
268                 // Play next sound
269                 playNext: function() {
270                         this.getActive().next().find('audio').trigger('beforePlay').trigger('play');
271                         return true;
272                 },
273                 // Play next sound
274                 playFirst: function() {
275                         this.playlistContainer.find('audio').first().trigger('beforePlay').trigger('play');
276                         return true;
277                 },
278                 // Play next sound
279                 playLast: function() {
280                         this.playlistContainer.find('audio').last().trigger('beforePlay').trigger('play');
281                         return true;
282                 },
283                 // Pause all sounds.
284                 pauseSounds: function() {
285                         this.playlistContainer.find('audio').each(function(){$(this).trigger('pause');});       
286                 },
287                 // stop all sounds.
288                 stopSounds: function() {
289                         this.playlistContainer.find('audio').each(function(){$(this).trigger('stop');});        
290                 },
291         });
292 })(jQuery);
293