Scripts and Code for Let’s Talk Explained

To facilitate the full screen experience a manifest.JSON file was created. This allowed for the application to open without the browser container, once the website is added to the homepage.

{
  "short_name": "Let's Talk ",
  "name": "Let's Talk - Sex Ed for Kids",
  "icons": [
    {
      "src": "logoapp.jpg",
      "sizes": "192x192",
      "type": "image/jpg"
    }
  ],
  "start_url": "/index.html",
  "display": "standalone",
  "orientation": "landscape"
}

The index.html file is displayed when a user isn’t logged in, it consists of a form that facilitates user login into the application. This form links back to a database of users, the only user currently created  demouser and this user must log in with the passcode demouser1. This document links to both my own style in style.css and Font Awesome’s all.css which is where the login person icon and lock icon come from. Font Awesome CDN is a very quick and easy way to insert simple icons onto your webpage. This document then contains a form which links to ‘authenticate.php’, which processes the data gathered by the form. This form requires only two inputs, the username and the password, and the form method POST is used. The submit button has the value of “login”, but it simply submits the data entered into the form to be processed in  ‘authenticate.php’.

<html>
<head>
<meta charset="utf-8">
<title>Login</title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
        <link href="style.css" rel="stylesheet" type="text/css">
</head>
<body id="index">
<div></div>
<div class="login">
<div><img src="assets/logo.png" id="logo" class="logo"></div>
      
<form action="authenticate.php" method="post">
<label for="username">
<i class="fas fa-user"></i>
</label>
<input type="text" name="username" placeholder="Username" id="username" required><br>
<label for="password">
<i class="fas fa-lock"></i>
</label>
<input type="password" name="password" placeholder="Password" id="password" required>
<br>
<input type="submit" value="Login">
</form>
</div>
<div></div>
</body>
</html>

The ‘authenticate.php’ file uses session_start(); to create a session or resumes the current one based on a session identifier passed via the POST request. Next it connects to the database, the below file is connecting to a database on the local host, for security reason to avoid displaying my webdevcit login online. If there is an error with this connection, the process will be stopped and the error message will be displayed. Next this script checks for the data submitted in the form elements, if this data isn’t set an error will display. If neither fields have been filled then  the process will be stopped and the error message ‘You must enter both a username and password’ will display.Next we prepare our SQL statement using bind parameters (s = string, i = int, b = blob,). Bind parameters are a different way to insert data into a database using placeholders like “?”, and although it isn’t necessarily bad to input directly into a database, bind variables are more secure and can be more efficient. We then select the id and the password where the username is equal to ‘s’, the bind parameter string. We then execute the statement and store the result so that we can verify if that account exists in the database. If the username is present in that database we check that the password entered by the user corresponds with the one stored  in the database. If they correspond the user is now logged in so we create a session to remember data on the server across pages and bring them to the home.php page. If the password isn’t correct a password error is displayed, if the username isn’t present on the database a username error is displayed. This is an example of nested if statements. This php file has been adapted from a tutorial by David Adams on login systems.(2019)

<?php
session_start();
$DATABASE_HOST = 'localhost';
$DATABASE_USER = 'root';
$DATABASE_PASS = '123';
$DATABASE_NAME = 'phplogin';
$con = mysqli_connect($DATABASE_HOST, $DATABASE_USER, $DATABASE_PASS, $DATABASE_NAME);
if ( mysqli_connect_errno() ) {
		die ('Failed to connect to MySQL: ' . mysqli_connect_error());
}
if ( !isset($_POST['username'], $_POST['password']) ) {
	die ('You must enter both a username and password');
}
if ($stmt = $con->prepare('SELECT id, password FROM accounts WHERE username = ?')) {
	$stmt->bind_param('s', $_POST['username']);
	$stmt->execute();
	$stmt->store_result();
    if ($stmt->num_rows > 0) {
	$stmt->bind_result($id, $password);
	$stmt->fetch();
	if ($_POST['password'] === $password) {
		session_regenerate_id();
		$_SESSION['loggedin'] = TRUE;
		$_SESSION['name'] = $_POST['username'];
		$_SESSION['id'] = $id;
		header('Location: home.php');
	} else {
		echo 'Incorrect password!';
	}
} else {
	echo 'Incorrect username!';
}
$stmt->close();
}

