INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Jobs

jQuery fullCalndar Alignment and Holidays

jQuery fullCalndar Alignment and Holidays

(OP)
Since I'm not sure if this is a JavaScript or CSS question, I am posting here because it is a JavaScript plug-in. On fullCalendar, I need to move the day numbers to the upper left when they seem to default to the upper right but so far I've not had any luck. I found numerous postings through Google that suggest various CSS but they either do nothing or they bunch up all the dates to the left on top of one another. I would also like the day row to have its own border.

Also, I need the calendar to automatically show certain holidays but not necessarily all of them. Is this possible?

Here is my current code, which is using PHP to get calendar events from the database:

CODE --> PHP/JavaScript

<script>
	$(document).ready(function() {
		$('#calendar').fullCalendar({
		weekMode: 'variable',
			header: {
				right: 'prev,next',
				left: 'title'
			},
			firstDay: 1, // Starts week on Monday
			handleWindowResize: true,
			selectable: false,
			selectHelper: true,
			select: function(start, end) {
				var title = prompt('Event Title:');
				var eventData;
				if (title) {
					eventData = {
						title: title,
						start: start,
						end: end
					};
					$('#calendar').fullCalendar('renderEvent', eventData, true); // stick? = true
				}
				$('#calendar').fullCalendar('unselect');
			},
			editable: true,			
			eventLimit: true, // allow "more" link when too many events
			
			
			eventRender: function(event, element, view) {
                  element.bind('click', function()  {
                         var day = ($.fullCalendar.formatDate( event.start, 'dd' ));
                         var month = ($.fullCalendar.formatDate( event.start, 'MM' ));
                         var year = ($.fullCalendar.formatDate( event.start, 'yyyy' ));
                          alert(year+'-'+month+'-'+day);
                         });
                   },
			
			
			events:
				[
					<?php
					$n = 0;
					for ($i=0;$i<=count($rowCat)-1;$i++) :
						$EntryID = $rowCat[$i]["ID"];
						$StartTime = strtotime(trim($rowCat[$i]["Start"]));
						$EndTime = strtotime(trim($rowCat[$i]["End"]));
						$DisplayName = trim($rowCat[$i]["StaffName"]);
						echo "{\ntitle: '$DisplayName',\n";
						if (!$rowCat[$i]["FirstName"] && !$rowCat[$i]["LastName"]) :
							$FormattedStart = date("Y-m-d", $StartTime);
							$FormattedEnd = ($EndTime > $StartTime) ? date('Y-m-d', strtotime('+1 day', $EndTime)): date("Y-m-d", $EndTime);
							echo "start: '$FormattedStart',\n";
							echo "end: '$FormattedEnd'";
							if (isset($_SESSION['AccessLevel']) && $_SESSION['AccessLevel'] > 1) :
								echo ",\n";
								echo "url: '/administration/events_admin.php?ID=$EntryID',";
							endif;
							echo "className: 'specialevent'\n";
							echo "}\n";
						else :
							$FormattedStart = date("Y-m-d\TH:i:s", $StartTime);
							$FormattedEnd = date("Y-m-d\TH:i:s", $EndTime);
							echo "start: '$FormattedStart',\n";
							echo "end: '$FormattedEnd'";
							if (isset($_SESSION['AccessLevel']) && $_SESSION['AccessLevel'] > 1) :
								echo ",\n";
								echo "url: '/administration/calendar_admin.php?ID=$EntryID',";
							endif;
							echo "className: 'calendarevent'\n";
							echo "}\n";
						endif;
						if(++$n !== $numRows) :
							echo ",\n\n";
						endif;
					endfor;
					?>
				],
				timeFormat: 'hh:mmt',
		});
		<?php
		if (isset($_COOKIE['CalendarDate'])) :
			$datePieces = explode('-', $_SESSION['CalendarDate']);
			$DateYear = $datePieces[0];
			$DateMonth = $datePieces[1];?>
			//$('#calendar').fullCalendar('gotoDate', '<?=$DateYear?>-<?=$DateMonth?>-01');
		<?php endif;?>
		});
</script> 

RE: jQuery fullCalndar Alignment and Holidays

i would add holiday as events and then specify that event as non-editable in the event object. you could also do so via a callback.

i think i'd also simplify the php output for the events and just push a json object rather than building the object manually.

i'd probably not bind the click event within with eventRenderer. is there a good reason why you are doing that rather than using the built in method (dayClick)? from memory, the jQuery method 'bind' is now deprecated too - use the on() method.

if you want to distinguish different classes of event (i.e. holiday from a booking) then you can use eventRenderer to do so.

CODE

eventRenderer: function (ev, elem, v){
  if(ev.description.toLowerCase.indexOf('holiday') >= 0){
    //event is a holiday
    elem.css({'background-color': "#08088A", color: "#EFFBFB"});
  }
}, 

RE: jQuery fullCalndar Alignment and Holidays

for the day number issue, the easiest solution is to change the .fc-day-number text alignment in the css file.

or if you want to do this programmatically, adding this code to the calendar options should do the trick (not tested)

CODE

viewRender: function(view, element){
  $('.fc-day-number').css('text-align', 'left');
},
windowResize: function(view){
 $('.fc-day-number').css('text-align', 'left');
}, 

as above, this code is not tested and I am not familiar with fullCalendar. this is just from five minutes with the docs and a quick view of the underlying source code of a rendered calendar.

RE: jQuery fullCalndar Alignment and Holidays

I am not sure what you mean by day row. but if you mean that you want a line under the day number then just apply a bottom border to the .fc-day-number class; either programmatically (beware of the frequent refreshes though) or in the css directly.

you also wanted to 'hide' days that were from a previous month. you can do this a number of ways. the easiest would be to prevent the event rendering for those days. to get rid of the dayNumber you can adjust the css for the fc-other-month class. again, either programmatically or in the css directly.

CODE

viewRender: function(){$('.fc-other-month').css('color','white');}); 


RE: jQuery fullCalndar Alignment and Holidays

(OP)
Doing it programmatically, the day is now to the left (!) but I was unable to hide the events of other months from showing.

