Initial commit

This commit is contained in:
Joey Kimsey
2024-08-04 21:15:59 -04:00
parent c9d1fb983f
commit 0d469501ee
695 changed files with 70184 additions and 71 deletions

View File

@ -0,0 +1,593 @@
<?php
/**
* app/plugins/calendar/controllers/calendar.php
*
* This is the calendar controller.
*
* @package TP Calendar
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Controllers;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Session;
use TheTempusProject\Bedrock\Functions\Date;
use TheTempusProject\Classes\Controller;
use TheTempusProject\Houdini\Classes\Forms as HoudiniForms;
use TheTempusProject\Classes\Forms;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Houdini\Classes\Template;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Models\Events;
use TheTempusProject\Models\Calendars;
use TheTempusProject\Houdini\Classes\Navigation;
class Calendar extends Controller {
protected static $events;
protected static $calendars;
protected static $defaultView;
protected static $defaultCalendar;
protected static $selectedDate;
public function __construct() {
if ( !App::$isLoggedIn ) {
Session::flash( 'notice', 'You must be logged in to create or manage calendars.' );
return Redirect::home();
}
parent::__construct();
self::$title = 'Calendar - {SITENAME}';
self::$pageDescription = 'The {SITENAME} calendar is where you can find various features for creating and managing events and schedules.';
self::$events = new Events;
self::$calendars = new Calendars;
$prefs = App::$activePrefs;
if ( ! empty( $prefs['calendarPreference'] ) ) {
$view = $prefs['calendarPreference'];
} else {
Session::flash( 'info', 'You can select a default view for this page in your user settings in the top right.' );
$view = 'byMonth';
}
self::$defaultView = $view;
self::$selectedDate = intval( strtotime( Date::determineDateInput() ) );
Template::setTemplate( 'calendar' );
// Date Dropdown
$dateDropdownView = Views::simpleView('calendar.nav.dateDropdown', Date::getDateBreakdown( self::$selectedDate ) );
Components::set( 'dateDropdown', $dateDropdownView );
// Calendar Top Tabs
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
$tabsView = Navigation::activePageSelect( $calendarTabs, Input::get( 'url' ), false, true );
// must be done after top-nav gets selected
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
Components::set( 'calendarDropdown', $calendarDropdownView);
// must be done after dropdown gets added
Components::set( 'CalendarNav', Template::parse( $calendarTabs ) );
}
public function index() {
if ( method_exists( $this, self::$defaultView ) ) {
Redirect::to( 'calendar/'.self::$defaultView.'/' );
} else {
Redirect::to( 'calendar/byMonth/' );
}
}
/**
* Events
*/
public function event( $id = null ) {
$event = $this->findEventOrFail( $id );
Views::view( 'calendar.events.view', $event );
}
public function createEvent() {
// get the url calendar input
$newCalendar = Input::get('calendar_id') ? Input::get('calendar_id') : '';// for loading the form
$calendarSelect = HoudiniForms::getFormFieldHtml( 'calendar_id', 'Calendar', 'select', $newCalendar, self::$calendars->simpleByUser() );
Components::set( 'calendarSelect', $calendarSelect );
$repeatSelect = HoudiniForms::getFormFieldHtml( 'repeats', 'Frequency', 'select', 'none', self::$events->repeatOptions );
Components::set( 'repeatSelect', $repeatSelect );
$dateSelect = Views::simpleView( 'calendar.dateSelect', $this->getEventBreakdown( self::$selectedDate ) );
Components::set( 'dateSelect', $dateSelect );
if ( ! Input::exists() ) {
return Views::view( 'calendar.events.create' );
}
/** Attempt to save the form data somewhat */
// get the form calendar input
$calendarID = Input::post('calendar_id') ? Input::post('calendar_id') : ''; // for submitting the form
$calendarSelect = HoudiniForms::getFormFieldHtml( 'calendar_id', 'Calendar', 'select', $calendarID, self::$calendars->simpleByUser() );
Components::set( 'calendarSelect', $calendarSelect );
$repeatSelect = HoudiniForms::getFormFieldHtml( 'repeats', 'Frequency', 'select', Input::post('repeats'), self::$events->repeatOptions );
Components::set( 'repeatSelect', $repeatSelect );
if ( ! Forms::check( 'createEvent' ) ) {
Issues::add( 'error', [ 'There was an error with your form.' => Check::userErrors() ] );
return Views::view( 'calendar.events.create' );
}
$event_id = self::$events->create(
$calendarID,
Input::post('title'),
Date::applyUtcToDate( Date::determineDateInput() ),
Input::post('description'),
Input::post('location'),
Input::post('repeats'),
Input::post('color'),
0,
);
if ( ! $event_id ) {
Issues::add( 'error', [ 'There was an error creating your event.' => Check::userErrors() ] );
return Views::view( 'calendar.events.create' );
}
if ( Input::post('repeats') != 'none' ) {
$childrens = self::$events->generateChildEvents( $event_id, true, true );
}
Session::flash( 'success', 'Your Event has been created.' );
Redirect::to( 'calendar/'.self::$defaultView.'/'. $calendarID );
}
public function editEvent( $id = null ) {
$calendar = Input::exists('calendar_id') ? Input::post('calendar_id') : '';
$event = self::$events->findById( $id );
$readableDate = date('Y-m-d H:i:s', $event->event_time);
if ( $event == false ) {
Session::flash( 'error', 'Event not found.' );
return Redirect::to( 'calendar/'.self::$defaultView.'/' );
}
if ( $event->createdBy != App::$activeUser->ID ) {
Session::flash( 'error', 'You do not have permission to modify this event.' );
return Redirect::to( 'calendar/'.self::$defaultView.'/' );
}
$repeatSelect = HoudiniForms::getFormFieldHtml( 'repeats', 'Frequency', 'select', $event->repeats, self::$events->repeatOptions );
Components::set( 'repeatSelect', $repeatSelect );
// there should be a way to do this natively
$event_at = Date::getDateBreakdown( $event->event_time, true );
// $readableDate = date('Y-m-d H:i:s', $readableDate);
$dateSelect = Views::simpleView( 'calendar.dateSelect', $event_at );
Components::set( 'dateSelect', $dateSelect );
Components::set( 'color', $event->color );
if ( ! Input::exists( 'submit' ) ) {
return Views::view( 'calendar.events.edit', $event );
}
if ( ! Forms::check( 'editEvent' ) ) {
Issues::add( 'error', [ 'There was an error updating your event.' => Check::userErrors() ] );
return Views::view( 'calendar.events.edit', $event );
}
$result = self::$events->update(
$id,
Input::post('title'),
Date::applyUtcToDate( Date::determineDateInput() ),
Input::post('description'),
Input::post('location'),
Input::post('repeats'),
Input::post('color'),
);
if ( Input::post('repeats') != 'none' && $event->parent_id == 0 ) {
$childrens = self::$events->generateChildEvents( $event->ID, true, true );
}
if ( ! $result ) {
Issues::add( 'error', [ 'There was an error updating your event.' => Check::userErrors() ] );
return Views::view( 'calendar.events.edit', $event->ID );
}
Session::flash( 'success', 'Your Event has been updated.' );
Redirect::to( 'calendar/'.self::$defaultView.'/'. $event->calendar_id );
}
public function deleteEvent( $id = null ) {
$event = self::$events->findById( $id );
if ( $event == false ) {
Issues::add( 'error', 'Event not found.' );
return $this->index();
}
if ( $event->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this event.' );
return $this->index();
}
$result = self::$events->delete( $id );
if ( !$result ) {
Session::flash( 'error', 'There was an error deleting the event(s)' );
} else {
Session::flash( 'success', 'Event deleted' );
}
return $this->index();
}
/**
* Calendars
*/
public function calendar( $id = null ) {
$calendar = $this->findCalendarOrFail( $id );
Views::view( 'calendar.calendar.view', $calendar );
}
public function createCalendar() {
$timezoneSelect = HoudiniForms::getTimezoneHtml( Date::getTimezone() );
Components::set( 'timezoneSelect', $timezoneSelect );
if ( ! Input::exists() ) {
return Views::view( 'calendar.calendar.create' );
}
if ( ! Forms::check( 'createCalendar' ) ) {
Issues::add( 'error', [ 'There was an error creating your calendar111.' => Check::userErrors() ] );
return Views::view( 'calendar.calendar.create' );
}
$calendar = self::$calendars->create( Input::post('title'), Input::post('description'), Input::post('timezone'), Input::post('color') );
if ( ! $calendar ) {
return Views::view( 'calendar.calendar.create' );
}
Session::flash( 'success', 'Your Calendar has been created.' );
Redirect::to( 'calendar/'.self::$defaultView.'/');
}
public function editCalendar( $id = null ) {
$calendar = $this->findCalendarOrFail( $id );
$timezoneSelect = HoudiniForms::getTimezoneHtml( Date::getTimezone() );
Components::set( 'timezoneSelect', $timezoneSelect );
Components::set( 'color', $calendar->color );
if ( ! Input::exists( 'submit' ) ) {
return Views::view( 'calendar.calendar.edit', $calendar );
}
if ( !Forms::check( 'editCalendar' ) ) {
Issues::add( 'error', [ 'There was an error editing your calendar.' => Check::userErrors() ] );
return Views::view( 'calendar.calendar.edit', $calendar );
}
$result = self::$calendars->update( $id, Input::post('title'), Input::post('description'), Input::post('timezone'), Input::post('color') );
if ( !$result ) {
Issues::add( 'error', [ 'There was an error updating your calendar.' => Check::userErrors() ] );
return Views::view( 'calendar.calendar.edit', $calendar );
}
Session::flash( 'success', 'Your Calendar has been updated.' );
Redirect::to( 'calendar/'.self::$defaultView.'/'. $calendar->ID );
}
public function deleteCalendar( $id = null ) {
$calendar = self::$calendars->findById( $id );
if ( $calendar == false ) {
Issues::add( 'error', 'Calendar not found.' );
return $this->index();
}
if ( $calendar->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this calendar.' );
return $this->index();
}
$results = self::$events->deleteByCalendar( $id );
$result = self::$calendars->delete( $id );
if ( !$result ) {
Session::flash( 'error', 'There was an error deleting the calendar(s)' );
} else {
Session::flash( 'success', 'Calendar deleted' );
}
Redirect::to( 'calendar/'.self::$defaultView.'/' );
}
/**
* Views
*/
public function byDay( $id = 0 ) {
// Set base components
Components::set( 'currentView', __FUNCTION__ );
Components::set( 'calendarID', $id );
// Set components for next / back arrows
$nextDayMonth = date( 'M', strtotime( 'tomorrow', self::$selectedDate ) );
$nextDay = date( 'd', strtotime( 'tomorrow', self::$selectedDate ) );
$lastDayMonth = date( 'M', strtotime( 'yesterday', self::$selectedDate ) );
$lastDay = date( 'd', strtotime( 'yesterday', self::$selectedDate ) );
Components::set( 'nextDayMonth', $nextDayMonth );
Components::set( 'nextDay', $nextDay );
Components::set( 'lastDayMonth', $lastDayMonth );
Components::set( 'lastDay', $lastDay );
// Get the data
$dayArray = self::$events->dayArray( $id, self::$selectedDate );
// build the results
$selectedHour = Date::getCurrentHour();
$day = date( 'd', self::$selectedDate );
$month = date( 'M', self::$selectedDate );
$year = date( 'Y', self::$selectedDate );
$fullDay = [];
foreach ( $dayArray as $hour => $events ) {
Components::set( 'hour', $hour );
$hourCell = new \stdClass();
$hourCell->hour = $hour;
if ( $hour == $selectedHour ) {
$hourCell->hourSelected = ' hour-active';
} else {
$hourCell->hourSelected = '';
}
$hourCell->day = $day;
$hourCell->month = $month;
$hourCell->year = $year;
$hourCell->EventCells = Views::simpleView( 'calendar.nav.row', $events );
$fullDay[] = $hourCell;
}
// Calendar Top Tabs
Components::unset( 'calendarDropdown');
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/byDay/', false, true );
// must be done after top-nav gets selected
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
Components::set( 'calendarDropdown', $calendarDropdownView);
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
Components::set( 'activeDate', date( 'F d, Y', self::$selectedDate ) );
Views::view( 'calendar.byDay', $fullDay );
}
public function byWeek( $id = 0 ) {
// Set base components
Components::set( 'currentView', __FUNCTION__ );
Components::set( 'calendarID', $id );
// Set components for next / back arrows
$lastWeekMonth = date( 'M', strtotime( '-7 days', self::$selectedDate) );
$lastWeekDay = date( 'd', strtotime( '-7 days', self::$selectedDate) );
$lastWeekYear = date( 'Y', strtotime( '-7 days', self::$selectedDate) );
$nextWeekMonth = date( 'M', strtotime( '+7 days', self::$selectedDate) );
$nextWeekDay = date( 'd', strtotime( '+7 days', self::$selectedDate) );
$nextWeekYear = date( 'Y', strtotime( '+7 days', self::$selectedDate) );
Components::set( 'lastWeekMonth', $lastWeekMonth );
Components::set( 'lastWeek', $lastWeekDay );
Components::set( 'lastYear', $lastWeekYear );
Components::set( 'nextWeekMonth', $nextWeekMonth );
Components::set( 'nextWeek', $nextWeekDay );
Components::set( 'nextYear', $nextWeekYear );
// Get the data
$weekArray = self::$events->weekArray( $id, self::$selectedDate );
// build the results
$presentMonth = date( 'F', self::$selectedDate );
$presentDay = date( 'd', self::$selectedDate );
foreach ( $weekArray as $week => $days ) {
$weekFormat = [];
foreach ( $days as $day => $events ) {
if ( empty( $first ) ) {
$first = true;
if ( intval( $presentDay ) >= $day ) {
$month = date( 'F', self::$selectedDate );
} else {
$month = date( 'F', strtotime( '-7 days', self::$selectedDate ) );
}
}
if ( $day == '01' ) {
$month = date( 'F', strtotime( '+7 days', self::$selectedDate ) );
}
Components::set( 'currentMonth', $month );
Components::set( 'currentDay', $day );
$dayCell = new \stdClass();
if ( $presentDay == $day && $presentMonth == $month ) {
$dayCell->highlightedDate = ' today';
} else {
$dayCell->highlightedDate = '';
}
$dayCell->day = $day;
$dayCell->dayEventList = Views::simpleView( 'calendar.nav.cell', $events );
$weekFormat[] = $dayCell;
}
$weekView = Views::simpleView( 'calendar.nav.week', $weekFormat );
Components::set( $week . 'Element', $weekView );
}
// Calendar Top Tabs
Components::unset( 'calendarDropdown');
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/byWeek/', false, true );
// must be done after top-nav gets selected
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
Components::set( 'calendarDropdown', $calendarDropdownView);
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
Components::set( 'dateWeek', 'Week of ' . date( 'F d, Y', self::$selectedDate ) );
Views::view( 'calendar.byWeek' );
}
public function byMonth( $id = 0 ) {
// Set base components
Components::set( 'currentView', __FUNCTION__ );
Components::set( 'calendarID', $id );
// Set components for next / back arrows
$month = date( 'F', strtotime( 'first day of last month', self::$selectedDate ) );
$lastMonthYear = date( 'Y', strtotime( 'first day of last month', self::$selectedDate ) );
$nextMonth = date( 'F', strtotime( 'first day of next month', self::$selectedDate ) );
$nextMonthYear = date( 'Y', strtotime( 'first day of next month', self::$selectedDate ) );
Components::set( 'lastMonth', $month );
Components::set( 'lastMonthYear', $lastMonthYear );
Components::set( 'nextMonth', $nextMonth );
Components::set( 'nextMonthYear', $nextMonthYear );
// Get the data
$monthArray = self::$events->monthArray( $id, self::$selectedDate );
// build the results
$lastMonth = strtotime( 'last month', self::$selectedDate );
$presentMonth = date( 'F', self::$selectedDate );
$presentDay = date( 'd', self::$selectedDate );
foreach ( $monthArray as $week => $days ) {
$weekFormat = [];
foreach ( $days as $day => $events ) {
if ( $day == '01' ) {
$month = date( 'F', strtotime( '+1 month', $lastMonth ) );
$lastMonth = strtotime( '+1 month', $lastMonth) ;
}
Components::set( 'currentMonth', $month );
Components::set( 'currentDay', $day );
$dayCell = new \stdClass();
if ( $presentDay == $day && $presentMonth == $month ) {
$dayCell->highlightedDate = ' today';
} else {
$dayCell->highlightedDate = '';
}
$dayCell->day = $day;
// prevent duplicated entries for previous/next month
if ( $lastMonth < strtotime( 'this month',self::$selectedDate ) || $lastMonth == strtotime( 'next month',self::$selectedDate )) {
$events = [];
}
$dayCell->dayEventList = Views::simpleView( 'calendar.nav.cell', $events );
$weekFormat[] = $dayCell;
}
$weekView = Views::simpleView( 'calendar.nav.week', $weekFormat );
Components::set( $week . 'Element', $weekView );
}
// Calendar Top Tabs
Components::unset( 'calendarDropdown');
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/byMonth/', false, true );
// must be done after top-nav gets selected
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
Components::set( 'calendarDropdown', $calendarDropdownView);
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
Components::set( 'dateMonth', date( 'F Y', self::$selectedDate ) );
Views::view( 'calendar.byMonth' );
}
public function byYear( $id = 0 ) {
// Set base components
Components::set( 'calendarID', $id );
Components::set( 'currentView', __FUNCTION__ );
// Set components for next / back arrows
$nextYear = date( 'Y', strtotime( 'next year', self::$selectedDate ) );
$lastYear = date( 'Y', strtotime( 'last year', self::$selectedDate ) );
Components::set( 'lastYear', $lastYear );
Components::set( 'nextYear', $nextYear );
// Get the data
$eventList = self::$events->yearArray( $id, self::$selectedDate );
// Calendar Top Tabs
Components::unset( 'calendarDropdown');
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/byYear/', false, true );
// must be done after top-nav gets selected
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
Components::set( 'calendarDropdown', $calendarDropdownView);
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
Components::set( 'dateYear', date( 'Y', self::$selectedDate ) );
Views::view( 'calendar.byYear', $eventList );
}
public function events( $id = 0 ) {
Components::set( 'currentView', __FUNCTION__ );
Components::set( 'calendarID', $id );
if ( ! empty( $id ) ) {
$calendar = self::$calendars->findById( $id );
if ( $calendar == false ) {
Issues::add( 'error', 'Calendar not found.' );
return $this->index();
}
if ( $calendar->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to view this calendar.' );
return $this->index();
}
Components::set( 'calendarName', $calendar->title );
$eventList = self::$events->findByCalendar( $id );
} else {
$eventList = self::$events->userEvents( 5 );
}
// Calendar Top Tabs
Components::unset( 'calendarDropdown');
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/events/', false, true );
// must be done after top-nav gets selected
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
Components::set( 'calendarDropdown', $calendarDropdownView);
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
Views::view( 'calendar.events.list', $eventList );
}
/**
* Support Functions
*/
private function findCalendarOrFail( $id = null ) {
$calendar = self::$calendars->findById( $id );
if ( $calendar == false ) {
Session::flash( 'error', 'Calendar not found.' );
Redirect::to( 'calendar/'.self::$defaultView.'/' );
}
if ( $calendar->createdBy != App::$activeUser->ID ) {
Session::flash( 'error', 'Permissions Error.' );
Redirect::to( 'calendar/'.self::$defaultView.'/' );
}
return $calendar;
}
private function findEventOrFail( $id = null ) {
$event = self::$events->findById( $id );
if ( $event == false ) {
Session::flash( 'error', 'Event not found.' );
Redirect::to( 'calendar/'.self::$defaultView.'/' );
}
if ( $event->createdBy != App::$activeUser->ID ) {
Session::flash( 'error', 'Permissions Error.' );
Redirect::to( 'calendar/'.self::$defaultView.'/' );
}
return $event;
}
private function getEventBreakdown( $start_timestamp = 0, $end_timestamp = 0, $with_timezone = false ) {
$out = new \stdClass();
if ( empty( $end_timestamp ) ) {
$out->allDay = 'true';
// $out->date = ;
// $out->time = ;
$out->endDate = $out->date;
$out->endTime = $out->time;
} else {
$out->allDay = 'false';
// $out->date = ;
// $out->time = ;
$out->endDate = $out->date;
$out->endTime = $out->time;
}
$timestamp = intval( $timestamp );
$init = date('Y-m-d H:i:s', $timestamp);
if ( true === $with_timezone ) {
$readableDate = self::applyTimezoneToTimestamp( $timestamp );
} else {
$readableDate = date('Y-m-d H:i:s', $timestamp);
}
$date = date( 'Y-m-d', strtotime( $readableDate ) );
$time = date( 'H:i', strtotime( $readableDate ) );
return [
'time' => $time,
'date' => $date,
];
}
}