The Home.php file begins with a session start(); as we need to use sessions, we must then check if the user is logged in and if the are not we force them back to the login page. The rest of this page is relatively straightforward, grids are used to style the page with a sidecar, which contains the logout and display profile buttons. At the time of writing this blog post the final version of this screen has not been completed, yet all the fundamental elements of functionality are present. <?=$_SESSION[‘name’]?> gets the name of the user from the database and allows for the home screen to be customised for the user that is currently logged in.  

<?php
session_start();
if (!isset($_SESSION['loggedin'])) {
	header('Location: index.html');
	exit();
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Home Page</title>
<link href="style.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
</head>
<body class="loggedin">
 <div><img src="assets/logo.png" id="logoheader"></div>
        <nav class="navtop">
		<div class="side">
   <div class="profile1"><a class='profile'href="profile.php"><i class="fas fa-user-circle"></i>Profile</a></div><div></div>
<div class="logout1"><a class='logout'href="logout.php"><i class="fas fa-sign-out-alt"></i>Logout</a></div>
		</div></nav>
        
<div class="content">
			<p>Welcome back, <?=$_SESSION['name']?>!</p>
<div class="newuser">  New Here ? <a href="puberty.html">Begin Journey</a> </div></div>
</body></html>

The Profile page connects to the database and reproduces the users information onto the page. We begin this file by starting a session and redirecting logged out users to the index page. We then connect to the database in the same way we did in ‘authenticate.php’. This page is styled using the same grid technique as was used in home.php. At the time of this blog post, this page also had not been completed. Initially, it had been thought that another table in the database would be used to gather users scores and track their progression through the application. However, as there is at present only one possible user for the application because it is a prototype, it was decided that local storage would be an appropriate way to track the users progression through the application. This page shows example of retrieving data from both the database and local storage. Below, profile information is retrieved using  the database, the user id is used here to select data from the database. This data is then displayed using <?=$_SESSION[‘name’]?>,<?=$email?>,<?=$password?>.Local storage is used to gather results from the various quizzes in the application, here an onload event triggers a function called scoreMe(); which checks for a score saved in local storage and gives feedback based on this score. This will be further developed to display medals and rewards based on scores achieved in tests, all the basic principles of this are evident from the below code.

<?php
<!--------PHP--------!>
session_start();
if (!isset($_SESSION['loggedin'])) {
	header('Location: index.html');
	exit();
}
$DATABASE_HOST = 'localhost';
$DATABASE_USER = 'root';
$DATABASE_PASS = '123';
$DATABASE_NAME = 'phplogin';
$con = mysqli_connect($DATABASE_HOST, $DATABASE_USER, $DATABASE_PASS, $DATABASE_NAME);
if (mysqli_connect_errno()) {
	die ('Failed to connect to MySQL: ' . mysqli_connect_error());
}
$stmt = $con->prepare('SELECT password, email FROM accounts WHERE id = ?');
$stmt->bind_param('s', $_SESSION['id']);
$stmt->execute();
$stmt->bind_result($password, $email);
$stmt->fetch();
$stmt->close();
?>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Profile Page</title>
		<link href="style.css" rel="stylesheet" type="text/css">
		<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
	</head>
	<body class="loggedin">
         <div><a href="home.php"><img src="assets/logo.png" id="logoheader"></a></div>
		<nav class="navtop">
			<div class="side">
                <div class="profile1"><a class='profile'href="profile.php"><i class="fas fa-user-circle"></i>Profile</a></div>
                <div></div>
				<div class="logout1"><a class='logout'href="logout.php"><i class="fas fa-sign-out-alt"></i>Logout</a></div>
			</div>
		</nav>
        <script>
    
function scoreMe(){
var periodscore = localStorage.periodScore;
document.getElementById("periodscore").innerHTML= periodscore;
var perscore = document.getElementById("periodscore").innerHTML;
//console.log(periodscore);}
// var score = localStorage.getItem('myScore');
if( perscore == "undefined"){console.log("Test Not Taken");}
else if( perscore <= "3"){console.log("You Failed");}
else if( perscore == "4"){console.log("You Passed");
                         document.getElementById("periodsmedal").style.display=("block")
                         document.getElementById("periodsmedal").style.innerHTML=("You Passed")}
}
            
 function load() {
        console.log("load event detected!");
        scoreMe();
      }
      window.onload = load;
        </script>
<!--------CSS--------!>
<style>#periodsmedal{
border: 2px solid red;
display: none;
}</style>
<!--------HTML---------!>
<html>
<div id="periods">
<div id="periodsmedal">YAY</div>
<div id="periodscore"></div>
</div>
</html>
        
		<div class="details">
			<h2>Profile Page</h2>
			<div>
				<p>Your account details are below:</p>
				<table>
					<tr>
						<td>Username:</td>
						<td><?=$_SESSION['name']?></td>
					</tr>
					<tr>
						<td>Password:</td>
						<td><?=$password?></td>
					</tr>
					<tr>
						<td>Email:</td>
						<td><?=$email?></td>
					</tr>
				</table>
			</div>
		</div>
	</body>