For day "row", I meant that the day is on a line by itself and I want a horizontal line under that line to separate the date from the events. It's not too important but I am trying to emulate an existing hard-copy calendar in layout.

Also, is there some way to get whatever the current year and month is and save it as a PHP session? I have a separate printable version but it always reverts back to the current month so I need a way to query only the events from whichever month was being viewed. If there is a way, this would also solve the part of the events showing from other months because, getting the events from MySQL, it could just query the current month.

RE: jQuery fullCalndar Alignment and Holidays

By 'the day is now to the left' does this mean that you have achieved what you want?

For the bottom border my preference is that you edit the CSS directly. If you insist on doing it programmatically add the CSS command inside the viewRender event.

For a printable version it is almost certain my better to use Pdf. Considee using WebKit and html2pdf to create the PSF. This supports JavaScript abs ime gives the most faithful rendition of a webpage.

RE: jQuery fullCalndar Alignment and Holidays

(OP)
Yes, thank you, the day is now to the left and I don't care if it's CSS or done programmatically but either way, I've not been able to locate any references to the line creation below the date.

On the print version, whatever I use I need to remove the page's header and footer first which is why I was using a second printable page. It does want to print oddly with dates with fewer entries scrunched down and fuller dates very large. In fact, some are a bit too large so any printable version would need the font size reduced a bit.

However, you might be right that using html2pdf would be better. I don't know how well fullCalendar can handle it, nor even how to do it since I've never needed to print to PDF.

RE: jQuery fullCalndar Alignment and Holidays

fullCalendar will never know of html2pdf. the way it works is to launch an internal browser with full js capability and render the page internally.

if you want bits to be non-printing then simply put a style sheet in and add a @media print declaration with visibility set to hidden.

when you say that you have not been able to locate any reference to the line below the date, are you saying that the solution I offered does not work for you? It does work for me. this for example:

CODE

viewRender: function(view, element){
  $('.fc-day-number').css({'text-align':'left', borderBottom: "thin solid black"});
  $('.fc-other-month').css('color','white'); 
},
windowResize: function(view){
  $('.fc-day-number').css({'text-align':'left', borderBottom: "thin solid black"});
  $('.fc-other-month').css('color','white');
}, 

RE: jQuery fullCalndar Alignment and Holidays

(OP)
Scrolling through the earlier posts, I do not see this code so this is the first I've seen it. I'll try it in the morning so thank you for that. The other code you sent for suppressing days from other months does not work but I was away for most of the day and haven't researched it further so see why.

RE: jQuery fullCalndar Alignment and Holidays

i had a spare ten minutes so created a dummy version. originally as a jsFiddle but i realised you don't get full functionality with that. so here's the script in raw. it is entirely self contained: just copy it to a file and point your browser at it (apart from the ajax elements - see later).

CODE

<!DOCTYPE HTML>
	<head>
		<title>Calendar test</title>
		 <meta charset="utf-8">
		<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
		<link rel="stylesheet" href="http://fullcalendar.io/css/base.css?2.1.1">
		<link rel="stylesheet" href="http://fullcalendar.io/js/fullcalendar-2.1.1/fullcalendar.css">
		<style>
.holiday{background-color: red}
.normalEvent{background-color:green}
#dialog .formRow{clear:left; overflow-y:hidden; }
#dialog .formRow .label {float:left; width: 5em;}
#dialog .formRow .formData {float:left: width: 12em;}
#dialog .formRow .formData input{width: 10em;}
#dialog, #dialog select, #dialog input{
	font-family: "Calibri";
	font-size: 0.8em;
}
#dialog{
	width: 20em;
}
h1{
	color:white;
	margin-bottom: 1em;
	background-color: #444;
}
		</style>
		<script src="//code.jquery.com/jquery-1.10.2.js"></script>
		<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
		<script src="http://fullcalendar.io//js/fullcalendar-2.1.1/lib/moment.min.js"></script>
		<script src="http://fullcalendar.io//js/fullcalendar-2.1.1/fullcalendar.min.js"></script>
		<script>
