Frontend polish and fixes; make empty placeholder implementation more abstract and add placeholder to 'My Podcast' view

This commit is contained in:
Duncan Sommerville 2015-11-12 19:02:09 -05:00
parent 0e74229975
commit 55df7775c2
10 changed files with 81 additions and 36 deletions

View File

@ -122,7 +122,7 @@ class LocaleController extends Zend_Controller_Action
"Input must be a number" => _("Input must be a number"), "Input must be a number" => _("Input must be a number"),
"Input must be in the format: yyyy-mm-dd" => _("Input must be in the format: yyyy-mm-dd"), "Input must be in the format: yyyy-mm-dd" => _("Input must be in the format: yyyy-mm-dd"),
"Input must be in the format: hh:mm:ss.t" => _("Input must be in the format: hh:mm:ss.t"), "Input must be in the format: hh:mm:ss.t" => _("Input must be in the format: hh:mm:ss.t"),
"Station Podcast" => _("Station Podcast"), "My Podcast" => _("My Podcast"),
//library/plupload.js //library/plupload.js
"You are currently uploading files. %sGoing to another screen will cancel the upload process. %sAre you sure you want to leave the page?" "You are currently uploading files. %sGoing to another screen will cancel the upload process. %sAre you sure you want to leave the page?"
=> _("You are currently uploading files. %sGoing to another screen will cancel the upload process. %sAre you sure you want to leave the page?"), => _("You are currently uploading files. %sGoing to another screen will cancel the upload process. %sAre you sure you want to leave the page?"),

View File

