fullcalendar example

Costas

Administrator
Staff member
the full example, can be found at :
https://github.com/pipiscrew/fullcalendar-php-example




When is not logged-in, view full calendar, with read only permissions.
fcalendar2.jpg


this is the view of admin
fcalendar1.jpg


introduction :
the application runs in index.php, all workers are available to view the calendar. When user logged-in (login.php) has the point3 - point2 - at point4 can move the event(s).

point1 - anchor drives to login.php / when logged-in drivers to logout.php
point2 - lists the workers, added from point3 (saved to local sqlite)



I will not explain the login/logout already done, on previous articles. We will focus, on security and how manipulate the fullcalendar.js aka https://fullcalendar.io/

all the php scripts, contains as header :
JavaScript:
<?php
	$is_admin=false;
	@session_start();
	if (isset($_SESSION["id"])) {
		date_default_timezone_set("UTC");
		
		if ($_SESSION["login_expiration"] != date("Y-m-d"))
		{	
			session_destroy();
			header("Location: login.php");
			exit ;
		} else {
                        $is_admin=true;
                }
	}
?>

<!DOCTYPE html>

index.php - references
JavaScript:
<script type="text/javascript" src="assets/jquery-3.1.0.min.js"></script>
<script src="assets/bootstrap.min.js"></script>
<script type="text/javascript" src="assets/moment.min.js"></script>
<script type="text/javascript" src="assets/fullcalendar.min.js"></script>
<script src="assets/jquery-ui.min.js"></script> <!-- needed for drag&drop (customized download at official site final size 72kb)

the calendar html is as the following :
JavaScript:
			<div class="row">
				<div class="col-md-12">
					<div class="panel">
						<div class="panel-heading">
							<div class="panel-title"><h4>CALENDAR</h4></div>
						</div> 
						<div class="panel-body">
							<div class="row">
								<?php if($is_admin){ ?>
									<div class="col-md-3">
										<div id="external-events">
											<div class="legend">Create Event</div>

											<form action="add_user.php" id="create-event">
												<div class="input-group">
													<div class="inputer">
														<div class="input-wrapper">
															<input id="event-title" name="event-title" type="text" class="form-control">
														</div>
													</div>
													<div class="input-group-btn">
														<button id="add-event" type="submit" class="btn btn-flat btn-default">Add</button>
													</div> 
												</div> 
											</form>

											<div class="legend">Draggable Events</div>
											<div class="draggable-events">
												<?php 
												include 'config.php';

												$db = connect();

												$r = getSet($db,"select * from users order by user_mail", null);

												$elements = "";
												foreach($r as $row){
													if(strpos($row["user_mail"], '@') == FALSE )
													echo "<div class=\"fc-event\" data-userid=\"{$row["user_id"]}\">[B]{$row["user_mail"]}[/B] <button type=\"button\" class=\"close\">&times;</button></div>\r\n";
												}
												?>
											</div> 
											

												<input type="checkbox" id="drop-remove" checked/>
												<label for="drop-remove">Remove After Drop</label>
											

											

												<input type="checkbox" id="drop-type"/>
												<label for="drop-type">Add as day off</label>
											

										</div> 
									</div> 
									<div class="col-md-9">
									<?php } else{  ?>
										<div class="col-md-12">
									<?php }?>
    
											<div id="calendar"></div> 
										</div> 
									</div> 
							</div> 
						</div> 
					</div> 
				</div> 
			</div> 
		</div> 
    
		<div id="modaloSUBSECTOR" class="modal fade bs-example-modal-sm" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
			<div class="modal-dialog modal-sm">
				<div class="modal-content">

					<div class="modal-header">
            
						<button type="button" class="close" data-dismiss="modal">[B]×[/B][B]Close[/B]</button>
						<h4 class="modal-title" id="mySmallModalLabel">Please choose type </h4>
            
					</div>
					<div class="modal-body">
						<button type="button" id="btn_dayoff_type" data-eventid="1" class="btn btn-purple btn-block btn-ripple">home office</button>
						<button type="button" id="btn_dayoff_type" data-eventid="2" class="btn btn-blue btn-block btn-ripple">vacation</button>
						<button type="button" id="btn_dayoff_type" data-eventid="3" class="btn btn-teal btn-block btn-ripple">half-day vacation</button>
						<button type="button" id="btn_dayoff_type" data-eventid="4" class="btn btn-deep-orange btn-block btn-ripple">left</button>
						<button type="button" id="btn_dayoff_type" data-eventid="5" class="btn btn-success btn-block btn-ripple">compensate</button>
						<button type="button" id="btn_dayoff_type" data-eventid="6" class="btn btn-yellow btn-block btn-ripple">sickness/doctor</button>
						<button type="button" id="btn_dayoff_type" data-eventid="7" class="btn btn-brown btn-block btn-ripple">training</button>
						<button type="button" id="btn_dayoff_type" data-eventid="8" class="btn btn-blue-grey btn-block btn-ripple">public holiday</button>
						<button type="button" id="btn_dayoff_type" data-eventid="9" class="btn btn-inverted btn-block btn-ripple">personal leave</button>
            
						<div class="input-group">
							<div class="inputer">
								<div class="input-wrapper">
									<input id="event_comment" name="event_comment" type="text" class="form-control">
								</div>
							</div>
						</div> 
					</div>
				</div><!-- /.modal-content -->
			</div><!-- /.modal-dialog -->
		</div><!-- /.modal -->

