Merge branch 'saas-dev' into saas-stream-settings

This commit is contained in:
Duncan Sommerville 2015-07-08 12:47:24 -04:00
commit 6b9d9e8063
17 changed files with 186 additions and 141 deletions

View File

@ -146,9 +146,7 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
$baseUrl = Application_Common_OsPath::getBaseDir(); $baseUrl = Application_Common_OsPath::getBaseDir();
$view->headLink(array('rel' => 'icon', $view->headLink(array('rel' => 'icon', 'href' => $baseUrl . 'favicon.ico?' . $CC_CONFIG['airtime_version'], 'type' => 'image/x-icon'), 'PREPEND')
'href' => $baseUrl . 'favicon.ico?' . $CC_CONFIG['airtime_version'],
'type' => 'image/x-icon'), 'PREPEND')
->appendStylesheet($baseUrl . 'css/bootstrap.css?' . $CC_CONFIG['airtime_version']) ->appendStylesheet($baseUrl . 'css/bootstrap.css?' . $CC_CONFIG['airtime_version'])
->appendStylesheet($baseUrl . 'css/redmond/jquery-ui-1.8.8.custom.css?' . $CC_CONFIG['airtime_version']) ->appendStylesheet($baseUrl . 'css/redmond/jquery-ui-1.8.8.custom.css?' . $CC_CONFIG['airtime_version'])
->appendStylesheet($baseUrl . 'css/pro_dropdown_3.css?' . $CC_CONFIG['airtime_version']) ->appendStylesheet($baseUrl . 'css/pro_dropdown_3.css?' . $CC_CONFIG['airtime_version'])

View File

@ -2,6 +2,27 @@
class FileDataHelper { class FileDataHelper {
public static function getAudioMimeTypeArray() {
return array(
"audio/ogg" => "ogg",
"application/ogg" => "ogg",
"audio/vorbis" => "ogg",
"audio/mp3" => "mp3",
"audio/mpeg" => "mp3",
"audio/mpeg3" => "mp3",
"audio/aac" => "aac",
"audio/aacp" => "aac",
"audio/mp4" => "mp4",
"audio/x-flac" => "flac",
"audio/wav" => "wav",
"audio/x-wav" => "wav",
"audio/mp2" => "mp2",
"audio/mp1" => "mp1",
"audio/x-ms-wma" => "wma",
"audio/basic" => "au",
);
}
/** /**
* We want to throw out invalid data and process the upload successfully * We want to throw out invalid data and process the upload successfully
* at all costs, so check the data and sanitize it if necessary * at all costs, so check the data and sanitize it if necessary
@ -24,4 +45,24 @@ class FileDataHelper {
$data["bpm"] = intval($data["bpm"]); $data["bpm"] = intval($data["bpm"]);
} }
} }
/**
* Return a suitable extension for the given file
*
* @param string $mime
*
* @return string file extension with(!) a dot (for convenience)
*
* @throws Exception
*/
public static function getFileExtensionFromMime($mime)
{
$mime = trim(strtolower($mime));
try {
return ('.' . static::getAudioMimeTypeArray()[$mime]);
} catch (Exception $e) {
throw new Exception("Unknown file type: $mime");
}
}
} }

View File

