7 Replies - 5360 Views - Last Post: 31 March 2014 - 07:50 AM

#1 Melodia  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 8
  • Joined: 03-October 13

HTML/CSS/JavaScript scheduler

Posted 31 March 2014 - 05:24 AM

I was unsure as to whether I should put this in the HTML/CSS forum or the Javascript forum.

I was given this assignment where I have to create a weekly personal organiser where I can place different appointments of varying lengths at different times of the day, in such a way that one from 11:00 to 12:30 would overlap half of the 12:00 slot. Here is what I have so far:

index.html
<!DOCTYPE html>
<html>
	<head>
		<title>Organiser</title>
		<link rel="stylesheet" href="style.css">
		<script src="script.js"></script>
	</head>

	<body onload="expandTables()">
		<div>
			<header>
				<h1 id="temp"><em><u>Planner</u></em></h1>
			</header>

			<div id="main">
				<table class = "container">
					<tr>
						<td class = "container">
						    <table id="hours"></table>
						</td>
						<td class = "container">
						    <table id="monday">
						    </table>
						</td>
						<td class = "container">
						    <table id="tuesday">
						    </table>
					    </td>
						<td class = "container">
						    <table id="wednesday">
						    </table>
					    </td>
						<td class = "container">
						    <table id="thursday">
						    </table>
						</td>
						<td class = "container">
						    <table id="friday">
						    </table>
						</td>
						<td class = "container">
						    <table id="saturday">
						    </table>
					    </td>
						<td class = "container">
						    <table id="sunday">
						    </table>
						</td>
					</tr>
				</table>

			</div>


<div id="coverDiv">

<div id="formDiv" style="">
	<form id="form" name="form" action="" method="get">
						<p id = "errorText" class ="error"></p>
						<p>
							Appointment details:
						</p>
						<textarea id="details" name="details" rows="5" cols="2"></textarea>
						<p>
							<!-- Duration: -->
							<input type="time" id="duration" hidden>
						<p id = "durationerror" class ="error"></p>
							Start time:
							<input type="text" id="startTime" readonly>
							End time:
							<input type="time" id="endTime">
							Select a colour for this appointment:
							<input type="color" id="colour" value = 'red'>
							<INPUT type="button" name="submit" Value="Create" onclick="putDataIn(this.form)">
							<INPUT type="button" name="cancel" Value="Cancel" onclick="closeForm(this.form)">
						</p>
					</form>

					<p id = "testOutput"></p>

				</div>

			</div>

			<div id="appointments">

			</div>	
					<p id = "pageTest"></p>

		
			<nav>
				<p>
					<a href="/">Home</a>
				</p>
				<p>
					<a href="/contact">Contact</a>
				</p>
			</nav>

		</div>
	</body>
</html>






style.css
/*css*/

body {
    font-family: verdana;
}


.container {
	max-width: 10%;
}

.appointment {
	position: absolute;
	outline: 2px solid #1166ff;
	outline-offset: -2px;
	background-color: #0000ff;
	overflow : auto;
	

}

.pencil_icon {
	position: absolute;
	bottom: 0;
	left: 0;
	display: inline;
	width: 20px;
	height: 28px;
	float:right;
	z-index: 20;
	background-image: url(images/pencil20.png);
	background-repeat: no-repeat;
}

.x_icon {
	position: absolute;
	bottom: 0;
	right: 0;
	display: inline;
	width: 20px;
	height: 28px;
	float:right;
	z-index: 20;
	background-image: url(images/x.jpg);
	background-repeat: no-repeat;
}




#hours, #monday, #tuesday, #wednesday, #thursday, #friday, #saturday, #sunday {
	border-collapse: collapse;
	max-width: 100%;
	border: 1px solid black;
	background-color:pink;
}

#main {
	display: block;
	max-width: 100%;
}

html{
    background-color:blue;
}

td{
    background-color:lightYellow;
}
.error {
	color: red;
}
#formDiv {
	position: absolute;
	top: 10%;
	left: 10%;
	background-color: lightGray;
	width: 80%;
}

#temp{
    color:white;
    text-align: center;
}

