ui changes and better secret use

This commit is contained in:
Arlo Filley 2023-09-05 08:52:28 +01:00
parent 39aedf8fcc
commit 3aec4a052f
39 changed files with 399 additions and 103 deletions

View File

@ -7,6 +7,9 @@
-[ ] Make js api asynchronous
-[ ] Hash passwords on front end so server plaintext password is never sent over the internet
-[ ] Use secret to uniquely identify
-[ ] Scrollbars
-[x] Scrollbars
-[ ] Change Color Scheme
-[ ] Be able to view others accounts
-[ ] Username gets cut off if too long
-[ ] Validate username length
-[ ] Test caret doesn't keep up

Binary file not shown.

View File

@ -10,8 +10,10 @@
//! - create structure for the input of post test
// Imports for json handling and rusqlite
use sqlx::sqlite::{SqlitePool, SqlitePoolOptions};
use rocket::serde::Serialize;
use sqlx::sqlite::{ SqlitePool, SqlitePoolOptions };
use rocket::serde::{ Serialize, json::Json };
use crate::typing::test::PostTest;
/// Contains the database connection pool
pub struct Database(SqlitePool);
@ -60,11 +62,23 @@ impl Database {
/// takes necessary data about a test and creates
/// a database record with the data
pub async fn create_test(&self, test_type: &str, test_length: u32, test_time: u32, test_seed: i64, quote_id: i32, wpm: u8, accuracy: u8, user_id: u32) -> Result<(), sqlx::Error> {
pub async fn create_test(&self, test: Json<PostTest<'_>>) -> Result<(), sqlx::Error> {
// Test to see whether the secret is correct
let user = sqlx::query!("
Select secret
From Users
Where user_id=?",
test.user_id
).fetch_one(&self.0).await?;
if user.secret != test.secret {
return Err(sqlx::Error::RowNotFound)
}
sqlx::query!("
INSERT INTO Tests (test_type, test_length, test_time, test_seed, quote_id, wpm, accuracy, user_id)
VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)",
test_type, test_length, test_time, test_seed, quote_id, wpm, accuracy, user_id
test.test_type, test.test_length, test.test_time, test.test_seed, test.quote_id, test.wpm, test.accuracy, test.user_id
).execute(&self.0).await?;
Ok(())

View File

@ -17,23 +17,25 @@ use std::{
#[derive(Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct PostTest<'r> {
test_type: &'r str,
test_length: u32,
test_time: u32,
test_seed: i64,
quote_id: i32,
wpm: u8,
accuracy: u8,
user_id: u32
pub test_type: &'r str,
pub test_length: u32,
pub test_time: u32,
pub test_seed: i64,
pub quote_id: i32,
pub wpm: u8,
pub accuracy: u8,
pub user_id: u32,
pub secret: &'r str
}
/// Api Route that accepts test data and posts it to the database
/// Acessible from http://url/api/post_test
#[post("/post_test", data = "<test>")]
pub async fn create_test(test: Json<PostTest<'_>>, database: &State<Database>) {
match database.create_test(test.test_type, test.test_length, test.test_time, test.test_seed, test.quote_id, test.wpm, test.accuracy, test.user_id).await {
let user_id = test.user_id;
match database.create_test(test).await {
Err(why) => { println!("A database error occured creating a test, {why}"); }
Ok(()) => { println!("Successfully created test for {}", test.user_id); }
Ok(()) => { println!("Successfully created test for {user_id}"); }
}
}

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Panel</title>
<link rel="stylesheet" href="../index.css">
<script src="index.js"></script>
</head>
<body>
<nav>
<p>Arlo Filley</p>
<ul>
<li><a href="../">Home</a></li>
<li><a href="./">Delete A User</a></li>
</ul>
</nav>
<h1>Password</h1>
<input id="password" type="password">
<table>
<tbody id="table"></tbody>
</table>
</body>
</html>

View File

@ -0,0 +1,51 @@
get();
function get() {
let xhr = new XMLHttpRequest();
xhr.open('GET', `https://arlofilley.com/api/typing/leaderboard`);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.responseType = 'json';
xhr.send();
xhr.onload = () => {
json = xhr.response
createTable(json);
};
}
function createTable(pJson) {
let table = document.getElementById("table");
console.log(password)
pJson.forEach(element => {
let tr = document.createElement('tr');
let button = document.createElement('button');
let username = element.username;
button.textContent = "delete"
button.addEventListener( "click", () => {
let xhr = new XMLHttpRequest();
let password = document.getElementById("password").value;
xhr.open('GET', `https://arlofilley.com/api/typing/delete_user/${password}/${username}/120932187`);
xhr.send();
})
create_table_element(tr, "", [element.username, element.wpm], button)
table.appendChild(tr)
});
}
function create_table_element(tr, string, elements, button) {
if (elements.length > 0) {
for (let i = 0; i < elements.length; i++) {
let td = document.createElement('td');
td.appendChild(document.createTextNode(elements[i]));
tr.appendChild(td);
}
} else {
let td = document.createElement('td');
td.appendChild(document.createTextNode(string));
tr.appendChild(td);
}
tr.appendChild(button);
}

125
websites/Typing/Admin/index.css Executable file
View File

@ -0,0 +1,125 @@
:root {
--navbar: #333333;
/* Navbar Button Properties */
--navbar-button: #058ED9;
--navbar-button-hover: #283F3B;
--navbar-button-border: #058ED9;
/* */
--background: #1f1f1f;
/* Table Properties*/
--table: #FFD07B;
--table-top:#FDB833;
/* Title Properties */
--title-background: #333333;
--title-text: #ffffff;
/* General Properties */
--text: #000000;
--border: #000000;
}
body {
background-color: #111;
margin: 0;
padding: 0;
}
nav {
background-color: #333;
height: 75px;
display: flex;
justify-content: center;
align-items: center;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
nav p {
margin-right: 700px;
text-decoration: none;
color: #fff;
font-size: 38px;
font-weight: bold;
text-transform: uppercase;
font-family: "Montserrat", sans-serif;
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
display: inline-block;
margin: 0 20px;
}
a {
text-decoration: none;
color: #fff;
font-size: 18px;
font-weight: bold;
text-transform: uppercase;
font-family: "Montserrat", sans-serif;
padding: 10px 20px;
transition: background-color 0.3s ease;
}
a:hover {
background-color: #555;
}
h1 {
margin-left: 5%;
margin-bottom: 0%;
color: #fff;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
input {
margin-left: 5%;
margin-top: 1.5%;
}
table {
width: 90%;
border-collapse: collapse;
margin: 0px;
margin-left: 5%;
margin-top: 30px;
padding: 0px;
border-spacing: 0px;
border: 2px var(--border) solid;
border-radius: 20px;
}
table tr:nth-child(n) {
background: var(--table);
}
table tr:nth-child(1) {
background: var(--table-top);
}
tr {
border: 1px black dotted;
}
td {
text-align: center;
padding: 10px;
font-size: larger;
}
button {
margin-left: 40%;
padding: 8px;
padding-left: 12.5%;
padding-right: 12.5%;
}

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Panel</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<nav>
<p>Arlo Filley</p>
<ul>
<li><a href="./">Home</a></li>
<li><a href="./Delete User/">Delete A User</a></li>
</ul>
</nav>
</body>
</html>

View File

@ -15,12 +15,7 @@
*/
class API {
constructor() {
// this.url = "https://arlofilley.com/api/";
this.url = "../api";
// this is the url of the server
// this may have to change later on
}
constructor() { this.url = "../api"; }
/**
* This takes the validated data and makes a post
@ -43,7 +38,8 @@ class API {
'quote_id': pQuoteId,
'wpm': pWpm,
'accuracy': pAccuracy,
'user_id': pUserId
'user_id': pUserId,
'secret': user.secret
}
const xhr = new XMLHttpRequest();
@ -210,13 +206,8 @@ class API {
* @returns
*/
login(pUsername, pPassword, initial = false) {
// Variable Validation
if (pUsername == undefined || pPassword == undefined) {
return
}
// If Local Storage has the information we need there is no need to make a request to the server
if (localStorage.getItem("username") == pUsername) {
if (localStorage.getItem("username") === pUsername || (initial && localStorage.length === 3) ) {
user.userId = localStorage.getItem("userId");
user.secret = localStorage.getItem("secret");
user.username = localStorage.getItem("username");
@ -224,6 +215,11 @@ class API {
return
}
// Variable Validation
if (pUsername == undefined || pPassword == undefined) {
return
}
let xhr = new XMLHttpRequest();
xhr.open('GET', `${this.url}/login/${pUsername}/${pPassword}`);
xhr.send();
@ -231,7 +227,7 @@ class API {
let response = JSON.parse(xhr.response);
// If there is an error with the login we need
if (xhr.response == null) {
if (xhr.response === null) {
alert("Error Logging in, maybe check your password");
return
}
@ -249,7 +245,7 @@ class API {
logout() {
user = new User();
user.username = "no one";
user.password = "none";
user.password = "";
user.userId = 0;
user.tests = [];
localStorage.clear();

8
websites/Typing/api/user.js Normal file → Executable file
View File

@ -17,7 +17,7 @@ class User {
constructor() {
this.username = "not logged in";
this.userId = 0;
this.secret = "";
this.secret;
this.leaderboard;
this.time = 15;
@ -27,8 +27,8 @@ class User {
this.nextTest = `satisfy powerful pleasant bells disastrous mean kited is gusted romantic past taste immolate productive leak close show crabby awake handsails finicky betray long-term incompetent wander show manage toys convey hop constitute number send like off ice aboard well-made vast vacuous tramp seed force divergent flower porter fire untidy soggy fetch`;
this.colorScheme = {
background: "#eeeee4",
text: "#000",
background: "#160C1C",
text: "#FBB",
timerBar: "#50C5B7",
timerText: "#000",
@ -40,7 +40,7 @@ class User {
buttonText: "#fff",
buttonBorder: "#000",
buttonHoverBG: "#0f0",
buttonHoverBG: "#FBB",
buttonHoverText: "#000",
buttonHoverBorder: "#000"
}

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

0
websites/Typing/assets/favicon/apple-touch-icon.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

0
websites/Typing/assets/favicon/favicon-16x16.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 552 B

After

Width:  |  Height:  |  Size: 552 B

0
websites/Typing/assets/favicon/favicon-32x32.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 968 B

After

Width:  |  Height:  |  Size: 968 B

0
websites/Typing/assets/favicon/favicon.ico Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

0
websites/Typing/assets/favicon/site.webmanifest Normal file → Executable file
View File

0
websites/Typing/assets/fonts/RobotoMono-Medium.ttf Normal file → Executable file
View File

0
websites/Typing/index.css Normal file → Executable file
View File

0
websites/Typing/index.html Normal file → Executable file
View File

View File

@ -32,7 +32,7 @@ function setup() {
user = new User();
screenManager.setScreen(new StartScreen());
api.login();
api.login(null, null, true);
api.getTest();
textFont(roboto);
}

0
websites/Typing/lib/p5.js Normal file → Executable file
View File

0
websites/Typing/lib/p5.min.js vendored Normal file → Executable file
View File

0
websites/Typing/screens/accountScreen.js Normal file → Executable file
View File

0
websites/Typing/screens/endscreen.js Normal file → Executable file
View File

51
websites/Typing/screens/leaderboardscreen.js Normal file → Executable file
View File

@ -17,11 +17,12 @@ class LeaderboardScreen {
this.menu = new Menu();
api.getLeaderBoard();
this.testButtons;
this.buttons = [
new Button(1150, 270, 240, 120, "up"),
new Button(1150, 390, 240, 120, "down"),
]
// this.buttons = [
// new Button(1150, 270, 240, 120, "up"),
// new Button(1150, 390, 240, 120, "down"),
// ]
this.offset = 0;
this.scroll_bar_button = new Button(1200, 200, 20, 20, "")
}
draw() {
@ -39,29 +40,40 @@ class LeaderboardScreen {
}
}
fill(user.colorScheme.testBad);
rect(1200, 270, 20, 420);
fill(user.colorScheme.testGood);
rect(1200, 270, 20, 420 / user.leaderboard.length * (this.offset + 1));
this.scroll_bar_button.height = (user.leaderboard.length)
if (this.scroll_bar_button.isPressed()) {
this.scroll_bar_button.y = mouseY - this.scroll_bar_button.height / 2;
}
// the furthest up the scrollbar can go is the top
if (this.scroll_bar_button.y < 270) {
this.scroll_bar_button.y = 270;
}
if (this.scroll_bar_button.y > 690 - this.scroll_bar_button.height) {
this.scroll_bar_button.y = 690 - this.scroll_bar_button.height;
}
this.scroll_bar_button.draw();
if (this.testButtons !== undefined && this.testButtons.length > 1) {
for (let i = 0; i < this.testButtons.length; i++) {
this.testButtons[i][0].draw()
this.testButtons[i][1].draw()
this.testButtons[i][2].draw()
}
if (this.buttons[0].isPressed()) {
if (this.offset > 0) {
this.offset--;
}
this.createTestButtons(this.offset);
} else if (this.buttons[1].isPressed()) {
if (this.offset < user.leaderboard.length - 13) {
this.offset++;
}
this.offset = Number((
// number of pixels from top of screen / total range of options, put to a whole integer to produce the correct offset
(this.scroll_bar_button.y - 270) / ((420 - this.scroll_bar_button.height) / (user.leaderboard.length - 13))
).toFixed(0));
this.createTestButtons(this.offset);
}
for (let i = 0; i < this.buttons.length; i++) {
this.buttons[i].draw();
}
this.createTestButtons(this.offset)
} else {
fill(user.colorScheme.text);
text("Looks Like There Isn't A Leaderboard", windowWidth / 2, 300);
@ -78,7 +90,6 @@ class LeaderboardScreen {
]];
let j = 300;
for (let i = 0 + offset; i < user.leaderboard.length && i <= 12+offset; i++) {
console.log(i);
this.testButtons.push([
new Button(400, j, 100, 30, `${i+1}`, true, true, "#000", "#000", "#fff"), // test # button
new Button(500, j, 400, 30, `${user.leaderboard[i].username}`, true, true, "#000", "#000", "#fff"), // accuracy button

0
websites/Typing/screens/loginscreen.js Normal file → Executable file
View File

72
websites/Typing/screens/profilescreen.js Normal file → Executable file
View File

@ -19,11 +19,12 @@ class ProfileScreen {
this.menu = new Menu();
api.getUserTests();
this.testButtons;
this.buttons = [
new Button(950, 270, 240, 120, "up"),
new Button(950, 390, 240, 120, "down"),
]
// this.buttons = [
// new Button(950, 270, 240, 120, "up"),
// new Button(950, 390, 240, 120, "down"),
// ]
this.offset = 0;
this.scroll_bar_button = new Button(1200, 200, 20, 20, "")
}
draw() {
@ -49,21 +50,6 @@ class ProfileScreen {
this.testButtons[i][2].draw()
this.testButtons[i][3].draw()
}
if (this.buttons[0].isPressed()) {
if (this.offset > 0) {
this.offset--;
}
this.createTestButtons(this.offset);
} else if (this.buttons[1].isPressed()) {
if (user.tests.length - 13 - this.offset > 0) {
this.offset++;
}
this.createTestButtons(this.offset);
}
for (let i = 0; i < this.buttons.length; i++) {
this.buttons[i].draw();
}
} else {
fill(user.colorScheme.text);
text("Looks Like You Don't have any tests :(", windowWidth / 2, 300);
@ -71,22 +57,54 @@ class ProfileScreen {
fill(user.colorScheme.text);
text(`Logged in as ${user.username}`, windowWidth-150, 15);
if (user.tests === undefined) {
return;
}
fill(user.colorScheme.testBad);
rect(1200, 270, 20, 420);
fill(user.colorScheme.testGood);
rect(1200, 270, 20, 420 / user.tests.length * (this.offset + 1));
this.scroll_bar_button.height = (user.tests.length)
if (this.scroll_bar_button.isPressed()) {
this.scroll_bar_button.y = mouseY - this.scroll_bar_button.height / 2;
}
// the furthest up the scrollbar can go is the top
if (this.scroll_bar_button.y < 270) {
this.scroll_bar_button.y = 270;
}
if (this.scroll_bar_button.y > 690 - this.scroll_bar_button.height) {
this.scroll_bar_button.y = 690 - this.scroll_bar_button.height;
}
this.scroll_bar_button.draw();
this.offset = Number((
// number of pixels from top of screen / total range of options, put to a whole integer to produce the correct offset
(this.scroll_bar_button.y - 270) / ((420 - this.scroll_bar_button.height) / (user.tests.length - 13))
).toFixed(0));
this.createTestButtons(this.offset);
}
createTestButtons(offset = 0) {
this.testButtons = [[
new Button(400, 270, 100, 30, "test #"), // test # button
new Button(500, 270, 100, 30, "wpm"), // wpm button
new Button(600, 270, 100, 30, "accuracy"), // accuracy button
new Button(700, 270, 240, 30, "characters typed")
new Button(600, 270, 100, 30, "test #"), // test # button
new Button(700, 270, 100, 30, "wpm"), // wpm button
new Button(800, 270, 100, 30, "accuracy"), // accuracy button
new Button(900, 270, 240, 30, "characters typed")
]];
let j = 300;
for (let i = user.tests.length-1-offset; i >= user.tests.length-13-offset && i >= 0; i--) {
this.testButtons.push([
new Button(400, j, 100, 30, `${i+1}`, true, true , "#000", "#000", "#fff"), // test # button
new Button(500, j, 100, 30, `${user.tests[i].wpm}`, true, true , "#000", "#000", "#fff"), // accuracy button
new Button(600, j, 100, 30, `${user.tests[i].accuracy}`, true, true , "#000", "#000", "#fff"), // wpm button
new Button(700, j, 240, 30, `${user.tests[i].test_length}`, true, true , "#000", "#000", "#fff")
new Button(600, j, 100, 30, `${i+1}`, true, true , "#000", "#000", "#fff"), // test # button
new Button(700, j, 100, 30, `${user.tests[i].wpm}`, true, true , "#000", "#000", "#fff"), // accuracy button
new Button(800, j, 100, 30, `${user.tests[i].accuracy}`, true, true , "#000", "#000", "#fff"), // wpm button
new Button(900, j, 240, 30, `${user.tests[i].test_length}`, true, true , "#000", "#000", "#fff")
])
j+=30;
}

0
websites/Typing/screens/screenmanager.js Normal file → Executable file
View File

5
websites/Typing/screens/settingsScreen.js Normal file → Executable file
View File

@ -17,9 +17,12 @@ class settingsScreen {
textSize(100);
fill(user.colorScheme.text);
text("Test Settings", 450, 100);
text("Test Settings", windowWidth / 2, 100);
this.menu.draw();
fill(user.colorScheme.text);
text("Test Duration", windowWidth / 2 - 250, 265)
this.timeMenu.draw();
fill("#000");
text(`Logged in as ${user.username}`, windowWidth-150, 15);

0
websites/Typing/screens/signUpScreen.js Normal file → Executable file
View File

0
websites/Typing/screens/startscreen.js Normal file → Executable file
View File

10
websites/Typing/screens/testscreen.js Normal file → Executable file
View File

@ -14,9 +14,13 @@
*/
class TestScreen {
constructor() {
this.textbox = new Textbox(100,100,windowWidth - 200,windowHeight,0,true,"#000", false, "#000", "#000", true, true);
this.textbox = new Textbox(
100, windowHeight / 2 - 100,
windowWidth - 500,windowHeight,
0, true, "#000", false, "#000", "#000", true, true);
this.timer = new Timer(0,0,windowWidth,50,0,true,"#fff", true, "#000", "#666", user.time, true);
this.timerStarted = false;
this.stopButton = new Button(0,50,200,50, "Stop Test");
}
draw() {
@ -25,6 +29,10 @@ class TestScreen {
if (this.timerStarted) {
this.timer.tick();
}
this.stopButton.draw();
if (this.stopButton.isPressed()) {
screenManager.setScreen(new StartScreen())
}
}
letterTyped(key) {

1
websites/Typing/ui_elements/button.js Normal file → Executable file
View File

@ -179,6 +179,7 @@ class Button {
return;
}
textSize(20);
textAlign(CENTER, CENTER);
if (mouseX > this.x && mouseX < this.x + this.width && mouseY > this.y && mouseY < this.y + this.height) {

0
websites/Typing/ui_elements/canvas.js Normal file → Executable file
View File

10
websites/Typing/ui_elements/menu.js Normal file → Executable file
View File

@ -13,11 +13,11 @@
class Menu {
constructor() {
this.buttons = [
new Button(0, 0, 100, 30, "Account"),
new Button(101, 0, 130, 30, "Test Data"),
new Button(232, 0, 140, 30, "Start Test"),
new Button(373, 0, 140, 30, "Leaderboard"),
new Button(514, 0, 180, 30, "Test Settings")
new Button(0, 0, 200, 50, "Account"),
new Button(201, 0, 200, 50, "Test Data"),
new Button(402, 0, 200, 50, "Start Test"),
new Button(603, 0, 200, 50, "Leaderboard"),
new Button(804, 0, 200, 50, "Test Settings")
]
}

18
websites/Typing/ui_elements/textbox.js Normal file → Executable file
View File

@ -27,6 +27,9 @@ class Textbox {
* @param {bool} pBorder
* @param {hexcode} pBorderColor
* @param {hexcode} pBackgroundColor
* @param {bool} pLine
* @param {bool} pIsTest
* @param {bool} pIsPassword
*/
constructor(
pX, pY,
@ -73,6 +76,7 @@ class Textbox {
this.goodColor = user.colorScheme.testGood;
this.badColor = user.colorScheme.testBad;
this.textColor = user.colorScheme.text;
}
getX() {
@ -271,7 +275,9 @@ class Textbox {
} else {
fill("#00044");
}
text(this.testContent[this.currentLine-1][x], i, j);
i += 13;
}
j+= 30;
@ -289,10 +295,18 @@ class Textbox {
} else {
fill(this.textColor);
}
text(this.testContent[this.currentLine][x], i, j);
if (this.letters.length > 0 && x == this.letters.length && this.line) {
fill(this.textColor)
rect(i, j-15, 1, 30)
}
i += 13;
}
i = this.x;
j += 30;
@ -343,4 +357,8 @@ class Textbox {
}
}
}
draw_line(line, y) {
}
}

24
websites/Typing/ui_elements/timemenu.js Normal file → Executable file
View File

@ -15,13 +15,14 @@
class TimeMenu {
constructor() {
this.buttons = [
new Button(100, 230, 100, 30, "15s"),
new Button(100, 260, 100, 30, "30s"),
new Button(100, 290, 100, 30, "45s"),
new Button(100, 320, 100, 30, "60s"),
new Button(900, 250, 100, 30, "15s"),
new Button(900, 280, 100, 30, "30s"),
new Button(900, 310, 100, 30, "45s"),
new Button(900, 340, 100, 30, "60s"),
];
this.topButton = this.buttons[0];
this.dropDownButton = new Button(1000, 250, 30, 30, "v")
this.dropdown = false;
}
@ -33,29 +34,28 @@ class TimeMenu {
if (this.buttons[0].isPressed() && user.time != 15) {
user.time = 15;
this.topButton = new Button(100, 230, 100, 30, "15s");
this.topButton = new Button(900, 250, 100, 30, "15s");
this.dropdown = false;
} else if (this.buttons[1].isPressed()) {
user.time = 30;
this.topButton = new Button(100, 230, 100, 30, "30s");
this.topButton = new Button(900, 250, 100, 30, "30s");
this.dropdown = false;
} else if (this.buttons[2].isPressed()) {
user.time = 45;
this.topButton = new Button(100, 230, 100, 30, "45s");
this.topButton = new Button(900, 250, 100, 30, "45s");
this.dropdown = false;
} else if (this.buttons[3].isPressed()) {
user.time = 60;
this.topButton = new Button(100, 230, 100, 30, "60s");
this.topButton = new Button(900, 250, 100, 30, "60s");
this.dropdown = false;
}
} else {
this.topButton.draw();
}
if (this.topButton.isPressed()) {
this.dropDownButton.draw();
if (this.dropDownButton.isPressed()) {
this.dropdown = true;
} else if (mouseIsPressed) {
this.dropdown = false;
}
} else if (mouseIsPressed) { this.dropdown = false };
}
}

0
websites/Typing/ui_elements/timer.js Normal file → Executable file
View File