Line 09 = if admin logged-in make the drag&drop area visible, make a DB connection enumerate the users.
Line 39 = when enumerating the users, add HTML5 attribute (userid) to each div, will be used for dbase record.
Line 53 = when admin use
JavaScript:
class="col-md-9"
otherwise use
JavaScript:
class="col-md-12"
for calendar.
Line 68 = modal with dayoff type.
Line 79-87 = modal hardcoded buttons, represent the dayoff types. All has the same ID (btn_dayoff_type) and different HTML5 data attribute (eventid), will be used for dbase record.



the js has as :
JavaScript:
//js
<script>
	//hold the user selection from modal
	var modal_selected_type;
	var modal_selected_color;
	var modal_event_html_element;
	var modal_event_date;

//instatiate calendar element, with our options
	var Calendar = {
		createCalendar: function() {
			var date = new Date(),
			m = date.getMonth(),
			d = date.getDate(),
			y = date.getFullYear();
			$('#calendar').fullCalendar({
					header: {
						left: 'prev,next today',
						center: 'title',
						right: 'month,agendaWeek,agendaDay'
					},
					events: {
						url: 'get_events.php',
						/*error: function() {
							$('#script-warning').show();
						}*/
					},
					firstDay: 0,
					isRTL: false,
					eventLimit: true,
					weekends : false,
					eventDurationEditable  : false, //disable resize
					<?php if ($is_admin) { ?>
						editable: true,
						droppable: true,
						drop: function(date) {
							//https://fullcalendar.io/docs1/dropping/drop/ -- function( date, allDay, jsEvent, ui ) { }
							//the object is
							console.log(date);

							if ($('#drop-type').is(':checked')) {

							} else {
								$("#modaloSUBSECTOR").modal('toggle');
							}

							//store to public variables - use it on modal button-click event + add_to_calendar procedure
							modal_event_html_element = $(this);
							modal_event_date = date;
						},
						eventDrop: function(event, delta, revertFunc) {
							//https://fullcalendar.io/docs/event_ui/eventDrop/
							console.log(event);
                
							var date_dropped = event.start['_d']; 
							date_dropped = moment(date_dropped).format('YYYY-MM-DD');

							$.ajax({
									url : "update_dayoff.php",
									type: "POST",
									data : {day_off_id:event.id, eventdate : date_dropped},
									dataType : "json",
									success:function(data, textStatus, jqXHR)
									{

										console.log(data);

										if (data!=100){ 
											revertFunc(); //everts the event's start/end date to the values before the drag. This is useful if an ajax call should fail.
											alert("ERROR");
										}
									},
									error: function(jqXHR, textStatus, errorThrown)
									{
										revertFunc();
										alert("ERROR - connection error");
									}
								}); 
                
						},
						eventClick: function(calEvent, jsEvent, view) {
                
							var rec_id = calEvent.id;
							console.log(rec_id);
                
							if (confirm(calEvent.title + "\r\n\r\nDo you want to delete")) {
								var del_confirm = prompt("Please write the world : delete", "PipisCrew");
								if (del_confirm != null) {
									if (del_confirm=="delete"){
										$.ajax({
												url : "del_dayoff.php",
												type: "POST",
												data : {day_off_id:rec_id},
												dataType : "json",
												success:function(data, textStatus, jqXHR)
												{

													console.log(data);

													if (data!=100){ 
														alert("ERROR");
													}
													else 
													$("#calendar").fullCalendar('removeEvents', rec_id);
													//or refresh the calendar only via
													//$("#calendar").fullCalendar("refetchEvents");
                                        
                                        
												},
												error: function(jqXHR, textStatus, errorThrown)
												{
													alert("ERROR - connection error");
												}
											});   
									}
								}
							}
						}
						<?php } ?>
				});

		},
		handleEventDragging: function(obj) {
			var eventObject = {
				title: $.trim(obj.find('span').text())
			};
			obj.data('eventObject', eventObject);
			obj.draggable({
					revert: true,
					revertDuration: 0,
					zIndex: 1999
				});
		},
		addEvent: function(title) {
			title = title.length === 0 ? "Missing Event Title" : title;
			var html = $('<div class="fc-event">[B]' + title + '[/B] <button type="button" class="close">&times;</button></div>');
			$('.draggable-events').append(html);
			Calendar.handleEventDragging(html);
		},
		init: function() {
			this.createCalendar();
		}
	}