#coverDiv {
	/*position: absolute;*/
	position: fixed;
	top: 0px;
	left: 0px;
	z-index: 10;
	width: 100%;
	height: 100%;
	background-color: rgba(0, 0, 0, 0.5);
	visibility: hidden;
}




script.js
var currentCell;
var durationHour;
var currentEditLeft;
var currentEditTop;
var currentEditWidth;
var currentEditHeight;
var normal = true;

function expandTables() {
	var hoursTable = document.getElementById("hours");
	var monday = document.getElementById("monday");
	var tuesday = document.getElementById("tuesday");
	expandHours(hoursTable);
	expandTable(monday);
	expandTable(tuesday);
	expandTable(wednesday);
	expandTable(thursday);
	expandTable(friday);
	expandTable(saturday);
	expandTable(sunday);
}

function expandHours(hoursTable) {
	createHeading(hoursTable);
	createHours(hoursTable);
}

function createHeading(table) {
	var row = document.createElement('tr');
	table.appendChild(row);
	var heading = document.createElement('th');
	row.appendChild(heading);
	// heading.style.border = "1px solid black";
	heading.innerHTML = table.id;
}

function createHours(table) {
	for (var i = 0; i < 24; i++) {
		var row = document.createElement('tr');
		table.appendChild(row);
		var cell = row.insertCell();
		cell.style.border = "1px solid black";
		cell.innerHTML = i + ":00";
	}
}

function expandTable(table) {
	createHeading(table);
	for (var i = 0; i < 24; i++) {
		var row = document.createElement("tr");
		table.appendChild(row);
		var cell = document.createElement("td");
		row.appendChild(cell);
		cell.className = i;
		cell.addEventListener("click", displayForm);
		cell.style.border = "1px solid black";
		cell.rowspan = "2";
		var div = document.createElement("div");
		cell.appendChild(div);
		div.style.height = "24px";
		div.style.width = window.innerWidth / 8 + "px";
		div.style.overflow = "auto";
		div.appendChild(document.createElement("br"));

	}
}

function displayForm() {
	document.getElementById("coverDiv").style.visibility = "visible";
	var formDiv = document.getElementById("formDiv");
	formDiv.style.visibility = "visible";
	currentCell = this;
	var box = document.getElementById("details");
	box.cols = (window.innerWidth * 0.8) / 13;
	var startTime = document.getElementById("startTime");
	var endTime = document.getElementById("endTime");
	document.getElementById("duration").value = "01:00";
	var startHour = currentCell.className;
	var endHour = parseInt(currentCell.className) + 1;

	if (startHour < 9) {
		startTime.value = "0" + startHour + ":00";
		endTime.value = "0" + endHour + ":00";
	} else if (startHour == 9) {
		startTime.value = "0" + startHour + ":00";
		endTime.value = endHour + ":00";
	} else {
		startTime.value = startHour + ":00";
		endTime.value = endHour + ":00";
	}

}

