SAAS-948, SAAS-983 - Showbuilder editor redesign, look and feel fixes

This commit is contained in:
Duncan Sommerville 2015-08-12 14:35:27 -04:00
parent 21250e91c4
commit 1957c7827f
18 changed files with 1573 additions and 88 deletions

View File

@ -86,7 +86,7 @@ class NewPlaylistController extends Zend_Controller_Action
$this->view->length = $formatter->format();
if ($isBlock) {
$form = new Application_Form_SmartBlockCriteria();
$form = new Application_Form_SmartBlockCriteriaNew();
$form->removeDecorator('DtDdWrapper');
$form->startForm($obj->getId(), $formIsValid);
@ -531,7 +531,7 @@ class NewPlaylistController extends Zend_Controller_Action
} catch (BlockNotFoundException $e) {
$this->playlistNotFound('block', true);
}
$form = new Application_Form_SmartBlockCriteria();
$form = new Application_Form_SmartBlockCriteriaNew();
$form->startForm($params['obj_id']);
if ($form->isValid($params)) {
$this->setPlaylistNameDescAction();
@ -547,14 +547,15 @@ class NewPlaylistController extends Zend_Controller_Action
$this->view->id = $bl->getId();
$result['html'] = $this->view->render($viewPath);
$result['result'] = 1;
$result['type'] = "sb";
$result['id'] = $bl->getId();
}
$result['type'] = "sb";
$result['id'] = $bl->getId();
$result["modified"] = $bl->getLastModified("U");
} else if ($params['type'] == 'playlist') {
$result["modified"] = $this->view->modified;
$this->setPlaylistNameDescAction();
}
$result["modified"] = $this->view->modified;
$this->_helper->json->sendJson($result);
}
@ -567,7 +568,7 @@ class NewPlaylistController extends Zend_Controller_Action
try {
$bl = new Application_Model_Block($params['obj_id']);
$form = new Application_Form_SmartBlockCriteria();
$form = new Application_Form_SmartBlockCriteriaNew();
$form->startForm($params['obj_id']);
if ($form->isValid($params)) {
$result = $bl->generateSmartBlock($params['data']);

View File

@ -46,7 +46,7 @@ class ShowBuilderController extends Zend_Controller_Action {
// MEDIA BUILDER
$this->view->headScript()->appendFile($baseUrl.'js/airtime/library/_spl.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'js/airtime/playlist/smart_blockbuilder.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'js/airtime/playlist/_smart_blockbuilder.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headLink()->appendStylesheet($baseUrl.'css/playlist_builder.css?'.$CC_CONFIG['airtime_version']);
$this->view->headLink()->appendStylesheet($baseUrl.'css/jquery.ui.timepicker.css?'.$CC_CONFIG['airtime_version']);

View File

@ -0,0 +1,615 @@
<?php
class Application_Form_SmartBlockCriteriaNew extends Zend_Form_SubForm
{
private $criteriaOptions;
private $stringCriteriaOptions;
private $numericCriteriaOptions;
private $sortOptions;
private $limitOptions;
/* We need to know if the criteria value will be a string
* or numeric value in order to populate the modifier
* select list
*/
private $criteriaTypes = array(
0 => "",
"album_title" => "s",
"bit_rate" => "n",
"bpm" => "n",
"composer" => "s",
"conductor" => "s",
"copyright" => "s",
"cuein" => "n",
"cueout" => "n",
"artist_name" => "s",
"encoded_by" => "s",
"utime" => "n",
"mtime" => "n",
"lptime" => "n",
"genre" => "s",
"isrc_number" => "s",
"label" => "s",
"language" => "s",
"length" => "n",
"mime" => "s",
"mood" => "s",
"owner_id" => "s",
"replay_gain" => "n",
"sample_rate" => "n",
"track_title" => "s",
"track_number" => "n",
"info_url" => "s",
"year" => "n"
);
private function getCriteriaOptions($option = null)
{
if (!isset($this->criteriaOptions)) {
$this->criteriaOptions = array(
0 => _("Select criteria"),
"album_title" => _("Album"),
"bit_rate" => _("Bit Rate (Kbps)"),
"bpm" => _("BPM"),
"composer" => _("Composer"),
"conductor" => _("Conductor"),
"copyright" => _("Copyright"),
"cuein" => _("Cue In"),
"cueout" => _("Cue Out"),
"artist_name" => _("Creator"),
"encoded_by" => _("Encoded By"),
"genre" => _("Genre"),
"isrc_number" => _("ISRC"),
"label" => _("Label"),
"language" => _("Language"),
"mtime" => _("Last Modified"),
"lptime" => _("Last Played"),
"length" => _("Length"),
"mime" => _("Mime"),
"mood" => _("Mood"),
"owner_id" => _("Owner"),
"replay_gain" => _("Replay Gain"),
"sample_rate" => _("Sample Rate (kHz)"),
"track_title" => _("Title"),
"track_number" => _("Track Number"),
"utime" => _("Uploaded"),
"info_url" => _("Website"),
"year" => _("Year")
);
}
if (is_null($option)) return $this->criteriaOptions;
else return $this->criteriaOptions[$option];
}
private function getStringCriteriaOptions()
{
if (!isset($this->stringCriteriaOptions)) {
$this->stringCriteriaOptions = array(
"0" => _("Select modifier"),
"contains" => _("contains"),
"does not contain" => _("does not contain"),
"is" => _("is"),
"is not" => _("is not"),
"starts with" => _("starts with"),
"ends with" => _("ends with")
);
}
return $this->stringCriteriaOptions;
}
private function getNumericCriteriaOptions()
{
if (!isset($this->numericCriteriaOptions)) {
$this->numericCriteriaOptions = array(
"0" => _("Select modifier"),
"is" => _("is"),
"is not" => _("is not"),
"is greater than" => _("is greater than"),
"is less than" => _("is less than"),
"is in the range" => _("is in the range")
);
}
return $this->numericCriteriaOptions;
}
private function getLimitOptions()
{
if (!isset($this->limitOptions)) {
$this->limitOptions = array(
"hours" => _("hours"),
"minutes" => _("minutes"),
"items" => _("items")
);
}
return $this->limitOptions;
}
private function getSortOptions()
{
if (!isset($this->sortOptions)) {
$this->sortOptions = array(
"random" => _("random"),
"newest" => _("newest"),
"oldest" => _("oldest")
);
}
return $this->sortOptions;
}
public function init()
{
}
/*
* converts UTC timestamp citeria into user timezone strings.
*/
private function convertTimestamps(&$criteria)
{
$columns = array("utime", "mtime", "lptime");
foreach ($columns as $column) {
if (isset($criteria[$column])) {
foreach ($criteria[$column] as &$constraint) {
$constraint['value'] =
Application_Common_DateHelper::UTCStringToUserTimezoneString($constraint['value']);
if (isset($constraint['extra'])) {
$constraint['extra'] =
Application_Common_DateHelper::UTCStringToUserTimezoneString($constraint['extra']);
}
}
}
}
}
public function startForm($p_blockId, $p_isValid = false)
{
// load type
$out = CcBlockQuery::create()->findPk($p_blockId);
if ($out->getDbType() == "static") {
$blockType = 0;
} else {
$blockType = 1;
}
$spType = new Zend_Form_Element_Radio('sp_type');
$spType->setLabel(_('Set smart block type:'))
->setDecorators(array('viewHelper'))
->setMultiOptions(array(
'static' => _('Static'),
'dynamic' => _('Dynamic')
))
->setValue($blockType);
$this->addElement($spType);
$bl = new Application_Model_Block($p_blockId);
$storedCrit = $bl->getCriteria();
//need to convert criteria to be displayed in the user's timezone if there's some timestamp type.
self::convertTimestamps($storedCrit["crit"]);
/* $modRoadMap stores the number of same criteria
* Ex: 3 Album titles, and 2 Track titles
* We need to know this so we display the form elements properly
*/
$modRowMap = array();
$openSmartBlockOption = false;
if (!empty($storedCrit)) {
$openSmartBlockOption = true;
}
$criteriaKeys = array();
if (isset($storedCrit["crit"])) {
$criteriaKeys = array_keys($storedCrit["crit"]);
}
$numElements = count($this->getCriteriaOptions());
for ($i = 0; $i < $numElements; $i++) {
$criteriaType = "";
if (isset($criteriaKeys[$i])) {
$critCount = count($storedCrit["crit"][$criteriaKeys[$i]]);
} else {
$critCount = 1;
}
$modRowMap[$i] = $critCount;
/* Loop through all criteria with the same field
* Ex: all criteria for 'Album'
*/
for ($j = 0; $j < $critCount; $j++) {
/****************** CRITERIA ***********/
if ($j > 0) {
$invisible = ' sp-invisible';
} else {
$invisible = '';
}
$criteria = new Zend_Form_Element_Select("sp_criteria_field_".$i."_".$j);
$criteria->setAttrib('class', 'input_select sp_input_select'.$invisible)
->setValue('Select criteria')
->setDecorators(array('viewHelper'))
->setMultiOptions($this->getCriteriaOptions());
if ($i != 0 && !isset($criteriaKeys[$i])) {
$criteria->setAttrib('disabled', 'disabled');
}
if (isset($criteriaKeys[$i])) {
$criteriaType = $this->criteriaTypes[$storedCrit["crit"][$criteriaKeys[$i]][$j]["criteria"]];
$criteria->setValue($storedCrit["crit"][$criteriaKeys[$i]][$j]["criteria"]);
}
$this->addElement($criteria);
/****************** MODIFIER ***********/
$criteriaModifers = new Zend_Form_Element_Select("sp_criteria_modifier_".$i."_".$j);
$criteriaModifers->setValue('Select modifier')
->setAttrib('class', 'input_select sp_input_select')
->setDecorators(array('viewHelper'));
if ($i != 0 && !isset($criteriaKeys[$i])) {
$criteriaModifers->setAttrib('disabled', 'disabled');
}
if (isset($criteriaKeys[$i])) {
if ($criteriaType == "s") {
$criteriaModifers->setMultiOptions($this->getStringCriteriaOptions());
} else {
$criteriaModifers->setMultiOptions($this->getNumericCriteriaOptions());
}
$criteriaModifers->setValue($storedCrit["crit"][$criteriaKeys[$i]][$j]["modifier"]);
} else {
$criteriaModifers->setMultiOptions(array('0' => _('Select modifier')));
}
$this->addElement($criteriaModifers);
/****************** VALUE ***********/
$criteriaValue = new Zend_Form_Element_Text("sp_criteria_value_".$i."_".$j);
$criteriaValue->setAttrib('class', 'input_text sp_input_text')
->setDecorators(array('viewHelper'));
if ($i != 0 && !isset($criteriaKeys[$i])) {
$criteriaValue->setAttrib('disabled', 'disabled');
}
if (isset($criteriaKeys[$i])) {
$criteriaValue->setValue($storedCrit["crit"][$criteriaKeys[$i]][$j]["value"]);
}
$this->addElement($criteriaValue);
/****************** EXTRA ***********/
$criteriaExtra = new Zend_Form_Element_Text("sp_criteria_extra_".$i."_".$j);
$criteriaExtra->setAttrib('class', 'input_text sp_extra_input_text')
->setDecorators(array('viewHelper'));
if (isset($criteriaKeys[$i]) && isset($storedCrit["crit"][$criteriaKeys[$i]][$j]["extra"])) {
$criteriaExtra->setValue($storedCrit["crit"][$criteriaKeys[$i]][$j]["extra"]);
$criteriaValue->setAttrib('class', 'input_text sp_extra_input_text');
} else {
$criteriaExtra->setAttrib('disabled', 'disabled');
}
$this->addElement($criteriaExtra);
}//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);
$sort = new Zend_Form_Element_Select('sp_sort_options');
$sort->setAttrib('class', 'sp_input_select')
->setDecorators(array('viewHelper'))
->setMultiOptions($this->getSortOptions());
if (isset($storedCrit["sort"])) {
$sort->setValue($storedCrit["sort"]["value"]);
}
$this->addElement($sort);
$limit = new Zend_Form_Element_Select('sp_limit_options');
$limit->setAttrib('class', 'sp_input_select')
->setDecorators(array('viewHelper'))
->setMultiOptions($this->getLimitOptions());
if (isset($storedCrit["limit"])) {
$limit->setValue($storedCrit["limit"]["modifier"]);
}
$this->addElement($limit);
$limitValue = new Zend_Form_Element_Text('sp_limit_value');
$limitValue->setAttrib('class', 'sp_input_text_limit')
->setLabel(_('Limit to'))
->setDecorators(array('viewHelper'));
$this->addElement($limitValue);
if (isset($storedCrit["limit"])) {
$limitValue->setValue($storedCrit["limit"]["value"]);
} else {
// setting default to 1 hour
$limitValue->setValue(1);
}
//getting block content candidate count that meets criteria
$bl = new Application_Model_Block($p_blockId);
if ($p_isValid) {
$files = $bl->getListofFilesMeetCriteria();
$showPoolCount = true;
} else {
$files = null;
$showPoolCount = false;
}
$generate = new Zend_Form_Element_Button('generate_button');
$generate->setAttrib('class', 'sp-button btn');
$generate->setAttrib('title', _('Generate playlist content and save criteria'));
$generate->setIgnore(true);
$generate->setLabel(_('Generate'));
$generate->setDecorators(array('viewHelper'));
$this->addElement($generate);
$shuffle = new Zend_Form_Element_Button('shuffle_button');
$shuffle->setAttrib('class', 'sp-button btn');
$shuffle->setAttrib('title', _('Shuffle playlist content'));
$shuffle->setIgnore(true);
$shuffle->setLabel(_('Shuffle'));
$shuffle->setDecorators(array('viewHelper'));
$this->addElement($shuffle);
$this->setDecorators(array(
array('ViewScript', array('viewScript' => 'form/_smart-block-criteria.phtml', "openOption"=> $openSmartBlockOption,
'criteriasLength' => count($this->getCriteriaOptions()), 'poolCount' => $files['count'], 'modRowMap' => $modRowMap,
'showPoolCount' => $showPoolCount))
));
}
public function preValidation($params)
{
$data = Application_Model_Block::organizeSmartPlaylistCriteria($params['data']);
// add elelments that needs to be added
// set multioption for modifier according to criteria_field
$modRowMap = array();
foreach ($data['criteria'] as $critKey=>$d) {
$count = 1;
foreach ($d as $modKey=>$modInfo) {
if ($modKey == 0) {
$eleCrit = $this->getElement("sp_criteria_field_".$critKey."_".$modKey);
$eleCrit->setValue($this->getCriteriaOptions($modInfo['sp_criteria_field']));
$eleCrit->setAttrib("disabled", null);
$eleMod = $this->getElement("sp_criteria_modifier_".$critKey."_".$modKey);
$criteriaType = $this->criteriaTypes[$modInfo['sp_criteria_field']];
if ($criteriaType == "s") {
$eleMod->setMultiOptions($this->getStringCriteriaOptions());
} elseif ($criteriaType == "n") {
$eleMod->setMultiOptions($this->getNumericCriteriaOptions());
} else {
$eleMod->setMultiOptions(array('0' => _('Select modifier')));
}
$eleMod->setValue($modInfo['sp_criteria_modifier']);
$eleMod->setAttrib("disabled", null);
$eleValue = $this->getElement("sp_criteria_value_".$critKey."_".$modKey);
$eleValue->setValue($modInfo['sp_criteria_value']);
$eleValue->setAttrib("disabled", null);
if (isset($modInfo['sp_criteria_extra'])) {
$eleExtra = $this->getElement("sp_criteria_extra_".$critKey."_".$modKey);
$eleExtra->setValue($modInfo['sp_criteria_extra']);
$eleValue->setAttrib('class', 'input_text sp_extra_input_text');
$eleExtra->setAttrib("disabled", null);
}
} else {
$criteria = new Zend_Form_Element_Select("sp_criteria_field_".$critKey."_".$modKey);
$criteria->setAttrib('class', 'input_select sp_input_select sp-invisible')
->setValue('Select criteria')
->setDecorators(array('viewHelper'))
->setMultiOptions($this->getCriteriaOptions());
$criteriaType = $this->criteriaTypes[$modInfo['sp_criteria_field']];
$criteria->setValue($this->getCriteriaOptions($modInfo['sp_criteria_field']));
$this->addElement($criteria);
/****************** MODIFIER ***********/
$criteriaModifers = new Zend_Form_Element_Select("sp_criteria_modifier_".$critKey."_".$modKey);
$criteriaModifers->setValue('Select modifier')
->setAttrib('class', 'input_select sp_input_select')
->setDecorators(array('viewHelper'));
if ($criteriaType == "s") {
$criteriaModifers->setMultiOptions($this->getStringCriteriaOptions());
} elseif ($criteriaType == "n") {
$criteriaModifers->setMultiOptions($this->getNumericCriteriaOptions());
} else {
$criteriaModifers->setMultiOptions(array('0' => _('Select modifier')));
}
$criteriaModifers->setValue($modInfo['sp_criteria_modifier']);
$this->addElement($criteriaModifers);
/****************** VALUE ***********/
$criteriaValue = new Zend_Form_Element_Text("sp_criteria_value_".$critKey."_".$modKey);
$criteriaValue->setAttrib('class', 'input_text sp_input_text')
->setDecorators(array('viewHelper'));
$criteriaValue->setValue($modInfo['sp_criteria_value']);
$this->addElement($criteriaValue);
/****************** EXTRA ***********/
$criteriaExtra = new Zend_Form_Element_Text("sp_criteria_extra_".$critKey."_".$modKey);
$criteriaExtra->setAttrib('class', 'input_text sp_extra_input_text')
->setDecorators(array('viewHelper'));
if (isset($modInfo['sp_criteria_extra'])) {
$criteriaExtra->setValue($modInfo['sp_criteria_extra']);
$criteriaValue->setAttrib('class', 'input_text sp_extra_input_text');
} else {
$criteriaExtra->setAttrib('disabled', 'disabled');
}
$this->addElement($criteriaExtra);
$count++;
}
}
$modRowMap[$critKey] = $count;
}
$decorator = $this->getDecorator("ViewScript");
$existingModRow = $decorator->getOption("modRowMap");
foreach ($modRowMap as $key=>$v) {
$existingModRow[$key] = $v;
}
$decorator->setOption("modRowMap", $existingModRow);
// reconstruct the params['criteria'] so we can populate the form
$formData = array();
foreach ($params['data'] as $ele) {
$formData[$ele['name']] = $ele['value'];
}
$this->populate($formData);
return $data;
}
public function isValid($params)
{
$isValid = true;
$data = $this->preValidation($params);
$criteria2PeerMap = array(
0 => "Select criteria",
"album_title" => "DbAlbumTitle",
"artist_name" => "DbArtistName",
"bit_rate" => "DbBitRate",
"bpm" => "DbBpm",
"composer" => "DbComposer",
"conductor" => "DbConductor",
"copyright" => "DbCopyright",
"cuein" => "DbCuein",
"cueout" => "DbCueout",
"encoded_by" => "DbEncodedBy",
"utime" => "DbUtime",
"mtime" => "DbMtime",
"lptime" => "DbLPtime",
"genre" => "DbGenre",
"info_url" => "DbInfoUrl",
"isrc_number" => "DbIsrcNumber",
"label" => "DbLabel",
"language" => "DbLanguage",
"length" => "DbLength",
"mime" => "DbMime",
"mood" => "DbMood",
"owner_id" => "DbOwnerId",
"replay_gain" => "DbReplayGain",
"sample_rate" => "DbSampleRate",
"track_title" => "DbTrackTitle",
"track_number" => "DbTrackNumber",
"year" => "DbYear"
);
// things we need to check
// 1. limit value shouldn't be empty and has upperbound of 24 hrs
// 2. sp_criteria or sp_criteria_modifier shouldn't be 0
// 3. validate formate according to DB column type
$multiplier = 1;
$result = 0;
// validation start
if ($data['etc']['sp_limit_options'] == 'hours') {
$multiplier = 60;
}
if ($data['etc']['sp_limit_options'] == 'hours' || $data['etc']['sp_limit_options'] == 'mins') {
$element = $this->getElement("sp_limit_value");
if ($data['etc']['sp_limit_value'] == "" || floatval($data['etc']['sp_limit_value']) <= 0) {
$element->addError(_("Limit cannot be empty or smaller than 0"));
$isValid = false;
} else {
$mins = floatval($data['etc']['sp_limit_value']) * $multiplier;
if ($mins > 1440) {
$element->addError(_("Limit cannot be more than 24 hrs"));
$isValid = false;
}
}
} else {
$element = $this->getElement("sp_limit_value");
if ($data['etc']['sp_limit_value'] == "" || floatval($data['etc']['sp_limit_value']) <= 0) {
$element->addError(_("Limit cannot be empty or smaller than 0"));
$isValid = false;
} elseif (!ctype_digit($data['etc']['sp_limit_value'])) {
$element->addError(_("The value should be an integer"));
$isValid = false;
} elseif (intval($data['etc']['sp_limit_value']) > 500) {
$element->addError(_("500 is the max item limit value you can set"));
$isValid = false;
}
}
if (isset($data['criteria'])) {
foreach ($data['criteria'] as $rowKey=>$row) {
foreach ($row as $key=>$d) {
$element = $this->getElement("sp_criteria_field_".$rowKey."_".$key);
// check for not selected select box
if ($d['sp_criteria_field'] == "0" || $d['sp_criteria_modifier'] == "0") {
$element->addError(_("You must select Criteria and Modifier"));
$isValid = false;
} else {
$column = CcFilesPeer::getTableMap()->getColumnByPhpName($criteria2PeerMap[$d['sp_criteria_field']]);
// validation on type of column
if (in_array($d['sp_criteria_field'], array('length', 'cuein', 'cueout'))) {
if (!preg_match("/^(\d{2}):(\d{2}):(\d{2})/", $d['sp_criteria_value'])) {
$element->addError(_("'Length' should be in '00:00:00' format"));
$isValid = false;
}
} elseif ($column->getType() == PropelColumnTypes::TIMESTAMP) {
if (!preg_match("/(\d{4})-(\d{2})-(\d{2})/", $d['sp_criteria_value'])) {
$element->addError(_("The value should be in timestamp format (e.g. 0000-00-00 or 0000-00-00 00:00:00)"));
$isValid = false;
} else {
$result = Application_Common_DateHelper::checkDateTimeRangeForSQL($d['sp_criteria_value']);
if (!$result["success"]) {
// check for if it is in valid range( 1753-01-01 ~ 12/31/9999 )
$element->addError($result["errMsg"]);
$isValid = false;
}
}
if (isset($d['sp_criteria_extra'])) {
if (!preg_match("/(\d{4})-(\d{2})-(\d{2})/", $d['sp_criteria_extra'])) {
$element->addError(_("The value should be in timestamp format (e.g. 0000-00-00 or 0000-00-00 00:00:00)"));
$isValid = false;
} else {
$result = Application_Common_DateHelper::checkDateTimeRangeForSQL($d['sp_criteria_extra']);
if (!$result["success"]) {
// check for if it is in valid range( 1753-01-01 ~ 12/31/9999 )
$element->addError($result["errMsg"]);
$isValid = false;
}
}
}
} elseif ($column->getType() == PropelColumnTypes::INTEGER &&
$d['sp_criteria_field'] != 'owner_id') {
if (!is_numeric($d['sp_criteria_value'])) {
$element->addError(_("The value has to be numeric"));
$isValid = false;
}
// length check
if ($d['sp_criteria_value'] >= pow(2,31)) {
$element->addError(_("The value should be less then 2147483648"));
$isValid = false;
}
} elseif ($column->getType() == PropelColumnTypes::VARCHAR) {
if (strlen($d['sp_criteria_value']) > $column->getSize()) {
$element->addError(sprintf(_("The value should be less than %s characters"), $column->getSize()));
$isValid = false;
}
}
}
if ($d['sp_criteria_value'] == "") {
$element->addError(_("Value cannot be empty"));
$isValid = false;
}
}//end foreach
}//for loop
}//if
return $isValid;
}
}

View File

@ -101,10 +101,10 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
<div class="media_type_selector" selection_id="4"><?php echo _("Webstreams") ?></div>
</div>
<?php $hint = Application_Common_UsabilityHints::getUsabilityHint(); ?>
<div class="usability_hint" <?php if ($hint == "") { echo "style='display:none'"; } ?>><?php echo $hint; ?></div>
<div class="wrapper dropzone" id="content">
<?php $hint = Application_Common_UsabilityHints::getUsabilityHint(); ?>
<div class="usability_hint" <?php if ($hint == "") { echo "style='display:none'"; } ?>><?php echo $hint; ?></div>
<?php echo $this->layout()->content ?>
</div>

View File

@ -0,0 +1,148 @@
<form class="smart-block-form" method="post" action="">
<dl class='zend_form search-criteria'>
<div id='sp-success' class='success' style='display:none'></div>
<dd id='sp_type-element'>
<label class='sp-label'>
<?php echo $this->element->getElement('sp_type')->getLabel() ?>
</label>
<?php $i=0;
$value = $this->element->getElement('sp_type')->getValue();
foreach ($this->element->getElement('sp_type')->getMultiOptions() as $radio) : ?>
<label class='sp-label' for='sp_type-<?php echo $i?>'>
<input type="radio" value="<?php echo $i ?>" id="sp_type-<?php echo $i ?>" name="sp_type" <?php if($i == $value){echo 'checked="checked"';}?> ><?php echo $radio ?>
</label>
<?php $i = $i + 1; ?>
<?php endforeach; ?>
<span class='playlist_type_help_icon'></span>
</dd>
<dd id='sp_criteria-element' class='criteria-element'>
<?php for ($i = 0; $i < $this->criteriasLength; $i++) {
// modRowMap holds the number of modifier rows for each criteria element
// i.e. if we have 'Album contains 1' and 'Album contains 2' the modRowMap
// for Album is 2
?>
<?php for ($j = 0; $j < $this->modRowMap[$i]; $j++) {
// determine if logic label should be 'and' or 'or'
if ($this->modRowMap[$i] > 1 && $j != $this->modRowMap[$i]-1) $logicLabel = _('or');
else $logicLabel = _('and');
$disabled = $this->element->getElement("sp_criteria_field_".$i."_".$j)->getAttrib('disabled') == 'disabled'?true:false;
// determine if the next row is disabled and only display the logic label if it isn't
if ($j == $this->modRowMap[$i]-1 && $i < 25) {
$n = $i+1;
$nextIndex = $n."_0";
} elseif ($j+1 <= $this->modRowMap[$i]-1) {
$n = $j+1;
$nextIndex = $i."_".$n;
}
$nextDisabled = $this->element->getElement("sp_criteria_field_".$nextIndex)->getAttrib('disabled') == 'disabled'?true:false;
?>
<div <?php if (($i > 0) && $disabled) {
echo 'style=display:none';
} ?>>
<?php echo $this->element->getElement("sp_criteria_field_".$i."_".$j) ?>
<a class='btn btn-small' id='modifier_add_<?php echo $i ?>'>
<i class='icon-white icon-plus'></i>
</a>
<?php echo $this->element->getElement("sp_criteria_modifier_".$i."_".$j) ?>
<?php echo $this->element->getElement("sp_criteria_value_".$i."_".$j) ?>
<span class='sp_text_font' id="extra_criteria" <?php echo $this->element->getElement("sp_criteria_extra_".$i."_".$j)->getAttrib("disabled") == "disabled"?'style="display:none;"':""?>><?php echo _(" to "); ?><?php echo $this->element->getElement('sp_criteria_extra_'.$i."_".$j) ?></span>
<a style='margin-right:3px' class='btn btn-small btn-danger' id='criteria_remove_<?php echo $i ?>'>
<i class='icon-white icon-remove'></i>
</a>
<span class='db-logic-label' <?php if ($nextDisabled) echo "style='display:none'"?>>
<?php echo $logicLabel;?>
</span>
<?php if($this->element->getElement("sp_criteria_field_".$i."_".$j)->hasErrors()) : ?>
<?php foreach($this->element->getElement("sp_criteria_field_".$i."_".$j)->getMessages() as $error): ?>
<span class='errors sp-errors'>
<?php echo $error; ?>
</span>
<?php endforeach; ?>
<?php endif; ?>
</div>
<?php } ?>
<?php } ?>
</dd>
<dd id='sp_repeat_tracks-element'>
<span class='sp_text_font'><?php echo $this->element->getElement('sp_repeat_tracks')->getLabel() ?></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; ?>
<span class='repeat_tracks_help_icon'></span>
</dd>
<dd id='sp_sort-element'>
<span class='sp_text_font'>Sort tracks by</span>
<?php echo $this->element->getElement('sp_sort_options') ?>
<?php if($this->element->getElement("sp_sort_options")->hasErrors()) : ?>
<?php foreach($this->element->getElement("sp_sort_options")->getMessages() as $error): ?>
<span class='errors sp-errors'>
<?php echo $error; ?>
</span>
<?php endforeach; ?>
<?php endif; ?>
</dd>
<dd id='sp_limit-element'>
<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_options') ?>
<?php if($this->element->getElement("sp_limit_value")->hasErrors()) : ?>
<?php foreach($this->element->getElement("sp_limit_value")->getMessages() as $error): ?>
<span class='errors sp-errors'>
<?php echo $error; ?>
</span>
<?php endforeach; ?>
<?php endif; ?>
</dd>
<?php if ($this->showPoolCount) { ?>
<div class='sp_text_font sp_text_font_bold'>
<span id='sp_pool_count' class='sp_text_font sp_text_font_bold'>
<?php
if ($this->poolCount > 1) {
echo $this->poolCount;
?>
<?php echo _("files meet the criteria")?>
</span>
<span class='checked-icon sp-checked-icon' id='sp_pool_count_icon'></span>
<?php
} else if ($this->poolCount == 1) {
echo $this->poolCount;
?>
<?php echo _("file meets the criteria")?>
</span>
<span class='checked-icon sp-checked-icon' id='sp_pool_count_icon'></span>
<?php
} else {
?>
0 <?php echo " "._("files meet the criteria")?>
</span>
<span class='sp-warning-icon' id='sp_pool_count_icon'></span>
<?php
}
?>
</div>
<?php } ?>
</dl>
</form>
<div class='btn-toolbar left-floated'>
<div class='btn-group sp-button'>
<?php echo $this->element->getElement('generate_button');?>
</div>
<div class='btn-group sp-button'>
<?php echo $this->element->getElement('shuffle_button');?>
</div>
</div>

View File

@ -27,10 +27,10 @@ if (isset($this->obj)) {
<div class="btn-toolbar spl-no-margin clearfix left-floated">
<div class='btn-group pull-right'>
<button class="btn btn-inverse" title='<?php echo _("Empty playlist content") ?>' type="button" id="pl-bl-clear-content"><?php echo _("Clear") ?></button>
<button class="btn btn-danger" title='<?php echo _("Empty playlist content") ?>' type="button" id="pl-bl-clear-content"><?php echo _("Clear") ?></button>
</div>
<div class='btn-group pull-right'>
<button class="btn btn-inverse" title='<?php echo _("Shuffle playlist") ?>' type="button" id="playlist_shuffle_button"><?php echo _("Shuffle") ?></button>
<button class="btn" title='<?php echo _("Shuffle playlist") ?>' type="button" id="playlist_shuffle_button"><?php echo _("Shuffle") ?></button>
</div>
<div class='btn-group pull-right'>
<a href="#" id="spl_crossfade" class="btn crossfade-main-button" style="display:<?php echo $count > 0 ?"block;":"none;"?>">

View File

@ -26,17 +26,14 @@ if (isset($this->obj)) {
<dl class="zend_form">
<dt id="description-label"><label for="description"><?php echo _("Description") ?></label></dt>
<dd id="description-element">
<textarea cols="80" rows="24" id="description" name="description"><?php
if (isset($this->unsavedDesc)) echo $this->unsavedDesc;
else echo $this->obj->getDescription();?>
</textarea>
<textarea cols="80" rows="24" id="description" name="description"><?php if (isset($this->unsavedDesc)) echo $this->unsavedDesc; else echo $this->obj->getDescription();?></textarea>
</dd>
</dl>
<?php echo $this->form; ?>
<div class="btn-toolbar spl-no-margin clearfix left-floated">
<div class='btn-group pull-right'>
<button class="btn btn-inverse" title='<?php echo _("Empty smart block content") ?>' type="button" id="pl-bl-clear-content"><?php echo _("Clear") ?></button>
<button class="btn btn-danger" title='<?php echo _("Empty smart block content") ?>' type="button" id="pl-bl-clear-content"><?php echo _("Clear") ?></button>
</div>
<div class='btn-group pull-right'>
<a href="#" id="spl_crossfade" class="btn crossfade-main-button" style="display:<?php echo ($this->obj->isStatic() && $count > 0) ?"block;":"none;"?>">

View File

@ -24,7 +24,7 @@
<div id="show_builder" class="sb-content content-pane wide-panel">
<div class="panel-header">
<ul class="nav nav-tabs">
<li id="timeline-tab" role="presentation" class="active"><a href="#">Scheduled Shows</a></li>
<li id="schedule-tab" role="presentation" class="active"><a href="#">Scheduled Shows</a></li>
</ul>
</div>
<div class="outer-datatable-wrapper active-tab">

View File

@ -68,7 +68,11 @@ div.ColVis_collectionBackground {
.content-pane {
position: relative;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
height: 100%;
border: 1px solid #202020;
@ -105,6 +109,7 @@ div.ColVis_collectionBackground {
.wrapper {
-webkit-flex-flow: column !important;
flex-flow: column !important;
padding-top: 10px !important;
}
.content-pane {
height: auto !important;
@ -114,11 +119,15 @@ div.ColVis_collectionBackground {
flex: 8 100%;
min-height: 50%;
}
}
@media screen and (max-width: 780px) {
.wrapper {
padding: 4px 4px 40px !important;
.usability_hint {
left: 0;
top: auto;
bottom: 0;
width: 100%;
z-index: 100;
}
.spl_sortable {
max-height: 50%;
}
}
@ -187,15 +196,10 @@ div.ColVis_collectionBackground {
top: 2px;
}
div.btn > span
{
div.btn > span {
color: red;
}
.fg-toolbar.ui-toolbar {
border: none;
}
.fg-toolbar.ui-toolbar.ui-widget-header.ui-corner-bl.ui-corner-br.ui-helper-clearfix {
position: absolute;
right: 0;
@ -228,6 +232,19 @@ div.btn > span
border: none;
}
#library_display_wrapper > .dataTables_scrolling,
#show_builder_table_wrapper > .dataTables_scrolling {
border: 1px solid #5b5b5b;
}
thead th.ui-state-default {
cursor: move;
border: solid #666;
border-width: 0 0 1px 1px;
color: #ccc;
}
/* Library Context Menu */
.context-menu-item.icon {
@ -315,6 +332,10 @@ div.btn > span
float: right;
}
#show_builder .fg-toolbar.ui-corner-tl.ui-corner-tr {
border-top: none;
}
.sb-content .dataTables_wrapper {
margin: 0;
}
@ -349,7 +370,7 @@ div.btn > span
}
.nav-tabs {
border-bottom: 1px solid #474747;
border-bottom: 1px solid #5b5b5b;
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
padding: 0;
@ -364,13 +385,12 @@ div.btn > span
text-decoration: none;
background-color: rgba(71,71,71,.5);
}
.nav-tabs :not(.active) a:hover {
background-color: rgba(239, 76, 10, .5) !important;
border: 1px solid transparent !important;
border-bottom: 1px solid #474747 !important;
border-bottom: 1px solid transparent !important;
}
.nav-tabs > .active > a, .nav-tabs > .active > a:hover {
@ -431,6 +451,20 @@ textarea {
/* Playlist/Block/Webstream Editors */
dl > dd > input, dl > dd > textarea {
margin: 0;
}
span.errors.sp-errors {
color: #902d2d;
}
li.ui-state-default {
border: 1px solid #7e7e7e;
}
/* Playlist Editor */
.side_playlist {
position: relative;
width: 100%; /* Override because we're using flexbox */
@ -452,9 +486,14 @@ textarea {
.side_playlist label, .side_playlist h4, .side_playlist span {
color: #efefef;
font-size: 14px;
line-height: 24px;
font-weight: normal;
}
.sb-content fieldset label {
font-size: 14px;
}
.editor_pane_wrapper {
display: -webkit-box;
display: -moz-box;
@ -471,7 +510,14 @@ textarea {
}
.inner_editor_wrapper {
max-height: 60%;
overflow-x: hidden;
width: 100%;
flex: 1 0 100%;
}
.clearfix:after, .side_playlist li:after {
display: none !important;
}
.spl-no-margin {
@ -534,10 +580,45 @@ textarea {
outline-width: 0;
}
/* Smart Block Editor */
.btn-toolbar {
margin: 0;
}
.sp-button {
margin-left: 0;
}
.sp-button + .sp-button {
margin: 0 5px 0 0;
}
.side_playlist .zend_form input {
box-sizing: border-box;
height: 26px;
}
.smart-block-form input[type='radio'] {
vertical-align: bottom;
margin: 0 5px -2px;
}
.smart-block-form input[type='checkbox'] {
vertical-align: bottom;
margin: 0 4px;
}
/* Hacky */
.smart-block-form + .btn-toolbar,
.smart-block-form + .btn-toolbar + .btn-toolbar {
padding-top: 4px;
}
/* Media type selector */
#media_type_nav {
position: absolute;
position: fixed;
top: 139px;
bottom: 0;
@ -626,6 +707,10 @@ textarea {
padding: 3px 9px;
}
.ColVis_title {
color: #000;
}
#show_builder .fg-toolbar > .btn-toolbar {
position: absolute;
top: 36px;
@ -661,6 +746,10 @@ textarea {
text-align: center;
}
.datatable tr td {
text-align: left;
}
th.library_checkbox {
text-align: center !important;
}
@ -673,6 +762,11 @@ th.library_checkbox {
position: fixed !important;
}
/* Since the z-index gets applied dynamically to the */
#ui-datepicker-div {
z-index: 1000 !important;
}
.datatable .ui-state-highlight, .spl_sortable .ui-state-highlight {
background: rgba(255, 93, 26, .6);
border: none;

View File

@ -168,7 +168,7 @@ td.library_bitrate {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
height: 25px;
height: 26px;
width:60%;
}
.dataTables_filter label {
@ -186,13 +186,13 @@ td.library_bitrate {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
height: 25px;
height: 26px;
}
.search-criteria .criteria-element > div .btn-small {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
height: 25px;
height: 26px;
padding: 3px 6px;
}

View File

@ -493,13 +493,17 @@ fieldset {
/* END Master Panel */
.wrapper {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
position: absolute;
top: 141px;
left: 10px;
right: 10px;
padding:10px 0 0 0;
bottom: 0;
left: 0;
right: 0;
padding: 10px;
}
.alpha-block {
@ -932,7 +936,7 @@ dl.inline-list dd {
.DataTables_sort_wrapper .ui-icon {
display: block;
float: right;
margin: 5px 5px 5px 5px;
margin: 5px 0;
}
.dataTables_type {
float:right;
@ -991,9 +995,10 @@ dl.inline-list dd {
.dataTables_info {
float: left;
padding: 10px;
font-size:12px;
font-weight:normal;
padding-left: 10px;
font-size: 15px;
font-weight: normal;
line-height: 36px;
}
.dataTables_paginate {
@ -1019,10 +1024,13 @@ dl.inline-list dd {
font-family: Arial,Helvetica,sans-serif;
font-size: 12px;
height: 25px;
margin: 0;
margin: 0 0 0 4px;
padding: 2px 2px 2px 0;
vertical-align: top;
}
.dataTables_empty {
cursor: auto;
}
table.dataTable tbody tr,
table.dataTable span.DataTables_sort_icon {
cursor: pointer;
@ -1370,10 +1378,14 @@ input[type="checkbox"] {
}
#schedule_calendar {
box-sizing: border-box;
width: 100%;
margin: 0;
}
#schedule_block_table {
padding-right: 5px;
width: 100%;
}
@ -1399,8 +1411,7 @@ div.fc-agenda > div:nth-child(2)
{
width: 100%;
height: 100%;
padding: 0px;
padding-right: 20px !important;
padding: 0 5px 0 0;
}
.schedule_change_slots /** The time span combobox */
@ -1409,7 +1420,7 @@ div.fc-agenda > div:nth-child(2)
}
#schedule_block_table td {
padding: 0px;
padding: 0;
vertical-align: top;
}
@ -3392,29 +3403,18 @@ dd .stream-status {
/* Usability Hints */
/*
* This is a temporary solution to a larger issue;
* we should revisit this (and really all of the
* absolute positioning in Airtime) when we want
* to focus on responsive design.
*/
.usability_hint:not(.hidden) + .wrapper {
top: 170px;
-webkit-transition: top 0.2s linear;
-moz-transition: top 0.2s linear;
-o-transition: top 0.2s linear;
transition: top 0.2s linear;
}
.usability_hint {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 5px 10px 5px 10px;
border: 1px solid #ff611f;
background-color: #ff611f;
color: white;
font-size: 14px;
position: absolute;
position: fixed;
top: 139px;
width: 100%;
z-index: 1;
@ -3427,3 +3427,9 @@ dd .stream-status {
.calendar-context-menu {
min-width: 200px !important;
}
/* Add Media Page */
#upload_form, #recent_uploads_wrapper {
box-sizing: border-box;
}

View File

@ -1,5 +1,6 @@
var previewWidth = 482,
previewHeight = 110;
previewHeight = 110,
USABILITY_HINT_PADDING = 40;
$(document).ready(function() {
@ -12,6 +13,9 @@ $(document).ready(function() {
//this statement tells the browser to fade out any success message after 5 seconds
setTimeout(function(){$(".success").fadeOut("slow", function(){$(this).empty()});}, 5000);
if ($('.usability_hint:visible')) {
$(".wrapper").css("padding-top", USABILITY_HINT_PADDING); // Account for usability hint
}
});
/*
@ -162,6 +166,17 @@ function removeSuccessMsg() {
$status.fadeOut("slow", function(){$status.empty()});
}
function hideHint(h) {
h.hide("slow").addClass("hidden");
$(".wrapper").css("padding-top", 10);
}
function showHint(h) {
console.log("test");
h.show("slow").removeClass("hidden");
$(".wrapper").css("padding-top", USABILITY_HINT_PADDING); // Account for usability hint
}
function getUsabilityHint() {
var pathname = window.location.pathname;
$.getJSON("/api/get-usability-hint", {"format": "json", "userPath": pathname}, function(json) {
@ -169,26 +184,25 @@ function getUsabilityHint() {
var current_hint = $hint_div.html();
if (json === "") {
// there are no more hints to display to the user
$hint_div.hide("slow").addClass("hidden");
hideHint($hint_div);
} else if (current_hint !== json) {
// we only change the message if it is new
if ($hint_div.is(":visible")) {
$hint_div.hide("slow").addClass("hidden");
hideHint($hint_div);
}
$hint_div.html(json);
$hint_div.show("slow").removeClass("hidden");
showHint($hint_div);
} else {
// hint is the same before we hid it so we just need to show it
if ($hint_div.is(":hidden")) {
$hint_div.show("slow").removeClass("hidden");
showHint($hint_div);
}
}
});
}
$(document).mouseup(function (e) {
var mb = $("#menu-btn"),
w = $(window).width();
var mb = $("#menu-btn"), w = $(window).width();
if (!mb.is(e.target) && mb.has(e.target).length === 0 && w <= 970) {
$('#nav .responsive-menu').slideUp();
}

View File

@ -559,16 +559,16 @@ var AIRTIME = (function(AIRTIME) {
/* ISRC Number */ { "sTitle" : $.i18n._("ISRC") , "mDataProp" : "isrc_number" , "bVisible" : false , "sClass" : "library_isrc" , "sWidth" : "150px" },
/* Label */ { "sTitle" : $.i18n._("Label") , "mDataProp" : "label" , "bVisible" : false , "sClass" : "library_label" , "sWidth" : "125px" },
/* Language */ { "sTitle" : $.i18n._("Language") , "mDataProp" : "language" , "bVisible" : false , "sClass" : "library_language" , "sWidth" : "125px" },
/* Last Modified */ { "sTitle" : $.i18n._("Last Modified") , "mDataProp" : "mtime" , "bVisible" : false , "sClass" : "library_modified_time" , "sWidth" : "125px" },
/* Last Played */ { "sTitle" : $.i18n._("Last Played") , "mDataProp" : "lptime" , "bVisible" : false , "sClass" : "library_modified_time" , "sWidth" : "125px" },
/* Last Modified */ { "sTitle" : $.i18n._("Last Modified") , "mDataProp" : "mtime" , "bVisible" : false , "sClass" : "library_modified_time" , "sWidth" : "155" },
/* Last Played */ { "sTitle" : $.i18n._("Last Played") , "mDataProp" : "lptime" , "bVisible" : false , "sClass" : "library_modified_time" , "sWidth" : "155px" },
/* Length */ { "sTitle" : $.i18n._("Length") , "mDataProp" : "length" , "sClass" : "library_length" , "sWidth" : "80px" } ,
/* Mime */ { "sTitle" : $.i18n._("Mime") , "mDataProp" : "mime" , "bVisible" : false , "sClass" : "library_mime" , "sWidth" : "80px" },
/* Mood */ { "sTitle" : $.i18n._("Mood") , "mDataProp" : "mood" , "bVisible" : false , "sClass" : "library_mood" , "sWidth" : "70px" },
/* Owner */ { "sTitle" : $.i18n._("Owner") , "mDataProp" : "owner_id" , "bVisible" : false , "sClass" : "library_language" , "sWidth" : "125px" },
/* Replay Gain */ { "sTitle" : $.i18n._("Replay Gain") , "mDataProp" : "replay_gain" , "bVisible" : false , "sClass" : "library_replay_gain" , "sWidth" : "80px" },
/* Sample Rate */ { "sTitle" : $.i18n._("Sample Rate") , "mDataProp" : "sample_rate" , "bVisible" : false , "sClass" : "library_sr" , "sWidth" : "80px" },
/* Track Number */ { "sTitle" : $.i18n._("Track Number") , "mDataProp" : "track_number" , "bVisible" : false , "sClass" : "library_track" , "sWidth" : "65px" },
/* Upload Time */ { "sTitle" : $.i18n._("Uploaded") , "mDataProp" : "utime" , "bVisible" : false , "sClass" : "library_upload_time" , "sWidth" : "125px" } ,
/* Replay Gain */ { "sTitle" : $.i18n._("Replay Gain") , "mDataProp" : "replay_gain" , "bVisible" : false , "sClass" : "library_replay_gain" , "sWidth" : "125px" },
/* Sample Rate */ { "sTitle" : $.i18n._("Sample Rate") , "mDataProp" : "sample_rate" , "bVisible" : false , "sClass" : "library_sr" , "sWidth" : "125px" },
/* Track Number */ { "sTitle" : $.i18n._("Track Number") , "mDataProp" : "track_number" , "bVisible" : false , "sClass" : "library_track" , "sWidth" : "125px" },
/* Upload Time */ { "sTitle" : $.i18n._("Uploaded") , "mDataProp" : "utime" , "bVisible" : false , "sClass" : "library_upload_time" , "sWidth" : "155px" } ,
/* Website */ { "sTitle" : $.i18n._("Website") , "mDataProp" : "info_url" , "bVisible" : false , "sClass" : "library_url" , "sWidth" : "150px" },
/* Year */ { "sTitle" : $.i18n._("Year") , "mDataProp" : "year" , "bVisible" : false , "sClass" : "library_year" , "sWidth" : "60px" }
],

View File

@ -586,7 +586,7 @@ var AIRTIME = (function(AIRTIME){
position: {
my: "left bottom",
at: "right center"
},
}
})
} else {
$(value).bind("click", openAudioPreview);
@ -968,7 +968,6 @@ var AIRTIME = (function(AIRTIME){
alert(json.error);
}
if (json.html !== undefined) {
console.log(json);
closeTab();
openPlaylist(json);
}
@ -1547,8 +1546,8 @@ var AIRTIME = (function(AIRTIME){
mod.onResize = function() {
var h = $(".panel-header .nav").height();
$(".pl-content").css("margin-top", h + 4); // 8px extra for padding
$("#show_builder_table_wrapper").css("top", h + 4);
$(".pl-content").css("margin-top", h + 5); // 8px extra for padding
$("#show_builder_table_wrapper").css("top", h + 5);
};
return AIRTIME;

View File

@ -0,0 +1,609 @@
$(document).ready(function() {
setSmartBlockEvents();
});
function setSmartBlockEvents() {
var activeTab = $('.active-tab'),
form = activeTab.find('.smart-block-form');
/********** ADD CRITERIA ROW **********/
form.find('#criteria_add').live('click', function(){
var div = $('dd[id="sp_criteria-element"]').children('div:visible:last');
div.find('.db-logic-label').text('and').show();
div = div.next().show();
div.children().removeAttr('disabled');
div = div.next();
if (div.length === 0) {
$(this).hide();
}
appendAddButton();
appendModAddButton();
removeButtonCheck();
});
/********** ADD MODIFIER ROW **********/
form.find('a[id^="modifier_add"]').live('click', function(){
var criteria_value = $(this).siblings('select[name^="sp_criteria_field"]').val();
//make new modifier row
var newRow = $(this).parent().clone(),
newRowCrit = newRow.find('select[name^="sp_criteria_field"]'),
newRowMod = newRow.find('select[name^="sp_criteria_modifier"]'),
newRowVal = newRow.find('input[name^="sp_criteria_value"]'),
newRowExtra = newRow.find('input[name^="sp_criteria_extra"]'),
newRowRemove = newRow.find('a[id^="criteria_remove"]');
//remove error msg
if (newRow.children().hasClass('errors sp-errors')) {
newRow.find('span[class="errors sp-errors"]').remove();
}
//hide the critieria field select box
newRowCrit.addClass('sp-invisible');
//keep criteria value the same
newRowCrit.val(criteria_value);
//reset all other values
newRowMod.val('0');
newRowVal.val('');
newRowExtra.val('');
disableAndHideExtraField(newRowVal);
sizeTextBoxes(newRowVal, 'sp_extra_input_text', 'sp_input_text');
//remove the 'criteria add' button from new modifier row
newRow.find('#criteria_add').remove();
$(this).parent().after(newRow);
reindexElements();
appendAddButton();
appendModAddButton();
removeButtonCheck();
});
/********** REMOVE ROW **********/
form.find('a[id^="criteria_remove"]').live('click', function(){
var curr = $(this).parent();
var curr_pos = curr.index();
var list = curr.parent();
var list_length = list.find("div:visible").length;
var count = list_length - curr_pos;
var next = curr.next();
var item_to_hide;
var prev;
var index;
//remove error message from current row, if any
var error_element = curr.find('span[class="errors sp-errors"]');
if (error_element.is(':visible')) {
error_element.remove();
}
/* assign next row to current row for all rows below and including
* the row getting removed
*/
for (var i=0; i<count; i++) {
index = getRowIndex(curr);
var criteria = next.find('[name^="sp_criteria_field"]').val();
curr.find('[name^="sp_criteria_field"]').val(criteria);
var modifier = next.find('[name^="sp_criteria_modifier"]').val();
populateModifierSelect(curr.find('[name^="sp_criteria_field"]'), false);
curr.find('[name^="sp_criteria_modifier"]').val(modifier);
var criteria_value = next.find('[name^="sp_criteria_value"]').val();
curr.find('[name^="sp_criteria_value"]').val(criteria_value);
/* if current and next row have the extra criteria value
* (for 'is in the range' modifier), then assign the next
* extra value to current and remove that element from
* next row
*/
if (curr.find('[name^="sp_criteria_extra"]').attr("disabled") != "disabled"
&& next.find('#extra_criteria').is(':visible')) {
var criteria_extra = next.find('[name^="sp_criteria_extra"]').val();
curr.find('[name^="sp_criteria_extra"]').val(criteria_extra);
disableAndHideExtraField(next.find(':first-child'), getRowIndex(next));
/* if only the current row has the extra criteria value,
* then just remove the current row's extra criteria element
*/
} else if (curr.find('[name^="sp_criteria_extra"]').attr("disabled") != "disabled"
&& next.find('#extra_criteria').not(':visible')) {
disableAndHideExtraField(curr.find(':first-child'), index);
/* if only the next row has the extra criteria value,
* then add the extra criteria element to current row
* and assign next row's value to it
*/
} else if (next.find('#extra_criteria').is(':visible')) {
criteria_extra = next.find('[name^="sp_criteria_extra"]').val();
enableAndShowExtraField(curr.find(':first-child'), index);
curr.find('[name^="sp_criteria_extra"]').val(criteria_extra);
}
/* determine if current row is a modifier row
* if it is, make the criteria select invisible
*/
prev = curr.prev();
if (curr.find('[name^="sp_criteria_field"]').val() == prev.find('[name^="sp_criteria_field"]').val()) {
if (!curr.find('select[name^="sp_criteria_field"]').hasClass('sp-invisible')) {
curr.find('select[name^="sp_criteria_field"]').addClass('sp-invisible');
}
} else {
if (curr.find('select[name^="sp_criteria_field"]').hasClass('sp-invisible')) {
curr.find('select[name^="sp_criteria_field"]').removeClass('sp-invisible');
}
}
curr = next;
next = curr.next();
}
/* Disable the last visible row since it holds the values the user removed
* Reset the values to empty and resize the criteria value textbox
* in case the row had the extra criteria textbox
*/
item_to_hide = list.find('div:visible:last');
item_to_hide.children().attr('disabled', 'disabled');
if (item_to_hide.find('select[name^="sp_criteria_field"]').hasClass('sp-invisible')) {
item_to_hide.find('select[name^="sp_criteria_field"]').removeClass('sp-invisible');
}
item_to_hide.find('[name^="sp_criteria_field"]').val(0).end()
.find('[name^="sp_criteria_modifier"]').val(0).end()
.find('[name^="sp_criteria_value"]').val('').end()
.find('[name^="sp_criteria_extra"]').val('');
sizeTextBoxes(item_to_hide.find('[name^="sp_criteria_value"]'), 'sp_extra_input_text', 'sp_input_text');
item_to_hide.hide();
list.next().show();
//check if last row is a modifier row
var last_row = list.find('div:visible:last');
if (last_row.find('[name^="sp_criteria_field"]').val() == last_row.prev().find('[name^="sp_criteria_field"]').val()) {
if (!last_row.find('select[name^="sp_criteria_field"]').hasClass('sp-invisible')) {
last_row.find('select[name^="sp_criteria_field"]').addClass('sp-invisible');
}
}
// always put '+' button on the last enabled row
appendAddButton();
reindexElements();
// always put '+' button on the last modifier row
appendModAddButton();
// remove the 'x' button if only one row is enabled
removeButtonCheck();
});
/********** SAVE ACTION **********/
// moved to spl.js
/********** GENERATE ACTION **********/
activeTab.find('button[id="generate_button"]').live("click", function(){
buttonClickAction('generate', 'new-playlist/smart-block-generate');
});
/********** SHUFFLE ACTION **********/
activeTab.find('button[id="shuffle_button"]').live("click", function(){
buttonClickAction('shuffle', 'new-playlist/smart-block-shuffle');
});
/********** CHANGE PLAYLIST TYPE **********/
form.find('dd[id="sp_type-element"]').live("change", function(){
setupUI();
AIRTIME.library.checkAddButton();
});
/********** CRITERIA CHANGE **********/
form.find('select[id^="sp_criteria"]:not([id^="sp_criteria_modifier"])').live("change", function(){
var index = getRowIndex($(this).parent());
//need to change the criteria value for any modifier rows
var critVal = $(this).val();
var divs = $(this).parent().nextAll(':visible');
$.each(divs, function(i, div){
var critSelect = $(div).children('select[id^="sp_criteria_field"]');
if (critSelect.hasClass('sp-invisible')) {
critSelect.val(critVal);
/* If the select box is visible we know the modifier rows
* have ended
*/
} else {
return false;
}
});
// disable extra field and hide the span
disableAndHideExtraField($(this), index);
populateModifierSelect(this, true);
});
/********** MODIFIER CHANGE **********/
form.find('select[id^="sp_criteria_modifier"]').live("change", function(){
var criteria_value = $(this).next(),
index_num = getRowIndex($(this).parent());
if ($(this).val() == 'is in the range') {
enableAndShowExtraField(criteria_value, index_num);
} else {
disableAndHideExtraField(criteria_value, index_num);
}
});
setupUI();
appendAddButton();
appendModAddButton();
removeButtonCheck();
}
function getRowIndex(ele) {
var id = ele.find('[name^="sp_criteria_field"]').attr('id'),
delimiter = '_',
start = 3,
tokens = id.split(delimiter).slice(start),
index = tokens.join(delimiter);
return index;
}
/* This function appends a '+' button for the last
* modifier row of each criteria.
* If there are no modifier rows, the '+' button
* remains at the criteria row
*/
function appendModAddButton() {
var divs = $('.active-tab .smart-block-form').find('div select[name^="sp_criteria_modifier"]').parent(':visible');
$.each(divs, function(i, div){
if (i > 0) {
/* If the criteria field is hidden we know it is a modifier row
* and can hide the previous row's modifier add button
*/
if ($(div).find('select[name^="sp_criteria_field"]').hasClass('sp-invisible')) {
$(div).prev().find('a[id^="modifier_add"]').addClass('sp-invisible');
} else {
$(div).prev().find('a[id^="modifier_add"]').removeClass('sp-invisible');
}
}
//always add modifier add button to the last row
if (i+1 == divs.length) {
$(div).find('a[id^="modifier_add"]').removeClass('sp-invisible');
}
});
}
/* This function re-indexes all the form elements.
* We need to do this everytime a row gets deleted
*/
function reindexElements() {
var divs = $('.active-tab .smart-block-form').find('div select[name^="sp_criteria_field"]').parent(),
index = 0,
modIndex = 0;
/* Hide all logic labels
* We will re-add them as each row gets indexed
*/
$('.db-logic-label').text('').hide();
$.each(divs, function(i, div){
if (i > 0 && index < 26) {
/* If the current row's criteria field is hidden we know it is
* a modifier row
*/
if ($(div).find('select[name^="sp_criteria_field"]').hasClass('sp-invisible')) {
if ($(div).is(':visible')) {
$(div).prev().find('.db-logic-label').text('or').show();
}
modIndex++;
} else {
if ($(div).is(':visible')) {
$(div).prev().find('.db-logic-label').text('and').show();
}
index++;
modIndex = 0;
}
$(div).find('select[name^="sp_criteria_field"]').attr('name', 'sp_criteria_field_'+index+'_'+modIndex);
$(div).find('select[name^="sp_criteria_field"]').attr('id', 'sp_criteria_field_'+index+'_'+modIndex);
$(div).find('select[name^="sp_criteria_modifier"]').attr('name', 'sp_criteria_modifier_'+index+'_'+modIndex);
$(div).find('select[name^="sp_criteria_modifier"]').attr('id', 'sp_criteria_modifier_'+index+'_'+modIndex);
$(div).find('input[name^="sp_criteria_value"]').attr('name', 'sp_criteria_value_'+index+'_'+modIndex);
$(div).find('input[name^="sp_criteria_value"]').attr('id', 'sp_criteria_value_'+index+'_'+modIndex);
$(div).find('input[name^="sp_criteria_extra"]').attr('name', 'sp_criteria_extra_'+index+'_'+modIndex);
$(div).find('input[name^="sp_criteria_extra"]').attr('id', 'sp_criteria_extra_'+index+'_'+modIndex);
$(div).find('a[name^="modifier_add"]').attr('id', 'modifier_add_'+index);
$(div).find('a[id^="criteria_remove"]').attr('id', 'criteria_remove_'+index+'_'+modIndex);
} else if (i > 0) {
$(div).remove();
}
});
}
function buttonClickAction(clickType, url){
var data = $('.active-tab .smart-block-form').serializeArray(),
obj_id = $('.active-tab .obj_id').val();
enableLoadingIcon();
$.post(url, {format: "json", data: data, obj_id: obj_id}, function(data){
callback(data, clickType);
disableLoadingIcon();
});
}
function setupUI() {
var activeTab = $('.active-tab'),
playlist_type = activeTab.find('input:radio[name=sp_type]:checked').val();
/* Activate or Deactivate shuffle button
* It is only active if playlist is not empty
*/
var sortable = activeTab.find('.spl_sortable'),
plContents = sortable.children(),
shuffleButton = activeTab.find('.sp-button, #pl-bl-clear-content');
if (!plContents.hasClass('spl_empty')) {
if (shuffleButton.hasClass('ui-state-disabled')) {
shuffleButton.removeClass('ui-state-disabled');
shuffleButton.removeAttr('disabled');
}
} else if (!shuffleButton.hasClass('ui-state-disabled')) {
shuffleButton.addClass('ui-state-disabled');
shuffleButton.attr('disabled', 'disabled');
}
if (activeTab.find('.obj_type').val() == 'block') {
if (playlist_type == "0") {
shuffleButton.parent().show();
sortable.show();
} else {
shuffleButton.parent().hide();
sortable.hide();
}
}
$(".playlist_type_help_icon").qtip({
content: {
text: $.i18n._("A static smart block will save the criteria and generate the block content immediately. This allows you to edit and view it in the Library before adding it to a show.")+"<br /><br />" +
$.i18n._("A dynamic smart block will only save the criteria. The block content will get generated upon adding it to a show. You will not be able to view and edit the content in the Library.")
},
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"
}
});
$(".repeat_tracks_help_icon").qtip({
content: {
text: sprintf($.i18n._("The desired block length will not be reached if %s cannot find enough unique tracks to match your criteria. Enable this option if you wish to allow tracks to be added multiple times to the smart block."), PRODUCT_NAME)
},
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) {
var spanExtra = valEle.nextAll("#extra_criteria");
spanExtra.children('#sp_criteria_extra_'+index).removeAttr("disabled");
spanExtra.show();
//make value input smaller since we have extra element now
var criteria_val = $('#sp_criteria_value_'+index);
sizeTextBoxes(criteria_val, 'sp_input_text', 'sp_extra_input_text');
}
function disableAndHideExtraField(valEle, index) {
var spanExtra = valEle.nextAll("#extra_criteria");
spanExtra.children('#sp_criteria_extra_'+index).val("").attr("disabled", "disabled");
spanExtra.hide();
//make value input larger since we don't have extra field now
var criteria_value = $('#sp_criteria_value_'+index);
sizeTextBoxes(criteria_value, 'sp_extra_input_text', 'sp_input_text');
}
function sizeTextBoxes(ele, classToRemove, classToAdd) {
if (ele.hasClass(classToRemove)) {
ele.removeClass(classToRemove).addClass(classToAdd);
}
}
function populateModifierSelect(e, popAllMods) {
var criteria_type = getCriteriaOptionType(e),
index = getRowIndex($(e).parent()),
divs;
if (popAllMods) {
index = index.substring(0, 1);
}
divs = $(e).parents().find('select[id^="sp_criteria_modifier_'+index+'"]');
$.each(divs, function(i, div){
$(div).children().remove();
if (criteria_type == 's') {
$.each(stringCriteriaOptions, function(key, value){
$(div).append($('<option></option>')
.attr('value', key)
.text(value));
});
} else {
$.each(numericCriteriaOptions, function(key, value){
$(div).append($('<option></option>')
.attr('value', key)
.text(value));
});
}
});
}
function getCriteriaOptionType(e) {
var criteria = $(e).val();
return criteriaTypes[criteria];
}
function callback(json, type) {
var dt = $('table[id="library_display"]').dataTable(),
form = $('.active-tab .smart-block-form');
if (type == 'shuffle' || type == 'generate') {
if (json.error !== undefined) {
alert(json.error);
}
AIRTIME.playlist.closeTab();
AIRTIME.playlist.fnOpenPlaylist(json);
if (json.result == "0") {
if (type == 'shuffle') {
form.find('.success').text($.i18n._('Smart block shuffled'));
} else if (type == 'generate') {
form.find('.success').text($.i18n._('Smart block generated and criteria saved'));
//redraw library table so the length gets updated
dt.fnStandingRedraw();
}
form.find('.success').show();
}
form.find('#smart_block_options').removeClass("closed");
} else {
AIRTIME.playlist.closeTab();
AIRTIME.playlist.fnOpenPlaylist(json);
if (json.result == "0") {
$('.active-tab #sp-success-saved').text($.i18n._('Smart block saved')).show();
//redraw library table so the length gets updated
dt.fnStandingRedraw();
}
form.find('#smart_block_options').removeClass("closed");
}
setTimeout(removeSuccessMsg, 5000);
}
function appendAddButton() {
var add_button = "<a class='btn btn-small' id='criteria_add'>" +
"<i class='icon-white icon-plus'></i></a>";
var rows = $('.active-tab #smart_block_options'),
enabled = rows.find('select[name^="sp_criteria_field"]:enabled');
rows.find('#criteria_add').remove();
if (enabled.length > 1) {
rows.find('select[name^="sp_criteria_field"]:enabled:last')
.siblings('a[id^="criteria_remove"]')
.after(add_button);
} else {
enabled.siblings('span[id="extra_criteria"]')
.after(add_button);
}
}
function removeButtonCheck() {
var rows = $('.active-tab dd[id="sp_criteria-element"]').children('div'),
enabled = rows.find('select[name^="sp_criteria_field"]:enabled'),
rmv_button = enabled.siblings('a[id^="criteria_remove"]');
if (enabled.length == 1) {
rmv_button.attr('disabled', 'disabled');
rmv_button.hide();
} else {
rmv_button.removeAttr('disabled');
rmv_button.show();
}
}
function enableLoadingIcon() {
$(".side_playlist.active-tab").block({
message: $.i18n._("Processing..."),
theme: true,
allowBodyStretch: true,
applyPlatformOpacityRules: false
});
}
function disableLoadingIcon() {
$(".side_playlist.active-tab").unblock()
}
// We need to know if the criteria value will be a string
// or numeric value in order to populate the modifier
// select list
var criteriaTypes = {
0 : "",
"album_title" : "s",
"bit_rate" : "n",
"bpm" : "n",
"composer" : "s",
"conductor" : "s",
"copyright" : "s",
"cuein" : "n",
"cueout" : "n",
"artist_name" : "s",
"encoded_by" : "s",
"utime" : "n",
"mtime" : "n",
"lptime" : "n",
"genre" : "s",
"isrc_number" : "s",
"label" : "s",
"language" : "s",
"length" : "n",
"mime" : "s",
"mood" : "s",
"owner_id" : "s",
"replay_gain" : "n",
"sample_rate" : "n",
"track_title" : "s",
"track_number" : "n",
"info_url" : "s",
"year" : "n"
};
var stringCriteriaOptions = {
"0" : $.i18n._("Select modifier"),
"contains" : $.i18n._("contains"),
"does not contain" : $.i18n._("does not contain"),
"is" : $.i18n._("is"),
"is not" : $.i18n._("is not"),
"starts with" : $.i18n._("starts with"),
"ends with" : $.i18n._("ends with")
};
var numericCriteriaOptions = {
"0" : $.i18n._("Select modifier"),
"is" : $.i18n._("is"),
"is not" : $.i18n._("is not"),
"is greater than" : $.i18n._("is greater than"),
"is less than" : $.i18n._("is less than"),
"is in the range" : $.i18n._("is in the range")
};

View File

@ -331,7 +331,7 @@ function reindexElements() {
function buttonClickAction(clickType, url){
var data = $('#smart-block-form').serializeArray(),
obj_id = $('input[id="obj_id"]').val();
obj_id = $('.obj_id').val();
enableLoadingIcon();
$.post(url, {format: "json", data: data, obj_id: obj_id}, function(data){

View File

@ -584,7 +584,7 @@ var AIRTIME = (function(AIRTIME){
$node.empty();
}
sSeparatorHTML = '<span>'+$.i18n._("Show Empty")+'</span>';
sSeparatorHTML = '<span>'+$.i18n._("Drag tracks here from the library")+'</span>';
cl = cl + " sb-empty odd";
fnPrepareSeparatorRow(sSeparatorHTML, cl, 1);
@ -773,12 +773,12 @@ var AIRTIME = (function(AIRTIME){
"sAjaxDataProp": "schedule",
"oLanguage": datatables_dict,
"sAjaxSource": baseUrl+"showbuilder/builder-feed" ,
"sAjaxSource": baseUrl+"showbuilder/builder-feed",
"bScrollCollapseY": false
});
$sbTable.find("tbody").on("mousedown", "tr:not(.sb-past, .sb-empty)", function(ev) {
$sbTable.find("tbody").on("mousedown", "tr:not(.sb-header, .sb-footer, .sb-past, .sb-empty, :has(td.dataTables_empty))", function(ev) {
var $tr = $(this),
// Get the ID of the selected row
$rowId = $tr.attr("id");
@ -814,7 +814,7 @@ var AIRTIME = (function(AIRTIME){
$previouslySelected = $tr;
});
$sbTable.find("tbody").on("click", "tr:not(.sb-past, .sb-empty)", function(ev) {
$sbTable.find("tbody").on("click", "tr:not(.sb-header, .sb-footer, .sb-past, .sb-empty, :has(td.dataTables_empty))", function(ev) {
if (flagForDeselection) {
flagForDeselection = false;
$(this).removeClass(SB_SELECTED_CLASS);

View File

@ -165,8 +165,10 @@ AIRTIME = (function(AIRTIME) {
$builder = $("#show_builder");
$fs = $builder.find('fieldset');
$("#timeline-tab").on("click", function() {
AIRTIME.showbuilder.switchTab($("#show_builder .outer-datatable-wrapper"), $(this));
$("#schedule-tab").on("click", function() {
if (!$(this).hasClass('active')) {
AIRTIME.showbuilder.switchTab($("#show_builder .outer-datatable-wrapper"), $(this));
}
});
/*