diff --git a/htdocs/js/mpd.js b/htdocs/js/mpd.js index 9fcaebb..b76fc39 100644 --- a/htdocs/js/mpd.js +++ b/htdocs/js/mpd.js @@ -367,67 +367,6 @@ function appInit() { toggleBtn(event.target.id); }, false); - var queueBody=document.getElementById('QueueList').getElementsByTagName('tbody')[0]; - queueBody.addEventListener('dragstart', function(event) { - if (event.target.nodeName == 'TR') { - event.target.classList.add('opacity05'); - event.dataTransfer.setDragImage(event.target, 0, 0); - event.dataTransfer.effectAllowed = 'move'; - event.dataTransfer.setData('Text', event.target.getAttribute('id')); - dragEl = event.target.cloneNode(true); - } - }, false); - queueBody.addEventListener('dragleave', function(event) { - event.preventDefault(); - var target = event.target; - if (event.target.nodeName == 'TD') - target = event.target.parentNode; - if (target.nodeName == 'TR') - target.classList.remove('dragover'); - }, false); - queueBody.addEventListener('dragover', function(event) { - event.preventDefault(); - var tr = queueBody.querySelectorAll('.dragover'); - var trLen = tr.length; - for (var i = 0; i < trLen; i++) { - tr[i].classList.remove('dragover'); - } - var target = event.target; - if (event.target.nodeName == 'TD') - target = event.target.parentNode; - if (target.nodeName == 'TR') - target.classList.add('dragover'); - event.dataTransfer.dropEffect = 'move'; - }, false); - queueBody.addEventListener('dragend', function(event) { - var tr = queueBody.querySelectorAll('.dragover'); - var trLen = tr.length; - for (var i = 0; i < trLen; i++) { - tr[i].classList.remove('dragover'); - } - if (document.getElementById(event.dataTransfer.getData('Text'))) - document.getElementById(event.dataTransfer.getData('Text')).classList.remove('opacity05'); - }, false); - queueBody.addEventListener('drop', function(event) { - event.stopPropagation(); - event.preventDefault(); - var target = event.target; - if (event.target.nodeName == 'TD') - target = event.target.parentNode; - var oldSongpos = document.getElementById(event.dataTransfer.getData('Text')).getAttribute('data-songpos'); - var newSongpos = target.getAttribute('data-songpos'); - document.getElementById(event.dataTransfer.getData('Text')).remove(); - dragEl.classList.remove('opacity05'); - queueBody.insertBefore(dragEl, target); - var tr = queueBody.querySelectorAll('.dragover'); - var trLen = tr.length; - for (var i = 0; i < trLen; i++) { - tr[i].classList.remove('dragover'); - } - document.getElementById('QueueList').classList.add('opacity05'); - sendAPI({"cmd": "MPD_API_MOVE_TRACK","data": {"from": oldSongpos, "to": newSongpos}}); - }, false); - document.getElementById('QueueList').addEventListener('click', function(event) { if (event.target.nodeName == 'TD') sendAPI({"cmd": "MPD_API_PLAY_TRACK","data": {"track": event.target.parentNode.getAttribute('data-trackid')}}); @@ -519,6 +458,9 @@ function appInit() { appGoto('Search', undefined, undefined, '0/' + app.current.filter + '/' + this.value); }, false); + dragAndDropTable('QueueList'); + dragAndDropTable('BrowsePlaylistsDetailList'); + window.addEventListener('hashchange', appRoute, false); document.addEventListener('keydown', function(event) { @@ -587,6 +529,77 @@ function appInit() { }); } +function dragAndDropTable(table) { + var tableBody=document.getElementById(table).getElementsByTagName('tbody')[0]; + tableBody.addEventListener('dragstart', function(event) { + if (event.target.nodeName == 'TR') { + event.target.classList.add('opacity05'); + event.dataTransfer.setDragImage(event.target, 0, 0); + event.dataTransfer.effectAllowed = 'move'; + event.dataTransfer.setData('Text', event.target.getAttribute('id')); + dragEl = event.target.cloneNode(true); + } + }, false); + tableBody.addEventListener('dragleave', function(event) { + event.preventDefault(); + var target = event.target; + if (event.target.nodeName == 'TD') + target = event.target.parentNode; + if (target.nodeName == 'TR') + target.classList.remove('dragover'); + }, false); + tableBody.addEventListener('dragover', function(event) { + event.preventDefault(); + var tr = tableBody.querySelectorAll('.dragover'); + var trLen = tr.length; + for (var i = 0; i < trLen; i++) { + tr[i].classList.remove('dragover'); + } + var target = event.target; + if (event.target.nodeName == 'TD') + target = event.target.parentNode; + if (target.nodeName == 'TR') + target.classList.add('dragover'); + event.dataTransfer.dropEffect = 'move'; + }, false); + tableBody.addEventListener('dragend', function(event) { + var tr = tableBody.querySelectorAll('.dragover'); + var trLen = tr.length; + for (var i = 0; i < trLen; i++) { + tr[i].classList.remove('dragover'); + } + if (document.getElementById(event.dataTransfer.getData('Text'))) + document.getElementById(event.dataTransfer.getData('Text')).classList.remove('opacity05'); + }, false); + tableBody.addEventListener('drop', function(event) { + event.stopPropagation(); + event.preventDefault(); + var target = event.target; + if (event.target.nodeName == 'TD') + target = event.target.parentNode; + var oldSongpos = document.getElementById(event.dataTransfer.getData('Text')).getAttribute('data-songpos'); + var newSongpos = target.getAttribute('data-songpos'); + document.getElementById(event.dataTransfer.getData('Text')).remove(); + dragEl.classList.remove('opacity05'); + tableBody.insertBefore(dragEl, target); + var tr = tableBody.querySelectorAll('.dragover'); + var trLen = tr.length; + for (var i = 0; i < trLen; i++) { + tr[i].classList.remove('dragover'); + } + document.getElementById(table).classList.add('opacity05'); + if (app.current.app == 'Queue') + sendAPI({"cmd": "MPD_API_MOVE_TRACK","data": {"from": oldSongpos, "to": newSongpos}}); + else if (app.current.app == 'Browse' && app.current.tab == 'Playlists' && app.current.view == 'Detail') + playlistMoveTrack(oldSongpos, newSongpos); + }, false); +} + +function playlistMoveTrack(from, to) { + sendAPI({"cmd": "MPD_API_PLAYLIST_MOVE_TRACK","data": { "plist": app.current.search, "from": from, "to": to}}); + sendAPI({"cmd": "MPD_API_GET_PLAYLIST_LIST","data": {"offset": app.current.page, "filter": app.current.filter, "uri": app.current.search}}, parsePlaylists); +} + function webSocketConnect() { socket = new WebSocket(getWsUrl()); @@ -1047,18 +1060,20 @@ function parsePlaylists(obj) { else if (app.current.view == 'Detail') { for (var i = 0; i < nrItems; i++) { var uri = encodeURI(obj.data[i].uri); + var songpos = obj.offset + i + 1; if (tr[i]) - if (tr[i].getAttribute('data-uri') == uri) + if (tr[i].getAttribute('data-uri') == uri && tr[i].getAttribute('id') == 'playlistTrackId' + songpos) continue; - var songpos = obj.offset + i; var row = document.createElement('tr'); + row.setAttribute('draggable','true'); + row.setAttribute('id','playlistTrackId' + songpos); row.setAttribute('data-type', obj.data[i].type); row.setAttribute('data-uri', uri); row.setAttribute('data-name', obj.data[i].name); row.setAttribute('data-songpos', songpos); var minutes = Math.floor(obj.data[i].duration / 60); var seconds = obj.data[i].duration - minutes * 60; - row.innerHTML = '' + (songpos + 1) + '' + + row.innerHTML = '' + songpos + '' + '' + obj.data[i].title + '' + '' + obj.data[i].artist + '' + '' + obj.data[i].album + '' + diff --git a/src/mpd_client.c b/src/mpd_client.c index f1f0b8c..302f4f0 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -183,12 +183,27 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) case MPD_API_MOVE_TRACK: je = json_scanf(msg.p, msg.len, "{ data: { from:%u, to:%u } }", &uint_buf1, &uint_buf2); if (je == 2) { - uint_buf1 -= 1; - uint_buf2 -= 1; + uint_buf1 --; + uint_buf2 --; + if (uint_buf1 < uint_buf2) + uint_buf2 --; mpd_run_move(mpd.conn, uint_buf1, uint_buf2); n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); } break; + case MPD_API_PLAYLIST_MOVE_TRACK: + je = json_scanf(msg.p, msg.len, "{ data: { plist: %Q, from:%u, to:%u } }", &p_charbuf1, &uint_buf1, &uint_buf2); + if (je == 3) { + uint_buf1 --; + uint_buf2 --; + if (uint_buf1 < uint_buf2) + uint_buf2 --; + mpd_send_playlist_move(mpd.conn, p_charbuf1, uint_buf1, uint_buf2); + mpd_response_finish(mpd.conn); + free(p_charbuf1); + n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + } + break; case MPD_API_PLAY_TRACK: je = json_scanf(msg.p, msg.len, "{ data: { track:%u } }", &uint_buf1); if (je == 1) { @@ -1170,11 +1185,11 @@ int mympd_put_playlist_list(char *buffer, char *uri, unsigned int offset, char * if (entities_returned ++) len += json_printf(&out,","); len += json_printf(&out, "{type: song, uri: %Q, album: %Q, artist: %Q, duration: %d, title: %Q, name: %Q }", mpd_song_get_uri(song), - mympd_get_tag(song, MPD_TAG_ALBUM), - mympd_get_tag(song, MPD_TAG_ARTIST), - mpd_song_get_duration(song), - entityName, - entityName + mympd_get_tag(song, MPD_TAG_ALBUM), + mympd_get_tag(song, MPD_TAG_ARTIST), + mpd_song_get_duration(song), + entityName, + entityName ); } else { entity_count --; diff --git a/src/mpd_client.h b/src/mpd_client.h index cf97095..15ff7c1 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -55,6 +55,7 @@ X(MPD_API_RM_PLAYLIST_TRACK) \ X(MPD_API_PLAYLIST_CLEAR) \ X(MPD_API_PLAYLIST_RENAME) \ + X(MPD_API_PLAYLIST_MOVE_TRACK) \ X(MPD_API_ADD_TO_PLAYLIST) \ X(MPD_API_PLAY_TRACK) \ X(MPD_API_SAVE_QUEUE) \