SAAS-1061 - implement podcast list view skeleton; small bugfixes

Conflicts:
	airtime_mvc/public/js/airtime/library/library.js
This commit is contained in:
Duncan Sommerville 2015-09-14 18:26:28 -04:00
parent 28493497fd
commit 8c65ba8f66
16 changed files with 406 additions and 333 deletions

View file

@ -31,6 +31,7 @@ require_once "Auth.php";
require_once "interface/OAuth2.php"; require_once "interface/OAuth2.php";
require_once "TaskManager.php"; require_once "TaskManager.php";
require_once "UsabilityHints.php"; require_once "UsabilityHints.php";
require_once "MediaType.php";
require_once __DIR__.'/models/formatters/LengthFormatter.php'; require_once __DIR__.'/models/formatters/LengthFormatter.php';
require_once __DIR__.'/services/CeleryService.php'; require_once __DIR__.'/services/CeleryService.php';
require_once __DIR__.'/services/SoundcloudService.php'; require_once __DIR__.'/services/SoundcloudService.php';

View file

@ -36,6 +36,8 @@ set_include_path(implode(PATH_SEPARATOR, array(
))); )));
set_include_path(APPLICATION_PATH . 'common' . PATH_SEPARATOR . get_include_path()); set_include_path(APPLICATION_PATH . 'common' . PATH_SEPARATOR . get_include_path());
set_include_path(APPLICATION_PATH . 'common/enum' . PATH_SEPARATOR . get_include_path());
set_include_path(APPLICATION_PATH . 'common/interface' . PATH_SEPARATOR . get_include_path());
//Propel classes. //Propel classes.
set_include_path(APPLICATION_PATH . 'models' . PATH_SEPARATOR . get_include_path()); set_include_path(APPLICATION_PATH . 'models' . PATH_SEPARATOR . get_include_path());

View file

@ -0,0 +1,47 @@
<?php
/**
* Basic enumeration implementation; from http://stackoverflow.com/questions/254514/php-and-enumerations
*
* Class Enum
*/
abstract class Enum {
const __default = NULL;
private static $constCacheArray = NULL;
private function __construct() {}
private static function getConstants() {
if (self::$constCacheArray == NULL) {
self::$constCacheArray = [];
}
$calledClass = get_called_class();
if (!array_key_exists($calledClass, self::$constCacheArray)) {
$reflect = new ReflectionClass($calledClass);
self::$constCacheArray[$calledClass] = $reflect->getConstants();
}
return self::$constCacheArray[$calledClass];
}
public static function isValidName($name, $strict = false) {
$constants = self::getConstants();
if ($strict) {
return array_key_exists($name, $constants);
}
$keys = array_map('strtolower', array_keys($constants));
return in_array(strtolower($name), $keys);
}
public static function isValidValue($value) {
$values = array_values(self::getConstants());
return in_array($value, $values, $strict = true);
}
public static function getDefault() {
return static::__default;
}
}

View file

@ -0,0 +1,14 @@
<?php
require_once "Enum.php";
final class MediaType extends Enum {
const __default = self::FILE;
const FILE = 1;
const PLAYLIST = 2;
const BLOCK = 3;
const WEBSTREAM = 4;
const PODCAST = 5;
}

View file

@ -66,22 +66,21 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
<a href="#"><?php echo _("Webstream") ?></a> <a href="#"><?php echo _("Webstream") ?></a>
</li> </li>
</ul> </ul>
<a href="/Plupload"> <a href="/plupload">
<button id="add_media_btn" class="btn btn-small dashboard-btn btn-new"> <button id="add_media_btn" class="btn btn-small dashboard-btn btn-new">
<span><?php echo _("Upload") ?></span> <span><?php echo _("Upload") ?></span>
</button> </button>
</a> </a>
</div> </div>
<div class="media_type_selector top-link" data-selection-id="1">
<a href="/showbuilder#"><i class='icon-home icon-white'></i><?php echo _("Dashboard") ?></a></div> <div class="media_type_selector top-link" data-selection-id="<?php echo MediaType::getDefault(); ?>">
<div class="media_type_selector dashboard_sub_nav" data-selection-id="1"> <a href="/showbuilder#">
<a href="/showbuilder#tracks"><i class='icon-music icon-white'></i><?php echo _("Tracks") ?></a></div> <i class='icon-home icon-white'></i>
<div class="media_type_selector dashboard_sub_nav" data-selection-id="2"> <?php echo _("Dashboard") ?>
<a href="/showbuilder#playlists"><i class='icon-list icon-white'></i><?php echo _("Playlists") ?></a></div> </a>
<div class="media_type_selector dashboard_sub_nav" data-selection-id="3"> </div>
<a href="/showbuilder#smart-blocks"><i class='icon-time icon-white'></i><?php echo _("Smart Blocks") ?></a></div> <?php $subnavPrefix = "/showbuilder"; require_once APPLICATION_PATH . "views/scripts/partialviews/dashboard-sub-nav.php"; ?>
<div class="media_type_selector dashboard_sub_nav" data-selection-id="4">
<a href="/showbuilder#webstreams"><i class='icon-random icon-white'></i><?php echo _("Webstreams") ?></a></div>
<hr style="margin-left: 5px; margin-right: 5px"> <hr style="margin-left: 5px; margin-right: 5px">
<div id="nav"> <div id="nav">
<?php echo $this->navigation()->menu(); ?> <?php echo $this->navigation()->menu(); ?>
@ -90,7 +89,6 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
<?php <?php
$partitions = Application_Model_Systemstatus::GetDiskInfo(); $partitions = Application_Model_Systemstatus::GetDiskInfo();
$status = new StdClass; $status = new StdClass;
$partitions = $partitions;
$disk = $partitions[0]; $disk = $partitions[0];
$used = $disk->totalSpace-$disk->totalFreeSpace; $used = $disk->totalSpace-$disk->totalFreeSpace;
$total = $disk->totalSpace; $total = $disk->totalSpace;