View File

@ -0,0 +1,153 @@
.calendar-container {
margin-left: 20px;
margin-right: 20px;
}
.calendar-row {
display: flex;
justify-content: space-between;
width: 100%;
}
.calendar-cell {
flex: 1;
border: 1px solid #ddd;
text-align: center;
padding: 10px 0;
margin: 0 5px;
}
.calendar-cell h4 {
margin: 0;
padding: 5px;
border-radius: 4px;
background-color: #f8f8f8;
}
.hour-row {
display: flex;
justify-content: space-between;
width: 100%;
}
.hour-body {
display: flex; /* Add this line to use flexbox */
flex-direction: row; /* Ensure the direction is row */
flex: 4;
border: 1px solid #ddd;
text-align: center;
padding: 10px 0;
margin-left: 5px;
margin-right: 5px;
align-items: center;
}
.hour-cell {
flex: 1;
border: 1px solid #ddd;
text-align: center;
padding: 10px 0;
margin-left: 5px;
margin-right: 5px;
align-items: center;
max-width: 250px;
}
.today {
background-color: #5cb85c !important;
}
.hour-header, .hour-footer {
flex: 0 0 10%;
background-color: #f8f8f8;
text-align: center;
padding: 10px 0;
margin: 0 5px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
/* Adjusting the first and last cell margins to align with the container edges */
.calendar-cell:first-child {
margin-left: 0;
}
.calendar-cell:last-child {
margin-right: 0;
}
.select-container {
color: white;
}
.custom-select {
/* color: red; */
color: #000;
}
.custom-select .white {
background-color: #ffffff;
}
.custom-select .primary {
background-color: #337ab7;
}
.custom-select .success {
background-color: #5cb85c;
}
.custom-select .info {
background-color: #5bc0de;
}
.custom-select .warning {
background-color: #f0ad4e;
}
.custom-select .danger {
background-color: #d9534f;
}
.select-container .primary {
background-color: #337ab7;
}
.select-container .white {
background-color: #ffffff;
}
.select-container .success {
background-color: #5cb85c;
}
.select-container .info {
background-color: #5bc0de;
}
.select-container .warning {
background-color: #f0ad4e;
}
.select-container .danger {
background-color: #d9534f;
}
.dateDayContainer {
width: 250px;
display: inline-block;
text-align: center;
}
.dateWeekContainer {
width: 450px;
display: inline-block;
text-align: center;
}
.dateMonthContainer {
width: 250px;
display: inline-block;
text-align: center;
}
.dateYearContainer {
width: 150px;
display: inline-block;
text-align: center;
}
.hour-active {
background-color: #217025 !important;
/* color: #00ff0d !important; */
background-image:none;
}

View File

@ -0,0 +1,136 @@
<?php
/**
* app/plugins/calendar/forms.php
*
* This houses all of the form checking functions for this plugin.
*
* @package TP Calendar
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Plugins\Calendar;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Classes\Forms;
class CalendarForms extends Forms {
/**
* Adds these functions to the form list.
*/
public function __construct() {
self::addHandler( 'calendarSelect', __CLASS__, 'calendarSelect' );
self::addHandler( 'createEvent', __CLASS__, 'createEvent' );
self::addHandler( 'createCalendar', __CLASS__, 'createCalendar' );
self::addHandler( 'editEvent', __CLASS__, 'editEvent' );
self::addHandler( 'editCalendar', __CLASS__, 'editCalendar' );
}
/**
* Validates the password re-send form.
*
* @return {bool}
*/
public static function calendarSelect() {
if ( ! Input::exists( 'calendar_id' ) ) {
Check::addUserError( 'You must include a title.' );
return false;
}
// if ( !self::token() ) {
// Check::addUserError( 'token - comment out later.' );
// return false;
// }
return true;
}
public static function createEvent() {
if ( ! Input::exists( 'title' ) ) {
Check::addUserError( 'You must include a title.' );
return false;
}
if ( ! Input::exists( 'date' ) ) {
Check::addUserError( 'You must include a date.' );
return false;
}
if ( ! Input::exists( 'time' ) ) {
Check::addUserError( 'You must include a time.' );
return false;
}
if ( ! Input::exists( 'repeats' ) ) {
Check::addUserError( 'You must include a frequency.' );
return false;
}
if ( ! Input::exists( 'calendar_id' ) ) {
Check::addUserError( 'You must select a calendar.' );
return false;
}
// if ( !self::token() ) {
// Check::addUserError( 'token - comment out later.' );
// return false;
// }
return true;
}
public static function createCalendar() {
if ( ! Input::exists( 'title' ) ) {
Check::addUserError( 'You must include a title.' );
return false;
}
if ( ! Input::exists( 'timezone' ) ) {
Check::addUserError( 'You must include a timezone.' );
return false;
}
// if ( ! self::token() ) {
// Check::addUserError( 'token - comment out later.' );
// return false;
// }
return true;
}
public static function editEvent() {
if ( ! Input::exists( 'title' ) ) {
Check::addUserError( 'You must include a title.' );
return false;
}
if ( ! Input::exists( 'date' ) ) {
Check::addUserError( 'You must include a date.' );
return false;
}
if ( ! Input::exists( 'time' ) ) {
Check::addUserError( 'You must include a time.' );
return false;
}
if ( ! Input::exists( 'repeats' ) ) {
Check::addUserError( 'You must include a frequency.' );
return false;
}
// if ( !self::token() ) {
// Check::addUserError( 'token - comment out later.' );
// return false;
// }
return true;
}
public static function editCalendar() {
if ( ! Input::exists( 'submit' ) ) {
return false;
}
if ( ! Input::exists( 'title' ) ) {
Check::addUserError( 'You must include a title.' );
return false;
}
if ( ! Input::exists( 'timezone' ) ) {
Check::addUserError( 'You must include a timezone.' );
return false;
}
// if ( !self::token() ) {
// Check::addUserError( 'token - comment out later.' );
// return false;
// }
return true;
}
}
new CalendarForms;

