Default_Calendar_List::scripts()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 14
nc 1
nop 1
dl 0
loc 20
rs 9.4285
c 1
b 0
f 0
1
<?php
2
/**
3
 * Default Calendar - List View
4
 *
5
 * @package SimpleCalendar/Calendars
6
 */
7
namespace SimpleCalendar\Calendars\Views;
8
9
use Carbon\Carbon;
10
use Mexitek\PHPColors\Color;
11
use SimpleCalendar\Abstracts\Calendar;
12
use SimpleCalendar\Abstracts\Calendar_View;
13
use SimpleCalendar\Calendars\Default_Calendar;
14
use SimpleCalendar\Events\Event;
15
16
if ( ! defined( 'ABSPATH' ) ) {
17
	exit;
18
}
19
20
/**
21
 * Default Calendar: List View.
22
 *
23
 * @since  3.0.0
24
 */
25
class Default_Calendar_List implements Calendar_View {
26
27
	/**
28
	 * Calendar.
29
	 *
30
	 * @access public
31
	 * @var Default_Calendar
32
	 */
33
	public $calendar = null;
34
35
	/**
36
	 * Current display start.
37
	 *
38
	 * @access private
39
	 * @var int
40
	 */
41
	private $start = 0;
42
43
	private $first_event = 0;
44
45
	private $last_event = 0;
46
47
	/**
48
	 * Current display end.
49
	 *
50
	 * @access private
51
	 * @var int
52
	 */
53
	private $end = 0;
54
55
	/**
56
	 * Previous display start.
57
	 *
58
	 * @access private
59
	 * @var int
60
	 */
61
	private $prev = 0;
62
63
	/**
64
	 * Next display start.
65
	 *
66
	 * @access private
67
	 * @var int
68
	 */
69
	private $next = 0;
70
71
	/**
72
	 * Constructor.
73
	 *
74
	 * @since 3.0.0
75
	 *
76
	 * @param string|Calendar $calendar
77
	 */
78
	public function __construct( $calendar = '' ) {
79
		$this->calendar = $calendar;
0 ignored issues
show
Documentation Bug introduced by
It seems like $calendar of type string or object<SimpleCalendar\Abstracts\Calendar> is incompatible with the declared type object<SimpleCalendar\Calendars\Default_Calendar> of property $calendar.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
80
	}
81
82
	/**
83
	 * Get the view parent calendar type.
84
	 *
85
	 * @since  3.0.0
86
	 *
87
	 * @return string
88
	 */
89
	public function get_parent() {
90
		return 'default-calendar';
91
	}
92
93
	/**
94
	 * Get the view type.
95
	 *
96
	 * @since  3.0.0
97
	 *
98
	 * @return string
99
	 */
100
	public function get_type() {
101
		return 'list';
102
	}
103
104
	/**
105
	 * Get the view name.
106
	 *
107
	 * @since  3.0.0
108
	 *
109
	 * @return string
110
	 */
111
	public function get_name() {
112
		return __( 'List', 'google-calendar-events' );
113
	}
114
115
	/**
116
	 * Add ajax actions.
117
	 *
118
	 * @since 3.0.0
119
	 */
120
	public function add_ajax_actions() {
121
		add_action( 'wp_ajax_simcal_default_calendar_draw_list', array( $this, 'draw_list_ajax' ) );
122
		add_action( 'wp_ajax_nopriv_simcal_default_calendar_draw_list', array( $this, 'draw_list_ajax' ) );
123
	}
124
125
	/**
126
	 * Default calendar list scripts.
127
	 *
128
	 * Scripts to load when this view is displayed.
129
	 *
130
	 * @since  3.0.0
131
	 *
132
	 * @param  string $min
133
	 *
134
	 * @return array
135
	 */
136
	public function scripts( $min = '' ) {
137
		return array(
138
			'simcal-qtip' => array(
139
				'src'       => SIMPLE_CALENDAR_ASSETS . 'js/vendor/qtip' . $min . '.js',
140
				'deps'      => array( 'jquery' ),
141
				'in_footer' => true,
142
			),
143
			'simcal-default-calendar' => array(
144
				'src'       => SIMPLE_CALENDAR_ASSETS . 'js/default-calendar' . $min . '.js',
145
				'deps'      => array(
146
					'jquery',
147
					'simcal-qtip',
148
				),
149
				'in_footer' => true,
150
				'localize'  => array(
151
					'simcal_default_calendar' => simcal_common_scripts_variables(),
152
				),
153
			),
154
		);
155
	}
156
157
	/**
158
	 * Default calendar list styles.
159
	 *
160
	 * Stylesheets to load when this view is displayed.
161
	 *
162
	 * @since  3.0.0
163
	 *
164
	 * @param  string $min = ''
165
	 *
166
	 * @return array
167
	 */
168
	public function styles( $min = '' ) {
169
		return array(
170
			'simcal-default-calendar-list' => array(
171
				'src'   => SIMPLE_CALENDAR_ASSETS . 'css/default-calendar-list' . $min . '.css',
172
				'media' => 'all',
173
			),
174
		);
175
	}
176
177
	/**
178
	 * Default calendar list markup.
179
	 *
180
	 * @since 3.0.0
181
	 */
182
	public function html() {
183
184
		$calendar = $this->calendar;
185
186
		if ( $calendar instanceof Default_Calendar ) {
187
188
			$disabled = $calendar->static === true || empty( $calendar->events ) ? ' disabled="disabled"' : '';
189
190
191
			$hide_header = get_post_meta( $this->calendar->id, '_default_calendar_list_header', true ) == 'yes' ? true : false;
192
			$static_calendar = get_post_meta( $this->calendar->id, '_calendar_is_static', true ) == 'yes' ? true : false;
193
194
			$header_class = '';
195
			$compact_list_class = $calendar->compact_list ? 'simcal-calendar-list-compact' : '';
196
197
			edit_post_link( __( 'Edit Calendar', 'google-calendar-events' ), '<p class="simcal-align-right"><small>', '</small></p>', $calendar->id );
198
199
			echo '<div class="simcal-calendar-list ' . $compact_list_class . '">';
200
201
			if ( ! $hide_header && ! $static_calendar ) {
202
				echo '<nav class="simcal-calendar-head">' . "\n";
203
204
				echo "\t" . '<div class="simcal-nav">' . "\n";
205
				echo "\t\t" . '<button class="simcal-nav-button simcal-prev" title="' . __('Previous', 'google-calendar-events') . '"' . $disabled . '>' . "\n";
206
				echo "\t\t\t" . '<i class="simcal-icon-left"></i>' . "\n";
207
				echo "\t\t" . '</button>' . "\n";
208
				echo "\t" . '</div>' . "\n";
209
210
				if ( $hide_header ) {
211
					$header_class = 'simcal-hide-header';
212
				}
213
214
215
				echo "\t" . '<div class="simcal-nav simcal-current ' . $header_class . '" data-calendar-current="' . $calendar->start . '">' . "\n";
216
				echo "\t\t" . '<h3 class="simcal-current-label"> </h3>' . "\n";
217
				echo "\t" . '</div>' . "\n";
218
219
				echo "\t" . '<div class="simcal-nav">';
220
				echo "\t\t" . '<button class="simcal-nav-button simcal-next" title="' . __('Next', 'google-calendar-events') . '"' . $disabled . '>';
221
				echo "\t\t\t" . '<i class="simcal-icon-right"></i>' . "\n";
222
				echo "\t\t" . '</button>' . "\n";
223
				echo "\t" . '</div>' . "\n";
224
225
				echo '</nav>' . "\n";
226
			}
227
228
			echo $this->draw_list( $calendar->start );
229
230
			echo '<div class="simcal-ajax-loader simcal-spinner-top" style="display: none;"><i class="simcal-icon-spinner simcal-icon-spin"></i></div>';
231
232
			echo '</div>';
233
234
		}
235
236
	}
237
238
	/**
239
	 * Get events for current display.
240
	 *
241
	 * @since  3.0.0
242
	 * @access private
243
	 *
244
	 * @param  int $timestamp
245
	 *
246
	 * @return array
247
	 */
248
	private function get_events( $timestamp ) {
249
250
		$calendar = $this->calendar;
251
252
		if ( ! $calendar->group_type || ! $calendar->group_span ) {
253
			return array();
254
		}
255
256
		// Need to pass in timezone here to get beginning of day.
257
		$current = Carbon::createFromTimestamp( $timestamp, $calendar->timezone );
258
		$prev = clone $current;
259
		$next = clone $current;
260
261
		$this->start = $timestamp;
262
263
		$interval = $span = max( absint( $calendar->group_span ), 1 );
264
265
		if ( 'monthly' == $calendar->group_type ) {
266
			$this->prev = $prev->subMonths( $span )->getTimestamp();
267
			$this->next = $next->addMonths( $span )->getTimestamp();
268
		} elseif ( 'weekly' == $calendar->group_type ) {
269
			$week = new Carbon( $calendar->timezone );
270
			$week->setTimestamp( $timestamp );
271
			$week->setWeekStartsAt( $calendar->week_starts );
272
			$this->prev = $prev->subWeeks( $span )->getTimestamp();
273
			$this->next = $next->addWeeks( $span )->getTimestamp();
274
		} elseif ( 'daily' == $calendar->group_type ) {
275
			$this->prev = $prev->subDays( $span )->getTimestamp();
276
			$this->next = $next->addDays( $span )->getTimestamp();
277
		}
278
279
		$events = $calendar->events;
280
		$daily_events = $paged_events = $flattened_events = array();
281
282
		if ( 'events' != $calendar->group_type ) {
283
284
			$this->end   = $this->next - 1;
285
286
			$timestamps   = array_keys( $events );
287
			$lower_bound  = array_filter( $timestamps,  array( $this, 'filter_events_before' ) );
288
			$higher_bound = array_filter( $lower_bound, array( $this, 'filter_events_after'  ) );
289
290
			if ( is_array( $higher_bound ) && !empty( $higher_bound ) ) {
291
				$filtered = array_intersect_key( $events, array_combine( $higher_bound, $higher_bound ) );
292
				foreach ( $filtered as $timestamp => $events ) {
293
					$paged_events[ intval( $timestamp ) ] = $events;
294
				}
295
			}
296
297
		} else {
298
299
			foreach ( $events as $timestamp => $e ) {
300
				$second = 0;
301
				foreach ( $e as $event ) {
302
					$flattened_events[ intval( $timestamp + $second ) ][] = $event;
303
					$second++;
304
				}
305
			}
306
307
			ksort( $flattened_events, SORT_NUMERIC );
308
309
			$keys  = array_keys( $flattened_events );
310
			$current = 0;
311
			foreach ( $keys as $timestamp ) {
312
				if ( $timestamp < $this->start ) {
313
					$current++;
314
				}
315
			}
316
317
			$paged_events = array_slice( $flattened_events, $current, $interval, true );
318
319
			$events_end = isset( $keys[ $current + $interval ] ) ? $keys[ $current + $interval ] : $calendar->end;
320
			$this->end  = $events_end > $calendar->end ? $calendar->end : $events_end;
0 ignored issues
show
Documentation Bug introduced by
It seems like $events_end > $calendar-...ndar->end : $events_end can also be of type string. However, the property $end is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
321
322
			$this->prev = isset( $keys[ $current - $interval ] ) ? $keys[ $current - $interval ] : $calendar->earliest_event;
0 ignored issues
show
Documentation Bug introduced by
It seems like isset($keys[$current - $...alendar->earliest_event can also be of type string. However, the property $prev is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
323
			$this->next = isset( $keys[ $current + $interval ] ) ? $keys[ $current + $interval ] : $this->end;
0 ignored issues
show
Documentation Bug introduced by
It seems like isset($keys[$current + $...$interval] : $this->end can also be of type string. However, the property $next is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
324
325
		}
326
327
		// Put resulting events in an associative array, with Ymd date as key for easy retrieval in calendar days loop.
328
329
		foreach ( $paged_events as $timestamp => $events ) {
330
331
			// TODO First $paged_events item timestamp 1 second off? Plus or minus?
332
333
			if ( $timestamp <= $this->end ) {
334
335
				// TODO Could go back to using Carbon to be consistent.
336
				// $date is off by a couple hours for dates in multi-day event, but not for first event.
337
				// But only certain timezones? UTC-1, UTC+1, UTC+2, UTC+3 ???
338
				// Offset changes after first day with these timezones only. Why?
339
				// November 1, 2016 is daylight savings for them!!!
340
341
				/*
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
342
				$date = Carbon::createFromTimestamp( $timestamp, $calendar->timezone );
343
344
				// Add date offset back in?
345
				// $date = Carbon::createFromTimestamp( $timestamp + $date->offset, $calendar->timezone );
346
347
				$dateYmd = $date->copy()->endOfDay()->format( 'Ymd' );
348
				*/
349
350
				// Using native PHP 5.3+ (not Carbon) here.
351
				// Offset value after first day same behavior as Carbon above still.
352
				$dtz = new \DateTimeZone( $calendar->timezone );
353
354
				$date = \DateTime::createFromFormat( 'U', $timestamp );
355
356
				// Doesn't seem to make a difference omitting timezone.
357
				//$date = \DateTime::createFromFormat( 'U', $timestamp, $dtz );
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
358
359
				// Add offset to timestamp to get correct date.
360
				// TODO Need to add +1 second also?
361
				$offset = $dtz->getOffset( $date );
362
				$date_offset = clone $date;
363
				$date_offset->add( \DateInterval::createFromDateString( $offset . ' seconds' ) );
364
365
				// TODO Multiple day events will be off if part-way through there's daylight savings.
366
367
				$dateYmd = $date_offset->format( 'Ymd' );
368
				$daily_events[ intval( $dateYmd ) ][] = $events;
369
			}
370
		}
371
372
		ksort( $daily_events, SORT_NUMERIC );
373
374
		if ( ! empty( $paged_events ) ) {
375
			$first_event       = array_slice( $paged_events, 0, 1, true );
376
			$first_event       = array_pop( $first_event );
377
			$this->first_event = $first_event[0]->start;
378
379
			$last_event       = array_pop( $paged_events );
380
			$this->last_event = $last_event[0]->start;
381
		}
382
383
		return $daily_events;
384
	}
385
386
	/**
387
	 * Get calendar list heading.
388
	 *
389
	 * Parses calender date format and adapts to current display range.
390
	 *
391
	 * @since  3.0.0
392
	 * @access private
393
	 *
394
	 * @return array
395
	 */
396
	private function get_heading() {
397
398
		$calendar = $this->calendar;
399
		$start = Carbon::createFromTimestamp( $calendar->start, $calendar->timezone );
400
		$end = Carbon::createFromTimestamp( $this->end, $calendar->timezone );
401
		$date_format = $this->calendar->date_format;
402
		$date_order  = simcal_get_date_format_order( $date_format );
403
404
		if ( $this->first_event !== 0 ) {
405
			$start = Carbon::createFromTimestamp( $this->first_event, $calendar->timezone );
406
		}
407
408
		if ( $this->last_event !== 0 ) {
409
			$end = Carbon::createFromTimestamp( $this->last_event, $calendar->timezone );
410
		}
411
412
		$st = strtotime( $start->toDateTimeString() );
413
		$et = strtotime( $end->toDateTimeString() );
414
415
		// TODO Is logic here causing the weird "29 Oct, 2016" format when navigating?
416
417
		if ( ( $start->day == $end->day ) && ( $start->month == $end->month ) && ( $start->year == $end->year ) ) {
418
			// Start and end on the same day.
419
			// e.g. 1 February 2020
420
			$large = $small = date_i18n( $calendar->date_format , $st );
421
			if ( ( $date_order['d'] !== false ) && ( $date_order['m'] !== false ) ) {
422
				if ( $date_order['m'] > $date_order['d'] ) {
423 View Code Duplication
					if ( $date_order['y'] !== false && $date_order['y'] > $date_order['m'] ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
424
						$small = date_i18n( 'Y, d M', $st );
425
					} else {
426
						$small = date_i18n( 'd M Y', $st );
427
					}
428 View Code Duplication
				} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
429
					if ( $date_order['y'] !== false && $date_order['y'] > $date_order['m'] ) {
430
						$small = date_i18n( 'Y, M d', $st );
431
					} else {
432
						$small = date_i18n( 'M d Y', $st );
433
					}
434
				}
435
			}
436
		} elseif ( ( $start->month == $end->month ) && ( $start->year == $end->year ) ) {
437
			// Start and end days on the same month.
438
			// e.g. August 2020
439
			if ( $date_order['y'] === false ) {
440
				// August.
441
				$large = $small = date_i18n( 'F', $st );
442
			} else {
443
				if ( $date_order['y'] < $date_order['m'] ) {
444
					// 2020 August.
445
					$large = date_i18n( 'Y F', $st );
446
					$small = date_i18n( 'Y M', $st );
447
				} else {
448
					// August 2020.
449
					$large = date_i18n( 'F Y', $st );
450
					$small = date_i18n( 'M Y', $st );
451
				}
452
			}
453
		} elseif ( $start->year == $end->year ) {
454
			// Start and end days on months of the same year.
455
			// e.g. August - September 2020
456
			if ( $date_order['y'] === false ) {
457
				// August - September.
458
				$large = date_i18n( 'F', $st ) . ' - ' . date_i18n( 'F', $et );
459
				$small = date_i18n( 'M', $st ) . ' - ' . date_i18n( 'M', $et );
460
			} else {
461
				if ( $date_order['y'] < $date_order['m'] ) {
462
					// 2020, August - September.
463
					$large  = $small = date( 'Y', $st ) . ', ';
464
					$large .= date_i18n( 'F', $st ) . ' - ' . date_i18n( 'F', $et );
465
					$small .= date_i18n( 'M', $st ) . ' - ' . date_i18n( 'M', $et );
466
				} else {
467
					// August - September, 2020.
468
					$large  = date_i18n( 'F', $st ) . ' - ' . date_i18n( 'F', $et ) . ', ';
469
					$small  = date_i18n( 'M', $st ) . ' - ' . date_i18n( 'M', $et ) . ' ';
470
					$year   = date( 'Y', $st );
471
					$large .= $year;
472
					$small .= $year;
473
				}
474
			}
475
		} else {
476
			$large = $small = date( 'Y', $st ) . ' - ' . date( 'Y', $et );
477
		}
478
479
		return array(
480
			'small' => $small,
481
			'large' => $large,
482
		);
483
	}
484
485
	/**
486
	 * Make a calendar list of events.
487
	 *
488
	 * Outputs a list of events according to events for the specified range.
489
	 *
490
	 * @since  3.0.0
491
	 * @access private
492
	 *
493
	 * @param  int $timestamp
494
	 * @param  int $id
495
	 *
496
	 * @return string
497
	 */
498
	private function draw_list( $timestamp, $id = 0 ) {
499
500
		$calendar = $this->calendar;
501
502
		if ( empty( $calendar ) ) {
503
			$calendar = $this->calendar = simcal_get_calendar( intval( $id ) );
504
			if ( ! $calendar instanceof Default_Calendar ) {
505
				return '';
506
			}
507
		}
508
509
		$now = $calendar->now;
510
		$current_events = $this->get_events( $timestamp );
511
		$format = $calendar->date_format;
512
513
		ob_start();
514
515
		// Draw the events.
516
517
		$block_tag = $calendar->compact_list && ! empty( $current_events ) ? 'div' : 'dl';
518
519
		$data_heading = '';
520
		$heading = $this->get_heading();
521
		foreach ( $heading as $k => $v ) {
522
			$data_heading .= ' data-heading-' . $k . '="' . $v . '"';
523
		}
524
525
		echo '<' . $block_tag . ' class="simcal-events-list-container"' .
526
			' data-prev="' . $this->prev . '"' .
527
			' data-next="' . $this->next . '"' .
528
			$data_heading . '>';
529
530
		if ( ! empty( $current_events ) && is_array( $current_events ) ) :
531
532
			$last_event = null;
533
534
			foreach ( $current_events as $ymd => $events ) :
535
536
				// This is where we can find out if an event is a multi-day event and if it needs to be shown.
537
				// Since this is for list view we are showing the event on the day viewed if it is part of that day even when
538
				// expand multi-day events are turned off.
539
540
				$first_event = $events[0][0];
541
542
				if ( isset( $first_event->multiple_days ) && $first_event->multiple_days > 0 ) {
543
544
					if ( 'current_day_only' == get_post_meta( $calendar->id, '_default_calendar_expand_multi_day_events', true ) ) {
545
546
						$year  = substr( $ymd, 0, 4 );
547
						$month = substr( $ymd, 4, 2 );
548
						$day   = substr( $ymd, 6, 2 );
549
550
						$temp_date = Carbon::createFromDate( $year, $month, $day );
551
552
						if ( ! ( $temp_date < Carbon::now()->endOfDay() ) ) {
553
554
							// Break here only if event already shown once.
555
							if ( $last_event == $first_event ) {
556
								continue;
557
							} else {
558
								// Save event as "last" for next time through, then break.
559
								$last_event = $first_event;
560
							}
561
						}
562
					}
563
				}
564
565
				// Add offset offset for list view day headings.
566
				$day_date = Carbon::createFromFormat( 'Ymd', $ymd, $calendar->timezone );
567
				$day_date_offset = clone $day_date;
568
				$day_date_offset->addSeconds( $day_date->offset );
569
				$day_date_ts_offset = $day_date_offset->timestamp;
570
571
				if ( ! $calendar->compact_list ) {
572
					if ( $day_date_offset->isToday() ) {
573
						$the_color = new Color( $calendar->today_color );
574
					} else {
575
						$the_color = new Color( $calendar->days_events_color );
576
					}
577
578
					$bg_color     = '#' . $the_color->getHex();
579
					$color        = $the_color->isDark() ? '#ffffff' : '#000000';
580
					$border_style = ' style="border-bottom: 1px solid ' . $bg_color . ';" ';
581
					$bg_style     = ' style="background-color: ' . $bg_color . '; color: ' . $color . ';"';
582
583
					echo "\t" . '<dt class="simcal-day-label"' . $border_style . '>';
584
					echo '<span' . $bg_style . '>';
585
586
					echo $format ? '<span class="simcal-date-format" data-date-format="' . $format . '">' . date_i18n( $format, $day_date_ts_offset, strtotime( $day_date_offset->toDateTimeString() ) ) . '</span> ' : ' ';
587
588
					echo '</span>';
589
					echo '</dt>' . "\n";
590
				}
591
592
				$list_events = '<ul class="simcal-events">' . "\n";
593
594
				$calendar_classes = array();
595
596
				// Add day of week number to CSS class.
597
				$day_classes = 'simcal-weekday-' . date( 'w', $day_date_ts_offset );
598
599
				// Is this the present, the past or the future, Doc?
600
				if ( $timestamp <= $now && $timestamp >= $now ) {
601
					$day_classes .= ' simcal-today simcal-present simcal-day';
602
				} elseif ( $timestamp < $now ) {
603
					$day_classes .= ' simcal-past simcal-day';
604
				} elseif ( $this->end > $now ) {
605
					$day_classes .= ' simcal-future simcal-day';
606
				}
607
608
				$count = 0;
609
610
				foreach ( $events as $day_events ) :
611
					foreach ( $day_events as $event ) :
612
613
						if ( $event instanceof Event ) :
614
615
							$event_classes = $event_visibility = '';
616
617
							$calendar_class     = 'simcal-events-calendar-' . strval( $event->calendar );
618
							$calendar_classes[] = $calendar_class;
619
620
							$recurring     = $event->recurrence ? 'simcal-event-recurring ' : '';
621
							$has_location  = $event->venue ? 'simcal-event-has-location ' : '';
622
623
							$event_classes .= 'simcal-event ' . $recurring . $has_location . $calendar_class;
624
625
							// Toggle some events visibility if more than optional limit.
626 View Code Duplication
							if ( ( $calendar->events_limit > - 1 ) && ( $count >= $calendar->events_limit ) ) :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
627
								$event_classes .= ' simcal-event-toggled';
628
								$event_visibility = ' style="display: none"';
629
							endif;
630
631
							$event_color = $event->get_color();
632
							if ( ! empty( $event_color ) ) {
633
								$side = is_rtl() ? 'right' : 'left';
634
								$event_color = ' style="border-' . $side . ': 4px solid ' . $event_color . '; padding-' . $side . ': 8px;"';
635
							}
636
637
							$list_events .= "\t" . '<li class="' . $event_classes . '"' . $event_visibility . $event_color . ' itemscope itemtype="http://schema.org/Event" data-start="' . esc_attr( $event->start ) . '">' . "\n";
638
							$list_events .= "\t\t" . '<div class="simcal-event-details">' . $calendar->get_event_html( $event ) . '</div>' . "\n";
639
							$list_events .= "\t" . '</li>' . "\n";
640
641
							$count ++;
642
643
							// Event falls within today.
644
							if ( ( $this->end <= $now ) && ( $this->start >= $now ) ) :
645
								$day_classes .= ' simcal-today-has-events';
646
							endif;
647
							$day_classes .= ' simcal-day-has-events simcal-day-has-' . strval( $count ) . '-events';
648
649
							if ( $calendar_classes ) :
0 ignored issues
show
Bug Best Practice introduced by
The expression $calendar_classes of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
650
								$day_classes .= ' ' . trim( implode( ' ', array_unique( $calendar_classes ) ) );
651
							endif;
652
653
						endif;
654
					endforeach;
655
				endforeach;
656
657
				$list_events .= '</ul>' . "\n";
658
659
				// If events visibility is limited, print the button toggle.
660
				if ( ( $calendar->events_limit > -1 ) && ( $count > $calendar->events_limit ) ) :
661
					$list_events .= '<button class="simcal-events-toggle"><i class="simcal-icon-down simcal-icon-animate"></i></button>';
662
				endif;
663
664
				// Print final list of events for the current day.
665
				$tag = $calendar->compact_list ? 'div' : 'dd';
666
				echo '<'  . $tag . ' class="' . $day_classes . '" data-events-count="' . strval( $count ) . '">' . "\n";
667
				echo "\t" . $list_events . "\n";
668
				echo '</' . $tag . '>' . "\n";
669
670
			endforeach;
671
672
		else :
673
674
			echo "\t" . '<p>';
675
676
			$message = get_post_meta( $calendar->id, '_no_events_message', true );
677
678
			if ( 'events' == $calendar->group_type ) {
679
				echo ! empty( $message ) ? $message : __( 'There are no upcoming events.', 'google-calendar-events' );
680
			} else {
681
				if ( ! empty( $message ) ) {
682
					echo $message;
683
				} else {
684
					$from = Carbon::createFromTimestamp( $this->start, $calendar->timezone )->getTimestamp();
685
					$to = Carbon::createFromTimestamp( $this->end, $calendar->timezone )->getTimestamp();
686
					echo apply_filters( 'simcal_no_events_message', sprintf(
687
						__( 'Nothing from %1$s to %2$s.', 'google-calendar-events' ),
688
						date_i18n( $calendar->date_format, $from ),
689
						date_i18n( $calendar->date_format, $to )
690
					), $calendar->id, $from, $to );
691
				}
692
			}
693
694
			echo "\t" . '</p>' . "\n";
695
696
		endif;
697
698
		echo '</' . $block_tag . '>';
699
700
		return ob_get_clean();
701
	}
702
703
	/**
704
	 * Ajax callback to request a new page.
705
	 *
706
	 * @since 3.0.0
707
	 */
708
	public function draw_list_ajax() {
0 ignored issues
show
Coding Style introduced by
draw_list_ajax uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
709
710
		if ( isset( $_POST['ts'] ) && isset( $_POST['id'] ) ) {
711
712
			$ts = absint( $_POST['ts'] );
713
			$id = absint( $_POST['id'] );
714
715
			wp_send_json_success( $this->draw_list( $ts, $id ) );
716
717
		} else {
718
719
			wp_send_json_error( 'Missing arguments in default calendar list ajax request.' );
720
721
		}
722
	}
723
724
	/**
725
	 * Array filter callback.
726
	 *
727
	 * @since  3.0.0
728
	 * @access private
729
	 *
730
	 * @param  int $event Timestamp.
731
	 *
732
	 * @return bool
733
	 */
734
	private function filter_events_before( $event ) {
735
		return intval( $event ) >= intval( $this->start );
736
	}
737
738
	/**
739
	 * Array filter callback.
740
	 *
741
	 * @since  3.0.0
742
	 * @access private
743
	 *
744
	 * @param  int $event Timestamp.
745
	 *
746
	 * @return bool
747
	 */
748
	private function filter_events_after( $event ) {
749
		return intval( $event ) < intval( $this->end );
750
	}
751
752
}
753