Merge branch '2.2.x' of dev.sourcefabric.org:airtime into 2.2.x

This commit is contained in:
Martin Konecny 2012-10-31 16:39:03 -04:00
commit 1472eb5e51
13 changed files with 242 additions and 109 deletions

View file

@ -181,7 +181,8 @@ class LibraryController extends Zend_Controller_Action
} }
} }
} }
if ($isAdminOrPM) {
if ($isAdminOrPM || $file->getFileOwnerId() == $user->getId()) {
$menu["del"] = array("name"=> "Delete", "icon" => "delete", "url" => "/library/delete"); $menu["del"] = array("name"=> "Delete", "icon" => "delete", "url" => "/library/delete");
$menu["edit"] = array("name"=> "Edit Metadata", "icon" => "edit", "url" => "/library/edit-file-md/id/{$id}"); $menu["edit"] = array("name"=> "Edit Metadata", "icon" => "edit", "url" => "/library/edit-file-md/id/{$id}");
} }
@ -364,15 +365,17 @@ class LibraryController extends Zend_Controller_Action
{ {
$user = Application_Model_User::getCurrentUser(); $user = Application_Model_User::getCurrentUser();
$isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER)); $isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER));
if (!$isAdminOrPM) {
return;
}
$request = $this->getRequest(); $request = $this->getRequest();
$form = new Application_Form_EditAudioMD();
$file_id = $this->_getParam('id', null); $file_id = $this->_getParam('id', null);
$file = Application_Model_StoredFile::Recall($file_id); $file = Application_Model_StoredFile::Recall($file_id);
if (!$isAdminOrPM && $file->getFileOwnerId() != $user->getId()) {
return;
}
$form = new Application_Form_EditAudioMD();
$form->populate($file->getDbColMetadata()); $form->populate($file->getDbColMetadata());
if ($request->isPost()) { if ($request->isPost()) {

View file

@ -513,6 +513,7 @@ class PlaylistController extends Zend_Controller_Action
} catch (BlockNotFoundException $e) { } catch (BlockNotFoundException $e) {
$this->playlistNotFound('block', true); $this->playlistNotFound('block', true);
} catch (Exception $e) { } catch (Exception $e) {
//Logging::info($e);
$this->playlistUnknownError($e); $this->playlistUnknownError($e);
} }
} }

View file

@ -212,6 +212,14 @@ class Application_Form_SmartBlockCriteria extends Zend_Form_SubForm
}//for }//for
$repeatTracks = new Zend_Form_Element_Checkbox('sp_repeat_tracks');
$repeatTracks->setDecorators(array('viewHelper'))
->setLabel('Allow Repeat Tracks:');
if (isset($storedCrit["repeat_tracks"])) {
$repeatTracks->setChecked($storedCrit["repeat_tracks"]["value"] == 1?true:false);
}
$this->addElement($repeatTracks);
$limit = new Zend_Form_Element_Select('sp_limit_options'); $limit = new Zend_Form_Element_Select('sp_limit_options');
$limit->setAttrib('class', 'sp_input_select') $limit->setAttrib('class', 'sp_input_select')
->setDecorators(array('viewHelper')) ->setDecorators(array('viewHelper'))

View file