var curEvent;
$(document).ready(function(){
	var ajaxServer = 'http://rathercurious.net/fullCalendarAjaxServer.php';
	//extend the prototype
	$.fn.addOption = function(optText, optValue){
        var option = new Option(optText, optValue);
        return this.append(option);
	}
	var opts = {
        select: function(start, end) {
			var el = $('#dialog');
			var s = fTime(start.hour(), start.minutes());
			var e = fTime(end.hour(), end.minutes());
			var d = fDate(start);
			if(s == '00:00') s = "09:30";
			if(e == '00:00') e = "17:30";
            $('#startTime').val(s);
            $('#endTime').val(e);
            $('#eventDate').val(d);
			$('#id').val(' ');
			$('#eventTitle').val('');
            el.dialog('open');
		},
        selectHelper: true,
        weekMode: 'variable',
		header: {
				right: 'prev,next,month,basicWeek,basicDay',
				left: 'title'
			},
		firstDay: 1, // Starts week on Monday
		handleWindowResize: true,
		selectable: true,
		editable: true,			
		eventLimit: true,
        timeFormat: 'hh:mmt',
        viewRender: function(view, element){
            $('.fc-day-number').css({
                    'text-align':'left', 
                    borderBottom: "thin solid black"});
            $('.fc-other-month').css('color','white'); 
        },
        windowResize: function(view){
            $('.fc-day-number').css({
                   'text-align':'left', 
                    borderBottom: "thin solid black"});
            $('.fc-other-month').css('color','white');
        },
		eventClick: function(event, jsEvent, view){
			$('#eventDate').val(fDate(event.start));
			$('#startTime').val(fTime(event.start.hour(), event.start.minutes()));
			$('#endTime').val(fTime(event.end.hour(), event.end.minutes()));
			$('#id').val(event.id);
			$('#eventTitle').val(event.title);
			$('#editable').val(event.editable);
			$('#dialog').dialog('open');
		},
		eventDrop: function(event, delta, revertFunc, jsEvent, ui, view){
			if(!event.start.hasTime()){
				revertFunc();
				return;
			}
			var eventData = {	id: event.id,
						start: event.start.format(),
						end: event.end.format(),
						title: event.title,
						allDay: event.allDay,
						editable: event.editable,
						action: 'updateEventDate'
					};
			$.ajax({
				url: ajaxServer,
				type: 'POST',
				dataType: 'json',
				success: function(data){
					if(data.result != 'ok'){
						revertFunc();
					}
				},
				data: eventData
			});
		},
        events: [
            {
                id: 1,
                title: 'default holiday',
                allDay: false,
                start: '2014-11-06T09:00-08:00',
                end:'2014-11-06T18:00-08:00',
                className:'holiday',
                editable: false
            },
        {
                id: 2,
                title: 'default event',
                allDay: false,
                start: '2014-11-07T09:00-08:00',
                end:'2014-11-07T18:00-08:00',
                className:'normalEvent',
                editable: true
        }
            ]
};	//end of options
    $('#calendar').fullCalendar(opts);
    for(var i = 8; i<=17; i++){
        $('#startTime').addOption(fTime(i,0), fTime(i,0));
        $('#startTime').addOption(fTime(i,30), fTime(i,30));
    }
    for (var i = 17; i<=24; i++){
        $('#endTime').addOption(fTime(i,0), fTime(i,0));
        $('#endTime').addOption(fTime(i,30), fTime(i,30));
    }
    function fTime(h, m){
        h = h==24 ? 0 : h;
        h = h < 10 ? '0' + h: h;
        m = m <10 ? '0' + m : m;
        return h + ':' + m;
    }
    function fDate(i){
        var d = i.date() < 10 ? '0' + i.date() : i.date();
        var m = i.month() < 9 ? '0' + (i.month +1) : i.month() + 1;
        return i.year() + '-' + m + '-' + d;
     }
     
    $('#eventSave').on('click', function(e){
        e.preventDefault();
        var eventData = {
            start: $('#eventDate').val() + 'T' + $('#startTime').val(),
            end: $('#eventDate').val() + 'T' + $('#endTime').val(),
            title: $('#eventTitle').val(),
			id:$('#id').val(),
            allDay: false,
			action: 'saveEvent',
			editable: $('#editable').val()
       };
	   $.ajax({
	   		url: 'ajaxServer',
			type: 'POST',
			dataType: 'json',
			success: function(data){
				$('#calendar').fullCalendar('removeEvents', data.id);
				$('#calendar').fullCalendar('renderEvent', data);
				$('#dialog').dialog('close');
			},
			data: eventData
	   });
    });
	$('#dialog').dialog({ autoOpen: false, closeOnEscape: false, buttons: [], modal: true});
	
});
		</script>
		
	</head>
	<body>

<h1>Don's Calendar Fiddle</h1>
<div id="calendar"></div>
<div id="dialog">
    <form>
        <div class="formRow">
            <div class="label">Event Title</div>
            <div class="formData"><input name="eventTitle" id="eventTitle" /></div>
        </div>
        <div class="formRow">
            <div class="label">Start Time:</div>
            <div class="formData"><select id="startTime"></select></div>
        </div>
        <div class="formRow">
            <div class="label">End Time:</div>
            <div class="formData"><select id="endTime"></select></div>
        </div>
        <div class="formRow">
            <div class="label"> </div>
            <div class="formData"><input type="button" id="eventSave" value="Save" />
			<input id="eventDate" type="hidden"/>
			<input id="editable" type="hidden"/>
			<input id="id" type="hidden" name="id" />
			</div>
        </div>
    </form>
</div>
	</body> 

the above uses ajax to send the updated event data to a server. here is a test php script to use for receiving and handling the data. you can easily change it to provide for proper saving and error management.

CODE --> ajaxServer.php

<?php
class base{
	public function load($data){
		foreach($this->fields as $field):
			if(isset($data[$field])):
				$this->$field = $data[$field];
			else:
				$this->$field = '';
			endif;
		endforeach;
	}
} 
class event extends base{
	public $fields = array('id', 'title', 'start', 'end', 'allDay', 'url', 'className', 'editable');
	public function save(){
		//save the incoming information	
		if(empty($this->id)):
			$this->id = rand(1,1000000);
		endif;
		if(strpos( strtolower($this->title), 'holiday') !== FALSE):
			$this->className = 'holiday';
		else:
			$this->className = 'normalEvent';
		endif;
		$this->editable = empty($this->editable) ? false: true;
		$this->allDay = empty($this->allDay) ? false : true;
		//if save was ok
		return true;
	}
	public function getObject(){
		date_default_timezone_set('America/Los_Angeles');
		$array = array(); 
		foreach($this->fields as $field):
			if($field == 'start' || $field == 'end'):
				$array[$field] = date("Y-m-d\TH:i:sO",strtotime($this->$field));
			else:
				$array[$field] = $this->$field;
			endif;
		endforeach;
		return json_encode($array);
	}
	
}
if(isset($_POST['action'])):
	switch ($_POST['action']):
		case 'saveEvent'://save the event
		//send it back with an ID
		$e = new event;
		$e->load($_POST);
		$e->save();
		echo $e->getObject();
		die;
		break;
		case 'updateEventDate':
			$e=new event;
			$e->load($_POST);
			$result = $e->save();
			echo json_encode(array('result'=> ($result) ? 'ok' : 'error'));
		die;
	endswitch;
endif;		
?> 

RE: jQuery fullCalndar Alignment and Holidays

i should add that the code above supports editing of the events, drag and drop of events and also creation of events by clicking on a day.

inevitably there are already a few bugs I have spotted. problem with only spending limited time on it. please use this version instead for testing

CODE

<!DOCTYPE HTML>
	<head>
		<title>Calendar test</title>
		 <meta charset="utf-8">
		<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
		<link rel="stylesheet" href="http://fullcalendar.io//css/base.css?2.1.1">
		<link rel="stylesheet" href="http://fullcalendar.io//js/fullcalendar-2.1.1/fullcalendar.css">
		<style>