@ -9,7 +9,7 @@ class Application_Form_PodcastPreferences extends Zend_Form_SubForm {
$isPrivate = Application_Model_Preference::getStationPodcastPrivacy(); $isPrivate = Application_Model_Preference::getStationPodcastPrivacy();
$stationPodcastPrivacy = new Zend_Form_Element_Radio('stationPodcastPrivacy'); $stationPodcastPrivacy = new Zend_Form_Element_Radio('stationPodcastPrivacy');
$stationPodcastPrivacy->setLabel(_('Station Podcast Feed Privacy')); $stationPodcastPrivacy->setLabel(_('My Podcast Feed Privacy'));
$stationPodcastPrivacy->setMultiOptions(array( $stationPodcastPrivacy->setMultiOptions(array(
_("Public"), _("Public"),
_("Private"), _("Private"),
@ -23,7 +23,7 @@ class Application_Form_PodcastPreferences extends Zend_Form_SubForm {
$feedUrl->setAttrib('class', 'input_text') $feedUrl->setAttrib('class', 'input_text')
->setAttrib('disabled', 'disabled') ->setAttrib('disabled', 'disabled')
->setRequired(false) ->setRequired(false)
->setLabel(_("Station Podcast Feed URL")) ->setLabel(_("My Podcast Feed URL"))
->setValue($url); ->setValue($url);
$this->addElement($feedUrl); $this->addElement($feedUrl);
} }

View File

@ -7,7 +7,7 @@ class Application_Service_PublishService {
*/ */
private static $SOURCES = array( private static $SOURCES = array(
"soundcloud" => SOUNDCLOUD, "soundcloud" => SOUNDCLOUD,
"station_podcast" => "Station Podcast" "station_podcast" => "My Podcast"
); );
/** /**

View File

@ -3,7 +3,7 @@
<?php echo $this->element->getSubform('preferences_general') ?> <?php echo $this->element->getSubform('preferences_general') ?>
<h3 class="collapsible-header" id="podcast-heading"><span class="arrow-icon"></span><?php echo _("Station Podcast Settings"); ?></h3> <h3 class="collapsible-header" id="podcast-heading"><span class="arrow-icon"></span><?php echo _("My Podcast Settings"); ?></h3>
<div class="collapsible-content" id="podcast-settings"> <div class="collapsible-content" id="podcast-settings">
<?php echo $this->element->getSubform('preferences_podcast') ?> <?php echo $this->element->getSubform('preferences_podcast') ?>
</div> </div>

View File

@ -1,7 +1,7 @@
<div class="angular_wrapper" ng-controller="StationPodcast"> <div class="angular_wrapper" ng-controller="StationPodcast">
<div class="inner_editor_title"> <div class="inner_editor_title">
<h2> <h2>
<span class="title_obj_name"><?php echo _("My Station Podcast") ?></span> <span class="title_obj_name"><?php echo _("My Podcast") ?></span>
</h2> </h2>
<a href="{{podcast.url}}" target="_blank"> <a href="{{podcast.url}}" target="_blank">
<button class="btn"><?php echo _("View Feed") ?></button> <button class="btn"><?php echo _("View Feed") ?></button>

View File

@ -488,8 +488,14 @@ li.ui-state-default {
color: #efefef; color: #efefef;
} }
.editor_pane_wrapper a:visited, .angular_wrapper a:visited { .editor_pane_wrapper a,
color: #cecece; .angular_wrapper a {
color: #FF5D1A;
}
.editor_pane_wrapper a:visited,
.angular_wrapper a:visited {
color: #CE3C01;
} }
.tab-name { .tab-name {

View File

@ -72,30 +72,35 @@ var AIRTIME = (function(AIRTIME) {
/** /**
* Draw a placeholder for the given table to show if it has no data. * Draw a placeholder for the given table to show if it has no data.
* *
* @param {jQuery} table jQuery object containing the table DOM node * @param {Object} table jQuery object containing the table DOM node
*/ */
mod.drawEmptyPlaceholder = function (table) { mod.drawEmptyPlaceholder = function (table) {
var opts;
if (table instanceof AIRTIME.widgets.Table) {
opts = table.getEmptyPlaceholder();
table = table.getDatatable();
if (!table) {
return;
}
}
var emptyRow = table.find('tr:has(td.dataTables_empty)'), var emptyRow = table.find('tr:has(td.dataTables_empty)'),
wrapper = table.closest(".dataTables_wrapper"); wrapper = table.closest(".dataTables_wrapper"),
libEmpty = wrapper.find('.empty_placeholder');
var libEmpty = wrapper.find('.empty_placeholder');
if (emptyRow.length > 0) { if (emptyRow.length > 0) {
emptyRow.hide(); emptyRow.hide();
var mediaType = parseInt($('.media_type_selector.selected').data('selection-id')), var mediaType = parseInt($('.media_type_selector.selected').data('selection-id')),
img = wrapper.find('.empty_placeholder_image'); img = wrapper.find('.empty_placeholder_image');
if (isNaN(mediaType)) { return; } if (isNaN(mediaType)) {
return;
}
// Remove all classes for when we change between empty media types // Remove all classes for when we change between empty media types
img.removeClass(function() { return $(this).attr("class"); }); img.removeClass(function() { return $(this).attr("class"); });
if (table[0] == AIRTIME.library.podcastEpisodeDataTable[0]) { if (opts) {
img.addClass("empty_placeholder_image icon-white icon-th-list"); img.addClass("empty_placeholder_image " + opts.iconClass);
wrapper.find('.empty_placeholder_text').html( wrapper.find('.empty_placeholder_text').html(opts.html);
$.i18n._("This podcast doesn't have any episodes!")
+ "<br/>" + $.i18n._("Make sure the RSS feed contains audio items (with enclosure tags).")
+ "<br/><a target='_blank' href='http://www.apple.com/ca/itunes/podcasts/specs.html'>" + $.i18n._("Learn about podcasts") + "</a>"
);
} else { } else {
var opts = AIRTIME.library.placeholder(mediaType); opts = AIRTIME.library.placeholder(mediaType);
img.addClass("empty_placeholder_image icon-white " + opts.icon); img.addClass("empty_placeholder_image icon-white " + opts.icon);
wrapper.find('.empty_placeholder_text').html( wrapper.find('.empty_placeholder_text').html(
$.i18n._("You haven't added any " + opts.media + ".") $.i18n._("You haven't added any " + opts.media + ".")

View File

@ -1399,7 +1399,7 @@ var AIRTIME = (function(AIRTIME) {
// Add a button to view the station podcast // Add a button to view the station podcast
podcastToolbarButtons["StationPodcast"] = { podcastToolbarButtons["StationPodcast"] = {
title : $.i18n._("Station Podcast"), title : $.i18n._("My Podcast"),
iconClass : "icon-music", iconClass : "icon-music",
extraBtnClass : "btn-small", extraBtnClass : "btn-small",
elementId : "", elementId : "",
@ -1419,9 +1419,6 @@ var AIRTIME = (function(AIRTIME) {
sAjaxSource : ajaxSourceURL, sAjaxSource : ajaxSourceURL,
oColReorder: { oColReorder: {
iFixedColumns: 1 // Checkbox iFixedColumns: 1 // Checkbox
},
fnDrawCallback: function () {
AIRTIME.library.drawEmptyPlaceholder($(this));
} }
}); });
@ -1588,13 +1585,18 @@ var AIRTIME = (function(AIRTIME) {
}, },
oColReorder: { oColReorder: {
iFixedColumns: 3 // Checkbox + imported iFixedColumns: 3 // Checkbox + imported
},
fnDrawCallback: function () {
AIRTIME.library.drawEmptyPlaceholder($(this));
} }
}, },
buttons, buttons,
{ hideIngestCheckboxes: false } {
hideIngestCheckboxes: false,
emptyPlaceholder: {
iconClass: "icon-white icon-th-list",
html: $.i18n._("This podcast doesn't have any episodes!")
+ "<br/>" + $.i18n._("Make sure the RSS feed contains audio items (with enclosure tags).")
+ "<br/><a target='_blank' href='http://www.apple.com/ca/itunes/podcasts/specs.html'>" + $.i18n._("Learn about podcasts") + "</a>"
}
}
); );
mod.podcastEpisodeDataTable = $datatables[mod.DataTableTypeEnum.PODCAST_EPISODES] = mod.podcastEpisodeTableWidget.getDatatable(); mod.podcastEpisodeDataTable = $datatables[mod.DataTableTypeEnum.PODCAST_EPISODES] = mod.podcastEpisodeTableWidget.getDatatable();

View File

@ -40,7 +40,7 @@ var AIRTIME = (function (AIRTIME) {
$http.put(endpoint + $scope.podcast.id, {csrf_token: $scope.csrf, podcast: $scope.podcast}) $http.put(endpoint + $scope.podcast.id, {csrf_token: $scope.csrf, podcast: $scope.podcast})
.success(function () { .success(function () {
AIRTIME.library.podcastDataTable.fnDraw(); AIRTIME.library.podcastDataTable.fnDraw();
tab.setName($scope.podcast.title); tab.close();
}); });
}; };
@ -205,9 +205,17 @@ var AIRTIME = (function (AIRTIME) {
buttons, buttons,
{ {
hideIngestCheckboxes: true, hideIngestCheckboxes: true,
podcastId: $scope.podcast.id podcastId: $scope.podcast.id,
emptyPlaceholder: {
iconClass: "icon-white icon-th-list",
html: $.i18n._("You haven't published any episodes!")
+ "<br/>" + $.i18n._("You can publish your uploaded content from the 'Tracks' view.")
+ "<br/><a target='_parent' href='showbuilder#tracks'>" + $.i18n._("Try it now") + "</a>"
}
} }
); );
mod.stationPodcastTable = this.episodeTable.getDatatable();
}; };
/** /**
@ -215,8 +223,8 @@ var AIRTIME = (function (AIRTIME) {
*/ */
StationPodcastController.prototype.initialize = function() { StationPodcastController.prototype.initialize = function() {
PodcastController.prototype.initialize.call(this); PodcastController.prototype.initialize.call(this);
// We want to override the default tab name behaviour and use "Station Podcast" for clarity // We want to override the default tab name behaviour and use "My Podcast" for clarity
this.$scope.tab.setName(jQuery.i18n._("Station Podcast")); this.$scope.tab.setName(jQuery.i18n._("My Podcast"));
this._initTable(); this._initTable();
}; };
@ -317,7 +325,7 @@ var AIRTIME = (function (AIRTIME) {
this.config = config; // Internal configuration object this.config = config; // Internal configuration object
this._setupImportListener(); this._setupImportListener();
// Call the superconstructor // Call the superconstructor
return AIRTIME.widgets.Table.call(this, wrapperDOMNode, bItemSelection, toolbarButtons, dataTablesOptions); return AIRTIME.widgets.Table.call(this, wrapperDOMNode, bItemSelection, toolbarButtons, dataTablesOptions, config.emptyPlaceholder);
}; // Subclass AIRTIME.widgets.Table }; // Subclass AIRTIME.widgets.Table
PodcastEpisodeTable.prototype = Object.create(AIRTIME.widgets.Table.prototype); PodcastEpisodeTable.prototype = Object.create(AIRTIME.widgets.Table.prototype);
PodcastEpisodeTable.prototype.constructor = PodcastEpisodeTable; PodcastEpisodeTable.prototype.constructor = PodcastEpisodeTable;
@ -459,7 +467,6 @@ var AIRTIME = (function (AIRTIME) {
*/ */
mod.addPodcast = function () { mod.addPodcast = function () {
$.post(endpoint, $("#podcast_url_dialog").find("form").serialize(), function(json) { $.post(endpoint, $("#podcast_url_dialog").find("form").serialize(), function(json) {
_initAppFromResponse(json);
// Open the episode view for the newly created podcast in the left-hand pane // Open the episode view for the newly created podcast in the left-hand pane
AIRTIME.library.podcastEpisodeTableWidget.reload(JSON.parse(json.podcast).id); AIRTIME.library.podcastEpisodeTableWidget.reload(JSON.parse(json.podcast).id);
AIRTIME.library.podcastTableWidget.clearSelection(); AIRTIME.library.podcastTableWidget.clearSelection();
@ -613,6 +620,9 @@ var AIRTIME = (function (AIRTIME) {
connectToSortable: $("#show_builder_table, .active-tab .spl_sortable") connectToSortable: $("#show_builder_table, .active-tab .spl_sortable")
}); });
} }
},
fnDrawCallback: function () {
AIRTIME.library.drawEmptyPlaceholder(this);
} }
} }
); );

View File

@ -10,7 +10,21 @@ var AIRTIME = (function(AIRTIME) {
} }
//Table widget constructor //Table widget constructor
var Table = function(wrapperDOMNode, bItemSelection, toolbarButtons, dataTablesOptions) { /**
*
*
* @param wrapperDOMNode
* @param {boolean} bItemSelection
* @param {Object} toolbarButtons
* @param {Object} dataTablesOptions
* @param {Object} [emptyPlaceholder]
* @param {string} emptyPlaceholder.html
* @param {string} emptyPlaceholder.iconClass
*
* @returns {Table}
* @constructor
*/
var Table = function(wrapperDOMNode, bItemSelection, toolbarButtons, dataTablesOptions, emptyPlaceholder) {
var self = this; var self = this;
@ -34,6 +48,7 @@ var AIRTIME = (function(AIRTIME) {
//Save some of the constructor parameters //Save some of the constructor parameters
self._$wrapperDOMNode = $(wrapperDOMNode); self._$wrapperDOMNode = $(wrapperDOMNode);
self._toolbarButtons = toolbarButtons; self._toolbarButtons = toolbarButtons;
self._emptyPlaceholder = emptyPlaceholder;
// Exclude the leftmost column if we're implementing item selection // Exclude the leftmost column if we're implementing item selection
self._colVisExcludeColumns = bItemSelection ? [0] : []; self._colVisExcludeColumns = bItemSelection ? [0] : [];
@ -93,6 +108,9 @@ var AIRTIME = (function(AIRTIME) {
if (options.fnCreatedRow) { if (options.fnCreatedRow) {
options.fnCreatedRow = options.fnCreatedRow.bind(this); options.fnCreatedRow = options.fnCreatedRow.bind(this);
} }
if (options.fnDrawCallback) {
options.fnDrawCallback = options.fnDrawCallback.bind(this);
}
self._datatable = self._$wrapperDOMNode.dataTable(options); self._datatable = self._$wrapperDOMNode.dataTable(options);
// self._datatable.fnDraw(); //Load the AJAX data now that our event handlers have been bound. // self._datatable.fnDraw(); //Load the AJAX data now that our event handlers have been bound.
@ -372,6 +390,10 @@ var AIRTIME = (function(AIRTIME) {
return this._selectedRows; return this._selectedRows;
}; };
Table.prototype.getEmptyPlaceholder = function () {
return this._emptyPlaceholder;
};
Table.prototype._handleAjaxError = function(r) { Table.prototype._handleAjaxError = function(r) {
// If the request was denied due to permissioning // If the request was denied due to permissioning
if (r.status === 403) { if (r.status === 403) {