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
airtime_mvc
application/controllers
public
css
js/airtime/library

View File

@ -11,6 +11,7 @@ class LibraryController extends Zend_Controller_Action
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('contents', 'json')
->addActionContext('delete', 'json')
->addActionContext('delete-group', 'json')
->addActionContext('context-menu', 'json')
->addActionContext('get-file-meta-data', 'html')
->addActionContext('upload-file-soundcloud', 'json')
@ -178,6 +179,45 @@ class LibraryController extends Zend_Controller_Action
$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()
{

View File

@ -8,18 +8,20 @@ class PlaylistController extends Zend_Controller_Action
{
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('add-item', 'json')
->addActionContext('delete-item', 'json')
->addActionContext('set-fade', 'json')
->addActionContext('set-cue', 'json')
->addActionContext('move-item', 'json')
->addActionContext('close', 'json')
->addActionContext('new', 'json')
->addActionContext('edit', 'json')
->addActionContext('delete-active', 'json')
->addActionContext('delete', 'json')
->addActionContext('delete-item', 'json')
->addActionContext('add-group', 'json')
->addActionContext('delete-group', 'json')
->addActionContext('set-fade', 'json')
->addActionContext('set-cue', 'json')
->addActionContext('move-item', 'json')
->addActionContext('close', 'json')
->addActionContext('new', 'json')
->addActionContext('edit', 'json')
->addActionContext('delete-active', 'json')
->addActionContext('delete', 'json')
->addActionContext('set-playlist-fades', 'json')
->addActionContext('set-playlist-name', 'json')
->addActionContext('set-playlist-description', 'json')
->addActionContext('set-playlist-description', 'json')
->initContext();
$this->pl_sess = new Zend_Session_Namespace(UI_PLAYLIST_SESSNAME);
@ -209,6 +211,59 @@ class PlaylistController extends Zend_Controller_Action
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()
{
$pos = $this->_getParam('pos');

View File

@ -607,10 +607,10 @@ dl.inline-list dd {
}
.dataTables_filter input {
background: url("images/search_auto_bg.png") no-repeat scroll 0 0 #DDDDDD;
width: 60%;
border: 1px solid #5B5B5B;
margin: 0;
padding: 4px 3px 4px 25px;
width: 60%;
border: 1px solid #5B5B5B;
margin-left: -8px;
padding: 4px 3px 4px 25px;
}
.dataTables_length select {
background-color: #DDDDDD;
@ -623,6 +623,15 @@ dl.inline-list dd {
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----*/
fieldset {

View File

@ -1,4 +1,5 @@
var dTable;
var checkedCount = 0;
//used by jjmenu
function getId() {
@ -32,8 +33,20 @@ function deleteAudioClip(json) {
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);
}
function confirmDeleteGroup() {
if(confirm('Are you sure you want to delete the selected items?')){
groupDelete();
}
}
//callbacks called by jjmenu
@ -75,11 +88,17 @@ function checkImportStatus(){
function deletePlaylist(json) {
if(json.message) {
alert(json.message);
return;
alert(json.message);
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();
}
//end callbacks called by jjmenu
@ -92,7 +111,7 @@ function addLibraryItemEvents() {
cursor: 'pointer'
});
$('#library_display tbody tr td').not('[class=datatable_checkbox]')
$('#library_display tbody tr td').not('[class=library_checkbox]')
.jjmenu("click",
[{get:"/Library/context-menu/format/json/id/#id#/type/#type#"}],
{id: getId, type: getType},
@ -105,36 +124,34 @@ function dtRowCallback( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
type = aData["ftype"].substring(0,2);
id = aData["id"];
if(type == "au") {
$('td:eq(6)', nRow).html( '<img src="css/images/icon_audioclip.png">' );
}
else if(type == "pl") {
$('td:eq(6)', nRow).html( '<img src="css/images/icon_playlist.png">' );
$('td.library_type', nRow).html( '<img src="css/images/icon_audioclip.png">' );
} else if(type == "pl") {
$('td.library_type', nRow).html( '<img src="css/images/icon_playlist.png">' );
}
$(nRow).attr("id", type+'_'+id);
$(nRow).attr("id", type+'_'+id);
// insert id on lenth field
$('td:eq(5)', nRow).attr("id", "length");
// insert id on lenth field
$('td.library_length', nRow).attr("id", "length");
return nRow;
return nRow;
}
function dtDrawCallback() {
addLibraryItemEvents();
addMetadataQtip();
saveNumEntriesSetting();
var temp = dTable.fnGetData()
console.log(temp)
addLibraryItemEvents();
addMetadataQtip();
saveNumEntriesSetting();
setupGroupActions();
}
function addProgressIcon(id) {
if($("#au_"+id).find("td:eq(0)").find("span").length > 0){
$("#au_"+id).find("td:eq(0)").find("span").removeClass();
if($("#au_"+id).find("td.library_title").find("span").length > 0){
$("#au_"+id).find("td.library_title").find("span").removeClass();
$("span[id="+id+"]").addClass("small-icon progress");
}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(){
var tableRow = $('#library_display tbody tr');
tableRow.each(function(){
var title = $(this).find('td:eq(0)').html()
var title = $(this).find('td.library_title').html()
var info = $(this).attr("id")
info = info.split("_");
var id = info[1];
@ -301,6 +318,133 @@ function getNumEntriesPreference(data) {
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) {
dTable = $('#library_display').dataTable( {
"bProcessing": true,
@ -318,14 +462,14 @@ function createDataTable(data) {
"fnRowCallback": dtRowCallback,
"fnDrawCallback": dtDrawCallback,
"aoColumns": [
/* Checkbox */ { "sTitle": "<input type='checkbox' name='cb_all'>", "bSortable": false, "bSearchable": false, "mDataProp": "checkbox", "sWidth": "25px", "sClass": "datatable_checkbox" },
/* Id */ { "sName": "id", "bSearchable": false, "bVisible": false, "mDataProp": "id" },
/* Title */ { "sTitle": "Title", "sName": "track_title", "mDataProp": "track_title" },
/* Creator */ { "sTitle": "Creator", "sName": "artist_name", "mDataProp": "artist_name" },
/* Album */ { "sTitle": "Album", "sName": "album_title", "mDataProp": "album_title" },
/* Genre */ { "sTitle": "Genre", "sName": "genre", "mDataProp": "genre" },
/* Length */ { "sTitle": "Length", "sName": "length", "mDataProp": "length" },
/* Type */ { "sTitle": "Type", "sName": "ftype", "bSearchable": false, "mDataProp": "ftype", "sWidth": "50px" },
/* 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", "sClass": "library_id"},
/* Title */ { "sTitle": "Title", "sName": "track_title", "mDataProp": "track_title", "sClass": "library_title"},
/* Creator */ { "sTitle": "Creator", "sName": "artist_name", "mDataProp": "artist_name", "sClass": "library_creator"},
/* Album */ { "sTitle": "Album", "sName": "album_title", "mDataProp": "album_title", "sClass": "library_album"},
/* Genre */ { "sTitle": "Genre", "sName": "genre", "mDataProp": "genre", "sClass": "library_genre"},
/* Length */ { "sTitle": "Length", "sName": "length", "mDataProp": "length", "sWidth": "15%", "sClass": "library_length"},
/* Type */ { "sTitle": "Type", "sName": "ftype", "bSearchable": false, "mDataProp": "ftype", "sWidth": "7%", "sClass": "library_type"},
],
"aaSorting": [[2,'asc']],
"sPaginationType": "full_numbers",
@ -335,9 +479,16 @@ function createDataTable(data) {
"sSearch": ""
},
"iDisplayLength": getNumEntriesPreference(data),
"bStateSave": true
"bStateSave": true,
"sDom": 'lfr<"H"C<"library_toolbar">>t<"F"ip>'
});
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() {
@ -346,7 +497,7 @@ $(document).ready(function() {
$.ajax({ url: "/Api/library-init/format/json", dataType:"json", success:createDataTable,
error:function(jqXHR, textStatus, errorThrown){}});
checkImportStatus()
checkImportStatus();
setInterval( "checkImportStatus()", 5000 );
setInterval( "checkSCUploadStatus()", 5000 );