function putDataIn(form) {
	var details = form.details.value;
	var startTime = document.getElementById("startTime").value;
	var endTime = document.getElementById("endTime").value;

	var duration = document.getElementById("duration").value;
	var split = duration.split(":");
	durationHour = parseInt(duration);
	durationMinutes = parseInt(split[1]);
	("0" + durationHour).slice(-2);

	if (durationInHours() > 8) {
		durationerror.innerText = " Duration must be 8 hours or less. ";
		return;
	}

	if (endTime < startTime) {
		durationerror.innerText = " Appointment has to finish on the same day and can last at most 8 hours. ";
	
		return;
	}

	var appointment = document.createElement("div");
	var appointments = document.getElementById("appointments");
	appointments.appendChild(appointment);
	appointment.className = "appointment";
	
	appointment.addEventListener('mouseover', mouseEnter(displayImages), true);
	appointment.addEventListener('mouseout', mouseEnter(removeImages), true);
	if (normal === true) {

		appointment.style.left = currentCell.getBoundingClientRect().left + "px";
		appointment.style.top = currentCell.getBoundingClientRect().top + "px";
		appointment.style.width = (currentCell.getBoundingClientRect().right - currentCell.getBoundingClientRect().left) + "px";
		appointment.style.height = ((currentCell.getBoundingClientRect().bottom - currentCell.getBoundingClientRect().top) * durationInHours()) + "px";

	} else {
		appointment.style.left = currentEditLeft;
		appointment.style.top = currentEditTop;
		appointment.style.width = currentEditWidth;
		appointment.style.height = currentEditHeight;
		normal = true;
	}
	appointment.setAttribute("data-startTime", startTime);
	appointment.setAttribute("data-endTime", endTime);
	appointment.setAttribute("data-details", details);
	appointment.innerHTML = appointment.getAttribute("data-startTime") + " - " + appointment.getAttribute("data-endTime") + " " + appointment.getAttribute("data-details");
	// appointment.innerHTML = "aaa";
	appointment.style.background = colour.value;

	var rect2;
	rect2 = appointment.getBoundingClientRect();
	// alert("updated appoi " + rect2.left + " " + rect2.right);
	// alert(appointment.innerHTML);
	if (inputIsOk(form)) {
		// alert(currentCell.getBoundingClientRect().top);
		document.getElementById("formDiv").style.visibility = "hidden";
		document.getElementById("coverDiv").style.visibility = "hidden";
		durationerror.innerText = "";
		errorText.innerText = "";
		form.details.value = "";
	} else {
		appointments.removeChild(appointment);
	}

}

function durationInHours() {
	var startTime = document.getElementById("startTime").value;
	var endTime = document.getElementById("endTime").value;
	var duration = document.getElementById("duration").value;
	var endSplit = endTime.split(":");
	var startSplit = startTime.split(":");
	durationHour = parseInt(endTime) - parseInt(startTime);
	durationMinutes = parseInt(endSplit[1]) - parseInt(startSplit[1]);
	return durationHour + (durationMinutes / 60);
}

function inputIsOk(form) {
	var details = form.details.value;
	var startTime = document.getElementById("startTime").value;
	var endTime = document.getElementById("endTime").value;
	var duration = document.getElementById("duration").value;
	var errorText = document.getElementById("errorText");
	if (details == "") {
		errorText.innerText = "Must enter details. ";
	}
	if (duration == "") {
		durationerror.innerText = " Must enter duration. ";
	}
	if (endTime == "") {
		durationerror.innerText = " Must enter duration. ";
	}
	return details != "" && startTime != "" && endTime != "" && noOverlap();

}

function noOverlap() {
	var duration = document.getElementById("duration").value;
	durationHour = parseInt(duration);
	var errorText = document.getElementById("errorText");
	var appointments = document.getElementById("appointments");
	var rect1 = appointments.lastChild.getBoundingClientRect();
	var rect2;
	rect2 = appointments.children[0].getBoundingClientRect();
	
	for (var i = 0; i < appointments.children.length - 1; i++) {

		rect2 = appointments.children[i].getBoundingClientRect();

	
		if (rectangleOverlap(rect1, rect2)) {
			errorText.innerText = "This appointment coincides with another appointment. ";
			return false;
		}
	};
	return true;
}

function rectangleOverlap(rect1, rect2) {
	var overlap = !(rect1.right <= rect2.left || rect1.left >= rect2.right || rect1.bottom <= rect2.top || rect1.top >= rect2.bottom);
	
	return overlap;
}

function closeForm(form) {
	document.getElementById("coverDiv").style.visibility = "hidden";
	document.getElementById("formDiv").style.visibility = "hidden";
	durationerror.innerText = "";
	errorText.innerText = "";
	form.details.value = "";
}

function displayImages() {

	this.innerHTML = this.getAttribute("data-startTime") + " - " + this.getAttribute("data-endTime") + " " + this.getAttribute("data-details") + '<span class="pencil_icon" id="edit" onclick="editAppointment(this.parentNode)"></span> <span class="x_icon" id="close" onclick="removeAppointment(this.parentNode)"></span>';
}

function removeImages() {
	this.innerHTML = this.getAttribute("data-startTime") + " - " + this.getAttribute("data-endTime") + " " + this.getAttribute("data-details");
}