.holiday{background-color: red}
.normalEvent{background-color:green}
#dialog .formRow{clear:left; overflow-y:hidden; }
#dialog .formRow .label {float:left; width: 5em;}
#dialog .formRow .formData {float:left: width: 12em;}
#dialog .formRow .formData input{width: 10em;}
#dialog, #dialog select, #dialog input{
	font-family: "Calibri";
	font-size: 0.8em;
}
#dialog{
	width: 20em;
}
h1{
	color:white;
	margin-bottom: 1em;
	background-color: #444;
}
		</style>
		<script src="//code.jquery.com/jquery-1.10.2.js"></script>
		<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
		<script src="http://fullcalendar.io//js/fullcalendar-2.1.1/lib/moment.min.js"></script>
		<script src="http://fullcalendar.io//js/fullcalendar-2.1.1/fullcalendar.min.js"></script>
		<script>
var curEvent;
$(document).ready(function(){
	var ajaxServer = 'ajaxServer.php';
	//extend the prototype
	$.fn.addOption = function(optText, optValue){
        var option = new Option(optText, optValue);
        return this.append(option);
	}
	var opts = {
        select: function(start, end) {
			var el = $('#dialog');
			var s = fTime(start.hour(), start.minutes());
			var e = fTime(end.hour(), end.minutes());
			var d = fDate(start);
			if(s == '00:00') s = "09:30";
			if(e == '00:00') e = "17:30";
            $('#startTime').val(s);
            $('#endTime').val(e);
            $('#eventDate').val(d);
			$('#id').val(' ');
			$('#eventTitle').val('');
            el.dialog('open');
		},
        selectHelper: true,
        weekMode: 'variable',
		header: {
				right: 'prev,next,month,basicWeek,basicDay',
				left: 'title'
			},
		firstDay: 1, // Starts week on Monday
		handleWindowResize: true,
		selectable: true,
		editable: true,			
		eventLimit: true,
        timeFormat: 'hh:mmt',
        viewRender: function(view, element){
            $('.fc-day-number').css({
                    'text-align':'left', 
                    borderBottom: "thin solid black"});
            $('.fc-other-month').css('color','white'); 
        },
        windowResize: function(view){
            $('.fc-day-number').css({
                   'text-align':'left', 
                    borderBottom: "thin solid black"});
            $('.fc-other-month').css('color','white');
        },
		eventClick: function(event, jsEvent, view){
			$('#eventDate').val(fDate(event.start));
			$('#startTime').val(fTime(event.start.hour(), event.start.minutes()));
			$('#endTime').val(fTime(event.end.hour(), event.end.minutes()));
			$('#id').val(event.id);
			$('#eventTitle').val(event.title);
			$('#editable').val(event.editable);
			$('#dialog').dialog('open');
		},
		eventDrop: function(event, delta, revertFunc, jsEvent, ui, view){
			if(!event.start.hasTime()){
				revertFunc();
				return;
			}
			var eventData = {	id: event.id,
						start: event.start.format(),
						end: event.end.format(),
						title: event.title,
						allDay: event.allDay,
						editable: event.editable,
						action: 'updateEventDate'
					};
			$.ajax({
				url: ajaxServer,
				type: 'POST',
				dataType: 'json',
				success: function(data){
					if(data.result != 'ok'){
						revertFunc();
					}
				},
				data: eventData
			});
		},
        events: [
            {
                id: 1,
                title: 'default holiday',
                allDay: false,
                start: '2014-11-06T09:00-08:00',
                end:'2014-11-06T18:00-08:00',
                className:'holiday',
                editable: false
            },
        {
                id: 2,
                title: 'default event',
                allDay: false,
                start: '2014-11-07T09:00-08:00',
                end:'2014-11-07T18:00-08:00',
                className:'normalEvent',
                editable: true
        }
            ]
};	//end of options
    $('#calendar').fullCalendar(opts);
    for(var i = 8; i<=17; i++){
        $('#startTime').addOption(fTime(i,0), fTime(i,0));
        $('#startTime').addOption(fTime(i,30), fTime(i,30));
    }
    for (var i = 17; i<=24; i++){
        $('#endTime').addOption(fTime(i,0), fTime(i,0));
        $('#endTime').addOption(fTime(i,30), fTime(i,30));
    }
    function fTime(h, m){
        h = h==24 ? 0 : h;
        h = h < 10 ? '0' + h: h;
        m = m <10 ? '0' + m : m;
        return h + ':' + m;
    }
    function fDate(i){
        var d = i.date() < 10 ? '0' + i.date() : i.date();
        var m = i.month() < 9 ? '0' + (i.month +1) : i.month() + 1;
        return i.year() + '-' + m + '-' + d;
     }
    $('#eventSave').closest('form').on('submit', function(e){
		e.preventDefault();
		$('#eventSave').trigger('click');
		
	});
    $('#eventSave').on('click', function(e){
        e.preventDefault();
        var eventData = {
            start: $('#eventDate').val() + 'T' + $('#startTime').val(),
            end: $('#eventDate').val() + 'T' + $('#endTime').val(),
            title: $('#eventTitle').val(),
			id:$('#id').val(),
            allDay: false,
			action: 'saveEvent',
			editable: $('#editable').val()
       };
	   $.ajax({
	   		url: ajaxServer,
			type: 'POST',
			dataType: 'json',
			success: function(data){
				$('#calendar').fullCalendar('removeEvents', data.id);
				$('#calendar').fullCalendar('renderEvent', data);
				$('#dialog').dialog('close');
			},
			data: eventData
	   });
    });
	$('#dialog').dialog({ autoOpen: false, closeOnEscape: false, buttons: [], modal: true});
	
});
		</script>
		
	</head>
	<body>

<h1>Don's Calendar Fiddle</h1>
<div id="calendar"></div>
<div id="dialog">
    <form>
        <div class="formRow">
            <div class="label">Event Title</div>
            <div class="formData"><input name="eventTitle" id="eventTitle" /></div>
        </div>
        <div class="formRow">
            <div class="label">Start Time:</div>
            <div class="formData"><select id="startTime"></select></div>
        </div>
        <div class="formRow">
            <div class="label">End Time:</div>
            <div class="formData"><select id="endTime"></select></div>
        </div>
        <div class="formRow">
            <div class="label"> </div>
            <div class="formData"><input type="button" id="eventSave" value="Save" />
			<input id="eventDate" type="hidden"/>
			<input id="editable" type="hidden"/>
			<input id="id" type="hidden" name="id" />
			</div>
        </div>
    </form>
