diff --git a/airtime_mvc/application/common/TaskManager.php b/airtime_mvc/application/common/TaskManager.php index 61e559e04..2792116d4 100644 --- a/airtime_mvc/application/common/TaskManager.php +++ b/airtime_mvc/application/common/TaskManager.php @@ -22,7 +22,7 @@ final class TaskManager { /** * @var int TASK_INTERVAL_SECONDS how often, in seconds, to run the TaskManager tasks */ - const TASK_INTERVAL_SECONDS = 300; // 5 minutes - will be run on every pypo request + const TASK_INTERVAL_SECONDS = 30; /** * @var $con PDO Propel connection object diff --git a/airtime_mvc/application/configs/constants.php b/airtime_mvc/application/configs/constants.php index c87fbc3f9..3180b888b 100644 --- a/airtime_mvc/application/configs/constants.php +++ b/airtime_mvc/application/configs/constants.php @@ -21,6 +21,8 @@ define('ABOUT_AIRTIME_URL' , 'https://www.airtime.pro/support/'); define('AIRTIME_TRANSIFEX_URL' , 'https://www.transifex.com/projects/p/airtime/'); define('WHMCS_PASSWORD_RESET_URL' , 'https://account.sourcefabric.com/pwreset.php'); define('SUPPORT_TICKET_URL' , 'https://sourcefabricberlin.zendesk.com/hc/en-us/requests/new'); +define('UI_REVAMP_EMBED_URL' , 'https://www.youtube.com/embed/nqpNnCKGluY'); +define('UI_REVAMP_YOUTUBE_URL' , 'https://www.youtube.com/watch?v=nqpNnCKGluY&feature=youtu.be'); define('LICENSE_VERSION' , 'GNU AGPL v.3'); define('LICENSE_URL' , 'http://www.gnu.org/licenses/agpl-3.0-standalone.html'); diff --git a/airtime_mvc/application/configs/navigation.php b/airtime_mvc/application/configs/navigation.php index 40bb48484..631833343 100644 --- a/airtime_mvc/application/configs/navigation.php +++ b/airtime_mvc/application/configs/navigation.php @@ -172,6 +172,11 @@ $pages = array( 'label' => _(sprintf("Help Translate %s", PRODUCT_NAME)), 'uri' => AIRTIME_TRANSIFEX_URL, 'target' => "_blank" + ), + array( + 'label' => _('What\'s New?'), + 'uri' => UI_REVAMP_YOUTUBE_URL, + 'target' => "_blank" ) ) ), diff --git a/airtime_mvc/application/controllers/LocaleController.php b/airtime_mvc/application/controllers/LocaleController.php index 41c7cd2e9..5a51190fa 100644 --- a/airtime_mvc/application/controllers/LocaleController.php +++ b/airtime_mvc/application/controllers/LocaleController.php @@ -426,8 +426,9 @@ class LocaleController extends Zend_Controller_Action "Next", "Previous", ": activate to sort column ascending", - ": activate to sort column descending" + ": activate to sort column descending", //End of datatables + "Welcome to the new Airtime Pro!" => _("Welcome to the new Airtime Pro!") ); $this->view->layout()->disableLayout(); $this->_helper->viewRenderer->setNoRender(true); diff --git a/airtime_mvc/application/controllers/PreferenceController.php b/airtime_mvc/application/controllers/PreferenceController.php index 359050510..c99f6a465 100644 --- a/airtime_mvc/application/controllers/PreferenceController.php +++ b/airtime_mvc/application/controllers/PreferenceController.php @@ -207,10 +207,6 @@ class PreferenceController extends Zend_Controller_Action $values["s4_data"] = $s4_data; if ($form->isValid($values)) { - - $values['icecast_vorbis_metadata'] = $form->getValue('icecast_vorbis_metadata'); - $values['streamFormat'] = $form->getValue('streamFormat'); - Application_Model_StreamSetting::setStreamSetting($values); /* If the admin password values are empty then we should not diff --git a/airtime_mvc/application/controllers/ShowbuilderController.php b/airtime_mvc/application/controllers/ShowbuilderController.php index 96b9bb0f4..7a0b0bcd8 100644 --- a/airtime_mvc/application/controllers/ShowbuilderController.php +++ b/airtime_mvc/application/controllers/ShowbuilderController.php @@ -55,6 +55,7 @@ class ShowbuilderController extends Zend_Controller_Action $this->view->headScript()->appendFile($baseUrl.'js/airtime/showbuilder/main_builder.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); // MEDIA BUILDER + $this->view->headScript()->appendFile($baseUrl.'js/js-timezone-detect/jstz-1.0.4.min.js','text/javascript'); $this->view->headScript()->appendFile($baseUrl.'js/airtime/library/spl.js?'.$CC_CONFIG['airtime_version'], 'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'js/airtime/library/podcast.js?'.$CC_CONFIG['airtime_version'], 'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'js/airtime/library/publish.js?'.$CC_CONFIG['airtime_version'], 'text/javascript'); @@ -84,6 +85,8 @@ class ShowbuilderController extends Zend_Controller_Action $end = DateTime::createFromFormat("U", $to, $utcTimezone); $end->setTimezone($displayTimeZone); + $this->checkAndShowSetupPopup($request); + $form = new Application_Form_ShowBuilder(); $form->populate(array( 'sb_date_start' => $start->format("Y-m-d"), diff --git a/airtime_mvc/application/controllers/WebstreamController.php b/airtime_mvc/application/controllers/WebstreamController.php index 41847c52d..6e0b8cf24 100644 --- a/airtime_mvc/application/controllers/WebstreamController.php +++ b/airtime_mvc/application/controllers/WebstreamController.php @@ -63,12 +63,16 @@ class WebstreamController extends Zend_Controller_Action if (!$isAdminOrPM && $webstream->getDbCreatorId() != $user->getId()) { $this->view->objType = "webstream"; + $this->view->type = "webstream"; $this->view->obj = $obj; + $this->view->id = $id; $this->view->html = $this->view->render('playlist/permission-denied.phtml'); return; } $this->view->obj = $obj; + $this->view->type = "webstream"; + $this->view->id = $id; $this->view->action = "edit"; $this->view->html = $this->view->render('webstream/webstream.phtml'); } diff --git a/airtime_mvc/application/forms/ShowBuilder.php b/airtime_mvc/application/forms/ShowBuilder.php index f7d61795f..5e7c54ff5 100644 --- a/airtime_mvc/application/forms/ShowBuilder.php +++ b/airtime_mvc/application/forms/ShowBuilder.php @@ -85,7 +85,11 @@ class Application_Form_ShowBuilder extends Zend_Form_SubForm private function getShowNames() { - $showNames = array("0" => _("Filter by Show")); + $user = Application_Model_User::getCurrentUser(); + $showNames = array("0" => _("Filter by Show")); + if ($user->getType() === 'H') { + $showNames["-1"] = _("My Shows"); + } $shows = CcShowQuery::create() ->setFormatter(ModelCriteria::FORMAT_ON_DEMAND) diff --git a/airtime_mvc/application/layouts/scripts/layout.phtml b/airtime_mvc/application/layouts/scripts/layout.phtml index 83b55c87f..454d6e3c7 100644 --- a/airtime_mvc/application/layouts/scripts/layout.phtml +++ b/airtime_mvc/application/layouts/scripts/layout.phtml @@ -167,6 +167,56 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= + + +
+
+
+ +
+

+

+ +
+ +
+ + + diff --git a/airtime_mvc/application/models/Preference.php b/airtime_mvc/application/models/Preference.php index d02868c75..e8bf5adf5 100644 --- a/airtime_mvc/application/models/Preference.php +++ b/airtime_mvc/application/models/Preference.php @@ -138,7 +138,13 @@ class Application_Model_Preference $st->execute(); } - private static function getValue($key, $isUserValue = false) + /** + * @param string $key the preference key string + * @param bool|false $isUserValue select the preference for the current user + * @param bool|false $forceDefault only look for default (no user ID) values + * @return mixed the preference value + */ + private static function getValue($key, $isUserValue = false, $forceDefault = false) { $cache = new Cache(); @@ -164,6 +170,8 @@ class Application_Model_Preference if ($isUserValue) { $sql .= " AND subjid = :id"; $paramMap[':id'] = $userId; + } else if ($forceDefault) { + $sql .= " AND subjid IS NULL"; } $result = Application_Common_Database::prepareAndExecute($sql, $paramMap, Application_Common_Database::COLUMN); @@ -1478,4 +1486,20 @@ class Application_Model_Preference { self::setValue("lang_tz_setup_complete", $value); } + + public static function getWhatsNewDialogViewed() + { + $val = self::getValue("whats_new_dialog_viewed", true); + if (empty($val)) { + // Check the default (no user ID) value if the user value is empty + // This is so that new stations won't see the popup + $val = self::getValue("whats_new_dialog_viewed", false, true); + } + return empty($val) ? false : $val; + } + + public static function setWhatsNewDialogViewed($value) + { + self::setValue("whats_new_dialog_viewed", $value, true); + } } diff --git a/airtime_mvc/application/models/Schedule.php b/airtime_mvc/application/models/Schedule.php index f6967d254..72acb6047 100644 --- a/airtime_mvc/application/models/Schedule.php +++ b/airtime_mvc/application/models/Schedule.php @@ -1035,7 +1035,11 @@ SQL; self::createStreamScheduleEvent($data, $item, $media_id, $uri); } else { - throw new Exception("Unknown schedule type: ".print_r($item, true)); + //throw new Exception("Unknown schedule type: ".print_r($item, true)); + //It's currently possible (and normal) to get cc_schedule rows without + //a file_id or stream_id. If you're using linked shows, placeholder rows can be put + //in the schedule when you cancel a track or delete stuff, so we should not throw an exception + //here and instead just ignore it. } } diff --git a/airtime_mvc/application/models/Scheduler.php b/airtime_mvc/application/models/Scheduler.php index 29991e893..51b964589 100644 --- a/airtime_mvc/application/models/Scheduler.php +++ b/airtime_mvc/application/models/Scheduler.php @@ -80,7 +80,7 @@ class Application_Model_Scheduler * * @param array $items, an array containing pks of cc_schedule items. */ - private function validateRequest($items, $addAction=false) + private function validateRequest($items, $addRemoveAction=false) { //$items is where tracks get inserted (they are schedule locations) @@ -164,7 +164,7 @@ class Application_Model_Scheduler * currently playing? * If yes, throw an exception */ - if ($addAction) { + if ($addRemoveAction) { $ccShow = $instance->getCcShow(); if ($ccShow->isLinked()) { //get all the linked shows instances and check if @@ -175,7 +175,7 @@ class Application_Model_Scheduler if ($ccShowInstance->getDbStarts() <= $timeNowUTC && $ccShowInstance->getDbEnds() > $timeNowUTC) { - throw new Exception(_("Content in linked shows must be scheduled before or after any one is broadcasted")); + throw new Exception(_("Content in linked shows cannot be changed while on air!")); } } } @@ -1091,7 +1091,7 @@ class Application_Model_Scheduler try { - $this->validateRequest($scheduledItems); + $this->validateRequest($scheduledItems, true); $scheduledIds = array(); foreach ($scheduledItems as $item) { diff --git a/airtime_mvc/application/models/Show.php b/airtime_mvc/application/models/Show.php index 832186d80..2653fe848 100644 --- a/airtime_mvc/application/models/Show.php +++ b/airtime_mvc/application/models/Show.php @@ -1044,17 +1044,31 @@ SQL; $event["nowPlaying"] = false; } - //event colouring - if ($show["color"] != "") { - $event["textColor"] = "#".$show["color"]; - } - if (!empty($show["background_color"])) { $event["color"] = "#" . $show["background_color"]; } else { $event["color"] = "#" . self::getDefaultBackgroundColor($startsDT);//DEFAULT_SHOW_COLOR; } + + //event colouring + if ($show["color"] != "") { + $event["textColor"] = "#".$show["color"]; + } else { + $bg = $event["color"]; + //Calculate the text colour (black or white) based on the brightness of the background. + $r = intval(substr($bg, 1, 2), 16); + $g = intval(substr($bg, 3, 2), 16); + $b = intval(substr($bg, 5, 2), 16); + $brightness = 0.299*floatval($r) + 0.587*floatval($g) + 0.114*floatval($b); + if ($brightness > 130) { + $event["textColor"] = "#000000"; + } else { + $event["textColor"] = "#fcfcfc"; + } + } + + foreach ($options as $key => $value) { $event[$key] = $value; } @@ -1067,12 +1081,33 @@ SQL; /** Get a palettized colour for the show. */ private static function getDefaultBackgroundColor($date) { + $basePalette = ['A22BE8', '2FFF8D', 'FF743C', '2ED4FF', 'E8D82B']; + // 'B23F11', 'FF7E4A', 'FF6C31' + + /* $palette = [['42d5a1', '56bd99', '65ab93', '7b938b'], ['42a4d5', '569bbd', '6594ab', '7b8b93'], ['4264d5', '566fbd', '6576ab', '7b8193']]; + */ + $palette = []; + for ($baseColorIdx = 0; $baseColorIdx < count($basePalette); $baseColorIdx++) { + $dayPalette = []; + for ($shade = 0.0; $shade < 0.8; $shade += 0.1) { + $origColour = $basePalette[$baseColorIdx]; + $r = intval(substr($origColour, 0, 2), 16); + $g = intval(substr($origColour, 2, 2), 16); + $b = intval(substr($origColour, 4, 2), 16); + $r = floatval($r) * (1.0 - $shade); + $g = floatval($g) * (1.0 - $shade); + $b = floatval($b) * (1.0 - $shade); + $color = sprintf("%02x%02x%02x", $r, $g, $b); + array_push($dayPalette, $color); + } + array_push($palette, $dayPalette); + } //$hashValue = (md5($date->format('d'))[0] % $cols) + ((intval($date->format('h'))/24) % $rows); - $row = intval($date->format('d')) % sizeof($palette); + $row = intval($date->format('w')) % sizeof($palette); $foo = $date->format('H'); $col = intval(intval($date->format('H'))/24.0 * sizeof($palette[0])); //$color = $palette[$hashValue % sizeof($palette)]; diff --git a/airtime_mvc/application/modules/rest/controllers/PodcastController.php b/airtime_mvc/application/modules/rest/controllers/PodcastController.php index 0147644b5..03a1cfbde 100644 --- a/airtime_mvc/application/modules/rest/controllers/PodcastController.php +++ b/airtime_mvc/application/modules/rest/controllers/PodcastController.php @@ -92,9 +92,6 @@ class Rest_PodcastController extends Zend_Rest_Controller $this->_helper->json->sendJson(array( "podcast"=>json_encode($podcast), "html"=>$this->view->render($path), - "type"=>"podcast", // TODO: get rid of these extraneous fields - "id"=>$podcast["id"] - // "id"=>$podcast->getDbId() )); } catch (PodcastLimitReachedException $e) { diff --git a/airtime_mvc/application/views/scripts/form/showbuilder.phtml b/airtime_mvc/application/views/scripts/form/showbuilder.phtml index a22bf98f4..69ecfaf97 100644 --- a/airtime_mvc/application/views/scripts/form/showbuilder.phtml +++ b/airtime_mvc/application/views/scripts/form/showbuilder.phtml @@ -9,8 +9,8 @@ element->getElement('sb_show_filter') ?> - element->getElement('sb_my_shows')):?> - - element->getElement('sb_my_shows'); ?> - +element->getElement('sb_my_shows')):?> +element->getElement('sb_my_shows')->getLabel(); ?> +element->getElement('sb_my_shows'); ?> + diff --git a/airtime_mvc/application/views/scripts/showbuilder/index.phtml b/airtime_mvc/application/views/scripts/showbuilder/index.phtml index d36794257..52cd6db7c 100644 --- a/airtime_mvc/application/views/scripts/showbuilder/index.phtml +++ b/airtime_mvc/application/views/scripts/showbuilder/index.phtml @@ -7,7 +7,7 @@
@@ -34,3 +34,4 @@
dialog ?> +lang_tz_popup_form; ?> diff --git a/airtime_mvc/build/sql/defaultdata.sql b/airtime_mvc/build/sql/defaultdata.sql index 4c2ca0af7..9b1512f07 100644 --- a/airtime_mvc/build/sql/defaultdata.sql +++ b/airtime_mvc/build/sql/defaultdata.sql @@ -385,3 +385,6 @@ 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 + +-- For now, just needs to be truthy - to be updated later; we should find a better way to implement this... +INSERT INTO cc_pref("keystr", "valstr") VALUES('whats_new_dialog_viewed', 1); \ No newline at end of file diff --git a/airtime_mvc/locale/es_ES/LC_MESSAGES/airtime.mo b/airtime_mvc/locale/es_ES/LC_MESSAGES/airtime.mo index 379e1edbc..c5212c0b5 100644 Binary files a/airtime_mvc/locale/es_ES/LC_MESSAGES/airtime.mo and b/airtime_mvc/locale/es_ES/LC_MESSAGES/airtime.mo differ diff --git a/airtime_mvc/locale/es_ES/LC_MESSAGES/airtime.po b/airtime_mvc/locale/es_ES/LC_MESSAGES/airtime.po index aed475746..8db0d5cd9 100644 --- a/airtime_mvc/locale/es_ES/LC_MESSAGES/airtime.po +++ b/airtime_mvc/locale/es_ES/LC_MESSAGES/airtime.po @@ -11,7 +11,7 @@ msgstr "" "Project-Id-Version: Airtime\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-09-04 11:17-0400\n" -"PO-Revision-Date: 2015-09-11 14:33+0000\n" +"PO-Revision-Date: 2015-09-25 13:52+0000\n" "Last-Translator: Maria Ituarte \n" "Language-Team: Spanish (Spain) (http://www.transifex.com/sourcefabric/airtime/language/es_ES/)\n" "MIME-Version: 1.0\n" @@ -22,7 +22,7 @@ msgstr "" #: airtime_mvc/application/services/CalendarService.php:50 msgid "Record file doesn't exist" -msgstr "" +msgstr "No existe el archivo" #: airtime_mvc/application/services/CalendarService.php:54 msgid "View Recorded File Metadata" @@ -1941,7 +1941,7 @@ msgstr "Stream en vivo" #: airtime_mvc/application/layouts/scripts/layout.phtml:63 msgid "Smart Block" -msgstr "" +msgstr "Bloque Inteligente" #: airtime_mvc/application/layouts/scripts/layout.phtml:66 msgid "Webstream" diff --git a/airtime_mvc/locale/nl_NL/LC_MESSAGES/airtime.mo b/airtime_mvc/locale/nl_NL/LC_MESSAGES/airtime.mo index b7bddfd6e..60dd3148f 100644 Binary files a/airtime_mvc/locale/nl_NL/LC_MESSAGES/airtime.mo and b/airtime_mvc/locale/nl_NL/LC_MESSAGES/airtime.mo differ diff --git a/airtime_mvc/locale/nl_NL/LC_MESSAGES/airtime.po b/airtime_mvc/locale/nl_NL/LC_MESSAGES/airtime.po index e11e40d98..000608cfd 100644 --- a/airtime_mvc/locale/nl_NL/LC_MESSAGES/airtime.po +++ b/airtime_mvc/locale/nl_NL/LC_MESSAGES/airtime.po @@ -11,8 +11,8 @@ msgstr "" "Project-Id-Version: Airtime\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2015-09-04 11:17-0400\n" -"PO-Revision-Date: 2015-09-05 08:33+0000\n" -"Last-Translator: Daniel James \n" +"PO-Revision-Date: 2015-09-28 12:25+0000\n" +"Last-Translator: dave van den berg \n" "Language-Team: Dutch (Netherlands) (http://www.transifex.com/sourcefabric/airtime/language/nl_NL/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -22,7 +22,7 @@ msgstr "" #: airtime_mvc/application/services/CalendarService.php:50 msgid "Record file doesn't exist" -msgstr "ecord bestand bestaat niet" +msgstr "Record bestand bestaat niet" #: airtime_mvc/application/services/CalendarService.php:54 msgid "View Recorded File Metadata" @@ -31,25 +31,25 @@ msgstr "Weergave opgenomen bestand Metadata" #: airtime_mvc/application/services/CalendarService.php:61 #: airtime_mvc/application/services/CalendarService.php:93 msgid "View" -msgstr "" +msgstr "Weergeven" #: airtime_mvc/application/services/CalendarService.php:81 msgid "Schedule Tracks" -msgstr "" +msgstr "Schema Tracks" #: airtime_mvc/application/services/CalendarService.php:106 msgid "Clear Show" -msgstr "" +msgstr "Wissen show" #: airtime_mvc/application/services/CalendarService.php:120 #: airtime_mvc/application/services/CalendarService.php:125 msgid "Cancel Show" -msgstr "" +msgstr "Annuleren show" #: airtime_mvc/application/services/CalendarService.php:146 #: airtime_mvc/application/services/CalendarService.php:165 msgid "Edit Instance" -msgstr "" +msgstr "Aanleg bewerken" #: airtime_mvc/application/services/CalendarService.php:152 #: airtime_mvc/application/controllers/LibraryController.php:184 @@ -74,11 +74,11 @@ msgstr "Verwijderen" #: airtime_mvc/application/services/CalendarService.php:194 msgid "Delete Instance" -msgstr "" +msgstr "Exemplaar verwijderen" #: airtime_mvc/application/services/CalendarService.php:200 msgid "Delete Instance and All Following" -msgstr "" +msgstr "Exemplaar verwijderen en alle volgende" #: airtime_mvc/application/services/CalendarService.php:254 msgid "Permission denied" @@ -275,16 +275,16 @@ msgstr "Download" #: airtime_mvc/application/controllers/LibraryController.php:147 msgid "View track" -msgstr "" +msgstr "Weergave track" #: airtime_mvc/application/controllers/LibraryController.php:148 msgid "Remove track" -msgstr "" +msgstr "Nummer verwijderen" #: airtime_mvc/application/controllers/LibraryController.php:154 #: airtime_mvc/application/controllers/LibraryController.php:159 msgid "Upload track" -msgstr "" +msgstr "Uploaden van track" #: airtime_mvc/application/controllers/LibraryController.php:169 msgid "Duplicate Playlist" @@ -300,11 +300,11 @@ msgstr "Je hebt geen toestemming om geselecteerde items te verwijderen" #: airtime_mvc/application/controllers/LibraryController.php:279 msgid "Could not delete file because it is scheduled in the future." -msgstr "" +msgstr "Kan bestand niet verwijderen omdat het in de toekomst is gepland." #: airtime_mvc/application/controllers/LibraryController.php:282 msgid "Could not delete file(s)." -msgstr "" +msgstr "Bestand(en) kan geen gegevens verwijderen." #: airtime_mvc/application/controllers/LibraryController.php:322 #, php-format @@ -329,13 +329,13 @@ msgid "" "To configure and use the embeddable player you must:

\n" " 1. Enable at least one MP3, AAC, or OGG stream under System -> Streams
\n" " 2. Enable the Public Airtime API under System -> Preferences" -msgstr "" +msgstr " Configureren en de integreerbare speler u moet gebruiken:

1. Inschakelen ten minste één MP3, AAC en OGG stream onder systeem->Streams
\n2. De openbare Airtime API inschakelen onder systeem->voorkeuren" #: airtime_mvc/application/controllers/EmbeddablewidgetsController.php:41 msgid "" "To use the embeddable weekly schedule widget you must:

\n" " Enable the Public Airtime API under System -> Preferences" -msgstr "" +msgstr "De integreerbare per schema widget u moet gebruiken:

\nde openbare Airtime API inschakelen onder systeem->voorkeuren" #: airtime_mvc/application/controllers/ListenerstatController.php:51 msgid "" @@ -391,19 +391,19 @@ msgstr "Onbekende afspeellijst" #: airtime_mvc/application/controllers/ErrorController.php:78 msgid "Page not found." -msgstr "" +msgstr "Pagina niet gevonden" #: airtime_mvc/application/controllers/ErrorController.php:87 msgid "The requested action is not supported." -msgstr "" +msgstr "De gevraagde actie wordt niet ondersteund." #: airtime_mvc/application/controllers/ErrorController.php:98 msgid "You do not have permission to access this resource." -msgstr "" +msgstr "U bent niet gemachtigd voor toegang tot deze bron." #: airtime_mvc/application/controllers/ErrorController.php:109 msgid "An internal application error has occurred." -msgstr "" +msgstr "Een interne toepassingsfout opgetreden." #: airtime_mvc/application/controllers/Apiv2Controller.php:77 #: airtime_mvc/application/controllers/ApiController.php:79 @@ -436,7 +436,7 @@ msgstr "Probleem met Liquidsoap..." #: airtime_mvc/application/controllers/PreferenceController.php:493 msgid "Request method not accepted" -msgstr "" +msgstr "Verzoek methode niet geaccepteerd" #: airtime_mvc/application/controllers/DashboardController.php:35 #: airtime_mvc/application/controllers/DashboardController.php:84 @@ -454,7 +454,7 @@ msgstr "Je hebt geen toestemming om over te schakelen van de bron." #: airtime_mvc/application/controllers/LoginController.php:43 msgid "Please enter your username and password." -msgstr "" +msgstr "Voer uw gebruikersnaam en wachtwoord." #: airtime_mvc/application/controllers/LoginController.php:93 msgid "Wrong username or password provided. Please try again." @@ -468,7 +468,7 @@ msgstr "E-mail kan niet worden verzonden. Controleer de instellingen van uw e-ma #: airtime_mvc/application/controllers/LoginController.php:173 msgid "There was a problem with the username or email address you entered." -msgstr "" +msgstr "Er was een probleem met de gebruikersnaam of email adres dat u hebt ingevoerd." #: airtime_mvc/application/controllers/ApiController.php:244 #: airtime_mvc/application/controllers/ApiController.php:317 @@ -570,39 +570,39 @@ msgstr "Selecteer een cursorpositie op de tijdlijn." #: airtime_mvc/application/controllers/LocaleController.php:54 msgid "You haven't added any tracks" -msgstr "" +msgstr "U hebt de nummers nog niet toegevoegd" #: airtime_mvc/application/controllers/LocaleController.php:55 msgid "You haven't added any playlists" -msgstr "" +msgstr "U heb niet alle afspeellijsten toegevoegd" #: airtime_mvc/application/controllers/LocaleController.php:56 msgid "You haven't added any smart blocks" -msgstr "" +msgstr "U nog niet toegevoegd een slimme blokken" #: airtime_mvc/application/controllers/LocaleController.php:57 msgid "You haven't added any webstreams" -msgstr "" +msgstr "U hebt webstreams nog niet toegevoegd" #: airtime_mvc/application/controllers/LocaleController.php:58 msgid "Learn about tracks" -msgstr "" +msgstr "Informatie over nummers" #: airtime_mvc/application/controllers/LocaleController.php:59 msgid "Learn about playlists" -msgstr "" +msgstr "Meer informatie over afspeellijsten" #: airtime_mvc/application/controllers/LocaleController.php:60 msgid "Learn about smart blocks" -msgstr "" +msgstr "Informatie over slimme blokken" #: airtime_mvc/application/controllers/LocaleController.php:61 msgid "Learn about webstreams" -msgstr "" +msgstr "Meer informatie over webstreams" #: airtime_mvc/application/controllers/LocaleController.php:62 msgid "Click 'New' to create one." -msgstr "" +msgstr "Klik op 'Nieuw' te maken." #: airtime_mvc/application/controllers/LocaleController.php:67 msgid "Add to selected show" @@ -636,12 +636,12 @@ msgstr "Gepland" #: airtime_mvc/application/layouts/scripts/layout.phtml:78 #: airtime_mvc/application/views/scripts/showbuilder/builderDialog.phtml:7 msgid "Tracks" -msgstr "" +msgstr "track" #: airtime_mvc/application/controllers/LocaleController.php:75 #: airtime_mvc/application/layouts/scripts/layout.phtml:60 msgid "Playlist" -msgstr "" +msgstr "Afspeellijsten" #: airtime_mvc/application/controllers/LocaleController.php:79 msgid "Bit Rate" @@ -1068,7 +1068,7 @@ msgstr "Als je live streaming client niet om een gebruikersnaam vraagt, moet dit msgid "" "WARNING: This will restart your stream and may cause a short dropout for " "your listeners!" -msgstr "" +msgstr "Waarschuwing: Dit zal opnieuw opstarten van uw stream en een korte dropout kan veroorzaken voor uw luisteraars!" #: airtime_mvc/application/controllers/LocaleController.php:185 msgid "" @@ -1255,19 +1255,19 @@ msgstr "dec" #: airtime_mvc/application/controllers/LocaleController.php:245 msgid "Today" -msgstr "" +msgstr "vandaag" #: airtime_mvc/application/controllers/LocaleController.php:246 msgid "Day" -msgstr "" +msgstr "dag" #: airtime_mvc/application/controllers/LocaleController.php:247 msgid "Week" -msgstr "" +msgstr "week" #: airtime_mvc/application/controllers/LocaleController.php:248 msgid "Month" -msgstr "" +msgstr "maand" #: airtime_mvc/application/controllers/LocaleController.php:249 #: airtime_mvc/application/forms/GeneralPreferences.php:158 @@ -1384,15 +1384,15 @@ msgstr "Duur" #: airtime_mvc/application/controllers/LocaleController.php:276 msgid "Filtering out " -msgstr "" +msgstr "Filteren op" #: airtime_mvc/application/controllers/LocaleController.php:277 msgid " of " -msgstr "" +msgstr "of" #: airtime_mvc/application/controllers/LocaleController.php:278 msgid " records" -msgstr "" +msgstr "records" #: airtime_mvc/application/controllers/LocaleController.php:284 #: airtime_mvc/application/layouts/scripts/layout.phtml:140 @@ -1492,7 +1492,7 @@ msgstr "Niets selecteren" #: airtime_mvc/application/controllers/LocaleController.php:306 msgid "Trim overbooked shows" -msgstr "" +msgstr "Trim overboekte shows" #: airtime_mvc/application/controllers/LocaleController.php:307 msgid "Remove selected scheduled items" @@ -1840,11 +1840,11 @@ msgstr "%sPrint weergave%sA.u.b. gebruik printfunctie in uw browser wilt afdrukk #: airtime_mvc/application/controllers/LocaleController.php:407 msgid "New Show" -msgstr "" +msgstr "Nieuw Show" #: airtime_mvc/application/controllers/LocaleController.php:408 msgid "New Log Entry" -msgstr "" +msgstr "Nieuwe logboekvermelding" #: airtime_mvc/application/controllers/ShowbuilderController.php:138 msgid "Select cursor" @@ -1865,43 +1865,43 @@ msgstr "Rebroadcast van show %s van %s in %s" #: airtime_mvc/application/common/UsabilityHints.php:55 msgid "Upload some tracks below to add them to your library!" -msgstr "" +msgstr "Uploaden sommige tracks hieronder toe te voegen aan uw bibliotheek!" #: airtime_mvc/application/common/UsabilityHints.php:57 #, php-format msgid "" "It looks like you haven't uploaded any audio files yet. %sUpload a file " "now%s." -msgstr "" +msgstr "Het lijkt erop dat u alle audio bestanden nog niet hebt geüpload. %sUpload een bestand nu%s." #: airtime_mvc/application/common/UsabilityHints.php:63 msgid "Click the 'New Show' button and fill out the required fields." -msgstr "" +msgstr "Klik op de knop 'Nieuwe Show' en vul de vereiste velden." #: airtime_mvc/application/common/UsabilityHints.php:65 #, php-format msgid "" "It looks like you don't have any shows scheduled. %sCreate a show now%s." -msgstr "" +msgstr "Het lijkt erop dat u niet alle shows gepland. %sCreate een show nu%s." #: airtime_mvc/application/common/UsabilityHints.php:73 msgid "" "To start broadcasting, cancel the current linked show by clicking on it and " "selecting 'Cancel Show'." -msgstr "" +msgstr "Om te beginnen omroep, de huidige gekoppelde show te annuleren door op te klikken en te selecteren 'Annuleren Show'." #: airtime_mvc/application/common/UsabilityHints.php:75 #, php-format msgid "" "Linked shows need to be filled with tracks before it starts. To start broadcasting cancel the current linked show and schedule an unlinked show.\n" " %sCreate an unlinked show now%s." -msgstr "" +msgstr "Gekoppelde toont dienen te worden opgevuld met tracks voordat het begint. Om te beginnen met omroep annuleren de huidige gekoppeld Toon en plannen van een niet-gekoppelde show.\n%sCreate een niet-gekoppelde Toon nu%s." #: airtime_mvc/application/common/UsabilityHints.php:80 msgid "" "To start broadcasting, click on the current show and select 'Schedule " "Tracks'" -msgstr "" +msgstr "Om te beginnen omroep, klik op de huidige show en selecteer 'Schema Tracks'" #: airtime_mvc/application/common/UsabilityHints.php:82 #, php-format diff --git a/airtime_mvc/public/css/add-show.css b/airtime_mvc/public/css/add-show.css index 385c616c6..3e128e8f9 100644 --- a/airtime_mvc/public/css/add-show.css +++ b/airtime_mvc/public/css/add-show.css @@ -113,11 +113,33 @@ label.wrapp-label input[type="checkbox"] { display: none; } +#add_show_hosts-label { + width: 100%; + padding-bottom: 10px; +} + #add_show_hosts-element { max-height: 80px; min-width: 150px; } +#add_show_hosts-element > label { + display: flex; + align-items: flex-end; +} + +#add_show_hosts-element input { + margin-right: 6px; +} + +#schedule-show-who { + overflow-x: hidden; +} + +#add_show_logo { + margin-top: 6px; +} + #add_show_start_time, #add_show_end_time { width: 54px; margin-left: 10px; diff --git a/airtime_mvc/public/css/dashboard.css b/airtime_mvc/public/css/dashboard.css index c78d2a639..c2944011c 100644 --- a/airtime_mvc/public/css/dashboard.css +++ b/airtime_mvc/public/css/dashboard.css @@ -42,13 +42,6 @@ } } -@media screen and (max-width: 1265px) { - .dataTables_length > label { - /* Hacky, but datatables dumps the select inside the label for some reason... */ - font-size: 0 !important; - } -} - @media screen and (max-width: 1200px) { .wrapper { -webkit-flex-flow: column !important; @@ -252,11 +245,19 @@ thead th.ui-state-default:focus { margin-top: 4px; } -#filter_message { +#lib-filter-message, .filter-message { border-top: none !important; text-shadow: none; } +.filter-message { + position: relative; + font-size: 13px; + float: right; + line-height: 26px; + padding: 0 6px; +} + #advanced-options { float: right; z-index: 1004; @@ -331,6 +332,9 @@ thead th.ui-state-default:focus { .sb-options-form label { color: #efefef; line-height: 26px; + display: inline-block; + padding: 0 0 0 4px; + vertical-align: middle; } #sb_show_filter { @@ -338,6 +342,11 @@ thead th.ui-state-default:focus { position: absolute; } +#sb_my_shows { + top: 1px; + left: 2px; +} + .nav-tabs { border-bottom: 1px solid #5b5b5b; font-family: Arial, Helvetica, sans-serif; @@ -477,9 +486,6 @@ li.ui-state-default { bottom: 4px; top: 4px; left: 4px; -} - -[data-tab-type='md'] > .editor_pane_wrapper { overflow-x: hidden; /* Show the y-direction scrollbar (magic!) */ } @@ -531,10 +537,10 @@ li.ui-state-default { } .spl_sortable { - position: relative; height: 100%; overflow: auto; flex: 1 100%; + -webkit-flex: 1 100%; margin: 4px 0; min-height: 0; diff --git a/airtime_mvc/public/css/fullcalendar.css b/airtime_mvc/public/css/fullcalendar.css index 2ce2e3a52..e0c991eb5 100644 --- a/airtime_mvc/public/css/fullcalendar.css +++ b/airtime_mvc/public/css/fullcalendar.css @@ -605,9 +605,9 @@ table.fc-border-separate { left: 0; width: 100%; height: 100%; - background: #fff; - opacity: 0.3; - filter: alpha(opacity=30); + background: #C3C3C3; + opacity: 0.15; + filter: alpha(opacity=15); } .fc .ui-draggable-dragging .fc-event-bg, /* TODO: something nicer like .fc-opacity */ diff --git a/airtime_mvc/public/css/styles.css b/airtime_mvc/public/css/styles.css index dcdb20c26..98574544a 100644 --- a/airtime_mvc/public/css/styles.css +++ b/airtime_mvc/public/css/styles.css @@ -950,7 +950,7 @@ dl.inline-list dd { background: url("img/loading.gif") no-repeat 50% 50% rgba(0, 0, 0, .25); } div.blockOverlay { - background: url("img/loading.gif") no-repeat 50% 50% rgba(0, 0, 0, .45); + background: 50% 50% rgba(0, 0, 0, .45); } #library_display_wrapper .ui-widget-header:first-child { background:none; @@ -981,7 +981,7 @@ div.blockOverlay { font-size:12px; font-weight:normal; padding: 0.2em 1em; - margin-right:3px; + margin-right:0; } .dataTables_filter input { background: url("images/search_auto_bg.png") no-repeat scroll 0 0 #DDDDDD; @@ -1371,7 +1371,7 @@ thead tr.fc-first height: 32px; line-height: 32px; } - +ful /** Extremely nasty workaround for a fullcalendar bug, where clicking "Add Show" would cause this large space under the table header. The CSS to get to that is ridiculously complicated and set in the HTML (!) dynamically with JS, @@ -3540,7 +3540,7 @@ button.btn-icon-text > i.icon-white { } #media_selector_wrapper { - flex: 0 0 100%; + flex: 1 1 100%; display: -webkit-box; display: -moz-box; display: -ms-flexbox; @@ -3869,13 +3869,15 @@ li .ui-state-hover { -webkit-flex-flow: column; flex-flow: column; - flex: 6 auto; + flex: 1 1; + -webkit-flex: 1 1; min-width: 505px; } .outer-datatable-wrapper { position: relative; flex: 1; + -webkit-flex: 1; } #user_list_inner_wrapper { @@ -3942,4 +3944,49 @@ li .ui-state-hover { .podcast-metadata input[type="text"] { width: 60%; -} \ No newline at end of file +} + +/* UI Revamp Video */ +#whatsnew { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + max-width: 640px; + max-height: 470px; + + padding: 10px 10px; +} + +#whatsnew_video { + text-align: center; +} + +#whatsnew > button { + margin-top: 10px; + align-self: flex-end; + flex: 1 0 auto; +} + +#whatsnew > div { + text-align: left; + font-size: 16px; + overflow-x: hidden; + padding: 20px; + box-sizing: border-box; +} + +#whatsnew iframe { + text-align: center; +} + +#whatsnew h2 { + margin-top: 10px; + font-weight: bold; + text-align: center; +} + +#whatsnew li { + margin-top: 20px; +} diff --git a/airtime_mvc/public/js/airtime/common/common.js b/airtime_mvc/public/js/airtime/common/common.js index 27f93ad61..14bf97ee0 100644 --- a/airtime_mvc/public/js/airtime/common/common.js +++ b/airtime_mvc/public/js/airtime/common/common.js @@ -58,6 +58,15 @@ var i18n_days_short = [ $.i18n._("Sa") ]; +var HTTPMethods = Object.freeze({ + GET: "GET", + POST: "POST", + PUT: "PUT", + PATCH: "PATCH", + DELETE: "DELETE", + OPTIONS: "OPTIONS" +}); + var dateStartId = "#sb_date_start", timeStartId = "#sb_time_start", dateEndId = "#sb_date_end", @@ -69,7 +78,7 @@ function getDatatablesStrings(overrideDict) { "sEmptyTable": $.i18n._("No data available in table"), "sInfo": $.i18n._("Showing _START_ to _END_ of _TOTAL_ entries"), "sInfoEmpty": $.i18n._("Showing 0 to 0 of 0 entries"), - "sInfoFiltered": $.i18n._("(filtered from _MAX_ total entries)"), + "sInfoFiltered": "", // $.i18n._("(filtered from _MAX_ total entries)"), "sInfoPostFix": $.i18n._(""), "sInfoThousands": $.i18n._(","), "sLengthMenu": $.i18n._("Show _MENU_"), @@ -79,13 +88,19 @@ function getDatatablesStrings(overrideDict) { "sSearch": $.i18n._(""), "sZeroRecords": $.i18n._("No matching records found"), "oPaginate": { - "sFirst": $.i18n._("First"), - "sLast": $.i18n._("Last"), - "sNext": $.i18n._("Next"), - "sPrevious": $.i18n._("Previous") + "sFirst": "«", + "sLast": "»", + "sNext": "›", + "sPrevious": "‹" }, + //"oPaginate": { + // "sFirst": $.i18n._("First"), + // "sLast": $.i18n._("Last"), + // "sNext": $.i18n._("Next"), + // "sPrevious": $.i18n._("Previous") + //}, "oAria": { - "sSortAscending": $.i18n._(": activate to sort column ascending"), + "sSortAscending": $.i18n._(": activate to sort column ascending"), "sSortDescending": $.i18n._(": activate to sort column descending") } }; @@ -308,4 +323,4 @@ jQuery.fn.textScroll = function(selector) { }); return this; // jQuery chaining -}; \ No newline at end of file +}; diff --git a/airtime_mvc/public/js/airtime/common/livechat.js b/airtime_mvc/public/js/airtime/common/livechat.js index 5d1fc9522..a5a0cd462 100644 --- a/airtime_mvc/public/js/airtime/common/livechat.js +++ b/airtime_mvc/public/js/airtime/common/livechat.js @@ -22,11 +22,8 @@ $(document).ready(function() { var ifr = document.getElementById('livechat-compact-container'); if (ifr) { LC_API.on_chat_state_changed = function(data) { - if (data.state == 'offline') { - $('body > .wrapper').css('padding-bottom', 10); - } else { - $('body > .wrapper').css('padding-bottom', 40); - } + // Hacky... select elements on pages that have different layouts separately + $('body > .wrapper, #stream_form > div, #his-tabs').css('padding-bottom', (data.state == 'offline') ? 10 : 40); }; clearInterval(lcLoadListener); } diff --git a/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js b/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js index 638c4b935..2e7db95c4 100644 --- a/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js +++ b/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js @@ -18,6 +18,7 @@ var AIRTIME = (function(AIRTIME) { check = true; } + var sortable = $(".spl_sortable"); if ($("#show_builder_table").is(":visible")) { if (shows.length === 0) { check = false; @@ -28,13 +29,15 @@ var AIRTIME = (function(AIRTIME) { } else if (current.length !== 0) { btnText = $.i18n._('Add to current show'); } - } else { + } else if (sortable.length > 0 && sortable.is(":visible")) { var objType = $('.active-tab .obj_type').val(); if (objType === 'block') { btnText = $.i18n._('Add to current smart block'); } else { btnText = $.i18n._('Add to current playlist'); } + } else { + check = false; } if (check) { @@ -100,86 +103,95 @@ var AIRTIME = (function(AIRTIME) { libEmpty.hide(); } + var sortable; + if ($("#show_builder_table").is(":visible")) { - $('#library_display tr[class*="lib-"]') - .draggable( - { - helper: function () { - - var $el = $(this), selected = mod - .getChosenItemsLength(), container, thead = $("#show_builder_table thead"), colspan = thead - .find("th").length, width = $el.width(), message; - - // dragging an element that has an unselected - // checkbox. - if (mod.isChosenItem($el) === false) { - selected++; - } - - if (selected === 1) { - message = $.i18n._("Adding 1 Item"); - } else { - message = sprintf($.i18n._("Adding %s Items"), selected); - } - - container = $('
').attr('id', - 'draggingContainer').append('') - .find("tr").append('').find("td") - .attr("colspan", colspan).width(width) - .addClass("ui-state-highlight").append( - message).end().end(); - - return container; - }, - cursor: 'move', - //cursorAt: { - // top: 30, - // right: 10 - //}, - distance: 25, // min-distance for dragging - connectToSortable: '#show_builder_table' - }); + sortable = "#show_builder_table"; } else { - $('#library_display tr[class*="lib-"]') - .draggable( - { - helper: function () { - - var $el = $(this), selected = mod - .getChosenAudioFilesLength(), container, message, - width = $(this).width(), height = 55; - - // dragging an element that has an unselected - // checkbox. - if (mod.isChosenItem($el) === false) { - selected++; - } - - if (selected === 1) { - message = $.i18n._("Adding 1 Item"); - } else { - message = sprintf($.i18n._("Adding %s Items"), selected); - } - - container = $('
').append( - "
  • ").find("li").addClass( - "ui-state-default").append("
    ") - .find("div").addClass( - "list-item-container").append( - message).end().width(width) - .height(height).end(); - - return container; - }, - cursor: 'move', - //cursorAt: { - // top: 30, - // right: 10 - //}, - distance: 25, // min-distance for dragging - connectToSortable: '.active-tab .spl_sortable' - }); + sortable = ".active-tab .spl_sortable"; + //$('#library_display tr[class*="lib-"]') + // .draggable( + // { + // helper: function () { + // + // var $el = $(this), selected = mod + // .getChosenAudioFilesLength(), container, message, + // width = $(this).width(), height = 55; + // + // // dragging an element that has an unselected + // // checkbox. + // if (mod.isChosenItem($el) === false) { + // selected++; + // } + // + // if (selected === 1) { + // message = $.i18n._("Adding 1 Item"); + // } else { + // message = sprintf($.i18n._("Adding %s Items"), selected); + // } + // + // container = $('
    ').append( + // "
  • ").find("li").addClass( + // "ui-state-default").append("
    ") + // .find("div").addClass( + // "list-item-container").append( + // message).end().width(width) + // .height(height).end(); + // + // return container; + // }, + // create: function(event, ui) { + // $(this).draggable("option", "cursorAt", { + // left: Math.floor(this.clientWidth / 2) + // }); + // }, + // cursor: 'move', + // distance: 25, // min-distance for dragging + // connectToSortable: '.active-tab .spl_sortable' + // }); } + + $('#library_display tr[class*="lib-"]') + .draggable( + { + helper: function () { + + var $el = $(this), selected = mod + .getChosenItemsLength(), container, thead = $("#show_builder_table thead"), colspan = thead + .find("th").length, width = $el.width(), message; + + // dragging an element that has an unselected + // checkbox. + if (mod.isChosenItem($el) === false) { + selected++; + } + + if (selected === 1) { + message = $.i18n._("Adding 1 Item"); + } else { + message = sprintf($.i18n._("Adding %s Items"), selected); + } + + container = $('
    ').attr('id', + 'draggingContainer').append('') + .find("tr").append('').find("td") + .attr("colspan", colspan).width(width) + .addClass("ui-state-highlight").append( + message).end().end(); + + return container; + }, + create: function(event, ui) { + $(this).draggable("option", "cursorAt", { + top: 20, + left: Math.floor($(this).outerWidth() / 2) + }); + }, + tolerance: 'pointer', + cursor: 'move', + distance: 25, // min-distance for dragging + connectToSortable: sortable + }); }; mod.dblClickAdd = function(data, type) { diff --git a/airtime_mvc/public/js/airtime/library/library.js b/airtime_mvc/public/js/airtime/library/library.js index 9ebc6159e..2b8a273e5 100644 --- a/airtime_mvc/public/js/airtime/library/library.js +++ b/airtime_mvc/public/js/airtime/library/library.js @@ -659,18 +659,19 @@ var AIRTIME = (function(AIRTIME) { "success": fnCallback, "error": handleAjaxError }).done(function (data) { + var filterMessage = $libContent.find('.filter-message'); if (data.iTotalRecords > data.iTotalDisplayRecords) { - $('#filter_message').text( + filterMessage.text( $.i18n._("Filtering out ") + (data.iTotalRecords - data.iTotalDisplayRecords) + $.i18n._(" of ") + data.iTotalRecords + $.i18n._(" records") ); $('#library_empty').hide(); - $('#library_display').find('tr:has(td.dataTables_empty)').show(); + $libTable.find('tr:has(td.dataTables_empty)').show(); } else { - $('#filter_message').text(""); + filterMessage.text(""); } - $('#library_content').find('.dataTables_filter input[type="text"]') + $libContent.find('.dataTables_filter input[type="text"]') .css('padding-right', $('#advanced-options').find('button').outerWidth()); }); }, @@ -846,12 +847,6 @@ var AIRTIME = (function(AIRTIME) { return getDatatablesStrings({ "sEmptyTable": $.i18n._(""), "sZeroRecords": $.i18n._("No matching results found.") - //"oPaginate": { - // "sFirst": "<<", - // "sLast": ">>", - // "sNext": ">", - // "sPrevious": "<" - //} }); break; } diff --git a/airtime_mvc/public/js/airtime/library/plupload.js b/airtime_mvc/public/js/airtime/library/plupload.js index e17f0ed96..95eefbe13 100644 --- a/airtime_mvc/public/js/airtime/library/plupload.js +++ b/airtime_mvc/public/js/airtime/library/plupload.js @@ -20,6 +20,7 @@ $(document).ready(function () { acceptedFiles: acceptedMimeTypes.join(), addRemoveLinks: true, dictRemoveFile: $.i18n._("Remove"), + maxFilesize: 500, //Megabytes init: function () { this.on("sending", function (file, xhr, data) { data.append("csrf_token", $("#csrf").val()); diff --git a/airtime_mvc/public/js/airtime/library/podcast.js b/airtime_mvc/public/js/airtime/library/podcast.js index fe1c0f246..74c5874f3 100644 --- a/airtime_mvc/public/js/airtime/library/podcast.js +++ b/airtime_mvc/public/js/airtime/library/podcast.js @@ -18,6 +18,7 @@ var AIRTIME = (function (AIRTIME) { //when you're creating a new podcast, we already have the object from the result of the POST. We're saving //a roundtrip by not fetching it again here. $scope.podcast = podcast; + console.log(podcast); tab.setName($scope.podcast.title); $scope.savePodcast = function() { @@ -25,7 +26,7 @@ var AIRTIME = (function (AIRTIME) { podcastData.episodes = episodeTable.getSelectedRows(); $http.put(endpoint + $scope.podcast.id, { csrf_token: jQuery("#csrf").val(), podcast: podcastData }) .success(function() { - // TODO + episodeTable.reload($scope.podcast.id); }); }; @@ -36,15 +37,24 @@ var AIRTIME = (function (AIRTIME) { }); function _bulkAction(method, callback) { - var selected = $("#podcast_table").find(".selected"), - ids = []; - var selectedData = AIRTIME.library.podcastTableWidget.getSelectedRows(); + var ids = [], selectedData = AIRTIME.library.podcastTableWidget.getSelectedRows(); selectedData.forEach(function(el) { - ids.push(el.id); + var uid = AIRTIME.library.MediaTypeStringEnum.PODCAST+"_"+el.id, + t = AIRTIME.tabs.get(uid); + if (t && method == HTTPMethods.DELETE) { + t.close(); + } + if (!(t && method == HTTPMethods.GET)) { + ids.push(el.id); + } else if (t != AIRTIME.tabs.getActiveTab()) { + t.switchTo(); + } }); - // Bulk methods should use post because we're sending data in the request body - $.post(endpoint + "bulk", { csrf_token: $("#csrf").val(), method: method, ids: ids }, callback); + if (ids.length > 0) { + // Bulk methods should use post because we're sending data in the request body + $.post(endpoint + "bulk", {csrf_token: $("#csrf").val(), method: method, ids: ids}, callback); + } } function _bootstrapAngularApp(podcast, tab, table) { @@ -56,6 +66,14 @@ var AIRTIME = (function (AIRTIME) { angular.bootstrap(wrapper.get(0), ["podcast"]); } + function _initAppFromResponse(data) { + var podcast = JSON.parse(data.podcast), + uid = AIRTIME.library.MediaTypeStringEnum.PODCAST+"_"+podcast.id, + tab = AIRTIME.tabs.openTab(data, uid, null), + table = mod.initPodcastEpisodeDatatable(podcast.episodes); + _bootstrapAngularApp(podcast, tab, table); + } + mod.createUrlDialog = function() { $.get('/render/podcast-url-dialog', function(json) { $(document.body).append(json.html); @@ -71,30 +89,22 @@ var AIRTIME = (function (AIRTIME) { mod.addPodcast = function() { $.post(endpoint, $("#podcast_url_dialog").find("form").serialize(), function(json) { - var podcast = JSON.parse(json.podcast); - var uid = AIRTIME.library.MediaTypeStringEnum.PODCAST+"_"+podcast.id, - tab = AIRTIME.tabs.openTab(json, uid, null); - var table = mod.initPodcastEpisodeDatatable(podcast.episodes); - _bootstrapAngularApp(podcast, tab, table); + _initAppFromResponse(json); $("#podcast_url_dialog").dialog("close"); }); }; mod.editSelectedPodcasts = function() { - _bulkAction("GET", function(json) { - json.forEach(function(el) { - var podcast = JSON.parse(el.podcast); - var uid = AIRTIME.library.MediaTypeStringEnum.PODCAST+"_"+podcast.id, - tab = AIRTIME.tabs.openTab(el, uid, null); - var table = mod.initPodcastEpisodeDatatable(podcast.episodes); - _bootstrapAngularApp(podcast, tab, table); + _bulkAction(HTTPMethods.GET, function(json) { + json.forEach(function(data) { + _initAppFromResponse(data); }); }); }; mod.deleteSelectedPodcasts = function() { if (confirm($.i18n._("Are you sure you want to delete the selected podcasts from your library?"))) { - _bulkAction("DELETE", function () { + _bulkAction(HTTPMethods.DELETE, function () { AIRTIME.library.podcastDataTable.fnDraw(); }); } @@ -102,7 +112,7 @@ var AIRTIME = (function (AIRTIME) { mod.initPodcastEpisodeDatatable = function(episodes) { var aoColumns = [ - /* GUID */ { "sTitle" : "" , "mDataProp" : "guid" , "sClass" : "podcast_episodes_guid" , "bVisible" : false }, + /* GUID */ { "sTitle" : "" , "mDataProp" : "guid" , "sClass" : "podcast_episodes_guid" , "bVisible" : false }, /* Title */ { "sTitle" : $.i18n._("Title") , "mDataProp" : "title" , "sClass" : "podcast_episodes_title" , "sWidth" : "170px" }, /* Author */ { "sTitle" : $.i18n._("Author") , "mDataProp" : "author" , "sClass" : "podcast_episodes_author" , "sWidth" : "170px" }, /* Description */ { "sTitle" : $.i18n._("Description") , "mDataProp" : "description" , "sClass" : "podcast_episodes_description" , "sWidth" : "300px" }, @@ -110,18 +120,46 @@ var AIRTIME = (function (AIRTIME) { /* Publication Date */ { "sTitle" : $.i18n._("Publication Date") , "mDataProp" : "pub_date" , "sClass" : "podcast_episodes_pub_date" , "sWidth" : "170px" } ]; + var PodcastTable = function(wrapperDOMNode, bItemSelection, toolbarButtons, dataTablesOptions) { + // Just call the superconstructor. For clarity/extensibility + return AIRTIME.widgets.Table.call(this, wrapperDOMNode, bItemSelection, toolbarButtons, dataTablesOptions); + }; // Subclass AIRTIME.widgets.Table + PodcastTable.prototype = Object.create(AIRTIME.widgets.Table.prototype); + PodcastTable.prototype.constructor = PodcastTable; + PodcastTable.prototype._SELECTORS = Object.freeze({ + SELECTION_CHECKBOX: ".airtime_table_checkbox:has(input)", + SELECTION_TABLE_ROW: "tr:has(td.airtime_table_checkbox > input)" + }); + PodcastTable.prototype._datatablesCheckboxDataDelegate = function(rowData, callType, dataToSave) { + if (rowData.ingested) return null; // Don't create checkboxes for ingested items + return AIRTIME.widgets.Table.prototype._datatablesCheckboxDataDelegate.call(this, rowData, callType, dataToSave); + }; + // Since we're using a static source, define a separate function to fetch and 'reload' the table data + // We use this when we save the Podcast because we need to flag rows the user is ingesting + PodcastTable.prototype.reload = function(id) { + var dt = this._datatable; + $.get(endpoint + id, function(json) { + dt.fnClearTable(); + dt.fnAddData(JSON.parse(json).episodes); + }); + }; + var podcastToolbarButtons = AIRTIME.widgets.Table.getStandardToolbarButtons(); // Set up the div with id "podcast_table" as a datatable. - var podcastEpisodesTableWidget = new AIRTIME.widgets.Table( + var podcastEpisodesTableWidget = new PodcastTable( AIRTIME.tabs.getActiveTab().contents.find('#podcast_episodes'), // DOM node to create the table inside. true, // Enable item selection podcastToolbarButtons, // Toolbar buttons { // Datatables overrides. - 'aoColumns' : aoColumns, - 'bServerSide': false, + 'aoColumns' : aoColumns, + 'bServerSide' : false, + // We want to make as few round trips as possible, so we get + // the episode data alongside the Podcast data and pass it in + // as json. Doing this caches all the episode data on the front-end, + // which means we also don't need to go back to the server for pagination 'sAjaxSource' : null, - 'aaData' : episodes, + 'aaData' : episodes, "oColVis": { "sAlign": "right", "aiExclude": [0, 1], diff --git a/airtime_mvc/public/js/airtime/library/spl.js b/airtime_mvc/public/js/airtime/library/spl.js index cdce25adb..f1349a188 100644 --- a/airtime_mvc/public/js/airtime/library/spl.js +++ b/airtime_mvc/public/js/airtime/library/spl.js @@ -1020,11 +1020,10 @@ var AIRTIME = (function(AIRTIME){ newTab.assignTabClickHandler(function() { if (!$(this).hasClass('active')) { newTab.switchTo(); - $.post(baseUrl+'playlist/edit', { - format: "json", - id: newTab.pane.find(".obj_id").val(), - type: newTab.pane.find(".obj_type").val() - }); + var type = newTab.contents.find(".obj_type").val(); + if (type == "playlist" || type == "block") { + $.post(baseUrl + 'playlist/edit', { format: "json", id: newTab.contents.find(".obj_id").val(), type: type }); + } } }); diff --git a/airtime_mvc/public/js/airtime/schedule/schedule.js b/airtime_mvc/public/js/airtime/schedule/schedule.js index ab2f45c16..110054eeb 100644 --- a/airtime_mvc/public/js/airtime/schedule/schedule.js +++ b/airtime_mvc/public/js/airtime/schedule/schedule.js @@ -224,7 +224,7 @@ function buildScheduleDialog (json, instance_id) { } ] }); - + //set the start end times so the builder datatables knows its time range. fnServer.start = json.start; fnServer.end = json.end; diff --git a/airtime_mvc/public/js/airtime/showbuilder/builder.js b/airtime_mvc/public/js/airtime/showbuilder/builder.js index 3ec1d8e8b..f3b62712a 100644 --- a/airtime_mvc/public/js/airtime/showbuilder/builder.js +++ b/airtime_mvc/public/js/airtime/showbuilder/builder.js @@ -766,7 +766,7 @@ var AIRTIME = (function(AIRTIME){ "bScrollCollapseY": false }); - $sbTable.find("tbody").on("mousedown", "tr:not(.sb-header, .sb-footer, .sb-past, .sb-empty, :has(td.dataTables_empty)) > td.sb-checkbox", function(ev) { + $sbTable.find("tbody").on("mousedown", "tr:not(.sb-not-allowed, .sb-header, .sb-footer, .sb-past, .sb-empty, :has(td.dataTables_empty)) > td.sb-checkbox", function(ev) { var $tr = $(this).parent(), // Get the ID of the selected row $rowId = $tr.attr("id"); @@ -803,7 +803,7 @@ var AIRTIME = (function(AIRTIME){ $previouslySelected = $tr; }); - $sbTable.find("tbody").on("mousedown", "tr:not(.sb-header, .sb-footer, .sb-past, .sb-empty, :has(td.dataTables_empty)) > td:not(.sb-checkbox)", function(ev) { + $sbTable.find("tbody").on("mousedown", "tr:not(.sb-not-allowed, .sb-header, .sb-footer, .sb-past, .sb-empty, :has(td.dataTables_empty)) > td:not(.sb-checkbox)", function(ev) { var $tr = $(this).parent(), // Get the ID of the selected row $rowId = $tr.attr("id"); @@ -851,7 +851,7 @@ var AIRTIME = (function(AIRTIME){ $previouslySelected = $tr; }); - $sbTable.find("tbody").on("click", "tr:not(.sb-header, .sb-footer, .sb-past, .sb-empty, :has(td.dataTables_empty)) > td.sb-checkbox", function() { + $sbTable.find("tbody").on("click", "tr:not(.sb-not-allowed, .sb-header, .sb-footer, .sb-past, .sb-empty, :has(td.dataTables_empty)) > td.sb-checkbox", function() { var tr = $(this).parent(); if (flagForDeselection) { flagForDeselection = false; @@ -867,7 +867,7 @@ var AIRTIME = (function(AIRTIME){ selectedRows = $("." + SB_SELECTED_CLASS); }); - $sbTable.find("tbody").on("click", "tr:not(.sb-header, .sb-footer, .sb-past, .sb-empty, :has(td.dataTables_empty)) > td:not(.sb-checkbox)", function(e) { + $sbTable.find("tbody").on("click", "tr:not(.sb-not-allowed, .sb-header, .sb-footer, .sb-past, .sb-empty, :has(td.dataTables_empty)) > td:not(.sb-checkbox)", function(e) { var tr = $(this).parent(); if (flagForDeselection) { flagForDeselection = false; @@ -887,7 +887,7 @@ var AIRTIME = (function(AIRTIME){ //begin context menu initialization. $.contextMenu({ - selector: '#show_builder tr.lib-audio:not(.sb-past)', + selector: '#show_builder tr.lib-audio:not(.sb-not-allowed, .sb-past)', trigger: "right", build: function($el, e) { diff --git a/airtime_mvc/public/js/airtime/showbuilder/main_builder.js b/airtime_mvc/public/js/airtime/showbuilder/main_builder.js index 7f42edde2..f2ad4e575 100644 --- a/airtime_mvc/public/js/airtime/showbuilder/main_builder.js +++ b/airtime_mvc/public/js/airtime/showbuilder/main_builder.js @@ -93,7 +93,7 @@ AIRTIME = (function(AIRTIME) { check; check = validateTimeRange(); - + if (check.isValid) { //reset timestamp value since input values could have changed. AIRTIME.showbuilder.resetTimestamp(); @@ -102,14 +102,15 @@ AIRTIME = (function(AIRTIME) { fn.start = check.start; fn.end = check.end; - op = $("div.sb-advanced-options"); + op = $("div.sb-options-form"); if (op.is(":visible")) { if (fn.ops === undefined) { fn.ops = {}; } fn.ops.showFilter = op.find("#sb_show_filter").val(); - fn.ops.myShows = op.find("#sb_my_shows").is(":checked") ? 1 : 0; + // Hacky? + fn.ops.myShows = (fn.ops.showFilter == -1) ? 1 : 0; } oTable.fnDraw(); diff --git a/airtime_mvc/public/js/airtime/showbuilder/tabs.js b/airtime_mvc/public/js/airtime/showbuilder/tabs.js index f04680ffb..c6d1e284f 100644 --- a/airtime_mvc/public/js/airtime/showbuilder/tabs.js +++ b/airtime_mvc/public/js/airtime/showbuilder/tabs.js @@ -316,12 +316,12 @@ var AIRTIME = (function(AIRTIME){ /** * Given a tab id, get the corresponding Tab object * - * @param {int} id the tab id of the Tab to retrieve - * @returns {Tab|undefined} the Tab object with the given id, or undefined - * if no Tab with the given id exists + * @param {int|string} id the tab or object ID of the Tab to retrieve + * @returns {Tab|undefined} the Tab object with the given ID, or undefined + * if no Tab with the given ID exists */ mod.get = function(id) { - return $openTabs[$tabMap[id]]; + return $.isNumeric(id) ? $openTabs[$tabMap[id]] : $openTabs[id]; }; /** diff --git a/airtime_mvc/public/js/airtime/widgets/table.js b/airtime_mvc/public/js/airtime/widgets/table.js index 2c14394ce..165b1b2b7 100644 --- a/airtime_mvc/public/js/airtime/widgets/table.js +++ b/airtime_mvc/public/js/airtime/widgets/table.js @@ -23,11 +23,6 @@ var AIRTIME = (function(AIRTIME) { MULTI_CTRL : 2 }; - // Internal enum for repeated jQuery selectors - self._SELECTORS = Object.freeze({ - SELECTION_CHECKBOX: ".airtime_table_checkbox" - }); - //Member variables self._datatable = null; self._selectedRows = []; //An array containing the underlying objects for each selected row. (Easy to use!) @@ -109,8 +104,8 @@ var AIRTIME = (function(AIRTIME) { * than having a per-row callback...) */ if (bItemSelection) { - $(self._datatable, 'tbody tr').on('click contextmenu', 'tr', function (e) { - var aData = self._datatable.fnGetData($(this).index()); // $(this).data(); //Neat trick - thanks DataTables! + $(self._datatable, 'tbody tr').on('click contextmenu', self._SELECTORS.SELECTION_TABLE_ROW, function (e) { + var aData = self._datatable.fnGetData($(this).index()); var iDisplayIndex = $(this).index(); //The index of the row in the current page in the table. var nRow = this; @@ -146,10 +141,32 @@ var AIRTIME = (function(AIRTIME) { }); } + // On filter, display the number of total and filtered results in the search bar + $(self._datatable).on('filter', function() { + var dt = self._datatable, f = dt.closest(".dataTables_wrapper").find(".filter-message"), + totalRecords = dt.fnSettings().fnRecordsTotal(), + totalDisplayRecords = dt.fnSettings().fnRecordsDisplay(); + + if (f.length === 0) { + var el = document.createElement("span"); + el.setAttribute("class", "filter-message"); + f = dt.closest(".dataTables_wrapper").find(".dataTables_filter").append(el).find(".filter-message"); + } + + f.text(totalRecords > totalDisplayRecords ? + $.i18n._("Filtering out ") + (totalRecords - totalDisplayRecords) + + $.i18n._(" of ") + totalRecords + + $.i18n._(" records") : "" + ); + + dt.closest(".dataTables_wrapper").find('.dataTables_filter input[type="text"]') + .css('padding-right', f.outerWidth()); + }); + $(self._datatable).on('init', function(e) { self._setupToolbarButtons(self._toolbarButtons); }); - } + }; /** @@ -257,12 +274,6 @@ var AIRTIME = (function(AIRTIME) { var foundAtIdx = $.inArray(aData, self._selectedRows); console.log('checkbox mouse', iVisualRowIdx, foundAtIdx); - //XXX: Debugging -- Bug here-ish - if (foundAtIdx >= 0) { - console.log(aData, self._selectedRows[foundAtIdx]); - } else { - console.log("clicked row not detected as already selected"); - } //If the clicked row is already selected, deselect it. if (foundAtIdx >= 0 && self._selectedRows.length >= 1) { @@ -375,22 +386,6 @@ var AIRTIME = (function(AIRTIME) { fnCallback(json); }, "error": self._handleAjaxError - }).done(function (data) { - /* - if (data.iTotalRecords > data.iTotalDisplayRecords) { - $('#filter_message').text( - $.i18n._("Filtering out ") + (data.iTotalRecords - data.iTotalDisplayRecords) - + $.i18n._(" of ") + data.iTotalRecords - + $.i18n._(" records") - ); - $('#library_empty').hide(); - $('#library_display').find('tr:has(td.dataTables_empty)').show(); - } else { - $('#filter_message').text(""); - } - $('#library_content').find('.dataTables_filter input[type="text"]') - .css('padding-right', $('#advanced-options').find('button').outerWidth()); - */ }); }; @@ -427,6 +422,12 @@ var AIRTIME = (function(AIRTIME) { //Static initializers / Class variables /** Predefined toolbar buttons that you can add to the table. Use getStandardToolbarButtons(). */ + Table.prototype._SELECTORS = Object.freeze({ + SELECTION_CHECKBOX: ".airtime_table_checkbox", + SELECTION_TABLE_ROW: "tr" + }); + + Table.TOOLBAR_BUTTON_ROLES = { NEW : 0, EDIT : 1,