3 $.widget( "panik.playlist", {
10 emission: "episode.slug",
11 episode: "episode.slug",
17 html5audioOptions:{controls:true},
20 controlContainer: $('<div>'),
21 playlistContainer: $('<ol>'),
25 onUpdate: function(){},
28 // Initialization logic here
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();
44 this.options.onLoad(this);
47 _setOption: function( key, value ) {
48 this.options[ key ] = value;
53 this.playlistContainer.find('audio').each(function(){
54 thePlaylist.playlist.push(thePlaylist.jsonifyAudio($(this)));
56 this.debugContainer.text(
57 JSON.stringify(this.playlist, null, '\t')
60 this.options.onUpdate(this);
66 this.playlistContainer.find('*').remove();
69 savePlaylist: function(){
70 var JSONPlaylist = JSON.stringify(this.playlist, null, '\t');
71 localStorage['playlist'] = JSON.stringify(this.playlist, null, '\t');
73 loadPlaylist: function(){
74 this.playlist = localStorage['playlist']?JSON.parse(localStorage['playlist']):this.playlist;
75 $.each(this.playlist,function(k,v){
76 thePlaylist.playlistContainer.append(thePlaylist._htmlifyJsonSound(v));
80 // Transform HTML5 <audio> to simple JSON object.
81 jsonifyAudio: function(audio) {
84 title: audio.attr('title'),
86 url:audio.attr('data-url'),
87 focus:audio.attr('data-player-focus')
89 audio.children('source').each(function(){
90 sound.source[$(this).attr('type')] = $(this).attr('src');
95 setFocus: function(element) {
96 this.isActive = element;
97 this.playlistContainer.find('li').each(function(){
98 $(this).removeClass('active');
99 $(this).find('audio').removeAttr('data-player-focus');
101 this.isActive.addClass('active').find('audio').attr('data-player-focus',true);
104 // Transform JSON sound object to HTML container for playlist.
105 _htmlifyJsonSound: function(sound) {
106 var container = $('<li>').attr('data-origin',sound.id);
107 var audio = $('<audio>',this.options.html5audioOptions)
108 .attr('title',sound.title).hide()
109 .attr('data-url',sound.url);
110 $.each(sound.source,function(k,v){
111 var source = $('<source>',{src:v,type:k});
112 audio.append(source);
114 audio.on('play',function(){
115 thePlaylist.setFocus(container);
116 container.addClass('playing');
117 playpause.addClass('icon-pause').removeClass('icon-play');
118 thePlaylist.controlButtons['playpause'].removeClass('icon-play').addClass('icon-pause');
119 thePlaylist.afterPlay();
120 }).on('pause',function(){
121 $(this).removeClass('playing');
122 playpause.addClass('icon-play').removeClass('icon-pause');
123 thePlaylist.controlButtons['playpause'].removeClass('icon-pause').addClass('icon-play');
124 }).on('stop',function(){
125 $(this).trigger('pause');
126 if($(this)[0].currentTime){$(this)[0].currentTime = 0;}
127 }).on("ended", function(){
128 thePlaylist.playNext();
129 }).on('beforePause',function(){
131 }).on('beforePlay',function(){
132 thePlaylist.pauseSounds();
135 var controls = $('<span>',{class:'soundControls controls'});
136 var link = $('<a>',{href:sound.url,class:'button icon-external-link'});
137 var html5 = $('<button>',{title:"Display HTML5 audio",class:'icon-html5',click:function(){
140 var remove = $('<button>',{title:"Remove from list",class:'icon-remove',click:function(){
142 thePlaylist._update();
144 var stop = $('<button>',{title:"Stop",class:'icon-stop',click:function(){
145 audio.trigger('stop');
147 var playpause = $('<button>',{title:"Play/Pause",class:'icon-play',click:function(){
149 if (audio[0].paused == false) { audio.trigger('pause');
151 audio.trigger('beforePlay').trigger('play');
154 controls.append(playpause).append(stop).append(remove).append(html5);
155 var title = $('<a>',{title:"More information",href:sound.url,class:"button title",html:sound.title});
156 container.append(controls).append(title).append(audio);
157 if(sound.focus){thePlaylist.setFocus(container);}
160 // Create a public method.
161 registerAudio: function(audio,success) {
162 var audioObj = this.jsonifyAudio(audio);
163 var htmlAudio = this._htmlifyJsonSound(audioObj);
164 this.playlistContainer.append(htmlAudio);
165 this.isLastAdd = htmlAudio;
166 if(!this.isActive){this.setFocus(this.isLastAdd);}
167 this.options.onAdd(this);
168 if(success){success();}
172 bindControl: function(control,audio,element,options) {
173 element.addClass('loading');
174 audioID = audio.attr('id');
175 //TODO for controls in page content
178 registerControl: function(name,options) {
179 this.controlButtons[name] = $('<button>',options);
180 this.controlContainer.append(this.controlButtons[name]);
183 buildPlaylistControls: function() {
184 this.controlContainer.empty();
186 this.registerControl('toggleList',{class:"icon-list",click: function(){
187 thePlaylist.playlistContainer.toggle();
189 this.registerControl('clearList',{class:"icon-trash",click: function(){
190 thePlaylist.playlistContainer.empty();
191 thePlaylist._update();
194 this.registerControl('previous',{class:"icon-step-backward",click:function(){
195 thePlaylist.playPrevious();
197 this.registerControl('stop',{class:"icon-stop",click: function(){
198 thePlaylist.stopSounds();
200 this.registerControl('playpause',{class:"icon-play playPause",click: function(){
201 thePlaylist.playPauseList();
203 this.registerControl('next',{class:"icon-step-forward",click: function(){
204 thePlaylist.playNext();
209 afterPlay: function() {
210 this.options.onPlay(this);
213 beforePlay: function() {
217 getActive: function() {
219 this.isActive = this.playlistContainer.children('li').first();
221 return this.isActive;
224 playPauseList: function() {
225 if(this.controlButtons['playpause'].hasClass('icon-play')){
226 this.getActive().find('audio').trigger('beforePlay').trigger('play');
228 this.getActive().find('audio').trigger('pause');
233 playPrevious: function() {
234 this.getActive().prev().find('audio').trigger('beforePlay').trigger('play');
238 playNext: function() {
239 this.getActive().next().find('audio').trigger('beforePlay').trigger('play');
243 playFirst: function() {
244 this.playlistContainer.find('audio').first().trigger('beforePlay').trigger('play');
248 playLast: function() {
249 this.playlistContainer.find('audio').last().trigger('beforePlay').trigger('play');
253 pauseSounds: function() {
254 this.playlistContainer.find('audio').each(function(){$(this).trigger('pause');});
257 stopSounds: function() {
258 this.playlistContainer.find('audio').each(function(){$(this).trigger('stop');});