function mouseEnter(_fn) {
	return function(_evt) {
		var relTarget = _evt.relatedTarget;
		if (this === relTarget || isAChildOf(this, relTarget)) {
			return;
		}

		_fn.call(this, _evt);
	};
}

function isAChildOf(_parent, _child) {
	if (_parent === _child) {
		return false;
	}
	while (_child && _child !== _parent) {
		_child = _child.parentNode;
	}

	return _child === _parent;
}

function editAppointment(appointment) {
	currentCell = appointment;

	currentEditLeft = currentCell.getBoundingClientRect().left + "px";
	currentEditTop = currentCell.getBoundingClientRect().top + "px";
	currentEditWidth = (currentCell.getBoundingClientRect().right - currentCell.getBoundingClientRect().left) + "px";
	currentEditHeight = ((currentCell.getBoundingClientRect().bottom - currentCell.getBoundingClientRect().top) * durationInHours()) + "px";

	var appointments = document.getElementById("appointments");
	appointments.removeChild(appointment);
	var box = document.getElementById("details");
	box.cols = (window.innerWidth * 0.8) / 13;
	var startTime = document.getElementById("startTime");
	var endTime = document.getElementById("endTime");
	startTime.value = appointment.getAttribute("data-startTime");

	endTime.value = appointment.getAttribute("data-endTime");
	box.value = appointment.getAttribute("data-details");

	document.getElementById("coverDiv").style.visibility = "visible";
	var formDiv = document.getElementById("formDiv");
	formDiv.style.visibility = "visible";

	var rect2 = appointments.children[0].getBoundingClientRect();
	normal = false;

	
}

function removeAppointment(appointment) {
	appointment.parentNode.removeChild(appointment);
}

function test() {
	alert("here");
}

function empty() {

}

function createOutsideTable() {
	var main = document.getElementById("main");
	var table = document.createElement("table");
	main.appendChild(table);
	table.style.width = '100%';
	table.style.border = "1px solid black";
	var row = document.createElement("tr");
	table.appendChild(row);
	var cell = document.createElement("td");
	row.appendChild(cell);
	createHoursTable(cell);
	for (var i = 0; i < 7; i++) {

	}

	// cell.innerHTML = "aaimg";
	var tuesday = document.getElementById("tuesday");
	td.innerHTML = "aaa";
	tuesday.appendChild(tbl);
}

function tableCreate() {
	var main = document.getElementById("main");
	var tbl = document.createElement('table');
	tbl.style.width = '100%';
	tbl.style.border = "1px solid black";

	var tr = tbl.insertRow();
	main.appendChild(tbl);
	for (var i = 0; i < 7; i++) {

		var td;
		tr.appendChild(td);
		td.innerHTML = "bbb";
	}

}

function createDayTable() {


	for ( j = 0; j < 24; j++) {
		var row = document.createElement('tr');
		innerTable.appendChild(row);
		var cell = row.insertCell();
		cell.style.border = "1px solid black";
		cell.innerHTML = "aaa";
	}
	td.appendChild(innerTable);
}



http://www.dhtmlgood...ek-planner.html
Now, here is an example of the kind of functionality and intuitive UI I would love to have:

Here is the catch. I am absolutely limited to HTML/CSS and Javascript. I am not allowed use PHP, AJAX, SQL, XML etc. I am not even allowed use JQuery (this was explicitly stated). I am supposed to use the DOM to accomplish this, but I didn't get much out of W3Schools and don't really know where to begin. I'm not asking for code (since that would be cheating), but what would be great is a tutorial that can explain how this can be done to a dummy like me. I hate asking for assignment help on forums, but already have a reduced grade, since it wasn't up to scratch when it was due last week and I am becoming desperate for anything that will so much as push me in a forward direction.

Is This A Good Question/Topic? 0
  • +

Replies To: HTML/CSS/JavaScript scheduler

#2 andrewsw  Icon User is offline

  • blow up my boots
  • member icon

Reputation: 6444
  • View blog
  • Posts: 26,066
  • Joined: 12-December 12