View File

@ -0,0 +1,157 @@
<?php
/**
* app/plugins/calendar/models/events.php
*
* This class is used for the manipulation of the calendars database table.
*
* @package TP Calendar
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Models;
use TheTempusProject\Bedrock\Classes\Config;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Functions\Date;
use TheTempusProject\Canary\Canary as Debug;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Houdini\Classes\Filters;
use TheTempusProject\Bedrock\Classes\CustomException;
class Calendars extends DatabaseModel {
public $tableName = 'calendars';
public $databaseMatrix = [
[ 'title', 'varchar', '256' ],
[ 'color', 'varchar', '48' ],
[ 'privacy', 'varchar', '48' ],
[ 'description', 'text', '' ],
[ 'createdBy', 'int', '11' ],
[ 'createdAt', 'int', '11' ],
[ 'timezone', 'varchar', '256' ],
];
/**
* The model constructor.
*/
public function __construct() {
parent::__construct();
}
public function create( $title, $description = '', $timezone = '', $color = 'default' ) {
if ( ! Check::dataTitle( $title ) ) {
Debug::info( 'Calendars: illegal title.' );
return false;
}
if ( empty( $timezone ) ) {
$timezone = Date::getTimezone();
}
$fields = [
'title' => $title,
'description' => $description,
'timezone' => $timezone,
'color' => $color,
'createdBy' => App::$activeUser->ID,
'createdAt' => time(),
];
if ( ! self::$db->insert( $this->tableName, $fields ) ) {
new CustomException( 'calendarCreate' );
Debug::error( "Calendar: not created " . var_export($fields,true) );
return false;
}
return self::$db->lastId();
}
public function update( $id, $title, $description = '', $timezone = '', $color = 'default' ) {
if ( empty( $timezone ) ) {
$timezone = Date::getTimezone();
}
if ( !Check::id( $id ) ) {
Debug::info( 'Calendars: illegal ID.' );
return false;
}
if ( !Check::dataTitle( $title ) ) {
Debug::info( 'Calendars: illegal title.' );
return false;
}
$fields = [
'title' => $title,
'description' => $description,
'timezone' => $timezone,
'color' => $color,
];
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'calendarUpdate' );
Debug::error( "Calendar: $id not updated: $fields" );
return false;
}
return true;
}
public function byUser( $limit = null ) {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
if ( empty( $limit ) ) {
$calendars = self::$db->get( $this->tableName, $whereClause );
} else {
$calendars = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
}
if ( !$calendars->count() ) {
Debug::info( 'No Calendars found.' );
return false;
}
return $this->filter( $calendars->results() );
}
public function getName( $id ) {
$calendar = self::findById( $id );
if (false == $calendar) {
return 'unknown';
}
return $calendar->title;
}
public function getColor( $id ) {
$calendar = self::findById( $id );
if (false == $calendar) {
return 'default';
}
return $calendar->color;
}
public function simpleByUser() {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
$calendars = self::$db->get( $this->tableName, $whereClause );
if ( !$calendars->count() ) {
Debug::warn( 'Could not find any calendars' );
return false;
}
$calendars = $calendars->results();
$out = [];
foreach ( $calendars as &$calendar ) {
$out[ $calendar->title ] = $calendar->ID;
}
return $out;
}
public function simpleObjectByUser() {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
$calendars = self::$db->get( $this->tableName, $whereClause );
if ( !$calendars->count() ) {
Debug::warn( 'Could not find any calendars' );
return false;
}
$calendars = $calendars->results();
$out = [];
foreach ( $calendars as &$calendar ) {
$obj = new \stdClass();
$obj->title = $calendar->title;
$obj->ID = $calendar->ID;
$out[] = $obj;
}
return $out;
}
}