@ -1093,6 +1093,14 @@ SQL;
->setDbValue($p_criteriaData['etc']['sp_limit_value']) ->setDbValue($p_criteriaData['etc']['sp_limit_value'])
->setDbBlockId($this->id) ->setDbBlockId($this->id)
->save(); ->save();
// insert repeate track option
$qry = new CcBlockcriteria();
$qry->setDbCriteria("repeat_tracks")
->setDbModifier("N/A")
->setDbValue($p_criteriaData['etc']['sp_repeat_tracks'])
->setDbBlockId($this->id)
->save();
} }
/** /**
@ -1105,7 +1113,12 @@ SQL;
$this->saveSmartBlockCriteria($p_criteria); $this->saveSmartBlockCriteria($p_criteria);
$insertList = $this->getListOfFilesUnderLimit(); $insertList = $this->getListOfFilesUnderLimit();
$this->deleteAllFilesFromBlock(); $this->deleteAllFilesFromBlock();
$this->addAudioClips(array_keys($insertList)); // constrcut id array
$ids = array();
foreach ($insertList as $ele) {
$ids[] = $ele['id'];
}
$this->addAudioClips(array_values($ids));
// update length in playlist contents. // update length in playlist contents.
$this->updateBlockLengthInAllPlaylist(); $this->updateBlockLengthInAllPlaylist();
@ -1134,6 +1147,7 @@ SQL;
$info = $this->getListofFilesMeetCriteria(); $info = $this->getListofFilesMeetCriteria();
$files = $info['files']; $files = $info['files'];
$limit = $info['limit']; $limit = $info['limit'];
$repeat = $info['repeat_tracks'];
$insertList = array(); $insertList = array();
$totalTime = 0; $totalTime = 0;
@ -1142,20 +1156,38 @@ SQL;
// this moves the pointer to the first element in the collection // this moves the pointer to the first element in the collection
$files->getFirst(); $files->getFirst();
$iterator = $files->getIterator(); $iterator = $files->getIterator();
while ($iterator->valid() && $totalTime < $limit['time']) {
$isBlockFull = false;
while ($iterator->valid()) {
$id = $iterator->current()->getDbId(); $id = $iterator->current()->getDbId();
$length = Application_Common_DateHelper::calculateLengthInSeconds($iterator->current()->getDbLength()); $length = Application_Common_DateHelper::calculateLengthInSeconds($iterator->current()->getDbLength());
$insertList[$id] = $length; $insertList[] = array('id'=>$id, 'length'=>$length);
$totalTime += $length; $totalTime += $length;
$totalItems++; $totalItems++;
if ((!is_null($limit['items']) && $limit['items'] == count($insertList)) || $totalItems > 500) { if ((!is_null($limit['items']) && $limit['items'] == count($insertList)) || $totalItems > 500 || $totalTime > $limit['time']) {
$isBlockFull = true;
break; break;
} }
$iterator->next(); $iterator->next();
} }
$sizeOfInsert = count($insertList);
// if block is not full and reapeat_track is check, fill up more
while (!$isBlockFull && $repeat == 1) {
$randomEleKey = array_rand(array_slice($insertList, 0, $sizeOfInsert));
$insertList[] = $insertList[$randomEleKey];
$totalTime += $insertList[$randomEleKey]['length'];
$totalItems++;
if ((!is_null($limit['items']) && $limit['items'] == count($insertList)) || $totalItems > 500 || $totalTime > $limit['time']) {
break;
}
}
return $insertList; return $insertList;
} }
@ -1202,6 +1234,8 @@ SQL;
if ($criteria == "limit") { if ($criteria == "limit") {
$storedCrit["limit"] = array("value"=>$value, "modifier"=>$modifier); $storedCrit["limit"] = array("value"=>$value, "modifier"=>$modifier);
} else if($criteria == "repeat_tracks") {
$storedCrit["repeat_tracks"] = array("value"=>$value);
} else { } else {
$storedCrit["crit"][$criteria][] = array("criteria"=>$criteria, "value"=>$value, "modifier"=>$modifier, "extra"=>$extra, "display_name"=>$criteriaOptions[$criteria]); $storedCrit["crit"][$criteria][] = array("criteria"=>$criteria, "value"=>$value, "modifier"=>$modifier, "extra"=>$extra, "display_name"=>$criteriaOptions[$criteria]);
} }
@ -1317,6 +1351,7 @@ SQL;
} }
// construct limit restriction // construct limit restriction
$limits = array(); $limits = array();
if (isset($storedCrit['limit'])) { if (isset($storedCrit['limit'])) {
if ($storedCrit['limit']['modifier'] == "items") { if ($storedCrit['limit']['modifier'] == "items") {
$limits['time'] = 1440 * 60; $limits['time'] = 1440 * 60;
@ -1328,10 +1363,16 @@ SQL;
$limits['items'] = null; $limits['items'] = null;
} }
} }
$repeatTracks = 0;
if (isset($storedCrit['repeat_tracks'])) {
$repeatTracks = $storedCrit['repeat_tracks']['value'];
}
try { try {
$out = $qry->setFormatter(ModelCriteria::FORMAT_ON_DEMAND)->find(); $out = $qry->setFormatter(ModelCriteria::FORMAT_ON_DEMAND)->find();
return array("files"=>$out, "limit"=>$limits, "count"=>$out->count()); return array("files"=>$out, "limit"=>$limits, "repeat_tracks"=> $repeatTracks, "count"=>$out->count());
} catch (Exception $e) { } catch (Exception $e) {
Logging::info($e); Logging::info($e);
} }

View file

@ -13,9 +13,9 @@ class Application_Model_Datatables
if ($dbname == 'utime' || $dbname == 'mtime') { if ($dbname == 'utime' || $dbname == 'mtime') {
$input1 = isset($info[0])?Application_Common_DateHelper::ConvertToUtcDateTimeString($info[0]):null; $input1 = isset($info[0])?Application_Common_DateHelper::ConvertToUtcDateTimeString($info[0]):null;
$input2 = isset($info[1])?Application_Common_DateHelper::ConvertToUtcDateTimeString($info[1]):null; $input2 = isset($info[1])?Application_Common_DateHelper::ConvertToUtcDateTimeString($info[1]):null;
} else if($dbname == 'bit_rate') { } else if($dbname == 'bit_rate' || $dbname == 'sample_rate') {
$input1 = isset($info[0])?intval($info[0]) * 1000:null; $input1 = isset($info[0])?doubleval($info[0]) * 1000:null;
$input2 = isset($info[1])?intval($info[1]) * 1000:null; $input2 = isset($info[1])?doubleval($info[1]) * 1000:null;
} else { } else {
$input1 = isset($info[0])?$info[0]:null; $input1 = isset($info[0])?$info[0]:null;
$input2 = isset($info[1])?$info[1]:null; $input2 = isset($info[1])?$info[1]:null;

View file

@ -270,6 +270,13 @@ SQL;
try { try {
//update the status flag in cc_schedule. //update the status flag in cc_schedule.
/* Since we didn't use a propel object when updating
* cc_show_instances table we need to clear the instances
* so the correct information is retrieved from the db
*/
CcShowInstancesPeer::clearInstancePool();
$instances = CcShowInstancesQuery::create() $instances = CcShowInstancesQuery::create()
->filterByDbEnds($current_timestamp, Criteria::GREATER_THAN) ->filterByDbEnds($current_timestamp, Criteria::GREATER_THAN)
->filterByDbShowId($this->_showId) ->filterByDbShowId($this->_showId)
@ -1254,6 +1261,7 @@ SQL;
$con = Propel::getConnection(CcSchedulePeer::DATABASE_NAME); $con = Propel::getConnection(CcSchedulePeer::DATABASE_NAME);
$con->beginTransaction(); $con->beginTransaction();
//current timesamp in UTC. //current timesamp in UTC.
$current_timestamp = gmdate("Y-m-d H:i:s"); $current_timestamp = gmdate("Y-m-d H:i:s");