</div>
	</body> 

CODE --> ajaxServer.php

<?php
class base{
	public function load($data){
		foreach($this->fields as $field):
			if(isset($data[$field])):
				$this->$field = $data[$field];
			else:
				$this->$field = '';
			endif;
		endforeach;
		$this->editable = $this->editable == 'false' ? false : true;
		$this->allDay = $this->allDay == 'false' ? false : true;
	}
} 
class event extends base{
	public $fields = array('id', 'title', 'start', 'end', 'allDay', 'url', 'className', 'editable');
	public function save(){
		//save the incoming information	
		if(empty($this->id)):
			$this->id = rand(1,1000000);
		endif;
		if(strpos( strtolower($this->title), 'holiday') !== FALSE):
			$this->className = 'holiday';
		else:
			$this->className = 'normalEvent';
		endif;
		$this->editable = empty(trim($this->editable)) ? false: true;
		$this->allDay = empty(trim($this->allDay)) ? false : true;
		//if save was ok
		return true;
	}
	public function getObject(){
		date_default_timezone_set('America/Los_Angeles');
		$array = array(); 
		foreach($this->fields as $field):
			if($field == 'start' || $field == 'end'):
				$array[$field] = date("Y-m-d\TH:i:sO",strtotime($this->$field));
			else:
				$array[$field] = $this->$field;
			endif;
		endforeach;
		return json_encode($array);
	}
	
}
if(isset($_POST['action'])):
	switch ($_POST['action']):
		case 'saveEvent'://save the event
		//send it back with an ID
		$e = new event;
		$e->load($_POST);
		$e->save();
		echo $e->getObject();
		die;
		break;
		case 'updateEventDate':
			$e=new event;
			$e->load($_POST);
			$result = $e->save();
			echo json_encode(array('result'=> ($result) ? 'ok' : 'error'));
		die;
	endswitch;
endif;		
?> 

RE: jQuery fullCalndar Alignment and Holidays

(OP)
Thank you for all that. It was a bit of an overkill answer for a simple question but I really appreciate it and am always happy to try new things.

It seems to work but I don't see how to tie it in to my existing database which is required. As it is, it seems to be free-standing without any relation to the rest of the site. The calendar administration form it still not working but I do need to be able to use it.

I noticed you did not use <html> or </html> tags. Are they obsolete now?

RE: jQuery fullCalndar Alignment and Holidays

(OP)
As an update, I have it tied back into my database but, of course, it still wants to open its own Ajax form momentarily before mine opens but that's easy to correct. It is also still showing events from the previous/next month but I've not attempted to fix that yet. The boxes around the days are also gone and, again, I've not tried to correct it yet. There is too much spacing above and below the calendar that I yet need to adjust.

Print version: I also added styles to make the header and footer not print so now the print version is much better but it does not expand longer entries so some do not print. The font size is fine for display but probably too large for printing onto a single sheet as needed.

External: I moved the styles into an external sheet. Before adding the embedded PHP I tried moving the JavaScript to an external file but it would not work so I moved it back but I think it must be embedded anyway to work in combination with the PHP. Here is what I have:

CODE --> JavaScript/PHP/HTML

<?php
include_once $_SERVER ['DOCUMENT_ROOT'] . "/functions/common.php";
accessRedirect(1);

$query = "SELECT c.ID, StaffID, Start, End, FirstName, LastName, 
		  CONCAT_WS(' ', IF(DisplayName IS NULL,FirstName,DisplayName), LEFT(LastName,1))
		  AS StaffName
  		  FROM calendar c
		  LEFT JOIN staff s ON StaffID = s.ID 
		  ORDER BY Start, DisplayName, FirstName, LastName";
$rowCat = DBConnect($query, "Multiple");
$numRows = DBConnect($query, "Count");