Re: HTML/CSS/JavaScript scheduler

Posted 31 March 2014 - 05:36 AM

So does your code work? If not, do you have a specific question to ask about it?

A screenshot might help.

I appreciate the honesty of your post but you'll either need to ask specific questions or seach for "javascript calendar" or similar. There is a Tutorials link at the top of this page, maybe there's something in there.

Javascript Kit
Was This Post Helpful? 0
  • +
  • -

#3 Melodia  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 8
  • Joined: 03-October 13

Re: HTML/CSS/JavaScript scheduler

Posted 31 March 2014 - 06:52 AM

It sort of works now, but not in a very nice way. I've attached an image to this post. When you click a cell that form appears. You can edit the end-time, but the start-time will always be set to whichever cell you clicked. Once there, it will be fixed to that location (no drag functionality). It also will not save anything for when it is re-opened (though I am supposed to use cookies to do this. I can also only make events that are divided discretely by hour cell, i.e. no making event of 1 and half hours etc. It's certainly more passable than what I had last week, to look on the bright side of things. Nevertheless, what I have now probably won't compensate for the reduced grade.
Was This Post Helpful? 0
  • +
  • -

#4 Melodia  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 8
  • Joined: 03-October 13

Re: HTML/CSS/JavaScript scheduler

Posted 31 March 2014 - 07:00 AM

Sorry, I had not clicked the "attach this file" button on the last post. I should also mention that my hours column does not harmonize with the rest of the comments on my grid, which is a significant problem (as it is VERY noticeable).

Attached image(s)

  • Attached Image

Was This Post Helpful? 0
  • +
  • -

#5 andrewsw  Icon User is offline

  • blow up my boots
  • member icon

Reputation: 6444
  • View blog
  • Posts: 26,066
  • Joined: 12-December 12

Re: HTML/CSS/JavaScript scheduler

Posted 31 March 2014 - 07:17 AM

<table id="hours"></table>

You are using nested tables - Why??!! These are horrible things and should be avoided. You don't need them.

If you stick with them then you'll need to make some effort with the css to get the hours to line up, especially cross-browser.

Clicking a cell to produce the appointment details dialog is quite neat ;). The other things you mention (cookies, half-hours, etc.) are just things that you'll need to continue to work on. These are additional functionality. Work on them but, of course, if you encounter a particular problem then you could ask a question.

Personally, I would probably have split the table at half-hourly intervals and removed the border between two cells.

This post has been edited by andrewsw: 31 March 2014 - 07:18 AM

Was This Post Helpful? 0
  • +
  • -

#6 andrewsw  Icon User is offline

  • blow up my boots
  • member icon

Reputation: 6444
  • View blog
  • Posts: 26,066
  • Joined: 12-December 12

Re: HTML/CSS/JavaScript scheduler

Posted 31 March 2014 - 07:23 AM

Actually, I perhaps wouldn't have split at half-hours, but insert an absolutely positioned element into a relatively-positioned cell, giving the element a specific height and using top (or bottom) to span the half-hours correctly.

(I haven't studied how you are approaching it.)
Was This Post Helpful? 0
  • +
  • -

#7 Melodia  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 8
  • Joined: 03-October 13

Re: HTML/CSS/JavaScript scheduler

Posted 31 March 2014 - 07:31 AM

View Postandrewsw, on 31 March 2014 - 07:17 AM, said:

<table id="hours"></table>

You are using nested tables - Why??!! These are horrible things and should be avoided. You don't need them.

If you stick with them then you'll need to make some effort with the css to get the hours to line up, especially cross-browser.


I don't suppose there's a simple way of re-doing the tables properly without losing functionality?
Was This Post Helpful? 0
  • +
  • -

#8 andrewsw  Icon User is offline

  • blow up my boots
  • member icon

Reputation: 6444
  • View blog
  • Posts: 26,066
  • Joined: 12-December 12

Re: HTML/CSS/JavaScript scheduler

Posted 31 March 2014 - 07:50 AM

This text is just to stretch out the answer to more than the one word, no ;)
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1