Jan Buzard Web Portfolio

Portfolio

My portfolio includes class projects in HTML5, CSS3, JavaScript, Web Design and User Experience.

JavaScript

  • cms website
  • This part of the project is a church website that allows users to open copies of the sermons, registration forms and newsletters, to see a map to the church's location and other information. The site uses HTML and PHP files that were provided by the instructor. The JavaScript opens files in another browser tab, displays a map and hides unnecessary content. It uses event delegation.

    CMS Project

  • This is the main object for the JavaScript.
  • var mainObj = {}

  • These are global variables.
  • mainObj.popup = document.getElementsByTagName('table')[0];
    mainObj.headtag = document.getElementsByTagName('h1')[0];

  • This function runs from the script tag. It uses event listeners to determine which functions to run.
  • mainObj.init = function() {
    	if (this.headtag.firstChild.data==="Contact Us") {
    		window.addEventListener('load', this.displayMap, false);
    	}
    	else if (this.headtag.firstChild.data==="Sermons" || 
    	this.headtag.firstChild.data==="Newsletter and Registration Forms") {
    		this.popup.addEventListener('click', this.openPopup, false;
    	}
    	window.addEventListener('load', this.noDisplay, false);
    }

  • This function opens files in a new tab.
  • mainObj.openPopup = function(evt) {
    	var anc = evt.target || evt.srcElement;
    	evt.preventDefault();
    	var wind;
    	wind = window.open(anc.href, '_blank');
    	wind.focus();
    }

  • This function displays a Google map in an inframe by embedding it into the iframe.
  • mainObj.displayMap = function() {
    	var content = document.getElementById('content');
    	var iframe = document.createElement('iframe');
    	iframe.style.width = 600+"px";
    	iframe.style.height = 450+"px";
    	iframe.frameborder = 0;
    	iframe.style.border = 0;
    	iframe.src = "https://www.google.com/maps/embed?pb=!1m16!1m10!1m3!1d5905.
    	319257288266!2d-83.66637768623039!3d42.26444073766583!2m1!3f0!3m2!1i1024!2i768!
    	4f13.1!3m3!1m2!1s0x883ca92fc70f5e69%3A0xb00770ea6d3cb659!2s4800+E+Huron+
    	River+Dr%2C+Ann+Arbor%2C+MI+48105!5e0!3m2!1sen!2sus!4v1410330444829";
    	content.appendChild(iframe);
    }

  • This function hides some content that was on the page that was not needed.
  • mainObj.noDisplay = function() {
    	var contentAck = document.getElementById("contentAck");
    	contentAck.className = "hide";
    }

JavaScript and AJAX

  • cms website
  • This part of the project is for the site administrator to add content and make changes. It allows the administrator to upload text files of forms and newsletters and pdf files of sermons, change the sermon times and change the content of the pages. The site uses HTML, AJAX and PHP files that were provided by the instructor. The JavaScript uses flags from the PHP file to determine which page the content is saved to. It has functions to change the sermon times and upload and delete files from the server using AJAX and the PHP file. It uses the tinyMCE editor for changes to page content using AJAX and the PHP file. The functions from the main page JavaScript are included. It uses event delegation. The password for this is password.

    CMS Project

  • This is the main object for the JavaScript.
  • var chr = {}
    

  • These are global variables.
  • chr.popup = document.getElementsByTagName('table')[0];
    chr.headtag = document.getElementsByTagName('h1')[0];
    chr.thebody = document.getElementsByTagName('body')[0];
    chr.headtag = document.getElementsByTagName('h1')[0];
    chr.changesermon = document.getElementById('aside').getElementsByTagName('span')[0];
    chr.sermoninput = document.getElementById('aside');
    chr.upload = document.getElementById('subBtn');
    chr.sermon = document.getElementById('uploadSermon');
    chr.news = document.getElementById('uploadNewsForms');
    chr.delser = document.getElementById('delSer');
    chr.delnews = document.getElementById('delNewsForms');
    chr.save = document.getElementById('submitContent');
    chr.sermontable = document.getElementById('sermons');
    chr.newstable = document.getElementById('newsForms');
    chr.xmldiv = document.getElementById('xmlData');

  • This function runs from the script tag. It runs the events function.
  • chr.init = function() {
    	this.events();
    }
    

  • This function uses event listeners to determine which functions to run. It uses a condition to determine which page the event listener works on and to prevent JavaScript errors.
  • chr.events = function() {
    	window.addEventListener('load', this.noDisplay, false);
    	window.addEventListener('load', this.displayLink, false);
    	this.save.addEventListener('click', this.saveContent, false);
    	if (this.headtag.firstChild.data === "Sermons" || 
    	this.headtag.firstChild.data === "Newsletter and Registration Forms") {
    		window.addEventListener('load', this.changeButtons, false);
    		this.popup.addEventListener('click', this.openPopup, false);
    	}
    	if (this.headtag.firstChild.data === "Sermons") {
    		this.sermontable.addEventListener('click', this.deleteSermon, false);
    		this.upload.addEventListener('click', this.saveSermon, false);
    	}
    	if (this.headtag.firstChild.data === 'Newsletter and Registration Forms') {
    		this.newstable.addEventListener('click', this.deleteNews, false);
    		this.upload.addEventListener('click', this.saveNews, false);		
    	}
    	if (this.headtag.firstChild.data==="Contact Us") {
    		window.addEventListener('load', this.displayMap, false);
    	}
    }

  • This function changes the text on the buttons to upper case.
  • chr.changeButtons = function() {
    	var savebut = document.getElementById('submitContent');
    	savebut.value = savebut.value.toUpperCase();
    	var subbut = document.getElementById('subBtn');
    	subbut.value = subbut.value.toUpperCase();
    }

  • This function displays the link for changing service times. The event listener is used here to make it work only in this function.
  • chr.displayLink = function() {
    	chr.changesermon.className = "display";
    	chr.changesermon.innerHTML = "change service times";
    	chr.changesermon.addEventListener('click', chr.displayInputs, false);
    }

  • This function toggles between displaying and hiding the input boxes for changing the sermon times and between text displayed for the link. Form validation is added to make sure a time has been entered. The function also encodes the data and saves it on the page using AJAX and the PHP file. The embedded function makes sure that nothing is returned from the AJAX call because the PHP handles it.
  • chr.displayInputs = function(evt) {
    	var sermontime = evt.target || evt.srcElement;
    	if (sermontime.nodeName.toLowerCase() === 'a') {
    		var li = document.getElementsByTagName('li');
    		var inputs = document.getElementById('aside').getElementsByTagName('input');
    		inputslen = inputs.length;
    		lilen = li.length;
    		if (sermontime.firstChild.data === 'change service times') {
    			for (var i=0; i j) {
    			if (j === 0) {
    				data += inputs[j].value + '^^';
    			}
    			else {
    				data += inputs[j].value;
    			}
    			j++;
    		}	
    		data = encodeURIComponent(data);
    		Ajax.sendRequest('php/process.php', sermonTimes, data);
    	}
    	function sermonTimes(req) {
    		return;
    	}
    }

  • This function displays errors when uploading a file and runs event listeners for files that are sermons and files that are newsletters and forms.
  • chr.uploadFile = function(evt) {
    	var inputs = document.getElementById('xmlData').getElementsByTagName('input')[0];
    	var file = document.getElementById('file');
    	var sermonsubmit = document.getElementById('subBtn');
    	var newssubmit = document.getElementById('subBtn');
    	evt.preventDefault();
    	if (file.value === "") {
    		file.parentNode.lastChild.innerHTML = "";
    		file.parentNode.innerHTML += "Please select a file";
    	}
    	else if (file.value.substr(-3) !== "pdf") {
    		file.parentNode.lastChild.innerHTML = "";
    		file.parentNode.innerHTML += "Please select a pdf file";
    	}
    	else {
    		file.parentNode.lastChild.innerHTML = "";
    	}
    	if (chr.sermon) {
    		sermonsubmit.addEventListener("click", chr.saveSermon, false);
    	}
    	if (chr.news) {
    		newssubmit.addEventListener('click', chr.saveNews, false);
    	}
    }

  • This function does form validation for file type and file name, sends an AJAX request tp the PHP file to save the file and runs the openPopup function. it uses an embedded function to add the information to the table that lists and links the file names and add back the event listeners to the table.
  • chr.saveSermon = function(evt) {
    	evt.preventDefault();
    	var sermontable = document.getElementById('sermons');
    	var filename = document.getElementById('fileName').value;
    	var file = document.getElementById('file');
    	if (file.value === "") {
    		file.parentNode.lastChild.innerHTML = "";
    		file.parentNode.innerHTML += "Please select a file";
    	}
    	else if (file.value.substr(-3) !== "pdf") {
    		file.parentNode.lastChild.innerHTML = "";
    		file.parentNode.innerHTML += "Please select a pdf file";
    	}
    	else if (file.value !== '' && file.value.substr(-3) !== "pdf") {
    		file.parentNode.lastChild.innerHTML = "";
    	}	
    	else if (filename === '') {
    		file.parentNode.lastChild.innerHTML = "";
    		file.parentNode.innerHTML += "
    Please enter a file name"; } else { var sermonData = new FormData(); sermonData.append('file', file.files[0]); sermonData.append('data', 'ser^^'+filename); Ajax.sendRequest('php/process.php', sermonFile, sermonData, true); } function sermonFile(req) { chr.xmldiv.innerHTML = req.responseText; document.getElementById('sermons').addEventListener('click', chr.deleteSermon, false); document.getElementsByTagName('table')[0].addEventListener('click', chr.openPopup, false); } }

  • This function does the same thing as the saveSermon function for newsletter and forms files.
  • chr.saveNews = function(evt) {
    	evt.preventDefault();
    	var eventname = document.getElementById('eventName');
    	var eventdesc = document.getElementById('eventDesc');
    	var file = document.getElementById('file');
    	if (file.value === "") {
    		file.parentNode.lastChild.innerHTML = "";
    		file.parentNode.innerHTML += "Please select a file";
    	}
    	else if (file.value.substr(-3) !== "pdf") {
    		file.parentNode.lastChild.innerHTML = "";
    		file.parentNode.innerHTML += "Please select a pdf file";
    	}
    	else if (file.value !== '' && file.value.substr(-3) !== "pdf") {
    		file.parentNode.lastChild.innerHTML = "";
    	}	
    	else if (eventname.value === '' || eventdesc.value === '') {
    		file.parentNode.lastChild.innerHTML = "";
    		file.parentNode.innerHTML += "
    Please enter a file name or description"; } else { var newsData = new FormData(); newsData.append('file', file.files[0]); newsData.append('data', 'nf^^' + eventname.value + '^^' + eventdesc.value); Ajax.sendRequest('php/process.php', newsFile, newsData, true); } function newsFile(req) { chr.xmldiv.innerHTML = req.responseText; document.getElementById('newsForms').addEventListener('click', chr.deleteNews, false); document.getElementsByTagName('table')[0].addEventListener('click', chr.openPopup, false); } }

  • This function deletes the sermon file if the user clicks OK on the comfirm button, deletes the file information from the table and adds back the event listeners to the table.
  • chr.deleteSermon = function(evt) {
    	var cell = evt.target || evt.srcElement;
    	if (cell.className === 'delSermon') {
    		evt.preventDefault();
    		if (confirm('Do you want to permanently delete this file? Click OK if yes')) {
    			var data = 'delSer^^'+cell.id;
    			Ajax.sendRequest('php/process.php', delSermon, data);
    		}
    	}
    	function delSermon(req) {
    		chr.xmldiv.innerHTML = req.responseText;
    		document.getElementById('sermons').addEventListener('click', 
    		chr.deleteSermon, false);
    		document.getElementById('subBtn').addEventListener('click', chr.uploadFile, false);
    		document.getElementsByTagName('table')[0].addEventListener('click', 
    			chr.openPopup, false);
    	}
    }

  • This function does the same things as the deleteSermon function for the newsletters and forms.
  • chr.deleteNews = function(evt) {
    	var cell = evt.target || evt.srcElement;
    	if (cell.className === 'delNewsForms') {
    		evt.preventDefault();
    		if (confirm('Do you want to permanently delete this file? Click OK if yes')) {
    			var data = 'delNewsForms^^'+cell.id;
    			Ajax.sendRequest('php/process.php', delNew, data);
    		}
    	}
    	function delNew(req) {
    		chr.xmldiv.innerHTML = req.responseText;
    		document.getElementById('newsForms').addEventListener('click', 
    		chr.deleteNews, false);
    		document.getElementById('subBtn').addEventListener('click', chr.uploadFile, false);
    		document.getElementsByTagName('table')[0].addEventListener('click', 
    			chr.openPopup, false);
    	}
    }

  • This function uses flags from the PHP file to save changed content from the tinyMCE editor. It encodes the data and uses AJAX and PHP to save the content. The embedded function puts a timeout on displaying the alert.
  • chr.saveContent = function() {
    	var cont = tinymce.activeEditor.getContent();
    	var hidefile = document.getElementById('hiddenFile').value;
    	var data = 'c^^' + hidefile +'^^' + cont;
    	data = encodeURIComponent(data);
    	Ajax.sendRequest('php/process.php', contentSaved, data);
    	function contentSaved(req) {
    		var saved = document.getElementById('contentAck');
    		saved.className = "display";
    		setTimeout(function(){saved.className = "hide"},1000);
    	}
    }

HTML5, CSS3, JavaScript, AJAX, REST, HTML5 APIs

  • realtor website
  • This project is a website that finds properties on zillow.com using JavaScript and the HTML5 APIs. It is a one page HTML5 website that uses JavaScript to open the content on each tab. It uses REST to find the property and display nearby properties that are for sale. It uses the Google Maps API to display the map. It calculates the monthly payment. A list of properties can be added, viewed and deleted from lcoal storage.

    Realtor Project

HTML5

This uses the HTML5 DOCTYPE and several HTML5 tags.

  • <!DOCTYPE html> <html lang="en"> <head> <title>My Properties</title> <meta charset="utf-8" /> <link rel="stylesheet" href="css/styles.css" /> </head> <body> <div id="container"> <header> <div id="header"><h1>My Properties</h1></div> <div id="pic"></div> </header> <div id="contents" class="both"> <section id="prop"> <form method="post" action="index.html" id="form"> <fieldset> <legend>Enter Property Address</legend> <ul> <li><label for="address">Address:</label></li> <li><input type="text" id="address" name="address" tabindex="10" autofocus required></li> <li><label for="city">City:</label></li> <li><input type="text" id="city" name="city" tabindex="20" required></li> <li><label for="state">State:</label></li> <li><input type="text" id="state" name="state" tabindex="30" required></li> <li><label for="zip">Zip:</label></li> <li><input type="text" id="zip" name="zip" tabindex="40" required></li> <li><input type="submit" id="submit" name="submit" value="Submit" tabindex="50"></li> </ul> </fieldset> </form> <div id="addlist"> <input type="submit" id="add" name="add" value="Add Property To List" tabindex="60"> <h2>My Properties List</h2> <div id="proplist"> <ul> </ul> </div> </div> </section> <section id="info"> <div id="tabhead"> <ul> <li><a href="#" id="maptab" tabindex="70">Map</a></li> <li><a href="#" id="calctab" tabindex="80">Calculator</a></li> <li><a href="#" id="compstab" tabindex="90">Comps</a></li> </ul> </div> <div id="map"> <p>Map Will Appear Here</p> </div> <div id="calc" class="hide"> <form method="post" action="index.html" id="calculator"> <fieldset> <legend>Loan Calculator</legend> <ul> <li><label for="amount">Loan Amount:</label> <input type="text" id="amount" name="amount" tabindex="100"> <span></span><span></span></li> <li><label for="interest">Interest:</label> <input type="text" id="interest" name="interest" tabindex="110"> <span></span></li> <li><label for="months">Number of Months:</label> <input type="text" id="months" name="months" tabindex="120"> <span></span></li> <li><label>&nbsp;</label> <input type="button" id="getamt" name="getamt" value="Get Monthly Amount" tabindex="130"></li> </ul> </fieldset> </form> </div> <div id="comps" class="hide"> <p>Comps Will Appear Here</p> <table> </table> </div> </section> </div> </div> <script src="http://maps.google.com/maps/api/js?sensor=false"></script> <script src="js/Ajax.js"></script> <script src="js/realtor.js"></script> </body> </html>

CSS3

  • body {
    	font: 14px/1.5 verdana;
    	margin: 0;
    	padding: 0;
    	color: #568fdc;
    }
    .both {
    	clear: both;
    }
    #container {
    	width: 950px;
    	margin: 0 auto;
    }
    #contents {
    	padding: 25px 30px 20px 20px;
    	border: 1px solid #000;
    	border-radius: 0 0 10px 10px;
    	height: 662px;
    }
    header {
    	height: 103px;
    	margin-top: -20px;
    }
    #pic {
    	border-radius: 0 10px 0 0;
    	border-top: 1px solid #000;
    	border-right: 1px solid #000;
    	background: url(../images/house-header.jpeg) no-repeat;
    	margin-left: 461px;	
    	float: left;
    	width: 488px;
    	height: 103px;
    	margin-top: -103px;
    }
    #header {
    	border-radius: 10px 0 0 0;
    	border-top: 1px solid #000;
    	border-left: 1px solid #000;
    	width: 460px;
    	background: #560e0f;
    	float: left;
    	padding: 6px 20px 40px 0;
    	color: #fff;
    	margin-top: 20px;
    	margin-bottom: -1px;
    }
    h1 {
    	font-size: 20px;
    	padding-left: 20px;
    }
    header span {
    	width: 930px;
    	text-align: right;
    }
    ul {
    	list-style: none;
    	margin: 0;
    	padding: 0;
    }
    a {
    	text-decoration: none;
    }
    .hide {
    	display: none;
    }
    .display {
    	display: block;
    }
    .show {
    	display: inline;
    }
    section {
    	float: left;
    }
    #prop label {
    	display: block;
    	padding-top: 10px;
    	font-weight: bold;
    }
    fieldset {
    	border: 2px solid #f8b64c;
    	border-radius: 10px;
    }
    #prop fieldset {
    	width: 295px;
    	height: 295px;
    	margin: 0 65px 20px 0;
    	padding: 20px 0 20px 10px;
    }
    #prop input {
    	width: 175px;
    	font-size: 90%;
    }
    #prop #submit {
    	margin-top: 15px;
    	width: 60px;
    	color: #568fdc;
    	font-size: 12px;
    }
    #add {
    	width: 125px;
    	font-size: 12px;
    }
    h2 {
    	font-size: 16px;
    }
    #proplist span {
    	color: #000;
    	font-size: 10px;
    }
    #proplist a {
    	display: inline;
    	font-size: 10px;
    	font-weight: normal;
    }
    #info {
    	width: 520px;
    	height: 570px;
    	background: #ddd;
    	border-radius: 5px;
    }
    #tabhead {
    	height: 50px;
    	background: #f8b64c;
    	border-radius: 5px 5px 0 0;
    	padding-left: 3px;
    }
    #tabhead li {
    	display: inline-block;
    	width: 80px;
    	height: 40px;
    	background: #fff;
    	margin: 10px 0 0 1px;
    	border-radius: 5px 5px 0 0;
    }
    a {
    	color: #568cdc;
    	text-align: center;
    	display: block;
    	padding: 10px 0;
    	font-size: 12px;
    	font-weight: bold;
    }
    a:hover, li a.open {
    	color: #696180;
    }
    #comps table {
    	width: 500px;
    	margin: 10px;
    	border-collapse: collapse;
    }
    th {
    	background: #568fdc;
    	color: #fff;
    	padding: 3px 5px;
    }
    td {
    	border: 1px solid #f8b64c;
    	font-size: 10px;
    	color: #000;
    }
    #calc {
    	position: relative;
    }
    #calc fieldset {
    	width: 475px;
    	height: 195px;
    	margin: 10px;
    	padding-top: 10px;
    }
    #calc label {
    	text-align: right;
    	padding-right: 5px;
    	width: 150px;
    	display: inline-block;
    	font-size: 12px;
    	color: #000;
    }
    #calc li {
    	padding-bottom: 10px;
    }
    #calc input {
    	width: 130px;
    	font-size: 100%;
    	padding: 2px;
    }
    #calc #getamt {
    	color: #568fdc;
    	width: 138px;
    	font-size: 12px;
    }
    .blue, .red1, .red2, .red3 {
    	position: absolute;
    	font-size: 10px;
    }
    .blue {
    	color: #568fdc;
    	width: 170px;
    	top: 35px;
    	left: 330px;
    	font-weight: bold;
    	display: inline-block;
    	line-height: 25px;
    }
    .red1, .red2, .red3 {
    	color: #f00;
    	width: 180px;
    	margin-left: 5px;
    	left: 320px;
    }
    .red1 {
    	top: 35px;
    }
    .red2 {
    	top: 70px;
    }
    .red3 {
    	top: 105px;
    }
    .lm {
    	margin-left: 324px;
    }
    #proplist span.remove, #proplist span.view, #add, #submit, #getamt {
    	cursor: pointer;
    	color: #568fdc;
    }
    #proplist li {
    	color: #000;
    }
    #map {
    	width: 520px;
    	height: 530px;
    }
    #map p, #comps p {
    	margin: 10px;
    	color: #f00;
    }
    #map p.black, #comps p.black {
    	color: #000;
    	font-size: 10px;
    }
    #add {
    	color: #000;
    }
    #add[disabled] {
    	color: #777;
    }