?><!DOCTYPE HTML>
	<head>
		<title>J. Lohr Staff Calendar</title>
		<meta charset="utf-8">
		<?php include("../includes/pageheader.php"); ?>
		<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
		<link rel="stylesheet" href="http://fullcalendar.io//css/base.css?2.1.1">
		<link rel="stylesheet" href="http://fullcalendar.io//js/fullcalendar-2.1.1/fullcalendar.css">
		<link rel="stylesheet" href="/style/calendar.css">
		<script src="//code.jquery.com/jquery-1.10.2.js"></script>
		<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
		<script src="http://fullcalendar.io//js/fullcalendar-2.1.1/lib/moment.min.js"></script>
		<script src="http://fullcalendar.io//js/fullcalendar-2.1.1/fullcalendar.min.js"></script>
		<script>
			var curEvent;
			$(document).ready(function(){
				var ajaxServer = 'ajaxServer.php';
				//extend the prototype
				$.fn.addOption = function(optText, optValue){
					var option = new Option(optText, optValue);
					return this.append(option);
				}
				var opts = {
					select: function(start, end) {
						var el = $('#dialog');
						var s = fTime(start.hour(), start.minutes());
						var e = fTime(end.hour(), end.minutes());
						var d = fDate(start);
						if(s == '00:00') s = "09:30";
						if(e == '00:00') e = "17:30";
						$('#startTime').val(s);
						$('#endTime').val(e);
						$('#eventDate').val(d);
						$('#id').val(' ');
						$('#eventTitle').val('');
						el.dialog('open');
					},
					selectHelper: true,
					weekMode: 'variable',
					header: {
							right: 'prev,next,month,basicWeek,basicDay',
							left: 'title'
						},
					firstDay: 1, // Starts week on Monday
					handleWindowResize: true,
					selectable: true,
					editable: true,			
					eventLimit: true,
					timeFormat: 'hh:mmt',
					viewRender: function(view, element){
						$('.fc-day-number').css({
								'text-align':'left', 
								borderBottom: "thin solid black"});
						$('.fc-other-month').css('color','white'); 
					},
					windowResize: function(view){
						$('.fc-day-number').css({
							   'text-align':'left', 
								borderBottom: "thin solid black"});
						$('.fc-other-month').css('color','white');
					},
					eventClick: function(event, jsEvent, view){
						$('#eventDate').val(fDate(event.start));
						$('#startTime').val(fTime(event.start.hour(), event.start.minutes()));
						$('#endTime').val(fTime(event.end.hour(), event.end.minutes()));
						$('#id').val(event.id);
						$('#eventTitle').val(event.title);
						$('#editable').val(event.editable);
						$('#dialog').dialog('open');
					},
					eventDrop: function(event, delta, revertFunc, jsEvent, ui, view){
						if(!event.start.hasTime()){
							revertFunc();
							return;
						}
						var eventData = {	id: event.id,
									start: event.start.format(),
									end: event.end.format(),
									title: event.title,
									allDay: event.allDay,
									editable: event.editable,
									action: 'updateEventDate'
								};
						$.ajax({
							url: ajaxServer,
							type: 'POST',
							dataType: 'json',
							success: function(data){
								if(data.result != 'ok'){
									revertFunc();
								}
							},
							data: eventData
						});
					},
					events: [
					<?php
					$n = 0;
					for ($i=0;$i<=count($rowCat)-1;$i++) :
						$EntryID = $rowCat[$i]["ID"];
						$StartTime = strtotime(trim($rowCat[$i]["Start"]));
						$EndTime = strtotime(trim($rowCat[$i]["End"]));
						$DisplayName = trim($rowCat[$i]["StaffName"]);
						echo "{\nid: $EntryID,\n";
						echo "title: '$DisplayName',\n";
						echo "allDay: false,\n";
						if (!$rowCat[$i]["FirstName"] && !$rowCat[$i]["LastName"]) :
							$FormattedStart = date("Y-m-d", $StartTime);
							$FormattedEnd = ($EndTime > $StartTime) ? date('Y-m-d', strtotime('+1 day', $EndTime)): date("Y-m-d", $EndTime);
							echo "start: '$FormattedStart',\n";
							echo "end: '$FormattedEnd'";
							if (isset($_SESSION['AccessLevel']) && $_SESSION['AccessLevel'] > 1) :
								echo ",\n";
								echo "url: '/administration/events_admin.php?ID=$EntryID',";
							endif;
							echo "className:'holiday',\n";
							//echo "className: 'specialevent',\n";
							echo "editable: false\n";
							echo "}\n";
						else :
							$FormattedStart = date("Y-m-d\TH:i:s", $StartTime);
							$FormattedEnd = date("Y-m-d\TH:i:s", $EndTime);
							echo "start: '$FormattedStart',\n";
							echo "end: '$FormattedEnd'";
							if (isset($_SESSION['AccessLevel']) && $_SESSION['AccessLevel'] > 1) :
								echo ",\n";
								echo "url: '/administration/calendar_admin.php?ID=$EntryID',";
							endif;
							echo "className: 'normalEvent',\n";
							//echo "className: 'calendarevent',\n,";
							echo "editable: true\n";
							echo "}\n";
						endif;
						if(++$n !== $numRows) :
							echo ",\n\n";
						endif;
					endfor;
					?>					
					]
			};	//end of options
				$('#calendar').fullCalendar(opts);
				for(var i = 8; i<=17; i++){
					$('#startTime').addOption(fTime(i,0), fTime(i,0));
					$('#startTime').addOption(fTime(i,30), fTime(i,30));
				}
				for (var i = 17; i<=24; i++){
					$('#endTime').addOption(fTime(i,0), fTime(i,0));
					$('#endTime').addOption(fTime(i,30), fTime(i,30));
				}
				function fTime(h, m){
					h = h==24 ? 0 : h;
					h = h < 10 ? '0' + h: h;
					m = m <10 ? '0' + m : m;
					return h + ':' + m;
				}
				function fDate(i){
					var d = i.date() < 10 ? '0' + i.date() : i.date();
					var m = i.month() < 9 ? '0' + (i.month +1) : i.month() + 1;
					return i.year() + '-' + m + '-' + d;
				 }
				$('#eventSave').closest('form').on('submit', function(e){
					e.preventDefault();
					$('#eventSave').trigger('click');
					
				});
				$('#eventSave').on('click', function(e){
					e.preventDefault();
					var eventData = {
						start: $('#eventDate').val() + 'T' + $('#startTime').val(),
						end: $('#eventDate').val() + 'T' + $('#endTime').val(),
						title: $('#eventTitle').val(),
						id:$('#id').val(),
						allDay: false,
						action: 'saveEvent',
						editable: $('#editable').val()
				   };
				   $.ajax({
						url: ajaxServer,
						type: 'POST',
						dataType: 'json',
						success: function(data){
							$('#calendar').fullCalendar('removeEvents', data.id);
							$('#calendar').fullCalendar('renderEvent', data);
							$('#dialog').dialog('close');
						},
						data: eventData
				   });
				});
				$('#dialog').dialog({ autoOpen: false, closeOnEscape: false, buttons: [], modal: true});
				
			});
		</script>
	</head>
	<body>

<?php include("../includes/header.php"); ?>

<div id="calendar"></div>
<div id="dialog">
    <form>
        <div class="formRow">
            <div class="label">Event Title</div>
            <div class="formData"><input name="eventTitle" id="eventTitle" /></div>
        </div>
        <div class="formRow">
            <div class="label">Start Time:</div>
            <div class="formData"><select id="startTime"></select></div>
        </div>
        <div class="formRow">
            <div class="label">End Time:</div>
            <div class="formData"><select id="endTime"></select></div>
        </div>
        <div class="formRow">
            <div class="label"> </div>
            <div class="formData"><input type="button" id="eventSave" value="Save" />
			<input id="eventDate" type="hidden"/>
			<input id="editable" type="hidden"/>
			<input id="id" type="hidden" name="id" />
			</div>
        </div>
    </form>
</div>

<?php include("../includes/footer.php"); ?>

</body> 

RE: jQuery fullCalndar Alignment and Holidays

ideally you would deliver events to the script via ajax or json. but otherwise you can just deliver via the options api as you are doing.

