From 161e8ed51e054bb20292db0b4f66e5609b7b4d38 Mon Sep 17 00:00:00 2001 From: Trevor Squillario Date: Wed, 25 Jan 2012 09:43:59 -0500 Subject: [PATCH] .020 table layout for songs, bug fixes, display tweaks --- README | 1 + images/albumdefault_56.jpg | Bin 0 -> 993 bytes images/asc.gif | Bin 0 -> 54 bytes images/bg.gif | Bin 0 -> 64 bytes images/desc.gif | Bin 0 -> 54 bytes images/star_wo_12x12.png | Bin 0 -> 394 bytes images/star_y_12x12.png | Bin 0 -> 240 bytes images/star_yo_12x12.png | Bin 0 -> 399 bytes index.html | 152 +++++++++++++---------- js/app.js | 216 +++++++++++++++++++++----------- js/jquery.metadata.js | 122 +++++++++++++++++++ js/jquery.tablesorter.min.js | 4 + style/Style.css | 230 +++++++++++++++++++++++------------ 13 files changed, 505 insertions(+), 220 deletions(-) create mode 100644 images/albumdefault_56.jpg create mode 100644 images/asc.gif create mode 100644 images/bg.gif create mode 100644 images/desc.gif create mode 100644 images/star_wo_12x12.png create mode 100644 images/star_y_12x12.png create mode 100644 images/star_yo_12x12.png create mode 100644 js/jquery.metadata.js create mode 100644 js/jquery.tablesorter.min.js diff --git a/README b/README index 909bdaf..96a16c7 100644 --- a/README +++ b/README @@ -19,6 +19,7 @@ External Subsonic Music Player 1/5/2012 .017 added FancyBox to CoverArt, improved current playlist functions 1/9/2012 .018 added media keyboard bindings from @itchy 1/18/2012 .019 rating support, random playlist, new preferences added +1/25/2012 .020 table layout for songs, bug fixes, display tweaks TO DO: (In no particular order...) - Jukebox Control diff --git a/images/albumdefault_56.jpg b/images/albumdefault_56.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fd41c873de423f0f3ef1c50007e45efc85e4f519 GIT binary patch literal 993 zcmex=^(PF6}rMnOeST|r4lSw=>~TvNxu(8R<c1}I=;VrF4wW9Q)H;sz?% zD!{d!pzFb!U9xX3zTPI5o8roG<0MW4oqZMDikqloVbuf*=gfJ(V&YTRE(2~ znmD<{#3dx9RMpfqG__1j&CD$#!zYjPUOOe%{J6E&?F(bA)Y7|0L%U0Q1Vv}| zJ1kb)y5PgNt%d#iK0BW;EYYx!31BPU8amF z`s}=F*2_!(8IJ0&uJB zn6--YvcBD#9>(r7@7466nfM|NkZc Ddo_fm literal 0 HcmV?d00001 diff --git a/images/asc.gif b/images/asc.gif new file mode 100644 index 0000000000000000000000000000000000000000..74157867f25acbc146704d43399d6c3605ba7724 GIT binary patch literal 54 zcmZ?wbhEHb6lGvxXkcJa);0M5|G(l-7DfgJMg|=QAOOiQF!A=tFW`Q0{?_dDi`go= G4AuZ#-wosd literal 0 HcmV?d00001 diff --git a/images/bg.gif b/images/bg.gif new file mode 100644 index 0000000000000000000000000000000000000000..fac668fcf42af844a3af0a239fa638ddbc08443c GIT binary patch literal 64 zcmZ?wbhEHb6lLIKXkcJa);0M5|G(l-7DfgJMg|=QAOOiQFp2l{H=O3Yl~fU8)V1~= QTew|n!uOuePzDBT00piR0RR91 literal 0 HcmV?d00001 diff --git a/images/desc.gif b/images/desc.gif new file mode 100644 index 0000000000000000000000000000000000000000..3b30b3c58eabdb47a1c420ad03c8e30b966cc858 GIT binary patch literal 54 zcmZ?wbhEHb6lGvxXkcJa);0M5|G(l-7DfgJMg|=QAOOiQF!A>EGoD<#VNP?1QCB1* GgEatI(+xQQ literal 0 HcmV?d00001 diff --git a/images/star_wo_12x12.png b/images/star_wo_12x12.png new file mode 100644 index 0000000000000000000000000000000000000000..04cd5636a51d9c9ed714a8c84e1a467681758f74 GIT binary patch literal 394 zcmV;50d@X~P)-HT_pxi!~Tv$lp zf0lI{Hc$Wa=MUT_0e*f?E-o%%C|m6N_a8H0azM5JSlHRv9sx}>G%+>|W@KbUaiWd2 zWh{vP|NsBLGiT4Qef|2)d9cKWOcK#gM(-N#x0A1++HC54rKpvcXjpw$-&eyLfx+>DIs3-@zdvr-@bk80*3czs5mb$ oh|Bo-c;%nJc-aCJzXcFr0Gm3WVF1&1hyVZp07*qoM6N<$f}}1B^+S-SD(VckeE~C!*iq2UPPF^VcCB6#6>v` zR;~;!8!fw8H6j>78JNF$ys25Rhf(N1vvNp+oq)7J!An*JzZOg8l)p6!|N5DmpRjDG z6q~*5>kpgWvyogUWZYCPI|_YYc!ybmpUF^XiiqS-Nx22q%Nbs^u&HchTM@x%_WeD3 k61&bLJ_Sn&d4&TE+rv{?wN_oY19TmOr>mdKI;Vst073{)H~;_u literal 0 HcmV?d00001 diff --git a/images/star_yo_12x12.png b/images/star_yo_12x12.png new file mode 100644 index 0000000000000000000000000000000000000000..a172014739fe20a388a06eca81c58eaf83b7175e GIT binary patch literal 399 zcmV;A0dW3_P)0_FC>Tk&NImLldoO!HkT5QJiRF z*b)n(|Nm$Hcjj8w+Sl)O&Vwa3Y+Mw(b?eNTzu$6x`~MLrkAy*DAUTj4jL-o|pljH@ zt9vd`P8M4z$%+bI5kwCaex66XKuQ=x11HB@8#&2C`hWg#em`=)X7Qer-Sa?fkQhh~ zC0Ie=_it`(PWE>^>-R5P4CM9#@pmBmkGoZ#4@eHCjuGm9HA#`PH6OpoJ^c1Vv_e!c(z002ovPDHLkV1h=;u5JJT literal 0 HcmV?d00001 diff --git a/index.html b/index.html index a8cf6bf..30e7f8d 100644 --- a/index.html +++ b/index.html @@ -72,11 +72,11 @@ var source = e.target.id; if (source != 'Search' && source != 'ChatMsg') { var unicode = e.charCode ? e.charCode : e.keyCode; - // a-z + // a-z if (unicode >= 65 && unicode <= 90) { var key = findKeyForCode(unicode); var el = '#index_' + key.toUpperCase(); - $('#Artists').stop().scrollTo(el, 800); + $('#Artists').stop().scrollTo(el, 400); // right arrow } else if (unicode == 39 || unicode == 176) { var next = $('ul.songlist li.playing').next(); @@ -96,61 +96,61 @@ // Main Click Events // Albums Click Event - $('ul#ArtistContainer li.item').live('click', function () { - $('ul#AutoAlbumContainer li').removeClass('selected'); - $('ul#ArtistContainer li').removeClass('selected'); + $('#ArtistContainer li.item').live('click', function () { + $('#AutoAlbumContainer li').removeClass('selected'); + $('#ArtistContainer li').removeClass('selected'); $(this).addClass('selected'); - getAlbums($(this).attr("id"), '', '', '#AlbumContainer'); + getAlbums($(this).attr("id"), '#AlbumRows'); }); $('#BottomIndex li a').live('click', function () { var el = '#index_' + $(this).text(); - $('#Artists').stop().scrollTo(el, 800); + $('#Artists').stop().scrollTo(el, 400); return false; }); - $('ul#AutoAlbumContainer li.item').live('click', function () { - $('ul#AutoAlbumContainer li').removeClass('selected'); - $('ul#ArtistContainer li').removeClass('selected'); + $('#AutoAlbumContainer li.item').live('click', function () { + $('#AutoAlbumContainer li').removeClass('selected'); + $('#ArtistContainer li').removeClass('selected'); $(this).addClass('selected'); getAlbumListBy($(this).attr("id")); }); - $('li.album a.play').live('click', function (e) { + $('tr.album a.play').live('click', function (e) { var albumid = $(this).parent().parent().attr('childid'); var artistid = $(this).parent().parent().attr('parentid'); - getAlbums(albumid, artistid, 'autoplay', '#CurrentPlaylistContainer'); + getSongs(albumid, artistid, 'autoplay', '#CurrentPlaylistContainer'); return false; }); - $('li.album a.add').live('click', function (e) { + $('tr.album a.add').live('click', function (e) { var albumid = $(this).parent().parent().attr('childid'); var artistid = $(this).parent().parent().attr('parentid'); - getAlbums(albumid, artistid, 'add', '#CurrentPlaylistContainer'); + getSongs(albumid, artistid, 'add', '#CurrentPlaylistContainer'); return false; }); - $('li.album a.rate').live('click', function (event) { + $('tr.album a.rate').live('click', function (event) { var itemid = $(this).parent().parent().attr('childid'); rateSong(itemid, 5); return false; }); - $('li.album a.favorite').live('click', function (event) { + $('tr.album a.favorite').live('click', function (event) { var itemid = $(this).parent().parent().attr('childid'); rateSong(itemid, 0); return false; }); - $('li.album').live('click', function (e) { + $('tr.album').live('click', function (e) { var albumid = $(this).attr('childid'); var artistid = $(this).attr('parentid'); - getAlbums(albumid, artistid, '', '#AlbumContainer'); + getSongs(albumid, artistid, '', '#AlbumRows'); return false; }); // Track - Click Events // Multiple Select $('.noselect').disableTextSelect(); var lastChecked = null; - $('ul.songlist li.song').live('click', function (event) { - var checkboxclass = 'ul.songlist li.song'; + $('table.songlist tr.song').live('click', function (event) { + var checkboxclass = 'table.songlist tr.song'; var songid = $(this).attr('childid'); var albumid = $(this).attr('parentid'); if (!event.ctrlKey) { - $('ul.songlist li.song').removeClass('selected'); + $(checkboxclass).removeClass('selected'); } if ($(this).hasClass('selected')) { $(this).removeClass('selected'); @@ -171,42 +171,42 @@ lastChecked = this; }); // Double Click - $('ul.songlist li.song').live('dblclick', function (e) { + $('table.songlist tr.song').live('dblclick', function (e) { e.preventDefault(); //$(this).addClass('playing').siblings().removeClass('playing'); var songid = $(this).attr('childid'); var albumid = $(this).attr('parentid'); playSong('', this, songid, albumid); }); - $('ul.songlist li.song a.play').live('click', function (event) { + $('table.songlist tr.song a.play').live('click', function (event) { var songid = $(this).parent().parent().attr('childid'); var albumid = $(this).parent().parent().attr('parentid'); playSong($(this).parent().parent(), songid, albumid); return false; }); - $('ul.songlist li.song a.add').live('click', function (event) { + $('table.songlist tr.song a.add').live('click', function (event) { var track = $(this).parent().parent(); - $(track).clone().appendTo('ul#CurrentPlaylistContainer'); + $(track).clone().appendTo('#CurrentPlaylistContainer'); return false; }); - $('ul.songlist li.song a.remove').live('click', function (event) { + $('table.songlist tr.song a.remove').live('click', function (event) { var track = $(this).parent().parent(); $(track).remove(); refreshRowColor(); return false; }); - $('ul.songlist li.song a.rate').live('click', function (event) { + $('table.songlist tr.song a.rate').live('click', function (event) { var songid = $(this).parent().parent().attr('childid'); rateSong(songid, 5); return false; }); - $('ul.songlist li.song a.favorite').live('click', function (event) { + $('table.songlist tr.song a.favorite').live('click', function (event) { var songid = $(this).parent().parent().attr('childid'); rateSong(songid, 0); return false; }); $('li.index').live('click', function (e) { - $('#Artists').stop().scrollTo('#auto', 800); + $('#Artists').stop().scrollTo('#auto', 400); return false; }); @@ -249,13 +249,13 @@ return false; }); $('#action_SelectAll').click(function () { - $('#Albums li.song').each(function () { + $('#Albums tr.song').each(function () { $(this).addClass('selected'); }); return false; }); $('#action_SelectNone').click(function () { - $('#Albums li.song').each(function () { + $('#Albums tr.song').each(function () { $(this).removeClass('selected'); }); return false; @@ -274,12 +274,12 @@ }); // Current Playlist Click Events $('#action_Shuffle').live('click', function () { - $('#CurrentPlaylistContainer li.song').shuffle(); + $('#CurrentPlaylistContainer tr.song').shuffle(); refreshRowColor(); return false; }); $('#action_Empty').live('click', function () { - $('#CurrentPlaylistContainer').empty(); + $('#CurrentPlaylistContainer tbody').empty(); return false; }); $('a#action_AddCurrentToPlaylist').click(function () { @@ -297,48 +297,50 @@ } }); $('#action_CurrentSelectAll').click(function () { - $('#CurrentPlaylist li.song').each(function () { + $('#CurrentPlaylist tr.song').each(function () { $(this).addClass('selected'); }); return false; }); $('#action_CurrentSelectNone').click(function () { - $('#CurrentPlaylist li.song').each(function () { + $('#CurrentPlaylist tr.song').each(function () { $(this).removeClass('selected'); }); return false; }); // Playlist Click Events - $('ul#AutoPlaylistContainer li.item').live('click', function () { - $('ul#AutoPlaylistContainer li').removeClass('selected'); + $('#AutoPlaylistContainer li.item').live('click', function () { + $('#AutoPlaylistContainer li').removeClass('selected'); + $('#PlaylistContainer li').removeClass('selected'); $(this).addClass('selected'); getRandomSongList('', '#TrackContainer'); }); - $('ul#AutoPlaylistContainer li.item a.play').live('click', function () { + $('#AutoPlaylistContainer li.item a.play').live('click', function () { getRandomSongList('autoplay', '#CurrentPlaylistContainer'); return false; }); - $('ul#AutoPlaylistContainer li.item a.add').live('click', function () { + $('#AutoPlaylistContainer li.item a.add').live('click', function () { getRandomSongList('', '#CurrentPlaylistContainer'); return false; }); - $('ul#PlaylistContainer li.item').live('click', function () { - $('ul#PlaylistContainer li').removeClass('selected'); + $('#PlaylistContainer li.item').live('click', function () { + $('#AutoPlaylistContainer li').removeClass('selected'); + $('#PlaylistContainer li').removeClass('selected'); $(this).addClass('selected'); - getPlaylist($(this).attr("id"), '', '#TrackContainer'); + getPlaylist($(this).attr("id"), '', '#TrackContainer tbody'); }); - $('ul#PlaylistContainer li.item a.play').live('click', function () { - getPlaylist($(this).parent().parent().attr("id"), 'autoplay', '#CurrentPlaylistContainer'); + $('#PlaylistContainer li.item a.play').live('click', function () { + getPlaylist($(this).parent().parent().attr("id"), 'autoplay', '#CurrentPlaylistContainer tbody'); return false; }); - $('ul#PlaylistContainer li.item a.add').live('click', function () { - getPlaylist($(this).parent().parent().attr("id"), '', '#CurrentPlaylistContainer'); + $('#PlaylistContainer li.item a.add').live('click', function () { + getPlaylist($(this).parent().parent().attr("id"), '', '#CurrentPlaylistContainer tbody'); return false; }); $('#action_DeletePlaylist').click(function () { - if ($('ul#PlaylistContainer li.selected').length > 0) { + if ($('#PlaylistContainer li.selected').length > 0) { if (confirmDelete()) { - $('ul#PlaylistContainer li.selected').each(function () { + $('#PlaylistContainer li.selected').each(function () { deletePlaylist($(this).attr("id")); }); } @@ -346,16 +348,16 @@ return false; }); $('#action_SavePlaylist').click(function () { - if ($('ul#PlaylistContainer li.selected').length > 0) { - $('ul#PlaylistContainer li.selected').each(function () { + if ($('#PlaylistContainer li.selected').length > 0) { + $('#PlaylistContainer li.selected').each(function () { savePlaylist($(this).attr("id")); }); } return false; }); $('#action_RemoveSongs').click(function () { - if ($('ul#TrackContainer li.selected').length > 0) { - $('ul#TrackContainer li.selected').each(function () { + if ($('#TrackContainer tr.selected').length > 0) { + $('#TrackContainer tr.selected').each(function () { $(this).remove(); }); } @@ -368,12 +370,12 @@ return false; }); $('#NextTrack').live('click', function () { - var next = $('#CurrentPlaylistContainer li.playing').next(); + var next = $('#CurrentPlaylistContainer tr.playing').next(); changeTrack(next); return false; }); $('#PreviousTrack').live('click', function () { - var prev = $('#CurrentPlaylistContainer li.playing').prev(); + var prev = $('#CurrentPlaylistContainer tr.playing').prev(); changeTrack(prev); return false; }); @@ -459,12 +461,13 @@ $.cookie('css', style, { expires: 365, path: '/' }); location.reload(true); }); - }); // End document.ready + }); // End document.ready $(window).load(function () { if ($.cookie('defaultsmwidth')) { var width = $.cookie('defaultsmwidth'); $('.smsection').css({ 'width': width + 'px' }); + $('#MainActions').css({ 'width': (width - 5) + 'px' }); $('#BottomContainer').css({ 'width': (width - 16) + 'px' }); var ulwidth = parseInt(width) + 6; $('#AlbumContainer').css({ 'margin-left': ulwidth + 'px' }); @@ -477,15 +480,21 @@ }); function resizeContent() { $('.tabcontent').css({ 'height': (($(window).height() - 160)) + 'px' }); - $('.smsection').css({ 'height': (($(window).height() - 160)) + 'px' }); + $('.smsection').css({ 'height': (($(window).height() - 200)) + 'px' }); var smheight = $('.smsection').height(); - $('#BottomContainer').css({ 'top': smheight + 35 + 'px' }); + var smwidth = $('.smsection').width(); + $('#BottomContainer').css({ 'top': smheight + 75 + 'px' }); + var screenwidth = $(window).width(); + $('#AlbumContainer').css({ 'width': (screenwidth - smwidth - 35) + 'px' }); + $('#TrackContainer').css({ 'width': (screenwidth - smwidth - 35) + 'px' }); + $('#CurrentPlaylistContainer').css({ 'width': (screenwidth - 35) + 'px' }); } function resizeSMSection(x) { var smwidth = $('.smsection').width(); var newsmwidth = smwidth + x; if (newsmwidth > 150 && newsmwidth < 500) { $('.smsection').css({ 'width': (newsmwidth) + 'px' }); + $('#MainActions').css({ 'width': (newsmwidth - 5) + 'px' }); $('#BottomContainer').css({ 'width': (newsmwidth - 16) + 'px' }); $.cookie('defaultsmwidth', newsmwidth, { expires: 365, path: '/' }); var ulwidth = newsmwidth + 6; @@ -499,7 +508,7 @@ audiojs.events.ready(function () { a = audiojs.createAll({ trackEnded: function () { - var next = $('#CurrentPlaylistContainer li.playing').next(); + var next = $('#CurrentPlaylistContainer tr.playing').next(); changeTrack(next); }, updatePlayhead: function (percent) { @@ -550,12 +559,12 @@
-
+
-
+
+ Playlist + Current @@ -569,17 +578,20 @@
  • Auto Albums
  • -
  • Random
  • -
  • Recently Played
  • Recently Added
  • +
  • Random
  • Top Rated
  • +
  • Recently Played
  • Most Played
      -
        + + + +
        @@ -592,7 +604,10 @@
        -
          + + + +
          @@ -609,13 +624,16 @@
          • Auto Playlists
          • -
          • Random
          • +
          • Random
          • Saved Playlists
            -
              + + + +
              @@ -673,7 +691,7 @@
              -
              +
              • diff --git a/js/app.js b/js/app.js index b8b65bf..a7ea6fd 100644 --- a/js/app.js +++ b/js/app.js @@ -14,6 +14,10 @@ function loadTabContent(tab) { case '#tabLibrary': loadArtists(); break; + case '#tabCurrent': + var header = generateSongHeaderHTML(); + $("#CurrentPlaylistContainer thead").html(header); + break; case '#tabPlaylists': loadPlaylists(); break; @@ -42,10 +46,15 @@ function loadArtists(refresh) { }, success: function (data) { if (data["subsonic-response"].status == 'ok') { - var indexlist; + var indexlist, indexname; $.each(data["subsonic-response"].indexes.index, function (i, index) { - $('
              • ' + index.name + '
              • ').appendTo("#ArtistContainer"); - indexlist += '
              • ' + index.name + '
              • '; + if (index.name == '#') { + indexname = '0-9'; + } else { + indexname = index.name; + } + $('
              • ' + indexname + '
              • ').appendTo("#ArtistContainer"); + indexlist += '
              • ' + indexname + '
              • '; var artists = []; if (index.artist.length > 0) { artists = index.artist; @@ -63,6 +72,7 @@ function loadArtists(refresh) { }); }); //$(indexlist).appendTo("#IndexList"); + $("#BottomIndex").empty(); $(indexlist).appendTo("#BottomIndex"); } else { var error = data["subsonic-response"].status; @@ -76,7 +86,7 @@ function loadArtists(refresh) { }); } } -function getAlbums(id, artistid, action, appendto) { +function getAlbums(id, appendto) { $.ajax({ url: baseURL + '/getMusicDirectory.view?v=1.6.0&c=subweb&f=json&id=' + id, method: 'GET', @@ -85,8 +95,46 @@ function getAlbums(id, artistid, action, appendto) { req.setRequestHeader('Authorization', auth); }, success: function (data) { - if (appendto == '#AlbumContainer' && action == '') { - $('#AlbumContainer').empty(); + $("#AlbumRows").empty(); + if (data["subsonic-response"].directory.child != undefined) { + // There is a bug in the API that doesn't return a JSON array for one artist + var children = []; + if (data["subsonic-response"].directory.child.length > 0) { + children = data["subsonic-response"].directory.child; + } else { + children[0] = data["subsonic-response"].directory.child; + } + + var rowcolor; + var albumhtml; + $.each(children, function (i, child) { + if (i % 2 == 0) { + rowcolor = 'even'; + } else { + rowcolor = 'odd'; + } + albumhtml = generateAlbumHTML(rowcolor, child.id, child.parent, child.coverArt, child.title, child.artist, child.userRating); + $(albumhtml).appendTo("#AlbumRows"); + }); + var header = generateAlbumHeaderHTML(); + $("#AlbumHeader").html(header); + } + } + }); +} +function getSongs(id, artistid, action, appendto) { + $.ajax({ + url: baseURL + '/getMusicDirectory.view?v=1.6.0&c=subweb&f=json&id=' + id, + method: 'GET', + dataType: 'json', + beforeSend: function (req) { + req.setRequestHeader('Authorization', auth); + }, + success: function (data) { + if (appendto == '#AlbumRows' && action == '') { + $('#AlbumRows').empty(); + var header = generateSongHeaderHTML(); + $("#AlbumHeader").html(header); } if (action == 'autoplay') { $('#CurrentPlaylistContainer').empty(); @@ -108,22 +156,20 @@ function getAlbums(id, artistid, action, appendto) { } else { rowcolor = 'odd'; } - if (child.isDir == true) { - albumhtml = generateAlbumHTML(rowcolor, child.id, child.parent, child.coverArt, child.title, child.artist, child.userRating); - $(albumhtml).appendTo("#AlbumContainer"); - } else { - var track; - if (child.track === undefined) { track = " "; } else { track = child.track; } - var time = secondsToTime(child.duration); - albumhtml = generateSongHTML(rowcolor, child.id, child.parent, track, child.title, child.artist, child.album, child.userRating, time['m'], time['s']); - if (appendto == '#AlbumContainer') { - if (i == 0) { - var backhtml = '
              • « Back to ' + child.artist + '
              • '; - $(backhtml).appendTo("#AlbumContainer"); - } + var track; + if (child.track === undefined) { track = " "; } else { track = child.track; } + var time = secondsToTime(child.duration); + albumhtml = generateSongHTML(rowcolor, child.id, child.parent, track, child.title, child.artist, child.album, child.coverArt, child.userRating, time['m'], time['s']); + /* + if (appendto == '#AlbumRows') { + if (i == 0) { + //var backhtml = '« Back to ' + child.artist + ''; + var backhtml = '' + child.artist + ''; + $("#BreadCrumb").html($(backhtml)); } - $(albumhtml).appendTo(appendto); } + */ + $(albumhtml).appendTo(appendto); }); if (action == 'autoplay') { autoPlay(); @@ -148,7 +194,9 @@ function getAlbumListBy(id) { }, success: function (data) { if (data["subsonic-response"].albumList.album != undefined) { - $("#AlbumContainer").empty(); + $("#AlbumRows").empty(); + var header = generateAlbumHeaderHTML(); + $("#AlbumHeader").html(header); // There is a bug in the API that doesn't return a JSON array for one artist var albums = []; if (data["subsonic-response"].albumList.album.length > 0) { @@ -170,10 +218,10 @@ function getAlbumListBy(id) { if (album.isDir == true) { albumhtml = generateAlbumHTML(rowcolor, album.id, album.parent, album.coverArt, album.title, album.artist, album.userRating); } - $(albumhtml).appendTo("#AlbumContainer") + $(albumhtml).appendTo("#AlbumRows") }); } else { - $('#AlbumContainer').empty(); + $('#AlbumRows').empty(); } } }); @@ -219,7 +267,7 @@ function getRandomSongList(action, appendto) { var track; if (item.track === undefined) { track = " "; } else { track = item.track; } var time = secondsToTime(item.duration); - html = generateSongHTML(rowcolor, item.id, item.parent, track, item.title, item.artist, item.album, item.userRating, time['m'], time['s']); + html = generateSongHTML(rowcolor, item.id, item.parent, track, item.title, item.artist, item.album, item.coverArt, item.userRating, time['m'], time['s']); $(html).appendTo(appendto); }); if (action == 'autoplay') { @@ -231,43 +279,56 @@ function getRandomSongList(action, appendto) { } }); } +function generateAlbumHeaderHTML() { + var html; + html = 'AlbumArtist'; + return html; +} function generateAlbumHTML(rowcolor, childid, parentid, coverart, title, artist, rating) { var html; - html = '
              • '; - html += '
                '; - html += '
                '; + html = ''; + html += ''; + html += ''; if (rating == 5) { - html += '
                '; + html += ''; } else { - html += '
                '; + html += ''; } - html += '
                '; - html += '' + title + ''; - html += '' + artist + ''; - html += '
              • '; + html += ''; + html += ''; + html += '' + title + ''; + html += '' + artist + ''; + html += ''; return html; } -function generateSongHTML(rowcolor, childid, parentid, track, title, artist, album, rating, m, s) { +function generateSongHeaderHTML() { var html; - html = '
              • '; - html += '
                '; - html += '
                '; - html += '
                '; - if (rating == 5) { - html += '
                '; - } else { - html += '
                '; - } - html += '' + track + ' '; - html += '' + title + ' '; - html += '' + artist + ': '; - html += '' + album + ' '; - html += ' ' + m + ':' + s + ''; - html += '
              • '; + html = 'TrackTitleArtistAlbumTime'; return html; } +function generateSongHTML(rowcolor, childid, parentid, track, title, artist, album, coverart, rating, m, s) { + var html; + html = ''; + html += ''; + html += ''; + html += ''; + if (rating == 5) { + html += ''; + } else { + html += ''; + } + html += ''; + html += '' + track + ''; + html += '' + title + ''; + html += '' + artist + ''; + html += '' + album + ''; + html += '' + m + ':' + s + ''; + html += ''; + return html; +} + function refreshRowColor() { - $.each($('ul.songlist li.song'), function (i) { + $.each($('table.songlist tr.song'), function (i) { $(this).removeClass('even odd'); var rowcolor; if (i % 2 == 0) { @@ -304,11 +365,12 @@ function playSong(el, songid, albumid) { $('#songdetails_song').attr('parentid', albumid); $('#songdetails_song').attr('childid', songid); $('#songdetails_artist').html(artist + ' - ' + album); + //$('#songdetails_artist').html('« Back to ' + artist + ''); $('#coverartimage').attr('href', baseURL + '/getCoverArt.view?v=1.6.0&c=subweb&f=json&id=' + songid); - $('#coverartimage img').attr('src', baseURL + '/getCoverArt.view?v=1.6.0&c=subweb&f=json&size=60&id=' + songid); + $('#coverartimage img').attr('src', baseURL + '/getCoverArt.view?v=1.6.0&c=subweb&f=json&size=56&id=' + songid); audio.load(baseURL + '/stream.view?v=1.6.0&c=subweb&f=json&id=' + songid); audio.play(); - $('ul.songlist li.song').removeClass('playing'); + $('table.songlist tr.song').removeClass('playing'); $(el).addClass('playing'); $('#PlayTrack').find('img').attr('src', 'images/pause_24x32.png'); $('#PlayTrack').addClass('playing'); @@ -360,12 +422,12 @@ function playPauseSong() { audio.playPause(); } else { // Start playing song - var play = $('#CurrentPlaylistContainer li.selected'); + var play = $('#CurrentPlaylistContainer tr.selected').first(); if (changeTrack(play)) { $(el).find('img').attr('src', 'images/pause_24x32.png'); $(el).addClass('playing'); } else { - var first = $('#CurrentPlaylistContainer li').first(); + var first = $('#CurrentPlaylistContainer tr').first(); changeTrack(first); } } @@ -373,7 +435,7 @@ function playPauseSong() { function changeTrack(next) { var songid = $(next).attr('childid'); if (songid != undefined) { - if (!next.length) next = $('#CurrentPlaylistContainer li').first(); + if (!next.length) next = $('#CurrentPlaylistContainer tr').first(); //next.addClass('playing').siblings().removeClass('playing'); var albumid = $(next).attr('parentid'); playSong(next, songid, albumid); @@ -383,7 +445,7 @@ function changeTrack(next) { } } function autoPlay() { - var firstsong = $('#CurrentPlaylistContainer li.song:first'); + var firstsong = $('#CurrentPlaylistContainer tr.song:first'); var songid = $(firstsong).attr('childid'); var albumid = $(firstsong).attr('parentid'); playSong(firstsong, songid, albumid); @@ -398,7 +460,9 @@ function search(type, query) { }, success: function (data) { if (data["subsonic-response"].searchResult2 != "") { - $("#AlbumContainer").empty(); + $("#AlbumRows").empty(); + var header = generateSongHeaderHTML(); + $("#AlbumHeader").html(header); // There is a bug in the API that doesn't return a JSON array for one artist var children = []; if (data["subsonic-response"].searchResult2.song.length > 0) { @@ -419,8 +483,8 @@ function search(type, query) { var track; if (child.track === undefined) { track = " "; } else { track = child.track; } var time = secondsToTime(child.duration); - albumhtml = generateSongHTML(rowcolor, child.id, child.parent, track, child.title, child.artist, child.album, child.userRating, time['m'], time['s']); - $(albumhtml).appendTo("#AlbumContainer"); + albumhtml = generateSongHTML(rowcolor, child.id, child.parent, track, child.title, child.artist, child.album, child.coverArt, child.userRating, time['m'], time['s']); + $(albumhtml).appendTo("#AlbumRows"); }); } } @@ -579,7 +643,7 @@ function loadPlaylists(refresh) { html += '
              • '; html += '' + playlist.name + ''; html += '
                '; - html += '
                '; + html += '
                '; html += '
              • '; $(html).appendTo("#PlaylistContainer"); }); @@ -610,7 +674,7 @@ function loadPlaylistsForMenu(menu) { } function newPlaylist() { var reply = prompt("Choose a name for your new playlist.", ""); - if (reply != "") { + if (reply) { $.ajax({ url: baseURL + '/createPlaylist.view?v=1.6.0&c=subweb&f=json&name=' + reply, method: 'GET', @@ -634,7 +698,7 @@ function deletePlaylist(id) { }, success: function (data) { loadPlaylists(true); - $('ul#TrackContainer').empty(); + $('#TrackContainer tbody').empty(); } }); } @@ -642,9 +706,9 @@ function addToPlaylist(playlistid, from) { var selected = []; var el; if (from == 'current') { - el = $('#CurrentPlaylist ul.songlist li.selected'); + el = $('#CurrentPlaylist table.songlist tr.selected'); } else { - el = $('#Albums ul.songlist li.selected'); + el = $('#Albums table.songlist tr.selected'); } el.each(function (index) { selected.push($(this).attr('childid')); @@ -690,7 +754,7 @@ function addToPlaylist(playlistid, from) { req.setRequestHeader('Authorization', auth); }, success: function () { - $('ul.songlist li.song').each(function () { + $('table.songlist tr.song').each(function () { $(this).removeClass('selected'); }); updateMessage('Playlist Updated!'); @@ -709,7 +773,7 @@ function addToPlaylist(playlistid, from) { req.setRequestHeader('Authorization', auth); }, success: function () { - $('ul.songlist li.song').each(function () { + $('table.songlist tr.song').each(function () { $(this).removeClass('selected'); }); updateMessage('Playlist Created!'); @@ -720,15 +784,15 @@ function addToPlaylist(playlistid, from) { } } function addToCurrent() { - var count = $('ul.songlist li.selected').length; - $('ul.songlist li.selected').each(function (index) { - $(this).clone().appendTo('ul#CurrentPlaylistContainer'); + var count = $('table.songlist tr.selected').length; + $('table.songlist tr.selected').each(function (index) { + $(this).clone().appendTo('#CurrentPlaylistContainer tbody'); updateMessage(count + ' Song(s) Added'); }); } function savePlaylist(playlistid) { var songs = []; - $('ul#TrackContainer li.song').each(function (index) { + $('#TrackContainer tr.song').each(function (index) { songs.push($(this).attr('childid')); }); if (songs.length > 0) { @@ -757,8 +821,10 @@ function getPlaylist(id, action, appendto) { }, success: function (data) { if (data["subsonic-response"].playlist.entry != undefined) { - if (appendto == '#TrackContainer') { - $("#TrackContainer").empty(); + if (appendto == '#TrackContainer tbody') { + $(appendto).empty(); + var header = generateSongHeaderHTML(); + $("#TrackContainer thead").html(header); } if (action == 'autoplay') { $(appendto).empty(); @@ -782,14 +848,16 @@ function getPlaylist(id, action, appendto) { var track; if (child.track === undefined) { track = " "; } else { track = child.track; } var time = secondsToTime(child.duration); - html = generateSongHTML(rowcolor, child.id, child.parent, track, child.title, child.artist, child.album, child.userRating, time['m'], time['s']); + html = generateSongHTML(rowcolor, child.id, child.parent, track, child.title, child.artist, child.album, child.coverArt, child.userRating, time['m'], time['s']); $(html).appendTo(appendto); }); if (action == 'autoplay') { autoPlay(); } } else { - //$(appentTo).empty(); + if (appendto == '#TrackContainer tbody') { + $(appendto).empty(); + } } } }); diff --git a/js/jquery.metadata.js b/js/jquery.metadata.js new file mode 100644 index 0000000..6a984db --- /dev/null +++ b/js/jquery.metadata.js @@ -0,0 +1,122 @@ +/* + * Metadata - jQuery plugin for parsing metadata from elements + * + * Copyright (c) 2006 John Resig, Yehuda Katz, J�örn Zaefferer, Paul McLanahan + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Revision: $Id$ + * + */ + +/** + * Sets the type of metadata to use. Metadata is encoded in JSON, and each property + * in the JSON will become a property of the element itself. + * + * There are three supported types of metadata storage: + * + * attr: Inside an attribute. The name parameter indicates *which* attribute. + * + * class: Inside the class attribute, wrapped in curly braces: { } + * + * elem: Inside a child element (e.g. a script tag). The + * name parameter indicates *which* element. + * + * The metadata for an element is loaded the first time the element is accessed via jQuery. + * + * As a result, you can define the metadata type, use $(expr) to load the metadata into the elements + * matched by expr, then redefine the metadata type and run another $(expr) for other elements. + * + * @name $.metadata.setType + * + * @example

                This is a p

                + * @before $.metadata.setType("class") + * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" + * @desc Reads metadata from the class attribute + * + * @example

                This is a p

                + * @before $.metadata.setType("attr", "data") + * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" + * @desc Reads metadata from a "data" attribute + * + * @example

                This is a p

                + * @before $.metadata.setType("elem", "script") + * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" + * @desc Reads metadata from a nested script element + * + * @param String type The encoding type + * @param String name The name of the attribute to be used to get metadata (optional) + * @cat Plugins/Metadata + * @descr Sets the type of encoding to be used when loading metadata for the first time + * @type undefined + * @see metadata() + */ + +(function($) { + +$.extend({ + metadata : { + defaults : { + type: 'class', + name: 'metadata', + cre: /({.*})/, + single: 'metadata' + }, + setType: function( type, name ){ + this.defaults.type = type; + this.defaults.name = name; + }, + get: function( elem, opts ){ + var settings = $.extend({},this.defaults,opts); + // check for empty string in single property + if ( !settings.single.length ) settings.single = 'metadata'; + + var data = $.data(elem, settings.single); + // returned cached data if it already exists + if ( data ) return data; + + data = "{}"; + + if ( settings.type == "class" ) { + var m = settings.cre.exec( elem.className ); + if ( m ) + data = m[1]; + } else if ( settings.type == "elem" ) { + if( !elem.getElementsByTagName ) + return undefined; + var e = elem.getElementsByTagName(settings.name); + if ( e.length ) + data = $.trim(e[0].innerHTML); + } else if ( elem.getAttribute != undefined ) { + var attr = elem.getAttribute( settings.name ); + if ( attr ) + data = attr; + } + + if ( data.indexOf( '{' ) <0 ) + data = "{" + data + "}"; + + data = eval("(" + data + ")"); + + $.data( elem, settings.single, data ); + return data; + } + } +}); + +/** + * Returns the metadata object for the first member of the jQuery object. + * + * @name metadata + * @descr Returns element's metadata object + * @param Object opts An object contianing settings to override the defaults + * @type jQuery + * @cat Plugins/Metadata + */ +$.fn.metadata = function( opts ){ + return $.metadata.get( this[0], opts ); +}; + +})(jQuery); \ No newline at end of file diff --git a/js/jquery.tablesorter.min.js b/js/jquery.tablesorter.min.js new file mode 100644 index 0000000..b8605df --- /dev/null +++ b/js/jquery.tablesorter.min.js @@ -0,0 +1,4 @@ + +(function($){$.extend({tablesorter:new +function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",cssChildRow:"expand-child",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,sortLocaleCompare:true,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'/\.|\,/g',onRenderHeader:null,selectorHeaders:'thead th',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}if(table.tBodies.length==0)return;var rows=table.tBodies[0].rows;if(rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function checkHeaderOptionsSortingLocked(table,i){if((table.config.headers[i])&&(table.config.headers[i].lockedOrder))return table.config.headers[i].lockedOrder;return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i b["+i+"]) ? 1 : 0));";};function makeSortTextDesc(i){return"((b["+i+"] < a["+i+"]) ? -1 : ((b["+i+"] > a["+i+"]) ? 1 : 0));";};function makeSortNumeric(i){return"a["+i+"]-b["+i+"];";};function makeSortNumericDesc(i){return"b["+i+"]-a["+i+"];";};function sortText(a,b){if(table.config.sortLocaleCompare)return a.localeCompare(b);return((ab)?1:0));};function sortTextDesc(a,b){if(table.config.sortLocaleCompare)return b.localeCompare(a);return((ba)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$.data(this,"tablesorter",config);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){$this.trigger("sortStart");var $cell=$(this);var i=this.column;this.order=this.count++%2;if(this.lockedOrder)this.order=this.lockedOrder;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i