View File

@ -0,0 +1,509 @@
<?php
/**
* app/plugins/calendar/models/events.php
*
* This class is used for the manipulation of the events database table.
*
* @package TP Calendar
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Models;
use TheTempusProject\Bedrock\Classes\Config;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Canary\Canary as Debug;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Houdini\Classes\Filters;
use TheTempusProject\Models\Calendars;
use TheTempusProject\Bedrock\Classes\CustomException;
use TheTempusProject\Bedrock\Functions\Date;
use TheTempusProject\Houdini\Classes\Pagination;
class Events extends DatabaseModel {
public $tableName = 'events';
public $repeatOptions = [
'Does Not Repeat' => 'none',
'Every Day' => 'daily',
'Every Week' => 'weekly',
'Every Month' => 'monthly',
'Every Year' => 'yearly',
];
public $databaseMatrix = [
[ 'calendar_id', 'int', '11' ],
[ 'title', 'varchar', '256' ],
[ 'event_time', 'int', '11' ],
[ 'event_ends', 'int', '11' ],
[ 'description', 'text', '' ],
[ 'location', 'varchar', '256' ],
[ 'repeats', 'varchar', '48' ],
[ 'color', 'varchar', '48' ],
[ 'parent_id', 'int', '11' ],
[ 'createdBy', 'int', '11' ],
[ 'createdAt', 'int', '11' ],
];
protected static $calendars;
/**
* The model constructor.
*/
public function __construct() {
parent::__construct();
self::$calendars = new Calendars;
}
/**
* Saves a chat form to the db.
*
* @param string $message -contents of the chat form.
* @return bool
*/
public function create( $calendar_id, $title, $event_time, $description = '', $location = '', $repeats = 'none', $color = 'default', $parent_id = 0 ) {
if ( ! Check::id( $calendar_id ) ) {
Debug::info( 'calendar event: illegal calendar ID.' );
return false;
}
$fields = [
'calendar_id' => $calendar_id,
'title' => $title,
'event_time' => $event_time,
'description' => $description,
'location' => $location,
'repeats' => $repeats,
'color' => $color,
'parent_id' => $parent_id,
'createdBy' => App::$activeUser->ID,
'createdAt' => time(),
];
if ( !self::$db->insert( $this->tableName, $fields ) ) {
Debug::info( 'Events::create - failed to insert to db' );
return false;
}
return self::$db->lastId();
}
public function update( $id, $title, $event_time, $description = '', $location ='', $repeats = 'none', $color = 'default', $parent_id = 0, $calendar_id = '' ) {
if ( ! Check::id( $id ) ) {
Debug::info( 'calendar event: illegal ID.' );
return false;
}
$fields = [
'title' => $title,
'event_time' => $event_time,
'description' => $description,
'location' => $location,
'repeats' => $repeats,
'color' => $color,
'parent_id' => $parent_id,
];
if ( ! self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'calendarEventUpdate' );
Debug::error( "Event: $id not updated: $fields" );
return false;
}
return true;
}
public function dayArray( $calendar_id = 0, $date = 0 ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
if ( ! empty( $calendar_id ) ) {
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id, 'AND' ] );
}
$whereClause = array_merge( $whereClause, [
'event_time', '>=', Date::getDayStartTimestamp( $date, true ), 'AND',
'event_time', '<=', Date::getDayEndTimestamp( $date, true ),
] );
$events = self::$db->get( $this->tableName, $whereClause );
if ( ! $events->count() ) {
$results = [];
} else {
$results = $events->results();
}
$events = $this->sortByEventTimeHour(
$this->filter(
$results
)
);
// Generate day array
$currentDay = [];
$currentHour = Date::getDayStartTimestamp( $date );
$lastHour = Date::getDayEndTimestamp( $date );
while ( $currentHour <= $lastHour ) {
$hour = date( 'H', $currentHour );
if ( ! empty( $events[ $hour ] ) ) {
$dailyEvents = $events[ $hour ];
} else {
$dailyEvents = [];
}
$currentDay[ $hour ] = $dailyEvents;
$currentHour = strtotime('+1 hour', $currentHour);
}
return $currentDay;
}
public function weekArray( $calendar_id = 0, $date = null ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
if ( ! empty( $calendar_id ) ) {
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id, 'AND' ] );
}
$whereClause = array_merge( $whereClause, [
'event_time', '>=', Date::getWeekStartTimestamp( $date, true ), 'AND',
'event_time', '<=', Date::getWeekEndTimestamp( $date, true ),
] );
$events = self::$db->get( $this->tableName, $whereClause );
if ( ! $events->count() ) {
$results = [];
} else {
$results = $events->results();
}
$events = $this->sortByEventTime(
$this->filter(
$results
),
);
// Generate weeks array
$output = [];
$currentWeek = [];
$currentDay = Date::getWeekStartTimestamp( $date );
$weekCounter = 1;
$dayCounter = 1;
// Re-index the array using the date derived from event_time as the key
while ( $currentDay <= Date::getWeekEndTimestamp( $date ) ) {
$month = date( 'F', $currentDay );
$dayOfMonth = date( 'd', $currentDay );
if ( ! empty( $events[ $month ][ $dayOfMonth ] ) ) {
$dailyEvents = $events[ $month ][ $dayOfMonth ];
} else {
$dailyEvents = [];
}
$currentWeek[ $dayOfMonth ] = $dailyEvents;
$currentDay = strtotime('+1 day', $currentDay);
}
// Handle any remaining days in the last week
if ( ! empty( $currentWeek ) ) {
$output["week$weekCounter"] = $currentWeek;
}
return $output;
}
public function monthArray( $calendar_id = 0, $date = null ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
if ( ! empty( $calendar_id ) ) {
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id, 'AND' ] );
}
$whereClause = array_merge( $whereClause, [
'event_time', '>=', Date::getMonthStartTimestamp( $date, true ), 'AND',
'event_time', '<=', Date::getMonthEndTimestamp( $date, true ),
] );
$events = self::$db->get( $this->tableName, $whereClause );
if ( ! $events->count() ) {
$results = [];
} else {
$results = $events->results();
}
$events = $this->sortByEventTime(
$this->filter(
$results
),
);
// Generate weeks array
$output = [];
$currentWeek = [];
$currentDay = Date::getMonthStartTimestamp( $date );
$weekCounter = 1;
$dayCounter = 1;
// Re-index the array using the date derived from event_time as the key
while ( $currentDay <= Date::getMonthEndTimestamp( $date ) ) {
$month = date( 'F', $currentDay );
$dayOfMonth = date( 'd', $currentDay );
if ( ! empty( $events[ $month ][ $dayOfMonth ] ) ) {
$dailyEvents = $events[ $month ][ $dayOfMonth ];
} else {
$dailyEvents = [];
}
$currentWeek[$dayOfMonth] = $dailyEvents;
if (count($currentWeek) == 7) {
$output["week$weekCounter"] = $currentWeek;
$currentWeek = [];
$weekCounter++;
}
$currentDay = strtotime('+1 day', $currentDay);
}
// Handle any remaining days in the last week
if ( ! empty( $currentWeek ) ) {
$output["week$weekCounter"] = $currentWeek;
}
while ( $weekCounter < 7 ) {
$output["week$weekCounter"] = [];
$weekCounter++;
}
return $output;
}
public function yearArray( $calendar_id = 0, $date = null ) {
if ( empty( $date ) ) {
$date = time();
}
$year = date( 'Y', $date );
$firstDayUnix = date( 'U', strtotime( "Jan 1, $year" ) );
$lastDayUnix = date( 'U', strtotime( "December 31, $year" ) );
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
if ( ! empty( $calendar_id ) ) {
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id, 'AND' ] );
}
$whereClause = array_merge( $whereClause, [
'event_time', '<=', $lastDayUnix, 'AND',
'event_time', '>=', $firstDayUnix,
] );
$events = self::$db->get( $this->tableName, $whereClause );
if ( ! $events->count() ) {
Debug::info( 'No ' . $this->tableName . ' data found.' );
return [];
}
return $this->filter( $events->results() );
}
public function compareEventTime($a, $b) {
return $a->event_time - $b->event_time;
}
public function sortByEventTimeHour( $results ) {
usort( $results, [ $this,'compareEventTime' ] );
$sortedResults = array();
foreach ( $results as $result ) {
$date = new \DateTime();
$date->setTimestamp( $result->event_time );
$timezone = new \DateTimeZone( Date::getTimezone() );
$date->setTimezone( $timezone );
$dateKey = $date->format('H');
$sortedResults[ $dateKey ][] = $result;
}
return $sortedResults;
}
public function sortByEventTime( $results ) {
usort( $results, [ $this,'compareEventTime' ] );
$sortedResults = array();
foreach ( $results as $result ) {
$date = new \DateTime();
$date->setTimestamp( $result->event_time );
$timezone = new \DateTimeZone( Date::getTimezone() );
$date->setTimezone( $timezone );
$month = $date->format('F');
$dateKey = $date->format('d');
if ( ! isset( $sortedResults[ $month ] ) ) {
$sortedResults[ $month ] = [];
}
if ( ! isset( $sortedResults[ $month ][ $dateKey ] ) ) {
$sortedResults[ $month ][ $dateKey ] = [];
}
$sortedResults[ $month ][ $dateKey ][] = $result;
}
return $sortedResults;
}
public function findByCalendar( $id ) {
$calendar = $this->verifyCalendar( $id );
if ( empty( $calendar ) ) {
return [];
}
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $id ] );
$events = self::$db->getPaginated( $this->tableName, $whereClause );
if ( ! $events->count() ) {
Debug::info( 'No ' . $this->tableName . ' data found.' );
return [];
}
return $this->filter( $events->results() );
}
public function userEvents( $limit = 0 ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID ];
$events = self::$db->getPaginated( $this->tableName, $whereClause );
if ( ! $events->count() ) {
Debug::info( 'No ' . $this->tableName . ' data found.' );
return [];
}
return $this->filter( $events->results() );
}
public function filter( $data, $params = [] ) {
$out = [];
foreach ( $data as $instance ) {
if ( !is_object( $instance ) ) {
$instance = $data;
$end = true;
}
$instance->repeatsText = array_search('none', $this->repeatOptions);
$instance->calendarName = self::$calendars->getName( $instance->calendar_id );
if ( empty( $instance->color ) || $instance->color == 'default' || $instance->color == 'none') {
$instance->displayColor = self::$calendars->getColor( $instance->calendar_id );
} else {
$instance->displayColor = $instance->color;
}
$out[] = $instance;
if ( !empty( $end ) ) {
$out = $out[0];
break;
}
}
return $out;
}
public function today( $limit = 0 ) {
$date = time();
$day = date('d', $date);
$month = date('M', $date);
$year = date( 'Y', $date );
$firstDayUnix = date( 'U', strtotime( "00:00:00 $day $month $year" ) );
$lastDayUnix = date( 'U', strtotime( "23:59:59 $day $month $year" ) );
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
$whereClause = array_merge( $whereClause, [
'event_time', '<=', $lastDayUnix, 'AND',
'event_time', '>=', $firstDayUnix,
] );
if ( empty( $limit ) ) {
$events = self::$db->get( $this->tableName, $whereClause );
} else {
$events = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
}
if ( ! $events->count() ) {
Debug::info( 'No ' . $this->tableName . ' data found.' );
return [];
}
return $this->filter( $events->results() );
}
private function verifyCalendar( $calendar_id ) {
if ( ! Check::id( $calendar_id ) ) {
Debug::info( 'Invalid Calendar ID' );
return false;
}
$calendar = self::$calendars->findById( $calendar_id );
if ( $calendar == false ) {
Debug::info( 'Calendar not found' );
return false;
}
if ( $calendar->createdBy != App::$activeUser->ID ) {
Debug::info( 'You do not have permission to view this calendar' );
return false;
}
return $calendar;
}
public function deleteByCalendar( $calendar_id ) {
$calendar = $this->verifyCalendar( $calendar_id );
if ( empty( $calendar ) ) {
return [];
}
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id ] );
$events = self::$db->get( $this->tableName, $whereClause );
if ( ! $events->count() ) {
Debug::info( 'No ' . $this->tableName . ' data found.' );
return [];
}
foreach( $events->results() as $event ) {
$this->deleteByParent( $event->ID );
}
return true;
}
public function deleteByParent( $event_id ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
$whereClause = array_merge( $whereClause, [ 'parent_id', '=', $event_id ] );
$events = self::$db->get( $this->tableName, $whereClause );
if ( ! $events->count() ) {
Debug::info( 'No ' . $this->tableName . ' data found.' );
return [];
}
foreach( $events->results() as $event ) {
$this->delete( $event->ID );
}
// need to delete all child events accordingly
return true;
}
public function delete( $idArray ) {
if ( !is_array( $idArray ) ) {
$idArray = [ $idArray ];
}
return parent::delete( $idArray );
}
public function generateChildEvents( $event_id, $remove_existing_children = true, $remove_history = false ) {
$event = self::findById( $event_id );
if (empty($event)) {
return false;
}
if ($event->parent_id != 0) {
return false;
}
if (!in_array($event->repeats, $this->repeatOptions)) {
return false;
}
$startDate = time();
$whereClause = [
'parent_id', '=', $event_id,
];
if ( $remove_history && ! $remove_existing_children) {
$whereClause = array_merge( $whereClause, [ 'AND', 'event_time', '<=', $startDate ] );
} elseif ( $remove_existing_children && ! $remove_history ) {
$whereClause = array_merge( $whereClause, [ 'AND', 'event_time', '>=', $startDate ] );
} elseif ( !$remove_existing_children && !$remove_history ) {
return false;
}
self::$db->delete($this->tableName, $whereClause);
switch ($event->repeats) {
case 'daily':
return $this->generateEvents( $event, 'P90D' );
case 'weekly':
return $this->generateEvents( $event, 'P1W' );
case 'monthly':
return $this->generateEvents( $event, 'P1M' );
case 'yearly':
return $this->generateEvents( $event, 'P1Y' );
default:
return false;
}
}
private function generateEvents( $event, $interval, $years = 2 ) {
$endDate = strtotime('+'.$years.' years');
$interval = new \DateInterval( $interval );
$period = new \DatePeriod(new \DateTime('@' . $event->event_time), $interval, new \DateTime('@' . $endDate));
foreach ($period as $date) {
if ( $date->getTimestamp() <= time() ) {
continue;
}
$result = $this->create(
$event->calendar_id,
$event->title,
$date->getTimestamp(),
$event->description,
$event->location,
$event->repeats,
$event->color,
$event->ID,
);
}
}
}