Quote:


it still wants to open its own Ajax form momentarily before mine opens
i don't understand that. if you are worried about the momentary flash of unstyled content (as it is proverbially known) then just add a css rule to set the #dialog to display: none

Quote:


It is also still showing events from the previous/next month but I've not attempted to fix that yet
the code deals with this. if it is not working then there is something in whatever you are doing that is overriding the style rules.

Quote:


The boxes around the days are also gone and, again, I've not tried to correct it yet
sorry but I don't understand. it sounds as if you are not loading one of the required style sheets. but you are at liberty to style the calendar precisely as you want.

Quote:


it does not expand longer entries so some do not print.

typically a calendar view is not the best for print. you may be better off printing a succession of agenda/weeks.


the <html> tags are not deprecated but are inferred in most browser support of html5. it is better to include them.

Quote:


I think it must be embedded anyway to work in combination with the PHP.
there is no requirement for the javascript to be embedded. it will work equally well in a separate file.

RE: jQuery fullCalndar Alignment and Holidays

(OP)
Most of the things you quoted and referred to were simply my comments by way of updating the status and each indicated that I hadn't worked on the issue yet. I wasn't saying there was any problem, only that that's the way they are now.

I do, however, need to print the entire monthly calendar and all events must show and that is something I'm not sure, yet, how to fix. This is a staff scheduling calendar sent to each person before the end of the previous month so that they can plan accordingly.

On this:

Quote:

Quote: It is also still showing events from the previous/next month but I've not attempted to fix that yet

the code deals with this. if it is not working then there is something in whatever you are doing that is overriding the style rules.

I'm not sure what I may have done to make previous/next month entries still show since the formatting from the database entries is identical to the hard-coded sample events that were already there. Other than to add the database links, I've not yet changed anything in the JavaScript or CSS.

I've never used json or Ajax so it these are capable of writing to the database when things are dragged, that would be great. However, per our offline work that you and I have been discussing, the PHP form still needs to be functional in order to populate dates quickly.

RE: jQuery fullCalndar Alignment and Holidays

Quote:

I'm not sure what I may have done to make previous/next month entries still show

we may be talking at cross purposes. i thought you were referring to the day numbers (over which you have no control). You may be referring to the event entries themselves (over which you do have control).

If so, then this would be non-standard for a month view calendar (as would suppressing the day numbers). But if you want a solution, here are several:

1. programmatically.
a. have all events delivered as a javascript object outside of the calendar constructor.
b. on viewRender callback refresh all the events and then remove them with a callback filter that checks the date.

or
b. on viewRender callback, remove all the events and then iterate through the javascript object testing the dates and adding them back in using renderEvent.

or
a. have all the events delivered as a javascript array of objects of the calendar constructor and store them in a structured format such as [year][month][day][{events}].
b. on viewRender callback remove all the events and then iterate through the object at the right point, derived from the knowledge of the current year and month of the view.

2. client-server (preferred)
a. set the source of the events to a json server
b. whenever the view changes, programmatically remove all the events from the calendar and then refetch from the server.
c. have the server only deliver the events that are relevant to the month in question (or week/day in question).


obviously the client-server is the best method and probably the easiest to implement by far.

Quote:


I've never used json or Ajax

json is javascript object notation. you will have used it countless times; or at least overtime you use javascript.

ie.

CODE

var obj = {fruit: ['apples','oranges'], vegetables:['carrots','onions']}; 
the above is an object with each item of the object holding an array.

in php an associative array is equivalent to a javascript object. a numeric array is equivalent to a javascript array. you can use json_encode to get php to collapse an array for output as an object. eg.

CODE

<?php
$array = array('fruit'=>array('apples','oranges'), 'vegetables'=>array('carrots','onions'));
echo json_encode($array);
//output
{"fruit":["apples","oranges"],"vegetables":["carrots","onions"]} 

just as it is very useful to hold structured data inside arrays within php, json is very useful for communicating structured data between systems. and particularly non-identical systems like javascript and php. so most ajax servers are designed to take POST input and return json output. jQuery automatically parses the response from the server and expands it into a proper object that you can use just like any other object/array in javascript.

ajax is simply a useful term for addressing the XHR object within javascript. this allows the browser to send post or get data to a web server and receive a response without refreshing the page. there is nothing more to it than that (other than that you can make the interaction asynchronous or synchronous where as a full page request is always synchronous). so from the perspective of your php you just need to decide: 1. what to do with incoming data; and 2; whether to output a full page or just a tiny amount of json encoded data. I prefer making these decisions based on entry point. so anything addressing ajaxServer.php will only ever get json data back and never html. anything addressing index.php will only ever get the full monty. both ajaxServer.php and index.php are always just bootstraps in my code - after that everything is handled by the same dispatchers and routines so there is no code/effort duplication.


Quote:


I do, however, need to print the entire monthly calendar and all events must show and that is something I'm not sure, yet, how to fix.
set eventLimit to false in the constructor.

RE: jQuery fullCalndar Alignment and Holidays

(OP)

Quote:


we may be talking at cross purposes. i thought you were referring to the day numbers (over which you have no control). You may be referring to the event entries themselves (over which you do have control).

Yes, Think we were. Non-standard or not, I want events for only the current month to show and I know it probably needs to be done in the query which is why I asked how the calendar's programming can create a session value with the date. With that, I can modify the query to pull up only events for the current month.

Quote:


json is javascript object notation. you will have used it countless times; or at least overtime you use javascript.

As I've always been a back-end programmer, I've virtually never needed to use JavaScript except for an occasional onclick(), onchange() and that sort of basic thing. I am only just now starting to use it more with these odd projects I've been finding myself doing.

Quote:

I do, however, need to print the entire monthly calendar and all events must show and that is something I'm not sure, yet, how to fix.

Quote:

set eventLimit to false in the constructor.

The problem with setting eventLimit to false is that it misshapes the calendar in viewing mode. I had wanted it to show with the "More" links as it has been but to print showing all of them. No worries, though, as eventLimit: false is a good workaround.

RE: jQuery fullCalndar Alignment and Holidays