View file

@ -1161,6 +1161,10 @@ SQL;
return $this->_file->getDbFileExists(); return $this->_file->getDbFileExists();
} }
public function getFileOwnerId()
{
return $this->_file->getDbOwnerId();
}
// note: never call this method from controllers because it does a sleep // note: never call this method from controllers because it does a sleep
public function uploadToSoundCloud() public function uploadToSoundCloud()

View file

@ -59,6 +59,20 @@
<br /> <br />
</dd> </dd>
<dd id='sp_repeate_tracks-element'>
<span class='sp_text_font'><?php echo $this->element->getElement('sp_repeat_tracks')->getLabel() ?></span>
<span class='repeat_tracks_help_icon'></span>
<?php echo $this->element->getElement('sp_repeat_tracks')?>
<?php if($this->element->getElement("sp_repeat_tracks")->hasErrors()) : ?>
<?php foreach($this->element->getElement("sp_repeat_tracks")->getMessages() as $error): ?>
<span class='errors sp-errors'>
<?php echo $error; ?>
</span>
<?php endforeach; ?>
<?php endif; ?>
<br />
</dd>
<dd id='sp_limit-element'> <dd id='sp_limit-element'>
<span class='sp_text_font'><?php echo $this->element->getElement('sp_limit_value')->getLabel() ?></span> <span class='sp_text_font'><?php echo $this->element->getElement('sp_limit_value')->getLabel() ?></span>
<?php echo $this->element->getElement('sp_limit_value')?> <?php echo $this->element->getElement('sp_limit_value')?>

View file

@ -1,6 +1,6 @@
<div class="ui-widget ui-widget-content block-shadow simple-formblock clearfix padded-strong"> <div class="ui-widget ui-widget-content block-shadow simple-formblock clearfix padded-strong">
<h2>Edit Metadata</h2> <h2>Edit Metadata</h2>
<?php $this->form->setAction($this->url()); <?php //$this->form->setAction($this->url());
echo $this->form; ?> echo $this->form; ?>
</div> </div>