View file

@ -806,21 +806,17 @@ SQL;
$unionTable = "({$plTable} UNION {$blTable} UNION {$fileTable} UNION {$streamTable}) AS RESULTS"; $unionTable = "({$plTable} UNION {$blTable} UNION {$fileTable} UNION {$streamTable}) AS RESULTS";
//choose which table we need to select data from. //choose which table we need to select data from.
// TODO : use constants instead of numbers -- RG
switch ($type) { switch ($type) {
case 0: case MediaType::FILE:
$fromTable = $unionTable;
break;
case 1:
$fromTable = $fileTable." AS File"; //need an alias for the table if it's standalone. $fromTable = $fileTable." AS File"; //need an alias for the table if it's standalone.
break; break;
case 2: case MediaType::PLAYLIST:
$fromTable = $plTable." AS Playlist"; //need an alias for the table if it's standalone. $fromTable = $plTable." AS Playlist"; //need an alias for the table if it's standalone.
break; break;
case 3: case MediaType::BLOCK:
$fromTable = $blTable." AS Block"; //need an alias for the table if it's standalone. $fromTable = $blTable." AS Block"; //need an alias for the table if it's standalone.
break; break;
case 4: case MediaType::WEBSTREAM:
$fromTable = $streamTable." AS StreamTable"; //need an alias for the table if it's standalone. $fromTable = $streamTable." AS StreamTable"; //need an alias for the table if it's standalone.
break; break;
default: default:

View file

@ -0,0 +1,30 @@
<div class="media_type_selector dashboard_sub_nav" data-selection-id="<?php echo MediaType::FILE ?>">
<a href="<?php echo $subnavPrefix; ?>#tracks">
<i class='icon-music icon-white'></i>
<span class="selector-name"><?php echo _("Tracks") ?></span>
</a>
</div>
<div class="media_type_selector dashboard_sub_nav" data-selection-id="<?php echo MediaType::PLAYLIST ?>">
<a href="<?php echo $subnavPrefix; ?>#playlists">
<i class='icon-list icon-white'></i>
<span class="selector-name"><?php echo _("Playlists") ?></span>
</a>
</div>
<div class="media_type_selector dashboard_sub_nav" data-selection-id="<?php echo MediaType::BLOCK ?>">
<a href="<?php echo $subnavPrefix; ?>#smart-blocks">
<i class='icon-time icon-white'></i>
<span class="selector-name"><?php echo _("Smart Blocks") ?></span>
</a>
</div>
<div class="media_type_selector dashboard_sub_nav" data-selection-id="<?php echo MediaType::WEBSTREAM ?>">
<a href="<?php echo $subnavPrefix; ?>#webstreams">
<i class='icon-random icon-white'></i>
<span class="selector-name"><?php echo _("Webstreams") ?></span>
</a>
</div>
<div class="media_type_selector dashboard_sub_nav" data-selection-id="<?php echo MediaType::PODCAST ?>">
<a href="<?php echo $subnavPrefix; ?>#podcasts">
<i class='icon-headphones icon-white'></i>
<span class="selector-name"><?php echo _("Podcasts") ?></span>
</a>
</div>

View file

@ -1,30 +1,7 @@
<div><!-- jQuery UI changes the styling on the outermost div; use a blank div so as not to break the .wrapper styling--> <div><!-- jQuery UI changes the styling on the outermost div; use a blank div so as not to break the .wrapper styling-->
<div class="wrapper"> <div class="wrapper">
<div id="media_selector_wrapper"> <div id="media_selector_wrapper">
<div class="media_type_selector dashboard_sub_nav" data-selection-id="1"> <?php $subnavPrefix = ""; require_once APPLICATION_PATH . "views/scripts/partialviews/dashboard-sub-nav.php"; ?>
<a href="#tracks">
<i class='icon-music icon-white'></i>
<span class="selector-name"><?php echo _("Tracks") ?></span>
</a>
</div>
<div class="media_type_selector dashboard_sub_nav" data-selection-id="2">
<a href="#playlists">
<i class='icon-list icon-white'></i>
<span class="selector-name"><?php echo _("Playlists") ?></span>
</a>
</div>
<div class="media_type_selector dashboard_sub_nav" data-selection-id="3">
<a href="#smart-blocks">
<i class='icon-time icon-white'></i>
<span class="selector-name"><?php echo _("Smart Blocks") ?></span>
</a>
</div>
<div class="media_type_selector dashboard_sub_nav" data-selection-id="4">
<a href="#webstreams">
<i class='icon-random icon-white'></i>
<span class="selector-name"><?php echo _("Webstreams") ?></span>
</a>
</div>
</div> </div>
<?php echo $this->csrf ?> <?php echo $this->csrf ?>

View file

@ -15,6 +15,7 @@
</div> </div>
<div class="outer-datatable-wrapper"> <div class="outer-datatable-wrapper">
<table id="library_display" cellpadding="0" cellspacing="0" class="datatable"></table> <table id="library_display" cellpadding="0" cellspacing="0" class="datatable"></table>
<table id="podcast_table" cellpadding="0" cellspacing="0" class="datatable"></table>
</div> </div>
</div> </div>

View file

@ -1,28 +0,0 @@
{
"1": {
"media": "tracks",
"icon": "icon-music",
"subtext": "Click 'Upload' to add some now.",
"href": "http://sourcefabric.booktype.pro/airtime-pro-for-broadcasters/add-media/"
},
"2": {
"media": "playlists",
"icon": "icon-list",
"subtext": "Click 'New' to create one now.",
"href": "http://sourcefabric.booktype.pro/airtime-pro-for-broadcasters/library/"
},
"3": {
"media": "smart blocks",
"icon": "icon-time",
"subtext": "Click 'New' to create one now.",
"href": "http://sourcefabric.booktype.pro/airtime-pro-for-broadcasters/library/"
},
"4": {
"media": "webstreams",
"icon": "icon-random",
"subtext": "Click 'New' to create one now.",
"href": "http://sourcefabric.booktype.pro/airtime-pro-for-broadcasters/library/"
},
"unauthorized": "You don't have permission to view the library."
}

View file

@ -716,3 +716,15 @@ th.library_checkbox {
background-color: #FF5D1A !important; background-color: #FF5D1A !important;
height: 38px !important; height: 38px !important;
} }
/* ~~~~~~~~~~~~~~~~
Podcasts
~~~~~~~~~~~~~~~~ */
#podcast_table {
display: none;
}
/* ~~~~~~~~~~~~~~~~
END Podcasts
~~~~~~~~~~~~~~~~ */

