1
/*global GLOBAL_PLAYLIST_LIST:true, soundManager */
2
var BOUNDINGBOX = 'boundingBox',
3
PARENTNODE = 'parentNode',
5
EVENTNEXT = 'music:next',
6
EVENTPAUSE = 'music:pause',
7
EVENTPLAY = 'music:play',
8
EVENTPREVIOUS = 'music:previous',
9
EVENTSTARTED = 'music:started',
10
EVENTSTOP = 'music:stop',
11
// Sound object events.
12
EVSOUNDLOADING = 'music:loading',
13
EVSOUNDPLAYING = 'music:playing',
14
EVSOUNDPLAY = 'music:soundplay',
15
EVSOUNDFINISH = 'music:soundfinish',
16
EVSOUNDSTOP = 'music:soundstop',
17
EVSOUNDPAUSE = 'music:soundpause',
26
DEFAULT_ALBUM_ART = MEDIA_URL + 'img/music/album.png',
27
DEFAULT_PLAYLIST_ART = MEDIA_URL + 'img/music/playlist.png',
32
PLAYBUTTON = 'playButton',
33
PREVBUTTON = 'prevButton',
34
STOPBUTTON = 'stopButton',
35
NEXTBUTTON = 'nextButton',
36
PROGRESSBARCONT = 'progressBarCont',
38
MUTECONTROL = 'muteControl',
39
REPEATCONTROL = 'repeatControl',
40
SHUFFLECONTROL = 'shuffleControl',
42
VIEWCHANGE = 'viewChange',
43
PLAYLISTCHANGE = 'playlistChange',
45
DISABLED = 'disabled',
53
DATASOURCE = 'datasource',
54
NOWPLAYING = 'nowplaying',
57
PLAYLIST = 'playlist',
58
PLAYLISTS = PLAYLIST + 's',
66
SELECTEDSONGS = 'selectedSongs',
67
VISIBLECHANGE = 'visibleChange',
71
PROGBARRIGHTARRCOUNT = 'progBarRightArrCount',
72
PROGBARLEFTARRCOUNT = 'progBarLeftArrCount',
76
DOTACTIVESONGSVIEW = '.active-songs-view',
80
MUSICPLAYSONGATINDEX = 'music:playSongAtIndex',
81
MUSICSETPLAYLIST = 'music:setPlaylist',
82
MUSICUPDATESELECTED = 'music:updateSelected',
83
MUSICADDSONGSTOPLAYLIST = 'music:addSongsToPlaylist',
84
MUSICREMOVEFROMNOWPLAYING = 'music:removeFromNowPlaying',
85
MUSICUPDATECOLPLAYBUTTON = 'music:updateColPlayButton',
86
MUSICUPDATECURRENTTRACKROW = 'music:updateCurrentTrackRow',
87
MUSICCHECKBOXESUPDATED = 'music:checkboxesUpdated',
88
MUSICCHECKBOXCHANGED = 'music:checkboxChanged',
89
MOVIESTARRX = /^aac|mp4|m4a$/,
90
namespace = Y.namespace('Music'),
94
ToggleView = function() {
95
Y.Do.before(this.beforeShow, this, 'show');
96
Y.Do.after(this.afterHide, this, 'hide');
98
ToggleView.ATTRS = {events: {value: []}};
99
ToggleView.prototype = {
100
afterHide: function() {
101
var events = this.get('events');
102
while (events.length) {
103
events.pop().detach();
106
beforeShow: function() {
107
if (this.get("rendered") === true) {
113
namespace.PlayerView = Y.Base.create('player', Y.Widget, [], {
114
renderUI: function() {
115
var slider = new Y.Music.Slider({
116
valueChangeHandler: Y.bind(this.onVolumeChange, this),
121
this.set(SLIDER, slider);
125
this.get(PLAYBUTTON).on(CLICK, this.emitPlay, this);
126
this.get(PREVBUTTON).on(CLICK, this.emitPrevious, this);
127
this.get(STOPBUTTON).on(CLICK, this.emitPause, this);
128
this.get(NEXTBUTTON).on(CLICK, this.emitNext, this);
129
this.get(PROGRESSBARCONT).on(CLICK, this.onProgressBarClick, this);
130
this.get(PROGRESSBARCONT).on('blur', this.onProgressBarBlur, this);
131
Y.on(KEY, this.onProgressBarKeyDown, this.get(PROGRESSBARCONT), 'down: 37, 39', this);
132
Y.on(KEY, this.onProgressBarKeyUp, this.get(PROGRESSBARCONT), 'up: 37, 39', this);
134
this.get(MUTECONTROL).on(CLICK, this.onMuteClick, this);
135
this.get('volumeControl').on(CLICK, this.onVolumeClick, this);
136
this.get(REPEATCONTROL).on(CLICK, this.onRepeatClick, this);
137
this.get(SHUFFLECONTROL).on(CLICK, this.onShuffleClick, this);
138
this.get(HISTORY).after(VIEWCHANGE, this.afterViewChange, this);
140
this.after('indexChange', this.afterIndexChange, this);
141
this.after(PLAYLISTCHANGE, this.afterPlaylistChange, this);
142
// This is so nowPlaying is updated as soon as
143
// something is added to the queue.
144
this.after(PLAYLISTCHANGE, this.afterPlay, this);
145
this.after('muteChange', this.afterMuteChange, this);
146
this.after('repeatChange', this.afterRepeatChange, this);
147
this.after('shuffleChange', this.afterShuffleChange, this);
149
Y.Global.on(EVENTSTOP, this.onStop, this);
150
Y.Global.on(EVENTPAUSE, this.onPause, this);
151
Y.Global.on(EVENTSTOP, this.onVuMeterEnd, this);
152
Y.Global.on(EVENTSTOP, this.resetTime, this);
153
Y.Global.on(EVENTPAUSE, this.onVuMeterEnd, this);
154
Y.Global.on(EVENTPLAY, this.onPlay, this);
155
Y.Global.on(MUSICPLAYSONGATINDEX, this.onPlaySongAtIndex, this);
156
Y.Global.on(EVENTNEXT, this.onNext, this);
157
Y.Global.on(EVENTPREVIOUS, this.onPrevious, this);
158
Y.Global.on(EVSOUNDPLAYING, Y.throttle(Y.bind(this.whilePlaying, this), 100), this);
159
Y.Global.on(EVSOUNDLOADING, this.whileLoading, this);
160
Y.Global.on(MUSICSETPLAYLIST, this.setPlaylist, this);
161
Y.Global.on(EVSOUNDFINISH, this.continuePlaylist, this);
162
Y.Global.on(MUSICUPDATESELECTED, this.onUpdateSelected, this);
163
Y.Global.on(MUSICADDSONGSTOPLAYLIST, this.onAddSongsToPlaylist, this);
164
Y.Global.on(MUSICREMOVEFROMNOWPLAYING, this.onRemoveFromNowPlaying, this);
165
Y.Global.on(MUSICUPDATECOLPLAYBUTTON, this.onUpdateColPlayButton, this);
166
Y.Global.on(MUSICUPDATECURRENTTRACKROW, this.updateCurrentTrackRow, this);
167
Y.Global.after(EVENTPLAY, this.afterPlay, this);
168
Y.Unity.onInit(Y.bind(this.bindUnity, this));
170
afterPlaylistChange: function(e) {
171
var index = this.get(INDEX),
173
nextButton = this.get(NEXTBUTTON),
174
playButton = this.get(PLAYBUTTON),
175
prevButton = this.get(PREVBUTTON),
178
if (playlist.length === 0) {
180
if (!nextButton.hasClass(DISABLED)) {
181
nextButton.addClass(DISABLED);
182
nextButton.set(DISABLED, DISABLED);
184
if (!playButton.hasClass(DISABLED)) {
185
playButton.addClass(DISABLED);
186
playButton.set(DISABLED, DISABLED);
188
if (!prevButton.hasClass(DISABLED)) {
189
prevButton.addClass(DISABLED);
190
prevButton.set(DISABLED, DISABLED);
193
playButton.removeClass(DISABLED);
194
playButton.removeAttribute(DISABLED);
196
if (index === 0 || playlist.length === 0) {
197
if (!prevButton.hasClass(DISABLED)) {
198
prevButton.addClass(DISABLED);
199
prevButton.set(DISABLED, DISABLED);
202
prevButton.removeClass(DISABLED);
203
prevButton.removeAttribute(DISABLED);
205
if (index + 1 >= playlist.length) {
206
if (!nextButton.hasClass(NEXTBUTTON)) {
207
nextButton.addClass(NEXTBUTTON);
210
nextButton.removeClass(DISABLED);
211
nextButton.removeAttribute(DISABLED);
214
mp = Y.Unity.Unity.MediaPlayer;
215
mp.setCanPlay(playlist.length !== 0);
216
mp.setCanPause(playlist.length !== 0);
217
mp.setCanGoPrevious(index !== 0 && playlist.length !== 0);
218
mp.setCanGoNext(index + 1 < playlist.length);
220
Y.Global.fire(MUSICCHECKBOXESUPDATED);
222
onUpdateSelected: function(e) {
224
index = this.get(INDEX),
225
history = this.get(HISTORY),
226
view = history.get(VIEW),
227
box = Y.one(".active-songs-view"),
231
if (view && view === NOWPLAYING) {
232
current = box.one('[data-u1m-songid='+song.sID+'][data-u1m-npindex='+index+']');
234
current = box.one('[data-u1m-songid="'+song.sID+'"]');
236
box.all('.current').removeClass(CURRENT);
238
if (current !== null) {
239
current.addClass(CURRENT);
241
Y.Global.fire(MUSICUPDATECOLPLAYBUTTON, { song: song });
244
onVuMeterEnd: function() {
245
var vuMeter = Y.one(".active-songs-view .vu"),
248
vuLeft = vuMeter.one(DOTLEFT);
249
vuRight = vuMeter.one(DOTRIGHT);
250
if (vuRight && vuLeft) {
264
onUpdateColPlayButton: function(e) {
265
var song = e && e.song || null,
266
oNodeRow = Y.one(".active-songs-view .current");
267
this.updateCurrentTrackRow({"node": oNodeRow, song: song});
269
updateCurrentTrackRow: function(e) {
270
var song = e.song || Y.Music.lastSong,
272
box = Y.one(DOTACTIVESONGSVIEW),
276
vuMeter = this.get("vuMeter");
279
currentButton = box.one('button.hidden');
280
currentVuMeter = box.one('.vu');
284
currentButton.removeClass(HIDDEN);
287
if (currentVuMeter) {
288
currentVuMeter.remove();
291
if (oNodeRow !== null) {
292
button = oNodeRow.one("button.play");
293
button.get(PARENTNODE).appendChild(vuMeter);
294
button.addClass(HIDDEN);
295
oNodeRow.addClass(CURRENT);
298
if (song && vuMeter) {
299
if (!song.isHTML5 && soundManager.flashVersion >= 9 && song.instanceOptions.usePeakData) {
300
vuMeter.addClass("has-peak-data");
302
vuMeter.removeClass("has-peak-data");
303
vuMeter.one(DOTLEFT).setStyle("height", 0);
304
vuMeter.one(DOTRIGHT).setStyle("height", 0);
308
onProgressBarClick: function(e) {
311
target = e.currentTarget,
312
song = Y.Music.lastSong,
315
duration = this.getDuration();
318
if (e.pageX || e.pageY) {
322
x = e.clientX + document.body.scrollLeft +
323
document.documentElement.scrollLeft;
325
x -= parseInt(target.getX(), 10);
326
percOfTrack = parseInt((100 / parseInt(target.getComputedStyle(WIDTH), 10)) * x, 10);
327
newPosition = parseInt((duration / 100 * percOfTrack), 10);
329
song.setPosition(newPosition);
333
onProgressBarKeyDown: function(e){
335
var song = Y.Music.lastSong,
337
leftArrCount = this.get(PROGBARLEFTARRCOUNT),
338
rightArrCount = this.get(PROGBARRIGHTARRCOUNT),
339
leftMultiplier = (leftArrCount / 10),
340
rightMultiplier = (rightArrCount / 10);
342
leftMultiplier = leftMultiplier > 0 ? leftMultiplier : 1;
343
rightMultiplier = rightMultiplier > 0 ? rightMultiplier : 1;
345
if (song && leftArrCount === 0 || rightArrCount === 0) {
349
if (keyCode === THIRTYNINE) {
350
song.setPosition(song.position + (100 * rightMultiplier));
351
this.set(PROGBARRIGHTARRCOUNT, rightArrCount + 1);
353
} else if (keyCode === THIRTYSEVEN){
354
song.setPosition(song.position - (100 * leftMultiplier));
355
this.set(PROGBARLEFTARRCOUNT, leftArrCount + 1);
359
onProgressBarKeyUp: function(e){
361
var song = Y.Music.lastSong,
364
if (song && song.paused) {
368
if (keyCode === THIRTYNINE) {
369
this.set(PROGBARRIGHTARRCOUNT, 0);
371
} else if (keyCode === THIRTYSEVEN){
372
this.set(PROGBARLEFTARRCOUNT, 0);
375
onProgressBarBlur: function() {
376
var song = Y.Music.lastSong,
377
leftArrCount = this.get(PROGBARLEFTARRCOUNT),
378
rightArrCount = this.get(PROGBARRIGHTARRCOUNT);
380
if (leftArrCount > 0 || rightArrCount > 0) {
381
if (song && song.paused) {
384
this.set(PROGBARLEFTARRCOUNT, 0);
385
this.set(PROGBARRIGHTARRCOUNT, 0);
388
updatePeakData: function () {
389
var vuMeter = Y.one(".vu"),
391
song = Y.Music.lastSong;
394
vuLeft = vuMeter.one(DOTLEFT);
395
vuRight = vuMeter.one(DOTRIGHT);
396
if (vuRight && vuLeft) {
397
vuLeft.setStyle(HEIGHT, Math.ceil(17*song.peakData.left)+'px');
398
vuRight.setStyle(HEIGHT, Math.ceil(17*song.peakData.right)+'px');
402
getTime: function(nMSec, bAsString) {
403
// convert milliseconds to mm:ss, return as object literal or string
404
var nSec = Math.floor(nMSec/1000),
405
min = Math.floor(nSec/60),
407
return (bAsString?(min+':'+(sec<10?ZERO+sec:sec)):{'min':min,'sec':sec});
409
updateTime: function() {
410
var totalTime = Y.one(".time-display .total"),
411
currentTime = Y.one(".time-display .current"),
412
song = Y.Music.lastSong,
413
duration = this.getDuration();
415
if (totalTime && currentTime) {
416
totalTime.setContent(this.getTime(duration, true));
417
currentTime.setContent(this.getTime(song.position, true));
420
resetTime: function() {
421
var blankTime = "-:--",
422
totalTime = Y.one(".time-display .total"),
423
currentTime = Y.one(".time-display .current");
425
if (totalTime && currentTime) {
426
totalTime.setContent(blankTime);
427
currentTime.setContent(blankTime);
430
onMuteClick: function(e) {
432
var newVal = !this.get('mute');
433
this.set('mute', newVal);
435
afterMuteChange: function(e) {
436
var song = Y.Music.lastSong;
437
if (e.newVal === true) {
438
this.get(MUTECONTROL).addClass(ENABLED);
439
if (song) { song.mute(); }
441
this.get(MUTECONTROL).removeClass(ENABLED);
442
if (song) { song.unmute(); }
445
onPlaySongAtIndex: function(e) {
447
this.set(INDEX, index);
448
Y.Global.fire(EVSOUNDPLAY);
450
onShuffleClick: function(e) {
452
var newVal = !this.get(SHUFFLE);
453
this.set(SHUFFLE, newVal);
455
afterShuffleChange: function(e) {
456
if (e.newVal === true) {
457
this.get(SHUFFLECONTROL).addClass(ENABLED);
459
this.get(SHUFFLECONTROL).removeClass(ENABLED);
461
this.setPlaylistContext();
463
onRepeatClick: function(e) {
465
var newVal = !this.get(REPEAT);
466
this.set(REPEAT, newVal);
468
afterRepeatChange: function(e) {
469
if (e.newVal === true) {
470
this.get(REPEATCONTROL).addClass(ENABLED);
472
this.get(REPEATCONTROL).removeClass(ENABLED);
474
this.setPlaylistContext();
476
onVolumeClick: function(e) {
477
var slider = this.get(SLIDER);
479
if (slider.get(VISIBLE)) {
483
slider.set('align', {
485
points: [Y.WidgetPositionAlign.BC, Y.WidgetPositionAlign.TC]
487
Y.one('body').on(CLICK, function(e) {
489
if (!slider.get(BOUNDINGBOX).contains(e.target)) {
491
e.currentTarget.detach();
496
onVolumeChange: function(e) {
497
/* The slider is actually reversed, so going up -> 0,
500
var value = 100 - e.newVal,
501
volumeControl = this.get(MUTECONTROL),
502
song = Y.Music.lastSong ;
505
song.setVolume(value);
508
volumeControl.removeClass(ENABLED);
509
volumeControl.removeClass(LOW);
510
volumeControl.removeClass(MED);
511
} else if (value === 0) {
512
volumeControl.removeClass(MED);
513
volumeControl.removeClass(LOW);
514
volumeControl.addClass(ENABLED);
515
} else if (value <= 25) {
516
volumeControl.removeClass(ENABLED);
517
volumeControl.removeClass(MED);
518
volumeControl.addClass(LOW);
520
volumeControl.removeClass(ENABLED);
521
volumeControl.removeClass(LOW);
522
volumeControl.addClass(MED);
525
onRemoveFromNowPlaying: function(e){
527
var songIds = e.songIds,
528
length = songIds.length,
529
quantifier = (length === 1) ? SONG : SONGS,
530
playlist = this.get(PLAYLIST),
531
playlistLength = playlist.length,
532
deletedCurrent = false,
533
index = this.get(INDEX),
539
if (length === playlistLength) {
540
Y.Global.fire("music:clearNowPlaying");
546
/* IE is apparently weird about array length of EventFacade
549
message = 'Songs removed from queue';
551
message = length + ' ' + quantifier + ' removed from the queue.';
554
for (i = 0; i < playlistLength; i++) {
555
for (k = 0; k < length; k++) {
556
if (playlist[i].id === songIds[k]) {
557
if (i === this.get(INDEX)){
558
deletedCurrent = true;
560
playlist.splice(i, 1);
562
playlistLength = playlist.length;
564
songIds.splice(k, 1);
566
length = songIds.length;
572
this.set(PLAYLIST, playlist);
574
if (deletedCurrent === true) {
575
song = Y.Music.lastSong;
579
Y.Global.fire(EVENTSTOP);
582
if (index === playlistLength) {
583
this.set(INDEX, index - 1);
585
this.set(INDEX, index);
589
Y.Global.fire(EVENTPLAY);
592
Y.Global.fire('music:nowPlayingButtonsUpdated');
593
Y.Global.fire('one:info', {'message': message});
595
onAddSongsToPlaylist: function(e) {
597
length = songs.length,
598
quantifier = (length === 1) ? SONG : SONGS,
599
injectSong = e.injectSong || false,
600
playNow = e.playNow || false,
601
playlist = this.get(PLAYLIST),
602
playlistLength = playlist.length,
606
currentIndex = this.get(INDEX);
607
if (injectSong && playlistLength > 0) {
608
for (i = length-1; i >= 0; i--) {
609
playlist.splice(currentIndex+1, 0, songs[i]);
611
this.set(PLAYLIST, playlist);
612
this.set(INDEX, currentIndex + 1);
614
this.set(PLAYLIST, playlist.concat(songs));
618
/* IE is apparently weird about array length of EventFacade
621
message = 'Songs added to queue';
623
message = length + ' ' + quantifier + ' added to the queue.';
625
if (playNow === true) {
626
Y.Global.fire(EVENTPLAY);
628
Y.Global.fire('one:info', {'message': message});
631
setPlaylist: function(e) {
632
Y.Global.fire(EVENTSTOP);
634
this.set(PLAYLIST, e.playlist);
637
afterViewChange: function(e) {
638
if (e.newVal === NOWPLAYING) {
639
Y.Global.fire('music:nowPlaying', {
640
songs: this.get(PLAYLIST) });
644
afterPlay: function() {
645
var index = this.get(INDEX),
646
playlist = this.get(PLAYLIST),
647
current = playlist[index],
648
length = playlist.length,
649
albumArtImage = Y.one(".albumart img"),
650
albumArtImageGenerated = false,
651
albumArtContainer = null,
655
// Generate the image elem if it doesn't already
657
if (!albumArtImage) {
658
albumArtImage = Y.Node.create("<img>");
659
albumArtImageGenerated = true;
661
if (current === undefined) {
664
Y.all(".player .hidden").removeClass(HIDDEN);
665
Y.one(".player .start-here").addClass(HIDDEN);
666
this.get('album').setContent(Y.Escape.html(current.album));
667
this.get('artist').setContent(Y.Escape.html(current.artist));
668
this.get('title').setContent(Y.Escape.html(current.title));
669
this.setPlaylistContext();
670
this.get(DATASOURCE).getAlbumArt(current, albumArtImage);
672
if (albumArtImageGenerated === true) {
673
albumArtContainer = Y.one(".albumart");
674
if (albumArtContainer) {
675
albumArtContainer.appendChild(albumArtImage);
680
mp = Y.Unity.Unity.MediaPlayer;
682
title: current.title,
683
artist: current.artist,
684
album: current.album,
685
artLocation: albumArtImage.get('src')
687
mp.setTrack(trackInfo);
688
// And show a notification
689
Y.Unity.Unity.Notification.showNotification(
691
"by " + trackInfo.artist + " from " + trackInfo.album,
692
trackInfo.artLocation);
695
this.get('header').setContent(
696
'Now playing ' + (index + 1) + ' of ' + length + ' songs');
698
setPlaylistContext: function() {
699
var index = this.get(INDEX),
700
repeat = this.get(REPEAT),
701
shuffle = this.get(SHUFFLE),
702
playlist = this.get(PLAYLIST),
703
previous = playlist[index - 1],
704
previousText = previous ? 'Previous: ' + Y.Escape.html(previous.title) + ' - ' + Y.Escape.html(previous.artist) : EMPTY,
705
next = playlist[index + 1],
706
nextText = next ? 'Next: ' + Y.Escape.html(next.title) + ' - ' + Y.Escape.html(next.artist): EMPTY,
710
if (shuffle === false && repeat === false) {
711
previousNode = this.get('previous');
713
previousNode.setContent(previousText);
714
previousNode.setStyle('display', 'block');
716
previousNode.setStyle('display', 'none');
718
nextNode = this.get('next');
720
nextNode.setContent(nextText);
721
nextNode.setStyle('display', 'block');
723
nextNode.setStyle('display', 'none');
726
this.get('previous').setContent(null);
727
this.get('next').setContent(null);
730
afterIndexChange: function(e) {
731
var index = e.newVal,
732
playlist = this.get(PLAYLIST),
733
nextButton = this.get(NEXTBUTTON),
734
prevButton = this.get(PREVBUTTON),
738
if (!prevButton.hasClass(DISABLED)) {
739
prevButton.addClass(DISABLED);
740
prevButton.set(DISABLED, DISABLED);
743
prevButton.removeClass(DISABLED);
744
prevButton.removeAttribute(DISABLED);
746
if (index + 1 >= playlist.length) {
747
if (!nextButton.hasClass(DISABLED)) {
748
nextButton.addClass(DISABLED);
749
nextButton.set(DISABLED, DISABLED);
752
nextButton.removeClass(DISABLED);
753
nextButton.removeAttribute(DISABLED);
756
mp = Y.Unity.Unity.MediaPlayer;
757
mp.setCanGoPrevious(index !== 0);
758
mp.setCanGoNext(index + 1 < playlist.length);
761
this.get("bytesLoadedBar").setStyle(WIDTH, 0);
762
Y.Global.fire(EVENTPLAY);
764
onPause: function() {
765
Y.Music.lastSong.pause();
766
this.get(PLAYBUTTON).show();
767
this.get(STOPBUTTON).hide();
769
var mp = Y.Unity.Unity.MediaPlayer;
770
mp.setPlaybackState(mp.PlaybackState.PAUSED);
774
var lastSong = Y.Music.lastSong,
777
this.get("bytesLoadedBar").setStyle(WIDTH, 0);
780
Y.Music.lastSong = null;
782
this.get(PLAYBUTTON).show();
783
this.get(STOPBUTTON).hide();
784
this.get('progressBar').setStyle(WIDTH, ZERO);
786
mp = Y.Unity.Unity.MediaPlayer;
787
mp.setPlaybackState(mp.PlaybackState.PAUSED);
792
var index = this.get(INDEX),
793
playlist = this.get(PLAYLIST),
794
songObj = playlist[index],
795
newSong = soundManager.getSoundById(songObj.id),
796
lastSong = Y.Music.lastSong,
797
songURI = this.get(DATASOURCE).getStreamingURI(songObj),
798
mute = this.get('mute'),
799
volume = 100 - this.get(SLIDER).getValue(),
804
if (playlist.length === 0) {
805
Y.Global.fire('music:emptyPlaylist');
806
Y.Music.lastSong = null;
810
if (songURI === null) {
815
if (newSong && lastSong && newSong === lastSong) {
816
// If readyState not failed/error
817
if (newSong.readyState !== 2) {
818
if (!newSong.paused) {
821
newSong.play({ 'volume': volume });
824
// Stop the previous song
832
this.get("bytesLoadedBar").setStyle(WIDTH, 0);
840
onfinish: function() {
841
Y.Global.fire(EVSOUNDFINISH);
843
onpause: function() {
844
Y.Global.fire(EVSOUNDPAUSE);
847
Y.Global.fire(EVSOUNDPLAY);
850
Y.Global.fire(EVSOUNDSTOP);
852
whileplaying: function() {
853
Y.Global.fire(EVSOUNDPLAYING);
855
whileloading: function() {
856
Y.Global.fire(EVSOUNDLOADING);
860
isMovieStar: MOVIESTARRX.test(songObj.suffix)
863
// Inform SM2 about ogg fixes LP: 1002481, 921841
864
if (songObj.suffix === "ogg") {
865
soundData.type = "audio/ogg";
868
newSong = soundManager.createSound(soundData);
869
newSong.setVolume(volume);
870
newSong.onposition(1000, function() {
877
newSong.whilePlaying = function() {
878
Y.Global.fire(EVSOUNDPLAYING);
880
Y.Global.fire(EVENTSTARTED, {song: songObj});
883
this.get(STOPBUTTON).show();
884
this.get(PLAYBUTTON).hide();
886
nAPIDurationMilSecs = songObj.duration;
887
newSong.nAPIDurationMilSecs = (nAPIDurationMilSecs) ? nAPIDurationMilSecs * 1000 : 0;
888
Y.Music.lastSong = newSong;
889
Y.Global.fire(MUSICUPDATESELECTED, { song: newSong });
892
mp = Y.Unity.Unity.MediaPlayer;
893
mp.setPlaybackState(mp.PlaybackState.PLAYING);
896
onPrevious: function() {
897
var song = Y.Music.lastSong,
900
if (song.position > 5000 && !song.paused) {
901
Y.Global.fire(EVENTSTOP);
902
Y.Global.fire(EVENTPLAY);
904
index = this.get(INDEX);
905
if (index <= 0) { return; }
907
this.set(INDEX, index);
911
var index = this.get(INDEX),
913
shuffle = this.get(SHUFFLE),
914
length = this.get(PLAYLIST).length;
915
if (shuffle === true) {
916
if (length <= 1) { return; }
919
newIndex = Math.floor(Math.random() * length);
920
} while (index === newIndex);
922
} else if (index+1 >= length) {
927
this.set(INDEX, index);
929
continuePlaylist: function() {
930
Y.Global.fire(EVENTSTOP);
931
var index = this.get(INDEX),
932
repeat = this.get(REPEAT),
933
length = this.get(PLAYLIST).length;
935
Y.Global.fire(EVENTPLAY);
937
Y.Global.fire(EVENTNEXT);
938
if (index+1 < length) {
939
Y.Global.fire(EVENTPLAY);
943
getDuration: function() {
944
var song = Y.Music.lastSong,
945
duration = song.nAPIDurationMilSecs,
946
songDuration = song.duration,
947
songDurationEstimate = song.durationEstimate,
948
songLoaded = song.loaded;
950
if (!duration && !songLoaded && songDurationEstimate) {
951
duration = songDurationEstimate;
954
if (songLoaded && songDuration) {
955
duration = songDuration;
960
whilePlaying: function() {
961
var song = Y.Music.lastSong,
962
progressBar = this.get('progressBar'),
963
duration = this.getDuration(),
964
width = Math.floor((100 * song.position) / duration) + 1;
966
progressBar.setStyle(WIDTH, width + '%');
967
if (soundManager.flashVersion >= 9 && song.instanceOptions.usePeakData) {
968
this.updatePeakData();
972
whileLoading: function() {
973
var song = Y.Music.lastSong,
974
bytesLoadedBar = this.get('bytesLoadedBar'),
975
maxWidth = Math.ceil((song.bytesLoaded/song.bytesTotal)*100),
976
width = maxWidth > 100 ? 100 : maxWidth;
977
bytesLoadedBar.setStyle(WIDTH, width + '%');
979
emitNext: function(e) {
981
if (e.target.hasClass(DISABLED)) { return; }
982
Y.Global.fire(EVENTNEXT);
984
emitPlay: function(e) {
986
if (e.target.hasClass(DISABLED)) { return; }
987
Y.Global.fire(EVENTPLAY);
989
emitPrevious: function(e) {
991
if (e.target.hasClass(DISABLED)) { return; }
992
Y.Global.fire(EVENTPREVIOUS);
994
emitStop: function(e) { e.halt(); Y.Global.fire(EVENTSTOP); },
995
emitPause: function(e) { e.halt(); Y.Global.fire(EVENTPAUSE); },
996
bindUnity: function() {
997
Y.log("Configuring Unity integration");
998
var mp = Y.Unity.Unity.MediaPlayer;
999
mp.init("Ubuntu One Music");
1000
mp.setCanPlay(true);
1001
mp.setCanPause(true);
1002
mp.setCanGoNext(true);
1003
mp.setCanGoPrevious(true);
1005
mp.onPlayPause(Y.bind(function() {
1006
Y.log("Sound Menu: play/pause");
1007
if (this.get(PLAYBUTTON).getStyle('display') !== "none") {
1008
Y.Global.fire(EVENTPLAY);
1010
Y.Global.fire(EVENTPAUSE);
1013
mp.onNext(function() {
1014
Y.log("Sound Menu: next track");
1015
Y.Global.fire(EVENTNEXT);
1017
mp.onPrevious(function() {
1018
Y.log("Sound Menu: previous track");
1019
Y.Global.fire(EVENTPREVIOUS);
1024
CONTENT_TEMPLATE: { value: null },
1025
album: { value: null },
1026
albumArt: { value: null },
1027
artist: { value: null },
1028
datasource: { value: null },
1029
header: { value: null },
1030
history: { value: null },
1031
next: { value: null },
1032
previous: { value: null },
1033
title: { value: null },
1034
mute: { value: false },
1035
shuffle: { value: false },
1036
repeat: { value: false },
1037
muteControl: { value: null },
1038
volumeControl: { value: null },
1039
repeatControl: { value: null },
1040
shuffleControl: { value: null },
1041
index: { value: 0 },
1042
nextButton: { value: null },
1043
vuMeter: { value: Y.Node.create(Y.one("#tpl-vu-meter").getContent()) },
1044
playlist: { value: [] },
1045
playButton: { value: null },
1046
prevButton: { value: null },
1047
progressBar: { value: null },
1048
progressBarCont: { value: null },
1049
progBarLeftArrCount: { value: 0 },
1050
progBarRightArrCount: { value: 0 },
1051
bytesLoadedBar: { value: null },
1052
stopButton: { value: null },
1053
timeDisplay: { value: null },
1054
volume: { value: null },
1055
volumeIndicator: { value: null },
1056
volumeNode: { value: null }
1063
previous: '.previous-song',
1066
muteControl: '#mute',
1067
volumeControl: '#volume',
1068
repeatControl: '#repeat',
1069
shuffleControl: '#shuffle',
1070
nextButton: '#next',
1071
playButton: '#play',
1072
prevButton: '#prev',
1073
progressBar: '.progress',
1074
progressBarCont: '.progress-bar',
1075
bytesLoadedBar: '.bytes-loaded',
1076
stopButton: '#stop',
1077
timeDisplay: '.time-display span',
1078
volumeIndicator: '.volume-indicator',
1079
volumeNode: '.volume-slider'
1083
namespace.AlbumListView = Y.Base.create('albumView', Y.Widget, [ToggleView], {
1084
initializer: function() {
1085
this.get(HISTORY).after(VIEWCHANGE, this.afterViewChange, this);
1088
bindUI: function() {
1089
var boundingBox = this.get('inner'),
1090
events = this.get('events');
1091
events.push(boundingBox.delegate(CLICK, this.onAlbumClick, '.album-listing', this));
1092
events.push(boundingBox.delegate(CLICK, this.onPlayAllClick, '.album-listing button', this));
1094
events.push(this.before(VISIBLECHANGE, this.beforeVisibleChange, this));
1095
events.push(this.after('albumsChange', this.afterAlbumsChange, this));
1097
syncUI: function() {
1098
var view = this.get(HISTORY).get(VIEW);
1099
if (view === ALBUMS) {
1102
this.get('inner').all('.album-listing').remove();
1106
onAlbumClick: function(e) {
1108
if (e.target.get('nodeName').toLowerCase() === 'button' || e.target.ancestor("button") !== null) {
1111
var target = e.currentTarget,
1112
albumId = target.one('a').getAttribute('data-u1m-albumid'),
1113
history = this.get(HISTORY);
1119
onPlayAllClick: function(e) {
1120
var albumId = e.target.ancestor(".album-listing").one('a').getAttribute('data-u1m-albumid'),
1121
datasource = this.get(DATASOURCE);
1122
datasource.getAlbum(albumId, function(e) {
1123
if (e.response.json.directory && e.response.json.directory.child) {
1124
var songs = e.response.json.directory.child;
1125
Y.Global.fire(MUSICADDSONGSTOPLAYLIST, {
1133
afterAlbumsChange: function() {
1134
var albums = this.get(ALBUMS),
1136
count = albums.length,
1137
box = this.get('inner'),
1138
imageGroup = new Y.U1.ImgLoadGroup({
1142
escapeHtml = function(k,v){
1143
return Y.Escape.html(v);
1154
this.set("imageGroup", imageGroup);
1156
box.setContent(EMPTY);
1157
for (i=0; i<count; i++) {
1159
album_art = '/api/music/v2/albums/' + album.u1CoverId + '/art/',
1161
albumNode = Y.Node.create(Y.substitute(Y.one("#tpl-album-listing").getContent(), album, escapeHtml)),
1162
temp_vars = { "img_id": img_id, "default_art_url": DEFAULT_ALBUM_ART },
1163
placeholder = Y.Node.create(Y.substitute(Y.one("#tpl-art").getContent(), temp_vars, escapeHtml)),
1164
link = albumNode.one('[data-u1m-albumid="'+album.id+'"]');
1166
if (album.has_cover_art === true) {
1167
imageGroup.registerImage({
1173
albumNode.insertBefore(placeholder, link);
1174
box.appendChild(albumNode);
1176
// This forces a redraw in IE8.
1177
if (Y.UA.ie === 8) {
1178
bbViews = Y.one(".views");
1180
bbViews.toggleClass("redraw");
1185
beforeVisibleChange: function(e) {
1186
if (e.newVal === true) {
1187
var artist = this.get(HISTORY).get('artist');
1188
this.get(DATASOURCE).getAlbums(artist, Y.bind(this.onIOSuccess, this));
1191
onIOSuccess: function(e) {
1192
var json = e.response.json,
1202
this.get('header').setContent('All albums');
1203
indexes = json.indexes.index,
1204
indexesLength = indexes.length;
1205
for (i=0; i<indexesLength; i++) {
1206
albumList = indexes[i].album;
1207
listLength = albumList.length;
1208
for (j=0; j<listLength; j++) {
1209
albums.push(albumList[j]);
1213
if (json.directory && json.directory.child) {
1214
albumList = json.directory.child;
1215
albumListLength = albumList.length;
1216
this.get('header').setContent(Y.Escape.html(albumList[0].artist) + ' albums');
1217
for (i=0; i<albumListLength; i++) {
1218
albums.push(albumList[i]);
1222
this.set(ALBUMS, albums);
1224
afterViewChange: function(e) {
1225
if (e.newVal === ALBUMS) {
1228
var imageGroup = this.get("imageGroup");
1230
imageGroup.destroy();
1232
this.get('inner').all('.album-listing').remove();
1238
CONTENT_TEMPLATE: { value: null },
1239
albums: { value: [] },
1240
datasource: { value: null },
1241
history: { value: null },
1242
header: { value: null },
1243
inner: { value: null },
1244
visible: { value: false },
1245
imageGroup: { value: false }
1248
header: '.view-header',
1249
inner: '.view-inner'
1253
namespace.ArtistListView = Y.Base.create('artistsView', Y.Widget, [ToggleView], {
1254
initializer: function() {
1255
this.get(HISTORY).on(VIEWCHANGE, this.onViewChange, this);
1258
bindUI: function() {
1259
var events = this.get('events');
1261
events.push(this.get('inner').delegate(CLICK, this.onArtistClick, '.artist-listing', this));
1262
events.push(this.before(VISIBLECHANGE, this.beforeVisibleChange, this));
1263
events.push(this.after('artistsChange', this.afterArtistsChange, this));
1265
syncUI: function() {
1266
var view = this.get(HISTORY).get(VIEW);
1267
if (view === ARTISTS) {
1270
this.get('inner').all('.artist-listing').remove();
1274
beforeVisibleChange: function(e) {
1275
if (e.newVal === true) {
1276
this.get(DATASOURCE).getArtists(Y.bind(this.onIOSuccess, this));
1279
afterArtistsChange: function() {
1280
var artists = this.get(ARTISTS),
1282
count = artists.length,
1283
box = this.get('inner'),
1284
imageGroup = new Y.U1.ImgLoadGroup({
1288
escapeHtml = function(k,v){
1289
return Y.Escape.html(v);
1300
this.set("imageGroup", imageGroup);
1302
box.setContent(EMPTY);
1303
for (i=0; i<count; i++) {
1304
artist = artists[i],
1305
artist_art = '/api/music/v2/artists/' + artist.u1CoverId + '/art/',
1307
artistNode = Y.Node.create(Y.substitute(Y.one("#tpl-artist-listing").getContent(), artist, escapeHtml)),
1308
temp_vars = { "img_id": img_id, "default_art_url": DEFAULT_ALBUM_ART },
1309
placeholder = Y.Node.create(Y.substitute(Y.one("#tpl-art-artist").getContent(), temp_vars, escapeHtml)),
1310
link = artistNode.one('[data-u1m-artistid="'+artist.id+'"]');
1312
if (artist.has_cover_art === true) {
1313
imageGroup.registerImage({
1319
artistNode.insertBefore(placeholder, link);
1320
box.appendChild(artistNode);
1322
// This forces a redraw in IE8.
1323
if (Y.UA.ie === 8) {
1324
bbViews = Y.one(".views");
1326
bbViews.toggleClass("redraw");
1330
onIOSuccess: function(e) {
1339
if (e.response.json && e.response.json.indexes) {
1340
indexes = e.response.json.indexes.index;
1341
indexesLength = indexes.length;
1344
for (i=0; i<indexesLength; i++) {
1345
artistList = indexes[i].artist,
1346
listLength = artistList.length;
1347
for (j=0; j<listLength; j++) {
1348
artists.push(artistList[j]);
1351
this.set(ARTISTS, artists);
1353
onViewChange: function(e) {
1354
var newView = e.newVal,
1357
if (newView === ARTISTS) {
1360
imageGroup = this.get("imageGroup");
1362
imageGroup.destroy();
1364
this.get(BOUNDINGBOX).all('.artist-listing').remove();
1368
onShowArtists: function(e) {
1369
var artists = e.artists,
1370
count = artists.length,
1371
box = this.get(BOUNDINGBOX),
1372
escapeHtml = function(k,v){
1373
return Y.Escape.html(v);
1377
for (i=0; i<count; i++) {
1378
box.appendChild(Y.Node.create(
1379
Y.substitute(Y.one("#tpl-artist-listing").getContent(), artists[i], escapeHtml)));
1382
onArtistClick: function(e) {
1384
var target = e.currentTarget,
1385
artistId = target.one('a').getAttribute('data-u1m-artistid'),
1386
history = this.get(HISTORY);
1394
CONTENT_TEMPLATE: { value: null },
1395
artists: { value: [] },
1396
datasource: { value: null },
1397
history: { value: null },
1398
header: { value: null },
1399
inner: { value: null },
1400
imageGroup: { value: null }
1403
header: '.view-header',
1404
inner: '.view-inner'
1408
namespace.MenuView = Y.Base.create('menu', Y.Widget, [], {
1409
renderUI: function() {
1410
this.get('playlistsds').getPlaylists(Y.bind(this.onIOSuccess, this));
1412
bindUI: function() {
1413
this.get('searchButton').on(CLICK, this.onSearchClick, this);
1414
this.get('searchField').on('keypress', this.onSearchClick, this);
1415
this.get('albumsMenuItem').on(CLICK, this.onAlbumsClick, this);
1416
this.get('artistsMenuItem').on(CLICK, this.onArtistsClick, this);
1417
this.get('songsMenuItem').on(CLICK, this.onSongsClick, this);
1419
var history = this.get(HISTORY),
1422
history.on(VIEWCHANGE, this.syncUI, this);
1423
history.on(PLAYLISTCHANGE, this.syncUI, this);
1425
playlists = this.get(PLAYLISTS);
1426
playlists.delegate(CLICK, this.onPlaylistClick, '.playlist-listing', this);
1427
this.get('nowPlaying').on(CLICK, this.onNowPlayingClick, this);
1429
Y.Global.on('music:playlistsStale', this.renderUI, this);
1431
syncUI: function() {
1432
Y.all(".u1-sidebar-menu .active").removeClass("active");
1433
var view = this.get(HISTORY).get(VIEW),
1440
this.updateActive(ARTISTS);
1443
this.updateActive(NOWPLAYING);
1446
this.updateActive(ALBUMS);
1449
this.updateActive(MYSONGS);
1452
playlist = this.get(HISTORY).get(PLAYLIST),
1453
playlistNode = Y.one('#menu #' + playlist);
1454
this.updateActive(playlistNode);
1457
menuItem = Y.one('#menu .more') || null;
1459
menuItem.addClass('active');
1466
updateActive: function(classOrNode) {
1467
var menuItem = Y.one("#menu ." + classOrNode) || classOrNode;
1468
if (Y.Lang.isObject(menuItem)) {
1469
menuItem.addClass("active");
1472
onSearchClick: function(e) {
1473
if (e.keyCode && e.keyCode !== 13) { return; }
1475
var term = this.get('searchField').get(VALUE),
1476
history = this.get(HISTORY);
1478
Y.Global.fire('one:error', {
1479
message: 'Please enter a search term'
1488
onIOSuccess: function(e) {
1489
var playlists = e.response.json.playlists.playlist,
1490
playlistsLength = playlists ? playlists.length : 0,
1491
playlistTemplate = Y.one('#playlist-listing').getContent(),
1492
playlistList = Y.one('.playlists ul'),
1493
escapeHtml = function(k,v){
1494
return Y.Escape.html(v);
1501
playlistList.all("li:not(#shuffle-all)").remove();
1503
playlistList = Y.Node.create('<ul></ul>');
1505
if (playlistsLength > 0){
1506
GLOBAL_PLAYLIST_LIST = playlists;
1507
if (playlistsLength > 10) {
1508
playlists = playlists.slice(0, 10);
1509
playlistsLength = 10;
1511
for (i=0; i<playlistsLength; i++) {
1512
playlist = playlists[i],
1513
node = Y.Node.create(
1514
Y.substitute(playlistTemplate, playlist, escapeHtml));
1515
playlistList.append(node);
1517
if (playlistsLength >= 1) {
1518
playlistList.append(
1519
Y.Node.create(Y.one('#more-playlists').getContent()));
1521
Y.one('.playlists').append(playlistList);
1523
GLOBAL_PLAYLIST_LIST = [];
1527
onAlbumsClick: function(e) {
1529
var history = this.get(HISTORY);
1534
onArtistsClick: function(e) {
1536
this.get(HISTORY).add(Y.mix({
1540
onNowPlayingClick: function(e) {
1542
this.get(HISTORY).add(Y.mix({
1546
onPlaylistClick: function(e) {
1548
var parentNode = e.target.get(PARENTNODE);
1549
if (parentNode.hasClass('more')) {
1550
// 'More' link was clicked
1551
this.get(HISTORY).add(Y.mix({
1555
// Playlist was clicked
1556
this.get(HISTORY).add(Y.mix({
1557
playlist: parentNode.get('id'),
1562
onSongsClick: function(e) {
1564
this.get(HISTORY).add(Y.mix({
1567
this.updateActive(MYSONGS);
1571
CONTENT_TEMPLATE: { value: null },
1572
albumsMenuItem: { value: null },
1573
artistsMenuItem: { value: null },
1574
datasource: { value: null },
1575
playlistsds: { value: null },
1576
history: { value: null },
1577
nowPlaying: { value: null },
1578
playlists: { value: null },
1579
searchField: { value: null },
1580
searchButton: { value: null },
1581
songsMenuItem: { value: null }
1584
albumsMenuItem: '.albums',
1585
artistsMenuItem: '.artists',
1586
nowPlaying: '.nowplaying',
1587
playlists: '.playlists',
1588
searchField: '.u1-search-input',
1589
searchButton: '.u1-search-button',
1590
songsMenuItem: '.my-songs'
1594
SongView = Y.Base.create('songView', Y.Widget, [ToggleView], {
1595
initializer: function() {
1596
this.after('songsChange', this.afterSongsChange, this);
1597
this.get(HISTORY).after(VIEWCHANGE, this.afterViewChange, this);
1599
bindUI: function() {
1600
var events = this.get('events'),
1601
selectAll = this.get('selectAll');
1603
events.push(selectAll.after(CLICK, this.afterSelectAllClick, this));
1604
events.push(selectAll.after('key', this.afterSelectAllClick, 'down: 32', this));
1606
events.push(this.before(VISIBLECHANGE, this.beforeVisibleChange, this));
1607
events.push(this.before(VISIBLECHANGE, this.beforeVisibleChangeSongView, this));
1608
events.push(this.after(VISIBLECHANGE, this.afterVisibleChangeSongView, this));
1609
this.trackedSongs = new Y.Array([]);
1610
events.push(this.get(BOUNDINGBOX).delegate(CLICK, this.onRowClick, 'tbody tr', this));
1611
events.push(this.get(BOUNDINGBOX).delegate('key', this.onRowClick, 'tbody input[type=checkbox]', 'down:32', this));
1612
events.push(Y.Global.on(MUSICCHECKBOXCHANGED, this.onCheckboxChange, this));
1613
events.push(Y.Global.on(MUSICCHECKBOXESUPDATED, this.onCheckboxesUpdated, this));
1615
syncUI: function() {
1616
if (this.get(HISTORY).get(VIEW) === this.get('viewName')) {
1622
onCheckboxChange: function(e) {
1623
var input = e.input,
1624
bChecked = input.get("checked"),
1627
oSongFromCache = null,
1628
tr = input.ancestor(TR),
1629
trackedSongsLen = this.trackedSongs.length,
1633
if (bChecked === true) {
1634
tr.addClass(CHECKED);
1636
tr.removeClass(CHECKED);
1638
songData = tr.getData("song");
1641
for (i=0; i<trackedSongsLen; i++) {
1642
if (this.trackedSongs[i].id === songData.id) {
1643
oSongFromCache = this.trackedSongs[i];
1648
// Add songData if not already present
1649
if (bChecked === true) {
1650
if (oSongFromCache === null) {
1651
this.trackedSongs.push(songData);
1654
} else if (bChecked === false) {
1655
if (oSongFromCache !== null && index !== null) {
1656
this.trackedSongs.splice(index, 1);
1660
Y.Global.fire(MUSICCHECKBOXESUPDATED);
1662
onRowClick: function(e) {
1664
var target = e.target,
1665
currentTarget = e.currentTarget,
1666
input = currentTarget.one('input[type=checkbox]'),
1667
button = currentTarget.one('button.play'),
1675
if (target === button || button.contains(target) === true) {
1677
trs = Y.all(".active-songs-view tbody tr");
1678
index = trs.indexOf(currentTarget);
1679
history = this.get(HISTORY);
1680
view = history.get(VIEW);
1682
if (view === NOWPLAYING || (view === PLAYLIST && this.get("isShufflePlaylist") === true)) {
1683
Y.Global.fire(MUSICPLAYSONGATINDEX, { index: index });
1685
song = this.get(SONGS)[index];
1686
// Get the song object from data added to the tr
1687
// in the case of infinite scrolled data.
1688
tr = target.ancestor(TR);
1690
song = tr.getData(SONG);
1693
Y.Global.fire(MUSICADDSONGSTOPLAYLIST,
1701
if (input && target !== input) {
1702
tr = target.ancestor(TR);
1704
this.setCheckBox(input, !input.get(CHECKED));
1707
// Fire for natural checking of the checkbox
1708
Y.Global.fire(MUSICCHECKBOXCHANGED, { input: input });
1712
setCheckBox: function(ele, value) {
1713
var curVal = ele.get("checked");
1714
ele.set(CHECKED, value);
1715
Y.Global.fire(MUSICCHECKBOXCHANGED, { input: ele, prevVal: curVal, newVal: value });
1717
clearAllCheckboxes: function() {
1718
if (this.trackedSongs) {
1719
this.trackedSongs = new Y.Array([]);
1721
var selectAll = this.get("selectAll");
1723
selectAll.set(CHECKED, false);
1725
this.get(SELECTEDSONGS).each(function(ele) {
1726
this.setCheckBox(ele, false);
1728
Y.Global.fire(MUSICCHECKBOXESUPDATED);
1730
resetSelectAll: function() {
1731
var selectAll = this.get('selectAll');
1733
selectAll.set(CHECKED, false);
1736
afterSelectAllClick: function(e) {
1737
var value = e.target.get(CHECKED);
1738
this.get(BOUNDINGBOX).all('.song-listing input').each(function(ele) {
1739
this.setCheckBox(ele, value);
1740
if (value === true){
1741
ele.ancestor(TR).addClass(CHECKED);
1743
ele.ancestor(TR).removeClass(CHECKED);
1746
Y.Global.fire(MUSICCHECKBOXESUPDATED);
1748
afterSongsChange: function(e) {
1749
var songs = e.newVal,
1750
playingSong = Y.Music.lastSong,
1751
view = this.get(HISTORY).get(VIEW),
1752
count = songs.length,
1753
tbody = this.get('table').one('.body'),
1755
playButtonTh = Y.one(".active-songs-view th.play-button"),
1757
escapeHtml = function(k,v){
1758
return Y.Escape.html(v);
1760
noSongsMsg = tbody.one(".no-songs"),
1766
this.get(BOUNDINGBOX).all('.song-listing').remove();
1770
listing = noSongsMsg;
1772
listing = Y.Node.create(Y.one("#tpl-no-songs").getContent());
1774
tbody.appendChild(listing);
1775
} else if (count > 0 && noSongsMsg) {
1776
noSongsMsg.remove();
1780
playButtonTh = Y.Node.create(Y.one("#tpl-play-button-th").getContent());
1781
theadRow = Y.one(".active-songs-view thead tr");
1783
theadRow.prepend(playButtonTh);
1787
if (view === "playlist" && this.get("isShufflePlaylist") === true) {
1789
this.get(BOUNDINGBOX).addClass("shuffled");
1791
this.get(BOUNDINGBOX).removeClass("shuffled");
1794
for (i=0; i<count; i++) {
1796
content = Y.mix(song, {index: i});
1798
if (view === 'search') {
1801
listing = Y.Node.create(Y.substitute(Y.one('#'+view+'-song-listing').getContent(), song, escapeHtml));
1802
// Stash the actual trackid + index on the DOM node using HTML5 custom data attrs.
1803
listing.setAttribute("data-u1m-songid", song.id);
1804
// If we are on the now playing view we need to track the index of the track
1805
// to compare with the the now playing index.
1806
if (view === NOWPLAYING) {
1807
// The concatanation is to co-erce data to a string for IE's benefit.
1808
listing.setAttribute("data-u1m-npindex", EMPTY+i);
1809
// If view !== nowplaying then we currently don't show duplicate tracks.
1810
// Should this change then extra tracking data will be required.
1811
} else if (playingSong !== null && song.id === playingSong.sID) {
1812
listing.addClass(CURRENT);
1814
tbody.appendChild(listing);
1816
// Now fire the event to update the selected track for the nowplaying view
1817
// using the data + the currently playing track index.
1818
Y.Global.fire(MUSICUPDATESELECTED, { song: playingSong });
1819
// Fire event to update the col playbutton.
1820
Y.Global.fire(MUSICUPDATECOLPLAYBUTTON);
1821
// This forces a redraw in IE8.
1822
if (Y.UA.ie === 8) {
1823
bbViews = Y.one(".views");
1825
bbViews.toggleClass("redraw");
1829
afterVisibleChangeSongView: function() {
1830
var playingSong = Y.Music.lastSong;
1831
Y.Global.fire(MUSICUPDATESELECTED, { song: playingSong });
1833
beforeVisibleChangeSongView: function(e) {
1834
if (e.newVal === false ) {
1835
this.resetSelectAll();
1836
this.get(BOUNDINGBOX).all('.song-listing').remove();
1838
Y.all(DOTACTIVESONGSVIEW).removeClass("active-songs-view");
1839
this.get(BOUNDINGBOX).addClass("active-songs-view");
1840
Y.Global.fire(MUSICCHECKBOXESUPDATED);
1843
afterViewChange: function(e) {
1844
if (e.newVal === this.get('viewName')) {
1845
if (this.get(VISIBLE) === false) {
1852
onCheckboxesUpdated: function() {
1853
var subMenu = this.get(BOUNDINGBOX).one(".submenu"),
1854
numChecked = this.get(SELECTEDSONGS).size(),
1855
nSongsTemplate = Y.one("#tpl-n-songs").getContent(),
1856
templVars = {"songs": "song", "num": 1 },
1857
numCheckedNodeList = Y.all(".n-songs"),
1861
// Improve checking size to better take into account the my-songs view which
1862
// doesn't always have rendered checked boxes.
1863
if (numChecked === 0 && this.trackedSongs && this.trackedSongs.length > 0) {
1864
numChecked = this.trackedSongs.length;
1866
if (numChecked > 0) {
1867
subMenu.all('.chk[disabled]').each( function(ele){
1868
ele.removeClass(DISABLED);
1869
ele.removeAttribute(DISABLED);
1871
numCheckedNodeList.each( function(ele) {
1872
if (numChecked === 1) {
1873
tmp = Y.substitute(nSongsTemplate, templVars); // safe
1875
templVars.songs = "songs";
1876
templVars.num = numChecked;
1877
tmp = Y.substitute(nSongsTemplate, templVars); // safe
1879
ele.setContent(tmp);
1883
subMenu.all('.chk:not([disabled=disabled])').each( function(ele){
1884
ele.addClass(DISABLED);
1885
ele.set(DISABLED, DISABLED);
1887
numCheckedNodeList.each( function(ele) {
1888
templVars.songs = "songs";
1890
tmp = Y.substitute(nSongsTemplate, templVars); // safe
1891
ele.setContent(tmp);
1895
onPlaylistCreate: function() {
1896
Y.Global.fire('music:playlistsStale');
1898
getSelectedTracks: function(){
1899
var songs = this.get(SONGS),
1900
songsLength = songs.length,
1902
selectedSongs = this.get(SELECTEDSONGS),
1905
if (selectedSongs.size() === 0 && this.trackedSongs.length === 0) {
1908
selectedSongs.each(function(ele) {
1909
var id = ele.get(VALUE),
1911
// For when songs is populated
1912
for (i=0; i<songsLength; i++) {
1913
if (songs[i].id === id) {
1914
selected.push(songs[i]);
1918
// For newer views using the dynamic table widget we use the songs that are tracked
1919
// as checkboxes are checked and unchecked.
1920
if (this.trackedSongs && this.trackedSongs.length > 0) {
1922
for (i=0, j=this.trackedSongs.length; i<j; i++) {
1923
selected.push(this.trackedSongs[i]);
1928
onAddSongsClick: function(e) {
1930
var selected = this.getSelectedTracks();
1931
if (selected.length === 0) {
1934
Y.Global.fire(MUSICADDSONGSTOPLAYLIST, { songs: selected });
1935
this.clearAllCheckboxes();
1937
onAddSongsToNewClick: function(e) {
1940
selectedSongs = this.get(SELECTEDSONGS),
1945
if (selectedSongs.size() === 0 && this.trackedSongs.length === 0) {
1949
createFn = function(name) {
1950
if (name === null || name === EMPTY) {
1953
this.get(SELECTEDSONGS).each(function(ele) {
1954
songs.push(ele.get(VALUE));
1956
if (songs.length === 0) { return; }
1957
this.get(DATASOURCE).createPlaylist(
1958
name, songs, Y.bind(this.onPlaylistCreate, this));
1959
this.clearAllCheckboxes();
1961
addFn = function(playlistId) {
1962
var datasource = this.get(DATASOURCE),
1964
getCallback = function(e) {
1965
var newSongList = [],
1966
oldSongs = e.response.json.playlist.entry,
1967
oldSongsLength = oldSongs.length,
1970
for (i=0; i<oldSongsLength; i++) {
1971
newSongList.push(oldSongs[i].id);
1973
selectedSongs.each(function(ele) {
1974
newSongList.push(ele.get(VALUE));
1976
datasource.updatePlaylist(
1977
playlistId, newSongList, function() {});
1978
self.clearAllCheckboxes();
1980
datasource.getPlaylist(playlistId, getCallback);
1982
dialog = new Y.Music.PlaylistDialog({
1983
createFn: Y.bind(createFn, this),
1984
addFn: Y.bind(addFn, this),
1985
focusNode: e.target,
1990
onPlaySongsClick: function(e) {
1992
var selected = this.getSelectedTracks();
1993
if (selected.length === 0) {
1994
selected = Y.clone(this.get(SONGS), true);
1996
Y.Global.fire(MUSICSETPLAYLIST, { playlist: selected });
1997
Y.Global.fire(EVENTPLAY);
1998
this.clearAllCheckboxes();
2002
datasource: { value: null },
2003
datasourceV2: { value: null },
2004
history: { value: null },
2005
isShufflePlaylist: { value: false },
2006
selectAll: { value: null },
2008
getter: function() {
2009
return Y.all('tbody input:checked');
2012
songs: { value: [] },
2013
submenu: { value: null },
2014
table: { value: null },
2016
getter: function() {
2018
Y.all('tbody input').each(function(ele) {
2019
if (!ele.get(CHECKED)) {
2026
header: { value: null },
2027
viewName: { value: null }
2030
selectAll: '.selectall',
2031
submenu: '.submenu',
2032
header: '.view-header',
2037
namespace.NowPlayingListView = Y.Base.create('nowplayingView', SongView, [], {
2038
initializer: function() {
2039
Y.Global.after('music:nowPlaying', this.afterNowPlaying, this);
2042
bindUI: function() {
2043
Y.bind(this.constructor.superclass.bindUI, this)();
2045
var events = this.get('events');
2046
events.push(this.get('clearNowPlayingButton').on(
2047
CLICK, this.onClearNowPlayingClick, this));
2048
events.push(this.get('removeFromNowPlayingButton').on(
2049
CLICK, this.onRemoveFromNowPlayingClick, this));
2050
events.push(this.get('saveNowPlayingButton').on(
2051
CLICK, this.onSaveNowPlayingClick, this));
2054
onClearNowPlayingClick: function(e) {
2056
Y.Global.fire(MUSICSETPLAYLIST, { playlist: [] });
2057
this.set(SONGS, []);
2058
Y.Global.fire(EVENTSTOP);
2060
// Clear now playing album art etc
2061
Y.one(".player .current-song").addClass(HIDDEN);
2062
Y.one(".player .next-song").addClass(HIDDEN);
2063
Y.one(".player .previous-song").addClass(HIDDEN);
2064
Y.one(".player .start-here").removeClass(HIDDEN);
2067
Y.one(".player h2").setContent("Ubuntu One Music Player");
2068
Y.Global.fire('music:nowPlayingButtonsUpdated');
2070
onSaveNowPlayingClick: function(e) {
2072
var songlist = this.get(SONGS),
2078
if (songlist.length === 0 && this.trackedSongs.length === 0) {
2081
for (i=0; i<songlist.length; i++) {
2082
songs.push(songlist[i].id);
2085
createFn = function(name) {
2086
if (name === null || name === EMPTY) { return; }
2087
this.get(DATASOURCE).createPlaylist(
2088
name, songs, Y.bind(this.onPlaylistCreate, this));
2089
this.clearAllCheckboxes();
2091
dialog = new Y.Music.PlaylistDialog({
2093
createFn: Y.bind(createFn, this),
2094
focusNode: e.target,
2099
onRemoveFromNowPlayingClick: function(e) {
2101
var selected = this.get(SELECTEDSONGS),
2102
length = selected.size(),
2108
selected.each(function(elm){
2109
songIds.push(elm.get(VALUE));
2110
elm.ancestor(TR).remove();
2112
Y.Global.fire(MUSICREMOVEFROMNOWPLAYING, { songIds: songIds });
2113
Y.Global.fire(MUSICCHECKBOXESUPDATED);
2115
afterNowPlaying: function(e) {
2116
this.set(SONGS, e.songs);
2120
clearNowPlayingButton: { value: null },
2121
saveNowPlayingButton: { value: null },
2122
removeFromNowPlayingButton: { value: null },
2123
viewName: { value: NOWPLAYING }
2126
clearNowPlayingButton: '.submenu .clear',
2127
saveNowPlayingButton: '.submenu .save',
2128
removeFromNowPlayingButton: '.submenu .delete'
2132
namespace.PlaylistListView = Y.Base.create('playlistView', SongView, [], {
2133
// Track the current playListId in flight
2134
currentPlaylistId: null,
2135
initializer: function() {
2138
bindUI: function() {
2139
Y.bind(this.constructor.superclass.bindUI, this)();
2141
var events = this.get('events');
2142
events.push(this.get(HISTORY).after(PLAYLISTCHANGE, this.afterPlaylistChange, this));
2144
events.push(this.get('queuePlaylistButton').on(CLICK, this.onQueuePlaylistClick, this));
2145
events.push(this.get('removeFromPlaylistButton').on(CLICK, this.onRemoveFromPlaylistClick, this));
2146
events.push(this.get('addSongsButton').on(CLICK, this.onAddSongsClick, this));
2147
events.push(this.get('deletePlaylistButton').on(CLICK, this.onDeletePlaylistClick, this));
2149
getPlaylist: function(playlistId) {
2150
if (playlistId === "shuffle-all") {
2151
this.set("isShufflePlaylist", true);
2152
this.get(DATASOURCE).getRandomSongs(200, Y.rbind(this.onIOSuccess, this, "random", playlistId));
2154
this.set("isShufflePlaylist", false);
2155
this.get(DATASOURCE).getPlaylist(playlistId, Y.rbind(this.onIOSuccess, this, "playlist", playlistId));
2158
afterPlaylistChange: function(e) {
2159
if (this.get(VISIBLE)) {
2160
if (e.newVal !== this.currentPlaylistId) {
2161
this.getPlaylist(e.newVal);
2162
this.currentPlaylistId = e.newVal;
2166
beforeVisibleChange: function(e) {
2167
if (e.newVal === true) {
2168
var playlist = this.get(HISTORY).get(PLAYLIST);
2169
if (e.newVal !== this.currentPlaylistId) {
2170
this.currentPlaylistId = playlist;
2171
this.getPlaylist(playlist);
2174
this.set("isShufflePlaylist", false);
2177
onIOSuccess: function(e, type) {
2178
type = type || "playlist";
2180
if (type === "random") {
2181
this.get('header').setContent("Shuffle All Songs");
2183
if (e.response.json.randomSongs && e.response.json.randomSongs.song) {
2184
songs = e.response.json.randomSongs.song;
2185
this.set(SONGS, songs);
2186
this.get(BOUNDINGBOX).one(".submenu").hide();
2187
if (songs.length === 0) {
2190
Y.Global.fire(MUSICSETPLAYLIST, { playlist: songs });
2191
Y.Global.fire(EVENTPLAY);
2194
this.get('header').setContent(Y.Escape.html(e.response.json.playlist.name));
2195
this.set(SONGS, e.response.json.playlist.entry);
2196
this.get(BOUNDINGBOX).one(".submenu").show();
2199
onQueuePlaylistClick: function(e) {
2201
var songs = this.get(SONGS);
2202
if (songs.length === 0) { return; }
2203
Y.Global.fire(MUSICSETPLAYLIST, { playlist: Y.clone(songs, true) });
2204
Y.Global.fire(EVENTPLAY);
2205
this.clearAllCheckboxes();
2207
onRemoveFromPlaylistClick: function(e) {
2210
unselectedSongs = this.get('unselectedSongs'),
2211
length = unselectedSongs.length,
2212
playlistId = this.get(HISTORY).get(PLAYLIST),
2215
for (i=0; i<length; i++) {
2216
songs.push(unselectedSongs[i].get(VALUE));
2218
this.get(DATASOURCE).updatePlaylist(
2219
playlistId, songs, Y.bind(this.onPlaylistUpdate, this));
2221
onPlaylistUpdate: function() {
2222
this.get(SELECTEDSONGS).each(function(ele) {
2223
ele.ancestor("tr").remove();
2225
Y.Global.fire('music:playlistsStale');
2227
onDeletePlaylistClick: function(e) {
2229
var history = this.get(HISTORY),
2230
id = history.get(PLAYLIST),
2231
datasource = this.get(DATASOURCE),
2232
confirmDialog = new Y.Music.YesNoDialog({
2233
message: 'Are you sure you want to delete this playlist?',
2235
datasource.deletePlaylist(id, function() {
2236
Y.Global.fire('music:playlistsStale');
2238
Y.mix({ view: ARTISTS }, HISTORYRESET));
2239
confirmDialog.destroy();
2242
noFn: function() { confirmDialog.destroy(); }
2244
confirmDialog.render();
2248
queuePlaylistButton: { value: null },
2249
removeFromPlaylistButton: { value: null },
2250
deletePlaylistButton: { value: null },
2251
addSongsButton: { value: null },
2252
viewName: { value: PLAYLIST }
2255
queuePlaylistButton: '.submenu .play',
2256
removeFromPlaylistButton: '.submenu .delete',
2257
deletePlaylistButton: '.delete-playlist',
2258
addSongsButton: '.submenu .add'
2262
namespace.SongListView = Y.Base.create('songView', SongView, [], {
2263
initializer: function() {
2266
bindUI: function() {
2267
Y.bind(this.constructor.superclass.bindUI, this)();
2268
var events = this.get('events');
2270
events.push(this.get(HISTORY).after('searchChange', this.afterSearchChange, this));
2272
events.push(this.get('addSongsButton').on(CLICK, this.onAddSongsClick, this));
2273
events.push(this.get('addSongsToNewButton').on(CLICK, this.onAddSongsToNewClick, this));
2274
events.push(this.get('playSongsButton').on(CLICK, this.onPlaySongsClick, this));
2276
syncUI: function() {
2277
var view = this.get(HISTORY).get(VIEW);
2278
if (view === SONGS || view === SEARCH) {
2284
afterSearchChange: function(e) {
2285
if (e.newVal === null ) { return; }
2286
if (this.get(VISIBLE)) {
2287
this.get(DATASOURCE).search(e.newVal, Y.bind(this.onIOSuccess, this));
2292
beforeVisibleChange: function(e) {
2298
if (e.newVal === true) {
2299
history = this.get(HISTORY),
2300
view = history.get(VIEW);
2301
if (view === SEARCH) {
2302
term = history.get(SEARCH);
2303
this.get(DATASOURCE).search(term, Y.bind(this.onIOSuccess, this));
2305
album = history.get('album');
2306
this.get(DATASOURCE).getAlbum(
2307
album, Y.bind(this.onIOSuccess, this));
2310
this.resetSelectAll();
2311
this.get(BOUNDINGBOX).all('.song-listing').remove();
2314
onIOSuccess: function(e) {
2315
var view = this.get(HISTORY).get(VIEW),
2321
if (view === SEARCH) {
2322
searchTerm = this.get(HISTORY).get('search');
2323
this.get('header').setContent('Songs matching "' + Y.Escape.html(searchTerm) + '"');
2324
songs = e.response.json.searchResult.match;
2326
if (e.response.json.directory && e.response.json.directory.child) {
2327
songs = e.response.json.directory.child;
2328
this.get('header').setContent(
2329
Y.Escape.html(songs[0].album) + ' by ' + Y.Escape.html(songs[0].artist));
2332
for (i=0; i<songs.length; i++) {
2334
if (song.track === ZERO) {
2338
this.set(SONGS, songs);
2340
afterViewChange: function(e) {
2341
var view = e.newVal;
2342
if (view === SONGS || view === SEARCH) {
2345
this.resetSelectAll();
2348
Y.Global.fire(MUSICCHECKBOXESUPDATED);
2352
addSongsButton: { value: null },
2353
addSongsToNewButton: { value: null },
2354
playSongsButton: { value: null }
2357
addSongsButton: '.submenu .add',
2358
addSongsToNewButton: '.submenu .addnew',
2359
playSongsButton: '.submenu .play'
2363
namespace.MySongListView = Y.Base.create('mySongView', SongView, [], {
2364
initializer: function() {
2367
renderUI: function() {
2368
this.nRowPlayingCacheIndex = null;
2369
var datasourceV2 = this.get("datasourceV2");
2370
this.tableScroll = new Y.u1.TableScroll({
2371
oNodeContainer: "#my-song-view .tablescroll",
2372
oDataSource: datasourceV2,
2375
sDataSourceMethod: "getSongs",
2376
fRecordTotalSchema: function(o) {
2377
return o.response.meta.total;
2379
fRecordListSchema: function(o) {
2380
return o.response.json.songs;
2384
// Width is a fixed width in px.
2385
// flexwidth is a percentage based width based on the
2386
// space remaining after the px based widths have been accounted for.
2387
// TODO: name isn't used currently should bin it if it's superfluos.
2388
{ "name": "play", "width": 40 },
2389
{ "name": "chk", "width": 35 },
2390
{ "name": "title", "flexwidth": "33.3", "ellipsis": true },
2391
{ "name": "artist", "flexwidth": "33.3", "ellipsis": true },
2392
{ "name": "album", "flexwidth": "33.3", "ellipsis": true }
2395
"preDataTemplate": '#song-list-item-predata',
2396
"postDataTemplate": '#song-list-item-postdata'
2398
// The rowData is the 1st arg
2399
// The row number is the 2nd arg
2400
// The instance is the 3rd arg
2401
fCustomRowRenderer: Y.rbind(function(rowData, nRow, context){
2402
var lastSong = Y.Music.lastSong,
2403
node = Y.Node.create(Y.substitute(context.get("sRowPostDataTemplate"), rowData, function(k,v){return Y.Escape.html(v);})),
2405
songId = node.getAttribute("data-u1m-songid");
2407
node.setData(SONG, rowData);
2408
if (lastSong && songId === lastSong.sID) {
2409
this.nRowPlayingCacheIndex = nRow;
2410
Y.Global.fire(MUSICUPDATECURRENTTRACKROW, {"node": node, "song": lastSong});
2412
// Looked for checked tracks based on the data we are tracking.
2413
if (this.trackedSongs && this.trackedSongs.length > 0) {
2414
songChecked = Y.Array.find(this.trackedSongs, function(songData) {
2415
if (songData.id === this.songId) {
2418
}, {"songId": songId});
2419
if (songChecked !== null) {
2420
this.setCheckBox(node.one('input[type=checkbox]'), true);
2421
Y.Global.fire(MUSICCHECKBOXESUPDATED);
2427
// If the current view is MYSONGS at the point of render
2428
// so we're on this view via history being set
2429
// update the scroll widget which will render if
2430
// it's not already rendered.
2431
if (this.get(HISTORY).get(VIEW) === MYSONGS) {
2432
this.updateScrollView();
2435
bindUI: function() {
2436
Y.bind(this.constructor.superclass.bindUI, this)();
2437
var events = this.get('events');
2439
events.push(this.get('addSongsButton').on(CLICK, this.onAddSongsClick, this));
2440
events.push(this.get('addSongsToNewButton').on(CLICK, this.onAddSongsToNewClick, this));
2441
events.push(this.get('playSongsButton').on(CLICK, this.onPlaySongsClick, this));
2443
events.push(this.after(VISIBLECHANGE, this.afterVisibleChange, this));
2444
events.push(this.tableScroll.after("visibleChange", this.updateScrollView, this));
2446
updateScrollView: function() {
2447
if (this.tableScroll.get("rendered") === true) {
2448
// Dump the cache so we re-evaluate what's currently playing.
2449
this.tableScroll.clearDataCache();
2450
this.tableScroll.clearRows();
2451
this.tableScroll.syncUI();
2453
this.tableScroll.render();
2456
afterVisibleChange: function(e) {
2457
if (e.newVal === true ) {
2458
this.tableScroll.set("visible", true);
2460
this.tableScroll.set("visible", false);
2463
afterViewChange: function(e) {
2464
var view = e.newVal;
2465
if (view === MYSONGS) {
2468
this.clearAllCheckboxes();
2474
addSongsButton: { value: null },
2475
addSongsToNewButton: { value: null },
2476
datasourceV2: { value: null },
2477
playSongsButton: { value: null },
2478
viewName: { value: MYSONGS }
2481
addSongsButton: '.submenu .add',
2482
addSongsToNewButton: '.submenu .addnew',
2483
playSongsButton: '.submenu .play'
2487
namespace.PlaylistGridView = Y.Base.create('PlaylistGridView', Y.Widget, [ToggleView], {
2488
initializer: function() {
2489
this.get(HISTORY).after(VIEWCHANGE, this.afterViewChange, this);
2492
bindUI: function() {
2493
var boundingBox = this.get('inner'),
2494
events = this.get('events');
2495
events.push(boundingBox.delegate(CLICK, this.onPlaylistClick, '.playlist-grid-listing', this));
2496
events.push(boundingBox.delegate(CLICK, this.onPlayAllClick, '.playlist-grid-listing button', this));
2497
events.push(this.get(HISTORY).after(VIEWCHANGE, this.afterViewChange, this));
2499
events.push(this.before(VISIBLECHANGE, this.beforeVisibleChange, this));
2500
events.push(this.after('playlistsChange', this.afterPlaylistsChange, this));
2502
syncUI: function() {
2503
var view = this.get(HISTORY).get(VIEW);
2504
if (view === PLAYLISTS) {
2507
this.get('inner').all('.playlist-listing').remove();
2511
onPlaylistClick: function(e) {
2513
if (e.target.get('nodeName').toLowerCase() === 'button' || e.target.ancestor("button") !== null) {
2516
var target = e.currentTarget,
2517
playlistId = target.one('a').getAttribute('data-u1m-playlistid'),
2518
history = this.get(HISTORY);
2520
playlist: playlistId,
2524
onPlayAllClick: function(e) {
2525
var playlistId = e.target.ancestor(".playlist-grid-listing").one('a').getAttribute('data-u1m-playlistid'),
2526
datasource = this.get(DATASOURCE);
2527
datasource.getPlaylist(playlistId, function(e) {
2528
var songs = e.response.json.playlist.entry;
2529
Y.Global.fire(MUSICADDSONGSTOPLAYLIST, {
2536
onPlaylistLoaded: function(e) {
2537
var songs = e.response.json.playlist.entry;
2538
if (songs.length === 0) { return; }
2539
Y.Global.fire(MUSICSETPLAYLIST, { playlist: songs });
2540
Y.Global.fire(EVENTPLAY);
2542
onIOSuccess: function(e) {
2543
this.set(PLAYLISTS, e.response.json.playlists.playlist);
2545
afterPlaylistsChange: function() {
2546
var playlists = this.get(PLAYLISTS),
2547
count = playlists.length,
2548
box = this.get('inner'),
2549
escapeHtml = function(k,v){
2550
return Y.Escape.html(v);
2560
box.setContent(EMPTY);
2561
for (i=0; i<count; i++) {
2562
playlist = playlists[i],
2564
playlistNode = Y.Node.create(Y.substitute(Y.one("#playlist-grid-listing").getContent(), playlist, escapeHtml)),
2565
temp_vars = { "img_id": img_id, "default_art_url": DEFAULT_PLAYLIST_ART },
2566
placeholder = Y.Node.create(Y.substitute(Y.one("#tpl-art").getContent(), temp_vars, escapeHtml)),
2567
link = playlistNode.one('[data-u1m-playlistid="'+playlist.id+'"]');
2569
playlistNode.insertBefore(placeholder, link);
2570
box.appendChild(playlistNode);
2573
beforeVisibleChange: function(e) {
2574
if (e.newVal === true) {
2575
this.get('playlistsds').getPlaylists(Y.bind(this.onIOSuccess, this));
2578
afterViewChange: function(e) {
2579
if (e.newVal === PLAYLISTS) {
2582
this.get('inner').all('.playlist-grid-listing').remove();
2588
CONTENT_TEMPLATE: { value: null },
2589
playlists: { value: [] },
2590
datasource: { value: null },
2591
playlistsds: { value: null },
2592
history: { value: null },
2593
header: { value: null },
2594
inner: { value: null },
2595
visible: { value: false }
2598
header: '.view-header',
2599
inner: '.view-inner'