JavaScript

This uses JavaScript, AJAX and the HTML5 APIs.

  • rel = { // global varibles used in more than one object map : document.getElementById('map'), maptab : document.getElementById('maptab'), calctab : document.getElementById('calctab'), compstab : document.getElementById('compstab'), comps : document.getElementById('comps'), calc : document.getElementById('calc'), init : function() { this.realtor(); this.disable(); this.right.init(); this.left.init(); this.rest.init(); }, // to do when page is loaded realtor : function() { rel.maptab.className = 'open'; // change text color on map tab rel.map.className = 'display'; // open map area // sets font color to black in map and comps areas rel.map.getElementsByTagName('p')[0].className = 'black'; rel.comps.getElementsByTagName('p')[0].className = 'black'; }, disable : function() { // disables Add Property to List button document.getElementById('add').disabled = 'disbled'; }, rest : { // global variables for rest object submit : document.getElementById('prop'), zpid : null, init : function() { // event listener for submit button this.submit.addEventListener('click', this.getRest, false); }, // runs function to get data from zillow // uses event delegation // enables Add Property to List button // works with submit button getRest : function(evt) { var sub = evt.target || evt.srcElement; if (sub.id === "submit" && document.getElementById('address').value !== '') {// add the rest of the form fields evt.preventDefault(); // enables add property to list button document.getElementById('add').disabled = ''; // runs openRest function rel.rest.openRest(); } //} }, // runs function to get data from zillow // does not use event delegation // disables Add Property to List button // works with view getRestData : function() { // disables add property to list button rel.disable(); // runs openRest function rel.rest.openRest(); //} }, // gets data from zillow using rest from form data // runs after the getRest or getRestData functions openRest : function() { // data from form var address = document.getElementById('address').value; var city = document.getElementById('city').value; var state = document.getElementById('state').value; var zip = document.getElementById('zip').value; // trimming, adding + and , to form data address = address.trim(); address = address.replace(/ /g,"+"); city = city.trim(); city = city.replace(/ /g,"+"); city = city + '%2C+'; state = state.trim(); state = state + '+'; zip = zip.trim(); // url to zillow data if (address.value !=='' || city.value !== '' || state.value !== '' || zip.value !== '') { var url='http://www.zillow.com/webservice/GetDeepSearchResults.htm?zws-id=X1-ZWz1b2purgbzm3_3e7gq&address='+address+ '&citystatezip='+city+state+zip; // encode url url = encodeURIComponent(url); // send request and run showMap function Ajax.sendRequest('php/getData.php',rel.rest.showMap, url); } }, // shows map with data from zillow and geolocation showMap : function(req) { // get data from zillow var xml = req.responseXML; // map size and class rel.map.style.width = '520px'; rel.map.style.height = '530px'; rel.map.className = "display"; // tabs showing and hidden rel.maptab.className = "open"; rel.calctab.className = ''; rel.compstab.className = ''; // calculator and maps hidden rel.calc.className = "hide"; rel.comps.className = 'hide'; // p tag for error messages var p = rel.comps.getElementsByTagName('p')[0]; p.className = ''; // check message code for xml if (xml.getElementsByTagName('code')[0].firstChild.data !== '0') { if (address.value !=='' || city.value !== '' || state.value !== '' || zip.value !== '') { map.innerHTML = "<p>We are sorry there is no map information for the address you entered.</p>"; p.innerHTML = "We are sorry there is no comparison information for the address you entered."; } } else { // get latitude and longitude var latitude = xml.getElementsByTagName('latitude')[0].firstChild.data; var longitude = xml.getElementsByTagName('longitude')[0].firstChild.data; // coordinates for google maps var coord = new google.maps.LatLng(latitude,longitude); // displays the map var themap = new google.maps.Map(map, {zoom: 15, center: coord, myTypeID: google.maps.MapTypeId.ROADMAP}); //displays the marker var marker = new google.maps.Marker({position: coord, map: themap}); // puts focus on the map // gets the zpid for comps rel.rest.zpid = xml.getElementsByTagName('zpid')[0].firstChild.data; // run the getComps function rel.rest.getComps(); } }, // gets comps from zillow getComps : function() { // url to zillow comps var url = 'http://www.zillow.com/webservice/GetDeepComps.htm?zws-id=X1-ZWz1b2purgbzm3_3e7gq&zpid='+rel.rest.zpid+'&count=25'; // enclode the url url = encodeURIComponent(url); // send request and run showComps function Ajax.sendRequest('php/getData.php',rel.rest.showComps, url); }, // shows comps in table showComps : function(req) { // get data from zillow var data = req.responseXML; // table tag var table = rel.comps.getElementsByTagName('table')[0]; // p tag var p = rel.comps.getElementsByTagName('p')[0]; // change class on p tag p.className = ''; // check for message code for data, put error in comps area if there are no comps if (data.getElementsByTagName('code')[0].firstChild.data !== '0') { p.innerHTML = "We are sorry there is no comparison information for the address you entered."; } else { // address from data var address = data.getElementsByTagName('address'); // length of address var addresslen = address.length; // clear out table and paragraph table.innerHTML = ''; p.innerHTML = ''; // tbody and table cells with data var tablecells = "<thead><tr><th>Address</th><th>City</th><th>State</th><th>Zip</th><th>Amount</th></tr></thead><tbody>"; for (var i=0; i<addresslen; i++) { // gets amount from xml file var amt = data.getElementsByTagName('amount')[i].firstChild.data; // formats number with commas amt = amt.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,"); // table cells with data from xml file tablecells += "<tr>"; tablecells += '<td>'+data.getElementsByTagName('street')[i].firstChild.data+'</td>'; tablecells += '<td>'+data.getElementsByTagName('city')[i].firstChild.data+'</td>'; tablecells += '<td>'+data.getElementsByTagName('state')[i].firstChild.data+'</td>'; tablecells += '<td>'+data.getElementsByTagName('zipcode')[i].firstChild.data+'</td>'; tablecells += '<td>$'+amt+'</td>'; tablecells += '</tr>'; } tablecells += '</tbody>'; } table.innerHTML = tablecells; }, }, left : { // global variables for left object add : document.getElementById('addlist'), prop : document.getElementById('prop'), listnode : document.getElementById('proplist').getElementsByTagName('ul')[0], address : document.getElementById('address'), city : document.getElementById('city'), state : document.getElementById('state'), zip : document.getElementById('zip'), init : function() { // functions and event listeners this.getData(); this.add.addEventListener('click', this.showList, false); this.listnode.addEventListener('click', this.removeView, false); }, // adds property to local storage // uses event delegation showList : function(evt) { var list = evt.target || evt.srcElement; evt.preventDefault(); // variables var inputs = prop.getElementsByTagName('input'); var values = []; var propdata; var props = []; // gets item from local storage props = JSON.parse(localStorage.getItem('properties')) || []; // puts values of input boxes into an JSON object if (list.value === 'Add Property To List') { for (var i=0; i<4; i++) { values.push(inputs[i].value.trim()); } // puts values into JSON format propdata = { 'address' : values[0], 'city' : values[1], 'state' : values[2], 'zip' : values[3] } // pushes data to array props.push(propdata); // adds data to local storage localStorage.setItem('properties', JSON.stringify(props)); // gets form inputs and set to '' rel.left.address.value = ''; rel.left.city.value = ''; rel.left.state.value = ''; rel.left.zip.value = ''; } // disableAdd Property to List button rel.disable(); // function to display data under My Properties List rel.left.getData(); }, // gets data from local storage and displays it on page getData : function() { // gets data from lcoal storage var data = localStorage.getItem('properties'); // parses data var jsondata = JSON.parse(data); var jsonlen; if (jsondata !== null) { jsonlen = jsondata.length; } // empties My Properties List rel.left.listnode.innerHTML = ''; // displays each data item under My Properties List for (var i=0; i<jsonlen; i++) { rel.left.listnode.innerHTML += '<li>[ <span class="remove" id="' + i + '">remove</span> ] [ <span class="view" id="' + i + '">view</span> ] <span>' + jsondata[i]['address'] + ' ' + jsondata[i]['city'] + ' ' + jsondata[i]['state'] + ' ' + jsondata[i]['zip'] + '</li>'; } }, // removes property from list or adds property values to form // uses event delegation removeView : function(evt) { var node = evt.target || evt.srcElement; evt.preventDefault(); // variables for local storage data var data = localStorage.getItem('properties'); var jsondata = JSON.parse(data); var jsonlen = jsondata.length; // remove from local storage by removing from array if (node.className === 'remove') { jsondata.splice(node.id,1); localStorage.setItem('properties', JSON.stringify(jsondata)); rel.left.getData(); } // view from local storage data by adding to form field values and running getRestData function else if (node.className === 'view') { var submit = document.getElementById('submit'); rel.left.address.value = jsondata[node.id]['address']; rel.left.city.value = jsondata[node.id]['city']; rel.left.state.value = jsondata[node.id]['state']; rel.left.zip.value = jsondata[node.id]['zip']; submit.addEventListener('submit', rel.rest.getRestData(), false); } }, }, right: { // global variables for right object info : document.getElementById('tabhead'), calc : document.getElementById('calc'), init : function() { // event listeners this.info.addEventListener("click", this.showTabContent, false); this.calc.addEventListener('click', this.validate, false); }, // shows content for each tab // uses event delegation showTabContent : function(evt) { var tab = evt.target || evt.srcElement; evt.preventDefault(); // variables var loan = document.getElementById('amount'); var interest = document.getElementById('interest'); var months = document.getElementById('months'); // initial class settings for variables // anchor tags variables rel.maptab.className = ''; rel.calctab.className = ''; rel.compstab.className = ''; // map, calculator and comps areas variables rel.map.className = 'hide'; rel.calc.className = 'hide'; rel.comps.className = 'hide'; evt.preventDefault(); if (tab.nodeName.toLowerCase() === 'a') { switch(tab.id) { // opens Map tab case 'maptab' : rel.maptab.className = "open"; // adds class to map anchor tag rel.map.className = "display"; // displays map area break; // opens Calculator tab case 'calctab' : rel.calctab.className = "open"; // adds class to calculator anchor tag rel.calc.className = "display"; // displays calculator area // hide form values on calculator tab loan.value = ''; interest.value = ''; months.value = ''; loan.focus(); // hide error messages and total on calculator tab var spans = document.getElementById('calc').getElementsByTagName('span'); spanslen = spans.length; for (var i=0; i<spanslen; i++) { spans[i].className = 'hide'; } break; // opens Comps tab case 'compstab' : rel.compstab.className = "open"; // adds class to comps anchor tag rel.comps.className = "display"; // displays comps area break; } } }, // form validation // payment calculation // uses event delegation validate : function(evt) { var submit = evt.target || evt.srcElement; evt.preventDefault(); // variables for error message spans, payment span and form fields var span0 = document.getElementById('calc').getElementsByTagName('span')[0]; var span1 = document.getElementById('calc').getElementsByTagName('span')[2]; var span2 = document.getElementById('calc').getElementsByTagName('span')[3]; var span3 = document.getElementById('calc').getElementsByTagName('span')[1]; var errors = '', msg1 = '', msg2 = '', msg3 = ''; var loan = document.getElementById('amount').value; var interest = document.getElementById('interest').value; var months = document.getElementById('months').value; // click on submit button in Calculator area if (submit.id === 'getamt') { interest = parseFloat(interest); months = parseInt(months); loan = loan.replace(/,/g,''); // replaces , with nothing loan = loan.replace('$',''); // replace $ with nothing loan = parseInt(loan); var intpattern = /^\d{0}\d*(\.\d{1,2})?$/g; var intcheck = intpattern.test(interest); var numpattern = /\D/g; var loancheck = numpattern.test(loan); var monthcheck = numpattern.test(months); span3.className = 'hide'; // error message for invalid data in loan amount if (loan === '' || loancheck || loan <= 0) { errors = '3'; // a flag for determining if errors or the amount should be displayed span0.className = 'red1'; msg1 = '<-You must enter a positive whole number greater than zero'; } // error message for invalid data in interest rate if (interest === '' || !intcheck || interest < .1) { span1.className = 'red2'; errors = '3'; // flag msg2 = '<-You must enter a number greater than or equal to .1'; } // error message for invalid data in number of months if (months === '' || monthcheck || months <= 0) { span2.className = 'red3'; errors = '3'; // flag msg3 = '<-You must enter a positive whole number greater than zero'; } // calculates the payment if (errors !== '3') { // changes data type from string to integer var rate = interest/1200; var payment = (rate + (rate/(Math.pow((1+rate),months)-1)))*loan; payment = payment.toFixed(2); payment = Intl.NumberFormat().format(payment); span0.className = 'hide'; span1.className = 'hide'; span2.className = 'hide'; span3.className = 'blue'; span3.innerHTML = 'Your monthly payment is:<br>$'+payment; } // displays error messages in span to right of input boxes else if (errors === '3') { span0.innerHTML = msg1; span1.innerHTML = msg2; span2.innerHTML = msg3; } } }, }, } //rel.init();</li>

Web Design

This is a redesign of an existing website, using vector art and yellow.

home page using vector art

This is an email ad for an existing website.

email ad

This is the home page for a website for an imaginary game.

home page for game site

This is an experimental web design style. Corkboard Sprawl uses the concept of a large bulletin board that people can explore.

corkboard sprawl style

This is a redesign of a website using the experimental web design style Dot Matrix. The website looks like a newsletter that was printed on a dot matrix printer.

dot matrix style

This is a redesign of a website using the experimental web design style Handdrawn Analog. Most of the website is handdrawn.

handdrawn analog style

This is a redesign of a website using the experimental web design style Mexican Pharmaceutical.

mexican pharmaceutical style

User Experience

  • Card Sorting
  • Navigation items were taken from an intranet website. Six volunteers sorted the carts by category. Data from the cart sort was analyzed and several categories were found to be similar from each cart sort.
  • Competitive Analysis
  • Competitor websites were analyzed and compared based on content, policies, terms, statements, navigation supported, search functionality, products and checkout.
  • Interface Redesign
  • The current site was analyzed for layout, color, graphics, interface elements, strengths and areas for improvement. Wireframes were made for a redesigned site, an analysis was done of the redesigned interface. Four imprementation options were discussed and one was recommended.

Version 1 of this website

Version 1 of Portfolio Website on GitHub

  • version 1 of index page of portfolio website

    version 1 of portfolio page of portfolio website
  • This is version 1 of the index page and portfolio page of my portfolio website.

Version 1 of this site includes links to class projects, a JavaScript slideshow of design projects, popups to display some of the projects and downloadable zip files of the code used in class projects and on this site.

This site uses HTML5, CSS3 and JavaScript. It was hand coded. It is standards complaint, validated on the W3C website for HTML5 and CSS3, accessible and semantic. It uses the Google font api for the header font.

This site uses responsive design. It uses media queries for breakpoints.

This site was designed using Adobe Photoshop CS6.

Current version of this website

  • version 2 of index page of portfolio website
  • This is version 2 of the index page of my portfolio website.

Version 2 of this site is the current version. The design has been changed to a more modern design. The portfolio content has been changed to display the code for JavaScript projects with an explanation of the code. The portfolio page has been changed to one page with an accordion.

In addition to the JavaScript from version 1 of this site, there is JavaScript to open and close the accordion.

Websites from jobs