From 375d83ab431d010041a0af27eb4fb1964cb9e061 Mon Sep 17 00:00:00 2001 From: Duncan Sommerville Date: Mon, 28 Sep 2015 10:40:04 -0400 Subject: [PATCH] Update to podcast frontend --- .../application/models/airtime/Podcast.php | 9 +++- .../rest/controllers/PodcastController.php | 3 -- .../public/js/airtime/common/common.js | 11 ++++- .../public/js/airtime/library/podcast.js | 43 ++++++++++++++----- .../public/js/airtime/showbuilder/tabs.js | 8 ++-- .../public/js/airtime/widgets/table.js | 15 ++++--- 6 files changed, 62 insertions(+), 27 deletions(-) diff --git a/airtime_mvc/application/models/airtime/Podcast.php b/airtime_mvc/application/models/airtime/Podcast.php index f948bd353..facecc5f2 100644 --- a/airtime_mvc/application/models/airtime/Podcast.php +++ b/airtime_mvc/application/models/airtime/Podcast.php @@ -139,13 +139,20 @@ class Podcast extends BasePodcast * @return array */ private static function _generatePodcastArray($podcast, $rss) { - $podcastArray = $podcast->toArray(BasePeer::TYPE_FIELDNAME); + $ingestedEpisodes = PodcastEpisodesQuery::create() + ->findByDbPodcastId($podcast->getDbId()); + $episodeIds = array(); + foreach ($ingestedEpisodes as $e) { + array_push($episodeIds, $e->getDbEpisodeGuid()); + } + $podcastArray = $podcast->toArray(BasePeer::TYPE_FIELDNAME); $podcastArray["episodes"] = array(); foreach ($rss->get_items() as $item) { /** @var SimplePie_Item $item */ array_push($podcastArray["episodes"], array( "guid" => $item->get_id(), + "ingested" => in_array($item->get_id(), $episodeIds), "title" => $item->get_title(), "author" => $item->get_author()->get_name(), "description" => $item->get_description(), diff --git a/airtime_mvc/application/modules/rest/controllers/PodcastController.php b/airtime_mvc/application/modules/rest/controllers/PodcastController.php index 138da8c3c..e18b49de9 100644 --- a/airtime_mvc/application/modules/rest/controllers/PodcastController.php +++ b/airtime_mvc/application/modules/rest/controllers/PodcastController.php @@ -90,9 +90,6 @@ class Rest_PodcastController extends Zend_Rest_Controller $this->_helper->json->sendJson(array( "podcast"=>json_encode($podcast), "html"=>$this->view->render($path), - "type"=>"podcast", // TODO: get rid of these extraneous fields - "id"=>$podcast["id"] - // "id"=>$podcast->getDbId() )); // $this->getResponse() diff --git a/airtime_mvc/public/js/airtime/common/common.js b/airtime_mvc/public/js/airtime/common/common.js index 27f93ad61..76adaf00d 100644 --- a/airtime_mvc/public/js/airtime/common/common.js +++ b/airtime_mvc/public/js/airtime/common/common.js @@ -58,6 +58,15 @@ var i18n_days_short = [ $.i18n._("Sa") ]; +var HTTPMethods = Object.freeze({ + GET: "GET", + POST: "POST", + PUT: "PUT", + PATCH: "PATCH", + DELETE: "DELETE", + OPTIONS: "OPTIONS" +}); + var dateStartId = "#sb_date_start", timeStartId = "#sb_time_start", dateEndId = "#sb_date_end", @@ -69,7 +78,7 @@ function getDatatablesStrings(overrideDict) { "sEmptyTable": $.i18n._("No data available in table"), "sInfo": $.i18n._("Showing _START_ to _END_ of _TOTAL_ entries"), "sInfoEmpty": $.i18n._("Showing 0 to 0 of 0 entries"), - "sInfoFiltered": $.i18n._("(filtered from _MAX_ total entries)"), + "sInfoFiltered": "", // $.i18n._("(filtered from _MAX_ total entries)"), "sInfoPostFix": $.i18n._(""), "sInfoThousands": $.i18n._(","), "sLengthMenu": $.i18n._("Show _MENU_"), diff --git a/airtime_mvc/public/js/airtime/library/podcast.js b/airtime_mvc/public/js/airtime/library/podcast.js index fe1c0f246..75219b322 100644 --- a/airtime_mvc/public/js/airtime/library/podcast.js +++ b/airtime_mvc/public/js/airtime/library/podcast.js @@ -25,7 +25,7 @@ var AIRTIME = (function (AIRTIME) { podcastData.episodes = episodeTable.getSelectedRows(); $http.put(endpoint + $scope.podcast.id, { csrf_token: jQuery("#csrf").val(), podcast: podcastData }) .success(function() { - // TODO + // TODO refresh the table here somehow.. }); }; @@ -36,15 +36,20 @@ var AIRTIME = (function (AIRTIME) { }); function _bulkAction(method, callback) { - var selected = $("#podcast_table").find(".selected"), - ids = []; - var selectedData = AIRTIME.library.podcastTableWidget.getSelectedRows(); + var ids = [], selectedData = AIRTIME.library.podcastTableWidget.getSelectedRows(); selectedData.forEach(function(el) { - ids.push(el.id); + var uid = AIRTIME.library.MediaTypeStringEnum.PODCAST+"_"+el.id; + var t = AIRTIME.tabs.get(uid); + if (t && method == HTTPMethods.DELETE) { + t.close(); + } + if (!(t && method == HTTPMethods.GET)) ids.push(el.id); }); - // Bulk methods should use post because we're sending data in the request body - $.post(endpoint + "bulk", { csrf_token: $("#csrf").val(), method: method, ids: ids }, callback); + if (ids.length > 0) { + // Bulk methods should use post because we're sending data in the request body + $.post(endpoint + "bulk", {csrf_token: $("#csrf").val(), method: method, ids: ids}, callback); + } } function _bootstrapAngularApp(podcast, tab, table) { @@ -81,7 +86,7 @@ var AIRTIME = (function (AIRTIME) { }; mod.editSelectedPodcasts = function() { - _bulkAction("GET", function(json) { + _bulkAction(HTTPMethods.GET, function(json) { json.forEach(function(el) { var podcast = JSON.parse(el.podcast); var uid = AIRTIME.library.MediaTypeStringEnum.PODCAST+"_"+podcast.id, @@ -94,7 +99,7 @@ var AIRTIME = (function (AIRTIME) { mod.deleteSelectedPodcasts = function() { if (confirm($.i18n._("Are you sure you want to delete the selected podcasts from your library?"))) { - _bulkAction("DELETE", function () { + _bulkAction(HTTPMethods.DELETE, function () { AIRTIME.library.podcastDataTable.fnDraw(); }); } @@ -102,7 +107,7 @@ var AIRTIME = (function (AIRTIME) { mod.initPodcastEpisodeDatatable = function(episodes) { var aoColumns = [ - /* GUID */ { "sTitle" : "" , "mDataProp" : "guid" , "sClass" : "podcast_episodes_guid" , "bVisible" : false }, + /* GUID */ { "sTitle" : "" , "mDataProp" : "guid" , "sClass" : "podcast_episodes_guid" , "bVisible" : false }, /* Title */ { "sTitle" : $.i18n._("Title") , "mDataProp" : "title" , "sClass" : "podcast_episodes_title" , "sWidth" : "170px" }, /* Author */ { "sTitle" : $.i18n._("Author") , "mDataProp" : "author" , "sClass" : "podcast_episodes_author" , "sWidth" : "170px" }, /* Description */ { "sTitle" : $.i18n._("Description") , "mDataProp" : "description" , "sClass" : "podcast_episodes_description" , "sWidth" : "300px" }, @@ -110,10 +115,26 @@ var AIRTIME = (function (AIRTIME) { /* Publication Date */ { "sTitle" : $.i18n._("Publication Date") , "mDataProp" : "pub_date" , "sClass" : "podcast_episodes_pub_date" , "sWidth" : "170px" } ]; + var PodcastTable = function(wrapperDOMNode, bItemSelection, toolbarButtons, dataTablesOptions) { + // Just call the superconstructor. For clarity/extensibility + return AIRTIME.widgets.Table.call(this, wrapperDOMNode, bItemSelection, toolbarButtons, dataTablesOptions); + }; // Subclass AIRTIME.widgets.Table + PodcastTable.prototype = Object.create(AIRTIME.widgets.Table.prototype); + PodcastTable.prototype.constructor = PodcastTable; + PodcastTable.prototype._SELECTORS = Object.freeze({ + SELECTION_CHECKBOX: ".airtime_table_checkbox:has(input)", + SELECTION_TABLE_ROW: "tr:has(td.airtime_table_checkbox > input)" + }); + PodcastTable.prototype._datatablesCheckboxDataDelegate = function(rowData, callType, dataToSave) { + if (rowData.ingested) return null; // Don't create checkboxes for ingested items + return AIRTIME.widgets.Table.prototype._datatablesCheckboxDataDelegate.call(this, rowData, callType, dataToSave); + }; + + // This method is static, so use AIRTIME.widgets.Table var podcastToolbarButtons = AIRTIME.widgets.Table.getStandardToolbarButtons(); // Set up the div with id "podcast_table" as a datatable. - var podcastEpisodesTableWidget = new AIRTIME.widgets.Table( + var podcastEpisodesTableWidget = new PodcastTable( AIRTIME.tabs.getActiveTab().contents.find('#podcast_episodes'), // DOM node to create the table inside. true, // Enable item selection podcastToolbarButtons, // Toolbar buttons diff --git a/airtime_mvc/public/js/airtime/showbuilder/tabs.js b/airtime_mvc/public/js/airtime/showbuilder/tabs.js index f04680ffb..c6d1e284f 100644 --- a/airtime_mvc/public/js/airtime/showbuilder/tabs.js +++ b/airtime_mvc/public/js/airtime/showbuilder/tabs.js @@ -316,12 +316,12 @@ var AIRTIME = (function(AIRTIME){ /** * Given a tab id, get the corresponding Tab object * - * @param {int} id the tab id of the Tab to retrieve - * @returns {Tab|undefined} the Tab object with the given id, or undefined - * if no Tab with the given id exists + * @param {int|string} id the tab or object ID of the Tab to retrieve + * @returns {Tab|undefined} the Tab object with the given ID, or undefined + * if no Tab with the given ID exists */ mod.get = function(id) { - return $openTabs[$tabMap[id]]; + return $.isNumeric(id) ? $openTabs[$tabMap[id]] : $openTabs[id]; }; /** diff --git a/airtime_mvc/public/js/airtime/widgets/table.js b/airtime_mvc/public/js/airtime/widgets/table.js index 2c14394ce..012ca853a 100644 --- a/airtime_mvc/public/js/airtime/widgets/table.js +++ b/airtime_mvc/public/js/airtime/widgets/table.js @@ -23,11 +23,6 @@ var AIRTIME = (function(AIRTIME) { MULTI_CTRL : 2 }; - // Internal enum for repeated jQuery selectors - self._SELECTORS = Object.freeze({ - SELECTION_CHECKBOX: ".airtime_table_checkbox" - }); - //Member variables self._datatable = null; self._selectedRows = []; //An array containing the underlying objects for each selected row. (Easy to use!) @@ -109,8 +104,8 @@ var AIRTIME = (function(AIRTIME) { * than having a per-row callback...) */ if (bItemSelection) { - $(self._datatable, 'tbody tr').on('click contextmenu', 'tr', function (e) { - var aData = self._datatable.fnGetData($(this).index()); // $(this).data(); //Neat trick - thanks DataTables! + $(self._datatable, 'tbody tr').on('click contextmenu', self._SELECTORS.SELECTION_TABLE_ROW, function (e) { + var aData = self._datatable.fnGetData($(this).index()); var iDisplayIndex = $(this).index(); //The index of the row in the current page in the table. var nRow = this; @@ -427,6 +422,12 @@ var AIRTIME = (function(AIRTIME) { //Static initializers / Class variables /** Predefined toolbar buttons that you can add to the table. Use getStandardToolbarButtons(). */ + Table.prototype._SELECTORS = Object.freeze({ + SELECTION_CHECKBOX: ".airtime_table_checkbox", + SELECTION_TABLE_ROW: "tr" + }); + + Table.TOOLBAR_BUTTON_ROLES = { NEW : 0, EDIT : 1,