View File

@ -0,0 +1,84 @@
<?php
/**
* app/plugins/calendar/plugin.php
*
* This houses all of the main plugin info and functionality.
*
* @package TP Calendar
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Plugins;
use TheTempusProject\Classes\Plugin;
use TheTempusProject\Models\Events;
use TheTempusProject\Models\Calendars;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Houdini\Classes\Template;
class Calendar extends Plugin {
public $pluginName = 'TP Calendar';
public $configName = 'calendar';
public $pluginAuthor = 'JoeyK';
public $pluginWebsite = 'https://TheTempusProject.com';
public $modelVersion = '1.0';
public $pluginVersion = '3.0';
public $pluginDescription = 'A simple plugin which adds a site wide calendar system.';
public $permissionMatrix = [
'useCalendar' => [
'pretty' => 'Can use the calendar feature',
'default' => false,
],
'createEvents' => [
'pretty' => 'Can add events to calendars',
'default' => false,
],
];
public $main_links = [
[
'text' => 'Calendar',
'url' => '{ROOT_URL}calendar/index',
'filter' => 'loggedin',
],
];
public $configMatrix = [
'enabled' => [
'type' => 'radio',
'pretty' => 'Enable Calendar.',
'default' => true,
],
];
public $preferenceMatrix = [
'calendarPreference' => [
'pretty' => 'Default Calendar View',
'type' => 'select',
'default' => 'byMonth',
'options' => [
'Daily' => 'byDay',
'Weekly' => 'byWeek',
'Monthly' => 'byMonth',
'Yearly' => 'byYear',
'All Events' => 'events',
],
],
'weekStart' => [
'pretty' => 'First day of the week for the Calendar',
'type' => 'select',
'default' => 'sunday',
'options' => [
'Sunday' => '6',
'Monday' => '7',
],
],
];
public $events;
public $calendars;
public function __construct( $load = false ) {
$this->events = new Events;
$this->calendars = new Calendars;
parent::__construct( $load );
}
}

View File

@ -0,0 +1,41 @@
<?php
/**
* app/plugins/blog/templates/blog.inc.php
*
* This is the loader for the blog template.
*
* @package TP Blog
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Templates;
use TheTempusProject\Plugins\Calendar;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Houdini\Classes\Navigation;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Houdini\Classes\Template;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Models\Events;
use TheTempusProject\Models\Calendars;
class CalendarLoader extends DefaultLoader {
/**
* This is the function used to generate any components that may be
* needed by this template.
*/
public function __construct() {
$events = new Events;
$calendars = new Calendars;
Navigation::setCrumbComponent( 'CALENDAR_BREADCRUMBS', Input::get( 'url' ) );
Components::set( 'todaysDate', date( 'F d, Y', time()) );
Components::set( 'currentDay', date( 'F d, Y', time()) );
Components::set( 'weekOf', 'Week of ' . date( 'F d, Y', strtotime( 'this week' ) ) );
Components::set( 'year', date( 'Y', time() ));
Components::set( 'month', date( 'F', time() ));
parent::__construct();
}
}