View file

@ -3598,7 +3598,7 @@ button.btn-icon-text > i.icon-white {
.media_type_selector a { .media_type_selector a {
text-decoration: none; text-decoration: none;
color: #cecece; color: #cecece;
padding: 10px 10px 10px 10px; padding: 10px 0 10px 10px;
display: block; display: block;
} }

View file

@ -80,22 +80,20 @@ var AIRTIME = (function(AIRTIME) {
var libEmpty = $('#library_empty'); var libEmpty = $('#library_empty');
if (emptyRow.length > 0) { if (emptyRow.length > 0) {
emptyRow.hide(); emptyRow.hide();
var mediaType = parseInt($('.media_type_selector.selected').attr('data-selection-id')), var mediaType = parseInt($('.media_type_selector.selected').data('selection-id')),
img = $('#library_empty_image'); img = $('#library_empty_image');
// 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() { img.removeClass(function() {
return $( this ).attr( "class" ); return $( this ).attr( "class" );
}); });
// TODO: once the new manual pages are added, change links!
$.getJSON( "ajax/library_placeholders.json", function( data ) { var opts = AIRTIME.library.placeholder(mediaType);
var opts = data[mediaType];
img.addClass("icon-white " + opts.icon); img.addClass("icon-white " + opts.icon);
$('#library_empty_text').html( $('#library_empty_text').html(
$.i18n._("You haven't added any " + opts.media + ".") $.i18n._("You haven't added any " + opts.media + ".")
+ "<br/>" + $.i18n._(opts.subtext) + "<br/>" + $.i18n._(opts.subtext)
+ "<br/><a target='_blank' href='" + opts.href + "'>" + $.i18n._("Learn about " + opts.media) + "</a>" + "<br/><a target='_blank' href='" + opts.href + "'>" + $.i18n._("Learn about " + opts.media) + "</a>"
); );
});
libEmpty.show(); libEmpty.show();
} else { } else {
@ -333,13 +331,13 @@ var AIRTIME = (function(AIRTIME) {
return; return;
} }
var selection = $(".media_type_selector.selected").attr("data-selection-id"); var selection = $(".media_type_selector.selected").data("selection-id");
if (selection == 2) { if (selection == AIRTIME.library.MediaTypeEnum.PLAYLIST) {
AIRTIME.playlist.fnNew(); AIRTIME.playlist.fnNew();
} else if (selection == 3) { } else if (selection == AIRTIME.library.MediaTypeEnum.BLOCK) {
AIRTIME.playlist.fnNewBlock(); AIRTIME.playlist.fnNewBlock();
} else if (selection == 4) { } else if (selection == AIRTIME.library.MediaTypeEnum.WEBSTREAM) {
AIRTIME.playlist.fnWsNew(); AIRTIME.playlist.fnWsNew();
} }
}); });

View file