@ -45,8 +45,6 @@ class Application_Common_HTTPHelper
class ZendActionHttpException extends Exception { class ZendActionHttpException extends Exception {
private $_action;
/** /**
* @param Zend_Controller_Action $action * @param Zend_Controller_Action $action
* @param int $statusCode * @param int $statusCode
@ -58,8 +56,7 @@ class ZendActionHttpException extends Exception {
*/ */
public function __construct(Zend_Controller_Action $action, $statusCode, $message, public function __construct(Zend_Controller_Action $action, $statusCode, $message,
$code = 0, Exception $previous = null) { $code = 0, Exception $previous = null) {
$this->_action = $action; Logging::error("Error in action " . $action->getRequest()->getActionName()
Logging::info("Error in action " . $action->getRequest()->getActionName()
. " with status code $statusCode: $message"); . " with status code $statusCode: $message");
$action->getResponse() $action->getResponse()
->setHttpResponseCode($statusCode) ->setHttpResponseCode($statusCode)
@ -67,8 +64,4 @@ class ZendActionHttpException extends Exception {
parent::__construct($message, $code, $previous); parent::__construct($message, $code, $previous);
} }
public function getAction() {
return $this->_action;
}
} }

View File

@ -98,7 +98,7 @@ class WidgetHelper
// javascript date formats so it's easier to sort the shows by day. // javascript date formats so it's easier to sort the shows by day.
$result["weekDays"][$weekStartDateTime->format("Y-n-j")] = array(); $result["weekDays"][$weekStartDateTime->format("Y-n-j")] = array();
$result["weekDays"][$weekStartDateTime->format("Y-n-j")]["dayOfMonth"] = $dateParse["day"]; $result["weekDays"][$weekStartDateTime->format("Y-n-j")]["dayOfMonth"] = $dateParse["day"];
$result["weekDays"][$weekStartDateTime->format("Y-n-j")]["dayOfWeek"] = strtoupper(date("D", $weekStartDateTime->getTimestamp())); $result["weekDays"][$weekStartDateTime->format("Y-n-j")]["dayOfWeek"] = strtoupper(_(date("D", $weekStartDateTime->getTimestamp())));
// Shows scheduled for this day will get added to this array when // Shows scheduled for this day will get added to this array when
// we convert the show times to the client's local timezone in weekly-program.phtml // we convert the show times to the client's local timezone in weekly-program.phtml
@ -127,6 +127,16 @@ class WidgetHelper
"ALL", "ALL",
$showQueryDateRangeEnd->format("Y-m-d H:i:s")); $showQueryDateRangeEnd->format("Y-m-d H:i:s"));
// Convert each start and end time string to DateTime objects
// so we can get a real timestamp. The timestamps will be used
// to convert into javascript Date objects.
foreach($shows as &$show) {
$dtStarts = new DateTime($show["starts"], new DateTimeZone("UTC"));
$show["starts_timestamp"] = $dtStarts->getTimestamp();
$dtEnds = new DateTime($show["ends"], new DateTimeZone("UTC"));
$show["ends_timestamp"] = $dtEnds->getTimestamp();
}
$result["shows"] = $shows; $result["shows"] = $shows;
// XSS exploit prevention // XSS exploit prevention

View File