</html>

This is the script that supports the book pages in the application, an example of which is shown below

The below functions support the audio, at this point in development only one voiceover was created, once the others have been created an array will be used to store the different audio for every page. When the book button is pressed, the page reads the audio. The onlaod function plays he background music on loop once the window is loaded

var readme = new Audio();
readme.src = "assets/voiceover.mp3";
 
 
window.onload = function() {
    document.getElementById("assets/my_audio").play();
}

The below function allows the text div to expand and retract. After user testing this function will be altered so that the div is expanded by default as opposed to retracted by default. This function works using the grid template column style to effect the portion of the screen that is taken up by the text div. The function stores the “container” div, which is the ones that contains the text, as variable y. The function then calls and if function that retracts the div if it;s expanded and expands it if its retracted.

function readMe(){
     var y = document.getElementById("container");
if(y.style.gridTemplateColumns == '4fr 7fr 1fr 0fr'){y.style.gridTemplateColumns = '1fr 10fr 1fr 0fr';
document.getElementById("view").style.display = "none";}
    else{y.style.gridTemplateColumns = '4fr 7fr 1fr 0fr'; 
    document.getElementById("view").style.display = "block";}
}
 
 
function Menu(){
    var x = document.getElementById("hiddenbuttons");
   if( x.style.display == "block"){ 
       x.style.display = "none";
  } else {
    x.style.display = "block";
  }
}
 

The menu button works in a similar way. By storing the hidden buttons div as a variable x, it when uses an if statement to hide them if they are displayed and display them if the are hidden.

Both these functions utilize if statements to allow the buttons to both complete and reverse a function

Functions for individual framework pages

Below are an example of some of the functions contained in framework.js that are called by specific framework pages only. These functions effects animations, styles or inner html of the pages to which they are associated. They all support the functionality in the center image elements of the pages.

function sun(){
if(document.getElementById("sun").style.top = "300px"){document.getElementById("sun").style.top = "100px";document.getElementById("sun").style.transitionDuration = "1s";}
else{
document.getElementById("sun").style.top = "300px"; }
}
 
function circle(){
document.getElementById("circle").style.display= "block";
}
function egg(){
document.getElementById("egg").style.animationName="egg";
}
function blood(){
document.getElementById("egg").style.animationName="blood";
document.getElementById("blood").style.animationName="blood";
}
function pad(){
document.getElementById("info").style.display="block";
document.getElementById("infop").innerHTML="Used by placing the pad on the inside of your underwear where it can absorb the menstrual fluid as it leaves the vagina.Pads come in all shapes and sizes to fit you.Each pad should only be used once and should be changed at least every 4 hours.When you are finished using a pad, you need to wrap it up in tissue and throw it in the bin – never flush them down the toilet.";
 document.getElementById("infohead").innerHTML="Pads";
}
function tampon(){
document.getElementById("info").style.display="block";
document.getElementById("infop").innerHTML="Tampons are for inside the body and are inserted into the vagina. They absorb menstrual fluid as it is being released before it leaves the vagina.  Each tampon must only be used once and changed every 4-6 hours or sooner if it is full. Some tampons come with applicators and some do not. Pick the one you feel most comfortable using. They also come in different sizes. If it’s your first period you may want to use slim or a thin tampon.";
 document.getElementById("infohead").innerHTML="Tampons";
}
function menstrual(){
document.getElementById("info").style.display="block";
document.getElementById("infop").innerHTML="menstrual cups are for inside the body and are inserted into the vagina. Instructions with on the box will explain how to insert the cup. Cups do not come with an applicator, you will need to be comfortable touching your vagina to insert and remove the cup. Cups must be changed and cleaned every 12 hours and are reusable for up to a year. ";
 document.getElementById("infohead").innerHTML="Menstrual Cup";
}
function hideInfo(){
document.getElementById("info").style.display="none";
}
function help(){
document.getElementById("help").animationName="bounceIn";
}

