Version 4.1.2

This commit is contained in:
Neo committed 2025-12-19 05:32:19 -08:00
1 parent 3ba79295ee
commit 28bd025b35
1131 files changed
+63658 -20579

No files matched your search

+12 -12
View File
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<emails><template><template_app>calendar</template_app><template_name>digests__item</template_name><template_content_html><![CDATA[<tr style='border-bottom: 1px solid #eeeeee'>
<td width='120' valign='top' align='center'>
<td dir='{dir}' width='120' valign='top' align='center'>
<table width='120' cellpadding='10' cellspacing='0' border='0' bgcolor='#fafafa'>
<tr>
<td>
<td dir='{dir}'>
<table width='100' cellpadding='0' cellspacing='0' border='0' bgcolor='#ffffff' style='border: 1px solid #cccccc;'>
<tr>
<td align='center' style="color: #a93848; font-size: 18px; line-height: 30px; text-transform: uppercase; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: bold; padding-top: 5px;">
<td dir='{dir}' align='center' style="color: #a93848; font-size: 18px; line-height: 30px; text-transform: uppercase; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: bold; padding-top: 5px;">
{$event->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' )->monthNameShort}
</td>
</tr>
<tr>
<td align='center' style="color: #333333; line-height: 40px; font-size: 44px; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: 300; padding-bottom: 10px">
<td dir='{dir}' align='center' style="color: #333333; line-height: 40px; font-size: 44px; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: 300; padding-bottom: 10px">
{$event->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' )->mday}
</td>
</tr>
@@ -20,7 +20,7 @@
</tr>
</table>
</td>
<td align='left'>
<td dir='{dir}' align='left'>
<p style='font-family: "Helvetica Neue", helvetica, sans-serif; margin: 0; font-size: 13px; font-weight: bold'>
{$email->language->addToStack("x_created_event_in", FALSE, array( 'sprintf' => array( $event->author()->name, $event->container()->_title ) ) )}
</p>
@@ -44,7 +44,7 @@
{{if $event->rsvp}}
<div style="font-size: 13px; font-family: 'Helvetica Neue', helvetica, sans-serif; margin-top: 10px">
{{if $attendees = $row->attendees()}}{{endif}}
{{if $attendees = $event->attendees()}}{{endif}}
<strong style="text-transform: uppercase; font-size: 12px; font-family: 'Helvetica Neue', helvetica, sans-serif;">{$email->language->addToStack("digest_users_going", FALSE, array( 'pluralize' => array( count( $attendees[1] ) ) ) )}</strong>
{{if count( $attendees[1] )}}
{{foreach $attendees[1] as $idx => $attendee}}
@@ -74,18 +74,18 @@
</td>
</tr>]]></template_content_html><template_data>$event, $email</template_data><template_content_plaintext><![CDATA[{$email->language->addToStack("x_created_event_in", FALSE, array( 'sprintf' => array( $event->author()->name, $event->container()->_title ) ) )}: {$event->title} ({$event->url()})
]]></template_content_plaintext></template><template><template_app>calendar</template_app><template_name>digests__comment</template_name><template_content_html><![CDATA[<tr style='border-bottom: 1px solid #eeeeee'>
<td width='120' valign='top' align='center'>
<td dir='{dir}' width='120' valign='top' align='center'>
<table width='120' cellpadding='10' cellspacing='0' border='0' bgcolor='#fafafa'>
<tr>
<td>
<td dir='{dir}'>
<table width='100' cellpadding='0' cellspacing='0' border='0' bgcolor='#ffffff' style='border: 1px solid #cccccc;'>
<tr>
<td align='center' style="color: #a93848; font-size: 18px; line-height: 30px; text-transform: uppercase; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: bold; padding-top: 5px;">
<td dir='{dir}' align='center' style="color: #a93848; font-size: 18px; line-height: 30px; text-transform: uppercase; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: bold; padding-top: 5px;">
{$comment->item()->nextOccurrence( $today, 'startDate' )->monthNameShort}
</td>
</tr>
<tr>
<td align='center' style="color: #333333; line-height: 40px; font-size: 44px; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: 300; padding-bottom: 10px">
<td dir='{dir}' align='center' style="color: #333333; line-height: 40px; font-size: 44px; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: 300; padding-bottom: 10px">
{$comment->item()->nextOccurrence( $today, 'startDate' )->mday}
</td>
</tr>
@@ -94,7 +94,7 @@
</tr>
</table>
</td>
<td align='left'>
<td dir='{dir}' align='left'>
<p style='font-family: "Helvetica Neue", helvetica, sans-serif; margin: 0; font-size: 13px; font-weight: bold'>
{$email->language->addToStack("x_commented_event", FALSE, array( 'sprintf' => array( $comment->author()->name ) ) )}
</p>
@@ -102,7 +102,7 @@
<a href='{$comment->item()->url()}' style='text-decoration: none;'>{$comment->item()->name}</a>
</h2>
<p style='font-family: "Helvetica Neue", helvetica, sans-serif; margin: 0; color: #8c8c8c; font-size: 13px;'>
{$email->language->addToStack("email_event_on", FALSE)} {$comment->item()->_start_date->dayName} {$comment->item()->_start_date->mday} {$comment->item()->_start_date->monthName} {$comment->item()->_start_date->year}{{if !$comment->item()->all_day}}, {$comment->item()->_start_date->localeTime( FALSE )}{{endif}}
{$email->language->addToStack("digest_event_on", FALSE)} {$comment->item()->_start_date->dayName} {$comment->item()->_start_date->mday} {$comment->item()->_start_date->monthName} {$comment->item()->_start_date->year}{{if !$comment->item()->all_day}}, {$comment->item()->_start_date->localeTime( FALSE )}{{endif}}
{{if $comment->item()->_end_date}}
&nbsp;&nbsp;&raquo;&nbsp;&nbsp;
{$comment->item()->_end_date->dayName} {$comment->item()->_end_date->mday} {$comment->item()->_end_date->monthName} {$comment->item()->_end_date->year}{{if !$comment->item()->all_day}}, {$comment->item()->_end_date->localeTime( FALSE )}{{endif}}
+14 -8
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<javascript app="calendar">
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.main.js" javascript_type="controller" javascript_version="100045" javascript_position="1000050"><![CDATA[/**
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.main.js" javascript_type="controller" javascript_version="101012" javascript_position="1000050"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -109,7 +109,7 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.monthView.js" javascript_type="controller" javascript_version="100045" javascript_position="1000050"><![CDATA[/**
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.monthView.js" javascript_type="controller" javascript_version="101012" javascript_position="1000050"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -251,7 +251,7 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/submit" javascript_name="ips.submit.dates.js" javascript_type="controller" javascript_version="100045" javascript_position="1000100"><![CDATA[/**
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/submit" javascript_name="ips.submit.dates.js" javascript_type="controller" javascript_version="101012" javascript_position="1000100"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -451,10 +451,17 @@
*/
_getDate: function(input) {
/* jQuery UI Polyfill needs to be changed into the correct format */
if ( input.hasClass('hasDatepicker') ) {
if( !ips.utils.time.supportsHTMLDate() ) {
/* If it has been initiated, we can use the getDate method */
try {
return input.datepicker( "getDate" );
var thisDate = input.datepicker( "getDate" );
if( _.isNull( thisDate ) )
{
thisDate = new Date( input.attr('value') );
}
return thisDate;
}
/* If it hasn't we can pull the 'value' attribute which can't have been changed yet. Not .val() as that will be in the wrong format */
catch(err) {
@@ -484,7 +491,7 @@
}
// We need to add the offset to ensure the day stays correct
if ( this.scope.find( 'input[name="event_dates[start_date]"]' ).hasClass('hasDatepicker') ) {
if( !ips.utils.time.supportsHTMLDate() ){
startDate.setTime( startDate.getTime() - new Date().getTimezoneOffset()*60000 );
}
@@ -497,8 +504,7 @@
// If we have a valid end date...
if( !singleDay.is(':checked') && ips.utils.time.isValidDateObj( endDate ) ){
if ( this.scope.find('input[name="event_dates[end_date]"]' ).hasClass( 'hasDatepicker' ) )
{
if( !ips.utils.time.supportsHTMLDate() ){
endDate.setTime( endDate.getTime() - new Date().getTimezoneOffset()*60000 );
}
endDateString = ips.utils.time.localeDateString( endDate, { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric', timeZone: 'UTC' } );
+4 -1
View File
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<language>
<app key="calendar" version="100045">
<app key="calendar" version="101012">
<word key="__app_calendar" js="0">Calendar</word>
<word key="frontnavigation_calendar" js="0">Calendar</word>
<word key="__indefart_calendar_event_comment" js="0">a comment on a calendar event</word>
<word key="__indefart_calendar_event" js="0">a calendar event</word>
<word key="__indefart_calendar_event_review" js="0">a review on a calendar event</word>
<word key="calendar_event_container" js="0">calendar</word>
<word key="menu__calendar_calendars" js="0">Calendar</word>
<word key="menu__calendar_calendars_calendars" js="0">Calendars</word>
<word key="menu__calendar_calendars_ical" js="0">iCalendar Feeds</word>
@@ -322,6 +323,7 @@
<word key="no_recent_reviews" js="0">No recent reviews found</word>
<word key="announce_calendars" js="0">Calendars</word>
<word key="review_count" js="0">Number of reviews to show</word>
<word key="widget_calendar" js="0">Calendar</word>
<word key="embed_calendar_event" js="0">Calendar Event</word>
<word key="x_users_going" js="0">{# [1:user][?:users]} going</word>
<word key="timezone_offset_short" js="0">GMT %s</word>
@@ -366,6 +368,7 @@
<word key="timezone_offset_14" js="0">[GMT + 14] Line Island Time</word>
<word key="task__icalendar" js="0">Checks iCalendar feeds for new events and imports into IP.Calendar.</word>
<word key="digest_area_calendar" js="0">Events</word>
<word key="digest_area_event" js="0">Event</word>
<word key="x_created_event_in" js="0">%s posted an event in %s</word>
<word key="x_commented_event" js="0">%s commented on an event</word>
<word key="digest_event_on" js="0">Event on</word>
+1 -1
View File
@@ -21,7 +21,7 @@
},
{
"key": "ipb_calendar_mon",
"default": "1"
"default": "0"
},
{
"key": "show_bday_calendar",
+182 -71
View File
@@ -133,8 +133,8 @@
</div>
{{endif}}
<span class="ipsType_pageTitle">
<a href='#elCalendars_menu' id='elCalendars' data-ipsMenu data-ipsMenu-appendTo="#elCalendarsHeader">{{if $thisCalendar}}{$thisCalendar->_title}{{else}}{lang="all_calendars"}{{endif}} &nbsp;<i class='fa fa-caret-down'></i></a>
&nbsp;&nbsp;<a href='#elCalendarSettings_menu' id='elCalendarSettings' data-ipsMenu data-ipsMenu-alignCenter data-ipsMenu-appendTo="#elCalendarsHeader"><i class='fa fa-cog'></i></a>
<a href='#elCalendars_menu' id='elCalendars' data-ipsMenu data-ipsMenu-appendTo="#elCalendarsHeader" class='ipsType_blendLinks'>{{if $thisCalendar}}{$thisCalendar->_title}{{else}}{lang="all_calendars"}{{endif}} &nbsp;<i class='fa fa-caret-down'></i></a>
&nbsp;&nbsp;<a href='#elCalendarSettings_menu' id='elCalendarSettings' data-ipsMenu data-ipsMenu-alignCenter data-ipsMenu-appendTo="#elCalendarsHeader" class='ipsType_blendLinks'><i class='fa fa-cog'></i></a>
{{if ( $thisCalendar AND $thisCalendar->can('add') ) OR ( !$thisCalendar AND \IPS\calendar\Calendar::canOnAny('add') )}}
&nbsp;&nbsp;
{{if $thisCalendar}}
@@ -417,7 +417,7 @@
{{foreach $collection as $input}}
{{if $input instanceof \IPS\Helpers\Form\Date}}
<li class='ipsFieldRow ipsFieldRow_fullWidth'>
<input type="date" data-control="date" placeholder="{lang="jump_to_placeholder"}" name='{$input->name}' id='{$input->htmlId}' {{if $input->required === TRUE}}required aria-required='true'{{endif}} value="{{if $input->defaultValue instanceof \IPS\DateTime}}{$input->defaultValue->format('Y-m-d')}{{endif}}">
<input type="date" data-control="date" placeholder="{lang="jump_to_placeholder"}" name='{$input->name}' id='{$input->htmlId}' {{if $input->required === TRUE}}required{{endif}} value="{{if $input->defaultValue instanceof \IPS\DateTime}}{$input->defaultValue->format('Y-m-d')}{{endif}}">
</li>
{{else}}
{$input->rowHtml($form)|raw}
@@ -501,6 +501,97 @@
</ul>
</div>
</div>]]></template>
<template template_group="global" template_name="manageFollowRow" template_data="$table, $headers, $rows, $includeFirstCommentInCommentCount=TRUE" template_location="front" template_app="calendar"><![CDATA[{{if count( $rows )}}
{{foreach $rows as $row}}
{{$idField = $row::$databaseColumnId;}}
<li class="ipsDataItem ipsDataItem_responsivePhoto {{if $row->unread()}}ipsDataItem_unread{{endif}} {{if method_exists( $row, 'tableClass' ) && $row->tableClass()}}ipsDataItem_{$row->tableClass()}{{endif}} {{if $row->hidden()}}ipsModerated{{endif}}" data-controller='core.front.system.manageFollowed' data-followID='{$row->_followData['follow_area']}-{$row->_followData['follow_rel_id']}'>
<div class='ipsDataItem_generic ipsDataItem_size2'>
{{if $row->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' )}}
<time datetime='{$row->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' )->mysqlDatetime()}' class='ipsCalendarDate ipsCalendarDate_large'>
<span class='ipsCalendarDate_month'>{$row->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' )->monthNameShort}</span>
<span class='ipsCalendarDate_date'>{$row->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' )->mday}</span>
</time>
{{else}}
<time datetime='{$row->lastOccurrence( 'startDate' )->mysqlDatetime()}' class='ipsCalendarDate ipsCalendarDate_large'>
<span class='ipsCalendarDate_month'>{$row->lastOccurrence( 'startDate' )->monthNameShort}</span>
<span class='ipsCalendarDate_date'>{$row->lastOccurrence( 'startDate' )->mday}</span>
</time>
{{endif}}
</div>
<div class='ipsDataItem_main ipsPos_middle'>
<h4 class='ipsDataItem_title ipsType_break ipsType_normal'>
{{if $row->mapped('locked')}}
<i class="fa fa-lock"></i>
{{endif}}
{{if $row->mapped('pinned') || $row->mapped('featured') || $row->hidden() === -1 || $row->hidden() === 1}}
<span>
{{if $row->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$row->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $row->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $row->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{{if $row->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
</span>
{{endif}}
{{if $row->prefix()}}
{template="prefix" group="global" app="core" params="$row->prefix( TRUE ), $row->prefix()"}
{{endif}}
<a href='{$row->url()}'>
{{if $row->mapped('title')}}{wordbreak="$row->mapped('title')"}{{else}}<em class="ipsType_light">{lang="content_deleted"}</em>{{endif}}
</a>
</h4>
<div class='ipsDataItem_meta ipsType_light ipsType_blendLinks' data-ipsTruncate data-ipsTruncate-size='2 lines' data-ipsTruncate-type='remove'>
{{if method_exists( $row, 'tableDescription' )}}
{$row->tableDescription()|raw}
{{else}}
{lang="byline" htmlsprintf="$row->author()->link( $row->warningRef() )"}{datetime="$row->__get( $row::$databaseColumnMap['date'] )"}
{lang="in"} <a href="{$row->container()->url()}">{$row->container()->_title}</a>
{{endif}}
</div>
</div>
<div class='ipsDataItem_generic ipsDataItem_size1 ipsType_center ipsType_large'>
<span class='ipsBadge ipsBadge_icon ipsBadge_new {{if !$row->_followData['follow_is_anon']}}ipsHide{{endif}}' data-role='followAnonymous' data-ipsTooltip title='{lang="follow_is_anon"}'><i class='fa fa-eye-slash'></i></span>
</div>
<div class='ipsDataItem_generic ipsDataItem_size6'>
<ul class='ipsList_reset'>
<li title='{lang="follow_when"}' data-role='followDate'><i class='fa fa-clock-o'></i> {datetime="$row->_followData['follow_added']"}</li>
<li title='{lang="follow_how"}' data-role='followFrequency'>
{{if $row->_followData['follow_notify_freq'] == 'none'}}
<i class='fa fa-bell-slash-o'></i>
{{else}}
<i class='fa fa-bell'></i>
{{endif}} {lang="follow_freq_{$row->_followData['follow_notify_freq']}"}
</li>
</ul>
</div>
<div class='ipsDataItem_generic ipsDataItem_size6 ipsType_center'>
{template="manageFollow" group="system" app="core" params="$row->_followData['follow_app'], $row->_followData['follow_area'], $row->_followData['follow_rel_id']"}
</div>
{{if $table->canModerate()}}
<div class='ipsDataItem_modCheck'>
<span class='ipsCustomInput'>
<input type='checkbox' data-role='moderation' name="moderate[{$row->$idField}]" data-actions="{expression="implode( ' ', $table->multimodActions( $row ) )"}" data-state='{{if $row->tableStates()}}{$row->tableStates()}{{endif}}'>
<span></span>
</span>
</div>
{{endif}}
</li>
{{endforeach}}
{{endif}}
]]></template>
<template template_group="global" template_name="rows" template_data="$table, $headers, $rows" template_location="front" template_app="calendar"><![CDATA[{{if count( $rows )}}
{{foreach $rows as $row}}
<li class="ipsDataItem {{if method_exists( $row, 'tableClass' ) && $row->tableClass()}}ipsDataItem_{$row->tableClass()}{{endif}} {{if $row->hidden()}}ipsModerated{{endif}}">
@@ -523,14 +614,6 @@
<i class="fa fa-lock"></i>
{{endif}}
{{if $row->prefix()}}
{template="prefix" group="global" app="core" params="$row->prefix( TRUE ), $row->prefix()"}
{{endif}}
<a href='{$row->url()}' class='ipsType_break' {{if $row->tableHoverUrl}}data-ipsHover{{endif}}>
{{if $row->mapped('title')}}{wordbreak="$row->mapped('title')"}{{else}}<em class="ipsType_light">{lang="content_deleted"}</em>{{endif}}
</a>
{{if $row->mapped('pinned') || $row->mapped('featured') || $row->hidden() === -1 || $row->hidden() === 1}}
{{if $row->hidden() === -1}}
<span class="ipsBadge ipsBadge_small ipsBadge_icon ipsBadge_warning" data-ipsTooltip title='{$row->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
@@ -544,6 +627,14 @@
<span class="ipsBadge ipsBadge_small ipsBadge_icon ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
{{endif}}
{{if $row->prefix()}}
{template="prefix" group="global" app="core" params="$row->prefix( TRUE ), $row->prefix()"}
{{endif}}
<a href='{$row->url()}' class='ipsType_break' {{if $row->tableHoverUrl}}data-ipsHover{{endif}}>
{{if $row->mapped('title')}}{wordbreak="$row->mapped('title')"}{{else}}<em class="ipsType_light">{lang="content_deleted"}</em>{{endif}}
</a>
</h4>
<div class='ipsDataItem_meta ipsType_light ipsType_blendLinks'>
{$row->eventBlurb()|raw}
@@ -613,76 +704,89 @@
{{if $table->canModerate()}}
<div class='ipsDataItem_modCheck'>
{{$idField = $row::$databaseColumnId;}}
<input type='checkbox' data-role='moderation' name="moderate[{$row->$idField}]" data-actions="{expression="implode( ' ', $table->multimodActions( $row ) )"}" data-state='{{if $row->tableStates()}}{$row->tableStates()}{{endif}}'>
<span class='ipsCustomInput'>
<input type='checkbox' data-role='moderation' name="moderate[{$row->$idField}]" data-actions="{expression="implode( ' ', $table->multimodActions( $row ) )"}" data-state='{{if $row->tableStates()}}{$row->tableStates()}{{endif}}'>
<span></span>
</span>
</div>
{{endif}}
</li>
{{endforeach}}
{{endif}}]]></template>
<template template_group="global" template_name="snippet" template_data="$activity, $type='activity'" template_location="front" template_app="calendar"><![CDATA[
{{if $activity instanceof \IPS\calendar\Event\Comment or $activity instanceof \IPS\calendar\Event\Review}}
{{$item = $activity->item();}}
<template template_group="global" template_name="searchResultCommentSnippet" template_data="$indexData, $nextOccurance, $startDate, $endDate, $allDay, $reviewRating, $condensed" template_location="front" template_app="calendar"><![CDATA[{{if $condensed}}
<time datetime='{$nextOccurance->mysqlDatetime()}' class='ipsCalendarDate ipsCalendarDate_small ipsPos_left'>
<span class='ipsCalendarDate_month'>{$nextOccurance->monthNameShort}</span>
<span class='ipsCalendarDate_date'>{$nextOccurance->mday}</span>
</time>
{{else}}
{{$item = $activity;}}
{{endif}}
<div class='cSearchActivity_info ipsContained'>
<div class='ipsColumns'>
<div class='ipsColumn ipsColumn_veryNarrow'>
{{$date = ( $item->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' ) == NULL ) ? $item->lastOccurrence() : $item->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' );}}
<time datetime='{$date->mysqlDatetime()}' class='ipsCalendarDate'>
<span class='ipsCalendarDate_month'>{$date->monthNameShort}</span>
<span class='ipsCalendarDate_date'>{$date->mday}</span>
<div class='ipsColumns ipsColumns_collapsePhone ipsColumns_noSpacing'>
<div class='ipsColumn ipsColumn_narrow'>
<time datetime='{$nextOccurance->mysqlDatetime()}' class='ipsCalendarDate ipsCalendarDate_large ipsPos_center'>
<span class='ipsCalendarDate_month'>{$nextOccurance->monthNameShort}</span>
<span class='ipsCalendarDate_date'>{$nextOccurance->mday}</span>
</time>
</div>
<div class='ipsColumn ipsColumn_fluid'>
{{if $activity instanceof \IPS\calendar\Event\Comment or $activity instanceof \IPS\calendar\Event\Review}}
{{if $activity instanceof \IPS\calendar\Event\Review}}
{template="rating" group="global" location="front" app="core" params="'large', $activity->mapped('rating'), \IPS\Settings::i()->reviews_rating_out_of"}
{{endif}}
<div class='ipsType_medium ipsType_richText ipsContained {{if $activity instanceof \IPS\calendar\Event\Review}}ipsSpacer_both{{else}}ipsSpacer_bottom{{endif}} ipsSpacer_half' data-ipsTruncate data-ipsTruncate-size='3 lines' data-ipsTruncate-type='remove'>
{$activity->truncated()|raw}
</div>
<ul class='ipsList_inline ipsType_light'>
{{if $activity instanceof \IPS\calendar\Event\Review}}
<li>{lang="x_members_found_helpful" sprintf="$activity->mapped('votes_helpful'), \IPS\Member::loggedIn()->language()->pluralize( \IPS\Member::loggedIn()->language()->get( 'x_members' ), array( $activity->mapped('votes_total') ) )"}</li>
{{endif}}
{{if $type != 'search' and $activity instanceof \IPS\Content\Reputation and settings.reputation_enabled}}
<li>{template="reputationMini" group="global" app="core" params="$activity, '', NULL, TRUE"}</li>
{{endif}}
</ul>
{{else}}
{{if $type != 'search'}}<a href='{$activity->url()}' class='ipsType_normal ipsType_break'>{$activity->mapped('title')}</a>{{endif}}
<p class='ipsType_reset ipsType_small'>
<strong>
<time itemprop='startDate' content='{expression="$item->_start_date->format( 'Y-m-d' )"}'>
{$item->_start_date->dayName} {$item->_start_date->mday} {$item->_start_date->monthName} {$item->_start_date->year}{{if !$item->all_day}}, {$item->_start_date->localeTime( FALSE )}{{endif}}
<div class='ipsStream_comment ipsPad'>
<p class='ipsType_reset ipsType_normal'>
<strong class='ipsType_normal'>
<time itemprop='startDate' content='{expression="$startDate->format( 'Y-m-d' )"}'>
{$startDate->dayName} {$startDate->mday} {$startDate->monthName} {$startDate->year}{{if !$allDay}}, {$startDate->localeTime( FALSE )}{{endif}}
</time>
{{if $item->_end_date}}
<em class='ipsType_light'>{lang="until"}</em>
<time itemprop='startDate' content='{expression="$item->_end_date->format( 'Y-m-d' )"}'>
{$item->_end_date->dayName} {$item->_end_date->mday} {$item->_end_date->monthName} {$item->_end_date->year}{{if !$item->all_day}}, {$item->_end_date->localeTime( FALSE )}{{endif}}
{{if $endDate}}
{lang="until_lc"}
<time itemprop='endDate' content='{expression="$endDate->format( 'Y-m-d' )"}'>
{$endDate->dayName} {$endDate->mday} {$endDate->monthName} {$endDate->year}{{if !$allDay}}, {$endDate->localeTime( FALSE )}{{endif}}
</time>
{{endif}}
</strong>
</p>
<div class='ipsType_medium ipsType_richText ipsContained ipsSpacer_both ipsSpacer_half' data-ipsTruncate data-ipsTruncate-size='3 lines' data-ipsTruncate-type='remove'>
{$activity->truncated()|raw}
{{if $reviewRating !== NULL}}
{template="rating" app="core" params="'medium', $reviewRating" group="global"}
{{endif}}
{{if trim( $indexData['index_content'] ) !== ''}}
<div class='ipsType_richText ipsType_break ipsType_medium ipsSpacer_top ipsSpacer_half' {{if !( \IPS\Dispatcher::i()->application->directory == 'core' and \IPS\Dispatcher::i()->module and \IPS\Dispatcher::i()->module->key == 'search' )}}data-ipsTruncate data-ipsTruncate-type='remove' data-ipsTruncate-size='3 lines'{{else}}data-searchable data-findTerm{{endif}}>
{$indexData['index_content']|raw}
</div>
{{endif}}
</div>
</div>
</div>
{{endif}}]]></template>
<template template_group="global" template_name="searchResultEventSnippet" template_data="$indexData, $itemData, $nextOccurance, $startDate, $endDate, $allDay, $condensed" template_location="front" template_app="calendar"><![CDATA[{{if $condensed}}
<time datetime='{$nextOccurance->mysqlDatetime()}' class='ipsCalendarDate ipsCalendarDate_small ipsPos_left'>
<span class='ipsCalendarDate_month'>{$nextOccurance->monthNameShort}</span>
<span class='ipsCalendarDate_date'>{$nextOccurance->mday}</span>
</time>
{{else}}
<div class='ipsColumns ipsColumns_collapsePhone'>
<div class='ipsColumn ipsColumn_narrow'>
<time datetime='{$nextOccurance->mysqlDatetime()}' class='ipsCalendarDate ipsCalendarDate_large ipsPos_center'>
<span class='ipsCalendarDate_month'>{$nextOccurance->monthNameShort}</span>
<span class='ipsCalendarDate_date'>{$nextOccurance->mday}</span>
</time>
</div>
<div class='ipsColumn ipsColumn_fluid ipsStream_snippetInfo'>
<strong class='ipsType_normal'>
<time itemprop='startDate' content='{expression="$startDate->format( 'Y-m-d' )"}'>
{$startDate->dayName} {$startDate->mday} {$startDate->monthName} {$startDate->year}{{if !$allDay}}, {$startDate->localeTime( FALSE )}{{endif}}
</time>
{{if $endDate}}
{lang="until_lc"}
<time itemprop='endDate' content='{expression="$endDate->format( 'Y-m-d' )"}'>
{$endDate->dayName} {$endDate->mday} {$endDate->monthName} {$endDate->year}{{if !$allDay}}, {$endDate->localeTime( FALSE )}{{endif}}
</time>
{{endif}}
</strong>
{{if trim( $indexData['index_content'] ) !== ''}}
<div class='ipsSpacer_top ipsSpacer_half ipsType_richText ipsType_break ipsType_medium' {{if !( \IPS\Dispatcher::i()->application->directory == 'core' and \IPS\Dispatcher::i()->module and \IPS\Dispatcher::i()->module->key == 'search' )}}data-ipsTruncate data-ipsTruncate-type='remove' data-ipsTruncate-size='2 lines'{{else}}data-searchable data-findTerm{{endif}}>
{$indexData['index_content']|raw}
</div>
<ul class='ipsList_inline ipsType_light'>
{{if $item->container()->allow_comments}}
<li>{lang="num_comments" pluralize="$activity->comments"}</li>
{{endif}}
{{if $item->container()->allow_reviews}}
<li>{lang="num_reviews" pluralize="$activity->reviews"} {{if $activity->reviews > 0}}&nbsp;&nbsp;{template="rating" group="global" location="front" app="core" params="'tiny', $item->rating, \IPS\Settings::i()->reviews_rating_out_of"}{{endif}}</li>
{{endif}}
{{if $type != 'search' and $item instanceof \IPS\Content\Reputation and settings.reputation_enabled}}
<li>{template="reputationMini" group="global" app="core" params="$activity, '', NULL, TRUE"}</li>
{{endif}}
</ul>
{{endif}}
</div>
</div>
</div>]]></template>
{{endif}}]]></template>
<template template_group="livesearch" template_name="calendar" template_data="$calendar" template_location="admin" template_app="calendar"><![CDATA[<li class='ipsPad_half ipsClearfix' data-role='result'>
<a href='{url="app=calendar&module=calendars&controller=calendars&do=form&id="}{$calendar->id}' class='ipsPos_left'>{$calendar->_title}</a>
</li>
@@ -878,7 +982,7 @@
<li>
<input type='radio' name='event_dates[repeat_end]' id='event_repeat_end_ondate' value='date'{{if $value['repeat_end_date']}} checked{{endif}}>
<div class='ipsField_fieldList_content'>
<label for="event_repeat_end_ondate">{lang="event_rpm_ends_date"}</label> <input type='date' name='event_dates[repeat_end_date]' class='cCalendar_shortInput' size='10' value='{$value['repeat_end_date']}'>
<label for="event_repeat_end_ondate">{lang="event_rpm_ends_date"}</label> <input type='date' name='event_dates[repeat_end_date]' class='cCalendar_shortInput' size='10' value='{{if $value['repeat_end_date'] instanceof \IPS\calendar\Date}}{$value['repeat_end_date']->mysqlDatetime( FALSE )}{{endif}}'>
</div>
</li>
</ul>
@@ -973,7 +1077,7 @@
</ul>
{{endif}}
</div>]]></template>
<template template_group="view" template_name="comments" template_data="$event" template_location="front" template_app="calendar"><![CDATA[<div class='' data-controller='core.front.core.commentFeed' data-baseURL='{$event->url()}' {{if $event->isLastPage()}}data-lastPage{{endif}} data-feedID='event-{$event->id}' id='comments'>
<template template_group="view" template_name="comments" template_data="$event" template_location="front" template_app="calendar"><![CDATA[<div class='' data-controller='core.front.core.commentFeed' {{if settings.auto_polling_enabled}}data-autoPoll{{endif}} data-baseURL='{$event->url()}' {{if $event->isLastPage()}}data-lastPage{{endif}} data-feedID='event-{$event->id}' id='comments'>
{{if $event->commentPageCount() > 1}}
{$event->commentPagination( array( 'tab' ) )|raw}
<br><br>
@@ -1027,7 +1131,8 @@
{template="prefix" group="global" app="core" params="$event->prefix( TRUE ), $event->prefix()"}
{{endif}}
{{if $event->locked()}}<i class='fa fa-lock'></i> {{endif}}<span itemprop='name'>{$event->title}</span>
{{if $event->locked()}}<i class='fa fa-lock'></i> {{endif}}
{{if $event->mapped('pinned') || $event->mapped('featured') || $event->hidden() === -1 || $event->hidden() === 1}}
{{if $event->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_warning" data-ipsTooltip title='{$event->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
@@ -1041,6 +1146,8 @@
<span class="ipsBadge ipsBadge_icon ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
{{endif}}
<span itemprop='name'>{$event->title}</span>
</h1>
<p class='ipsType_normal ipsType_reset'>
<time itemprop='startDate' content='{expression="$event->_start_date->format( 'Y-m-d' )"}'>
@@ -1164,7 +1271,7 @@
<div class='ipsBox'>
<h3 class='ipsType_reset ipsType_sectionHead ipsHide'>{lang="event_rsvp_attendees"}</h3>
<div class='ipsTabs ipsTabs_small ipsClearfix' id='elAttendees{$tabId}' data-ipsTabBar data-ipsTabBar-stretch data-ipsTabBar-contentArea='#elAttendees{$tabId}_content'>
<div class='ipsTabs ipsTabs_small ipsTabs_stretch ipsClearfix' id='elAttendees{$tabId}' data-ipsTabBar data-ipsTabBar-contentArea='#elAttendees{$tabId}_content'>
<a href='#elAttendees{$tabId}' data-action='expandTabs'><i class='fa fa-caret-down'></i></a>
<ul role="tablist">
<li>
@@ -1242,7 +1349,7 @@
</div>
</div>
{{endif}}]]></template>
<template template_group="view" template_name="reviews" template_data="$event" template_location="front" template_app="calendar"><![CDATA[<div data-controller='core.front.core.commentFeed' data-baseURL='{$event->url()}' {{if $event->isLastPage('reviews')}}data-lastPage{{endif}} data-feedID='event-{$event->id}-reviews' id='reviews'>
<template template_group="view" template_name="reviews" template_data="$event" template_location="front" template_app="calendar"><![CDATA[<div data-controller='core.front.core.commentFeed' {{if settings.auto_polling_enabled}}data-autoPoll{{endif}} data-baseURL='{$event->url()}' {{if $event->isLastPage('reviews')}}data-lastPage{{endif}} data-feedID='event-{$event->id}-reviews' id='reviews'>
{{if $event->canReview()}}
{{if $event->locked()}}
<strong class='ipsType_warning'><i class='fa fa-info-circle'></i> {lang="item_locked_can_review"}</strong>
@@ -1296,6 +1403,8 @@
<hr class='ipsHr'>
{$event->reviewPagination( array( 'tab', 'sort' ) )|raw}
{{endif}}
{{elseif !$event->canReview()}}
<p class="ipsType_normal ipsType_light ipsType_reset" data-role="noReviews">{lang="no_reviews"}</p>
{{endif}}
</div>]]></template>
<template template_group="view" template_name="rsvpControls" template_data="$event, $attendees" template_location="front" template_app="calendar"><![CDATA[<!-- Don't use IDs here, this template is called twice in view -->
@@ -1606,11 +1715,11 @@
<span class='ipsCalendarDate_date'>{$event->nextOccurrence( $today, 'startDate' )->mday}</span>
</time>
</div>
<div class='ipsDataItem_main ipsType_break'>
<div class='ipsDataItem_main ipsType_break ipsContained'>
{{if $event->container()->allow_comments && $orientation == 'vertical'}}
<div class="ipsCommentCount ipsPos_right {{if $event->comments === 0}}ipsFaded{{endif}}" data-ipsTooltip title='{lang="replies_number" pluralize="$event->comments"}'>{expression="$event->comments"}</div>
{{endif}}
{{if $event->unread()}}<span class="ipsItemStatus ipsItemStatus_tiny"><i class="fa fa-circle"></i></span> <strong>{{endif}}<a href="{$event->url()}" title='{lang="view_this_event" sprintf="$event->title"}'>{wordbreak="$event->title"}</a>{{if $event->unread()}}</strong>{{endif}}<br>
{{if $event->unread()}}<span class="ipsItemStatus ipsItemStatus_tiny"><i class="fa fa-circle"></i></span> <strong>{{endif}}<a href="{$event->url()}" title='{lang="view_this_event" sprintf="$event->title"}'>{$event->title}</a>{{if $event->unread()}}</strong>{{endif}}<br>
<strong class='ipsType_small'>
{{if $event->nextOccurrence( $today, 'startDate' )}}
{$event->nextOccurrence( $today, 'startDate' )->calendarDate()}{{if !$event->all_day}} {$event->nextOccurrence( $today, 'startDate' )->localeTime( FALSE )} {{endif}}
@@ -1988,7 +2097,9 @@ a.cEvents_event, .cEvents_event a, .cEvents_event.cEvents_empty span {
white-space: nowrap;
overflow: hidden;
}
html[dir="rtl"] a.cEvents_event, .cEvents_event a, .cEvents_event.cEvents_empty span {
html[dir="rtl"] a.cEvents_event,
html[dir="rtl"] .cEvents_event a,
html[dir="rtl"] .cEvents_event.cEvents_empty span {
padding: 0 10px 0 8px;
}
+14 -1
View File
@@ -55,5 +55,18 @@
"100042": "4.0.12",
"100043": "4.0.12.1",
"100044": "4.0.13",
"100045": "4.0.13.1"
"100045": "4.0.13.1",
"101000": "4.1.0 Beta 1",
"101001": "4.1.0 Beta 2",
"101002": "4.1.0 Beta 3",
"101003": "4.1.0 Beta 4",
"101004": "4.1.0 Beta 5",
"101005": "4.1.0 Beta 6",
"101006": "4.1.0 Beta 7",
"101007": "4.1.0 Beta 8",
"101008": "4.1.0 Beta 9",
"101009": "4.1.0 Beta 10",
"101010": "4.1.0",
"101011": "4.1.1",
"101012": "4.1.2"
}
@@ -27,5 +27,19 @@ class _Calendar
/**
* @brief Content Item Classes
*/
public $classes = array( 'IPS\calendar\Event' );
public $classes = array();
/**
* Constructor
*
* @param \IPS\Member|NULL $member If checking access, the member to check for, or NULL to not check access
* @return void
*/
public function __construct( \IPS\Member $member = NULL )
{
if ( $member === NULL or $member->canAccessModule( \IPS\Application\Module::get( 'calendar', 'calendar', 'front' ) ) )
{
$this->classes[] = 'IPS\calendar\Event';
}
}
}
@@ -22,8 +22,18 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
/**
* Front Navigation Extension: Calendar
*/
class _Calendar
class _Calendar extends \IPS\core\FrontNavigation\FrontNavigationAbstract
{
/**
* Get Type Title which will display in the AdminCP Menu Manager
*
* @return string
*/
public static function typeTitle()
{
return \IPS\Member::loggedIn()->language()->addToStack('frontnavigation_calendar');
}
/**
* Can access?
*
@@ -31,7 +41,7 @@ class _Calendar
*/
public function canView()
{
return !\IPS\Application::load('calendar')->hide_tab and \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'calendar', 'calendar' ) );
return parent::canView() and \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'calendar', 'calendar' ) );
}
/**
@@ -63,14 +73,4 @@ class _Calendar
{
return \IPS\Dispatcher::i()->application->directory === 'calendar';
}
/**
* Children
*
* @return array
*/
public function children()
{
return array();
}
}
@@ -185,7 +185,7 @@ class _event extends \IPS\Content\Controller
}
/* We delete either way at this point, because even if we select a different action we have to remove any existing RSVP preference */
\IPS\Db::i()->delete( 'calendar_event_rsvp', array( 'rsvp_event_id=? AND rsvp_member_id=?', $this->event->id, \IPS\Member::loggedIn()->member_id ) );
\IPS\Db::i()->delete( 'calendar_event_rsvp', array( 'rsvp_event_id=? AND rsvp_member_id=?', $this->event->id, (int) \IPS\Member::loggedIn()->member_id ) );
if( \IPS\Request::i()->action == 'leave' )
{
@@ -229,7 +229,7 @@ class _event extends \IPS\Content\Controller
\IPS\Db::i()->insert( 'calendar_event_rsvp', array(
'rsvp_event_id' => $this->event->id,
'rsvp_member_id' => \IPS\Member::loggedIn()->member_id,
'rsvp_member_id' => (int) \IPS\Member::loggedIn()->member_id,
'rsvp_date' => time(),
'rsvp_response' => (int) $_go
) );
@@ -239,4 +239,16 @@ class _event extends \IPS\Content\Controller
\IPS\Output::i()->redirect( $this->event->url(), $message );
}
/**
* Edit Item
*
* @return void
*/
protected function edit()
{
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_submit.js', 'calendar', 'front' ) );
return parent::edit();
}
}
@@ -495,21 +495,25 @@ class _view extends \IPS\Dispatcher\Controller
if( $values = $form->values() )
{
\IPS\Request::i()->view = 'day';
if( \IPS\Request::i()->goto )
{
\IPS\Request::i()->y = null;
\IPS\Request::i()->m = null;
\IPS\Request::i()->d = null;
\IPS\Request::i()->w = null;
$dateToGoTo = \IPS\DateTime::create();
}
else
{
\IPS\Request::i()->y = $values['jump_to']->format('Y');
\IPS\Request::i()->m = $values['jump_to']->format('m');
\IPS\Request::i()->d = $values['jump_to']->format('j');
$dateToGoTo = $values['jump_to'];
}
if ( $this->_calendar )
{
$url = \IPS\Http\Url::internal( "app=calendar&module=calendar&controller=view&view=day&id={$this->_calendar->_id}&y={$dateToGoTo->format('Y')}&m={$dateToGoTo->format('m')}&d={$dateToGoTo->format('j')}", 'front', 'calendar_calday', $this->_calendar->title_seo );
}
else
{
$url = \IPS\Http\Url::internal( "app=calendar&module=calendar&controller=view&view=day&y={$dateToGoTo->format('Y')}&m={$dateToGoTo->format('m')}&d={$dateToGoTo->format('j')}", 'front', 'calendar_day' );
}
\IPS\Output::i()->redirect( $url );
}
return $form;
@@ -107,6 +107,3 @@ $SQL[] = "INSERT INTO cal_events SELECT event_id, event_calendar_id, event_membe
event_recurring, FROM_UNIXTIME(event_unix_from), CASE WHEN event_unix_to > 0 THEN FROM_UNIXTIME(event_unix_to) ELSE NULL END, '', 0, 0, 0, 0, MD5( CONCAT( event_id, event_title ) ), 0, 1 FROM " . \IPS\Db::i()->prefix . "cal_events_bak;";
$SQL[] = "DROP TABLE cal_events_bak;";
$SQL[] = "ALTER TABLE cal_events ADD event_all_day TINYINT NOT NULL DEFAULT '0';";
$SQL[] = "UPDATE cal_events SET event_all_day=1 WHERE TIME(event_start_date) = '00:00:00';";
Whitespace-only changes.
@@ -0,0 +1,4 @@
<?php
$SQL[] = "ALTER TABLE cal_events ADD event_all_day TINYINT NOT NULL DEFAULT '0';";
$SQL[] = "UPDATE cal_events SET event_all_day=1 WHERE TIME(event_start_date) = '00:00:00';";
@@ -0,0 +1,38 @@
<?php
/**
* @brief 4.0.0 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Calendar
* @since 8 October 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\calendar\setup\upg_32005;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* 4.0.0 Upgrade Code
*/
class _Upgrade
{
/**
* Conversion from 3.0
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
\IPS\core\Setup\Upgrade::runLegacySql( 'calendar', 32005 );
return TRUE;
}
}
@@ -65,7 +65,7 @@ class _Upgrade
{
foreach( \IPS\Db::i()->select( '*', 'calendar_calendars' ) as $calendar )
{
\IPS\Lang::saveCustom( 'calendar', "calendar_calendar_{$calendar['cal_id']}", html_entity_decode( $calendar['cal_title'], ENT_QUOTES, 'UTF-8' ) );
\IPS\Lang::saveCustom( 'calendar', "calendar_calendar_{$calendar['cal_id']}", \IPS\Text\Parser::utf8mb4SafeDecode( $calendar['cal_title'] ) );
}
\IPS\Db::i()->dropColumn( 'calendar_calendars', 'cal_title' );
@@ -185,21 +185,21 @@ class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
* @brief Cached URL
*/
protected $_url = NULL;
/**
* Get URL
*
* @return \IPS\Http\Url
* @brief URL Base
*/
public function url()
{
if( $this->_url === NULL )
{
$this->_url = \IPS\Http\Url::internal( "app=calendar&module=calendar&controller=view&id={$this->_id}", 'front', 'calendar_calendar', $this->title_seo );
}
return $this->_url;
}
public static $urlBase = 'app=calendar&module=calendar&controller=view&id=';
/**
* @brief URL Base
*/
public static $urlTemplate = 'calendar_calendar';
/**
* @brief SEO Title Column
*/
public static $seoTitleColumn = 'title_seo';
/**
* [ActiveRecord] Delete Record
+14 -2
View File
@@ -425,11 +425,11 @@ class _Date extends \IPS\DateTime
{
if( \IPS\Settings::i()->calendar_date_format == -1 AND \IPS\Settings::i()->calendar_date_format_custom )
{
return \IPS\Member::loggedIn()->language()->convertString( strftime( \IPS\Settings::i()->calendar_date_format_custom, $this->getTimestamp() + $this->getTimezone()->getOffset( $this ) ) );
return \IPS\Member::loggedIn()->language()->convertString( strftime( \IPS\Settings::i()->calendar_date_format_custom, $this->getTimestamp() + $this->offset ) );
}
elseif( isset( static::$dateFormats[ \IPS\Settings::i()->calendar_date_format ] ) )
{
return \IPS\Member::loggedIn()->language()->convertString( strftime( static::$dateFormats[ \IPS\Settings::i()->calendar_date_format ], $this->getTimestamp() + $this->getTimezone()->getOffset( $this ) ) );
return \IPS\Member::loggedIn()->language()->convertString( strftime( static::$dateFormats[ \IPS\Settings::i()->calendar_date_format ], $this->getTimestamp() + $this->offset ) );
}
else
{
@@ -731,4 +731,16 @@ class _Date extends \IPS\DateTime
return NULL;
}
/**
* Format the time according to the user's locale (without the date)
*
* @param bool $seconds If TRUE, will include seconds
* @param bool $minutes If TRUE, will include minutes
* @return string
*/
public function localeTime( $seconds=TRUE, $minutes=TRUE )
{
return \IPS\Member::loggedIn()->language()->convertString( strftime( $this->localeTimeFormat( $seconds, $minutes ), $this->getTimestamp() + $this->offset ) );
}
}
@@ -105,4 +105,37 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory,
{
return array( \IPS\Theme::i()->getTemplate( 'tables', 'core' ), 'commentRows' );
}
/**
* Get snippet HTML for search result display
*
* @param array $indexData Data from the search index
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
* @param array $reputationData Array of people who have given reputation and the reputation they gave
* @param int|NULL $reviewRating If this is a review, the rating
* @param string $view 'expanded' or 'condensed'
* @return callable
*/
public static function searchResultSnippet( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $view )
{
$startDate = \IPS\calendar\Date::parseTime( $itemData['event_start_date'], $itemData['event_all_day'] ? FALSE : TRUE );
$endDate = $itemData['event_end_date'] ? \IPS\calendar\Date::parseTime( $itemData['event_end_date'], $itemData['event_all_day'] ? FALSE : TRUE ) : NULL;
$nextOccurance = $startDate;
if ( $itemData['event_recurring'] )
{
$occurances = \IPS\calendar\Event::_findOccurances( $startDate, $endDate, $startDate->adjust( "-1 month" ), $startDate->adjust( "+2 years" ), \IPS\calendar\Icalendar\ICSParser::parseRrule( $itemData['event_recurring'] ) );
foreach( $occurances as $occurrence )
{
if( $occurrence['startDate'] AND $occurrence['startDate']->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) )
{
$nextOccurance = $occurrence['startDate'];
break;
}
}
}
return \IPS\Theme::i()->getTemplate( 'global', 'calendar', 'front' )->searchResultCommentSnippet( $indexData, $nextOccurance, $startDate, $endDate, $itemData['event_all_day'], $reviewRating, $view == 'condensed' );
}
}
+150 -44
View File
@@ -145,6 +145,21 @@ class _Event extends \IPS\Content\Item implements
const RSVP_YES = 1;
const RSVP_MAYBE = 2;
/**
* Columns needed to query for search result / stream view
*
* @return array
*/
public static function basicDataColumns()
{
$return = parent::basicDataColumns();
$return[] = 'event_recurring';
$return[] = 'event_start_date';
$return[] = 'event_end_date';
$return[] = 'event_all_day';
return $return;
}
/**
* Set the title
*
@@ -308,10 +323,27 @@ class _Event extends \IPS\Content\Item implements
//return $results;
}
/* Now figure out when this event occurs on */
/* Return the results we found after storing them */
$this->parsedOccurrences = static::_findOccurances( $this->_start_date, $this->_end_date, $startDate, $endDate, $recurringData );
return $this->parsedOccurrences;
}
/**
* Get occurances
*
* @param \IPS\calendar\Date $eventStart Event start date
* @param \IPS\calendar\Date $eventEnd Event end date
* @param \IPS\calendar\Date $startDate Date to start from
* @param \IPS\calendar\Date $endDate Date to end at
* @param array $recurringData Reccurance data
*/
public static function _findOccurances( $eventStart, $eventEnd, $startDate, $endDate, $recurringData )
{
$instances = array();
$occurrences = 0;
$keyword = NULL;
$results = array();
switch( $recurringData['event_repeats'] )
{
@@ -338,8 +370,8 @@ class _Event extends \IPS\Content\Item implements
}
else
{
$date = $this->_start_date;
$eDate = $this->_end_date;
$date = $eventStart;
$eDate = $eventEnd;
if( ( $date->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $date->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
( $eDate !== NULL AND $eDate->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
@@ -348,8 +380,18 @@ class _Event extends \IPS\Content\Item implements
{
$results[] = array( 'startDate' => $date, 'endDate' => $eDate );
}
$nextDay = current( $_repeatDays );
/* Figure out which of teh days is next. For example, if the start date is a Wednesday, and the
event repeats every Monday and Friday, we need to start with Friday (not Monday) because that's
when the first occurance is */
$nextTimes = array();
foreach ( $_repeatDays as $repeatDay )
{
$nextTimes[ $repeatDay ] = $date->adjust( "next {$repeatDay}" )->getTimestamp();
}
asort( $nextTimes );
$nextTimes = array_keys( $nextTimes );
$nextDay = array_shift( $nextTimes );
/* Do we have an occurrences limit? */
if( $recurringData['repeat_end_occurrences'] )
@@ -445,8 +487,8 @@ class _Event extends \IPS\Content\Item implements
/* Normal recurrence checks */
if( $keyword !== NULL )
{
$date = $this->_start_date;
$eDate = $this->_end_date;
$date = $eventStart;
$eDate = $eventEnd;
if( ( $date->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $date->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
( $eDate !== NULL AND $eDate->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
@@ -496,7 +538,7 @@ class _Event extends \IPS\Content\Item implements
/* Recurs indefinitely... the most fun type... */
else
{
while( $date->mysqlDatetime( FALSE ) < $endDate->mysqlDatetime( FALSE ) )
while( $date->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) )
{
if( ( $date->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $date->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
( $eDate !== NULL AND $eDate->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
@@ -511,11 +553,8 @@ class _Event extends \IPS\Content\Item implements
}
}
}
/* Return the results we found after storing them */
$this->parsedOccurrences = $results;
return $this->parsedOccurrences;
return $results;
}
/**
@@ -716,29 +755,21 @@ class _Event extends \IPS\Content\Item implements
* @brief Cached URLs
*/
protected $_url = array();
/**
* Get URL
*
* @param string|NULL $action Action
* @return \IPS\Http\Url
*/
public function url( $action=NULL )
{
$_key = md5( $action );
if( !isset( $this->_url[ $_key ] ) )
{
$this->_url[ $_key ] = \IPS\Http\Url::internal( "app=calendar&module=calendar&controller=event&id={$this->id}", 'front', 'calendar_event', $this->title_seo );
if ( $action )
{
$this->_url[ $_key ] = $this->_url[ $_key ]->setQueryString( 'do', $action );
}
}
return $this->_url[ $_key ];
}
/**
* @brief URL Base
*/
public static $urlBase = 'app=calendar&module=calendar&controller=event&id=';
/**
* @brief URL Base
*/
public static $urlTemplate = 'calendar_event';
/**
* @brief SEO Title Column
*/
public static $seoTitleColumn = 'title_seo';
/**
* Get URL for last comment page
@@ -772,6 +803,40 @@ class _Event extends \IPS\Content\Item implements
return array( \IPS\Theme::i()->getTemplate( 'global', 'calendar' ), 'rows' );
}
/**
* HTML to manage an item's follows
*
* @return callable
*/
public static function manageFollowRows()
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'calendar.css', 'calendar' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'calendar_responsive.css', 'calendar' ) );
return array( \IPS\Theme::i()->getTemplate( 'global', 'calendar', 'front' ), 'manageFollowRow' );
}
/**
* Are comments supported by this class?
*
* @param \IPS\Member\NULL $member The member to check for or NULL fto not check permission
* @return int
*/
public static function supportsComments( \IPS\Member $member = NULL )
{
return parent::supportsComments() and ( !$member or \IPS\calendar\Calendar::countWhere( 'read', $member, array( 'cal_allow_comments=1' ) ) );
}
/**
* Are reviews supported by this class?
*
* @param \IPS\Member\NULL $member The member to check for or NULL to not check permission
* @return int
*/
public static function supportsReviews( \IPS\Member $member = NULL )
{
return parent::supportsReviews() and ( !$member or \IPS\calendar\Calendar::countWhere( 'read', $member, array( 'cal_allow_reviews=1' ) ) );
}
/**
* Get available comment/review tabs
*
@@ -1009,12 +1074,12 @@ class _Event extends \IPS\Content\Item implements
/* Cover photo and location */
$return['header'] = new \IPS\Helpers\Form\Upload( 'event_cover_photo', ( $item AND $item->cover_photo ) ? \IPS\File::get( 'calendar_Events', $item->cover_photo ) : NULL, FALSE, array( 'image' => TRUE, 'storageExtension' => 'calendar_Events' ) );
$return['location'] = new \IPS\Helpers\Form\Address( 'event_location', ( $item AND $item->location ) ? \IPS\GeoLocation::buildFromJson( $item->location ) : NULL, FALSE, array( 'minimize' => TRUE ) );
$return['location'] = new \IPS\Helpers\Form\Address( 'event_location', ( $item AND $item->location ) ? \IPS\GeoLocation::buildFromJson( $item->location ) : NULL, FALSE, array( 'minimize' => TRUE, 'requireFullAddress' => FALSE ) );
/* Gallery album association */
if( \IPS\Application::appIsEnabled( 'gallery' ) )
{
$return['album'] = new \IPS\Helpers\Form\Node( 'event_album', ( $item AND $item->event_album ) ? $item->event_album : NULL, FALSE, array(
$return['album'] = new \IPS\Helpers\Form\Node( 'event_album', ( $item AND $item->album ) ? $item->album : NULL, FALSE, array(
'url' => \IPS\Http\Url::internal( 'app=calendar&module=calendar&controller=submit', 'front', 'calendar_submit' ),
'class' => 'IPS\gallery\Album',
'permissionCheck' => 'add',
@@ -1049,7 +1114,7 @@ class _Event extends \IPS\Content\Item implements
* @return void
*/
public function processForm( $values )
{
{
/* Anything but Chrome, basically, falls back to a text input and submitter might submit 22.00 instead of 22:00 */
if( isset( $values['event_dates']['start_time'] ) )
{
@@ -1183,11 +1248,11 @@ class _Event extends \IPS\Content\Item implements
/**
* Retrieve events to show based on a provided start and end date, optionally filtering by a supplied calendar
*
* @param \IPS\calendar\Date $startDate Date to start from
* @param \IPS\calendar\Date|NULL $endDate Cut off date for events. NULL accepted as a possible value only if $formatEvents is set to FALSE.
* @param \IPS\calendar\Calendar|NULL $calendar Calendar to filter by
* @param int|null $limit Maximum number of events to return (only supported when not formatting events)
* @param bool $formatEvents Whether or not to format events into a structured array
* @param \IPS\calendar\Date $startDate Date to start from
* @param \IPS\calendar\Date|NULL $endDate Cut off date for events. NULL accepted as a possible value only if $formatEvents is set to FALSE.
* @param \IPS\calendar\Calendar|NULL|array $calendar Calendar to filter by
* @param int|null $limit Maximum number of events to return (only supported when not formatting events)
* @param bool $formatEvents Whether or not to format events into a structured array
* @return \IPS\Patterns\ActiveRecordIterator
* @throws \InvalidArgumentException
* @see \IPS\Content\_Item::getItemsWithPermission()
@@ -1198,7 +1263,15 @@ class _Event extends \IPS\Content\Item implements
if( $calendar !== NULL )
{
$where[] = array( 'event_calendar_id=?', (int) $calendar->_id );
if ( is_array( $calendar ) )
{
$where[] = array( \IPS\Db::i()->in( 'event_calendar_id', $calendar ) );
}
else
{
$where[] = array( 'event_calendar_id=?', (int) $calendar->_id );
}
}
if( $endDate === NULL AND $formatEvents === TRUE )
@@ -1475,4 +1548,37 @@ class _Event extends \IPS\Content\Item implements
{
return \IPS\Theme::i()->getTemplate( 'global', 'calendar' )->embedCalendar_event( $this, $this->url()->setQueryString( $params ) );
}
/**
* Get snippet HTML for search result display
*
* @param array $indexData Data from the search index
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
* @param array $reputationData Array of people who have given reputation and the reputation they gave
* @param int|NULL $reviewRating If this is a review, the rating
* @param string $view 'expanded' or 'condensed'
* @return callable
*/
public static function searchResultSnippet( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $view )
{
$startDate = \IPS\calendar\Date::parseTime( $itemData['event_start_date'], $itemData['event_all_day'] ? FALSE : TRUE );
$endDate = $itemData['event_end_date'] ? \IPS\calendar\Date::parseTime( $itemData['event_end_date'], $itemData['event_all_day'] ? FALSE : TRUE ) : NULL;
$nextOccurance = $startDate;
if ( $itemData['event_recurring'] )
{
$occurances = \IPS\calendar\Event::_findOccurances( $startDate, $endDate, $startDate->adjust( "-1 month" ), $startDate->adjust( "+2 years" ), \IPS\calendar\Icalendar\ICSParser::parseRrule( $itemData['event_recurring'] ) );
foreach( $occurances as $occurrence )
{
if( $occurrence['startDate'] AND $occurrence['startDate']->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) )
{
$nextOccurance = $occurrence['startDate'];
break;
}
}
}
return \IPS\Theme::i()->getTemplate( 'global', 'calendar', 'front' )->searchResultEventSnippet( $indexData, $itemData, $nextOccurance, $startDate, $endDate, $itemData['event_all_day'], $view == 'condensed' );
}
}
@@ -109,4 +109,21 @@ class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \
{
return array( \IPS\Theme::i()->getTemplate( 'tables', 'core' ), 'commentRows' );
}
/**
* Get snippet HTML for search result display
*
* @param array $indexData Data from the search index
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
* @param array $reputationData Array of people who have given reputation and the reputation they gave
* @param int|NULL $reviewRating If this is a review, the rating
* @param string $view 'expanded' or 'condensed'
* @return callable
*/
public static function searchResultSnippet( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $view )
{
return \IPS\calendar\Event\Comment::searchResultSnippet( $indexData, $authorData, $itemData, $containerData, $reputationData, $reviewRating, $view );
}
}
@@ -383,7 +383,7 @@ class _ICSParser
{
try
{
$eventId = \IPS\Db::i()->select( 'import_event_id', 'calendar_import_map', array( 'import_guid=?', $event['uid'] ) )->first();
$eventId = \IPS\Db::i()->select( 'import_event_id', 'calendar_import_map', array( array( 'import_guid=? and import_feed_id=?', $event['uid'], $this->feed->id ) ) )->first();
try
{
@@ -696,8 +696,8 @@ class _ICSParser
}
else
{
$output .= "DTSTART;TZID=Europe/London:" . $event->_start_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
$output .= "DTEND;TZID=Europe/London:" . $event->_end_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
$output .= "DTSTART;" . $event->_start_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
$output .= "DTEND;" . $event->_end_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
}
}
else
@@ -708,7 +708,7 @@ class _ICSParser
}
else
{
$output .= "DTSTART;TZID=Europe/London:" . $event->_start_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
$output .= "DTSTART;" . $event->_start_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
}
}
@@ -1124,8 +1124,11 @@ class _ICSParser
break;
case 'ORGANIZER':
$line = explode( ':', $_data );
$_event['organizer'] = array( 'name' => str_replace( 'CN=', '', $line[0] ), 'email' => $line[1] );
if ( $_data )
{
$line = explode( ':', $_data );
$_event['organizer'] = array( 'name' => str_replace( 'CN=', '', $line[0] ), 'email' => $line[1] );
}
break;
case 'ATTENDEE':
@@ -50,13 +50,37 @@ class _recentReviews extends \IPS\Widget\PermissionCache
if ( $form === null )
{
$form = new \IPS\Helpers\Form;
}
}
/* Container */
$form->add( new \IPS\Helpers\Form\Node( 'widget_calendar', isset( $this->configuration['widget_calendar'] ) ? $this->configuration['widget_calendar'] : 0, FALSE, array(
'class' => '\IPS\calendar\Calendar',
'zeroVal' => 'all',
'permissionCheck' => 'view',
'multiple' => true
) ) );
$form->add( new \IPS\Helpers\Form\Number( 'review_count', isset( $this->configuration['review_count'] ) ? $this->configuration['review_count'] : 5, TRUE ) );
return $form;
}
/**
* Ran before saving widget configuration
*
* @param array $values Values from form
* @return array
*/
public function preConfig( $values )
{
if ( is_array( $values['widget_calendar'] ) )
{
$values['widget_calendar'] = array_keys( $values['widget_calendar'] );
}
return $values;
}
/**
* Render a widget
*
@@ -64,12 +88,14 @@ class _recentReviews extends \IPS\Widget\PermissionCache
*/
public function render()
{
if( !\IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'calendar', 'calendar' ) ) )
$where = array();
if ( ! empty( $this->configuration['widget_calendar'] ) )
{
return '';
$where['item'][] = array( \IPS\Db::i()->in( 'event_calendar_id', $this->configuration['widget_calendar'] ) );
}
$reviews = \IPS\calendar\Event\Review::getItemsWithPermission( array(), NULL, ( isset( $this->configuration['review_count'] ) AND $this->configuration['review_count'] > 0 ) ? $this->configuration['review_count'] : 5 );
$reviews = \IPS\calendar\Event\Review::getItemsWithPermission( $where, NULL, ( isset( $this->configuration['review_count'] ) AND $this->configuration['review_count'] > 0 ) ? $this->configuration['review_count'] : 5 );
return $this->output( $reviews );
}
@@ -44,7 +44,26 @@ class _upcomingEvents extends \IPS\Widget\PermissionCache
* @note We allow this cache to be valid for 12 hours
*/
public $cacheExpiration = 43200;
/**
* Constructor
*
* @param String $uniqueKey Unique key for this specific instance
* @param array $configuration Widget custom configuration
* @param null|string|array $access Array/JSON string of executable apps (core=sidebar only, content=IP.Content only, etc)
* @param null|string $orientation Orientation (top, bottom, right, left)
* @param boolean $allowReuse If true, when the block is used, it will remain in the sidebar so it can be used again.
* @param string $menuStyle Menu is a drop down menu, modal is a bigger modal panel.
* @return void
*/
public function __construct( $uniqueKey, array $configuration, $access=null, $orientation=null )
{
parent::__construct( $uniqueKey, $configuration, $access, $orientation );
/* We need to adjust for timezone too */
$this->cacheKey = "widget_{$this->key}_" . $this->uniqueKey . '_' . md5( json_encode( $configuration ) . "_" . \IPS\Member::loggedIn()->language()->id . "_" . \IPS\Member::loggedIn()->skin . "_" . json_encode( \IPS\Member::loggedIn()->groups ) . "_" . $orientation . \IPS\Member::loggedIn()->timezone );
}
/**
* Initialize this widget
*
@@ -70,12 +89,36 @@ class _upcomingEvents extends \IPS\Widget\PermissionCache
$form = new \IPS\Helpers\Form;
}
/* Container */
$form->add( new \IPS\Helpers\Form\Node( 'widget_calendar', isset( $this->configuration['widget_calendar'] ) ? $this->configuration['widget_calendar'] : 0, FALSE, array(
'class' => '\IPS\calendar\Calendar',
'zeroVal' => 'all',
'permissionCheck' => 'view',
'multiple' => true
) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'auto_hide', isset( $this->configuration['auto_hide'] ) ? $this->configuration['auto_hide'] : FALSE, FALSE ) );
$form->add( new \IPS\Helpers\Form\Number( 'days_ahead', isset( $this->configuration['days_ahead'] ) ? $this->configuration['days_ahead'] : NULL, TRUE, array( 'unlimited' => -1 ) ) );
$form->add( new \IPS\Helpers\Form\Number( 'maximum_count', isset( $this->configuration['maximum_count'] ) ? $this->configuration['maximum_count'] : 5, TRUE, array( 'unlimited' => -1 ) ) );
return $form;
}
/**
* Ran before saving widget configuration
*
* @param array $values Values from form
* @return array
*/
public function preConfig( $values )
{
if ( is_array( $values['widget_calendar'] ) )
{
$values['widget_calendar'] = array_keys( $values['widget_calendar'] );
}
return $values;
}
/**
* Render a widget
*
@@ -97,8 +140,15 @@ class _upcomingEvents extends \IPS\Widget\PermissionCache
{
$endDate = $_today->adjust( "+" . $this->configuration['days_ahead'] . " days" );
}
$events = \IPS\calendar\Event::retrieveEvents( $_today, $endDate, NULL, ( isset( $this->configuration['maximum_count'] ) AND $this->configuration['maximum_count'] > 0 ) ? $this->configuration['maximum_count'] : 5, FALSE );
$calendars = NULL;
if ( ! empty( $this->configuration['widget_calendar'] ) )
{
$calendars = $this->configuration['widget_calendar'];
}
$events = \IPS\calendar\Event::retrieveEvents( $_today, $endDate, $calendars, ( isset( $this->configuration['maximum_count'] ) AND $this->configuration['maximum_count'] > 0 ) ? $this->configuration['maximum_count'] : 5, FALSE );
/* Auto hiding? */
if( !count($events) AND isset( $this->configuration['auto_hide'] ) AND $this->configuration['auto_hide'] )