@ -24,7 +24,8 @@ define('LICENSE_URL' , 'http://www.gnu.org/licenses/agpl-3.0-standalone.h
define('AIRTIME_COPYRIGHT_DATE' , '2010-2015'); define('AIRTIME_COPYRIGHT_DATE' , '2010-2015');
define('AIRTIME_REST_VERSION' , '1.1'); define('AIRTIME_REST_VERSION' , '1.1');
define('AIRTIME_API_VERSION' , '1.1'); define('AIRTIME_API_VERSION' , '1.1');
define('AIRTIME_CODE_VERSION' , '2.5.13'); // XXX: it's important that we upgrade this every time we add an upgrade!
define('AIRTIME_CODE_VERSION' , '2.5.14');
// Defaults // Defaults
define('DEFAULT_LOGO_PLACEHOLDER', 1); define('DEFAULT_LOGO_PLACEHOLDER', 1);

View File

@ -198,23 +198,10 @@ class AudiopreviewController extends Zend_Controller_Action
$elementMap['type'] = $track['type']; $elementMap['type'] = $track['type'];
if ($track['type'] == 0) { if ($track['type'] == 0) {
$mime = $track['mime']; $mime = trim(strtolower($track['mime']));
//type is file try {
if (strtolower($mime) === 'audio/mp3') { $elementMap['element_' . FileDataHelper::getAudioMimeTypeArray()[$mime]] = $track['item_id'];
$elementMap['element_mp3'] = $track['item_id']; } catch (Exception $e) {
} elseif (strtolower($mime) === 'audio/ogg') {
$elementMap['element_oga'] = $track['item_id'];
} elseif (strtolower($mime) === 'audio/vorbis') {
$elementMap['element_oga'] = $track['item_id'];
} elseif (strtolower($mime) === 'audio/mp4') {
$elementMap['element_m4a'] = $track['item_id'];
} elseif (strtolower($mime) === 'audio/wav') {
$elementMap['element_wav'] = $track['item_id'];
} elseif (strtolower($mime) === 'audio/x-wav') {
$elementMap['element_wav'] = $track['item_id'];
} elseif (strtolower($mime) === 'audio/x-flac') {
$elementMap['element_flac'] = $track['item_id'];
} else {
throw new Exception("Unknown file type: $mime"); throw new Exception("Unknown file type: $mime");
} }
@ -288,22 +275,10 @@ class AudiopreviewController extends Zend_Controller_Action
$elementMap['type'] = $track['type']; $elementMap['type'] = $track['type'];
if ($track['type'] == 0) { if ($track['type'] == 0) {
$mime = $track['mime']; $mime = trim(strtolower($track['mime']));
if (strtolower($mime) === 'audio/mp3') { try {
$elementMap['element_mp3'] = $track['item_id']; $elementMap['element_' . FileDataHelper::getAudioMimeTypeArray()[$mime]] = $track['item_id'];
} elseif (strtolower($mime) === 'audio/ogg') { } catch (Exception $e) {
$elementMap['element_oga'] = $track['item_id'];
} elseif (strtolower($mime) === 'audio/vorbis') {
$elementMap['element_oga'] = $track['item_id'];
} elseif (strtolower($mime) === 'audio/mp4') {
$elementMap['element_m4a'] = $track['item_id'];
} elseif (strtolower($mime) === 'audio/wav') {
$elementMap['element_wav'] = $track['item_id'];
} elseif (strtolower($mime) === 'audio/x-wav') {
$elementMap['element_wav'] = $track['item_id'];
} elseif (strtolower($mime) === 'audio/x-flac') {
$elementMap['element_flac'] = $track['item_id'];
} else {
throw new Exception("Unknown file type: $mime"); throw new Exception("Unknown file type: $mime");
} }

View File

@ -0,0 +1,4 @@
ALTER TABLE cc_pref ALTER COLUMN subjid SET NULL;
ALTER TABLE cc_pref ALTER COLUMN subjid SET DEFAULT NULL;
CREATE UNIQUE INDEX cc_pref_key_idx ON cc_pref (keystr) WHERE subjid IS NULL;
ANALYZE cc_pref;

View File

@ -98,7 +98,7 @@ class Application_Form_LiveStreamingPreferences extends Zend_Form_SubForm
$showSourceMount = new Zend_Form_Element_Text('show_source_mount'); $showSourceMount = new Zend_Form_Element_Text('show_source_mount');
$showSourceMount->setAttrib('readonly', true) $showSourceMount->setAttrib('readonly', true)
->setLabel(_('Mount:')) ->setLabel(_('Mount:'))
->setValue(isset($showSourceParams["mount"])?$showSourceParams["mount"]:""); ->setValue(isset($showSourceParams["path"])?$showSourceParams["path"]:"");
$this->addElement($showSourceMount); $this->addElement($showSourceMount);
// demo only code // demo only code
@ -127,10 +127,10 @@ class Application_Form_LiveStreamingPreferences extends Zend_Form_SubForm
'viewScript' => 'form/preferences_livestream.phtml', 'viewScript' => 'form/preferences_livestream.phtml',
'master_source_host' => isset($masterSourceParams["host"])?$masterSourceParams["host"]:"", 'master_source_host' => isset($masterSourceParams["host"])?$masterSourceParams["host"]:"",
'master_source_port' => isset($masterSourceParams["port"])?$masterSourceParams["port"]:"", 'master_source_port' => isset($masterSourceParams["port"])?$masterSourceParams["port"]:"",
'master_source_mount' => isset($masterSourceParams["mount"])?$masterSourceParams["mount"]:"", 'master_source_mount' => isset($masterSourceParams["path"])?$masterSourceParams["path"]:"",
'show_source_host' => isset($showSourceParams["host"])?$showSourceParams["host"]:"", 'show_source_host' => isset($showSourceParams["host"])?$showSourceParams["host"]:"",
'show_source_port' => isset($showSourceParams["port"])?$showSourceParams["port"]:"", 'show_source_port' => isset($showSourceParams["port"])?$showSourceParams["port"]:"",
'show_source_mount' => isset($showSourceParams["mount"])?$showSourceParams["mount"]:"", 'show_source_mount' => isset($showSourceParams["path"])?$showSourceParams["path"]:"",
'isDemo' => $isDemo, 'isDemo' => $isDemo,
) )
) )

