Version 4.3.6

This commit is contained in:
Neo committed 2025-12-19 05:49:12 -08:00
1 parent fe1acf984a
commit 1a0c7fd3c2
609 files changed
+14707 -5726

No files matched your search

+2 -1
View File
@@ -145,7 +145,8 @@ class _Application extends \IPS\Application
foreach ( \IPS\calendar\Event::retrieveEvents( $_today, $endDate, NULL, NULL, FALSE, $member ) as $event )
{
$document->addItem( $event->title, $event->url(), $event->content, \IPS\DateTime::ts( $event->saved ), $event->id );
$next = ( (int) \IPS\Settings::i()->calendar_rss_feed_order === 0 ) ? $event->nextOccurrence( $_today, 'startDate' ) : \IPS\DateTime::ts( $event->saved );
$document->addItem( $event->title, $event->url(), $event->content, $next, $event->id );
}
/* @note application/rss+xml is not a registered IANA mime-type so we need to stick with text/xml for RSS */
+7 -7
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="103005" javascript_position="1000250"><![CDATA[/**
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.main.js" javascript_type="controller" javascript_version="103038" javascript_position="1000250"><![CDATA[/**
* Invision Community
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
*
@@ -112,7 +112,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="103005" javascript_position="1000250"><![CDATA[/**
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.monthView.js" javascript_type="controller" javascript_version="103038" javascript_position="1000250"><![CDATA[/**
* Invision Community
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
*
@@ -254,7 +254,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="103005" 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="103038" javascript_position="1000100"><![CDATA[/**
* Invision Community
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
*
@@ -699,7 +699,7 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/venue" javascript_name="ips.venue.main.js" javascript_type="controller" javascript_version="103005" javascript_position="1000200"><![CDATA[/**
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/venue" javascript_name="ips.venue.main.js" javascript_type="controller" javascript_version="103038" javascript_position="1000200"><![CDATA[/**
* Invision Community
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
*
@@ -811,7 +811,7 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/view" javascript_name="ips.view.reminderButton.js" javascript_type="controller" javascript_version="103005" javascript_position="1000150"><![CDATA[/**
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/view" javascript_name="ips.view.reminderButton.js" javascript_type="controller" javascript_version="103038" javascript_position="1000150"><![CDATA[/**
* Invision Community
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
*
@@ -894,7 +894,7 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/view" javascript_name="ips.view.reminderForm.js" javascript_type="controller" javascript_version="103005" javascript_position="1000150">/**
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/view" javascript_name="ips.view.reminderForm.js" javascript_type="controller" javascript_version="103038" javascript_position="1000150">/**
* Invision Community
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
*
@@ -1004,7 +1004,7 @@
});
}(jQuery, _));
</file>
<file javascript_app="calendar" javascript_location="front" javascript_path="templates" javascript_name="ips.calendar.templates.js" javascript_type="framework" javascript_version="103005" javascript_position="1000050"><![CDATA[/**
<file javascript_app="calendar" javascript_location="front" javascript_path="templates" javascript_name="ips.calendar.templates.js" javascript_type="framework" javascript_version="103038" javascript_position="1000050"><![CDATA[/**
* Invision Community
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
*/
+6 -2
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<language>
<app key="calendar" version="103005">
<app key="calendar" version="103038">
<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>
@@ -48,6 +48,9 @@
<word key="calendar_rss_feed" js="0">Enable upcoming events RSS feed</word>
<word key="calendar_rss_feed_desc" js="0"><![CDATA[Only content that is available to guests will be shown. For more options, create a <a href='{internal.app=core&module=discovery&controller=rss}'>Custom RSS Feed</a>]]></word>
<word key="calendar_rss_feed_days" js="0">Number of forthcoming days to include in the feed</word>
<word key="calendar_rss_feed_order" js="0">Order feed by</word>
<word key="calendar_rss_feed_order_date" js="0">Event Date</word>
<word key="calendar_rss_feed_order_publish" js="0">Publish Date</word>
<word key="acplogs__calendar_settings" js="0">Updated calendar settings</word>
<word key="calendar_default_view" js="0">Default layout</word>
<word key="calendar_default_view_desc" js="0">This setting allows you to control the default layout of the calendar homepage. Users can override the default view if they wish.</word>
@@ -64,7 +67,7 @@
<word key="calendar_custom_df" js="0">Or specify a custom date format</word>
<word key="calendar_date_format" js="0">Date format for events</word>
<word key="calendar_date_format_custom" js="0">Custom date format</word>
<word key="calendar_date_format_custom_desc" js="0"><![CDATA[You can use any <a href='{external.php-strftime}' target='_blank'>PHP strftime</a> options to specify a custom format for dates in calendar]]></word>
<word key="calendar_date_format_custom_desc" js="0"><![CDATA[You can use any <a href='{external.php-strftime}' target='_blank' rel='noopener'>PHP strftime</a> options to specify a custom format for dates in calendar]]></word>
<word key="calendar_no_date_format" js="0">You must either choose a predefined date format or specify a custom date format</word>
<word key="calendars" js="0">Calendars</word>
<word key="calendars_sg" js="0">Calendar</word>
@@ -258,6 +261,7 @@
<word key="end_date_before_start" js="0">Please select an end date after the event start date</word>
<word key="invalid_start_date" js="0">The provided start date is not valid</word>
<word key="invalid_end_date" js="0">The provided end date is not valid</word>
<word key="invalid_recurrence" js="0">The event cannot repeat that frequently. Each occurrence must end before the next starts.</word>
<word key="event__save" js="0">Save</word>
<word key="calendar_delete_title" js="0">Delete this event</word>
<word key="blurb_date_with_time" js="0">%s %s</word>
+1 -1
View File
@@ -1471,7 +1471,7 @@
"comment": "The member ID of the review author",
"decimals": null,
"default": "0",
"length": 8,
"length": 20,
"name": "review_mid",
"type": "BIGINT",
"unsigned": true,
+5
View File
@@ -29,6 +29,11 @@
"default": "30",
"report": "full"
},
{
"key": "calendar_rss_feed_order",
"default": "0",
"report": "full"
},
{
"key": "calendar_venues_enabled",
"default": "0",
+26 -7
View File
@@ -288,7 +288,7 @@
<li class='cEvents_ranged'>
<ul class='cEvents'>
{{foreach $events[ $date->year . '-' . $date->mon . '-' . $k ]['ranged'] as $event }}
<li class='cEvents_event cEvents_style{$event->calendar_id}{{if $event->nextOccurrence( \IPS\calendar\Date::getDate( $date->year, $date->mon, $k ), 'startDate' ) AND $event->nextOccurrence( \IPS\calendar\Date::getDate( $date->year, $date->mon, $k ), 'startDate' )->mysqlDatetime( FALSE, TRUE ) == $date->year . '-' . $date->mon . '-' . $k }}{{$startDates[ $event->id ] = $date->year . '-' . $date->mon . '-' . $k;}} cEvents_first{{endif}}{{if $event->nextOccurrence( \IPS\calendar\Date::getDate( $date->year, $date->mon, $k ) ?: $event->nextOccurrence( \IPS\calendar\Date::getDate( $date->year, $date->mon, $k ), 'startDate' ), 'endDate' ) AND $event->nextOccurrence( \IPS\calendar\Date::getDate( $date->year, $date->mon, $k ) ?: $event->nextOccurrence( \IPS\calendar\Date::getDate( $date->year, $date->mon, $k ), 'startDate' ), 'endDate' )->mysqlDatetime( FALSE, TRUE ) == $date->year . '-' . $date->mon . '-' . $k }} cEvents_last{{endif}}' data-eventID='{$event->id}'>
<li class='cEvents_event cEvents_style{$event->calendar_id}{{if $event->nextOccurrence( \IPS\calendar\Date::getDate( $date->year, $date->mon, $k ), 'startDate' ) AND $event->nextOccurrence( \IPS\calendar\Date::getDate( $date->year, $date->mon, $k ), 'startDate' )->mysqlDatetime( FALSE ) == $date->year . '-' . $date->mon . '-' . $k }}{{$startDates[ $event->id ] = $date->year . '-' . $date->mon . '-' . $k;}} cEvents_first{{endif}}{{if $event->nextOccurrence( \IPS\calendar\Date::getDate( $date->year, $date->mon, $k ) ?: $event->nextOccurrence( \IPS\calendar\Date::getDate( $date->year, $date->mon, $k ), 'startDate' ), 'endDate' ) AND $event->nextOccurrence( \IPS\calendar\Date::getDate( $date->year, $date->mon, $k ) ?: $event->nextOccurrence( \IPS\calendar\Date::getDate( $date->year, $date->mon, $k ), 'startDate' ), 'endDate' )->mysqlDatetime( FALSE ) == $date->year . '-' . $date->mon . '-' . $k }} cEvents_last{{endif}}' data-eventID='{$event->id}'>
<a href='{$event->url()}' data-ipsHover data-ipsHover-target='{$event->url('hovercard')->setQuerystring( 'sd', isset( $startDates[ $event->id ] ) ? $startDates[ $event->id ] : $date->year . '-' . $date->mon . '-' . $k )}' title='{$event->title}'>{{if !$event->all_day}}<span class='cEvents_time'>{$event->_start_date->localeTime( FALSE )}</span> {{endif}}{truncate="$event->title" length="15"}{{if $event->hidden() === 1}} <i class='fa fa-warning'></i>{{endif}}</a>
</li>
{{endforeach}}
@@ -431,7 +431,7 @@
<li class='cEvents_ranged'>
<ul class='cEvents'>
{{foreach $events[ $day->year . '-' . $day->mon . '-' . $day->mday ]['ranged'] as $event }}
<li class='cEvents_event cEvents_style{$event->calendar_id}{{if $event->nextOccurrence( $day, 'startDate' ) AND $event->nextOccurrence( $day, 'startDate' )->mysqlDatetime( FALSE, TRUE ) == $day->mysqlDatetime( FALSE ) }}{{$startDates[ $event->id ] = $day->mysqlDatetime( FALSE );}} cEvents_first{{endif}}{{if $event->nextOccurrence( $day ?: $event->nextOccurrence( $day, 'startDate' ), 'endDate' ) AND $event->nextOccurrence( $day ?: $event->nextOccurrence( $day, 'startDate' ), 'endDate' )->mysqlDatetime( FALSE, TRUE ) == $day->mysqlDatetime( FALSE ) }} cEvents_last{{endif}}'>
<li class='cEvents_event cEvents_style{$event->calendar_id}{{if $event->nextOccurrence( $day, 'startDate' ) AND $event->nextOccurrence( $day, 'startDate' )->mysqlDatetime( FALSE ) == $day->mysqlDatetime( FALSE ) }}{{$startDates[ $event->id ] = $day->mysqlDatetime( FALSE );}} cEvents_first{{endif}}{{if $event->nextOccurrence( $day ?: $event->nextOccurrence( $day, 'startDate' ), 'endDate' ) AND $event->nextOccurrence( $day ?: $event->nextOccurrence( $day, 'startDate' ), 'endDate' )->mysqlDatetime( FALSE ) == $day->mysqlDatetime( FALSE ) }} cEvents_last{{endif}}'>
<a href='{$event->url()}' data-ipsHover data-ipsHover-target='{$event->url('hovercard')->setQuerystring( 'sd', isset( $startDates[ $event->id ] ) ? $startDates[ $event->id ] : $day->mysqlDatetime( FALSE ) )}'>{$event->title}{{if $event->hidden() === 1}} <i class='fa fa-warning'></i>{{endif}}</a>
</li>
{{endforeach}}
@@ -1158,13 +1158,13 @@
</div>
<div class='cCalendarSubmit_field' id='end_time_wrap'>
<i class='fa fa-clock-o'></i>
<input name="event_dates[end_time]" id="end_time" type="time" size='12' class="ipsField_short" placeholder="{lang="_time_format_hhmm"}" step='60' min='00:00' value="{$value['end_time']}">
<input name="event_dates[end_time]" id="end_time" type="time" size='12' class="ipsField_short" placeholder="{lang="_time_format_hhmm"}" step='60' min='00:00' value="{{if isset( $value['end_time'] )}}{$value['end_time']}{{endif}}">
</div>
<br><br>
<ul class='ipsList_inline' id='end_date_controls'>
<li>
<span class='ipsCustomInput'>
<input type="checkbox" role="checkbox" name="event_dates[no_end_time]" {{if !$value['end_time']}}checked aria-checked='true'{{endif}} value="1" id="check_no_end_time">
<input type="checkbox" role="checkbox" name="event_dates[no_end_time]" {{if !isset( $value['end_time'] ) OR !$value['end_time']}}checked aria-checked='true'{{endif}} value="1" id="check_no_end_time">
<span></span>
</span> <label for='check_no_end_time'>{lang="no_end_time"}</label>
</li>
@@ -1557,7 +1557,13 @@
<time content='{expression="$event->_end_date->format( 'Y-m-d' )"}'>
{{$sameDay = !( ($event->_start_date->mday != $event->_end_date->mday) or ($event->_start_date->mon != $event->_end_date->mon) or ($event->_start_date->year != $event->_end_date->year) );}}
{{if $event->nextOccurrence( $event->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' ) ?: \IPS\calendar\Date::getDate(), 'endDate' )}}
{{if !$sameDay}}{$event->nextOccurrence( $event->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' ) ?: \IPS\calendar\Date::getDate(), 'endDate' )->calendarDate()}{{endif}}{{if !$event->all_day}}{{if !$sameDay}}, {{endif}}{$event->nextOccurrence( $event->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' ) ?: \IPS\calendar\Date::getDate(), 'endDate' )->localeTime( FALSE )}{{endif}}
{{if !$sameDay}}
{$event->nextOccurrence( $event->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' ) ?: \IPS\calendar\Date::getDate(), 'endDate' )->calendarDate()}
{{endif}}
{{if !$event->all_day}}
{{if !$sameDay}}, {{endif}}
{$event->nextOccurrence( $event->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' ) ?: \IPS\calendar\Date::getDate(), 'endDate' )->localeTime( FALSE )}
{{endif}}
{{else}}
{$event->lastOccurrence( 'endDate' )->calendarDate()}{{if !$event->all_day}} {$event->lastOccurrence( 'endDate' )->localeTime( FALSE )}{{endif}}
{{endif}}
@@ -1590,10 +1596,18 @@
{{$startDate = $event->nextOccurrence( \IPS\calendar\Date::getDate( $date->year, $date->mon, 1 ), 'startDate' );}}
{{endif}}
{{if $startDate}}
{{$sameDay = ( $event->nextOccurrence( $startDate ?: $date, 'endDate' ) ) AND ( $startDate->calendarDate() == $event->nextOccurrence( $startDate ?: $date, 'endDate' )->calendarDate() );}}
{{$nextEndDate = $event->nextOccurrence( $startDate ?: $date, 'endDate' );}}
{{$sameDay = ( $nextEndDate AND $startDate->calendarDate() == $nextEndDate->calendarDate() );}}
{$startDate->calendarDate()}{{if !$event->all_day}} {$startDate->localeTime( FALSE )} {{endif}}
{{if $event->_end_date AND $event->nextOccurrence( $startDate ?: $date, 'endDate' ) }}
&nbsp;&nbsp;<i class='fa fa-arrow-circle-right ipsType_large ipsType_light'></i>&nbsp;&nbsp;{{if !$sameDay}}{$event->nextOccurrence( $startDate ?: $date, 'endDate' )->calendarDate()}{{endif}}{{if !$event->all_day}}{{if !$sameDay}} {{endif}}{$event->nextOccurrence( $startDate ?: $date, 'endDate' )->localeTime( FALSE )}{{endif}}
&nbsp;&nbsp;<i class='fa fa-arrow-circle-right ipsType_large ipsType_light'></i>&nbsp;&nbsp;
{{if !$sameDay}}
{$event->nextOccurrence( $startDate ?: $date, 'endDate' )->calendarDate()}
{{endif}}
{{if !$event->all_day}}
{{if !$sameDay}} {{endif}}
{$event->nextOccurrence( $startDate ?: $date, 'endDate' )->localeTime( FALSE )}
{{endif}}
{{endif}}
{{else}}
{$event->lastOccurrence( 'startDate' )->calendarDate()}{{if !$event->all_day}} {$event->lastOccurrence( 'startDate' )->localeTime( FALSE )} {{endif}}
@@ -2602,6 +2616,11 @@
#elEventHeader_details time p .fa-arrow-circle-right:before{
content:"\f0ab";
}
.cCalendarBlock .cCalendarBlock_map {
display: block;
float: none;
}
}]]></css>
<css css_location="front" css_app="calendar" css_attributes="" css_path="." css_name="calendar.css"><![CDATA[.cCalendar {
width: 100%;
+35 -1
View File
@@ -217,9 +217,43 @@
"102046": "4.2.7",
"102047": "4.2.8",
"102048": "4.2.8",
"102049": "4.2.9",
"103000": "4.3.0 Beta 1",
"103002": "4.3.0 Beta 2",
"103003": "4.3.0 Beta 3",
"103004": "4.3.0 Beta 4",
"103005": "4.3.0"
"103005": "4.3.0",
"103006": "4.3.1",
"103007": "4.3.1",
"103008": "4.3.1",
"103009": "4.3.2",
"103010": "4.3.2",
"103011": "4.3.3",
"103012": "4.3.3",
"103013": "4.3.3",
"103014": "4.3.3",
"103015": "4.3.3",
"103016": "4.3.3",
"103017": "4.3.3",
"103018": "4.3.3",
"103019": "4.3.3",
"103020": "4.3.3",
"103021": "4.3.4",
"103022": "4.3.4",
"103023": "4.3.4",
"103024": "4.3.4",
"103025": "4.3.4",
"103026": "4.3.5 Beta 1",
"103027": "4.3.5 Beta 2",
"103028": "4.3.5",
"103029": "4.3.5",
"103030": "4.3.5",
"103031": "4.3.5",
"103032": "4.3.5",
"103033": "4.3.6 Beta 1",
"103034": "4.3.6 Beta 2",
"103035": "4.3.6",
"103036": "4.3.6",
"103037": "4.3.6",
"103038": "4.3.6"
}
@@ -23,9 +23,15 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _Calendars
{
/**
* @brief ID Field
*/
public static $idField = "id";
public static $controllers = array();
/**
* @brief Controller classes
*/
public static $controllers = array( "IPS\\calendar\\modules\\front\\calendar\\view" );
/**
* Get Setting Field
@@ -48,14 +48,15 @@ class _Calendar
/**
* Permission check for attachments
*
* @param \IPS\Member $member The member
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @param \IPS\Member $member The member
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @param array $attachment The attachment data
* @param bool $viewOnly If true, just check if the user can see the attachment rather than download it
* @return bool
*/
public function attachmentPermissionCheck( $member, $id1, $id2, $id3, $attachment )
public function attachmentPermissionCheck( $member, $id1, $id2, $id3, $attachment, $viewOnly=FALSE )
{
try
{
@@ -54,9 +54,10 @@ class _Venue
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @param array $attachment The attachment data
* @param bool $viewOnly If true, just check if the user can see the attachment rather than download it
* @return bool
*/
public function attachmentPermissionCheck( $member, $id1, $id2, $id3, $attachment )
public function attachmentPermissionCheck( $member, $id1, $id2, $id3, $attachment, $viewOnly=FALSE )
{
return TRUE;
}
@@ -47,10 +47,14 @@ class _StreamItems
}
foreach ( \IPS\Db::i()->select( '*', 'calendar_event_rsvp', $where, 'rsvp_date DESC', 10 ) as $rsvp )
{
$member = \IPS\Member::load( $rsvp['rsvp_member_id'] );
$event = \IPS\calendar\Event::load( $rsvp[ 'rsvp_event_id' ] );
$title = htmlspecialchars( $event->title, ENT_DISALLOWED, 'UTF-8', FALSE );
$rsvps[] = new \IPS\Content\Search\Result\Custom( \IPS\DateTime::ts( $rsvp[ 'rsvp_date' ] ), \IPS\Member::loggedIn()->language()->addToStack( 'calendar_activity_stream_rsvp', FALSE, array( 'htmlsprintf' => array( \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->userLink( $member ), $event->url(), $title ) ) ) );
if( $event->canView() )
{
$member = \IPS\Member::load( $rsvp['rsvp_member_id'] );
$title = htmlspecialchars( $event->title, ENT_DISALLOWED, 'UTF-8', FALSE );
$rsvps[] = new \IPS\Content\Search\Result\Custom( \IPS\DateTime::ts( $rsvp[ 'rsvp_date' ] ), \IPS\Member::loggedIn()->language()->addToStack( 'calendar_activity_stream_rsvp', FALSE, array( 'htmlsprintf' => array( \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->userLink( $member ), $event->url(), $title ) ) ) );
}
}
/* Return */
@@ -255,7 +255,7 @@ class _ical extends \IPS\Dispatcher\Controller
try
{
$icsParser = new \IPS\calendar\Icalendar\ICSParser;
$count = $icsParser->parse( \file_get_contents( $values['feed_file'] ), $values['feed_calendar_id'], $values['feed_member_id'], $values['feed_venue_id'] );
$count = $icsParser->parse( \file_get_contents( $values['feed_file'] ), $values['feed_calendar_id'], $values['feed_member_id'], ( isset( $values['feed_venue_id'] ) ) ? $values['feed_venue_id']->_id : NULL );
}
catch( \UnexpectedValueException $e )
{
@@ -53,8 +53,15 @@ class _settings extends \IPS\Dispatcher\Controller
$form->add( new \IPS\Helpers\Form\YesNo( 'show_bday_calendar', \IPS\Settings::i()->show_bday_calendar ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'ipb_calendar_mon', \IPS\Settings::i()->ipb_calendar_mon ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'calendar_rss_feed', \IPS\Settings::i()->calendar_rss_feed, FALSE, array( 'togglesOn' => array( 'calendar_rss_feed_days' ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'calendar_rss_feed', \IPS\Settings::i()->calendar_rss_feed, FALSE, array( 'togglesOn' => array( 'calendar_rss_feed_days', 'calendar_rss_feed_order' ) ) ) );
$form->add( new \IPS\Helpers\Form\Number( 'calendar_rss_feed_days', \IPS\Settings::i()->calendar_rss_feed_days, FALSE, array( 'unlimited' => -1 ), NULL, NULL, NULL, 'calendar_rss_feed_days' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'calendar_rss_feed_order', \IPS\Settings::i()->calendar_rss_feed_order, FALSE, array( 'options' => array(
0 => 'calendar_rss_feed_order_date',
1 => 'calendar_rss_feed_order_publish'
) ), NULL, NULL, NULL, 'calendar_rss_feed_order' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'calendar_venues_enabled', \IPS\Settings::i()->calendar_venues_enabled ) );
@@ -150,7 +150,7 @@ class _event extends \IPS\Content\Controller
$this->event->lastOccurrence( 'endDate' )->format( \IPS\DateTime::ISO8601 );
}
if( $this->event->container()->allow_reviews AND $this->event->reviews )
if( $this->event->container()->allow_reviews AND $this->event->reviews AND $this->event->averageReviewRating() )
{
\IPS\Output::i()->jsonLd['event']['aggregateRating'] = array(
'@type' => 'AggregateRating',
@@ -178,6 +178,13 @@ class _submit extends \IPS\Dispatcher\Controller
{
$obj = \IPS\calendar\Event::createFromForm( $values );
/* Set cover photo offset from original if we're using the same photo */
if( $existing->cover_photo == $obj->cover_photo )
{
$obj->cover_offset = $existing->cover_offset;
$obj->save();
}
if ( !\IPS\Member::loggedIn()->member_id and $obj->hidden() )
{
\IPS\Output::i()->redirect( $obj->container()->url(), 'mod_queue_message' );
@@ -547,7 +547,7 @@ class _view extends \IPS\Dispatcher\Controller
{
/* Build the form */
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\Date( 'jump_to', $this->_today, TRUE, array(), NULL, NULL, NULL, 'jump_to' ) );
$form->add( new \IPS\Helpers\Form\Date( 'jump_to', \IPS\DateTime::create(), TRUE, array(), NULL, NULL, NULL, 'jump_to' ) );
if( $values = $form->values() )
{
@@ -75,5 +75,18 @@
]
}
]
},
"5": {
"method": "update",
"params": [
"core_sys_lang_words",
{
"word_app": "calendar"
},
[
"word_app=? AND word_key LIKE '%calendar_venue_%'",
"venues"
]
]
}
}
@@ -28,19 +28,19 @@
]
},
"5": {
"method": "dropIndex",
"params": [
"cal_events",
"approved"
]
},
"6": {
"method": "renameTable",
"params": [
"cal_events",
"calendar_events"
]
},
"6": {
"method": "dropIndex",
"params": [
"calendar_events",
"approved"
]
},
"7": {
"method": "changeColumn",
"params": [
+20 -13
View File
@@ -95,9 +95,14 @@ class _Date extends \IPS\DateTime
public static function getDate( $year=NULL, $month=NULL, $day=NULL, $hour=0, $minute=0, $second=0, $offset=NULL )
{
/* Get our time zone offset */
$timezone = NULL;
if ( $offset === NULL and \IPS\Member::loggedIn()->timezone )
{
$offset = \IPS\DateTime::create()->setTimezone( new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) )->getOffset();
$timezone = \IPS\DateTime::create();
$timezone->setTimezone( new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) );
$offset = $timezone->getOffset();
}
/* Set appropriate defaults for values not supplied, which is normal */
@@ -125,6 +130,14 @@ class _Date extends \IPS\DateTime
/* Create the timestamp */
$timeStamp = gmmktime( $hour, $minute, $second, $month, $day, $year );
/* Recalculate offset in case we go over DST boundary */
if( $timezone )
{
$timeZoneCheck = $timezone->setTimestamp( $timeStamp );
$offset = $timeZoneCheck->getOffset();
}
/* Store the information and return the object */
$obj = static::ts( $timeStamp - $offset );
$obj->getDateInformation( $timeStamp );
@@ -180,7 +193,7 @@ class _Date extends \IPS\DateTime
*
* @note This is basically a timezone aware wrapper for getdate
* @param int $time Timestamp
* @return void
* @return array
*/
public function getDateInformation( $time )
{
@@ -197,6 +210,7 @@ class _Date extends \IPS\DateTime
'month' => $this->strFormat( '%B' ),
0 => $time
);
return $this->dateInformation;
}
/**
@@ -519,25 +533,18 @@ class _Date extends \IPS\DateTime
/**
* Return the MySQL-style datetime value
*
* @param bool $includeTime Whether to include time or not
* @param bool $timezoned Whether to adjust for timezone or not. This will usually be FALSE for database purposes, but set to TRUE if you're using this to compare if two dates are on the same day
* @param bool $includeTime Whether to include time or not
* @return string
*/
public function mysqlDatetime( $includeTime=TRUE, $timezoned = FALSE )
public function mysqlDatetime( $includeTime=TRUE )
{
$timeStamp = isset( $this->dateInformation[0] ) ? $this->dateInformation[0] : $this->getTimestamp();
if ( $timezoned )
{
$timeStamp += $this->getTimezone()->getOffset( $this );
}
if( $includeTime )
{
return date( 'Y-m-d H:i:s', $timeStamp );
return date( 'Y-m-d H:i:s', isset( $this->dateInformation[0] ) ? $this->dateInformation[0] : $this->getTimestamp() );
}
else
{
return date( 'Y-m-d', $timeStamp );
return date( 'Y-m-d', isset( $this->dateInformation[0] ) ? $this->dateInformation[0] : $this->getTimestamp() );
}
}
+68 -23
View File
@@ -564,7 +564,8 @@ class _Event extends \IPS\Content\Item implements
( $eDate !== NULL AND $date->mysqlDatetime( FALSE ) <= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) >= $endDate->mysqlDatetime( FALSE ) )
)
{
$results[] = array( 'startDate' => new \IPS\calendar\Date( $dateOccurrence->mysqlDatetime( FALSE, TRUE ) ), 'endDate' => $eDate );
$thisOccurrence = $dateOccurrence->getDateInformation( $dateOccurrence->getTimestamp() );
$results[] = array( 'startDate' => \IPS\calendar\Date::getDate( $thisOccurrence['year'], $thisOccurrence['mon'], $thisOccurrence['mday'], $thisOccurrence['hours'], $thisOccurrence['minutes'], $thisOccurrence['seconds'] ), 'endDate' => $eDate );
}
$eDate = ( $eDate !== NULL ) ? $eDate->adjust( "+{$recurringData['event_repeat_freq']} {$keyword}" ) : NULL;
@@ -584,7 +585,8 @@ class _Event extends \IPS\Content\Item implements
( $eDate !== NULL AND $date->mysqlDatetime( FALSE ) <= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) >= $endDate->mysqlDatetime( FALSE ) )
)
{
$results[] = array( 'startDate' => new \IPS\calendar\Date( $dateOccurrence->mysqlDatetime( FALSE, TRUE ) ), 'endDate' => $eDate );
$thisOccurrence = $dateOccurrence->getDateInformation( $dateOccurrence->getTimestamp() );
$results[] = array( 'startDate' => \IPS\calendar\Date::getDate( $thisOccurrence['year'], $thisOccurrence['mon'], $thisOccurrence['mday'], $thisOccurrence['hours'], $thisOccurrence['minutes'], $thisOccurrence['seconds'] ), 'endDate' => $eDate );
}
$eDate = ( $eDate !== NULL ) ? $eDate->adjust( "+{$recurringData['event_repeat_freq']} {$keyword}" ) : NULL;
@@ -602,7 +604,8 @@ class _Event extends \IPS\Content\Item implements
( $eDate !== NULL AND $date->mysqlDatetime( FALSE ) <= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) >= $endDate->mysqlDatetime( FALSE ) )
)
{
$results[] = array( 'startDate' => new \IPS\calendar\Date( $dateOccurrence->mysqlDatetime( FALSE, TRUE ) ), 'endDate' => $eDate );
$thisOccurrence = $dateOccurrence->getDateInformation( $dateOccurrence->getTimestamp() );
$results[] = array( 'startDate' => \IPS\calendar\Date::getDate( $thisOccurrence['year'], $thisOccurrence['mon'], $thisOccurrence['mday'], $thisOccurrence['hours'], $thisOccurrence['minutes'], $thisOccurrence['seconds'] ), 'endDate' => $eDate );
}
$eDate = ( $eDate !== NULL ) ? $eDate->adjust( "+{$recurringData['event_repeat_freq']} {$keyword}" ) : NULL;
@@ -1132,9 +1135,9 @@ class _Event extends \IPS\Content\Item implements
$val['start_time'] = str_replace( '.', ':', $val['start_time'] );
}
if( isset( $val['no_end_time'] ) AND $val['no_end_time'] AND isset( $val['end_time'] ) )
if ( isset( $val['no_end_time'] ) AND $val['no_end_time'] AND ( isset( $val['end_time'] ) OR isset( $val['end_date'] ) ) )
{
unset( $val['end_time'] );
unset( $val['end_time'], $val['end_date'] );
}
if( isset( $val['end_time'] ) )
@@ -1152,7 +1155,7 @@ class _Event extends \IPS\Content\Item implements
}
$end = null;
if( isset( $val['end_date'] ) AND $val['end_date'] )
{
if( !isset( $val['single_day'] ) OR !$val['single_day'] )
@@ -1169,7 +1172,7 @@ class _Event extends \IPS\Content\Item implements
}
}
}
else
elseif( isset( $val['end_time'] ) )
{
try
{
@@ -1214,6 +1217,38 @@ class _Event extends \IPS\Content\Item implements
}
}
/* Check we are not trying to recur in such a way that a new occurance starts before
the last ends, which could cause timeouts if someone does something like sets an
event to recur every day and span many days */
if ( isset( $val['event_repeat'] ) and $val['event_repeat'] and $end )
{
$diff = intval( strtotime( $end ) ) - intval( strtotime( $start ) );
switch ( $val['event_repeats'] )
{
case 'daily':
$maxDiff = intval( $val['event_repeat_freq'] ) * 86400;
break;
case 'weekly':
$maxDiff = intval( $val['event_repeat_freq'] ) * 86400 * 7;
break;
case 'monthly':
$maxDiff = intval( $val['event_repeat_freq'] ) * 86400 * 31;
break;
case 'yearly':
$maxDiff = intval( $val['event_repeat_freq'] ) * 86400 * 365;
break;
}
if ( $diff > $maxDiff )
{
throw new \DomainException( "invalid_recurrence" );
}
}
}, NULL, NULL, 'event_dates' );
/* Init */
@@ -1230,16 +1265,18 @@ class _Event extends \IPS\Content\Item implements
/* Get default elements */
$return = array_merge( $return, parent::formElements( $item, $container ) );
/* Event description */
$return['description'] = new \IPS\Helpers\Form\Editor( 'event_content', $item ? $item->content : NULL, TRUE, array( 'app' => 'calendar', 'key' => 'Calendar', 'autoSaveKey' => 'calendar-event', 'attachIds' => ( $item === NULL ? NULL : array( $item->id, NULL, 'description' ) ) ) );
$return['description'] = new \IPS\Helpers\Form\Editor( 'event_content', $item ? $item->content : NULL, TRUE, array( 'app' => 'calendar', 'key' => 'Calendar', 'autoSaveKey' => ( $item === NULL ) ? 'calendar-event' : "calendar-event-{$item->id}", 'attachIds' => ( $item === NULL ? NULL : array( $item->id, NULL, 'description' ) ) ) );
/* 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' ) );
if( \IPS\Settings::i()->calendar_venues_enabled )
{
$return['venue'] = new \IPS\Helpers\Form\Node( static::$formLangPrefix . 'venue', ( $item ) ? $item->venue ?: 0 : ( isset( \IPS\Request::i()->venue ) ? \IPS\Request::i()->venue : NULL ), FALSE, array(
$roots = \IPS\calendar\Venue::roots();
$return['venue'] = new \IPS\Helpers\Form\Node( static::$formLangPrefix . 'venue', ( $item ) ? $item->venue ?: 0 : ( isset( \IPS\Request::i()->venue ) ? \IPS\Request::i()->venue : ( count( $roots ) ? NULL : 0 ) ), FALSE, array(
'url' => \IPS\Http\Url::internal( 'app=calendar&module=calendar&controller=submit', 'front', 'calendar_submit' ),
'class' => 'IPS\calendar\Venue',
'zeroVal' => 'venues_not_listed',
@@ -1355,7 +1392,7 @@ class _Event extends \IPS\Content\Item implements
$this->end_date = \IPS\calendar\Date::createFromForm( $values['event_dates']['end_date'], ( ( !isset( $values['event_dates']['all_day'] ) OR !$values['event_dates']['all_day'] ) ? $values['event_dates']['end_time'] : NULL ), ( isset( $values['event_dates']['all_day'] ) AND $values['event_dates']['all_day'] ) ? 'UTC' : $values['event_dates']['event_timezone'] )->format( 'Y-m-d H:i' );
}
}
else if( ( !isset( $values['event_dates']['all_day'] ) OR !$values['event_dates']['all_day'] ) AND $values['event_dates']['end_time'] != $values['event_dates']['start_time'] )
else if( ( !isset( $values['event_dates']['all_day'] ) OR !$values['event_dates']['all_day'] ) AND isset( $values['event_dates']['end_time'] ) AND $values['event_dates']['end_time'] != $values['event_dates']['start_time'] )
{
$this->end_date = \IPS\calendar\Date::createFromForm( $values['event_dates']['start_date'], $values['event_dates']['end_time'], ( isset( $values['event_dates']['all_day'] ) AND $values['event_dates']['all_day'] ) ? 'UTC' : $values['event_dates']['event_timezone'] )->format( 'Y-m-d H:i' );
}
@@ -1679,20 +1716,20 @@ class _Event extends \IPS\Content\Item implements
foreach( $events as $event )
{
/* Is this a ranged event? */
if( $event->_end_date !== NULL AND $event->_start_date->mysqlDatetime( FALSE ) < $event->_end_date->mysqlDatetime( FALSE ) )
if( $event->_end_date !== NULL AND $event->_start_date->mysqlDatetime( FALSE, TRUE ) < $event->_end_date->mysqlDatetime( FALSE, TRUE ) )
{
$date = $event->_start_date;
while( $date->mysqlDatetime( FALSE ) < $event->_end_date->mysqlDatetime( FALSE ) )
while( $date->mysqlDatetime( FALSE, TRUE ) < $event->_end_date->mysqlDatetime( FALSE, TRUE ) )
{
$formattedEvents[ $date->mysqlDatetime( FALSE ) ]['ranged'][ $event->id ] = $event;
$date = $date->adjust( '+1 day' );
}
$formattedEvents[ $event->_end_date->mysqlDatetime( FALSE ) ]['ranged'][ $event->id ] = $event;
$formattedEvents[ $event->_end_date->mysqlDatetime( FALSE, TRUE ) ]['ranged'][ $event->id ] = $event;
}
else
{
$formattedEvents[ $event->_start_date->mysqlDatetime( FALSE ) ]['single'][ $event->id ] = $event;
$formattedEvents[ $event->_start_date->mysqlDatetime( FALSE, TRUE ) ]['single'][ $event->id ] = $event;
}
}
}
@@ -1723,18 +1760,26 @@ class _Event extends \IPS\Content\Item implements
if( $occurrence['endDate'] !== NULL )
{
$date = $occurrence['startDate'];
$eDate = ( $thisEndDate->mysqlDatetime( FALSE ) < $occurrence['endDate']->mysqlDatetime( FALSE ) ) ? $thisEndDate : $occurrence['endDate'];
while( $date->mysqlDatetime( FALSE ) < $eDate->mysqlDatetime( FALSE ) )
{
$formattedEvents[ $date->mysqlDatetime( FALSE ) ]['ranged'][ $event->id ] = $event;
$date = $date->adjust( '+1 day' );
}
$eDate = ( $thisEndDate->mysqlDatetime( FALSE, TRUE ) < $occurrence['endDate']->mysqlDatetime( FALSE, TRUE ) ) ? $thisEndDate : $occurrence['endDate'];
$formattedEvents[ $occurrence['endDate']->mysqlDatetime( FALSE ) ]['ranged'][ $event->id ] = $event;
if( $date->mysqlDatetime( FALSE, TRUE ) < $eDate->mysqlDatetime( FALSE, TRUE ) )
{
while( $date->mysqlDatetime( FALSE, TRUE ) < $eDate->mysqlDatetime( FALSE, TRUE ) )
{
$formattedEvents[ $date->mysqlDatetime( FALSE ) ]['ranged'][ $event->id ] = $event;
$date = $date->adjust( '+1 day' );
}
$formattedEvents[ $occurrence['endDate']->mysqlDatetime( FALSE, TRUE ) ]['ranged'][ $event->id ] = $event;
}
else
{
$formattedEvents[ $date->mysqlDatetime( FALSE, TRUE ) ]['single'][ $event->id ] = $event;
}
}
else
{
$formattedEvents[ $occurrence['startDate']->mysqlDatetime( FALSE ) ]['single'][ $event->id ] = $event;
$formattedEvents[ $occurrence['startDate']->mysqlDatetime( FALSE, TRUE ) ]['single'][ $event->id ] = $event;
}
}
}
@@ -449,11 +449,20 @@ class _ICSParser
/* Basics */
$newEvent->title = ( isset( $event['summary'] ) AND $event['summary'] ) ? $event['summary'] : mb_substr( strip_tags( $event['description'] ), 0, 100 );
$newEvent->content = ( isset( $event['description'] ) AND $event['description'] ) ? nl2br( $event['description'] ) : $event['summary'] . ( isset( $event['location'] ) ? '<br>' . $event['location'] : '' );
$content = ( isset( $event['description'] ) AND $event['description'] ) ? nl2br( $event['description'] ) : $event['summary'] . ( isset( $event['location'] ) ? '<br>' . $event['location'] : '' );
$newEvent->content = \IPS\Text\Parser::parseStatic( $content, TRUE, NULL, $this->member );
$newEvent->sequence = ( isset( $event['sequence'] ) ? intval( $event['sequence'] ) : 0 );
/* Times and dates */
$newEvent->lastupdated = ( isset( $event['last_modified'] ) AND $event['last_modified'] AND $event['last_modified'] < time() ) ? $event['last_modified'] : ( ( isset( $event['created'] ) AND $event['created'] AND $event['created'] < time() ) ? $event['created'] : time() );
if( isset( $event['last_modified'] ) AND $event['last_modified'] AND $event['last_modified'] < time() )
{
$newEvent->lastupdated = $event['last_modified'];
}
elseif( !$eventId )
{
$newEvent->lastupdated = ( isset( $event['created'] ) AND $event['created'] AND $event['created'] < time() ) ? $event['created'] : time();
}
$newEvent->all_day = $event_all_day;
$newEvent->recurring = ( isset( $event['recurr'] ) ) ? $event['recurr'] : NULL;
$newEvent->start_date = $event_unix_from->setTimezone( new \DateTimeZone( 'UTC' ) )->format( 'Y-m-d H:i:s' );
@@ -462,11 +471,27 @@ class _ICSParser
/* Geolocation? */
if( isset( $event['geo'] ) AND is_array( $event['geo'] ) AND count( $event['geo'] ) )
{
try
/* If we are updating an event, don't pull geo data if we already have it and it hasn't changed */
$update = TRUE;
if( $newEvent->location )
{
$newEvent->location = json_encode( \IPS\GeoLocation::getByLatLong( $event['geo']['lat'], $event['geo']['long'] ) );
$existingLocation = json_decode( $newEvent->location, true );
if( isset( $existingLocation['lat'] ) AND $existingLocation['lat'] == $event['geo']['lat'] AND isset( $existingLocation['long'] ) AND $existingLocation['long'] == $event['geo']['long'] )
{
$update = FALSE;
}
}
if( $update === TRUE )
{
try
{
$newEvent->location = json_encode( \IPS\GeoLocation::getByLatLong( $event['geo']['lat'], $event['geo']['long'] ) );
}
catch( \BadFunctionCallException $e ){}
}
catch( \BadFunctionCallException $e ){}
}
elseif( isset( $event['location'] ) )
{
@@ -474,10 +499,9 @@ class _ICSParser
{
$location = new \IPS\GeoLocation;
$location->addressLines = array( $event['location'] );
$location->getLatLong();
$location->getLatLong( TRUE );
/* We get by LatLong because getLatLong() does not populate the other address data. */
$newEvent->location = json_encode( \IPS\GeoLocation::getByLatLong( $location->lat, $location->long ) );
$newEvent->location = json_encode( $location );
}
catch( \BadFunctionCallException $e ){}
}
@@ -190,6 +190,7 @@ class _Venue extends \IPS\Node\Model
*/
public function delete()
{
\IPS\Lang::deleteCustom( 'calendar', 'calendar_venue_' . $this->id );
\IPS\Lang::deleteCustom( 'calendar', 'calendar_venue_' . $this->id . '_desc' );
return parent::delete();
+2 -2
View File
@@ -49,11 +49,11 @@ class _icalendar extends \IPS\Task
}
catch( \Exception $e )
{
throw new \IPS\Task\Exception( $this, \IPS\Member::loggedIn()->language()->addToStack( 'task_' . $e->getMessage(), FALSE, array( 'sprintf' => array( $next['feed_title'] ) ) ) );
throw new \IPS\Task\Exception( $this, array( 'task_' . $e->getMessage(), $next['feed_title'] ) );
}
/* Task log */
return \IPS\Member::loggedIn()->language()->addToStack( 'acplog__icalfeed_refreshed', FALSE, array( 'sprintf' => array( $count['imported'], $count['skipped'] ) ) );
return NULL;
}
}
catch( \UnderflowException $e )
@@ -38,6 +38,25 @@ class _todaysBirthdays extends \IPS\Widget
*/
public $plugin = '';
/**
* 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 );
}
/**
* Specify widget configuration
*