There were quizzes implemented in the application to test user understanding of the covered topics. These were  facilitated using arrays which stored various questions and multiple choice answers, there were then displayed using javascript. When the quiz had been scored we added the score to local storage so it could be retrieved on the profile page. These pages all stored results to a different local storage variable. These quizzes were adapted from previous assignments and online tutorials . Below is the Javascript for one of the quizes

function Question(text, choices, answer) {
    this.text = text;
    this.choices = choices;
    this.answer = answer;
}
 
Question.prototype.isCorrectAnswer = function(choice) {
    return this.answer === choice;
}
 
function Quiz(questions) {
    this.score = 0;
    this.questions = questions;
    this.questionIndex = 0;
}
 
Quiz.prototype.getQuestionIndex = function() {
    return this.questions[this.questionIndex];
}
 
Quiz.prototype.guess = function(answer) {
    if(this.getQuestionIndex().isCorrectAnswer(answer)) {
        this.score++;
    }
 
    this.questionIndex++;
}
 
Quiz.prototype.isEnded = function() {
    return this.questionIndex === this.questions.length;
}
 
function populate() {
    if(quiz.isEnded()) {
        showScores();
    }
    else {   
        // show options
        var choices = quiz.getQuestionIndex().choices;
        for(var i = 0; i < choices.length; i++) {
            var element = document.getElementById("choice" + i);
            element.innerHTML = choices[i];
            guess("btn" + i, choices[i]);
        }
 
        showProgress();
    }
};
 
function guess(id, guess) {
    var button = document.getElementById(id);
    button.onclick = function() {
        quiz.guess(guess);
        populate();
    }
};
 
 
function showProgress() {
    var currentQuestionNumber = quiz.questionIndex + 1;
    var element = document.getElementById("progress");
    element.innerHTML = "Question " + currentQuestionNumber + " of " + quiz.questions.length;
    console.log(currentQuestionNumber);
        if (currentQuestionNumber == 1){
            console.log("hello");
            document.getElementById("arrow1").style.display = "block";
            document.getElementById("arrow2").style.display = "none";
            }
        else if (currentQuestionNumber == 2){
            document.getElementById("arrow2").style.display = "block";
            document.getElementById("arrow1").style.display = "none";
        }
};
 
 
function showScores() {
 
    document.getElementById("arrow1").style.display = "none";
    document.getElementById("arrow2").style.display = "none";
    document.getElementById("result").style.display = "block";
    console.log(quiz.score);
 localStorage.femanatomyScore = quiz.score;
    document.getElementById("resultheader").innerHTML = 'You got <b>' + quiz.score + '/' + questions.length + '</b> questions correct.';
};
 
// create questions
var questions = [
    new Question("", ["Ovary", "Fallopian Tube","Uterus"], "Ovary"),
    new Question("", ["Ovary", "Fallopian Tube", "Uterus"], "Uterus"),
 
];
 
// create quiz
var quiz = new Quiz(questions);
 
// display quiz
populate();

Here is the html associated with the above quiz,

/style>
</head>
<body>
    <div class="grid">
        <div id="quiz">
            <h1>What is this body part called ?</h1>
     
            <div class="buttons">
                <button id="btn0"><span id="choice0"></span></button>
                <button id="btn1"><span id="choice1"></span></button>
                <button id="btn2"><span id="choice2"></span></button>
 
            </div>
            <footer>
                <p id="progress">Question x of y</p>
            </footer>
        </div>
    </div>
    <img src="assets/arrow.png" id="arrow1">
    <img src="assets/arrow.png" id="arrow2">
<div id="result"><p id="resultheader"></p></div>
 
<script src="labelquiz.js"></script>
</body>
</html>

References

Adams, D (2019), ‘Secure Login System with PHP and MySQL’, CodeShack.io, accessed 04/05/2019 via <https://codeshack.io/secure-login-system-php-mysql/>.

Lauren@phantomesse (n.d) ‘Multiple CHoice Quiz’, CodePen accessed 10/04/2019 via <https://codepen.io/phantomesse/pen/YPrqLJ/>.


Hansan,M (2018) ‘Making a multiple choice quiz using javascript arrays’ Youtube accessed 10/04/2019 via <https://www.youtube.com/watch?v=3hu5n3xHsnw&t=252s

Leave a comment