View File

@ -27,17 +27,18 @@ class Application_Model_Preference
private static function setValue($key, $value, $isUserValue = false) private static function setValue($key, $value, $isUserValue = false)
{ {
$cache = new Cache(); $cache = new Cache();
$con = Propel::getConnection(CcPrefPeer::DATABASE_NAME);
try { $con->beginTransaction();
$con = Propel::getConnection(CcPrefPeer::DATABASE_NAME);
$con->beginTransaction();
try {
/* Comment this out while we reevaluate it in favor of a unique constraint
static::_lock($con); */
$userId = self::getUserId(); $userId = self::getUserId();
if ($isUserValue && is_null($userId)) if ($isUserValue && is_null($userId)) {
throw new Exception("User id can't be null for a user preference {$key}."); throw new Exception("User id can't be null for a user preference {$key}.");
}
//Check if key already exists //Check if key already exists
$sql = "SELECT COUNT(*) FROM cc_pref" $sql = "SELECT COUNT(*) FROM cc_pref"
." WHERE keystr = :key"; ." WHERE keystr = :key";
@ -113,6 +114,28 @@ class Application_Model_Preference
$cache->store($key, $value, $isUserValue, $userId); $cache->store($key, $value, $isUserValue, $userId);
} }
/**
* Given a PDO connection, lock the cc_pref table for the current transaction
*
* Creates a table level lock, which defaults to ACCESS EXCLUSIVE mode;
* see http://www.postgresql.org/docs/9.1/static/explicit-locking.html
*
* @param PDO $con
*/
private static function _lock($con) {
// If we're not in a transaction, a lock is pointless
if (!$con->inTransaction()) {
return;
}
// Don't specify NOWAIT here; we should block on obtaining this lock
// in case we're handling simultaneous requests.
// Locks only last until the end of the transaction, so we shouldn't have to
// worry about this causing any noticeable difference in request processing speed
$sql = "LOCK TABLE cc_pref";
$st = $con->prepare($sql);
$st->execute();
}
private static function getValue($key, $isUserValue = false) private static function getValue($key, $isUserValue = false)
{ {
$cache = new Cache(); $cache = new Cache();
@ -140,9 +163,9 @@ class Application_Model_Preference
$sql .= " AND subjid = :id"; $sql .= " AND subjid = :id";
$paramMap[':id'] = $userId; $paramMap[':id'] = $userId;
} }
$result = Application_Common_Database::prepareAndExecute($sql, $paramMap, Application_Common_Database::COLUMN); $result = Application_Common_Database::prepareAndExecute($sql, $paramMap, Application_Common_Database::COLUMN);
//return an empty string if the result doesn't exist. //return an empty string if the result doesn't exist.
if ($result == 0) { if ($result == 0) {
$res = ""; $res = "";

View File

@ -17,6 +17,7 @@ class Application_Model_StoredFile
{ {
/** /**
* @holds propel database object * @holds propel database object
* @var CcFiles
*/ */
private $_file; private $_file;
@ -467,48 +468,6 @@ SQL;
$this->_file->save(); $this->_file->save();
} }
public function getRealFileExtension() {
$path = $this->_file->getDbFilepath();
$path_elements = explode('.', $path);
if (count($path_elements) < 2) {
return "";
} else {
return $path_elements[count($path_elements) - 1];
}
}
/**
* Return suitable extension.
*
* @return string
* file extension without a dot
*/
public function getFileExtension()
{
$possible_ext = $this->getRealFileExtension();
if ($possible_ext !== "") {
return $possible_ext;
}
// We fallback to guessing the extension from the mimetype if we
// cannot extract it from the file name
$mime = $this->_file->getDbMime();
if ($mime == "audio/ogg" || $mime == "application/ogg" || $mime == "audio/vorbis") {
return "ogg";
} elseif ($mime == "audio/mp3" || $mime == "audio/mpeg") {
return "mp3";
} elseif ($mime == "audio/x-flac") {
return "flac";
} elseif ($mime == "audio/mp4") {
return "mp4";
} else {
throw new Exception("Unknown $mime");
}
}
/** /**
* Get the absolute filepath * Get the absolute filepath
* *
@ -568,7 +527,7 @@ SQL;
*/ */
public function getRelativeFileUrl($baseUrl) public function getRelativeFileUrl($baseUrl)
{ {
return $baseUrl."api/get-media/file/".$this->getId().".".$this->getFileExtension(); return $baseUrl."api/get-media/file/".$this->getId();
} }
public function getResourceId() public function getResourceId()

View File

@ -205,11 +205,6 @@ class CcFiles extends BaseCcFiles {
$cloudFile->save(); $cloudFile->save();
Application_Model_Preference::updateDiskUsage($fileSizeBytes); Application_Model_Preference::updateDiskUsage($fileSizeBytes);
$now = new DateTime("now", new DateTimeZone("UTC"));
$file->setDbMtime($now);
$file->save();
} else if ($file) { } else if ($file) {
// Since we check for this value when deleting files, set it first // Since we check for this value when deleting files, set it first
@ -238,14 +233,13 @@ class CcFiles extends BaseCcFiles {
$file->setDbFilepath($filePathRelativeToStor); $file->setDbFilepath($filePathRelativeToStor);
} }
} }
$now = new DateTime("now", new DateTimeZone("UTC"));
$file->setDbMtime($now);
$file->save();
} else { } else {
throw new FileNotFoundException(); throw new FileNotFoundException();
} }
$now = new DateTime("now", new DateTimeZone("UTC"));
$file->setDbMtime($now);
$file->save();
} }
catch (FileNotFoundException $e) catch (FileNotFoundException $e)
{ {
@ -356,17 +350,27 @@ class CcFiles extends BaseCcFiles {
/** /**
* *
* Strips out the private fields we do not want to send back in API responses * Strips out the private fields we do not want to send back in API responses
* @param $file string a CcFiles object *
* @param CcFiles $file a CcFiles object
*
* @return array
*/ */
//TODO: rename this function? //TODO: rename this function?
public static function sanitizeResponse($file) public static function sanitizeResponse($file) {
{
$response = $file->toArray(BasePeer::TYPE_FIELDNAME); $response = $file->toArray(BasePeer::TYPE_FIELDNAME);
foreach (self::$privateFields as $key) { foreach (self::$privateFields as $key) {
unset($response[$key]); unset($response[$key]);
} }
$mime = $file->getDbMime();
if (!empty($mime)) {
// Get an extension based on the file's mime type and change the path to use this extension
$path = pathinfo($file->getDbFilepath());
$ext = FileDataHelper::getFileExtensionFromMime($mime);
$response["filepath"] = ($path["dirname"] . '/' . $path["filename"] . $ext);
}
return $response; return $response;
} }

View File

@ -455,3 +455,21 @@ class AirtimeUpgrader2513 extends AirtimeUpgrader
return '2.5.13'; return '2.5.13';
} }
} }
/**
* Class AirtimeUpgrader2514
*
* SAAS-923 - Add a partial constraint to cc_pref so that keystrings must be unique
*/
class AirtimeUpgrader2514 extends AirtimeUpgrader
{
protected function getSupportedSchemaVersions() {
return array (
'2.5.13'
);
}
public function getNewVersion() {
return '2.5.14';
}
}