View File

@ -0,0 +1,96 @@
<!DOCTYPE html>
<html lang="en">
<!--
* app/plugins/calendar/templates/calendar.tpl
*
* @package TP Calendar
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta property="og:url" content="{CURRENT_URL}">
<meta name='twitter:card' content='summary' />
<title>{TITLE}</title>
<meta itemprop="name" content="{TITLE}">
<meta name="twitter:title" content="{TITLE}">
<meta property="og:title" content="{TITLE}">
<meta name="description" content="{PAGE_DESCRIPTION}">
<meta itemprop="description" content="{PAGE_DESCRIPTION}">
<meta name="twitter:description" content="{PAGE_DESCRIPTION}">
<meta property="og:description" content="{PAGE_DESCRIPTION}">
<meta itemprop="image" content="{META_IMAGE}">
<meta name="twitter:image" content="{META_IMAGE}">
<meta property="og:image" content="{META_IMAGE}">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="The Tempus Project">
{ROBOT}
<link rel="alternate" hreflang="en-us" href="alternateURL">
<link rel="icon" href="{ROOT_URL}images/favicon.ico">
<!-- Required CSS -->
<link rel="stylesheet" href="{FONT_AWESOME_URL}font-awesome.min.css" crossorigin="anonymous">
<link rel="stylesheet" href="{BOOTSTRAP_CDN}css/bootstrap-theme.min.css" crossorigin="anonymous">
<link rel="stylesheet" href="{BOOTSTRAP_CDN}css/bootstrap.min.css" crossorigin="anonymous">
<!-- RSS -->
<link rel="alternate" href="{ROOT_URL}blog/rss" title="{TITLE} Feed" type="application/rss+xml" />
<!-- Custom styles for this template -->
{TEMPLATE_CSS_INCLUDES}
<link rel="stylesheet" href="{ROOT_URL}app/plugins/calendar/css/calendar.css" />
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<!--Brand and toggle should get grouped for better mobile display -->
<div class="navbar-header">
<a href="{ROOT_URL}" class="navbar-brand">{SITENAME}</a>
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse" style="">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="container-fluid">
<div class="collapse navbar-collapse navbar-ex1-collapse">
{topNavLeft}
<div class="navbar-right">
<ul class="nav navbar-nav">
{topNavRight}
</ul>
</div>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="foot-pad">
{ISSUES}
<div class="row">
<div class="container">
{ERROR}
{NOTICE}
{SUCCESS}
</div>
</div>
{/ISSUES}
<div class="row">
<div class="container-fluid calendar-container">
<div class="row">
{CalendarNav}
{CONTENT}
</div>
</div>
</div>
</div>
</div>
<footer>
{COPY}
</footer>
<!-- Bootstrap core JavaScript and jquery -->
<script src="{JQUERY_CDN}jquery.min.js" crossorigin="anonymous"></script>
<script src="{BOOTSTRAP_CDN}js/bootstrap.min.js" crossorigin="anonymous"></script>
<!-- Custom javascript for this template -->
{TEMPLATE_JS_INCLUDES}
</body>
</html>