@ -59,6 +59,67 @@ var AIRTIME = (function(AIRTIME) {
} }
mod = AIRTIME.library; mod = AIRTIME.library;
/* ############################################
CONFIGURATION
############################################ */
mod.MediaTypeEnum = Object.freeze({
DEFAULT: 1,
FILE: 1,
PLAYLIST: 2,
BLOCK: 3,
WEBSTREAM: 4,
PODCAST: 5
});
// TODO: once the new manual pages are added, change links!
mod.placeholder = function(mediaType) {
switch (mediaType) {
// TODO: remove duplication in a nice way?
case MediaTypeEnum.FILE:
return {
"media": "tracks",
"icon": "icon-music",
"subtext": "Click 'Upload' to add some now.",
"href": "http://sourcefabric.booktype.pro/airtime-pro-for-broadcasters/add-media/"
};
case MediaTypeEnum.PLAYLIST:
return {
"media": "playlists",
"icon": "icon-list",
"subtext": "Click 'New' to create one now.",
"href": "http://sourcefabric.booktype.pro/airtime-pro-for-broadcasters/library/"
};
case MediaTypeEnum.BLOCK:
return {
"media": "smart blocks",
"icon": "icon-time",
"subtext": "Click 'New' to create one now.",
"href": "http://sourcefabric.booktype.pro/airtime-pro-for-broadcasters/library/"
};
case MediaTypeEnum.WEBSTREAM:
return {
"media": "webstreams",
"icon": "icon-random",
"subtext": "Click 'New' to create one now.",
"href": "http://sourcefabric.booktype.pro/airtime-pro-for-broadcasters/library/"
};
case MediaTypeEnum.PODCAST:
return {
"media": "podcasts",
"icon": "icon-headphones",
"subtext": "Click 'Add' to create one now.",
"href": "http://sourcefabric.booktype.pro/airtime-pro-for-broadcasters/library/"
};
default:
break;
}
};
/* ############################################
END CONFIGURATION
############################################ */
mod.getChosenItemsLength = function(){ mod.getChosenItemsLength = function(){
var cItem, var cItem,
selected, selected,
@ -199,10 +260,10 @@ var AIRTIME = (function(AIRTIME) {
}; };
mod.checkNewButton = function() { mod.checkNewButton = function() {
var selected = $(".media_type_selector.selected").attr("data-selection-id"), var selected = $(".media_type_selector.selected").data("selection-id"),
check = false; check = false;
if (selected != 1) { if (selected != AIRTIME.library.MediaTypeEnum.FILE) {
check = true; check = true;
} }
@ -455,131 +516,13 @@ var AIRTIME = (function(AIRTIME) {
var colReorderMap = new Array(); var colReorderMap = new Array();
$libTable = $libContent.find("table"); $libTable = $("#library_display");
function getTableHeight() { /* ############################################
return $libContent.height() - 175; DATATABLES
} ############################################ */
function setColumnFilter(oTable){ mod.libraryDataTable = $libTable.dataTable({
// TODO : remove this dirty hack once js is refactored
if (!oTable.fnSettings()) { return ; }
var aoCols = oTable.fnSettings().aoColumns;
var colsForAdvancedSearch = new Array();
var advanceSearchDiv = $("div#advanced_search");
advanceSearchDiv.empty();
$.each(aoCols, function(i,ele){
if (ele.bSearchable) {
var currentColId = ele._ColReorder_iOrigCol;
var inputClass = 'filter_column filter_number_text';
var labelStyle = "style='margin-right:35px;'";
if (libraryColumnTypes[ele.mDataProp] != "s") {
inputClass = 'filterColumn filter_number_range';
labelStyle = "";
}
if (ele.bVisible) {
advanceSearchDiv.append(
"<div id='advanced_search_col_"+currentColId+"' class='control-group'>" +
"<label class='control-label'"+labelStyle+">"+ele.sTitle+"</label>" +
"<div id='"+ele.mDataProp+"' class='controls "+inputClass+"'></div>" +
"</div>");
} else {
advanceSearchDiv.append(
"<div id='advanced_search_col_"+currentColId+"' class='control-group' style='display:none;'>" +
"<label class='control-label'"+labelStyle+">"+ele.sTitle+"</label>" +
"<div id='"+ele.mDataProp+"' class='controls "+inputClass+"'></div>" +
"</div>");
}
if (libraryColumnTypes[ele.mDataProp] == "s") {
var obj = { sSelector: "#"+ele.mDataProp }
} else {
var obj = { sSelector: "#"+ele.mDataProp, type: "number-range" }
}
colsForAdvancedSearch.push(obj);
} else {
colsForAdvancedSearch.push(null);
}
});
oTable.columnFilter({
aoColumns: colsForAdvancedSearch,
bUseColVis: true,
sPlaceHolder: "head:before"
}
);
}
function setFilterElement(iColumn, bVisible){
var actualId = colReorderMap[iColumn];
var selector = "div#advanced_search_col_"+actualId;
var $el = $(selector);
if (bVisible) {
$el.show();
} else {
$el.hide();
}
}
function getLibraryDatatableStrings() {
//Set up the datatables string translation table with different strings depending on
//whether you're viewing files, playlists, smart blocks, etc.
var type = parseInt($(".media_type_selector.selected").attr("data-selection-id"));
type = (type === undefined) ? 1 : type;
//FIXME: The code that calls this function doesn't work as intended because you can't
// change the oLanguage property of a datatable dynamically. :(
switch (type) {
/*
case 0:
return getDatatablesStrings({
"sEmptyTable": $.i18n._("No files found"),
});
break;
case 1:
return getDatatablesStrings({
"sEmptyTable": $.i18n._("No playlists found"),
});
break;
case 2:
return getDatatablesStrings({
"sEmptyTable": $.i18n._("No smart blocks found"),
});
break;*/
default:
return getDatatablesStrings({
"sEmptyTable": $.i18n._(""),
"sZeroRecords": $.i18n._("No matching results found.")
//"oPaginate": {
// "sFirst": "<<",
// "sLast": ">>",
// "sNext": ">",
// "sPrevious": "<"
//}
});
break;
}
}
function handleAjaxError(r) {
// If the request was denied due to permissioning
if (r.status === 403) {
// Hide the processing div
$("#library_display_wrapper").find(".dt-process-rel").hide();
$.getJSON( "ajax/library_placeholders.json", function( data ) {
$('#library_empty_text').text($.i18n._(data.unauthorized));
}) ;
$('#library_empty').show();
}
}
oTable = $libTable.dataTable( {
// put hidden columns at the top to insure they can never be visible // put hidden columns at the top to insure they can never be visible
// on the table through column reordering. // on the table through column reordering.
@ -688,10 +631,10 @@ var AIRTIME = (function(AIRTIME) {
oData.iCreate = parseInt(oData.iCreate, 10); oData.iCreate = parseInt(oData.iCreate, 10);
}, },
"sAjaxSource": baseUrl+"Library/contents-feed", "sAjaxSource": baseUrl + "Library/contents-feed",
"sAjaxDataProp": "files", "sAjaxDataProp": "files",
"fnServerData": function ( sSource, aoData, fnCallback ) { "fnServerData": function (sSource, aoData, fnCallback) {
/* /*
* The real validation check is done in * The real validation check is done in
* dataTables.columnFilter.js We also need to check it here * dataTables.columnFilter.js We also need to check it here
@ -702,13 +645,13 @@ var AIRTIME = (function(AIRTIME) {
var advSearchFields = $("div#advanced_search").children(':visible'); var advSearchFields = $("div#advanced_search").children(':visible');
var advSearchValid = validateAdvancedSearch(advSearchFields); var advSearchValid = validateAdvancedSearch(advSearchFields);
var type; var type;
aoData.push( { name: "format", value: "json"} ); aoData.push({name: "format", value: "json"});
aoData.push( { name: "advSearch", value: advSearchValid} ); aoData.push({name: "advSearch", value: advSearchValid});
// push whether to search files/playlists or all. // push whether to search files/playlists or all.
type = $(".media_type_selector.selected").attr("data-selection-id"); type = $(".media_type_selector.selected").data("selection-id");
type = (type === undefined) ? 1 : type; type = (type === undefined) ? AIRTIME.library.MediaTypeEnum.DEFAULT : type;
aoData.push( { name: "type", value: type} ); aoData.push({name: "type", value: type});
//getUsabilityHint(); //getUsabilityHint();
@ -719,7 +662,7 @@ var AIRTIME = (function(AIRTIME) {
"data": aoData, "data": aoData,
"success": fnCallback, "success": fnCallback,
"error": handleAjaxError "error": handleAjaxError
}).done(function(data) { }).done(function (data) {
if (data.iTotalRecords > data.iTotalDisplayRecords) { if (data.iTotalRecords > data.iTotalDisplayRecords) {
$('#filter_message').text( $('#filter_message').text(
$.i18n._("Filtering out ") + (data.iTotalRecords - data.iTotalDisplayRecords) $.i18n._("Filtering out ") + (data.iTotalRecords - data.iTotalDisplayRecords)
@ -736,25 +679,25 @@ var AIRTIME = (function(AIRTIME) {
}); });
}, },
"fnRowCallback": AIRTIME.library.fnRowCallback, "fnRowCallback": AIRTIME.library.fnRowCallback,
"fnCreatedRow": function( nRow, aData, iDataIndex ) { "fnCreatedRow": function (nRow, aData, iDataIndex) {
// add checkbox // add checkbox
$(nRow).find('td.library_checkbox').html("<input type='checkbox' name='cb_"+aData.id+"'>"); $(nRow).find('td.library_checkbox').html("<input type='checkbox' name='cb_" + aData.id + "'>");
$(nRow).find('td.library_actions') $(nRow).find('td.library_actions')
.text("...") .text("...")
.on('click', function(e) { .on('click', function (e) {
$(this).contextMenu({x: $(e.target).offset().left, y: $(e.target).offset().top}) $(this).contextMenu({x: $(e.target).offset().left, y: $(e.target).offset().top})
}).html("<div class='library_actions_btn'>...</div>"); }).html("<div class='library_actions_btn'>...</div>");
// add audio preview image/button // add audio preview image/button
if (aData.ftype === "audioclip") { if (aData.ftype === "audioclip") {
$(nRow).find('td.library_type').html('<img title="'+$.i18n._("Track preview")+'" src="'+baseUrl+'css/images/icon_audioclip.png">'); $(nRow).find('td.library_type').html('<img title="' + $.i18n._("Track preview") + '" src="' + baseUrl + 'css/images/icon_audioclip.png">');
} else if (aData.ftype === "playlist") { } else if (aData.ftype === "playlist") {
$(nRow).find('td.library_type').html('<img title="'+$.i18n._("Playlist preview")+'" src="'+baseUrl+'css/images/icon_playlist.png">'); $(nRow).find('td.library_type').html('<img title="' + $.i18n._("Playlist preview") + '" src="' + baseUrl + 'css/images/icon_playlist.png">');
} else if (aData.ftype === "block") { } else if (aData.ftype === "block") {
$(nRow).find('td.library_type').html('<img title="'+$.i18n._("Smart Block")+'" src="'+baseUrl+'css/images/icon_smart-block.png">'); $(nRow).find('td.library_type').html('<img title="' + $.i18n._("Smart Block") + '" src="' + baseUrl + 'css/images/icon_smart-block.png">');
} else if (aData.ftype === "stream") { } else if (aData.ftype === "stream") {
$(nRow).find('td.library_type').html('<img title="'+$.i18n._("Webstream preview")+'" src="'+baseUrl+'css/images/icon_webstream.png">'); $(nRow).find('td.library_type').html('<img title="' + $.i18n._("Webstream preview") + '" src="' + baseUrl + 'css/images/icon_webstream.png">');
} }
if (aData.is_scheduled) { if (aData.is_scheduled) {
@ -769,8 +712,8 @@ var AIRTIME = (function(AIRTIME) {
} }
// add the play function to the library_type td // add the play function to the library_type td
$(nRow).find('td.library_type').click(function(){ $(nRow).find('td.library_type').click(function () {
if (aData.ftype === 'playlist' && aData.length !== '0.0'){ if (aData.ftype === 'playlist' && aData.length !== '0.0') {
open_playlist_preview(aData.audioFile, 0); open_playlist_preview(aData.audioFile, 0);
} else if (aData.ftype === 'audioclip') { } else if (aData.ftype === 'audioclip') {
if (isAudioSupported(aData.mime)) { if (isAudioSupported(aData.mime)) {
@ -787,7 +730,7 @@ var AIRTIME = (function(AIRTIME) {
}); });
}, },
// remove any selected nodes before the draw. // remove any selected nodes before the draw.
"fnPreDrawCallback": function( oSettings ) { "fnPreDrawCallback": function (oSettings) {
// make sure any dragging helpers are removed or else they'll be // make sure any dragging helpers are removed or else they'll be
// stranded on the screen. // stranded on the screen.
@ -822,6 +765,143 @@ var AIRTIME = (function(AIRTIME) {
}); });
/* TODO: implement podcast datatable
* mod.podcastDataTable = $("#podcast_table").dataTable({});
*/
mod.podcastDataTable = mod.libraryDataTable;
/* ############################################
END DATATABLES
############################################ */
function getTableHeight() {
return $libContent.height() - 175;
}
function setColumnFilter(oTable){
// TODO : remove this dirty hack once js is refactored
if (!oTable.fnSettings()) { return ; }
var aoCols = oTable.fnSettings().aoColumns;
var colsForAdvancedSearch = new Array();
var advanceSearchDiv = $("div#advanced_search");
advanceSearchDiv.empty();
$.each(aoCols, function(i,ele){
if (ele.bSearchable) {
var currentColId = ele._ColReorder_iOrigCol;
var inputClass = 'filter_column filter_number_text';
var labelStyle = "style='margin-right:35px;'";
if (libraryColumnTypes[ele.mDataProp] != "s") {
inputClass = 'filterColumn filter_number_range';
labelStyle = "";
}
if (ele.bVisible) {
advanceSearchDiv.append(
"<div id='advanced_search_col_"+currentColId+"' class='control-group'>" +
"<label class='control-label'"+labelStyle+">"+ele.sTitle+"</label>" +
"<div id='"+ele.mDataProp+"' class='controls "+inputClass+"'></div>" +
"</div>");
} else {
advanceSearchDiv.append(
"<div id='advanced_search_col_"+currentColId+"' class='control-group' style='display:none;'>" +
"<label class='control-label'"+labelStyle+">"+ele.sTitle+"</label>" +
"<div id='"+ele.mDataProp+"' class='controls "+inputClass+"'></div>" +
"</div>");
}
if (libraryColumnTypes[ele.mDataProp] == "s") {
var obj = { sSelector: "#"+ele.mDataProp }
} else {
var obj = { sSelector: "#"+ele.mDataProp, type: "number-range" }
}
colsForAdvancedSearch.push(obj);
} else {
colsForAdvancedSearch.push(null);
}
});
oTable.columnFilter({
aoColumns: colsForAdvancedSearch,
bUseColVis: true,
sPlaceHolder: "head:before"
}
);
}
function setFilterElement(iColumn, bVisible){
var actualId = colReorderMap[iColumn];
var selector = "div#advanced_search_col_"+actualId;
var $el = $(selector);
if (bVisible) {
$el.show();
} else {
$el.hide();
}
}
function getLibraryDatatableStrings() {
//Set up the datatables string translation table with different strings depending on
//whether you're viewing files, playlists, smart blocks, etc.
var type = parseInt($(".media_type_selector.selected").data("selection-id"));
type = (type === undefined) ? AIRTIME.library.MediaTypeEnum.DEFAULT : type;
//FIXME: The code that calls this function doesn't work as intended because you can't
// change the oLanguage property of a datatable dynamically. :(
switch (type) {
/*
case 0:
return getDatatablesStrings({
"sEmptyTable": $.i18n._("No files found"),
});
break;
case 1:
return getDatatablesStrings({
"sEmptyTable": $.i18n._("No playlists found"),
});
break;
case 2:
return getDatatablesStrings({
"sEmptyTable": $.i18n._("No smart blocks found"),
});
break;*/
default:
return getDatatablesStrings({
"sEmptyTable": $.i18n._(""),
"sZeroRecords": $.i18n._("No matching results found.")
//"oPaginate": {
// "sFirst": "<<",
// "sLast": ">>",
// "sNext": ">",
// "sPrevious": "<"
//}
});
break;
}
}
function handleAjaxError(r) {
// If the request was denied due to permissioning
if (r.status === 403) {
// Hide the processing div
$("#library_display_wrapper").find(".dt-process-rel").hide();
$('#library_empty_text').text($.i18n._("You don't have permission to view the library."));
$('#library_empty').show();
}
}
var selected = $("a[href$='"+location.hash+"']");
if (selected.parent().data("selection-id") == AIRTIME.library.MediaTypeEnum.PODCAST) {
$("#library_display_wrapper").hide();
oTable = mod.podcastDataTable.show();
} else {
oTable = mod.libraryDataTable;
}
setColumnFilter(oTable); setColumnFilter(oTable);
oTable.fnSetFilteringDelay(350); oTable.fnSetFilteringDelay(350);

View file

@ -37,90 +37,13 @@ $(document).ready(function () {
self.recentUploadsTable.fnDraw(); //Only works because we're using bServerSide self.recentUploadsTable.fnDraw(); //Only works because we're using bServerSide
//In DataTables 1.10 and greater, we can use .fnAjaxReload() //In DataTables 1.10 and greater, we can use .fnAjaxReload()
}); });
this.on("complete", function() {
this.on("queuecomplete", function() {
uploadProgress = false; uploadProgress = false;
}); });
} }
}; };
/*
var uploader = new plupload.Uploader({
runtimes: 'html5, flash, html4',
browse_button: 'pickfiles',
container: $("#container"),
url : baseUrl+'rest/media',
filters : [
{title: "Audio Files", extensions: "ogg,mp3,oga,flac,wav,m4a,mp4,opus,aac,oga,mp1,mp2,wma,au"}
],
multipart_params : {
"csrf_token" : $("#csrf").attr('value')
},
init: {
PostInit: function() {
document.getElementById('filelist').innerHTML = '';
document.getElementById('uploadfiles').onclick = function() {
uploader.start();
return false;
};
},
FilesAdded: function(up, files) {
plupload.each(files, function(file) {
document.getElementById('filelist').innerHTML += '<div id="' + file.id + '">' + file.name + ' (' + plupload.formatSize(file.size) + ') <b></b></div>';
});
},
UploadProgress: function(up, file) {
document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = '<span>' + file.percent + "%</span>";
},
Error: function(up, err) {
document.getElementById('console').innerHTML += "\nError #" + err.code + ": " + err.message;
}
}
});
uploader.init();
*/
/*
$("#plupload_files").pluploadQueue({
// General settings
runtimes : 'gears, html5, html4',
url : baseUrl+'rest/media',
//chunk_size : '5mb', //Disabling chunking since we're using the File Upload REST API now
unique_names : 'true',
multiple_queues : 'true',
filters : [
{title: "Audio Files", extensions: "ogg,mp3,oga,flac,wav,m4a,mp4,opus,aac,oga,mp1,mp2,wma,au"}
],
multipart_params : {
"csrf_token" : $("#csrf").attr('value'),
}
});
uploader = $("#plupload_files").pluploadQueue();
uploader.bind('FileUploaded', function(up, file, json)
{
//Refresh the upload table:
self.recentUploadsTable.fnDraw(); //Only works because we're using bServerSide
//In DataTables 1.10 and greater, we can use .fnAjaxReload()
});
var uploadProgress = false;
uploader.bind('QueueChanged', function(){
uploadProgress = (uploader.files.length > 0);
});
uploader.bind('UploadComplete', function(){
uploadProgress = false;
});*/
$(window).bind('beforeunload', function () { $(window).bind('beforeunload', function () {
if (uploadProgress) { if (uploadProgress) {
return sprintf($.i18n._("You are currently uploading files. %sGoing to another screen will cancel the upload process. %sAre you sure you want to leave the page?"), return sprintf($.i18n._("You are currently uploading files. %sGoing to another screen will cancel the upload process. %sAre you sure you want to leave the page?"),
@ -173,11 +96,11 @@ $(document).ready(function () {
}); });
self.setupRecentUploadsTable = function () { self.setupRecentUploadsTable = function () {
recentUploadsTable = $("#recent_uploads_table").dataTable({ return $("#recent_uploads_table").dataTable({
"bJQueryUI": true, "bJQueryUI": true,
"bProcessing": false, "bProcessing": false,
"bServerSide": true, "bServerSide": true,
"sAjaxSource": '/Plupload/recent-uploads/format/json', "sAjaxSource": '/plupload/recent-uploads/format/json',
"sAjaxDataProp": 'files', "sAjaxDataProp": 'files',
"bSearchable": false, "bSearchable": false,
"bInfo": true, "bInfo": true,
@ -221,11 +144,13 @@ $(document).ready(function () {
areAnyFileImportsPending = true; areAnyFileImportsPending = true;
} }
} }
if (areAnyFileImportsPending) { if (areAnyFileImportsPending) {
//alert("pending uploads, starting refresh on timer"); //alert("pending uploads, starting refresh on timer");
self.startRefreshingRecentUploads(); self.startRefreshingRecentUploads();
} else { } else if (self.isRecentUploadsRefreshTimerActive) {
self.stopRefreshingRecentUploads(); self.stopRefreshingRecentUploads();
self.recentUploadsTable.fnDraw();
} }
// Update usability hint - in common.js // Update usability hint - in common.js
@ -239,7 +164,7 @@ $(document).ready(function () {
var sw = $(this)[0].scrollWidth, iw = $(this).innerWidth(); var sw = $(this)[0].scrollWidth, iw = $(this).innerWidth();
if (sw > iw) { if (sw > iw) {
$(this).stop().animate({ $(this).stop().animate({
textIndent: "-" + (sw + 2 - iw) + "px" textIndent: "-" + (sw - iw) + "px"
}, sw * 8); }, sw * 8);
} }
}, },
@ -251,37 +176,41 @@ $(document).ready(function () {
); );
} }
}); });
return recentUploadsTable;
}; };
self.isRecentUploadsRefreshTimerActive = false;
self.startRefreshingRecentUploads = function () { self.startRefreshingRecentUploads = function () {
if (self.isRecentUploadsRefreshTimerActive()) { //Prevent multiple timers from running if (!self.isRecentUploadsRefreshTimerActive) { //Prevent multiple timers from running
return; self.recentUploadsRefreshTimer = setInterval(function() {
self.recentUploadsTable.fnDraw();
}, 3000);
self.isRecentUploadsRefreshTimerActive = true;
} }
self.recentUploadsRefreshTimer = setInterval("self.recentUploadsTable.fnDraw()", 3000);
};
self.isRecentUploadsRefreshTimerActive = function () {
return (self.recentUploadsRefreshTimer != null);
}; };
self.stopRefreshingRecentUploads = function () { self.stopRefreshingRecentUploads = function () {
clearInterval(self.recentUploadsRefreshTimer); clearInterval(self.recentUploadsRefreshTimer);
self.recentUploadsRefreshTimer = null; self.isRecentUploadsRefreshTimerActive = false;
}; };
$("#upload_status_all").click(function () { $("#upload_status_all").click(function () {
if (self.uploadFilter !== "all") {
self.uploadFilter = "all"; self.uploadFilter = "all";
self.recentUploadsTable.fnPageChange(0).fnDraw(); self.recentUploadsTable.fnPageChange(0).fnDraw();
}
}); });
$("#upload_status_pending").click(function () { $("#upload_status_pending").click(function () {
if (self.uploadFilter !== "pending") {
self.uploadFilter = "pending"; self.uploadFilter = "pending";
self.recentUploadsTable.fnPageChange(0).fnDraw(); self.recentUploadsTable.fnPageChange(0).fnDraw();
}
}); });
$("#upload_status_failed").click(function () { $("#upload_status_failed").click(function () {
if (self.uploadFilter !== "failed") {
self.uploadFilter = "failed"; self.uploadFilter = "failed";
self.recentUploadsTable.fnPageChange(0).fnDraw(); self.recentUploadsTable.fnPageChange(0).fnDraw();
}
}); });
//Create the recent uploads table. //Create the recent uploads table.

View file

@ -137,8 +137,24 @@ AIRTIME = (function(AIRTIME) {
}); });
$(window).on('hashchange', function() { $(window).on('hashchange', function() {
var selected = $("a[href$='"+location.hash+"']"); var selected = $("a[href$='"+location.hash+"']"),
var dashboardLink = $(".media_type_selector:first"); dashboardLink = $(".media_type_selector:first"),
t;
if (selected.parent().data("selection-id") == AIRTIME.library.MediaTypeEnum.PODCAST) {
$("#library_display_wrapper").hide();
$("#podcast_table").show();
t = AIRTIME.library.podcastDataTable;
} else {
if (typeof oTable === 'undefined') {
oTable = AIRTIME.library.libraryDataTable;
}
$("#library_display_wrapper").show();
$("#podcast_table").hide();
t = oTable;
}
dashboardLink.find("a").attr("href", selected.attr("href")); dashboardLink.find("a").attr("href", selected.attr("href"));
AIRTIME.library.selectNone(); AIRTIME.library.selectNone();
@ -146,7 +162,7 @@ AIRTIME = (function(AIRTIME) {
$(this).removeClass("selected"); $(this).removeClass("selected");
}); });
selected.parent().addClass("selected"); selected.parent().addClass("selected");
oTable.fnDraw(); t.fnDraw();
$("#library_filter").text(selected.text()); $("#library_filter").text(selected.text());
// Highlight the dashboard link // Highlight the dashboard link
dashboardLink.addClass("highlight"); dashboardLink.addClass("highlight");