514 lines
22 KiB
PHP
514 lines
22 KiB
PHP
<?php
|
|
|
|
/**
|
|
* The concrete class for day view.
|
|
*
|
|
* @author Time.ly Network Inc.
|
|
* @since 2.0
|
|
*
|
|
* @package AI1EC
|
|
* @subpackage AI1EC.View
|
|
*/
|
|
class Ai1ec_Calendar_View_Week extends Ai1ec_Calendar_View_Abstract {
|
|
|
|
/* (non-PHPdoc)
|
|
* @see Ai1ec_Calendar_View_Abstract::get_name()
|
|
*/
|
|
public function get_name() {
|
|
return 'week';
|
|
}
|
|
|
|
/* (non-PHPdoc)
|
|
* @see Ai1ec_Calendar_View_Abstract::get_content()
|
|
*/
|
|
public function get_content( array $view_args ) {
|
|
$date_system = $this->_registry->get( 'date.system' );
|
|
$settings = $this->_registry->get( 'model.settings' );
|
|
$defaults = array(
|
|
'week_offset' => 0,
|
|
'cat_ids' => array(),
|
|
'tag_ids' => array(),
|
|
'auth_ids' => array(),
|
|
'post_ids' => array(),
|
|
'instance_ids' => array(),
|
|
'exact_date' => $date_system->current_time(),
|
|
);
|
|
$args = wp_parse_args( $view_args, $defaults );
|
|
|
|
// Localize requested date and get components.
|
|
$local_date = $this->_registry
|
|
->get( 'date.time', $args['exact_date'], 'sys.default' );
|
|
$start_day_offset = $this->get_week_start_day_offset( $local_date->format( 'w' ) );
|
|
// get the first day of week
|
|
$local_date->adjust_day( 0 + $start_day_offset + ( $args['week_offset'] * 7 ) )
|
|
->set_time( 0, 0, 0 );
|
|
|
|
$cell_array = $this->get_week_cell_array(
|
|
$local_date,
|
|
apply_filters(
|
|
'ai1ec_get_events_relative_to_filter',
|
|
array(
|
|
'cat_ids' => $args['cat_ids'],
|
|
'tag_ids' => $args['tag_ids'],
|
|
'post_ids' => $args['post_ids'],
|
|
'auth_ids' => $args['auth_ids'],
|
|
'instance_ids' => $args['instance_ids'],
|
|
),
|
|
$view_args,
|
|
apply_filters(
|
|
'ai1ec_show_unique_events',
|
|
false
|
|
)
|
|
)
|
|
);
|
|
|
|
// Create pagination links. (Translators: '%s' = week's start date.)
|
|
$title = sprintf(
|
|
__( 'Week of %s', AI1EC_PLUGIN_NAME ),
|
|
$local_date->format_i18n( 'F j' )
|
|
);
|
|
$pagination_links = $this->_get_pagination( $args, $title );
|
|
|
|
$time_format = $this->_registry->get( 'model.option' )
|
|
->get( 'time_format', Ai1ec_I18n::__( 'g a' ) );
|
|
|
|
// Calculate today marker's position.
|
|
$now = $this->_registry->get( 'date.time', 'now', 'sys.default' );
|
|
$now_text = $now->format_i18n( 'M j h:i a' );
|
|
$now = $now->format( 'G' ) * 60 + $now->format( 'i' );
|
|
// Find out if the current week view contains "now" and thus should display
|
|
// the "now" marker.
|
|
$show_now = false;
|
|
foreach ( $cell_array as $day ) {
|
|
if ( $day['today'] ) {
|
|
$show_now = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
$is_ticket_button_enabled = apply_filters( 'ai1ec_week_ticket_button', false );
|
|
$show_reveal_button = apply_filters( 'ai1ec_week_reveal_button', false );
|
|
|
|
$hours = array();
|
|
$today = $this->_registry->get( 'date.time', 'now', 'sys.default' );
|
|
for ( $hour = 0; $hour < 24; $hour++ ) {
|
|
$hours[] = $today
|
|
->set_time( $hour, 0, 0 )
|
|
->format_i18n( $time_format );
|
|
}
|
|
|
|
$view_args = array(
|
|
'title' => $title,
|
|
'type' => 'week',
|
|
'cell_array' => $cell_array,
|
|
'show_location_in_title' => $settings->get( 'show_location_in_title' ),
|
|
'now_top' => $now,
|
|
'now_text' => $now_text,
|
|
'show_now' => $show_now,
|
|
'post_ids' => join( ',', $args['post_ids'] ),
|
|
'time_format' => $time_format,
|
|
'done_allday_label' => false,
|
|
'done_grid' => false,
|
|
'data_type' => $args['data_type'],
|
|
'is_ticket_button_enabled' => $is_ticket_button_enabled,
|
|
'show_reveal_button' => $show_reveal_button,
|
|
'text_full_day' => __( 'Reveal full day', AI1EC_PLUGIN_NAME ),
|
|
'text_all_day' => __( 'All-day', AI1EC_PLUGIN_NAME ),
|
|
'text_now_label' => __( 'Now:', AI1EC_PLUGIN_NAME ),
|
|
'text_venue_separator' => __( '@ %s', AI1EC_PLUGIN_NAME ),
|
|
'hours' => $hours,
|
|
'indent_multiplier' => 8,
|
|
'indent_offset' => 0,
|
|
'pagination_links' => $pagination_links,
|
|
);
|
|
|
|
// Add navigation if requested.
|
|
$view_args['navigation'] = $this->_get_navigation(
|
|
array(
|
|
'no_navigation' => $args['no_navigation'],
|
|
'pagination_links' => $pagination_links,
|
|
'views_dropdown' => $args['views_dropdown'],
|
|
'below_toolbar' => apply_filters(
|
|
'ai1ec_below_toolbar',
|
|
'',
|
|
$this->get_name(),
|
|
$args
|
|
),
|
|
)
|
|
);
|
|
|
|
$view_args = $this->get_extra_template_arguments( $view_args );
|
|
|
|
return
|
|
$this->_registry->get( 'http.request' )->is_json_required(
|
|
$args['request_format'], 'week'
|
|
)
|
|
? $this->_apply_filters_to_args( $view_args )
|
|
: $this->_get_view( $view_args );
|
|
}
|
|
|
|
/**
|
|
* Returns a non-associative array of two links for the week view of the
|
|
* calendar:
|
|
* previous week, and next week.
|
|
* Each element is an associative array containing the link's enabled status
|
|
* ['enabled'], CSS class ['class'], text ['text'] and value to assign to
|
|
* link's href ['href'].
|
|
*
|
|
* @param array $args Current request arguments
|
|
* @param string $title Title to display in datepicker button
|
|
*
|
|
* @return array Array of links
|
|
*/
|
|
protected function get_week_pagination_links( $args, $title ) {
|
|
$links = array();
|
|
|
|
$orig_date = $args['exact_date'];
|
|
|
|
$negative_offset = $args['week_offset'] * 7 - 7;
|
|
$positive_offset = $args['week_offset'] * 7 + 7;
|
|
// =================
|
|
// = Previous week =
|
|
// =================
|
|
$local_date = $this->_registry
|
|
->get( 'date.time', $args['exact_date'], 'sys.default' )
|
|
->adjust_day( $negative_offset )
|
|
->set_time( 0, 0, 0 );
|
|
$args['exact_date'] = $local_date->format();
|
|
$href = $this->_registry->get( 'html.element.href', $args );
|
|
$links[] = array(
|
|
'enabled' => true,
|
|
'class'=> 'ai1ec-prev-week',
|
|
'text' => '<i class="ai1ec-fa ai1ec-fa-chevron-left"></i>',
|
|
'href' => $href->generate_href(),
|
|
);
|
|
// ======================
|
|
// = Minical datepicker =
|
|
// ======================
|
|
$args['exact_date'] = $orig_date;
|
|
$factory = $this->_registry->get( 'factory.html' );
|
|
$links[] = $factory->create_datepicker_link(
|
|
$args,
|
|
$args['exact_date'],
|
|
$title
|
|
);
|
|
|
|
// =============
|
|
// = Next week =
|
|
// =============
|
|
$local_date->adjust_day( $positive_offset * 2 ); // above was (-1), (+2) is to counteract
|
|
$args['exact_date'] = $local_date->format();
|
|
$href = $this->_registry->get( 'html.element.href', $args );
|
|
$links[] = array(
|
|
'enabled' => true,
|
|
'class'=> 'ai1ec-next-week',
|
|
'text' => '<i class="ai1ec-fa ai1ec-fa-chevron-right"></i>',
|
|
'href' => $href->generate_href(),
|
|
);
|
|
|
|
return $links;
|
|
}
|
|
|
|
/**
|
|
* get_week_cell_array function
|
|
*
|
|
* Return an associative array of weekdays, indexed by the day's date,
|
|
* starting the day given by $timestamp, each element an associative array
|
|
* containing three elements:
|
|
* ['today'] => whether the day is today
|
|
* ['allday'] => non-associative ordered array of events that are all-day
|
|
* ['notallday'] => non-associative ordered array of non-all-day events to
|
|
* display for that day, each element another associative
|
|
* array like so:
|
|
* ['top'] => how many minutes offset from the start of the day
|
|
* ['height'] => how many minutes this event spans
|
|
* ['indent'] => how much to indent this event to accommodate multiple
|
|
* events occurring at the same time (0, 1, 2, etc., to
|
|
* be multiplied by whatever desired px/em amount)
|
|
* ['event'] => event data object
|
|
*
|
|
* @param int $start_of_week the UNIX timestamp of the first day of the week
|
|
* @param array $filter Array of filters for the events returned:
|
|
* ['cat_ids'] => non-associatative array of category IDs
|
|
* ['tag_ids'] => non-associatative array of tag IDs
|
|
* ['post_ids'] => non-associatative array of post IDs
|
|
* ['auth_ids'] => non-associatative array of author IDs
|
|
*
|
|
* @return array array of arrays as per function description
|
|
*/
|
|
protected function get_week_cell_array( Ai1ec_Date_Time $start_of_week, $filter = array() ) {
|
|
$search = $this->_registry->get( 'model.search' );
|
|
$settings = $this->_registry->get( 'model.settings' );
|
|
$date_system = $this->_registry->get( 'date.system' );
|
|
$end_of_week = $this->_registry->get( 'date.time', $start_of_week );
|
|
$end_of_week->adjust_day( 7 );
|
|
// Do one SQL query to find all events for the week, including spanning
|
|
$week_events = $search->get_events_between(
|
|
$start_of_week,
|
|
$end_of_week,
|
|
$filter,
|
|
true
|
|
);
|
|
$this->_update_meta( $week_events );
|
|
// Split up events on a per-day basis
|
|
$all_events = array();
|
|
$this->_days_cache = $this->_registry->get( 'cache.memory' );
|
|
$this->_registry->get( 'controller.content-filter' )
|
|
->clear_the_content_filters();
|
|
foreach ( $week_events as $evt ) {
|
|
list( $evt_start, $evt_end ) = $this->
|
|
_get_view_specific_timestamps( $evt );
|
|
|
|
// Iterate through each day of the week and generate new event object
|
|
// based on this one for each day that it spans
|
|
for (
|
|
$day = $start_of_week->format( 'j' ),
|
|
$last_week_day_index = $start_of_week->format( 'j' ) + 7;
|
|
$day < $last_week_day_index;
|
|
$day++
|
|
) {
|
|
list( $day_start, $day_end ) = $this->
|
|
_get_wkday_start_end( $day, $start_of_week );
|
|
|
|
if ( $evt_end < $day_start ) {
|
|
break; // save cycles
|
|
}
|
|
|
|
// If event falls on this day, make a copy.
|
|
if ( $evt_end > $day_start && $evt_start < $day_end ) {
|
|
$_evt = clone $evt;
|
|
if ( $evt_start < $day_start ) {
|
|
// If event starts before this day, adjust copy's start time
|
|
$_evt->set( 'start', $day_start );
|
|
$_evt->set( 'start_truncated', true );
|
|
}
|
|
if ( $evt_end > $day_end ) {
|
|
// If event ends after this day, adjust copy's end time
|
|
$_evt->set( 'end', $day_end );
|
|
$_evt->set( 'end_truncated', true );
|
|
}
|
|
|
|
// Store reference to original, unmodified event, required by view.
|
|
$_evt->set( '_orig', $evt );
|
|
$this->_add_runtime_properties( $_evt );
|
|
|
|
// Place copy of event in appropriate category
|
|
if ( $_evt->is_allday() ) {
|
|
$all_events[$day_start]['allday'][] = $_evt;
|
|
} else {
|
|
$all_events[$day_start]['notallday'][] = $_evt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$this->_registry->get( 'controller.content-filter' )
|
|
->restore_the_content_filters();
|
|
// This will store the returned array
|
|
$days = array();
|
|
$now = $this->_registry->get(
|
|
'date.time',
|
|
'now',
|
|
$start_of_week->get_timezone()
|
|
);
|
|
// =========================================
|
|
// = Iterate through each date of the week =
|
|
// =========================================
|
|
for (
|
|
$day = $start_of_week->format( 'j' ),
|
|
$last_week_day_index = $start_of_week->format( 'j' ) + 7;
|
|
$day < $last_week_day_index;
|
|
$day++
|
|
) {
|
|
list( $day_date, , $day_date_ob ) = $this->
|
|
_get_wkday_start_end( $day, $start_of_week );
|
|
|
|
$exact_date = $date_system->format_datetime_for_url(
|
|
$day_date_ob,
|
|
$settings->get( 'input_date_format' )
|
|
);
|
|
$href_for_date = $this->_create_link_for_day_view( $exact_date );
|
|
|
|
// Initialize empty arrays for this day if no events to minimize warnings
|
|
if ( ! isset( $all_events[$day_date]['allday'] ) ) {
|
|
$all_events[$day_date]['allday'] = array();
|
|
}
|
|
if ( ! isset( $all_events[$day_date]['notallday'] ) ) {
|
|
$all_events[$day_date]['notallday'] = array();
|
|
}
|
|
|
|
$evt_stack = array( 0 ); // Stack to keep track of indentation
|
|
|
|
foreach ( $all_events[$day_date] as $event_type => &$events ) {
|
|
foreach ( $events as &$evt ) {
|
|
$event = array(
|
|
'filtered_title' => $evt->get_runtime( 'filtered_title' ),
|
|
'post_excerpt' => $evt->get_runtime( 'post_excerpt' ),
|
|
'color_style' => $evt->get_runtime( 'color_style' ),
|
|
'category_colors' => $evt->get_runtime( 'category_colors' ),
|
|
'permalink' => $evt->get_runtime( 'instance_permalink' ),
|
|
'ticket_url_label' => $evt->get_runtime( 'ticket_url_label' ),
|
|
'edit_post_link' => $evt->get_runtime( 'edit_post_link' ),
|
|
'faded_color' => $evt->get_runtime( 'faded_color' ),
|
|
'rgba_color' => $evt->get_runtime( 'rgba_color' ),
|
|
'short_start_time' => $evt->get_runtime( 'short_start_time' ),
|
|
'instance_id' => $evt->get( 'instance_id' ),
|
|
'post_id' => $evt->get( 'post_id' ),
|
|
'is_multiday' => $evt->get( 'is_multiday' ),
|
|
'venue' => $evt->get( 'venue' ),
|
|
'ticket_url' => $evt->get( 'ticket_url' ),
|
|
'start_truncated' => $evt->get( 'start_truncated' ),
|
|
'end_truncated' => $evt->get( 'end_truncated' ),
|
|
'popup_timespan' => $this->_registry
|
|
->get( 'twig.ai1ec-extension')->timespan( $evt, 'short' ),
|
|
'avatar_not_wrapped' => $evt->getavatar( false ),
|
|
'avatar' => $this->_registry
|
|
->get( 'twig.ai1ec-extension')->avatar(
|
|
$evt,
|
|
array(
|
|
'post_thumbnail',
|
|
'content_img',
|
|
'location_avatar',
|
|
'category_avatar',
|
|
),
|
|
'',
|
|
false ),
|
|
);
|
|
$meta = $this->_registry->get( 'model.meta-post' );
|
|
if ( ! $event['ticket_url'] ) {
|
|
$timely_tickets = $meta->get(
|
|
$evt->get( 'post_id' ),
|
|
'_ai1ec_timely_tickets_url',
|
|
null
|
|
);
|
|
if ( $timely_tickets ) {
|
|
$event['ticket_url'] = $timely_tickets;
|
|
$evt->set( 'ticket_url', $event['ticket_url'] );
|
|
}
|
|
}
|
|
if (
|
|
true === apply_filters(
|
|
'ai1ec_buy_button_product',
|
|
false
|
|
)
|
|
) {
|
|
$full_details = $meta->get(
|
|
$evt->get( 'post_id' ),
|
|
'_ai1ec_ep_product_details',
|
|
null
|
|
);
|
|
if (
|
|
is_array( $full_details ) &&
|
|
isset( $full_details['show_buy_button'] ) &&
|
|
true === $full_details['show_buy_button']
|
|
&& $event['ticket_url']
|
|
) {
|
|
// Tickets button is shown by default in this case.
|
|
} else {
|
|
// Otherwise not.
|
|
$event['ticket_url'] = false;
|
|
}
|
|
$evt->set( 'ticket_url', $event['ticket_url'] );
|
|
}
|
|
|
|
if (
|
|
$this->_compatibility->use_backward_compatibility()
|
|
) {
|
|
$event = $evt;
|
|
}
|
|
if ( 'notallday' === $event_type) {
|
|
$start = $evt->get( 'start' );
|
|
// Calculate top and bottom edges of current event
|
|
$top = $start->format( 'G' ) * 60 + $start->format( 'i' );
|
|
$bottom = min( $top + $evt->get_duration() / 60, 1440 );
|
|
// While there's more than one event in the stack and this event's top
|
|
// position is beyond the last event's bottom, pop the stack
|
|
while ( count( $evt_stack ) > 1 && $top >= end( $evt_stack ) ) {
|
|
array_pop( $evt_stack );
|
|
}
|
|
// Indentation is number of stacked events minus 1
|
|
$indent = count( $evt_stack ) - 1;
|
|
// Push this event onto the top of the stack
|
|
array_push( $evt_stack, $bottom );
|
|
$evt = array(
|
|
'top' => $top,
|
|
'height' => $bottom - $top,
|
|
'indent' => $indent,
|
|
'event' => $event,
|
|
);
|
|
} else {
|
|
$evt = $event;
|
|
}
|
|
}
|
|
}
|
|
|
|
$days[$day_date] = array(
|
|
'today' =>
|
|
$day_date_ob->format( 'Y' ) == $now->format( 'Y' ) &&
|
|
$day_date_ob->format( 'm' ) == $now->format( 'm' ) &&
|
|
$day_date_ob->format( 'j' ) == $now->format( 'j' ),
|
|
'allday' => $all_events[$day_date]['allday'],
|
|
'notallday' => $all_events[$day_date]['notallday'],
|
|
'href' => $href_for_date,
|
|
'day' => $this->_registry->
|
|
get( 'date.time', $day_date )->format_i18n( 'j' ),
|
|
'weekday' => $this->_registry->
|
|
get( 'date.time', $day_date )->format_i18n( 'D' ),
|
|
);
|
|
}
|
|
|
|
return apply_filters( 'ai1ec_get_week_cell_array', $days, $start_of_week, $filter );
|
|
}
|
|
|
|
/**
|
|
* get_week_start_day_offset function
|
|
*
|
|
* Returns the day offset of the first day of the week given a weekday in
|
|
* question.
|
|
*
|
|
* @param int $wday The weekday to get information about
|
|
* @return int A value between -6 and 0 indicating the week start
|
|
* day relative to the given weekday.
|
|
*/
|
|
protected function get_week_start_day_offset( $wday ) {
|
|
$settings = $this->_registry->get( 'model.settings' );
|
|
return - ( 7 - ( $settings->get( 'week_start_day' ) - $wday ) ) % 7;
|
|
}
|
|
|
|
/**
|
|
* Get start/end timestamps for a given weekday and week start identifier.
|
|
*
|
|
* @param int $day Week day number.
|
|
* @param Ai1ec_Date_Time $week_start Date/Time information for week start.
|
|
*
|
|
* @return array List of start and and timestamps, 0-indexed array.
|
|
*/
|
|
protected function _get_wkday_start_end(
|
|
$day,
|
|
Ai1ec_Date_Time $week_start
|
|
) {
|
|
$entry = null;
|
|
$day = (int)$day;
|
|
if ( null === ( $entry = $this->_days_cache->get( $day ) ) ) {
|
|
$day_start = $this->_registry
|
|
->get( 'date.time', $week_start )
|
|
->set_date(
|
|
$week_start->format( 'Y' ),
|
|
$week_start->format( 'm' ),
|
|
$day
|
|
)
|
|
->set_time( 0, 0, 0 );
|
|
$day_end = $this->_registry->get( 'date.time', $day_start );
|
|
$day_end->adjust_day( 1 );
|
|
$entry = array(
|
|
$day_start->format(),
|
|
$day_end->format(),
|
|
$day_start
|
|
);
|
|
unset( $day_end ); // discard and free memory
|
|
$this->_days_cache->set( $day, $entry );
|
|
}
|
|
return $entry;
|
|
}
|
|
|
|
}
|