View File

@ -0,0 +1,25 @@
<h2 class="pull-left">
<a href="{ROOT_URL}calendar/byDay/{calendarID}?day={lastDay}&month={lastDayMonth}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-left"></i>
</a>
<span class="dateDayContainer">{activeDate}</span>
<a href="{ROOT_URL}calendar/byDay/{calendarID}?day={nextDay}&month={nextDayMonth}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-right"></i>
</a>
</h2>
{dateDropdown}
<div class="container-fluid">
{LOOP}
<div class="hour-row{hourSelected}">
<h2 class="hour-header">{hour}:00</h2>
{EventCells}
<span class="hour-footer">
<a href="{ROOT_URL}calendar/createEvent?calendar_id={calendarID}&hour={hour}&day={day}" class="btn btn-sm btn-success" role="button"><i class="glyphicon glyphicon-plus"></i></a>
</span>
</div>
{/LOOP}
{ALT}
<div class="hour-row{hourSelected}">
</div>
{/ALT}
</div>

View File

@ -0,0 +1,34 @@
<h2 class="pull-left">
<a href="{ROOT_URL}calendar/byMonth/{calendarID}?month={lastMonth}&year={lastMonthYear}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-left"></i>
</a>
<span class="dateMonthContainer">{dateMonth}</span>
<a href="{ROOT_URL}calendar/byMonth/{calendarID}?month={nextMonth}&year={nextMonthYear}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-right"></i>
</a>
</h2>
{dateDropdown}
<div class="container-fluid">
<!-- Header -->
<div class="row calendar-row">
<div class="col-xs-1 calendar-cell"><h4>Sunday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Monday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Tuesday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Wednesday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Thursday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Friday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Saturday</h4></div>
</div>
<!-- Week 1 -->
{week1Element}
<!-- Week 2 -->
{week2Element}
<!-- Week 3 -->
{week3Element}
<!-- Week 4 -->
{week4Element}
<!-- Week 5 -->
{week5Element}
<!-- Week 6 -->
{week6Element}
</div>

View File

@ -0,0 +1,25 @@
<h2 class="pull-left">
<a href="{ROOT_URL}calendar/byWeek/{calendarID}?month={lastWeekMonth}&day={lastWeek}&year={lastYear}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-left"></i>
</a>
<span class="dateWeekContainer">{dateWeek}</span>
<a href="{ROOT_URL}calendar/byWeek/{calendarID}?month={nextWeekMonth}&day={nextWeek}&year={nextYear}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-right"></i>
</a>
</h2>
{dateDropdown}
<div class="container-fluid">
<!-- Header -->
<div class="row calendar-row">
<div class="col-xs-1 calendar-cell"><h4>Sunday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Monday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Tuesday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Wednesday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Thursday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Friday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Saturday</h4></div>
</div>
<!-- Week 1 -->
{week1Element}
</div>

View File

@ -0,0 +1,42 @@
<h2 class="pull-left">
<a href="{ROOT_URL}calendar/byYear/{calendarID}?year={lastYear}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-left"></i>
</a>
<span class="dateYearContainer">{dateYear}</span>
<a href="{ROOT_URL}calendar/byYear/{calendarID}?year={nextYear}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-right"></i>
</a>
</h2>
{dateDropdown}
<table class="table table-striped">
<thead>
<tr>
<th style="width: 10%">ID</th>
<th style="width: 20%">Time</th>
<th style="width: 40%">Title</th>
<th style="width: 10%"></th>
<th style="width: 10%"></th>
<th style="width: 10%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td style="text-align: center;">{ID}</td>
<td style="text-align: center;">{DTC}{event_time}{/DTC}</td>
<td style="text-align: center;">{title}</td>
<td><a href="{ROOT_URL}calendar/event/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a></td>
<td><a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td style="text-align: center;" colspan="6">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}calendar/createEvent" class="btn btn-sm btn-primary" role="button">Create</a>

View File

@ -0,0 +1,34 @@
<legend>Create Calendar</legend>
<form action="" method="post" class="form-horizontal">
<input type="hidden" name="token" value="{TOKEN}">
<div class="form-group">
<label for="title" class="col-lg-3 control-label">Title</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="title" id="title">
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Description</label>
<div class="col-lg-3">
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description"></textarea>
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Timezone</label>
<div class="col-lg-3">
{timezoneSelect}
</div>
</div>
<div class="form-group">
<label for="color" class="col-lg-3 control-label">Calendar Color</label>
<div class="col-lg-3 select-container" id="colorContainer">
{colorSelect}
</div>
</div>
<div class="form-group">
<label for="submit" class="col-lg-3 control-label"></label>
<div class="col-lg-3">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Submit</button>
</div>
</div>
</form>

View File

@ -0,0 +1,29 @@
<legend>Edit Calendar</legend>
<form action="" method="post" class="form-horizontal">
<div class="form-group">
<label for="title" class="col-lg-3 control-label">Title</label>
<div class="col-lg-3">
<input type="text" class="form-check-input form-control" name="title" id="title" value="{title}">
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Description</label>
<div class="col-lg-6">
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description">{description}</textarea>
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Timezone</label>
<div class="col-lg-3">
{timezoneSelect}
</div>
</div>
<div class="form-group">
<label for="color" class="col-lg-3 control-label">Calendar Color</label>
<div class="col-lg-3 select-container" id="colorContainer">
{colorSelect}
</div>
</div>
<input type="hidden" name="token" value="{TOKEN}">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Submit</button>
</form>

View File

@ -0,0 +1,45 @@
<legend>Calendars</legend>
<form action="{ROOT_URL}calendar/deleteCalendar" method="post">
<table class="table table-striped">
<thead>
<tr>
<th style="width: 5%">ID</th>
<th style="width: 20%">Title</th>
<th style="width: 50%">Description</th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%">
<input type="checkbox" onchange="checkAll(this)" name="check.br" value="CAL_[]"/>
</th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td align="center">{ID}</td>
<td align="center">{title}</td>
<td>{description}</td>
<td><a href="{ROOT_URL}calendar/byMonth/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-share-alt"></i></a></td>
<td><a href="{ROOT_URL}calendar/calendar/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-info-sign"></i></a></td>
<td><a href="{ROOT_URL}calendar/editCalendar/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}calendar/deleteCalendar/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
<td>
<input type="checkbox" value="{ID}" name="CAL_[]">
</td>
</tr>
{/LOOP}
{ALT}
<tr>
<td align="center" colspan="7">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}calendar/createCalendar" class="btn btn-sm btn-primary" role="button">Create</a>
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger">Delete</button>
</form>
<br />

View File

