Add schedule embed widget for embedding the stations playlist schedule view into websites (#4323)

This commit is contained in:
Vaalyn 2021-06-21 03:58:02 +02:00 committed by GitHub
parent fc44a4ea91
commit 328caf3987
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 171 additions and 1 deletions

View File

@ -496,6 +496,12 @@ return [
// Auto-managed by Assets
],
'Vue_PublicSchedule' => [
'order' => 10,
'require' => ['vue-component-common', 'bootstrap-vue', 'moment_base', 'moment_timezone'],
// Auto-managed by Assets
],
'Vue_PublicWebDJ' => [
'order' => 10,
'require' => ['vue-component-common'],

View File

@ -33,6 +33,9 @@ return function (App $app) {
$group->get('/ondemand[/{embed:embed}]', Controller\Frontend\PublicPages\OnDemandAction::class)
->setName('public:ondemand');
$group->get('/schedule[/{embed:embed}]', Controller\Frontend\PublicPages\ScheduleAction::class)
->setName('public:schedule');
$group->get('/podcasts', Controller\Frontend\PublicPages\PodcastsController::class)
->setName('public:podcasts');

View File

@ -0,0 +1,61 @@
<template>
<div class="card" style="height: 100%;">
<div class="card-header bg-primary-dark">
<div class="d-flex align-items-center">
<div class="flex-shrink">
<h2 class="card-title py-2">
<template v-if="stationName">
{{ stationName }}
</template>
<template v-else>
<translate key="lang_title">Schedule</translate>
</template>
</h2>
</div>
</div>
</div>
<div id="station-schedule-calendar">
<schedule ref="schedule" :schedule-url="scheduleUrl" :station-time-zone="stationTimeZone"
:locale="locale"></schedule>
</div>
</div>
</template>
<style lang="scss">
.schedule.embed {
.container {
max-width: 100%;
padding: 0 !important;
}
}
#station-schedule-calendar {
overflow-y: auto;
}
</style>
<script>
import Schedule from '../Common/ScheduleView';
export default {
components: { Schedule },
props: {
scheduleUrl: String,
stationName: String,
locale: String,
stationTimeZone: String
},
mounted () {
moment.relativeTimeThreshold('ss', 1);
moment.relativeTimeRounding(function (value) {
return Math.round(value * 10) / 10;
});
},
methods: {
formatTime (time) {
return moment(time).tz(this.stationTimeZone).format('LT');
}
}
};
</script>

View File

@ -72,7 +72,8 @@ export const profileEmbedModalProps = {
publicPageEmbedUri: String,
publicOnDemandEmbedUri: String,
publicRequestEmbedUri: String,
publicHistoryEmbedUri: String
publicHistoryEmbedUri: String,
publicScheduleEmbedUri: String
}
};
@ -88,6 +89,10 @@ export default {
{
value: 'history',
text: this.$gettext('History')
},
{
value: 'schedule',
text: this.$gettext('Schedule')
}
];
@ -142,6 +147,9 @@ export default {
case 'requests':
return this.publicRequestEmbedUri;
case 'schedule':
return this.publicScheduleEmbedUri;
case 'player':
default:
return this.publicPageEmbedUri;
@ -170,6 +178,9 @@ export default {
case 'history':
return '300px';
case 'schedule':
return '800px'
case 'player':
default:
return '150px';

View File

@ -37,6 +37,12 @@
<a :href="publicPodcastsUri">{{ publicPodcastsUri }}</a>
</td>
</tr>
<tr>
<td key="lang_profile_schedule" v-translate>Schedule</td>
<td>
<a :href="publicScheduleUri">{{ publicScheduleUri }}</a>
</td>
</tr>
</tbody>
</table>
<div class="card-actions" v-if="userCanManageProfile">
@ -85,6 +91,7 @@ export const profilePublicProps = {
publicWebDjUri: String,
publicOnDemandUri: String,
publicPodcastsUri: String,
publicScheduleUri: String,
togglePublicPageUri: String
}
};

View File

@ -13,6 +13,7 @@ module.exports = {
PublicOnDemand: './vue/Public/OnDemand.vue',
PublicPlayer: './vue/Public/Player.vue',
PublicRequests: './vue/Public/Requests.vue',
PublicSchedule: './vue/Public/Schedule.vue',
PublicWebDJ: './vue/Public/WebDJ.vue',
StationsMedia: './vue/Stations/Media.vue',
StationsMounts: './vue/Stations/Mounts.vue',

View File

@ -0,0 +1,36 @@
<?php
namespace App\Controller\Frontend\PublicPages;
use App\Exception\StationNotFoundException;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
class ScheduleAction
{
public function __invoke(
ServerRequest $request,
Response $response,
bool $embed = false
): ResponseInterface {
// Override system-wide iframe refusal
$response = $response->withHeader('X-Frame-Options', '*');
$station = $request->getStation();
if (!$station->getEnablePublicPage()) {
throw new StationNotFoundException();
}
return $request->getView()->renderToResponse(
$response,
'frontend/public/schedule',
[
'embed' => $embed,
'station' => $station,
'station_tz' => $station->getTimezone(),
]
);
}
}

View File

@ -0,0 +1,33 @@
<?php
/** @var App\Entity\Station $station */
$pageClass = 'schedule station-' . $station->getShortName();
if ($embed) {
$pageClass .= ' embed';
}
$this->layout(
'minimal',
[
'page_class' => $pageClass,
'title' => __('Schedule') . ' - ' . $this->e($station->getName()),
'hide_footer' => true,
]
);
$props = [
'scheduleUrl' => (string)$router->named('api:stations:schedule', ['station_id' => $station->getId()]),
'stationName' => $station->getName(),
'locale' => substr($customization->getLocale()->getLocale(), 0, 2),
'stationTimeZone' => $station_tz,
];
/** @var \App\Assets $assets */
$assets->addVueRender('Vue_PublicSchedule', '#station-schedule', $props);
?>
<section id="content" role="main" class="d-flex align-items-stretch" style="height: 100vh;">
<div class="container pt-5 pb-5 h-100" style="flex: 1;">
<div id="station-schedule"></div>
</div>
</section>

View File

@ -72,6 +72,12 @@ $props = [
[],
true
),
'publicScheduleUri' => (string)$router->named(
'public:schedule',
['station_id' => $station->getShortName()],
[],
true
),
'publicOnDemandEmbedUri' => (string)$router->named(
'public:ondemand',
['station_id' => $station->getShortName(), 'embed' => 'embed'],
@ -90,6 +96,12 @@ $props = [
[],
true
),
'publicScheduleEmbedUri' => (string)$router->named(
'public:schedule',
['station_id' => $station->getShortName(), 'embed' => 'embed'],
[],
true
),
'togglePublicPageUri' => $router->fromHere(
'stations:profile:toggle',