Line 23 = get data from dbase the query (GET) as : get_events.php?start=2016-08-29&end=2016-10-08&_=1474657959047
Line 33 = remove edit/drop/click events & properties when is not admin
Line 36-49 = when a worker dropped to calendar, store to public vars the worker_html_element (contains the data-userid) + in which day dropped (*story1)
Line 51 = this event occured when the user move the timebar to another day, we read the dropped day and update the record (the get_events.php, returns also the record ID, will see it later on get_events.php)
Line 81 = this occured when the admin make a plain click to timebar, I used it for deletion!
Line 104 = after success del_dayoff.php postback remove the timebar from calendar

*story1 :
this opens the modal form, admin is able to choose the dayoff type as :
fcalendar3.png


when a button type clicked - raise this event :
JavaScript:
$(function() {
Calendar.init();
//modal - event button click
$(document).on("click", "#btn_dayoff_type", function(e) {
		e.preventDefault();

		//take button properties > assign to public vars
		modal_selected_type = $(this).data("eventid"); //eventtype id-is hardcoded to HTMLelement - needed to store it on the record
		modal_selected_color = $(this).css("background-color"); //get the color from HTMLelement - needed for calendar draw

		console.log("eventid :", modal_selected_type);
		console.log("color :", modal_selected_color);

		//get HTML5 attribute - is the dbase user_id (var assigned at drop callback)
		var user_id = modal_event_html_element.data("userid");

		//get the dropped date (var assigned at drop callback)
		var date_dropped = modal_event_date['_d']; //ex. Mon Sep 05 2016 02:00:00 GMT+0200 (Central Europe Daylight Time)
		date_dropped = moment(date_dropped).format('YYYY-MM-DD'); //moment.min.js - 2016-09-05

		var comment = $("#event_comment").val();

		console.log("userid :", user_id);
		console.log("date dropped :", date_dropped); 
		console.log("comment :", comment);

		store_day(user_id, modal_selected_type, date_dropped, comment);
});

Line 2 = Init the calendar.
Line 27 = Call store_day.

the store_day is as:
JavaScript:
function store_day(userid, typeid, eventdate, comment){
	console.log(userid,typeid,eventdate,comment);
	$.ajax({
			url : "add_dayoff.php",
			type: "POST",
			data : {userid:userid, eventdate : eventdate, typeid: typeid, comment: comment},
			dataType : "json",
			success:function(data, textStatus, jqXHR)
			{

				console.log(data);

				if (data==100){

					//close modal
					$("#modaloSUBSECTOR").modal('toggle');


					add_to_calendar();
				}
				else
				alert("ERROR");
			},
			error: function(jqXHR, textStatus, errorThrown)
			{
				alert("ERROR - connection error");
			}
		});    
}

//draw it at calendar
function add_to_calendar()
{
	////////////////////////////////////////////////////////////////////////
	//add to calendar
	////////////////////////////////////////////////////////////////////////
	var originalEventObject = modal_event_html_element.data('eventObject');

	var extendedEventObject = $.extend({}, originalEventObject);
	extendedEventObject.start = modal_event_date;

	//http://stackoverflow.com/a/7918786
	extendedEventObject.color = modal_selected_color; //"red";

	$('#calendar').fullCalendar('renderEvent', extendedEventObject, true);

	//remove from event list, when option is checked
	if ($('#drop-remove').is(':checked')) {
		modal_event_html_element.remove();
	}

	//clear global vars 
	modal_selected_type = "";
	modal_selected_color = "";
	modal_event_html_element = "";
	modal_event_date = "";
	$("#event_comment").val('');

	console.log(modal_selected_type, modal_selected_color, modal_event_html_element, modal_event_date);
}



get timebars :
JavaScript:
//get_events.php
<?php

    if (!isset($_GET["start"]) || !isset($_GET["end"]) || !isset($_GET["_"])) {
        echo json_encode(3);
        exit;
    } 

    include 'config.php';

    $db = connect();
	
	$rows = getSet($db, "select * from day_offs left join users on users.user_id=day_offs.user_id where date_occur between ? and ?",array($_GET["start"],$_GET["end"]));
	
	//create an array
	$record = array();
	
	//for each record
	foreach($rows as $row) {
		$datetime = new DateTime($row['date_occur']);
	 
		$event_type = $row['day_off_type'];
		
		//give to calendar bar the proper color
		switch ($event_type) {
			case 1 :
				$color = "#9B26AF";
				break;
			case 2 :
				$color = "#2095F2";
				break;
			case 3 :
				$color = "#009587";
				break;
			case 4 :
				$color = "#FE5621";
				break;
			case 5 :
				$color = "#5CB85C";
				break;
			case 6 :
				$color = "#FEEA3A";
				break;
			case 7 :
				$color = "#785447";
				break;
			case 8 :
				$color = "#5F7C8A";
				break;
			case 9 :
				$color = "#212121";
				break;
			 default:
				$color = "#212121";
			}
		
        //https://fullcalendar.io/docs/agenda/allDaySlot/
        //https://fullcalendar.io/docs/event_data/Event_Object/
		//convert mysql datetime to ISO8601 format FullCalendar compatible
		$record[] = array("id" => $row['day_off_id'],"title" => $row['user_mail'].$row['comment'],"color" => $color, "allDay" => true, "start" => $datetime->format(DateTime::ISO8601));
		//add it to array
	}

	echo json_encode($record);
?>




add time bar :
JavaScript:
//add_dayoff.php
<?php
    @session_start();

    if (!isset($_SESSION["id"])) {
        echo json_encode(1);
        exit;
    }
    else {
        date_default_timezone_set("UTC");

        if ($_SESSION["login_expiration"] != date("Y-m-d"))
        {	
            session_destroy();
            echo json_encode(2);
            exit;
        }
    }

    if (!isset($_POST["userid"]) || !isset($_POST["eventdate"]) || !isset($_POST["typeid"]) || !isset($_POST["comment"])) {
        echo json_encode(3);
        exit;
    } 

    include 'config.php';

    $db = connect();

    $sql = "INSERT INTO day_offs (day_off_type, user_id, date_occur, comment) VALUES (:day_off_type, :user_id, :date_occur, :comment)";
    $stmt = $db->prepare($sql);

    $stmt->bindValue(':day_off_type' , $_POST['typeid']);
    $stmt->bindValue(':user_id' , $_POST['userid']);
    $stmt->bindValue(':date_occur' , $_POST["eventdate"]);
    $stmt->bindValue(':comment' , $_POST["comment"]);

    $stmt->execute();

    $res = $stmt->rowCount();

    if($res == 1)
        echo json_encode(100);
    else
        echo json_encode(0);
?>

update time bar :
JavaScript:
//update_dayoff.php
<?php
    @session_start();

    if (!isset($_SESSION["id"])) {
        echo json_encode(1);
        exit;
    }
    else {
        date_default_timezone_set("UTC");

        if ($_SESSION["login_expiration"] != date("Y-m-d"))
        {	
            session_destroy();
            echo json_encode(2);
            exit;
        }
    }

    if (!isset($_POST["day_off_id"]) || !isset($_POST["eventdate"])) {
        echo json_encode(3);
        exit;
    } 

    include 'config.php';

    $db = connect();

    $sql = "update day_offs set date_occur=:date_occur where day_off_id=:day_off_id";
    $stmt = $db->prepare($sql);

    $stmt->bindValue(':date_occur' , $_POST['eventdate']);
    $stmt->bindValue(':day_off_id' , $_POST['day_off_id']);

    $stmt->execute();

    $res = $stmt->rowCount();

    if($res == 1)
        echo json_encode(100);
    else
        echo json_encode(0);
?>


the sqlite dbase is :
JavaScript:
-- ----------------------------
-- Table structure for day_offs
-- ----------------------------
CREATE TABLE "day_offs" (
	`day_off_id`	INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
	`day_off_type`	INTEGER,
	`user_id`	INTEGER,
	`date_occur`	TEXT,
	`comment`	TEXT
);


-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS "main"."users";
CREATE TABLE [users] (user_id INTEGER PRIMARY KEY, user_mail TEXT, user_password TEXT, user_level INTEGER);

sqlite doesnt have date field type, using dddd/mm/yy on TEXT field type, we are able to execute a query (get_events.php) like :
JavaScript:
select * from day_offs 
left join users on users.user_id=day_offs.user_id
where date_occur between '2016-09-23' and '2016-09-29'

more at https://www.sqlite.org/lang_datefunc.html



another example FullCalendar (display appointments, saved from erp)
https://www.pipiscrew.com/2015/01/js-fullcalendar/
 
Top