From d9ad319ff41cae1c0a9d2a771941be25c1208e3d Mon Sep 17 00:00:00 2001 From: Carl Worth <cworth@cworth.org> Date: Fri, 22 May 2020 19:29:33 -0700 Subject: [PATCH] Convert rendering of login.html to use a nunjucks template This new base.html template will allow us to avoid duplicating a bunch of boilerplate as we start adding additional HTML pages. Also, we pull the undisplay, add_message, lmno_login, and lmno_login_loaded functions in instead of including the static JavaScript file from /lmno.js. This makes things much more independent here, (rather than relying on JavaScript functions defined in a script file that is maintained in a separate git repository: lmno.games). --- lmno.js | 8 ++++++- login.html | 42 -------------------------------- templates/base.html | 42 ++++++++++++++++++++++++++++++++ templates/login.html | 57 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 43 deletions(-) delete mode 100644 login.html create mode 100644 templates/base.html create mode 100644 templates/login.html diff --git a/lmno.js b/lmno.js index abcdba2..ff66a9b 100644 --- a/lmno.js +++ b/lmno.js @@ -4,6 +4,7 @@ const body_parser = require("body-parser"); const session = require("express-session"); const bcrypt = require("bcrypt"); const path = require("path"); +const nunjucks = require("nunjucks"); try { var lmno_config = require("./lmno-config.json"); @@ -40,6 +41,11 @@ app.use(session({ saveUninitialized: false })); +nunjucks.configure("templates", { + autoescape: true, + express: app +}); + /* Load each of our game mini-apps. */ var empires = require("./empires"); @@ -184,7 +190,7 @@ app.get('/login', (request, response) => { return; } - response.sendFile(path.join(__dirname, './login.html')); + response.render('login.html'); }); app.post('/login', async (request, response) => { diff --git a/login.html b/login.html deleted file mode 100644 index f78e679..0000000 --- a/login.html +++ /dev/null @@ -1,42 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta charset="utf-8"/> - <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" /> - - <title>LMNO: Login</title> - - <link rel="stylesheet" href="/reset.css" type="text/css" /> - <link rel="stylesheet" href="/style.css" type="text/css" /> - </head> - <body> - - <script src="/lmno.js"></script> - - <div id="page"> - - <div id="message-area"> - </div> - - <!-- The return false prevents the page from being reloaded --> - <form id="login-form" onsubmit="lmno_login(this); return false"> - <div class="form-field large"> - <label for="username">Username</label> - <input type="text" id="username" required> - </div> - - <div class="form-field large"> - <label for="Password">Password</label> - <input type="password" id="password" required> - </div> - - <div class="form-field large"> - <button type="submit"> - Login - </button> - </div> - </form> - - </div> - </body> -</html> diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..6895772 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"/> + <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" /> + + <title>{{ title }}</title> + + <link rel="stylesheet" href="/reset.css" type="text/css" /> + <link rel="stylesheet" href="/style.css" type="text/css" /> + + <script> + function undisplay(element) { + element.style.display="none"; + } + + function add_message(severity, message) { + message = `<div class="message ${severity}" onclick="undisplay(this)"> +<span class="hide-button" onclick="undisplay(this.parentElement)">×</span> +${message} +</div>`; + const message_area = document.getElementById('message-area'); + message_area.insertAdjacentHTML('beforeend', message); + } + </script> + {% block head %} + {% endblock %} + + </head> + <body> + + <div id="page"> + + <div id="message-area"> + </div> + + {% block page %} + {% endblock %} + + </div> + </body> +</html> diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000..5767316 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,57 @@ +{% extends "base.html" %} + +{% block head %} +<script> + function lmno_login_loadend(request, username) { + if (request.status === 404) { + add_message("danger", "User authentication failed. Please try again."); + return; + } + + /* Now that user is logged in, advance to the desired page (if any). */ + const url = new URL(window.location); + const next_param = url.searchParams.get('next'); + if (next_param) { + window.location.href = next_param; + return; + } + + /* Otherwise, just report the successful login. */ + add_message("success", `User ${username} logged in. Have fun.`); +} + +function lmno_login(form) { + const username = form.username.value; + const password = form.password.value; + + console.log("In lmno_login with username: " + username); + var request = new XMLHttpRequest(); + request.addEventListener("loadend", () => lmno_login_loadend(request, username)); + + request.open("POST", "/login"); + request.setRequestHeader("Content-Type", "application/json; charset=UTF-8"); + request.send(`{"username": "${username}", "password": "${password}"}`); +} +</script> +{% endblock %} + +{% block page %} +<!-- The return false prevents the page from being reloaded --> +<form id="login-form" onsubmit="lmno_login(this); return false"> + <div class="form-field large"> + <label for="username">Username</label> + <input type="text" id="username" required> + </div> + + <div class="form-field large"> + <label for="Password">Password</label> + <input type="password" id="password" required> + </div> + + <div class="form-field large"> + <button type="submit"> + Login + </button> + </div> +</form> +{% endblock %} -- 2.45.2