diff --git a/airtime_mvc/application/controllers/LibraryController.php b/airtime_mvc/application/controllers/LibraryController.php index da0f10e1b..3c07bc235 100644 --- a/airtime_mvc/application/controllers/LibraryController.php +++ b/airtime_mvc/application/controllers/LibraryController.php @@ -231,13 +231,13 @@ class LibraryController extends Zend_Controller_Action $id = $this->_getParam('id'); $type = $this->_getParam('type'); - if($type == "audioclip") { + if ($type == "audioclip") { $file = Application_Model_StoredFile::Recall($id); $this->view->type = $type; $this->view->md = $file->getMetadata(); } - else if($type == "playlist") { - $file = Application_Model_Playlist::Recall($id); + else if ($type == "playlist") { + $file = new Application_Model_Playlist($id); $this->view->type = $type; $this->view->md = $file->getAllPLMetaData(); $this->view->contents = $file->getContents(); diff --git a/airtime_mvc/application/controllers/PlaylistController.php b/airtime_mvc/application/controllers/PlaylistController.php index b005f709a..fa2918d32 100644 --- a/airtime_mvc/application/controllers/PlaylistController.php +++ b/airtime_mvc/application/controllers/PlaylistController.php @@ -8,7 +8,6 @@ class PlaylistController extends Zend_Controller_Action { $ajaxContext = $this->_helper->getHelper('AjaxContext'); $ajaxContext->addActionContext('add-items', 'json') - ->addActionContext('add-item', 'json') ->addActionContext('move-item', 'json') ->addActionContext('delete-item', 'json') ->addActionContext('set-fade', 'json') @@ -26,31 +25,17 @@ class PlaylistController extends Zend_Controller_Action private function getPlaylist() { - $pl_sess = $this->pl_sess; + $pl = null; - if(isset($pl_sess->id)) { - - $pl = Application_Model_Playlist::Recall($pl_sess->id); - if($pl === FALSE) { - unset($pl_sess->id); - return false; - } - return $pl; - }else{ - return false; + if (isset($this->pl_sess->id)) { + $pl = new Application_Model_Playlist($this->pl_sess->id); } + return $pl; } private function changePlaylist($pl_id) { - $pl_sess = $this->pl_sess; - - $pl = Application_Model_Playlist::Recall($pl_id); - if($pl === FALSE) { - return FALSE; - } - - $pl_sess->id = $pl_id; + $this->pl_sess->id = intval($pl_id); } private function createUpdateResponse($pl) @@ -68,7 +53,7 @@ class PlaylistController extends Zend_Controller_Action { if (isset($pl)) { $this->view->pl = $pl; - $this->view->pl_id = $pl->getId(); + $this->view->id = $pl->getId(); $this->view->html = $this->view->render('playlist/index.phtml'); unset($this->view->pl); } @@ -86,10 +71,21 @@ class PlaylistController extends Zend_Controller_Action $this->view->headLink()->appendStylesheet($baseUrl.'/css/playlist_builder.css'); $this->_helper->viewRenderer->setResponseSegment('spl'); - $pl = $this->getPlaylist(); - if($pl !== false){ - $this->view->pl = $pl; - } + + try { + $pl = $this->getPlaylist(); + + if (isset($pl)) { + $this->view->pl = $pl; + } + } + catch (PlaylistNotFoundException $e) { + Logging::log("Playlist not found"); + $this->changePlaylist(null); + } + catch (Exception $e) { + Logging::log("{$e->getMessage()}"); + } } public function newAction() @@ -98,11 +94,10 @@ class PlaylistController extends Zend_Controller_Action $userInfo = Zend_Auth::getInstance()->getStorage()->read(); $pl = new Application_Model_Playlist(); - $pl->create("Untitled Playlist"); + $pl->setName("Untitled Playlist"); $pl->setPLMetaData('dc:creator', $userInfo->login); $this->changePlaylist($pl->getId()); - $this->createFullResponse($pl); } @@ -110,134 +105,128 @@ class PlaylistController extends Zend_Controller_Action { $pl_id = $this->_getParam('id', null); - if(!is_null($pl_id)) { + if (!is_null($pl_id)) { $this->changePlaylist($pl_id); } - $pl = $this->getPlaylist(); - if($pl === false){ - $this->view->playlist_error = true; - return false; - } + try { + $pl = $this->getPlaylist(); + } + catch (PlaylistNotFoundException $e) { + Logging::log("Playlist {$pl_id} not found"); + $this->changePlaylist(null); + } + catch (Exception $e) { + Logging::log("{$e->getFile()}"); + Logging::log("{$e->getLine()}"); + Logging::log("{$e->getMessage()}"); + $this->changePlaylist(null); + } $this->createFullResponse($pl); } - public function addItemAction() + public function deleteAction() { - $id = $this->_getParam('id'); - $pos = $this->_getParam('pos', null); + $ids = $this->_getParam('ids'); + $ids = (!is_array($ids)) ? array($ids) : $ids; + $pl = null; - if (!is_null($id)) { + try { - $pl = $this->getPlaylist(); - if($pl === false){ - $this->view->playlist_error = true; - return false; + Logging::log("Currently active playlist {$this->pl_sess->id}"); + if (in_array($this->pl_sess->id, $ids)) { + Logging::log("Deleting currently active playlist"); + $this->changePlaylist(null); + } + else { + $pl = $this->getPlaylist(); + Logging::log("Not deleting currently active playlist"); } - $res = $pl->addAudioClip($id, $pos); - if (PEAR::isError($res)) { - $this->view->message = $res->getMessage(); - } - - $this->createUpdateResponse($pl); - return; - } - $this->view->message = "a file is not chosen"; - } - - public function moveItemAction() - { - $oldPos = $this->_getParam('oldPos'); - $newPos = $this->_getParam('newPos'); - - $pl = $this->getPlaylist(); - if($pl === false){ - $this->view->playlist_error = true; - return false; + Application_Model_Playlist::DeletePlaylists($ids); + } + catch(PlaylistNotFoundException $e) { + Logging::log("Playlist not found"); + $this->changePlaylist(null); + $pl = null; + } + catch(Exception $e) { + Logging::log("{$e->getFile()}"); + Logging::log("{$e->getLine()}"); + Logging::log("{$e->getMessage()}"); } - $pl->moveAudioClip($oldPos, $newPos); - - $this->createUpdateResponse($pl); - } - - public function deleteItemAction() - { - $positions = $this->_getParam('pos', array()); - - if (!is_array($positions)) - $positions = array($positions); - - //so the automatic updating of playlist positioning doesn't affect removal. - sort($positions); - $positions = array_reverse($positions); - - $pl = $this->getPlaylist(); - if($pl === false){ - $this->view->playlist_error = true; - return false; - } - - foreach ($positions as $pos) { - $pl->delAudioClip($pos); - } - - $this->createUpdateResponse($pl); + $this->createFullResponse($pl); } public function addItemsAction() { $ids = $this->_getParam('ids'); - $pos = $this->_getParam('pos', null); + $ids = (!is_array($ids)) ? array($ids) : $ids; + $afterItem = $this->_getParam('afterItem', null); - if (!is_null($ids)) { + + try { $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->createUpdateResponse($pl); - return; + $pl->addAudioClips($ids, $afterItem); } - $this->view->message = "a file is not chosen"; + catch (PlaylistNotFoundException $e) { + Logging::log("Playlist {$pl_id} not found"); + $this->changePlaylist(null); + } + catch (Exception $e) { + Logging::log("{$e->getFile()}"); + Logging::log("{$e->getLine()}"); + Logging::log("{$e->getMessage()}"); + } + + $this->createUpdateResponse($pl); } - public function deleteAction() + public function moveItemAction() { - $ids = $this->_getParam('ids', array()); - $active = $this->_getParam('active', false); + $ids = $this->_getParam('ids'); + $ids = (!is_array($ids)) ? array($ids) : $ids; + $afterItem = $this->_getParam('afterItem', null); - if ($active === true) { - $ids = array_merge($ids, array($pl_sess->id)); + try { + $pl = $this->getPlaylist(); + $pl->moveAudioClips($ids, $afterItem); + } + catch (PlaylistNotFoundException $e) { + Logging::log("Playlist {$pl_id} not found"); + $this->changePlaylist(null); + } + catch (Exception $e) { + Logging::log("{$e->getFile()}"); + Logging::log("{$e->getLine()}"); + Logging::log("{$e->getMessage()}"); } - foreach ($ids as $key => $id) { - $pl = Application_Model_Playlist::Recall($id); + $this->createUpdateResponse($pl); + } - 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; - } + public function deleteItemsAction() + { + $ids = $this->_getParam('ids'); + $ids = (!is_array($ids)) ? array($ids) : $ids; + + try { + $pl = $this->getPlaylist(); + $pl->delAudioClips($ids); + } + catch (PlaylistNotFoundException $e) { + Logging::log("Playlist {$pl_id} not found"); + $this->changePlaylist(null); + } + catch (Exception $e) { + Logging::log("{$e->getFile()}"); + Logging::log("{$e->getLine()}"); + Logging::log("{$e->getMessage()}"); } - $this->createFullResponse(null); + $this->createUpdateResponse($pl); } public function setCueAction() diff --git a/airtime_mvc/application/models/Playlist.php b/airtime_mvc/application/models/Playlist.php index e6f4bb2b2..027ac163c 100644 --- a/airtime_mvc/application/models/Playlist.php +++ b/airtime_mvc/application/models/Playlist.php @@ -55,20 +55,25 @@ class Application_Model_Playlist { if (isset($id)) { $this->pl = CcPlaylistQuery::create()->findPK($id); - if (is_null($this->_pl)){ - throw new Exception(); + if (is_null($this->pl)){ + throw new PlaylistNotFoundException(); } } else { $this->pl = new CcPlaylist(); + $this->pl->setDbState('ready'); $this->pl->setDbUtime(new DateTime("now"), new DateTimeZone("UTC")); + $this->pl->save(); } - $this->plItem["fadein"] = Application_Model_Preference::GetDefaultFade(); - $this->plItem["fadeout"] = Application_Model_Preference::GetDefaultFade(); + $defaultFade = Application_Model_Preference::GetDefaultFade(); + if ($defaultFade !== "") { + $this->plItem["fadein"] = $defaultFade; + $this->plItem["fadeout"] = $defaultFade; + } - $this->id = $this->pl->getDbId(); $this->con = isset($con) ? $con : Propel::getConnection(CcPlaylistPeer::DATABASE_NAME); + $this->id = $this->pl->getDbId(); } /** @@ -124,6 +129,9 @@ class Application_Model_Playlist { * @return array */ public function getContents() { + + Logging::log("Getting contents for playlist {$this->id}"); + $files = array(); $rows = CcPlaylistcontentsQuery::create() ->joinWith('CcFiles') @@ -181,12 +189,13 @@ class Application_Model_Playlist { */ private function buildEntry($p_item, $pos) { - $file = CcFilesQuery::create()->findPK($p_item["id"], $this->con); + $file = CcFilesQuery::create()->findPK($p_item, $this->con); $entry = $this->plItem; $entry["id"] = $file->getDbId(); $entry["pos"] = $pos; $entry["cliplength"] = $file->getDbLength(); + $entry["cueout"] = $file->getDbLength(); return $entry; } @@ -204,35 +213,44 @@ class Application_Model_Playlist { try { - if (isset($p_afterItem)) { + if (is_numeric($p_afterItem)) { + Logging::log("Finding playlist content item {$p_afterItem}"); + $afterItem = CcPlaylistcontentsQuery::create()->findPK($p_afterItem); + $pos = $afterItem->getDbPosition() + 1; $contentsToUpdate = CcPlaylistcontentsQuery::create() ->filterByDbPlaylistId($this->id) + ->filterByDbPosition($pos-1, Criteria::GREATER_THAN) ->orderByDbPosition() ->find($this->con); - $pos = $afterItem->getDbPosition() + 1; + Logging::log("Adding to playlist"); + Logging::log("at position {$pos}"); } else { + $pos = $this->getSize(); + Logging::log("Adding to end of playlist"); + Logging::log("at position {$pos}"); } foreach($p_items as $ac) { + Logging::log("Adding audio file {$ac}"); - $res = $this->insertPlaylistElement($this->buildEntry($ac), $pos); + $res = $this->insertPlaylistElement($this->buildEntry($ac, $pos)); $pos = $pos + 1; } //reset the positions of the remaining items. for ($i = 0; $i < count($contentsToUpdate); $i++) { - $contents[$i]->setDbPosition($pos); - $contents[$i]->save($this->con); + $contentsToUpdate[$i]->setDbPosition($pos); + $contentsToUpdate[$i]->save($this->con); $pos = $pos + 1; } - $pl->setDbMtime(new DateTime("now"), new DateTimeZone("UTC")); - $pl->save($this->con); + $this->pl->setDbMtime(new DateTime("now"), new DateTimeZone("UTC")); + $this->pl->save($this->con); $this->con->commit(); } @@ -245,12 +263,12 @@ class Application_Model_Playlist { /** * Move audioClip to the new position in the playlist * - * @param array $selectedItems + * @param array $p_items * array of unique ids of the selected items - * @param int $afterItem + * @param int $p_afterItem * unique id of the item to move the clip after */ - public function moveAudioClip($selectedItems, $afterItem) + public function moveAudioClips($p_items, $p_afterItem=NULL) { $this->con->beginTransaction(); @@ -533,7 +551,6 @@ class Application_Model_Playlist { public function getAllPLMetaData() { $categories = $this->categories; - $row = CcPlaylistQuery::create()->findPK($this->id); $md = array(); foreach($categories as $key => $val) { @@ -543,7 +560,7 @@ class Application_Model_Playlist { } $method = 'get' . $val; - $md[$key] = $row->$method(); + $md[$key] = $this->pl->$method(); } return $md; @@ -557,21 +574,17 @@ class Application_Model_Playlist { return $this->getLength(); } - $row = CcPlaylistQuery::create()->findPK($this->id); $method = 'get' . $cat; - return $row->$method(); + return $this->pl->$method(); } public function setPLMetaData($category, $value) { $cat = $this->categories[$category]; - $row = CcPlaylistQuery::create()->findPK($this->id); $method = 'set' . $cat; - $row->$method($value); - $row->save(); - - return TRUE; + $this->pl->$method($value); + $this->pl->save($this->con); } @@ -639,4 +652,16 @@ class Application_Model_Playlist { CcPlaylistcontentsQuery::create()->filterByDbFileId($p_fileId)->delete(); } + /** + * Delete playlists that match the ids.. + * @param array $p_ids + */ + public static function DeletePlaylists($p_ids) + { + CcPlaylistQuery::create()->findPKs($p_ids)->delete(); + } + } // class Playlist + +class PlaylistNotFoundException extends Exception {} +class OutDatedException extends Exception {} diff --git a/airtime_mvc/application/views/scripts/playlist/update.phtml b/airtime_mvc/application/views/scripts/playlist/update.phtml index 7d15c76f2..b8a99fabf 100644 --- a/airtime_mvc/application/views/scripts/playlist/update.phtml +++ b/airtime_mvc/application/views/scripts/playlist/update.phtml @@ -4,7 +4,7 @@ if (count($items)) : ?> -
  • "> +
  • " unqid="">
    ', diff --git a/airtime_mvc/public/js/airtime/library/events/library_playlistbuilder.js b/airtime_mvc/public/js/airtime/library/events/library_playlistbuilder.js index b9658d162..4d9a9186b 100644 --- a/airtime_mvc/public/js/airtime/library/events/library_playlistbuilder.js +++ b/airtime_mvc/public/js/airtime/library/events/library_playlistbuilder.js @@ -1,6 +1,7 @@ function fnLibraryTableRowCallback( nRow, aData, iDisplayIndex, iDisplayIndexFull ) { $(nRow).attr("id", aData["tr_id"]); + $(nRow).data("aData", aData); $(nRow).find('td') .jjmenu("rightClick", @@ -12,8 +13,19 @@ function fnLibraryTableRowCallback( nRow, aData, iDisplayIndex, iDisplayIndexFul function fnLibraryTableDrawCallback() { $('#library_display tr[id ^= "au"]').draggable({ - helper: 'clone', - cursor: 'pointer' + //helper: 'clone', + helper: function(ev, el) { + var data, li; + + data = $(ev.currentTarget).data("aData"); + + li = $("
  • "); + li.append(data.track_title); + + return li; + }, + cursor: 'pointer', + connectToSortable: '#spl_sortable' }); } diff --git a/airtime_mvc/public/js/airtime/library/spl.js b/airtime_mvc/public/js/airtime/library/spl.js index f6e83a930..0a32d92f1 100644 --- a/airtime_mvc/public/js/airtime/library/spl.js +++ b/airtime_mvc/public/js/airtime/library/spl.js @@ -219,14 +219,6 @@ function redrawDataTablePage() { } function setSPLContent(json) { - if(json.playlist_error == true){ - alertPlaylistErrorAndReload(); - } - - if(json.message) { - alert(json.message); - return; - } $('#spl_name > a') .empty() @@ -243,8 +235,6 @@ function setSPLContent(json) { //redraw the library list redrawDataTablePage(); - - return false; } function addSPLItem(event, ui){ @@ -301,12 +291,11 @@ function moveSPLItem(event, ui) { } function noOpenPL(json) { - if(json.playlist_error == true){ - alertPlaylistErrorAndReload(); - } + $("#side_playlist") .empty() - .append(json.html); + .append(json.html) + .data("id", null); $("#spl_new") .button() @@ -317,9 +306,9 @@ function newSPL() { var url; stopAudioPreview(); - url = '/Playlist/new/format/json'; + url = '/Playlist/new'; - $.post(url, function(json){ + $.post(url, {format: "json"}, function(json){ openDiffSPL(json); //redraw the library list @@ -328,16 +317,16 @@ function newSPL() { } function deleteSPL() { - var url; + var url, id; stopAudioPreview(); + id = $("#side_playlist").data("id"); + url = '/Playlist/delete'; - $.post(url, {"format": "json", "active": true}, function(json){ - if(json.playlist_error == true){ - alertPlaylistErrorAndReload(); - } + $.post(url, {format: "json", ids: id}, function(json){ + noOpenPL(json); //redraw the library list redrawDataTablePage(); @@ -346,15 +335,11 @@ function deleteSPL() { function openDiffSPL(json) { - if(json.playlist_error == true){ - alertPlaylistErrorAndReload(); - } $("#side_playlist") .empty() .append(json.html) - .data("id", json.pl_id); + .data("id", json.id); - currentlyOpenedSplId = json.pl_id; setUpSPL(); } @@ -386,12 +371,102 @@ function editName() { } function setUpSPL() { + + var sortableConf = (function(){ + var origRow, + iItem, + iAfter, + setSPLContent, + fnAdd, + fnMove, + fnReceive, + fnUpdate; + + function redrawDataTablePage() { + var dt; + dt = $("#library_display").dataTable(); + dt.fnStandingRedraw(); + } + + setSPLContent = function(json) { - $("#spl_sortable").sortable({ - handle: 'div.list-item-container' - }); - $("#spl_sortable" ).bind( "sortstop", moveSPLItem); + $('#spl_name > a') + .empty() + .append(json.name); + $('#spl_length') + .empty() + .append(json.length); + $('#fieldset-metadate_change textarea') + .empty() + .val(json.description); + $('#spl_sortable') + .empty() + .append(json.html); + + //redraw the library list + redrawDataTablePage(); + } + + fnAdd = function() { + + $.post("/playlist/add-items", + {format: "json", "ids": iItem, "afterItem": iAfter}, + function(json){ + setSPLContent(json); + }); + }; + + fnMove = function() { + + $.post("/showbuilder/schedule-move", + {"format": "json", "selectedItem": aSelect, "afterItem": aAfter}, + function(json){ + oTable.fnDraw(); + }); + }; + + fnReceive = function(event, ui) { + origRow = ui.item; + }; + + fnUpdate = function(event, ui) { + var prev; + + prev = ui.item.prev(); + if (prev.hasClass("spl_empty") || prev.length === 0) { + iAfter = null; + } + else { + iAfter = prev.attr("id").split("_").pop(); + } + + //item was dragged in from library datatable + if (origRow !== undefined) { + iItem = origRow.data("aData").id; + origRow = undefined; + fnAdd(); + } + //item was reordered. + else { + oItemData = ui.item.data("aData"); + fnMove(); + } + }; + + return { + items: 'li', + placeholder: "placeholder lib-placeholder ui-state-highlight", + forcePlaceholderSize: true, + handle: 'div.list-item-container', + receive: fnReceive, + update: fnUpdate + }; + }()); + + $("#spl_sortable").sortable(sortableConf); + $("#spl_remove_selected").click(deleteSPLItem); + $("#spl_new") .button() .click(newSPL); @@ -536,10 +611,6 @@ function setUpSPL() { $("#spl_delete") .button() .click(deleteSPL); - - - $("#spl_sortable").droppable(); - $("#spl_sortable" ).bind( "drop", addSPLItem); } //sets events dynamically for playlist entries (each row in the playlist) @@ -579,15 +650,7 @@ function setFadeEvents(el) { "keydown": submitOnEnter}); } -// Alert the error and reload the page -// this function is used to resolve concurrency issue -function alertPlaylistErrorAndReload(){ - alert("The playlist doesn't exist anymore!"); - window.location.reload(); -} - $(document).ready(function() { - var currentlyOpenedSplId; var playlist = $("#side_playlist"); setUpSPL(playlist);