CC-1977: Allow multiple files to be selected and acted upon in the library and playlist

- Added checkbox column to playlist builder
- Added the ability to add multiple songs to playlist by using checkboxes and "Add" button
- Added the ability to delete multiple songs/playlists by using checkboxes and "Delete" button
- Make them look nice by adjusting CSS and datatable
This commit is contained in:
Yuchen Wang 2012-01-07 23:37:37 -05:00
parent f025dccc4f
commit 8833f4462e
4 changed files with 303 additions and 48 deletions

View File

@ -11,6 +11,7 @@ class LibraryController extends Zend_Controller_Action
$ajaxContext = $this->_helper->getHelper('AjaxContext'); $ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('contents', 'json') $ajaxContext->addActionContext('contents', 'json')
->addActionContext('delete', 'json') ->addActionContext('delete', 'json')
->addActionContext('delete-group', 'json')
->addActionContext('context-menu', 'json') ->addActionContext('context-menu', 'json')
->addActionContext('get-file-meta-data', 'html') ->addActionContext('get-file-meta-data', 'html')
->addActionContext('upload-file-soundcloud', 'json') ->addActionContext('upload-file-soundcloud', 'json')
@ -178,6 +179,45 @@ class LibraryController extends Zend_Controller_Action
$this->view->id = $id; $this->view->id = $id;
} }
} }
public function deleteGroupAction()
{
$ids = $this->_getParam('ids');
$userInfo = Zend_Auth::getInstance()->getStorage()->read();
$user = new Application_Model_User($userInfo->id);
if ($user->isAdmin()) {
if (!is_null($ids)) {
foreach ($ids as $key => $id) {
$file = Application_Model_StoredFile::Recall($id);
if (PEAR::isError($file)) {
$this->view->message = $file->getMessage();
return;
}
else if(is_null($file)) {
$this->view->message = "file doesn't exist";
return;
}
$res = $file->delete();
if (PEAR::isError($res)) {
$this->view->message = $res->getMessage();
return;
}
else {
$res = settype($res, "integer");
$data = array("filepath" => $file->getFilePath(), "delete" => $res);
Application_Model_RabbitMq::SendMessageToMediaMonitor("file_delete", $data);
}
}
$this->view->ids = $ids;
}
}
}
public function contentsAction() public function contentsAction()
{ {

View File

@ -8,18 +8,20 @@ class PlaylistController extends Zend_Controller_Action
{ {
$ajaxContext = $this->_helper->getHelper('AjaxContext'); $ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('add-item', 'json') $ajaxContext->addActionContext('add-item', 'json')
->addActionContext('delete-item', 'json') ->addActionContext('delete-item', 'json')
->addActionContext('set-fade', 'json') ->addActionContext('add-group', 'json')
->addActionContext('set-cue', 'json') ->addActionContext('delete-group', 'json')
->addActionContext('move-item', 'json') ->addActionContext('set-fade', 'json')
->addActionContext('close', 'json') ->addActionContext('set-cue', 'json')
->addActionContext('new', 'json') ->addActionContext('move-item', 'json')
->addActionContext('edit', 'json') ->addActionContext('close', 'json')
->addActionContext('delete-active', 'json') ->addActionContext('new', 'json')
->addActionContext('delete', 'json') ->addActionContext('edit', 'json')
->addActionContext('delete-active', 'json')
->addActionContext('delete', 'json')
->addActionContext('set-playlist-fades', 'json') ->addActionContext('set-playlist-fades', 'json')
->addActionContext('set-playlist-name', 'json') ->addActionContext('set-playlist-name', 'json')
->addActionContext('set-playlist-description', 'json') ->addActionContext('set-playlist-description', 'json')
->initContext(); ->initContext();
$this->pl_sess = new Zend_Session_Namespace(UI_PLAYLIST_SESSNAME); $this->pl_sess = new Zend_Session_Namespace(UI_PLAYLIST_SESSNAME);
@ -209,6 +211,59 @@ class PlaylistController extends Zend_Controller_Action
unset($this->view->pl); unset($this->view->pl);
} }
public function addGroupAction()
{
$ids = $this->_getParam('ids');
$pos = $this->_getParam('pos', null);
if (!is_null($ids)) {
$pl = $this->getPlaylist();
if ($pl === false) {
$this->view->playlist_error = true;
return false;
}
foreach ($ids as $key => $value) {
$res = $pl->addAudioClip($value);
if (PEAR::isError($res)) {
$this->view->message = $res->getMessage();
break;
}
}
$this->view->pl = $pl;
$this->view->html = $this->view->render('playlist/update.phtml');
$this->view->name = $pl->getName();
$this->view->length = $pl->getLength();
$this->view->description = $pl->getDescription();
return;
}
$this->view->message = "a file is not chosen";
}
public function deleteGroupAction()
{
$ids = $this->_getParam('ids', null);
foreach ($ids as $key => $id) {
$pl = Application_Model_Playlist::Recall($id);
if ($pl !== FALSE) {
Application_Model_Playlist::Delete($id);
$pl_sess = $this->pl_sess;
if($pl_sess->id === $id){
unset($pl_sess->id);
}
} else {
$this->view->playlist_error = true;
return false;
}
}
$this->view->ids = $ids;
$this->view->html = $this->view->render('playlist/index.phtml');
}
public function setCueAction() public function setCueAction()
{ {
$pos = $this->_getParam('pos'); $pos = $this->_getParam('pos');

View File

@ -607,10 +607,10 @@ dl.inline-list dd {
} }
.dataTables_filter input { .dataTables_filter input {
background: url("images/search_auto_bg.png") no-repeat scroll 0 0 #DDDDDD; background: url("images/search_auto_bg.png") no-repeat scroll 0 0 #DDDDDD;
width: 60%; width: 60%;
border: 1px solid #5B5B5B; border: 1px solid #5B5B5B;
margin: 0; margin-left: -8px;
padding: 4px 3px 4px 25px; padding: 4px 3px 4px 25px;
} }
.dataTables_length select { .dataTables_length select {
background-color: #DDDDDD; background-color: #DDDDDD;
@ -623,6 +623,15 @@ dl.inline-list dd {
vertical-align: top; vertical-align: top;
} }
.library_toolbar .ui-button {
float: right;
text-align:center;
font-size:12px;
font-weight:normal;
padding: 0.2em 1em;
margin: 0.5em 0.2em;
}
/*----END Data Table----*/ /*----END Data Table----*/
fieldset { fieldset {

View File

@ -1,4 +1,5 @@
var dTable; var dTable;
var checkedCount = 0;
//used by jjmenu //used by jjmenu
function getId() { function getId() {
@ -32,8 +33,20 @@ function deleteAudioClip(json) {
return; return;
} }
deleteItem("au", json.id); if (json.ids != undefined) {
for (var i = json.ids.length - 1; i >= 0; i--) {
deleteItem("au", json.ids[i]);
}
} else if (json.id != undefined) {
deleteItem("au", json.id);
}
location.reload(true); location.reload(true);
}
function confirmDeleteGroup() {
if(confirm('Are you sure you want to delete the selected items?')){
groupDelete();
}
} }
//callbacks called by jjmenu //callbacks called by jjmenu
@ -75,11 +88,17 @@ function checkImportStatus(){
function deletePlaylist(json) { function deletePlaylist(json) {
if(json.message) { if(json.message) {
alert(json.message); alert(json.message);
return; return;
} }
deleteItem("pl", json.id); if (json.ids != undefined) {
for (var i = json.ids.length - 1; i >= 0; i--) {
deleteItem("pl", json.ids[i]);
}
} else if (json.id != undefined) {
deleteItem("pl", json.id);
}
window.location.reload(); window.location.reload();
} }
//end callbacks called by jjmenu //end callbacks called by jjmenu
@ -92,7 +111,7 @@ function addLibraryItemEvents() {
cursor: 'pointer' cursor: 'pointer'
}); });
$('#library_display tbody tr td').not('[class=datatable_checkbox]') $('#library_display tbody tr td').not('[class=library_checkbox]')
.jjmenu("click", .jjmenu("click",
[{get:"/Library/context-menu/format/json/id/#id#/type/#type#"}], [{get:"/Library/context-menu/format/json/id/#id#/type/#type#"}],
{id: getId, type: getType}, {id: getId, type: getType},
@ -105,36 +124,34 @@ function dtRowCallback( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
type = aData["ftype"].substring(0,2); type = aData["ftype"].substring(0,2);
id = aData["id"]; id = aData["id"];
if(type == "au") { if(type == "au") {
$('td:eq(6)', nRow).html( '<img src="css/images/icon_audioclip.png">' ); $('td.library_type', nRow).html( '<img src="css/images/icon_audioclip.png">' );
} } else if(type == "pl") {
else if(type == "pl") { $('td.library_type', nRow).html( '<img src="css/images/icon_playlist.png">' );
$('td:eq(6)', nRow).html( '<img src="css/images/icon_playlist.png">' );
} }
$(nRow).attr("id", type+'_'+id); $(nRow).attr("id", type+'_'+id);
// insert id on lenth field // insert id on lenth field
$('td:eq(5)', nRow).attr("id", "length"); $('td.library_length', nRow).attr("id", "length");
return nRow; return nRow;
} }
function dtDrawCallback() { function dtDrawCallback() {
addLibraryItemEvents(); addLibraryItemEvents();
addMetadataQtip(); addMetadataQtip();
saveNumEntriesSetting(); saveNumEntriesSetting();
var temp = dTable.fnGetData() setupGroupActions();
console.log(temp)
} }
function addProgressIcon(id) { function addProgressIcon(id) {
if($("#au_"+id).find("td:eq(0)").find("span").length > 0){ if($("#au_"+id).find("td.library_title").find("span").length > 0){
$("#au_"+id).find("td:eq(0)").find("span").removeClass(); $("#au_"+id).find("td.library_title").find("span").removeClass();
$("span[id="+id+"]").addClass("small-icon progress"); $("span[id="+id+"]").addClass("small-icon progress");
}else{ }else{
$("#au_"+id).find("td:eq(0)").append('<span id="'+id+'" class="small-icon progress"></span>') $("#au_"+id).find("td.library_title").append('<span id="'+id+'" class="small-icon progress"></span>')
} }
} }
@ -233,7 +250,7 @@ function addQtipToSCIcons(){
function addMetadataQtip(){ function addMetadataQtip(){
var tableRow = $('#library_display tbody tr'); var tableRow = $('#library_display tbody tr');
tableRow.each(function(){ tableRow.each(function(){
var title = $(this).find('td:eq(0)').html() var title = $(this).find('td.library_title').html()
var info = $(this).attr("id") var info = $(this).attr("id")
info = info.split("_"); info = info.split("_");
var id = info[1]; var id = info[1];
@ -301,6 +318,133 @@ function getNumEntriesPreference(data) {
return parseInt(data.libraryInit.numEntries); return parseInt(data.libraryInit.numEntries);
} }
function groupAdd() {
var ids = new Array();
var addGroupUrl = '/Playlist/add-group';
var newSPLUrl = '/Playlist/new/format/json';
var dirty = true;
$('#library_display tbody tr').each(function() {
var idSplit = $(this).attr('id').split("_");
var id = idSplit.pop();
var type = idSplit.pop();
if (dirty && $(this).find(":checkbox").attr("checked")) {
if (type == "au") {
ids.push(id);
} else if (type == "pl") {
alert("Can't add playlist to another playlist");
dirty = false;
}
}
});
if (dirty && ids.length > 0) {
stopAudioPreview();
if ($('#spl_sortable').length == 0) {
$.post(newSPLUrl, function(json) {
openDiffSPL(json);
redrawDataTablePage();
$.post(addGroupUrl, {format: "json", ids: ids}, setSPLContent);
});
} else {
$.post(addGroupUrl, {format: "json", ids: ids}, setSPLContent);
}
}
}
function groupDelete() {
var auIds = new Array();
var plIds = new Array();
var auUrl = '/Library/delete-group';
var plUrl = '/Playlist/delete-group';
var dirty = true;
$('#library_display tbody tr').each(function() {
var idSplit = $(this).attr('id').split("_");
var id = idSplit.pop();
var type = idSplit.pop();
if (dirty && $(this).find(":checkbox").attr("checked")) {
if (type == "au") {
auIds.push(id);
} else if (type == "pl") {
plIds.push(id);
}
}
});
if (dirty && (auIds.length > 0 || plIds.length > 0)) {
stopAudioPreview();
if (auIds.length > 0) {
$.post(auUrl, {format: "json", ids: auIds}, deleteAudioClip);
}
if (plIds.length > 0) {
$.post(plUrl, {format: "json", ids: plIds}, deletePlaylist);
}
}
}
function toggleAll() {
var checked = $(this).attr("checked");
$('#library_display tr').each(function() {
$(this).find(":checkbox").attr("checked", checked);
if (checked) {
$(this).addClass('selected');
} else {
$(this).removeClass('selected');
}
});
if (checked) {
checkedCount = $('#library_display tbody tr').size();
} else {
checkedCount = 0;
}
}
function checkBoxChanged() {
var cbAll = $('#library_display thead').find(":checkbox");
var cbAllChecked = cbAll.attr("checked");
var checked = $(this).attr("checked");
var size = $('#library_display tbody tr').size();
if (checked) {
if (checkedCount < size) {
checkedCount++;
}
$(this).parent().parent().addClass('selected');
} else {
if (!checked && checkedCount > 0) {
checkedCount--;
}
$(this).parent().parent().removeClass('selected');
}
if (cbAllChecked && checkedCount < size) {
cbAll.attr("checked", false);
} else if (!cbAllChecked && checkedCount == size) {
cbAll.attr("checked", true);
}
}
function setupGroupActions() {
checkedCount = 0;
$('#library_display tr:nth-child(1)').find(":checkbox").attr("checked", false);
$('#library_display thead').find(":checkbox").change(toggleAll);
$('#library_display tbody tr').each(function() {
$(this).find(":checkbox").change(checkBoxChanged);
});
}
function fnShowHide(iCol) {
/* Get the DataTables object again - this is not a recreation, just a get of the object */
var oTable = dTable;
var bVis = oTable.fnSettings().aoColumns[iCol].bVisible;
oTable.fnSetColumnVis( iCol, bVis ? false : true );
}
function createDataTable(data) { function createDataTable(data) {
dTable = $('#library_display').dataTable( { dTable = $('#library_display').dataTable( {
"bProcessing": true, "bProcessing": true,
@ -318,14 +462,14 @@ function createDataTable(data) {
"fnRowCallback": dtRowCallback, "fnRowCallback": dtRowCallback,
"fnDrawCallback": dtDrawCallback, "fnDrawCallback": dtDrawCallback,
"aoColumns": [ "aoColumns": [
/* Checkbox */ { "sTitle": "<input type='checkbox' name='cb_all'>", "bSortable": false, "bSearchable": false, "mDataProp": "checkbox", "sWidth": "25px", "sClass": "datatable_checkbox" }, /* Checkbox */ { "sTitle": "<input type='checkbox' name='cb_all'>", "bSortable": false, "bSearchable": false, "mDataProp": "checkbox", "sWidth": "25px", "sClass": "library_checkbox"},
/* Id */ { "sName": "id", "bSearchable": false, "bVisible": false, "mDataProp": "id" }, /* Id */ { "sName": "id", "bSearchable": false, "bVisible": false, "mDataProp": "id", "sClass": "library_id"},
/* Title */ { "sTitle": "Title", "sName": "track_title", "mDataProp": "track_title" }, /* Title */ { "sTitle": "Title", "sName": "track_title", "mDataProp": "track_title", "sClass": "library_title"},
/* Creator */ { "sTitle": "Creator", "sName": "artist_name", "mDataProp": "artist_name" }, /* Creator */ { "sTitle": "Creator", "sName": "artist_name", "mDataProp": "artist_name", "sClass": "library_creator"},
/* Album */ { "sTitle": "Album", "sName": "album_title", "mDataProp": "album_title" }, /* Album */ { "sTitle": "Album", "sName": "album_title", "mDataProp": "album_title", "sClass": "library_album"},
/* Genre */ { "sTitle": "Genre", "sName": "genre", "mDataProp": "genre" }, /* Genre */ { "sTitle": "Genre", "sName": "genre", "mDataProp": "genre", "sClass": "library_genre"},
/* Length */ { "sTitle": "Length", "sName": "length", "mDataProp": "length" }, /* Length */ { "sTitle": "Length", "sName": "length", "mDataProp": "length", "sWidth": "15%", "sClass": "library_length"},
/* Type */ { "sTitle": "Type", "sName": "ftype", "bSearchable": false, "mDataProp": "ftype", "sWidth": "50px" }, /* Type */ { "sTitle": "Type", "sName": "ftype", "bSearchable": false, "mDataProp": "ftype", "sWidth": "7%", "sClass": "library_type"},
], ],
"aaSorting": [[2,'asc']], "aaSorting": [[2,'asc']],
"sPaginationType": "full_numbers", "sPaginationType": "full_numbers",
@ -335,9 +479,16 @@ function createDataTable(data) {
"sSearch": "" "sSearch": ""
}, },
"iDisplayLength": getNumEntriesPreference(data), "iDisplayLength": getNumEntriesPreference(data),
"bStateSave": true "bStateSave": true,
"sDom": 'lfr<"H"C<"library_toolbar">>t<"F"ip>'
}); });
dTable.fnSetFilteringDelay(350); dTable.fnSetFilteringDelay(350);
$("div.library_toolbar").html('<span class="fg-button ui-button ui-state-default" id="library_group_delete">Delete</span>' +
'<span class="fg-button ui-button ui-state-default" id="library_group_add">Add</span>');
$('#library_group_add').click(groupAdd);
$('#library_group_delete').click(confirmDeleteGroup);
} }
$(document).ready(function() { $(document).ready(function() {
@ -346,7 +497,7 @@ $(document).ready(function() {
$.ajax({ url: "/Api/library-init/format/json", dataType:"json", success:createDataTable, $.ajax({ url: "/Api/library-init/format/json", dataType:"json", success:createDataTable,
error:function(jqXHR, textStatus, errorThrown){}}); error:function(jqXHR, textStatus, errorThrown){}});
checkImportStatus() checkImportStatus();
setInterval( "checkImportStatus()", 5000 ); setInterval( "checkImportStatus()", 5000 );
setInterval( "checkSCUploadStatus()", 5000 ); setInterval( "checkSCUploadStatus()", 5000 );