View file

@ -105,7 +105,7 @@ select {
} }
.airtime_auth_help_icon, .custom_auth_help_icon, .stream_username_help_icon, .airtime_auth_help_icon, .custom_auth_help_icon, .stream_username_help_icon,
.playlist_type_help_icon, .master_username_help_icon { .playlist_type_help_icon, .master_username_help_icon, .repeat_tracks_help_icon{
cursor: help; cursor: help;
position: relative; position: relative;
display:inline-block; zoom:1; display:inline-block; zoom:1;

View file

@ -70,7 +70,7 @@ var AIRTIME = (function(AIRTIME) {
}; };
mod.getChosenAudioFilesLength = function(){ mod.getChosenAudioFilesLength = function(){
//var files = Object.keys(chosenItems), // var files = Object.keys(chosenItems),
var files, var files,
$trs, $trs,
cItem, cItem,
@ -215,7 +215,7 @@ var AIRTIME = (function(AIRTIME) {
mod.removeFromChosen = function($el) { mod.removeFromChosen = function($el) {
var id = $el.attr("id"); var id = $el.attr("id");
//used to not keep dragged items selected. // used to not keep dragged items selected.
if (!$el.hasClass(LIB_SELECTED_CLASS)) { if (!$el.hasClass(LIB_SELECTED_CLASS)) {
delete chosenItems[id]; delete chosenItems[id];
} }
@ -252,11 +252,11 @@ var AIRTIME = (function(AIRTIME) {
}; };
/* /*
* selects all items which the user can currently see. * selects all items which the user can currently see. (behaviour taken from
* (behaviour taken from gmail) * gmail)
* *
* by default the items are selected in reverse order * by default the items are selected in reverse order so we need to reverse
* so we need to reverse it back * it back
*/ */
mod.selectCurrentPage = function() { mod.selectCurrentPage = function() {
$.fn.reverse = [].reverse; $.fn.reverse = [].reverse;
@ -276,8 +276,8 @@ var AIRTIME = (function(AIRTIME) {
}; };
/* /*
* deselects all items that the user can currently see. * deselects all items that the user can currently see. (behaviour taken
* (behaviour taken from gmail) * from gmail)
*/ */
mod.deselectCurrentPage = function() { mod.deselectCurrentPage = function() {
var $inputs = $libTable.find("tbody input:checkbox"), var $inputs = $libTable.find("tbody input:checkbox"),
@ -328,7 +328,7 @@ var AIRTIME = (function(AIRTIME) {
temp, temp,
aMedia = []; aMedia = [];
//process selected files/playlists. // process selected files/playlists.
for (item in aData) { for (item in aData) {
temp = aData[item]; temp = aData[item];
if (temp !== null && temp.hasOwnProperty('id') ) { if (temp !== null && temp.hasOwnProperty('id') ) {
@ -433,7 +433,8 @@ var AIRTIME = (function(AIRTIME) {
oTable = $libTable.dataTable( { oTable = $libTable.dataTable( {
//put hidden columns at the top to insure they can never be visible on the table through column reordering. // put hidden columns at the top to insure they can never be visible
// on the table through column reordering.
"aoColumns": [ "aoColumns": [
/* ftype */ { "sTitle" : "" , "mDataProp" : "ftype" , "bSearchable" : false , "bVisible" : false } , /* ftype */ { "sTitle" : "" , "mDataProp" : "ftype" , "bSearchable" : false , "bVisible" : false } ,
/* Checkbox */ { "sTitle" : "" , "mDataProp" : "checkbox" , "bSortable" : false , "bSearchable" : false , "sWidth" : "25px" , "sClass" : "library_checkbox" } , /* Checkbox */ { "sTitle" : "" , "mDataProp" : "checkbox" , "bSortable" : false , "bSearchable" : false , "sWidth" : "25px" , "sClass" : "library_checkbox" } ,
@ -472,7 +473,7 @@ var AIRTIME = (function(AIRTIME) {
"bStateSave": true, "bStateSave": true,
"fnStateSaveParams": function (oSettings, oData) { "fnStateSaveParams": function (oSettings, oData) {
//remove oData components we don't want to save. // remove oData components we don't want to save.
delete oData.oSearch; delete oData.oSearch;
delete oData.aoSearchCols; delete oData.aoSearchCols;
}, },
@ -499,8 +500,8 @@ var AIRTIME = (function(AIRTIME) {
length, length,
a = oData.abVisCols; a = oData.abVisCols;
//putting serialized data back into the correct js type to make // putting serialized data back into the correct js type to make
//sure everything works properly. // sure everything works properly.
for (i = 0, length = a.length; i < length; i++) { for (i = 0, length = a.length; i < length; i++) {
if (typeof(a[i]) === "string") { if (typeof(a[i]) === "string") {
a[i] = (a[i] === "true") ? true : false; a[i] = (a[i] === "true") ? true : false;
@ -524,11 +525,12 @@ var AIRTIME = (function(AIRTIME) {
"sAjaxDataProp": "files", "sAjaxDataProp": "files",
"fnServerData": function ( sSource, aoData, fnCallback ) { "fnServerData": function ( sSource, aoData, fnCallback ) {
/* The real validation check is done in dataTables.columnFilter.js /*
* We also need to check it here because datatable is redrawn everytime * The real validation check is done in
* an action is performed in the Library page. * dataTables.columnFilter.js We also need to check it here
* In order for datatable to redraw the advanced search fields * because datatable is redrawn everytime an action is performed
* MUST all be valid. * in the Library page. In order for datatable to redraw the
* advanced search fields MUST all be valid.
*/ */
var advSearchFields = $("div#advanced_search").children(':visible'); var advSearchFields = $("div#advanced_search").children(':visible');
var advSearchValid = validateAdvancedSearch(advSearchFields); var advSearchValid = validateAdvancedSearch(advSearchFields);
@ -536,7 +538,7 @@ var AIRTIME = (function(AIRTIME) {
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 = $("#library_display_type").find("select").val(); type = $("#library_display_type").find("select").val();
type = (type === undefined) ? 0 : type; type = (type === undefined) ? 0 : type;
aoData.push( { name: "type", value: type} ); aoData.push( { name: "type", value: type} );
@ -552,30 +554,37 @@ var AIRTIME = (function(AIRTIME) {
"fnRowCallback": AIRTIME.library.fnRowCallback, "fnRowCallback": AIRTIME.library.fnRowCallback,
"fnCreatedRow": function( nRow, aData, iDataIndex ) { "fnCreatedRow": function( nRow, aData, iDataIndex ) {
//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'){
playlistIndex = $(this).parent().attr('id').substring(3); //remove the pl_ playlistIndex = $(this).parent().attr('id').substring(3); // remove
// the
// pl_
open_playlist_preview(playlistIndex, 0); open_playlist_preview(playlistIndex, 0);
} else if (aData.ftype === 'audioclip') { } else if (aData.ftype === 'audioclip') {
open_audio_preview(aData.ftype, aData.audioFile, aData.track_title, aData.artist_name); open_audio_preview(aData.ftype, aData.audioFile, aData.track_title, aData.artist_name);
} else if (aData.ftype == 'stream') { } else if (aData.ftype == 'stream') {
open_audio_preview(aData.ftype, aData.audioFile, aData.track_title, aData.artist_name); open_audio_preview(aData.ftype, aData.audioFile, aData.track_title, aData.artist_name);
} else if (aData.ftype == 'block' && aData.bl_type == 'static') { } else if (aData.ftype == 'block' && aData.bl_type == 'static') {
blockIndex = $(this).parent().attr('id').substring(3); //remove the bl_ blockIndex = $(this).parent().attr('id').substring(3); // remove
// the
// bl_
open_block_preview(blockIndex, 0); open_block_preview(blockIndex, 0);
} }
return false; return false;
}); });
alreadyclicked=false; alreadyclicked=false;
//call the context menu so we can prevent the event from propagating. // call the context menu so we can prevent the event from
// propagating.
$(nRow).find('td:not(.library_checkbox, .library_type)').click(function(e){ $(nRow).find('td:not(.library_checkbox, .library_type)').click(function(e){
var el=$(this); var el=$(this);
if (alreadyclicked) if (alreadyclicked)
{ {
alreadyclicked=false; // reset alreadyclicked=false; // reset
clearTimeout(alreadyclickedTimeout); // prevent this from happening clearTimeout(alreadyclickedTimeout); // prevent this
// from
// happening
// do what needs to happen on double click. // do what needs to happen on double click.
$tr = $(el).parent(); $tr = $(el).parent();
@ -596,7 +605,8 @@ var AIRTIME = (function(AIRTIME) {
return false; return false;
}); });
//add a tool tip to appear when the user clicks on the type icon. // add a tool tip to appear when the user clicks on the type
// icon.
$(nRow).find("td:not(.library_checkbox, .library_type)").qtip({ $(nRow).find("td:not(.library_checkbox, .library_type)").qtip({
content: { content: {
text: "Loading...", text: "Loading...",
@ -620,7 +630,8 @@ var AIRTIME = (function(AIRTIME) {
}, },
my: 'left center', my: 'left center',
at: 'right center', at: 'right center',
viewport: $(window), // Keep the tooltip on-screen at all times viewport: $(window), // Keep the tooltip on-screen at
// all times
effect: false // Disable positioning animation effect: false // Disable positioning animation
}, },
style: { style: {
@ -638,10 +649,11 @@ var AIRTIME = (function(AIRTIME) {
hide: {event:'mouseout', delay: 50, fixed:true} hide: {event:'mouseout', delay: 50, fixed:true}
}); });
}, },
//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 stranded on the screen. // make sure any dragging helpers are removed or else they'll be
// stranded on the screen.
$("#draggingContainer").remove(); $("#draggingContainer").remove();
}, },
"fnDrawCallback": AIRTIME.library.fnDrawCallback, "fnDrawCallback": AIRTIME.library.fnDrawCallback,
@ -674,17 +686,32 @@ var AIRTIME = (function(AIRTIME) {
setColumnFilter(oTable); setColumnFilter(oTable);
oTable.fnSetFilteringDelay(350); oTable.fnSetFilteringDelay(350);
var simpleSearchText;
$libContent.on("click", "legend", function(){ $libContent.on("click", "legend", function(){
$simpleSearch = $libContent.find("#library_display_filter label"); $simpleSearch = $libContent.find("#library_display_filter label");
var $fs = $(this).parents("fieldset"); var $fs = $(this).parents("fieldset");
if ($fs.hasClass("closed")) { if ($fs.hasClass("closed")) {
$fs.removeClass("closed"); $fs.removeClass("closed");
//keep value of simple search for when user switches back to it
simpleSearchText = $simpleSearch.find('input').val();
// clear the simple search text field and reset datatable
$(".dataTables_filter input").val("").keyup();
$simpleSearch.addClass("sp-invisible"); $simpleSearch.addClass("sp-invisible");
} }
else { else {
$fs.addClass("closed"); //clear the advanced search fields and reset datatable
$(".filter_column input").val("").keyup();
//reset datatable with previous simple search results (if any)
$(".dataTables_filter input").val(simpleSearchText).keyup();
$simpleSearch.removeClass("sp-invisible"); $simpleSearch.removeClass("sp-invisible");
$fs.addClass("closed");
} }
}); });
@ -737,7 +764,7 @@ var AIRTIME = (function(AIRTIME) {
addQtipToSCIcons(); addQtipToSCIcons();
//begin context menu initialization. // begin context menu initialization.
$.contextMenu({ $.contextMenu({
selector: '#library_display td:not(.library_checkbox)', selector: '#library_display td:not(.library_checkbox)',
trigger: "left", trigger: "left",
@ -752,7 +779,7 @@ var AIRTIME = (function(AIRTIME) {
function processMenuItems(oItems) { function processMenuItems(oItems) {
//define an add to playlist callback. // define an add to playlist callback.
if (oItems.pl_add !== undefined) { if (oItems.pl_add !== undefined) {
var aItems = []; var aItems = [];
@ -764,7 +791,7 @@ var AIRTIME = (function(AIRTIME) {
oItems.pl_add.callback = callback; oItems.pl_add.callback = callback;
} }
//define an edit callback. // define an edit callback.
if (oItems.edit !== undefined) { if (oItems.edit !== undefined) {
if (data.ftype === "audioclip") { if (data.ftype === "audioclip") {
@ -788,7 +815,7 @@ var AIRTIME = (function(AIRTIME) {
oItems.edit.callback = callback; oItems.edit.callback = callback;
} }
//define a play callback. // define a play callback.
if (oItems.play !== undefined) { if (oItems.play !== undefined) {
if (oItems.play.mime !== undefined) { if (oItems.play.mime !== undefined) {
@ -799,23 +826,28 @@ var AIRTIME = (function(AIRTIME) {
callback = function() { callback = function() {
if (data.ftype === 'playlist' && data.length !== '0.0'){ if (data.ftype === 'playlist' && data.length !== '0.0'){
playlistIndex = $(this).parent().attr('id').substring(3); //remove the pl_ playlistIndex = $(this).parent().attr('id').substring(3); // remove
// the
// pl_
open_playlist_preview(playlistIndex, 0); open_playlist_preview(playlistIndex, 0);
} else if (data.ftype === 'audioclip' || data.ftype === 'stream') { } else if (data.ftype === 'audioclip' || data.ftype === 'stream') {
open_audio_preview(data.ftype, data.audioFile, data.track_title, data.artist_name); open_audio_preview(data.ftype, data.audioFile, data.track_title, data.artist_name);
} else if (data.ftype === 'block') { } else if (data.ftype === 'block') {
blockIndex = $(this).parent().attr('id').substring(3); //remove the pl_ blockIndex = $(this).parent().attr('id').substring(3); // remove
// the
// pl_
open_block_preview(blockIndex, 0); open_block_preview(blockIndex, 0);
} }
}; };
oItems.play.callback = callback; oItems.play.callback = callback;
} }
//define a delete callback. // define a delete callback.
if (oItems.del !== undefined) { if (oItems.del !== undefined) {
//delete through the playlist controller, will reset // delete through the playlist controller, will reset
//playlist screen if this is the currently edited playlist. // playlist screen if this is the currently edited
// playlist.
if ((data.ftype === "playlist" || data.ftype === "block") && screen === "playlist") { if ((data.ftype === "playlist" || data.ftype === "block") && screen === "playlist") {
callback = function() { callback = function() {
aMedia = []; aMedia = [];
@ -849,7 +881,7 @@ var AIRTIME = (function(AIRTIME) {
oItems.del.callback = callback; oItems.del.callback = callback;
} }
//define a download callback. // define a download callback.
if (oItems.download !== undefined) { if (oItems.download !== undefined) {
callback = function() { callback = function() {
@ -857,11 +889,11 @@ var AIRTIME = (function(AIRTIME) {
}; };
oItems.download.callback = callback; oItems.download.callback = callback;
} }
//add callbacks for Soundcloud menu items. // add callbacks for Soundcloud menu items.
if (oItems.soundcloud !== undefined) { if (oItems.soundcloud !== undefined) {
var soundcloud = oItems.soundcloud.items; var soundcloud = oItems.soundcloud.items;
//define an upload to soundcloud callback. // define an upload to soundcloud callback.
if (soundcloud.upload !== undefined) { if (soundcloud.upload !== undefined) {
callback = function() { callback = function() {
@ -872,7 +904,7 @@ var AIRTIME = (function(AIRTIME) {
soundcloud.upload.callback = callback; soundcloud.upload.callback = callback;
} }
//define a view on soundcloud callback // define a view on soundcloud callback
if (soundcloud.view !== undefined) { if (soundcloud.view !== undefined) {
callback = function() { callback = function() {
@ -988,7 +1020,8 @@ function addQtipToSCIcons(){
viewport: $(window) viewport: $(window)
}, },
show: { show: {
ready: true // Needed to make it show on first mouseover event ready: true // Needed to make it show on first mouseover
// event
} }
}); });
} }
@ -1015,7 +1048,8 @@ function addQtipToSCIcons(){
viewport: $(window) viewport: $(window)
}, },
show: { show: {
ready: true // Needed to make it show on first mouseover event ready: true // Needed to make it show on first mouseover
// event
} }
}); });
}else if($(this).hasClass("sc-error")){ }else if($(this).hasClass("sc-error")){
@ -1042,7 +1076,8 @@ function addQtipToSCIcons(){
viewport: $(window) viewport: $(window)
}, },
show: { show: {
ready: true // Needed to make it show on first mouseover event ready: true // Needed to make it show on first mouseover
// event
} }
}); });
} }
@ -1096,7 +1131,7 @@ function validateAdvancedSearch(divs) {
} }
} }
//string fields do not need validation // string fields do not need validation
if (searchTermType !== "s") { if (searchTermType !== "s") {
valid = regExpr.test(searchTerm[i]); valid = regExpr.test(searchTerm[i]);
if (!valid) allValid = false; if (!valid) allValid = false;
@ -1104,11 +1139,11 @@ function validateAdvancedSearch(divs) {
addRemoveValidationIcons(valid, $(field), searchTermType); addRemoveValidationIcons(valid, $(field), searchTermType);
/* Empty fields should not have valid/invalid indicator /*
* Range values are considered valid even if only the * Empty fields should not have valid/invalid indicator Range values
* 'From' value is provided. Therefore, if the 'To' value * are considered valid even if only the 'From' value is provided.
* is empty but the 'From' value is not empty we need to * Therefore, if the 'To' value is empty but the 'From' value is not
* keep the validation icon on screen. * empty we need to keep the validation icon on screen.
*/ */
} else if (searchTerm[0] === "" && searchTerm[1] !== "" || } else if (searchTerm[0] === "" && searchTerm[1] !== "" ||
searchTerm[0] === "" && searchTerm[1] === ""){ searchTerm[0] === "" && searchTerm[1] === ""){
@ -1144,7 +1179,7 @@ function addRemoveValidationIcons(valid, field, searchTermType) {
if (valid) { if (valid) {
if (!field.closest('div').children(':last-child').hasClass('checked-icon')) { if (!field.closest('div').children(':last-child').hasClass('checked-icon')) {
//remove invalid icon before adding valid icon // remove invalid icon before adding valid icon
if (field.closest('div').children(':last-child').hasClass('not-available-icon')) { if (field.closest('div').children(':last-child').hasClass('not-available-icon')) {
field.closest('div').children(':last-child').remove(); field.closest('div').children(':last-child').remove();
} }
@ -1152,7 +1187,7 @@ function addRemoveValidationIcons(valid, field, searchTermType) {
} }
} else { } else {
if (!field.closest('div').children(':last-child').hasClass('not-available-icon')) { if (!field.closest('div').children(':last-child').hasClass('not-available-icon')) {
//remove valid icon before adding invalid icon // remove valid icon before adding invalid icon
if (field.closest('div').children(':last-child').hasClass('checked-icon')) { if (field.closest('div').children(':last-child').hasClass('checked-icon')) {
field.closest('div').children(':last-child').remove(); field.closest('div').children(':last-child').remove();
} }
@ -1161,12 +1196,9 @@ function addRemoveValidationIcons(valid, field, searchTermType) {
} }
} }
/* Validation types: /*
* s => string * Validation types: s => string i => integer n => numeric (positive/negative,
* i => integer * whole/decimals) t => timestamp l => length
* n => numeric (positive/negative, whole/decimals)
* t => timestamp
* l => length
*/ */
var validationTypes = { var validationTypes = {
"album_title" : "s", "album_title" : "s",
@ -1195,7 +1227,7 @@ var validationTypes = {
"owner_id" : "s", "owner_id" : "s",
"rating" : "i", "rating" : "i",
"replay_gain" : "n", "replay_gain" : "n",
"sample_rate" : "i", "sample_rate" : "n",
"track_title" : "s", "track_title" : "s",
"track_number" : "i", "track_number" : "i",
"info_url" : "s", "info_url" : "s",

View file

@ -384,6 +384,28 @@ function setupUI() {
at: "right center" at: "right center"
}, },
}); });
$(".repeat_tracks_help_icon").qtip({
content: {
text: "If your criteria is too strict, Airtime may not be able to fill up the desired smart block length." +
" Hence, if you check this option, tracks will be used more than once."
},
hide: {
delay: 500,
fixed: true
},
style: {
border: {
width: 0,
radius: 4
},
classes: "ui-tooltip-dark ui-tooltip-rounded"
},
position: {
my: "left bottom",
at: "right center"
},
});
} }
function enableAndShowExtraField(valEle, index) { function enableAndShowExtraField(valEle, index) {

View file

@ -190,7 +190,7 @@
} else if (th.attr('id') == "length") { } else if (th.attr('id') == "length") {
label = " hh:mm:ss.t"; label = " hh:mm:ss.t";
} else if (th.attr('id') == "sample_rate") { } else if (th.attr('id') == "sample_rate") {
label = " Hz"; label = " kHz";
} }
th.html(_fnRangeLabelPart(0)); th.html(_fnRangeLabelPart(0));