Use proper Vue components and methods for selection

This commit is contained in:
An Phan 2016-01-17 17:59:58 +08:00
parent f3355746cd
commit adc77e882f
3 changed files with 67 additions and 46 deletions

View file

@ -26,6 +26,7 @@
data() {
return {
playbackState: 'stopped',
selected: false,
};
},
@ -57,6 +58,21 @@
break;
}
},
/**
* Toggle the "selected" state of the current component.
*/
toggleSelectedState() {
this.selected = !this.selected;
},
select() {
this.selected = true;
},
deselect() {
this.selected = false;
}
},
events: {

View file

@ -39,14 +39,15 @@
| limitBy numOfItems"
is="song-item"
data-song-id="{{ item.id }}"
track-by="$index"
track-by="id"
:song="item"
@click="rowClick"
v-ref:rows
@click="rowClick(item.id, $event)"
draggable="true"
@dragstart="dragStart"
@dragleave="removeDroppableState"
@dragover.prevent="allowDrop"
@drop.stop.prevent="handleDrop"
@dragstart="dragStart(item.id, $event)"
@dragleave="removeDroppableState(item.id, $event)"
@dragover.prevent="allowDrop(item.id, $event)"
@drop.stop.prevent="handleDrop(item.id, $event)"
>
</tr>
</tbody>
@ -79,6 +80,7 @@
q: '', // The filter query
sortKey: 'title',
order: 1,
componentCache: {},
};
},
@ -203,6 +205,22 @@
this.clearSelection();
},
/**
* Get the song-item component that's associated with a song ID.
*
* @param {string} id The song ID.
*
* @return {Object} The Vue compoenent
*/
getComponentBySongId(id) {
// A Vue component can be removed (as a result of filter for example), so we check for its $el as well.
if (!this.componentCache[id] || !this.componentCache[id].$el) {
this.componentCache[id] = _.find(this.$refs.rows, { song: { id } });
}
return this.componentCache[id];
},
/**
* Capture A keydown event and select all if applicable.
*
@ -213,7 +231,7 @@
return;
}
$(this.$els.wrapper).find('.song-item').addClass('selected');
_.invoke(this.$refs.rows, 'select');
this.gatherSelected();
},
@ -223,7 +241,8 @@
* @return {Array} An array of Song objects
*/
gatherSelected() {
var ids = _.map($(this.$els.wrapper).find('.song-item.selected'), row => $(row).data('song-id'));
var selectedRows = _.where(this.$refs.rows, { selected: true });
var ids = _.map(selectedRows, row => row.song.id);
this.selectedSongs = songStore.byIds(ids);
},
@ -238,15 +257,14 @@
* -----------------------------------------------------------
*/
rowClick(e) {
var $target = $(e.target);
var row = $target.is('tr') ? $target[0] : $target.parents('tr')[0];
rowClick(songId, e) {
var row = this.getComponentBySongId(songId);
// If we're on a touch device, just toggle selection.
// If we're on a touch device, or if Ctrl/Cmd key is pressed, just toggle selection.
if (isMobile.any) {
this.toggleRow(row);
this.gatherSelected();
return;
}
@ -260,8 +278,8 @@
this.toggleRow(row);
}
if (e.shiftKey && this.lastSelectedRow) {
this.selectRowsBetweenIndexes([this.lastSelectedRow.rowIndex, row.rowIndex])
if (e.shiftKey && this.lastSelectedRow && this.lastSelectedRow.$el) {
this.selectRowsBetweenIndexes([this.lastSelectedRow.$el.rowIndex, row.$el.rowIndex]);
}
}
@ -271,26 +289,26 @@
/**
* Toggle select/unslect a row.
*
* @param {Object} row The row DOM.
* @param {Object} row The song-item component
*/
toggleRow(row) {
$(row).toggleClass('selected');
row.toggleSelectedState();
this.lastSelectedRow = row;
},
selectRowsBetweenIndexes(indexes) {
indexes.sort((a, b) => a - b);
var rows = $(this.lastSelectedRow).parents('tbody').find('tr');
var rows = $(this.$els.wrapper).find('tbody tr');
for (var i = indexes[0]; i <= indexes[1]; ++i) {
$(rows[i-1]).addClass('selected');
this.getComponentBySongId($(rows[i-1]).data('song-id')).select();
}
},
clearSelection() {
this.selectedSongs = [];
$(this.$els.wrapper).find('.song-item.selected').removeClass('selected');
_.invoke(this.$refs.rows, 'deselect');
this.gatherSelected();
},
/**
@ -300,10 +318,9 @@
*
* @param {Object} e The event.
*/
dragStart(e) {
dragStart(songId, e) {
// Select the current target as well.
$(e.target).addClass('selected');
this.getComponentBySongId(songId).select();
this.gatherSelected();
// We can opt for something like application/x-koel.text+plain here to sound fancy,
@ -322,7 +339,7 @@
*
* @param {Object} e The dragover event.
*/
allowDrop(e) {
allowDrop(songId, e) {
if (this.type !== 'queue') {
return;
}
@ -333,7 +350,7 @@
return false;
},
handleDrop(e) {
handleDrop(songId, e) {
if (this.type !== 'queue') {
return;
}
@ -350,34 +367,17 @@
var $row = this.removeDroppableState(e);
queueStore.move(songs, songStore.byId($row.data('song-id')));
queueStore.move(songs, songStore.byId(songId));
return false;
},
removeDroppableState(e) {
removeDroppableState(songId, e) {
return $(e.target).parents('tr').removeClass('droppable');
},
},
events: {
/**
* Listen to queue:select-rows event and mark a range of song-item rows as selected
*
* @param {Array} range An array in the format of [startIndex, stopIndex]
*/
'queue:select-rows': function (range) {
if (this.type != 'queue') {
return;
}
var rows = $(this.$els.wrapper).find('.song-item');
for (i = range[0]; i <= range[1]; ++i) {
$(rows[i]).addClass('selected');
}
},
/**
* Listen to song:played event to do some logic.
*

View file

@ -79,8 +79,13 @@ export default {
* @param {?Function} cb
*/
addSongs(playlist, songs, cb = null) {
var count = playlist.songs.length;
playlist.songs = _.union(playlist.songs, songs);
if (count === playlist.songs.length) {
return;
}
http.put(`playlist/${playlist.id}/sync`, { songs: _.pluck(playlist.songs, 'id') }, () => {
if (cb) {
cb();