View File

@ -40,8 +40,10 @@
// First we have to create a Date object out of the show time in UTC. // First we have to create a Date object out of the show time in UTC.
// Then we can format the string in the client's local timezone. // Then we can format the string in the client's local timezone.
var start_date = new Date(value.starts + " UTC"); // NOTE: we have to multiply the timestamp by 1000 because in PHP
var end_date = new Date(value.ends + " UTC"); // the timestamps are in seconds and are in milliseconds in javascript.
var start_date = new Date(value.starts_timestamp*1000);
var end_date = new Date(value.ends_timestamp*1000);
// This variable is used to identify which schedule_data object (which day of the week) // This variable is used to identify which schedule_data object (which day of the week)
// we should assign the show to. // we should assign the show to.
@ -53,13 +55,17 @@
if ($window.schedule_data["weekDays"][format_start_date] !== undefined) { if ($window.schedule_data["weekDays"][format_start_date] !== undefined) {
$window.schedule_data["weekDays"][format_start_date]["shows"].push( $window.schedule_data["weekDays"][format_start_date]["shows"].push(
{ {
"show_start_hour": start_date.getHours().toString().paddingLeft("00")+":"+ start_date.getMinutes().toString().paddingLeft("00"), "show_start_hour": start_date.toLocaleTimeString([], { hour: 'numeric', minute : 'numeric' }),
"show_end_hour": end_date.getHours().toString().paddingLeft("00")+":"+ end_date.getMinutes().toString().paddingLeft("00"), "show_end_hour": end_date.toLocaleTimeString([], { hour: 'numeric', minute : 'numeric' }),
"name": value.name "name": value.name
}); });
} }
}); });
$scope.weekDays = $window.schedule_data["weekDays"]; // Convert the object into an array to maintain the same order when we
// iterate over each weekday
$scope.weekDays = $.map($window.schedule_data["weekDays"], function(value, index) {
return [value];
});
$scope.isEmpty = function(obj) { $scope.isEmpty = function(obj) {
return obj.length == 0; return obj.length == 0;

View File

@ -376,3 +376,11 @@ INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_descripti
INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_genre', '', 'string'); INSERT INTO cc_stream_setting ("keyname", "value", "type") VALUES ('s4_genre', '', 'string');
INSERT INTO cc_stream_setting (keyname, value, type) VALUES ('s4_channels', 'stereo', 'string'); INSERT INTO cc_stream_setting (keyname, value, type) VALUES ('s4_channels', 'stereo', 'string');
-- added in 2.5.14 - this can't be set up in Propel's XML schema, so we need to do it here -- Duncan
ALTER TABLE cc_pref ALTER COLUMN subjid SET NULL;
ALTER TABLE cc_pref ALTER COLUMN subjid SET DEFAULT NULL;
CREATE UNIQUE INDEX cc_pref_key_idx ON cc_pref (keystr) WHERE subjid IS NULL;
ANALYZE cc_pref; -- this validates the new partial index
--end added in 2.5.14

View File

@ -123,7 +123,7 @@ background: rgba(53, 53, 53, 1.0);
.schedule_item div.time_grid { .schedule_item div.time_grid {
/*padding-right: 10px;*/ /*padding-right: 10px;*/
width: 20%; width: 30%;
font-weight: 300; font-weight: 300;
color: #AAAAAA; color: #AAAAAA;
display: inline-block; display: inline-block;
@ -133,7 +133,7 @@ background: rgba(53, 53, 53, 1.0);
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
padding-left: 10px; padding-left: 10px;
width: 77%; width: 67%;
display:inline-block; display:inline-block;
vertical-align: middle; vertical-align: middle;
} }
@ -182,11 +182,11 @@ background: rgba(53, 53, 53, 1.0);
@media (max-width: 630px) { @media (max-width: 630px) {
.schedule_item div.time_grid { .schedule_item div.time_grid {
width: 25%; width: 37%;
} }
.schedule_item div.name_grid { .schedule_item div.name_grid {
width: 70%; width: 58%;
} }
} }
@ -197,31 +197,31 @@ background: rgba(53, 53, 53, 1.0);
} }
.schedule_item div.time_grid { .schedule_item div.time_grid {
width: 30%; width: 35%;
} }
.schedule_item div.name_grid { .schedule_item div.name_grid {
width: 67%; width: 60%;
} }
} }
@media (max-width: 500px) { @media (max-width: 500px) {
.schedule_item div.time_grid { .schedule_item div.time_grid {
width: 35%; width: 40%;
} }
.schedule_item div.name_grid { .schedule_item div.name_grid {
width: 62%; width: 55%;
} }
} }
@media (max-width: 400px) { @media (max-width: 400px) {
.schedule_item div.time_grid { .schedule_item div.time_grid {
width: 40%; width: 90%;
} }
.schedule_item div.name_grid { .schedule_item div.name_grid {
width: 50%; width: 90%;
} }
} }

