This week's topic is about creating content for the Web.
Up to 10 points can be gained towards your final score by completing the in-class exercises on Friday.
This week's preparation is to watch three short videos about Web applications and three short videos about 'The Cloud', and then complete a couple of short exercises to experience some of the fundamental concepts.
Each set of three videos progresses from very simple to more detailed.
Web Apps
What is a Web App? | 1:48 | https://www.youtube.com/watch?v=qt6gSW-uYKI |
What is a web application? | 6:28 | https://www.youtube.com/watch?v=Hv3czsQh8tg |
Web pages, Websites, and Web Applications | 6:36 | https://www.youtube.com/watch?v=ylbQrYhfa18 |
The Cloud
Computer Basics: What Is the Cloud? | 2:31 | https://www.youtube.com/watch?v=4OO77HFcCUs |
What is the cloud? | 3:00 | https://www.youtube.com/watch?v=i9x0UO8MY0g |
The Three Ways to Cloud Compute | 7:09 | https://www.youtube.com/watch?v=SgujaIzkwrE |
There are two exercises below. The first shows how to run code in the user's browser. The second shows how to run a program on the server to generate page content dynamically.
If you do not want to try the second exercise then you skip the rest of this section.
If you want to try the second exercise then you will need to install a local Web server that can run server-side scripts. The most popular language for that is called PHP. Run the following command to check if you already have PHP installed on your computer:
php --version
If your shell says “command not found
” then expand the instructions below to learn how to install it.
The following two mini-projects illustrate (A) how to run a program in the client Web browser when displaying a page, and (B) how to run a program in the server to generate parts of a Web page dynamically. These techniques are the foundations of Web and cloud apps.
We have already seen some of the necessary parts for making a small Web app:
id
property and the getElementById()
JavaScript function.To make a small 'app' such as a click counter requires just a few additional things, which we will investigate soon:
p
).
Let's begin very simply and create a file containing just the HTML describing the visible structure of the application.
(You can call file called anything you like, including “index.html
”.)
The structure will have the following parts:
0
, and<!DOCTYPE html> <html> <body> <h1>Click counter</h1> <p> 0 </p> <p> <button> Count </button> </p> </body> </html>
The text content of a paragraph is stored in the innerHTML
attribute of the p
element.
Assigning a new value to the innerHTML
property of a paragraph will dynamically change what is displayed inside that paragraph.
For example, this will remove the old content of a p
whose id
is my-paragraph
and replace it with a 'Welcome' message:
document.getElementById('my-paragraph').innerHTML = 'Welcome to some new content!'
To run this code whenever a button is clicked, put the code in the onclick
property of the button.
The first time the button is clicked, the 0
that is initially in the paragraph will be replaced by a longer message.
Let's add the two things we need which are
an id
for the paragraph (we'll call it display
)
<p id="display"> 0 </p>
and the onclick
property for the button (containing the code that updates the paragraph's content).
<button onclick="document.getElementById('display').innerHTML = 'You clicked!';">
Click here to see the updated Web site code
The innerHTML
property of an element can also be read, so we can also store information there.
Let's store the value of the counter in the innerHTML
property of the display
paragraph.
One of the interesting things about JavaScript is that values can be used very freely.
If a string 'looks like' a number then you can treat it as a number (and perform arithmetic on it).
This means we can use the string stored in the innerHTML
of the display
paragraph to remember the numeric value of the counter
and to represent the string that should be displayed in the paragraph.
The +=
operator will increment its left-hand side by its right-hand side.
For example, x += 42
will increment x
by 42
.
Instead of assigning a new string to the display
, we'll use the +=
operator to add 1
to it.
<button onclick="document.getElementById('display').innerHTML = document.getElementById('display').innerHTML + 1;">
Click here to see the updated Web site code
Well, that almost worked!
Instead of adding 1 to the numeric value of the count (which is stored as a string),
JavaScript converted the 1
into a string and then added that to the end of the displayed count.
JavaScript 'pro-tip': if you have a string that you know represents a decimal integer then
to convert it into an actual integer you can use the 'unary +
' operator.
So, if x
contains the string "41"
then
x + 1
will be "411"
, whereas
+x + 1
will be 42
, which is exactly the effect we want when incrementing our counter.
Putting a unary +
in front of the left hand side of the binary +
operator makes the counter work properly.
<button onclick="document.getElementById('display').innerHTML = +document.getElementById('display').innerHTML + 1;">
Click here to see the updated Web site code
More complex Web apps will, of course, have a lot more JavaScript code.
The script
element provides a place to put JavaScript code (in a similar way to the style
element providing a place to put CSS code).
One advantage of using a script
element is that you can define things like 'helper functions' and global variables to store persistent values.
Let's tidy up the code of our Web app in the following ways:
display
paragraph just once, and remember it in a global variable called display
,onclick
action of the button.<script> var display = document.getElementById("display"); function count(amount) { display.innerHTML = +display.innerHTML + amount; } </script>
The first line of this script creates the global variable display
and assigns to it the element whose id
is display
.
(In other words, the variable will remember the p
paragraph element that is holding and displaying the current counter value.)
The last four lines of this script declare a function called count
with one parameter amount
.
When the function count
is called with a numeric argument it first
converts display.innerHTML
to an integer,
adds amount
to that integer,
and then stores the result back in display.innerHTML
.
Storing the results back into the display.innerHTML
has the side effect of causing the
browser to redraw the changed parts of the screen, thereby showing the updated counter.
The final Web app looks like this:
<!DOCTYPE html> <html> <body> <h1>Click counter</h1> <p id="display"> 0 </p> <script> var display = document.getElementById("display"); function count(amount) { display.innerHTML = +display.innerHTML + amount; } </script> <p> <button onclick="count(1)"> Count </button> </p> </body> </html>
1. Does it matter where you put the script
element? What happens if you move it to the start of the body
?
2. Add a second button that decrements the counter.
3. Replace the buttons with a row of four buttons labelled -10
, -1
, +1
, and +10
. Make the buttons add the appropriate amount to the counter. Add another row containing just one button labelled reset
that resets the counter to 0
when it is clicked.
4. Explore some more pieces of JavaScript. Maybe start with the functions ''setInterval'' and ''clearInterval'' which can be used to call a function regularly, for example, once every second. Use these functions to implement a stop watch with three buttons: “start”, “stop”, and “clear”.
Note: to run this example you (or one of your friends) need to have a computer with PHP installed.
PHP only needs to be installed on the server, so you can still try this example by connecting your browser (the client) to the app
running on your friend's Web server where PHP is installed.
To do this, instead of visiting localhost:8000/chat.php
just replace localhost
with the IP address of your friend's computer.
Since the app is 'served' from your friends Web server, there is nothing left for you to do (except maybe help them to implement the chat app!).
However, if you did install PHP on your computer, then please have fun following along with the rest of this project.
If you are still running the Python Web server, stop it first.
Create a directory for your chat project. Change to that directory and start the PHP Web server on port 8000.
mkdir WebChat cd WebChat php -S localhost:8000
(If you want your friends to be able to connect to your server, run “php -S 0.0.0.0:8000
” instead.)
What is the simplest text chat app that you can imagine? Obviously, at the very least, the client would need:
It could look something like the window shown on the right. So, just as with the simple counter Web app, let's begin by entering the HTML that we need to display the static structure of the page.
Because we will be running some PHP code every time the web page is accessed, we have to use a file name ending in .php
(instead of .html
).
You can call your file anything you like, but something like chat.php
would be appropriate.
Inside a .php
file you can write HTML, including CSS style and JavaScript that runs on the client,
exactly like any other Web page.
The following HTML will create the basic static structure of the page:
<html> <head> <title>PHP Chat</title> </head> <body> <p> <textarea rows="10" cols="80"> </textarea> </p> <p> <form> <input type="text" size="70" /> <input type="submit" value="send" /> </form> </p> </body> </html>
The new elements here are textarea
, form
, and input
.
A textarea
creates a box of a given size (rows and columns) that can display and/or allow editing of text.
input
creates various kinds of input element according to its type
attribute.
A text
input
creates a single-line text box that you can type into.
A submit
input
creates a button whose value
attribute can be used to set its label.
A form
groups several input
elements together and allows data from those elements to be sent ('posted') back to the server.
Within the form
, clicking the submit
input
button will cause the form
's data to be posted back to the server.
One source of data sent back to the server is the content of any text
input
boxes.
(Conveniently, pressing Enter
inside a text
input
box will also post the content of the form
back to the server.)
To demonstrate how PHP generates content in the page, let's insert the name of the server into the page title.
In addition to normal HTML, a .php
file can also contain opening “<?php
” and end “?>
” tags.
Between those tags is PHP code that is run on the server before the content of the file is sent back to the client in the response to the HTTP GET
request.
The tags and PHP code are removed from the page contents,
but anything that the PHP code prints while it is running is added to the page content.
The following PHP code prints the name of the server:
echo gethostname()
Adding that code into the content of the title
element, between <?php
and ?>
tags,
inserts the server name into the page title every time the client fetches the page.
<head> <title>PHP Chat @ <?php echo gethostname() ?></title> </head>
To send the form data back to the server we have to do three things:
form
how to reload the page when the submit button is pressed,text
input
how to name its content while the form is reloading, andtextarea
content as the page is reloading.
First, add two attributes to the form
to make it reload the page when its data is submitted.
The method
attribute says how to send the form data back to the server.
GET
and POST
are the usual ways, and we'll use POST
.
The action
attribute says what URL should be used to reload a 'result' Web page.
We will use the original chat app URL.
In PHP, variable names all begin with a dollar sign “$
”.
The PHP variable $_PHP_SELF
contains the URL of the app page.
<form action="<?php $_PHP_SELF ?>" method="POST"> <input type="text" size="70" name="send" /> <input type="submit" value="send" /> </form>
The name
attribute has been added to the text
input
element.
Setting that attribute to send
will allow the server retrieve the content of the text
input
element using the name send
when the page reload request is received.
If you reload the page you should now find that either clickling the send
button,
or pressing Enter
in the text input field, will cause the page to reload.
The input text is currently being thrown away by the server. Let's instead insert that text into the text area, so that we can see the data is being uploaded properly.
To do this we will insert some PHP code into the textarea
content.
This code has to
text
input
that was uploaded along with the page request (under the name send
), andtextarea
.
When the page is reloaded, the PHP variable $_REQUEST
contains all the information about the request sent by the client.
It behaves like an array, indexed by the name of the data you want.
The data send from the input
text
is included in the $_REQUEST
array.
We previously asked the form
element to call that data send
(using the name
attribute of the text input).
The data of interest is therefore available as $_REQUEST["send"]
.
Inside the textarea
we will add some PHP code that retrieves the $_REQUEST["send"]
data,
store it in the variable $send
, and if it is not empty then echo
it (to make it become the conent of the textarea
element).
<p> <textarea rows="10" cols="80"><?php $send = $_REQUEST["send"]; if ($send) echo $send; ?></textarea> </p>
PHP can write to, and read from, files stored on the server.
Let's append each line of text sent in $_REQUEST["send"]
into a 'chat log' file,
and then insert the contents of that file into the page as the content of the textarea
element.
The effect will be to collect all the text sent to the chat app and echo them all in the display area.
The code will have to
echo
the contents of the 'chat log' file to provide the contents of the textarea
element.
Let's store the 'chat log' in a file called chatlog.txt
.
Instead of echo
ing the $send
text into the textarea
,
first (if it is not empty) append a newline ("\n"
) to it (using the string concatenation operator “.
”) and then
use the function file_put_contents
to append the result to the chatlog.txt
file.
Next, let's use file_get_contents
to retrive the entire contents of chatlog.txt
and
(if it is not empty) echo
those contents to make them become the content of the textarea
element.
<textarea rows="10" cols="80"><?php $send = $_REQUEST["send"]; if ($send) { $send = $send."\n"; file_put_contents("chatlog.txt", $send, FILE_APPEND); } $chat = file_get_contents("chatlog.txt"); if ($chat) echo $chat; ?></textarea>
We now have a working Web chat app! Your complete app should look like this:
<!DOCTYPE html> <html> <head> <title>PHP Chat @ <?php echo gethostname() ?></title> </head> <body> <p> <textarea rows="10" cols="80"><?php $send = $_REQUEST["send"]; if ($send) { $send = $send."\n"; file_put_contents("chatlog.txt", $send, FILE_APPEND); } $chat = file_get_contents("chatlog.txt"); if ($chat) echo $chat; ?></textarea> </p> <p> <form action="<?php $_PHP_SELF ?>" method="POST"> <input type="text" size="70" name="send" /> <input type="submit" value="send" /> </form> </p> </body> </html>
1. Automatically set the focus to the text input area when the page (re)loads.
Currently it is necessary to click in the text input area to begin typing into it.
One way to cure this is to set focus to the correct element when the page has finished loading.
Similar to the onclick
attribute for button
elements,
you can use the onload
attribute of the body
element to run some JavaScript
when the page has finished loading completely.
text
input
element an identifier (e.g, “text
”), and thenonload
property of the body
element to JavaScript that sets focus to the element with the identifier text
.The code you need will look something like this:
document.getElementById('text').focus()
2. Scroll the textarea
element to the bottom when the page is (re)loaded.
When the chat textarea
has more lines of content than space to display them,
it displays the oldest lines instead of the newest ones.
To fix this, you can
textarea
element an identifier (e.g., chat
), andchat
area to the bottom using JavaScript.
The JavaScript to scroll a textarea
to the bottom looks like this:
var chat = document.getElementById('chat'); chat.scrollTop = chat.scrollHeight;
3. Prepend the time to each message.
In PHP you can obtain the time as a string like this:
date("H:i:s")
If you prepend this to the message (in the same statement that appends the newline character to it) you will get timestamps in the chat.
4. Add each participant's name to their chat messages.
Add another text input field to the form that contains your name.
Automatically include your name at the start of the message.
The easiest way to do this is to send your name (along with chat message text)
to the server then the send button is pressed,
then use that value both to include your name in the message
and to re-initialise the value
attribute of the same text input field
which will preserve your name across page reloads.
Calling this a 'cloud app' is maybe debatable, but it does…
The server-side data is stored in a simple text file and the server code runs only on one server. If the persistent data were instead stored a distributed database, and if multiple servers cooperated to share the work needed to handle thousands of simultaneous users, then there would be no question that this qualifies as a 'cloud app'.