diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/assets/js/views-basic.js b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/assets/js/views-basic.js index c6a8580b1..8dbcc3a12 100644 --- a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/assets/js/views-basic.js +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/assets/js/views-basic.js @@ -75,6 +75,28 @@ displayElement.addEventListener('change', updateLimitElement); updateLimitElement(); } + + // Unified selectors to handle both cases + const entityTypesSelector = 'input[name="settings[block_form][group_user_selection][entity_and_view_mode][entity_types]"], input[name="block_form[group_user_selection][entity_and_view_mode][entity_types]"]'; + const viewModeSelector = 'input[name="settings[block_form][group_user_selection][entity_and_view_mode][view_mode]"], input[name="block_form[group_user_selection][entity_and_view_mode][view_mode]"]'; + const eventTimePeriod = document.querySelector('#edit-event-time-period'); + + const entityTypes = document.querySelectorAll(entityTypesSelector); + const viewModes = document.querySelectorAll(viewModeSelector); + + // Function to handle visibility based on conditions + function updateVisibility() { + const entityType = Array.from(entityTypes).find(input => input.checked)?.value; + const viewMode = Array.from(viewModes).find(input => input.checked)?.value; + + if (eventTimePeriod) { + eventTimePeriod.style.display = (entityType === 'event' && viewMode === 'calendar') ? 'none' : ''; + } + } + + entityTypes.forEach(input => input.addEventListener('change', updateVisibility)); + viewModes.forEach(input => input.addEventListener('change', updateVisibility)); + updateVisibility(); }, }; })(Drupal); diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Controller/EventsCalendarController.php b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Controller/EventsCalendarController.php new file mode 100644 index 000000000..e43e8968d --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Controller/EventsCalendarController.php @@ -0,0 +1,66 @@ +get('ys_views_basic.events_calendar'), + ); + } + + /** + * Builds the response. + */ + public function __invoke(Request $request): AjaxResponse { + $response = new AjaxResponse(); + + if (!$request->request->has('calendar_id') || !$request->request->has('month') || !$request->request->has('year')) { + return $response; + } + + // Calendar wrapper that needs to be updated. + $calendar_id = $request->request->get('calendar_id'); + $month = $request->request->get('month'); + $year = $request->request->get('year'); + + $events_calendar = $this->eventsCalendar + ->getCalendar($month, $year); + + $calendar = [ + '#theme' => 'views_basic_events_calendar', + '#month_data' => $events_calendar, + '#cache' => [ + 'tags' => ['node_list:event'], + ], + ]; + + $response->addCommand(new ReplaceCommand($calendar_id, $calendar)); + + return $response; + } + +} diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Plugin/Field/FieldFormatter/ViewsBasicDefaultFormatter.php b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Plugin/Field/FieldFormatter/ViewsBasicDefaultFormatter.php index 3428c952e..56ffeb944 100644 --- a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Plugin/Field/FieldFormatter/ViewsBasicDefaultFormatter.php +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Plugin/Field/FieldFormatter/ViewsBasicDefaultFormatter.php @@ -6,7 +6,7 @@ use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Field\FormatterBase; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; -use Drupal\Core\Render\Renderer; +use Drupal\ys_views_basic\Service\EventsCalendarInterface; use Drupal\ys_views_basic\ViewsBasicManager; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -28,14 +28,14 @@ class ViewsBasicDefaultFormatter extends FormatterBase implements ContainerFacto * * @var \Drupal\ys_views_basic\ViewsBasicManager */ - protected $viewsBasicManager; + protected ViewsBasicManager $viewsBasicManager; /** - * The renderer service. + * The Events Calendar service. * - * @var \Drupal\Core\Render\Renderer + * @var \Drupal\ys_views_basic\Service\EventsCalendarInterface */ - protected $rendererService; + protected EventsCalendarInterface $eventsCalendar; /** * Constructs an views basic default formatter object. @@ -54,10 +54,10 @@ class ViewsBasicDefaultFormatter extends FormatterBase implements ContainerFacto * The view mode. * @param array $third_party_settings * Any third party settings. - * @param \Drupal\ys_views_basic\Plugin\ViewsBasicManager $viewsBasicManager + * @param \Drupal\ys_views_basic\ViewsBasicManager $viewsBasicManager * The views basic manager service. - * @param \Drupal\Core\Render\Renderer $renderer_service - * Drupal Core renderer service. + * @param \Drupal\ys_views_basic\Service\EventsCalendarInterface $eventsCalendar + * The Events Calendar service. */ public function __construct( string $plugin_id, @@ -68,7 +68,7 @@ public function __construct( string $view_mode, array $third_party_settings, ViewsBasicManager $viewsBasicManager, - Renderer $renderer_service, + EventsCalendarInterface $eventsCalendar, ) { parent::__construct( $plugin_id, @@ -78,20 +78,15 @@ public function __construct( $label, $view_mode, $third_party_settings, - $this->rendererService = $renderer_service, ); $this->viewsBasicManager = $viewsBasicManager; + $this->eventsCalendar = $eventsCalendar; } /** * {@inheritdoc} */ - public static function create( - ContainerInterface $container, - array $configuration, - $plugin_id, - $plugin_definition, - ) { + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( $plugin_id, $plugin_definition, @@ -101,33 +96,57 @@ public static function create( $configuration['view_mode'], $configuration['third_party_settings'], $container->get('ys_views_basic.views_basic_manager'), - $container->get('renderer'), + $container->get('ys_views_basic.events_calendar') ); } /** * Define how the field type is showed. */ - public function viewElements(FieldItemListInterface $items, $langcode) { + public function viewElements(FieldItemListInterface $items, $langcode): array { $elements = []; + foreach ($items as $delta => $item) { + // Get decoded parameters. + $paramsDecoded = json_decode($item->getValue()['params'], TRUE); + + if ($paramsDecoded['filters']['types'][0] === 'event' && $paramsDecoded['view_mode'] === 'calendar') { + // Calculate the remaining time until the end of the current month. + $now = new \DateTime(); + $end_of_month = new \DateTime('last day of this month 23:59:59'); + $remaining_time_in_seconds = $end_of_month->getTimestamp() - $now->getTimestamp(); - $view = $this->viewsBasicManager->getView('rendered', $item->getValue()['params']); + $events_calendar = $this->eventsCalendar + ->getCalendar(date('m'), date('Y')); - $elements[$delta] = [ - '#theme' => 'views_basic_formatter_default', - '#view' => $view, - // Extract exposed filters from the view and place them separately. - // This is necessary because we are conditionally displaying - // specific exposed filters based on field configuration. - // By placing the exposed filters outside of the view rendering - // context, we ensure that they do not get re-rendered - // when AJAX operations are performed on the view, - // allowing for better control over which filters are displayed - // and maintaining the expected user interface behavior. - '#exposed' => $view['#view']->exposed_widgets, - ]; + $elements[$delta] = [ + '#theme' => 'views_basic_events_calendar', + '#month_data' => $events_calendar, + '#cache' => [ + 'tags' => ['node_list:event'], + // Set max-age to the remaining time until the end of the month. + 'max-age' => $remaining_time_in_seconds, + 'contexts' => ['timezone'], + ], + ]; + } + else { + $view = $this->viewsBasicManager->getView('rendered', $item->getValue()['params']); + $elements[$delta] = [ + '#theme' => 'views_basic_formatter_default', + '#view' => $view, + // Extract exposed filters from the view and place them separately. + // This is necessary because we are conditionally displaying + // specific exposed filters based on field configuration. + // By placing the exposed filters outside of the view rendering + // context, we ensure that they do not get re-rendered + // when AJAX operations are performed on the view, + // allowing for better control over which filters are displayed + // and maintaining the expected user interface behavior. + '#exposed' => $view['#view']->exposed_widgets, + ]; + } } return $elements; diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Plugin/Field/FieldWidget/ViewsBasicDefaultWidget.php b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Plugin/Field/FieldWidget/ViewsBasicDefaultWidget.php index 468fbe71d..7680c5f2d 100644 --- a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Plugin/Field/FieldWidget/ViewsBasicDefaultWidget.php +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Plugin/Field/FieldWidget/ViewsBasicDefaultWidget.php @@ -219,6 +219,11 @@ public function formElement( '#suffix' => '', ]; + // Define the state for when the view mode is 'calendar' once. + $calendarViewInvisibleState = [ + $formSelectors['view_mode_input_selector'] => ['value' => 'calendar'], + ]; + $fieldOptionValue = ($items[$delta]->params) ? $this->viewsBasicManager->getDefaultParamValue('field_options', $items[$delta]->params) : []; $fieldOptionDefaultValue = $fieldOptionValue ?? ['show_thumbnail' => 'show_thumbnail']; $isNewForm = str_contains($formState->getCompleteForm()['#id'], 'layout-builder-add-block'); @@ -234,6 +239,7 @@ public function formElement( '#title' => $this->t('Field Display Options'), '#tree' => TRUE, '#default_value' => ($isNewForm && empty($fieldOptionValue)) ? ['show_thumbnail'] : $fieldOptionDefaultValue, + '#states' => ['invisible' => $calendarViewInvisibleState], 'show_thumbnail' => [ '#states' => [ 'visible' => [ @@ -256,14 +262,9 @@ public function formElement( '#title' => $this->t('Exposed Filter Options'), '#tree' => TRUE, '#default_value' => ($items[$delta]->params) ? $this->viewsBasicManager->getDefaultParamValue('exposed_filter_options', $items[$delta]->params) : [], + '#states' => ['invisible' => $calendarViewInvisibleState], 'show_year_filter' => [ - '#states' => [ - 'visible' => [ - $formSelectors['entity_types_ajax'] => [ - 'value' => 'post', - ], - ], - ], + '#states' => ['visible' => [$formSelectors['entity_types_ajax'] => ['value' => 'post']]], ], ]; @@ -273,9 +274,8 @@ public function formElement( '#description' => $this->t("Enter a custom label for the Category Filter. This label will be displayed to users as the filter's name. If left blank, the default label Category will be used."), '#default_value' => ($items[$delta]->params) ? $this->viewsBasicManager->getDefaultParamValue('category_filter_label', $items[$delta]->params) : NULL, '#states' => [ - 'visible' => [ - $formSelectors['show_category_filter_selector'] => ['checked' => TRUE], - ], + 'visible' => [$formSelectors['show_category_filter_selector'] => ['checked' => TRUE]], + 'invisible' => $calendarViewInvisibleState, ], ]; @@ -291,9 +291,8 @@ public function formElement( '#prefix' => '
', '#suffix' => '
', '#states' => [ - 'visible' => [ - $formSelectors['show_category_filter_selector'] => ['checked' => TRUE], - ], + 'visible' => [$formSelectors['show_category_filter_selector'] => ['checked' => TRUE]], + 'invisible' => $calendarViewInvisibleState, ], ]; @@ -306,6 +305,7 @@ public function formElement( '#tags' => TRUE, '#target_type' => 'taxonomy_term', '#default_value' => ($items[$delta]->params) ? $this->viewsBasicManager->getDefaultParamValue('terms_include', $items[$delta]->params) : [], + '#states' => ['invisible' => $calendarViewInvisibleState], ]; $form['group_user_selection']['filter_and_sort']['terms_exclude'] = [ @@ -317,6 +317,7 @@ public function formElement( '#tags' => TRUE, '#target_type' => 'taxonomy_term', '#default_value' => ($items[$delta]->params) ? $this->viewsBasicManager->getDefaultParamValue('terms_exclude', $items[$delta]->params) : [], + '#states' => ['invisible' => $calendarViewInvisibleState], ]; $form['group_user_selection']['filter_and_sort']['term_operator'] = [ @@ -333,7 +334,7 @@ public function formElement( 'term-operator-item', ], ], - + '#states' => ['invisible' => $calendarViewInvisibleState], ]; // Gets the view mode options based on Ajax callbacks or initial load. @@ -349,6 +350,7 @@ public function formElement( '#validated' => 'true', '#prefix' => '
', '#suffix' => '
', + '#states' => ['invisible' => $calendarViewInvisibleState], ]; $form['group_user_selection']['entity_specific']['event_time_period'] = [ @@ -360,13 +362,8 @@ public function formElement( 'all' => $this->t('All Events') . 'All Events icon showing a calendar.', ], '#default_value' => ($items[$delta]->params) ? $this->viewsBasicManager->getDefaultParamValue('event_time_period', $items[$delta]->params) : 'future', - '#states' => [ - 'visible' => [ - $formSelectors['entity_types_ajax'] => [ - 'value' => 'event', - ], - ], - ], + '#prefix' => '
', + '#suffix' => '
', ]; $displayValue = ($items[$delta]->params) ? $this->viewsBasicManager->getDefaultParamValue('display', $items[$delta]->params) : 'all'; @@ -381,6 +378,7 @@ public function formElement( 'limit' => $this->t('Limit to'), 'pager' => $this->t('Pagination after'), ], + '#states' => ['invisible' => $calendarViewInvisibleState], ]; $limitTitle = $this->t('Items'); @@ -401,6 +399,7 @@ public function formElement( '#required' => TRUE, '#prefix' => '
', '#suffix' => '
', + '#states' => ['invisible' => $calendarViewInvisibleState], ]; $form['group_user_selection']['options']['offset'] = [ @@ -412,6 +411,7 @@ public function formElement( '#attributes' => [ 'placeholder' => 0, ], + '#states' => ['invisible' => $calendarViewInvisibleState], ]; $element['group_params']['params'] = [ @@ -424,6 +424,7 @@ public function formElement( 'views-basic--params', ], ], + '#states' => ['invisible' => $calendarViewInvisibleState], ]; $form['#attached']['library'][] = 'ys_views_basic/ys_views_basic'; diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Service/EventsCalendar.php b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Service/EventsCalendar.php new file mode 100644 index 000000000..9f54e5584 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Service/EventsCalendar.php @@ -0,0 +1,280 @@ +entityTypeManager = $entity_type_manager; + $this->aliasManager = $alias_manager; + $this->nodeStorage = $entity_type_manager->getStorage('node'); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container): static { + return new static( + $container->get('entity_type.manager'), + $container->get('path_alias.manager') + ); + } + + /** + * {@inheritdoc} + */ + public function getCalendar(string $month, string $year): array { + // Create a date object for the first day of the given month and year. + $firstDayOfMonth = new DrupalDateTime("$year-$month-01"); + $totalDaysInMonth = (int) $firstDayOfMonth->format('t'); + $startDayOfWeek = (int) $firstDayOfMonth->format('w'); + $lastDayOfMonth = new DrupalDateTime("$year-$month-$totalDaysInMonth"); + $endDayOfWeek = (int) $lastDayOfMonth->format('w'); + + $paddingStart = $startDayOfWeek; + $paddingEnd = 6 - $endDayOfWeek; + $totalCells = $totalDaysInMonth + $paddingStart + $paddingEnd; + $totalRows = (int) ceil($totalCells / 7); + $calendarRows = []; + + // Calculate the previous month and year. + $previousMonthDate = clone $firstDayOfMonth; + $previousMonthDate->modify('-1 month'); + $daysInPreviousMonth = (int) $previousMonthDate->format('t'); + $previousMonth = $previousMonthDate->format('m'); + $previousYear = $previousMonthDate->format('Y'); + + // Calculate the next month and year. + $nextMonthDate = clone $lastDayOfMonth; + $nextMonthDate->modify('+1 month'); + $nextMonth = $nextMonthDate->format('m'); + $nextYear = $nextMonthDate->format('Y'); + + // Load all events for the given month and year. + $monthlyEvents = $this->loadMonthlyEvents($month, $year); + + $currentDay = 1; + + for ($row = 0; $row < $totalRows; $row++) { + $calendarRows[$row] = []; + for ($cell = 0; $cell < 7; $cell++) { + if ($row == 0 && $cell < $paddingStart) { + // Fill in days from the previous month. + $day = $daysInPreviousMonth - ($paddingStart - $cell - 1); + $calendarRows[$row][] = $this->createCalendarCell($day, $previousMonth, $previousYear, $monthlyEvents); + } + elseif ($row == $totalRows - 1 && $cell > $endDayOfWeek) { + // Fill in days from the next month. + $day = $cell - $endDayOfWeek; + $calendarRows[$row][] = $this->createCalendarCell($day, $nextMonth, $nextYear, $monthlyEvents); + } + else { + // Normal date cell within the current month. + $calendarRows[$row][] = $this->createCalendarCell($currentDay, $month, $year, $monthlyEvents); + $currentDay++; + } + } + } + + return $calendarRows; + } + + /** + * {@inheritdoc} + */ + public function createCalendarCell(int $day, string $month, string $year, array $events): array { + return [ + 'date' => [ + 'day' => str_pad($day, 2, '0', STR_PAD_LEFT), + 'month' => $month, + 'year' => $year, + ], + 'events' => $this->getEvents($day, $month, $year, $events), + ]; + } + + /** + * {@inheritdoc} + */ + public function getEvents(int $day, string $month, string $year, array $events): array { + $startDate = new DrupalDateTime("$year-$month-$day 00:00:00"); + $endDate = new DrupalDateTime("$year-$month-$day 23:59:59"); + + $startTimestamp = $startDate->getTimestamp(); + $endTimestamp = $endDate->getTimestamp(); + + $events_data = []; + foreach ($events as $event) { + if (!$event->get('field_event_date')->isEmpty()) { + // Handle recurrence rules if present. + if ($event->field_event_date?->rrule) { + + /** @var \Drupal\smart_date_recur\Entity\SmartDateRule $rule */ + $rule = $this->entityTypeManager->getStorage('smart_date_rule') + ->load($event->field_event_date->rrule); + + if ($rule instanceof SmartDateRule) { + // Iterate over the stored instances to find occurrences for the + // current day. + foreach ($rule->getStoredInstances() as $instance) { + $instanceStartTimestamp = $instance['value']; + $instanceEndTimestamp = $instance['end_value']; + + // Check if the instance overlaps with the current day. + if ($instanceStartTimestamp <= $endTimestamp && $instanceEndTimestamp >= $startTimestamp) { + $time = $this->isAllDay($instanceStartTimestamp, $instanceEndTimestamp) + ? $this->t('All Day') + : $this->t('@start to @end', [ + '@start' => date('g:iA', $instanceStartTimestamp), + '@end' => date('g:iA', $instanceEndTimestamp), + ]); + + $events_data[] = $this->createEventArray($event, $time, $instanceStartTimestamp); + } + } + } + } + else { + // Iterate through the nodes to extract event details. + foreach ($event->get('field_event_date')->getValue() as $eventDate) { + $eventStartTimestamp = $eventDate['value']; + $eventEndTimestamp = $eventDate['end_value']; + + // Check if the event overlaps with the current day. + if ($eventStartTimestamp <= $endTimestamp && $eventEndTimestamp >= $startTimestamp) { + if (date('Y-m-d', $eventStartTimestamp) !== date('Y-m-d', $eventEndTimestamp)) { + $time = $this->t('Multi-day Event'); + } + else { + $time = $this->isAllDay($eventStartTimestamp, $eventEndTimestamp) + ? $this->t('All Day') + : $this->t('@start to @end', [ + '@start' => date('g:iA', $eventStartTimestamp), + '@end' => date('g:iA', $eventEndTimestamp), + ]); + } + + // Add event to the list if it overlaps with the current day. + $events_data[] = $this->createEventArray($event, $time, $eventStartTimestamp); + } + } + } + } + } + + // Sort events by the start timestamp. + usort($events_data, function ($a, $b) { + return $a['timestamp'] <=> $b['timestamp']; + }); + + return $events_data; + } + + /** + * {@inheritdoc} + */ + public function createEventArray($node, string $time, int $timestamp): array { + // Extract the event's categories. + $categories = implode(' | ', array_map(function ($term) { + return $term->label(); + }, $node->get('field_category')->referencedEntities())); + + // Extract the event's tags. + $tags = array_map(fn($term) => $term->label(), $node->get('field_tags')->referencedEntities()); + + // Build and return the event array. + return [ + 'category' => $categories, + 'title' => $node->label(), + 'url' => $this->aliasManager->getAliasByPath('/node/' . $node->id()), + 'time' => $time, + 'type' => $tags, + 'timestamp' => $timestamp, + ]; + } + + /** + * {@inheritdoc} + */ + public function isAllDay(int $start_ts, int $end_ts, ?string $timezone = NULL): bool { + if ($timezone) { + $default_tz = date_default_timezone_get(); + date_default_timezone_set($timezone); + } + + $temp_start = date('H:i', $start_ts); + $temp_end = date('H:i', $end_ts); + + if ($timezone) { + date_default_timezone_set($default_tz); + } + + return $temp_start == '00:00' && $temp_end == '23:59'; + } + + /** + * {@inheritdoc} + */ + public function loadMonthlyEvents(string $month, string $year): array { + $startDate = new DrupalDateTime("$year-$month-01 00:00:00"); + $endDate = clone $startDate; + $endDate->modify('last day of this month 23:59:59'); + + // Query to fetch event nodes that overlap with the given month. + $query = $this->nodeStorage->getQuery() + ->accessCheck() + ->condition('type', 'event') + ->condition('status', 1) + ->condition('field_event_date.value', $endDate->getTimestamp(), '<=') + ->condition('field_event_date.end_value', $startDate->getTimestamp(), '>='); + + $nids = $query->execute(); + return $this->nodeStorage->loadMultiple($nids); + } + +} diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Service/EventsCalendarInterface.php b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Service/EventsCalendarInterface.php new file mode 100644 index 000000000..4c4640478 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/src/Service/EventsCalendarInterface.php @@ -0,0 +1,102 @@ + '/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/assets/icons/display-type-condensed.svg', 'img_alt' => 'Icon showing 3 generic list items one on top of the other with no images on the items.', ], + 'calendar' => [ + 'label' => 'Calendar', + 'img' => '/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/assets/icons/content-type-event.svg', + 'img_alt' => 'Calendar', + ], ], 'sort_by' => [ 'field_event_date:DESC' => 'Event Date - newer first', diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/templates/views-basic-events-calendar.html.twig b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/templates/views-basic-events-calendar.html.twig new file mode 100644 index 000000000..7d089c2a1 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/templates/views-basic-events-calendar.html.twig @@ -0,0 +1,5 @@ +{{ attach_library('atomic/calendar') }} + +{% include "@organisms/calendar/yds-calendar.twig" with { + month:month_data +} %} diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/ys_views_basic.module b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/ys_views_basic.module index a58c13d94..70ad89fb5 100644 --- a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/ys_views_basic.module +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/ys_views_basic.module @@ -32,6 +32,11 @@ function ys_views_basic_theme($existing, $type, $theme, $path): array { 'contentType' => NULL, ], ], + 'views_basic_events_calendar' => [ + 'variables' => [ + 'month_data' => [], + ], + ], ]; } diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/ys_views_basic.routing.yml b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/ys_views_basic.routing.yml new file mode 100644 index 000000000..818b81880 --- /dev/null +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/ys_views_basic.routing.yml @@ -0,0 +1,7 @@ +ys_views_basic.events_calendar: + path: '/events-calendar' + defaults: + _title: 'Events Calendar' + _controller: '\Drupal\ys_views_basic\Controller\EventsCalendarController' + requirements: + _permission: 'access content' diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/ys_views_basic.services.yml b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/ys_views_basic.services.yml index 4039bf8a2..0a37a9f47 100644 --- a/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/ys_views_basic.services.yml +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_views_basic/ys_views_basic.services.yml @@ -3,3 +3,7 @@ services: ys_views_basic.views_basic_manager: class: Drupal\ys_views_basic\ViewsBasicManager arguments: ['@entity_type.manager', '@entity_display.repository'] + + ys_views_basic.events_calendar: + class: Drupal\ys_views_basic\Service\EventsCalendar + arguments: ['@entity_type.manager', '@path_alias.manager']