@ -0,0 +1,42 @@
<div class="container col-md-4 col-lg-4">
<div class="row">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Calendar</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="">
<table class="table table-user-primary">
<tbody>
<tr>
<td align="left" width="200"><b>Title</b></td>
<td align="right">{title}</td>
</tr>
<tr>
<td><b>Created</b></td>
<td align="right">{DTC}{createdAt}{/DTC}</td>
</tr>
<tr>
<td align="center" colspan="2"><b>Description</b></td>
</tr>
<tr>
<td colspan="2">{description}</td>
</tr>
<tr>
<td><b>TimeZone</b></td>
<td align="right">{timezone}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="panel-footer">
<a href="{ROOT_URL}calendar/deleteCalendar/{ID}" class="btn btn-md btn-danger" role="button">Delete</a>
<a href="{ROOT_URL}calendar/editCalendar/{ID}" class="btn btn-md btn-warning" role="button">Edit</a>
<a href="{ROOT_URL}calendar/byMonth/{ID}" class="btn btn-md btn-primary" role="button">View Events</a>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,20 @@
<div class="form-group">
<label for="day" class="col-lg-3 control-label">All-Day Event</label>
<div class="col-lg-3">
<input class="" type="checkbox" name="allDay" id="allDay" value="true" {CHECKED:allDay=true}>
</div>
</div>
<div class="form-group">
<label for="month" class="col-lg-3 control-label">Event Start</label>
<div class="col-lg-3">
<input type="date" name="date" id="date" class="form-control" value="{date}" />
<input type="time" name="time" id="time" class="form-control" value="{time}" />
</div>
</div>
<div class="form-group">
<label for="month" class="col-lg-3 control-label">Event End</label>
<div class="col-lg-3">
<input type="date" name="endDate" id="endDate" class="form-control" value="{endDate}" />
<input type="time" name="endTime" id="endTime" class="form-control" value="{endTime}" />
</div>
</div>

View File

@ -0,0 +1,37 @@
<legend>Create Event</legend>
<form action="" method="post" class="form-horizontal">
<input type="hidden" name="token" value="{TOKEN}">
{calendarSelect}
<div class="form-group">
<label for="title" class="col-lg-3 control-label">Title</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="title" id="title">
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Description</label>
<div class="col-lg-3">
<textarea class="form-control" name="description" maxlength="2000" rows="6" cols="30" id="description"></textarea>
</div>
</div>
<div class="form-group">
<label for="location" class="col-lg-3 control-label">Location</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="location" id="location">
</div>
</div>
<div class="form-group">
<label for="color" class="col-lg-3 control-label">Event Color</label>
<div class="col-lg-3 select-container" id="colorContainer">
{colorSelect}
</div>
</div>
{dateSelect}
{repeatSelect}
<div class="form-group">
<label for="submit" class="col-lg-3 control-label"></label>
<div class="col-lg-3">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Submit</button>
</div>
</div>
</form>

View File

@ -0,0 +1,31 @@
<legend>Edit Event</legend>
<form action="" method="post" class="form-horizontal">
<div class="form-group">
<label for="title" class="col-lg-3 control-label">Title</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="title" id="title" value="{title}">
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Description</label>
<div class="col-lg-6">
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description">{description}</textarea>
</div>
</div>
<div class="form-group">
<label for="location" class="col-lg-3 control-label">Location</label>
<div class="col-lg-6">
<input type="text" class="form-control" name="location" id="location" value="{location}">
</div>
</div>
<div class="form-group">
<label for="color" class="col-lg-3 control-label">Event Color</label>
<div class="col-lg-3 select-container" id="colorContainer">
{colorSelect}
</div>
</div>
{dateSelect}
{repeatSelect}
<input type="hidden" name="token" value="{TOKEN}">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Submit</button>
</form>

View File

@ -0,0 +1,34 @@
{PAGINATION}
<table class="table table-striped">
<thead>
<tr>
<th style="width: 10%">ID</th>
<th style="width: 20%">Time</th>
<th style="width: 40%">Title</th>
<th style="width: 10%"></th>
<th style="width: 10%"></th>
<th style="width: 10%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td style="text-align: center;">{ID}</td>
<td style="text-align: center;">{DTC}{event_time}{/DTC}</td>
<td style="text-align: center;">{title}</td>
<td><a href="{ROOT_URL}calendar/event/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a></td>
<td><a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td style="text-align: center;" colspan="6">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
{PAGINATION}
<a href="{ROOT_URL}calendar/createEvent" class="btn btn-sm btn-primary" role="button">Create</a>

View File

@ -0,0 +1,52 @@
<div class="container col-md-4 col-lg-4">
<div class="row">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Event</h3>
</div>
<div class="panel-body">
<div class="row">
<table class="table table-user-primary">
<tbody>
<tr>
<td style="text-align: left;" width="200"><b>Title</b></td>
<td style="text-align: right;">{title}</td>
</tr>
<tr>
<td><b>Created</b></td>
<td style="text-align: right;">{DTC}{createdAt}{/DTC}</td>
</tr>
<tr>
<td><b>Event Time</b></td>
<td style="text-align: right;">{DTC}{event_time}{/DTC}</td>
</tr>
<tr>
<td style="text-align: center;" colspan="2"><b>Description</b></td>
</tr>
<tr>
<td colspan="2">{description}</td>
</tr>
<tr>
<td><b>Location</b></td>
<td style="text-align: right;">{location}</td>
</tr>
<tr>
<td><b>Frequency</b></td>
<td style="text-align: right;">{repeatsText}</td>
</tr>
<tr>
<td><b>Calendar</b></td>
<td style="text-align: right;">{calendarName}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="panel-footer">
<a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-md btn-danger" role="button">Delete</a>
<a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-md btn-warning" role="button">Edit</a>
<a href="{ROOT_URL}calendar/byMonth/{calendar_id}" class="btn btn-md btn-primary" role="button">View Events</a>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,16 @@
<li class="pull-right dropdown">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Calendars <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="{ROOT_URL}calendar/{currentView}/">All</a></li>
<li role="separator" class="divider"></li>
{LOOP}
<li><a href="{ROOT_URL}calendar/{currentView}/{ID}">{title}</a></li>
{/LOOP}
<li role="separator" class="divider"></li>
<li><a href="{ROOT_URL}calendar/createCalendar">Create Calendar</a></li>
<li><a href="{ROOT_URL}calendar/editCalendar/{calendarID}">Edit Calendar</a></li>
<li><a href="{ROOT_URL}calendar/deleteCalendar/{calendarID}">Delete Calendar</a></li>
</ul>
</li>

View File

@ -0,0 +1,23 @@
<ul class="list-group">
{LOOP}
<li class="list-group-item btn-{displayColor}">
<p style="text-align: center;">{title}</p>
<p style="text-align: center;">{DTC}{event_time}{/DTC}</p>
<p>
<a href="{ROOT_URL}calendar/event/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a>
<a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a>
<a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a>
</p>
</li>
{/LOOP}
{ALT}
<li class="list-group-item">
<br />
<br />
<br />
<br />
<br />
</li>
{/ALT}
<a href="{ROOT_URL}calendar/createEvent?calendar_id={calendarID}&month={currentMonth}&day={currentDay}" class="list-group-item list-group-item-success"><i class="glyphicon glyphicon-plus"></i></a>
</ul>

View File

@ -0,0 +1,18 @@
<ul class="nav nav-pills">
<li class="dropdown pull-right">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Switch Date <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<form action="" method="post" class="form-horizontal">
<li><input type="date" name="date" id="date" class="form-control" value="{date}" /></li>
<li role="separator" class="divider"></li>
<li>
<button name="submit" value="submit" type="submit" class="btn btn-primary center-block">
Select Date
</button>
</li>
</form>
</ul>
</li>
</ul>

View File

@ -0,0 +1,12 @@
<span class="hour-body">
{LOOP}
<div class="hour-cell btn-{displayColor}">
<p class="event-title">{title}</p>
<a href="{ROOT_URL}calendar/event/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a>
<a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a>
<a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a>
</div>
{/LOOP}
{ALT}
{/ALT}
</span>

View File

@ -0,0 +1,8 @@
<ul class="nav nav-tabs">
<li><a href="{ROOT_URL}calendar/byDay/{calendarID}">Daily</a></li>
<li><a href="{ROOT_URL}calendar/byWeek/{calendarID}">Weekly</a></li>
<li><a href="{ROOT_URL}calendar/byMonth/{calendarID}">Monthly</a></li>
<li><a href="{ROOT_URL}calendar/byYear/{calendarID}">Yearly</a></li>
<li><a href="{ROOT_URL}calendar/events/{calendarID}">Events</a></li>
{calendarDropdown}
</ul>

View File

@ -0,0 +1,9 @@
<div class="row calendar-row">
{LOOP}
<div class="col-xs-1 calendar-cell">
<h4 class="{highlightedDate}">{day}</h4>{dayEventList}
</div>
{/LOOP}
{ALT}
{/ALT}
</div>