but you can do that with just print. if you use htmltopdf you can point the url to be printed at a php script that outputs eventLimit: false.

Quote:


how the calendar's programming can create a session value with the date
there is no way for a javascript to create a session variable. one is client side, the other server side.
but using ajax the script can request events between certain dates, very easily. and then the server can return only the events to show.

i have not tested this at all, and it is the work of only a few minutes and limited exposure to the fullCalendar API, but I believe that this approach will work. your server side script will receive the criteria in the POST vars and needs to rreturn properly formatted events as a numeric array of associative arrays, all json_encoded like this

CODE

echo json_encode(array('events'=>array( .... events ...)));
die; 

CODE

viewRender: function(view, element){
			switch(view.name){
				case 'month':
					if(view.start.month() != view.end.month()){
						var mD = view.end.month() - view.start.month();
						if(mD == 2){
							var y = view.start.year();
							if(view.start.month() == 11){
								var s = y+1 + '-01-01';
								var e = y+1 + '-01-31';
							} else {
								var s = y + '-' + (view.start.month() + 2) + '-01';
								var _t = new date(y, view.start.month() + 2, 0);
								var e = _t.getFullYear() + '-' + (_t.getMonth() + 1) + '-' + _t.getDate();	
							}
						} else if(mD == 1){
							if(view.start.date() == 1){
								var s = view.start.year() + '-' + (view.start.month() + 1) + '-01';
								var _t = new date(view.start.year(), view.start.month() + 2, 0);
								var e = _t.getFullYear() + '-' + (_t.getMonth() + 1) + '-' + _t.getDate();
							}
						}
					} else {
						var s = view.start.year() + '-' + (view.start.month() + 1) + '-01';
						var _t = new Date( view.start.year(), view.start.month() + 2,0);
						var e = _t.getFullYear() + '-' + (_t.getMonth() + 1) + '-' + _t.getDate();    
					}
				break;
				
				case 'basicDay':
				case 'agendaDay':
					var s = view.start.year() + '-' + (view.start.month() + 1 ) + '-' + view.start.date();
					var e = s;	
					break;
				case 'agendaWeek':
				case 'basicWeek':
					var s = view.start.year() + '-' + (view.start.month() + 1) + '-' + view.start.date();
					var e = view.end.year() + '-' + (1 + view.end.month() ) + '-' + view.end.date();;	
					break;
			}
			$.ajax({
				url: ajaxServer,
				type:'POST',
				dataType:'json',
				data:{
					action: 'getEvents',
					start: s,
					end: e
				},
				success: function(data){
					$('#calendar').fullCalendar('removeEvents');
					$('#calendar').fullCalendar('addEventSource', data.events);
				}
			})
			
            $('.fc-day-number').css({
                    'text-align':'left', 
                    borderBottom: "thin solid black"});
            $('.fc-other-month').css('color','white'); 
        }, 

RE: jQuery fullCalndar Alignment and Holidays

(OP)

Quote:

how the calendar's programming can create a session value with the date

Quote:

there is no way for a javascript to create a session variable. one is client side, the other server side.
but using ajax the script can request events between certain dates, very easily. and then the server can return only the events to show.

Yes, I know that but, as I've already embedded PHP into JavaScript, is there no way to do it to fetch the date? Better still, do the calendar's forward or back arrows submit anything that can be grabbed for the purpose? I mean, it appears that that's what you're saying but when I replace the viewRender I already had with that above, I get no calendar at all, and the update/insert form shows all the time so I'm not really sure what to do with it.

RE: jQuery fullCalndar Alignment and Holidays

There is probably a syntax error in the js.

RE: jQuery fullCalndar Alignment and Holidays

(OP)
Thank you, I'll give it a try! It has a totally different table design that mine currently but I suppose it should be easy to adjust. I'm only just starting to use MySQLi and I've not tried PDO at all on my development system so this will be a good test.

The link you provided just gives a gray screen with the title bar across the top so I couldn't test it but, since I've made many appearance modifications, I'll test yours as a copy before committing it to the "real" thing. It shouldn't be a problem.

You may recall that we were working off-line on a form - I'll still need to be able to use it too for bulk populating of the database - unless there is a way to drag from a box showing the staff members to a date in the calendar to populate several at a time that way. It's just a thought.

RE: jQuery fullCalndar Alignment and Holidays

Quote:


I'll test yours as a copy before committing it to the "real" thing. It shouldn't be a problem.
it's all working. there were (very) good reasons why I had to take it down fast.

Quote:


unless there is a way to drag from a box showing the staff members to a date in the calendar to populate several at a time that way. It's just a thought.

for sure that's a possibility. either in the pop-up dialog or whatever. wouldn't be too difficult to allow multiples in the creation routine (i.e. on selecting a day rather than an event). equally not difficult to assign staff by dropping the staff member on to an event. although the event prototype within fullcalendar does not support the nature of a staff member or resource attached to an event. and extending the prototype probably would lead to issues. so the most you would get visually is a text and colour signifier for each staff member. that may be enough though?

RE: jQuery fullCalndar Alignment and Holidays

(OP)
Your test is working now and I played with it a bit although I'm not sure anything was moving when dragged. It was hard to tell. Oh, I just realized that when I drag an event, it copies it rather than moves it and it is doing so quite well. (It's certainly colorful!)

There aren't many staff members nor will there ever be so I am thinking of a popup with a list of their names that could be dropped onto a date several at a time for perhaps a default start/end time of, say 9:30 AM to 5:30 PM. Then the entries could be edited one at a time if the times are different as some will be. But it would also need to be able to drag in special events from the same "staff" table that do no have start/end times because they are all day events or even span several days.

Should we discuss this off-line? it is quite a departure from my original question.

RE: jQuery fullCalndar Alignment and Holidays

Quote:


Should we discuss this off-line
sure.

Quote:


when I drag an event, it copies it rather than moves it
yes. to move an event use SHIFT + drag. the shift button must be pressed before the mousedown.

it would be better to have drag to move and ctrl to copy but on my system that interrupts with right mouse clicks. there's probably a workaround. neither are very touch friendly unfortunately.

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members!

Resources

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close