View File

@ -97,7 +97,7 @@ body {
.schedule_item div.time_grid { .schedule_item div.time_grid {
/*padding-right: 10px;*/ /*padding-right: 10px;*/
width: 20%; width: 30%;
font-weight: 300; font-weight: 300;
color: #AAAAAA; color: #AAAAAA;
display: inline-block; display: inline-block;
@ -107,7 +107,7 @@ body {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
padding-left: 10px; padding-left: 10px;
width: 77%; width: 67%;
display:inline-block; display:inline-block;
vertical-align: middle; vertical-align: middle;
} }
@ -132,11 +132,11 @@ body {
@media (max-width: 630px) { @media (max-width: 630px) {
.schedule_item div.time_grid { .schedule_item div.time_grid {
width: 25%; width: 37%;
} }
.schedule_item div.name_grid { .schedule_item div.name_grid {
width: 72%; width: 58%;
} }
} }
@ -147,31 +147,31 @@ body {
} }
.schedule_item div.time_grid { .schedule_item div.time_grid {
width: 30%; width: 35%;
} }
.schedule_item div.name_grid { .schedule_item div.name_grid {
width: 67%; width: 60%;
} }
} }
@media (max-width: 500px) { @media (max-width: 500px) {
.schedule_item div.time_grid { .schedule_item div.time_grid {
width: 35%; width: 40%;
} }
.schedule_item div.name_grid { .schedule_item div.name_grid {
width: 62%; width: 55%;
} }
} }
@media (max-width: 400px) { @media (max-width: 400px) {
.schedule_item div.time_grid { .schedule_item div.time_grid {
width: 40%; width: 90%;
} }
.schedule_item div.name_grid { .schedule_item div.name_grid {
width: 50%; width: 90%;
} }
} }

View File

@ -786,6 +786,11 @@ function setAddShowEvents(form) {
scheduleRefetchEvents(json); scheduleRefetchEvents(json);
$addShowForm.hide(); $addShowForm.hide();
} }
/* CC-6062: Resize the window to avoid stretching the last column */
windowResize();
makeAddShowButton();
} }
}); });
}); });