8 Front End
pop1040 edited this page 3 years ago

Front end

Wishlist's frontend is a web page which uses CSS for all page transitions and vanilla javascript for any advanced actions and backend interaction. All dynamic content is accessed through the JSON api in the form of HTTP POST requests to /api/ (wishlist/api/).

JSON api interaction

The HTTP POST requests made to the JSON api are done through the AJAX api which is native to JavaScript and thus native to every browser. All calls to said api are managed through the request function:

function request(input, callback){
	// console.log(JSON.stringify(input));
	console.log('sending');
	let xhr = new XMLHttpRequest();
	xhr.open('POST', '/api/', true);

	//Send the proper header information along with the request
	xhr.setRequestHeader('Content-Type', 'application/json');

	xhr.onreadystatechange = function() { // Call a function when the state changes.
		if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
			let resp = JSON.parse(xhr.responseText);
			console.log(resp);
			callback(resp);
		}
	}
	xhr.send(JSON.stringify(input)); 
	console.log('sent');
}

This function calls XMLHttpRequest (this is AJAX, it was originally made for XML), the post content is set to the JavaScript object input parameter converted to JSON. When the server responds the onreadystatechange function is asynchronously called which converts the response to JSON and then calls the callback function provided as the second parameter. Usage of this function is demonstrated below.

Page transition mechanism (how the modals work)

Any modals, tabs or other pages are done entirely with CSS. Rather than loading a seperate page or using javascript when the user clicks a button that goes to another page (i.e. a settings page) or opens a modal like the add comment or a confirmation dialog on deleting a comment, the transition is done entirely with css. This works because the button is actually a label for a hidden checkbox (or radiobutton), which is then used in css selectors to turn on and off other pages and modals.

Example

The add comment modal uses a hidden checkbox. In the HTML the button to activate the modal is the following label:

<div class="center">
    <label class="bestButton" for="commentModal">Add wish</label>
</div>

this label when clicked toggles the following checkbox (as denoted by the for="commentModal" attribute)

<input type="checkbox" id="commentModal" class="modalControl">
<div>
    <div class="modal">
        ...more stuff...

Once this invisible checkbox is checked the following CSS

input.modalControl + div{
	display: none;
	position: fixed;
	top: 0;
	bottom: 0;
	left: 0;
	right: 0;
	background-color: rgba(143, 143, 143, 0.425);
	align-items: center;
	justify-content: center;
}
input.modalControl:checked + div{
	display: flex;
}

changes the modal div from display: none; to display: flex via the handy + CSS selector which selects the next sibling element in the HTML tree if it matches. In this case input.modalControl selects all input type element with the class modalControl, the :checked selector only selects those that are checked, and the + div selects all divs that directly follow one of the previously specified elements.

The modal div has CSS such that it overlays the whole page with a semi-transparent overlay.

Any page transfers such as settings pages or tabs will be identical except they will use radio buttons so only one can be active at a time.

Interfacing with JavaScript

To interface with this system from javascript the checkbox is first selected by it's ID and the .checked property is used to set it's state.

document.getElementById('commentModal').checked = false;

Page intialization

On page load the following code is run

window.onload = function(){
	addEvent(document, "keydown", function(evt) {
		evt = evt || window.event;
		let isEscape = false;
		if ("key" in evt) {
			isEscape = (evt.key === "Escape" || evt.key === "Esc");
		} else {
			isEscape = (evt.keyCode === 27);
		}
		if (isEscape) {
			qSelectAll(document, 'input.modalControl[type="checkbox"]:checked').forEach(el => el.checked = false);
		}
	});
	search(document.getElementById('search-comment-name').value, document.getElementById('search-comment-text').value);
}

which does two things.

  • First is sets up a hook so when the escape key is pressed any modal that is open is closed (via unchecking all check boxes for modal control).
  • The other thing it does is trigger the first search with no search text which is how the list of comments is first loaded.