From d920bd587782a1d002dc9e7f46242c80cb5a20de Mon Sep 17 00:00:00 2001 From: riaan Date: Tue, 22 Aug 2023 16:29:58 +0200 Subject: [PATCH 01/27] Getting Started Steps Complete to "Hello world" --- app.ts | 1 + index.html | 1 + package-lock.json | 62 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 25 +++++++++++++++++++ 4 files changed, 89 insertions(+) create mode 100644 app.ts create mode 100644 package-lock.json create mode 100644 package.json diff --git a/app.ts b/app.ts new file mode 100644 index 00000000..5a8ed90b --- /dev/null +++ b/app.ts @@ -0,0 +1 @@ +window.onload = () => { $("body").text("Hello world"); } \ No newline at end of file diff --git a/index.html b/index.html index add5e736..e682b072 100644 --- a/index.html +++ b/index.html @@ -7,6 +7,7 @@

Hello

+ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..75a2a795 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,62 @@ +{ + "name": "onboard-javascript", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "onboard-javascript", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@types/jquery": "^3.5.16", + "typescript": "^3.9.2" + } + }, + "node_modules/@types/jquery": { + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz", + "integrity": "sha512-bsI7y4ZgeMkmpG9OM710RRzDFp+w4P1RGiIt30C1mSBT+ExCleeh4HObwgArnDFELmRrOpXgSYN9VF1hj+f1lw==", + "dependencies": { + "@types/sizzle": "*" + } + }, + "node_modules/@types/sizzle": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", + "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==" + }, + "node_modules/typescript": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.2.tgz", + "integrity": "sha512-q2ktq4n/uLuNNShyayit+DTobV2ApPEo/6so68JaD5ojvc/6GClBipedB9zNWYxRSAlZXAe405Rlijzl6qDiSw==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + } + }, + "dependencies": { + "@types/jquery": { + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz", + "integrity": "sha512-bsI7y4ZgeMkmpG9OM710RRzDFp+w4P1RGiIt30C1mSBT+ExCleeh4HObwgArnDFELmRrOpXgSYN9VF1hj+f1lw==", + "requires": { + "@types/sizzle": "*" + } + }, + "@types/sizzle": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", + "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==" + }, + "typescript": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.2.tgz", + "integrity": "sha512-q2ktq4n/uLuNNShyayit+DTobV2ApPEo/6so68JaD5ojvc/6GClBipedB9zNWYxRSAlZXAe405Rlijzl6qDiSw==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..fc8f5735 --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "onboard-javascript", + "version": "1.0.0", + "description": "This is a JavaScript project for all new developers to complete before venturing into our web frontend codebase.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "tsc" + + }, + "repository": { + "type": "git", + "url": "git+https://github.com/riaanwastaken/onboard-javascript.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/riaanwastaken/onboard-javascript/issues" + }, + "homepage": "https://github.com/riaanwastaken/onboard-javascript#readme", + "dependencies": { + "@types/jquery": "^3.5.16", + "typescript": "^3.9.2" + } +} From adb6798436e3277821bd3958c4b8035374581eb9 Mon Sep 17 00:00:00 2001 From: riaan Date: Thu, 24 Aug 2023 15:52:31 +0200 Subject: [PATCH 02/27] index.html script error changed from .js to .ts --- index.html | 2 +- package-lock.json | 24 +++++++++++++++--------- package.json | 5 +++-- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/index.html b/index.html index e682b072..448ae533 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@

Hello

- + diff --git a/package-lock.json b/package-lock.json index 75a2a795..9ee14bc8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,14 +9,17 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@types/jquery": "^3.5.16", "typescript": "^3.9.2" + }, + "devDependencies": { + "@types/jquery": "^3.5.17" } }, "node_modules/@types/jquery": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz", - "integrity": "sha512-bsI7y4ZgeMkmpG9OM710RRzDFp+w4P1RGiIt30C1mSBT+ExCleeh4HObwgArnDFELmRrOpXgSYN9VF1hj+f1lw==", + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.17.tgz", + "integrity": "sha512-U40tNEAGSTZ7R1OC6kGkD7f4TKW5DoVx6jd9kTB9mo5truFMi1m9Yohnw9kl1WpTPvDdj7zAw38LfCHSqnk5kA==", + "dev": true, "dependencies": { "@types/sizzle": "*" } @@ -24,7 +27,8 @@ "node_modules/@types/sizzle": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==" + "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", + "dev": true }, "node_modules/typescript": { "version": "3.9.2", @@ -41,9 +45,10 @@ }, "dependencies": { "@types/jquery": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz", - "integrity": "sha512-bsI7y4ZgeMkmpG9OM710RRzDFp+w4P1RGiIt30C1mSBT+ExCleeh4HObwgArnDFELmRrOpXgSYN9VF1hj+f1lw==", + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.17.tgz", + "integrity": "sha512-U40tNEAGSTZ7R1OC6kGkD7f4TKW5DoVx6jd9kTB9mo5truFMi1m9Yohnw9kl1WpTPvDdj7zAw38LfCHSqnk5kA==", + "dev": true, "requires": { "@types/sizzle": "*" } @@ -51,7 +56,8 @@ "@types/sizzle": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==" + "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", + "dev": true }, "typescript": { "version": "3.9.2", diff --git a/package.json b/package.json index fc8f5735..fdadee1e 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,6 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "tsc" - }, "repository": { "type": "git", @@ -19,7 +18,9 @@ }, "homepage": "https://github.com/riaanwastaken/onboard-javascript#readme", "dependencies": { - "@types/jquery": "^3.5.16", "typescript": "^3.9.2" + }, + "devDependencies": { + "@types/jquery": "^3.5.17" } } From 5be4a0c6e211c8ab81d1d894bb8cd5296a11032d Mon Sep 17 00:00:00 2001 From: riaan Date: Thu, 24 Aug 2023 15:56:14 +0200 Subject: [PATCH 03/27] Changed Back to app.js script in index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 448ae533..e682b072 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@

Hello

- + From 89830dd1afd770dc467ac627515f5cad70173f8f Mon Sep 17 00:00:00 2001 From: riaan Date: Fri, 25 Aug 2023 11:34:47 +0200 Subject: [PATCH 04/27] Added "npn run build" to package.json --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index fdadee1e..b5adf9a5 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "build": "tsc" + "build": "tsc", + "start" : "npm run build -- -w" }, "repository": { "type": "git", From a2b438f908c75340540e73977f7e2acffac3ec6a Mon Sep 17 00:00:00 2001 From: riaan Date: Mon, 28 Aug 2023 11:54:12 +0200 Subject: [PATCH 05/27] Table Index Values Load in Browser Success Rev 1.1 --- app.ts | 28 +++++++++++++++++++++++++++- index.html | 11 +++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/app.ts b/app.ts index 5a8ed90b..3925a92b 100644 --- a/app.ts +++ b/app.ts @@ -1 +1,27 @@ -window.onload = () => { $("body").text("Hello world"); } \ No newline at end of file +window.onload = () => { $("footer").text("Hello Riaan Theron!!"); + +$.ajax({ + url: '/columns', + method: 'GET', + success: function(data) { + const columnNames = JSON.parse(data); + const tableHeader = $(''); + //console.log('Success:', data); + + columnNames.forEach(function(columnName: string) { + const th = $('').text(columnName); + tableHeader.append(th); + }); + + // Append the table header to your table using the correct selector + $('#myTable thead').replaceWith(tableHeader); + }, + error: function(xhr, status, error) { + console.error('Error fetching column names:', error); + } + }); + + // Fetch and display data, and implement navigation controls in the following steps... +}; + + diff --git a/index.html b/index.html index e682b072..9cee1897 100644 --- a/index.html +++ b/index.html @@ -3,11 +3,18 @@ JS Onboard Project + -

Hello

- + + + + + +
+

This is a test para

+
From 0e12f47ea6e2bbb48cde6cc0b6569a244b5e3a10 Mon Sep 17 00:00:00 2001 From: riaan Date: Tue, 29 Aug 2023 10:32:58 +0200 Subject: [PATCH 06/27] Program Rebuilt using Fetch API Rev 1.2 --- app.ts | 68 +++++++++++++++++++++++++++++++++------------------- package.json | 3 ++- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/app.ts b/app.ts index 3925a92b..ff2bad1f 100644 --- a/app.ts +++ b/app.ts @@ -1,27 +1,47 @@ -window.onload = () => { $("footer").text("Hello Riaan Theron!!"); - -$.ajax({ - url: '/columns', - method: 'GET', - success: function(data) { - const columnNames = JSON.parse(data); - const tableHeader = $(''); - //console.log('Success:', data); - - columnNames.forEach(function(columnName: string) { - const th = $('').text(columnName); - tableHeader.append(th); - }); - - // Append the table header to your table using the correct selector - $('#myTable thead').replaceWith(tableHeader); - }, - error: function(xhr, status, error) { - console.error('Error fetching column names:', error); - } - }); - - // Fetch and display data, and implement navigation controls in the following steps... +// *** Development Setup ***// +// go run main.go +// npm run build +// npm run watch + +window.onload = () => { + $("footer").text("Hello Who is wathching!!"); + fetchTotalRecords(); + fetchColumns(); + + }; + +async function fetchTotalRecords() { + // Fetch data from API + const response = await fetch("http://localhost:2050/recordCount"); + + // Check for successful response + if (response.ok) { + // Parse the text content from the response body + const data = await response.text(); + + // Log the data to the console + console.log(`Total records: ${data}`); + } else { + // Log an error message if the request was not successful + console.log(`Fetch failed: ${response.status} ${response.statusText}`); + } }; +async function fetchColumns() { + // Fetch data from API + const response = await fetch("http://localhost:2050/columns"); + + // Check for successful response + if (response.ok) { + // Parse the text content from the response body + const data = await response.json(); + + // Log the data to the console + console.log(`Columns: ${data}`); + } else { + // Log an error message if the request was not successful + console.log(`Fetch failed: ${response.status} ${response.statusText}`); + } + +} diff --git a/package.json b/package.json index b5adf9a5..9d7593ae 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "tsc", - "start" : "npm run build -- -w" + "start" : "npm run build", + "watch": "tsc --watch" }, "repository": { "type": "git", From 66fa84a9562e42bad4f682edb76dae7e32f1c839 Mon Sep 17 00:00:00 2001 From: riaan Date: Wed, 30 Aug 2023 10:58:54 +0200 Subject: [PATCH 07/27] HTML Static Table Display on Browser Rev 1.3 --- app.ts | 4 +--- index.html | 59 +++++++++++++++++++++++++++++++++++++++++++++----- stylesheet.css | 23 ++++++++++++++++++++ 3 files changed, 77 insertions(+), 9 deletions(-) create mode 100644 stylesheet.css diff --git a/app.ts b/app.ts index ff2bad1f..ecb965f8 100644 --- a/app.ts +++ b/app.ts @@ -4,7 +4,7 @@ // npm run watch window.onload = () => { - $("footer").text("Hello Who is wathching!!"); + $("footer").text("Hello Who is watching ??"); fetchTotalRecords(); fetchColumns(); @@ -42,6 +42,4 @@ async function fetchColumns() { // Log an error message if the request was not successful console.log(`Fetch failed: ${response.status} ${response.statusText}`); } - - } diff --git a/index.html b/index.html index 9cee1897..aee1374a 100644 --- a/index.html +++ b/index.html @@ -4,18 +4,65 @@ JS Onboard Project + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDCityPopulationCityPopulationCityPopulation
1John2828282828
2Mary2228282828
2Mary2228282828
2Mary2228282828
-

This is a test para

+ +
- diff --git a/stylesheet.css b/stylesheet.css new file mode 100644 index 00000000..99aa0138 --- /dev/null +++ b/stylesheet.css @@ -0,0 +1,23 @@ +/* Set the background color for the entire page */ +body { + background-color: black; + } + +/* Apply background color and text color to the table headers */ +th { + background-color: hsl(198 21% 6% / 1); + color: white; + border: 1px solid hsl(180deg, 100%, 49%); + } + + /* Apply background color and text color to table data cells */ + td { + background-color: hsl(198 21% 6% / 1); + color: white; + border: 1px solid hsl(180deg, 100%, 49%); + } + + /* Style the table itself for gridlines */ + table { + border-collapse: collapse; /* This makes sure the grid lines are continuous */ + } From d37649ed032bba9d7252ab384a3e0d520306f013 Mon Sep 17 00:00:00 2001 From: riaan Date: Thu, 31 Aug 2023 14:26:42 +0200 Subject: [PATCH 08/27] Dynamic Table Generation Rev 1.4 --- app.ts | 136 ++++++++++++++++++++++++++++++++++++++++------------- index.html | 48 +------------------ 2 files changed, 106 insertions(+), 78 deletions(-) diff --git a/app.ts b/app.ts index ecb965f8..4df37133 100644 --- a/app.ts +++ b/app.ts @@ -5,41 +5,113 @@ window.onload = () => { $("footer").text("Hello Who is watching ??"); - fetchTotalRecords(); - fetchColumns(); + //fetchTotalRecords(); + //fetchColumns(); + generateTable(); + }; -async function fetchTotalRecords() { - // Fetch data from API - const response = await fetch("http://localhost:2050/recordCount"); - - // Check for successful response - if (response.ok) { - // Parse the text content from the response body - const data = await response.text(); + async function fetchColumnData() { + const response = await fetch("http://localhost:2050/columns"); + const columnNames = await response.json(); + return columnNames; + } + - // Log the data to the console - console.log(`Total records: ${data}`); - } else { - // Log an error message if the request was not successful - console.log(`Fetch failed: ${response.status} ${response.statusText}`); + function generateTableHeader(columnNames: string[]) { + const thead = document.createElement('thead'); + const tr = document.createElement('tr'); + columnNames.forEach((name) => { + const th = document.createElement('th'); + th.textContent = name; + tr.appendChild(th); + }); + thead.appendChild(tr); + return thead; + } + + async function fetchRowData(from: number, to: number) { + const response = await fetch(`http://localhost:2050/records?from=${from}&to=${to}`); + const records = await response.json(); + return records; + } + + function generateTableRows(records: any[][]) { + const tbody = document.createElement('tbody'); + records.forEach((record) => { + const tr = document.createElement('tr'); + record.forEach((cell) => { + const td = document.createElement('td'); + td.textContent = cell; + tr.appendChild(td); + }); + tbody.appendChild(tr); + }); + return tbody; } -}; - -async function fetchColumns() { - // Fetch data from API - const response = await fetch("http://localhost:2050/columns"); - - // Check for successful response - if (response.ok) { - // Parse the text content from the response body - const data = await response.json(); - - // Log the data to the console - console.log(`Columns: ${data}`); - } else { - // Log an error message if the request was not successful - console.log(`Fetch failed: ${response.status} ${response.statusText}`); + + async function generateTable() { + const columnNames = await fetchColumnData(); + const records = await fetchRowData(0, 10); // Replace with your fromID and toID + const thead = generateTableHeader(columnNames); + const tbody = generateTableRows(records); + + const table = document.getElementById('myTable'); + table?.appendChild(thead); + table?.appendChild(tbody); } -} + + + + + + + + + + + + + + + + + + + + + +// async function fetchTotalRecords() { +// // Fetch data from API +// const response = await fetch("http://localhost:2050/recordCount"); + +// // Check for successful response +// if (response.ok) { +// // Parse the text content from the response body +// const data = await response.text(); + +// // Log the data to the console +// console.log(`Total records: ${data}`); +// } else { +// // Log an error message if the request was not successful +// console.log(`Fetch failed: ${response.status} ${response.statusText}`); +// } +// }; + +// async function fetchColumns() { +// // Fetch data from API +// const response = await fetch("http://localhost:2050/columns"); + +// // Check for successful response +// if (response.ok) { +// // Parse the text content from the response body +// const data = await response.json(); + +// // Log the data to the console +// console.log(`Columns: ${data}`); +// } else { +// // Log an error message if the request was not successful +// console.log(`Fetch failed: ${response.status} ${response.statusText}`); +// } +// } diff --git a/index.html b/index.html index aee1374a..203ab84a 100644 --- a/index.html +++ b/index.html @@ -5,59 +5,15 @@ - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
IDCityPopulationCityPopulationCityPopulation
1John2828282828
2Mary2228282828
2Mary2228282828
2Mary2228282828
From fec8ceaef213edce50fe633ebd752a8d1da015ca Mon Sep 17 00:00:00 2001 From: riaan Date: Fri, 1 Sep 2023 13:40:14 +0200 Subject: [PATCH 09/27] Pagination Complete Rev 1.5 --- app.ts | 110 ++++++++++++++++++++++++++++++++++++------------- index.html | 9 ++-- stylesheet.css | 7 +++- 3 files changed, 92 insertions(+), 34 deletions(-) diff --git a/app.ts b/app.ts index 4df37133..c2fd2942 100644 --- a/app.ts +++ b/app.ts @@ -2,15 +2,54 @@ // go run main.go // npm run build // npm run watch +let currentPage = 1; +const recordsPerPage = 10; +let totalRecords: number; + +window.onload = async () => { + $("footer").text("Hellooooooooooo ??"); + await fetchTotalRecords(); -window.onload = () => { - $("footer").text("Hello Who is watching ??"); - //fetchTotalRecords(); //fetchColumns(); - generateTable(); + const from = 0; + const to = recordsPerPage; + generateTable(from, to); + + document.getElementById("prevBtn")?.addEventListener("click", () => { + currentPage--; + const from = (currentPage - 1) * recordsPerPage; + const to = from + recordsPerPage; + generateTable(from, to); + if (currentPage === 1) { + document.getElementById("prevBtn")?.setAttribute("disabled", "true"); + } else { + document.getElementById("prevBtn")?.removeAttribute("disabled"); + document.getElementById("nextBtn")?.removeAttribute("disabled"); + } + }); - - }; + document.getElementById("nextBtn")?.addEventListener("click", () => { + currentPage++; + const from = (currentPage - 1) * recordsPerPage; + const to = from + recordsPerPage; + generateTable(from, to); + if (currentPage * recordsPerPage >= totalRecords) { + document.getElementById("nextBtn")?.setAttribute("disabled", "true"); + } else { + document.getElementById("nextBtn")?.removeAttribute("disabled"); + document.getElementById("prevBtn")?.removeAttribute("disabled"); + } + }); + + // Filter functionality + const filterInput = document.getElementById("filterInput") as HTMLInputElement; + if (filterInput) { + filterInput.addEventListener("input", function() { + const query = this.value; + filterRecordsById(query); + }); + } +}; async function fetchColumnData() { const response = await fetch("http://localhost:2050/columns"); @@ -51,37 +90,50 @@ window.onload = () => { return tbody; } - async function generateTable() { + async function generateTable(from: number, to: number) { const columnNames = await fetchColumnData(); - const records = await fetchRowData(0, 10); // Replace with your fromID and toID + const records = await fetchRowData(from, to); const thead = generateTableHeader(columnNames); const tbody = generateTableRows(records); - + + // Clear existing data if any const table = document.getElementById('myTable'); + if (table) { + table.innerHTML = ""; + } + + table?.appendChild(thead); table?.appendChild(tbody); } - - - - - - - - - - - - - - - - - - - - + + async function fetchTotalRecords() { + const response = await fetch("http://localhost:2050/recordCount"); + totalRecords = await response.json(); + } + + async function filterRecordsById(query: string) { + if (!query) { + // Revert to initial state if no query + generateTable(0, recordsPerPage); + return; + } + + // Parse the query to get the ID we're interested in + const id = parseInt(query, 10); + + // Calculate which page the ID should be on + currentPage = Math.floor((id - 1) / recordsPerPage) + 1; + + // Calculate the 'from' and 'to' parameters for that page + const from = (currentPage - 1) * recordsPerPage; + const to = from + recordsPerPage; + + // Generate the table for that page + generateTable(from, to); + } + // async function fetchTotalRecords() { // // Fetch data from API // const response = await fetch("http://localhost:2050/recordCount"); diff --git a/index.html b/index.html index 203ab84a..2c237b30 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ - JS Onboard Project + Riaan JS Onboard Project @@ -16,8 +16,11 @@ - - +
diff --git a/stylesheet.css b/stylesheet.css index 99aa0138..aa11ae42 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,12 +1,15 @@ /* Set the background color for the entire page */ +@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap'); + body { + font-family: 'Montserrat', sans-serif; background-color: black; } /* Apply background color and text color to the table headers */ th { - background-color: hsl(198 21% 6% / 1); - color: white; + background-color: hsl(199, 26%, 17%); + color: #FAF0E6; border: 1px solid hsl(180deg, 100%, 49%); } From 054fa47901fb4d7c6131a3de6d60f66808c64bfa Mon Sep 17 00:00:00 2001 From: riaan Date: Tue, 5 Sep 2023 14:03:27 +0200 Subject: [PATCH 10/27] Dynamic Rows Rev 1.6 --- app.ts | 105 ++++++++++++++++++++++++++++++++++++++++--------- stylesheet.css | 25 ++++++++---- 2 files changed, 104 insertions(+), 26 deletions(-) diff --git a/app.ts b/app.ts index c2fd2942..22d566e5 100644 --- a/app.ts +++ b/app.ts @@ -2,24 +2,54 @@ // go run main.go // npm run build // npm run watch +const ROW_HEIGHT = 30; let currentPage = 1; -const recordsPerPage = 10; +let recordsPerPage = 25; let totalRecords: number; +let lastFilteredId: string | null = null; + + +function calculateRecordsPerPage() { + // Change this based on your row's actual height + recordsPerPage = Math.floor(window.innerHeight / ROW_HEIGHT); +} + window.onload = async () => { $("footer").text("Hellooooooooooo ??"); + + calculateRecordsPerPage(); + await fetchTotalRecords(); + // Re-generate the table when the window is resized + window.addEventListener("resize", async () => { + calculateRecordsPerPage(); + if (lastFilteredId) { + const id = parseInt(lastFilteredId, 10); + filterRecordsById(id.toString()); + } else { + const from = (currentPage - 1) * recordsPerPage; + const to = from + recordsPerPage; + generateTable(from, to, null); + } + }); + + //fetchColumns(); const from = 0; const to = recordsPerPage; - generateTable(from, to); + generateTable(from, to, null); + centerHighlightedRow(); // add this line +; document.getElementById("prevBtn")?.addEventListener("click", () => { + lastFilteredId = null; currentPage--; const from = (currentPage - 1) * recordsPerPage; const to = from + recordsPerPage; - generateTable(from, to); + generateTable(from, to, null); +; if (currentPage === 1) { document.getElementById("prevBtn")?.setAttribute("disabled", "true"); } else { @@ -29,10 +59,12 @@ window.onload = async () => { }); document.getElementById("nextBtn")?.addEventListener("click", () => { + lastFilteredId = null; currentPage++; const from = (currentPage - 1) * recordsPerPage; const to = from + recordsPerPage; - generateTable(from, to); + generateTable(from, to, null); +; if (currentPage * recordsPerPage >= totalRecords) { document.getElementById("nextBtn")?.setAttribute("disabled", "true"); } else { @@ -49,6 +81,7 @@ window.onload = async () => { filterRecordsById(query); }); } + }; async function fetchColumnData() { @@ -76,10 +109,20 @@ window.onload = async () => { return records; } - function generateTableRows(records: any[][]) { + function generateTableRows(records: any[][], highlightId: string | null) { const tbody = document.createElement('tbody'); - records.forEach((record) => { + records.forEach((record, index) => { const tr = document.createElement('tr'); + tr.id = `row-${record[0]}`; // Assuming the ID is the first cell in each record + + // Highlight the row if it matches the filtered ID + if (highlightId && highlightId === record[0].toString()) { + tr.classList.add("highlighted-green"); + console.log(`Row with ID ${record[0]} should be highlighted.`); + console.log("Class List:", tr.classList); + + } + record.forEach((cell) => { const td = document.createElement('td'); td.textContent = cell; @@ -90,11 +133,15 @@ window.onload = async () => { return tbody; } - async function generateTable(from: number, to: number) { + async function generateTable(from: number, to: number, highlightId: string | null) { const columnNames = await fetchColumnData(); const records = await fetchRowData(from, to); + + if (to > totalRecords) { + to = totalRecords; + } const thead = generateTableHeader(columnNames); - const tbody = generateTableRows(records); + const tbody = generateTableRows(records, highlightId); // Passing highlightId here // Clear existing data if any const table = document.getElementById('myTable'); @@ -105,6 +152,7 @@ window.onload = async () => { table?.appendChild(thead); table?.appendChild(tbody); + centerHighlightedRow(); } @@ -114,26 +162,45 @@ window.onload = async () => { } async function filterRecordsById(query: string) { + lastFilteredId = query; if (!query) { // Revert to initial state if no query - generateTable(0, recordsPerPage); + generateTable(0, recordsPerPage, null); return; } - // Parse the query to get the ID we're interested in - const id = parseInt(query, 10); - - // Calculate which page the ID should be on - currentPage = Math.floor((id - 1) / recordsPerPage) + 1; + let id = parseInt(query, 10); + + + // Assuming your IDs start from 0 and are sequential + let from = Math.max(0, id - Math.floor(recordsPerPage / 2)); + let to = from + recordsPerPage; + + to = Math.min(to, totalRecords - 1); + + if (to === totalRecords - 1) { + from = to - recordsPerPage + 1; + } + console.log(`Fetching records from ${from} to ${to} with highlight on ${id}`); + + await generateTable(from, to, id.toString()); + centerHighlightedRow(); + } - // Calculate the 'from' and 'to' parameters for that page - const from = (currentPage - 1) * recordsPerPage; - const to = from + recordsPerPage; + function centerHighlightedRow() { + const highlightedRow = document.querySelector(".highlighted"); + const mainContainer = document.getElementById("main-container"); // Add this line - // Generate the table for that page - generateTable(from, to); + if (highlightedRow && mainContainer) { + const containerHeight = mainContainer.clientHeight; + const rowTop = highlightedRow.getBoundingClientRect().top; + const rowHeight = highlightedRow.clientHeight; + const scrollPosition = rowTop + mainContainer.scrollTop - (containerHeight / 2) + (rowHeight / 2); + mainContainer.scrollTop = scrollPosition; + } } + // async function fetchTotalRecords() { // // Fetch data from API // const response = await fetch("http://localhost:2050/recordCount"); diff --git a/stylesheet.css b/stylesheet.css index aa11ae42..44a81245 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -3,24 +3,35 @@ body { font-family: 'Montserrat', sans-serif; - background-color: black; + + } /* Apply background color and text color to the table headers */ th { - background-color: hsl(199, 26%, 17%); - color: #FAF0E6; - border: 1px solid hsl(180deg, 100%, 49%); + background-color: hsl(0, 3%, 77%); + color: #464443; + border: 1px solid hsl(180, 43%, 82%); } /* Apply background color and text color to table data cells */ td { - background-color: hsl(198 21% 6% / 1); - color: white; - border: 1px solid hsl(180deg, 100%, 49%); + background-color: hsl(0, 31%, 51%); + color: rgb(204, 196, 196); + border: 1px solid hsl(180, 44%, 86%); } /* Style the table itself for gridlines */ table { border-collapse: collapse; /* This makes sure the grid lines are continuous */ } + + #myTable { + width: 100%; + height: 100%; + /* Additional styles */ + } + .highlighted-green td { + background-color: green !important; + } + \ No newline at end of file From 453d11ca34167b623d1f3daa7027139caad4e7ea Mon Sep 17 00:00:00 2001 From: riaan Date: Tue, 5 Sep 2023 16:57:40 +0200 Subject: [PATCH 11/27] Styling Applied Rev 1.6 --- app.ts | 74 ++++++++++++++------------------------------------ index.html | 41 +++++++++++++++------------- stylesheet.css | 64 +++++++++++++++++++++++++++++++++++-------- 3 files changed, 95 insertions(+), 84 deletions(-) diff --git a/app.ts b/app.ts index 22d566e5..5e64b63a 100644 --- a/app.ts +++ b/app.ts @@ -2,6 +2,10 @@ // go run main.go // npm run build // npm run watch +// *** Development Setup ***// + + +// *** Global Variables ***// const ROW_HEIGHT = 30; let currentPage = 1; let recordsPerPage = 25; @@ -9,14 +13,9 @@ let totalRecords: number; let lastFilteredId: string | null = null; -function calculateRecordsPerPage() { - // Change this based on your row's actual height - recordsPerPage = Math.floor(window.innerHeight / ROW_HEIGHT); -} window.onload = async () => { - $("footer").text("Hellooooooooooo ??"); calculateRecordsPerPage(); @@ -81,16 +80,21 @@ window.onload = async () => { filterRecordsById(query); }); } - }; + // *** Function ***// + function calculateRecordsPerPage() { + recordsPerPage = Math.floor(window.innerHeight / ROW_HEIGHT); + } + + // *** Function ***// async function fetchColumnData() { const response = await fetch("http://localhost:2050/columns"); const columnNames = await response.json(); return columnNames; } - + // *** Function ***// function generateTableHeader(columnNames: string[]) { const thead = document.createElement('thead'); const tr = document.createElement('tr'); @@ -102,13 +106,15 @@ window.onload = async () => { thead.appendChild(tr); return thead; } - + + // *** Function ***// async function fetchRowData(from: number, to: number) { const response = await fetch(`http://localhost:2050/records?from=${from}&to=${to}`); const records = await response.json(); return records; } + // *** Function ***// function generateTableRows(records: any[][], highlightId: string | null) { const tbody = document.createElement('tbody'); records.forEach((record, index) => { @@ -118,11 +124,7 @@ window.onload = async () => { // Highlight the row if it matches the filtered ID if (highlightId && highlightId === record[0].toString()) { tr.classList.add("highlighted-green"); - console.log(`Row with ID ${record[0]} should be highlighted.`); - console.log("Class List:", tr.classList); - } - record.forEach((cell) => { const td = document.createElement('td'); td.textContent = cell; @@ -132,7 +134,8 @@ window.onload = async () => { }); return tbody; } - + + // *** Function ***// async function generateTable(from: number, to: number, highlightId: string | null) { const columnNames = await fetchColumnData(); const records = await fetchRowData(from, to); @@ -148,19 +151,18 @@ window.onload = async () => { if (table) { table.innerHTML = ""; } - - table?.appendChild(thead); table?.appendChild(tbody); centerHighlightedRow(); } - + // *** Function ***// async function fetchTotalRecords() { const response = await fetch("http://localhost:2050/recordCount"); totalRecords = await response.json(); } - + + // *** Function ***// async function filterRecordsById(query: string) { lastFilteredId = query; if (!query) { @@ -168,10 +170,8 @@ window.onload = async () => { generateTable(0, recordsPerPage, null); return; } - let id = parseInt(query, 10); - // Assuming your IDs start from 0 and are sequential let from = Math.max(0, id - Math.floor(recordsPerPage / 2)); let to = from + recordsPerPage; @@ -186,7 +186,8 @@ window.onload = async () => { await generateTable(from, to, id.toString()); centerHighlightedRow(); } - + + // *** Function ***// function centerHighlightedRow() { const highlightedRow = document.querySelector(".highlighted"); const mainContainer = document.getElementById("main-container"); // Add this line @@ -201,36 +202,3 @@ window.onload = async () => { } -// async function fetchTotalRecords() { -// // Fetch data from API -// const response = await fetch("http://localhost:2050/recordCount"); - -// // Check for successful response -// if (response.ok) { -// // Parse the text content from the response body -// const data = await response.text(); - -// // Log the data to the console -// console.log(`Total records: ${data}`); -// } else { -// // Log an error message if the request was not successful -// console.log(`Fetch failed: ${response.status} ${response.statusText}`); -// } -// }; - -// async function fetchColumns() { -// // Fetch data from API -// const response = await fetch("http://localhost:2050/columns"); - -// // Check for successful response -// if (response.ok) { -// // Parse the text content from the response body -// const data = await response.json(); - -// // Log the data to the console -// console.log(`Columns: ${data}`); -// } else { -// // Log an error message if the request was not successful -// console.log(`Fetch failed: ${response.status} ${response.statusText}`); -// } -// } diff --git a/index.html b/index.html index 2c237b30..3192b619 100644 --- a/index.html +++ b/index.html @@ -1,27 +1,30 @@ - Riaan JS Onboard Project - - - + Riaan JS Onboard Project + + + - - - - - - - -
- -
+
+ + +

Riaan's Table

+ + + + + + +
+ +
+ - diff --git a/stylesheet.css b/stylesheet.css index 44a81245..e86c7787 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,23 +1,36 @@ /* Set the background color for the entire page */ -@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap'); +/* Apple-like Heading */ +#main-heading { + font-family: 'SF Pro Text', 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-size: 2.5em; + font-weight: bold; + text-align: center; + margin: 10px 0; + color: #333; + text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1); +} -body { - font-family: 'Montserrat', sans-serif; - - - } +#main-container { + + margin: 0 auto; + padding: 20px; + background-color: #fff; + border-radius: 10px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} +html, body { + font-family: 'SF Pro Text', 'Helvetica Neue', Helvetica, Arial, sans-serif; + color: #333; +} /* Apply background color and text color to the table headers */ th { - background-color: hsl(0, 3%, 77%); - color: #464443; border: 1px solid hsl(180, 43%, 82%); + background-color: #f7f7f7 } /* Apply background color and text color to table data cells */ td { - background-color: hsl(0, 31%, 51%); - color: rgb(204, 196, 196); border: 1px solid hsl(180, 44%, 86%); } @@ -29,9 +42,36 @@ th { #myTable { width: 100%; height: 100%; + border: 1px solid hsl(180, 83%, 53%); /* Apply the border color here */ + border-radius: 12px; /* Rounded corners */ + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Subtle shadow */ + overflow: hidden; /* Makes sure rounded corners are visible */ /* Additional styles */ } .highlighted-green td { - background-color: green !important; + background-color: #007AFF !important; } - \ No newline at end of file + + button { + padding: 10px 20px; + border: none; + background-color: #007AFF; + color: #fff; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.3s; + } + + button:disabled { + background-color: #ccc; + } + + button:hover:not(:disabled) { + background-color: #0056D6; + } + + #filterInput { + padding: 10px; + border: 1px solid #ccc; + border-radius: 5px; + } \ No newline at end of file From 86a108eb28a21d832840802ac67b98f9f858724c Mon Sep 17 00:00:00 2001 From: riaan Date: Wed, 6 Sep 2023 14:52:21 +0200 Subject: [PATCH 12/27] Applied Performance Changes Rev 1.7 --- app.ts | 67 +++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/app.ts b/app.ts index 5e64b63a..25d4aa9a 100644 --- a/app.ts +++ b/app.ts @@ -11,6 +11,7 @@ let currentPage = 1; let recordsPerPage = 25; let totalRecords: number; let lastFilteredId: string | null = null; +let cachedColumnNames: string[] | null = null; @@ -22,7 +23,7 @@ window.onload = async () => { await fetchTotalRecords(); // Re-generate the table when the window is resized - window.addEventListener("resize", async () => { + window.addEventListener("resize", debounce(async () => { calculateRecordsPerPage(); if (lastFilteredId) { const id = parseInt(lastFilteredId, 10); @@ -32,7 +33,7 @@ window.onload = async () => { const to = from + recordsPerPage; generateTable(from, to, null); } - }); + }, 200)); //fetchColumns(); @@ -40,15 +41,18 @@ window.onload = async () => { const to = recordsPerPage; generateTable(from, to, null); centerHighlightedRow(); // add this line -; - document.getElementById("prevBtn")?.addEventListener("click", () => { + +document.getElementById("prevBtn")?.addEventListener("click", () => { + const filterInput = document.getElementById("filterInput") as HTMLInputElement; + if (!filterInput.value) { lastFilteredId = null; - currentPage--; - const from = (currentPage - 1) * recordsPerPage; - const to = from + recordsPerPage; - generateTable(from, to, null); -; + } + currentPage--; + const from = (currentPage - 1) * recordsPerPage; + const to = from + recordsPerPage; + generateTable(from, to, lastFilteredId); + if (currentPage === 1) { document.getElementById("prevBtn")?.setAttribute("disabled", "true"); } else { @@ -58,19 +62,17 @@ window.onload = async () => { }); document.getElementById("nextBtn")?.addEventListener("click", () => { - lastFilteredId = null; + const filterInput = document.getElementById("filterInput") as HTMLInputElement; + if (!filterInput.value) { + lastFilteredId = null; + } currentPage++; const from = (currentPage - 1) * recordsPerPage; const to = from + recordsPerPage; - generateTable(from, to, null); -; - if (currentPage * recordsPerPage >= totalRecords) { - document.getElementById("nextBtn")?.setAttribute("disabled", "true"); - } else { - document.getElementById("nextBtn")?.removeAttribute("disabled"); - document.getElementById("prevBtn")?.removeAttribute("disabled"); - } + generateTable(from, to, lastFilteredId); + document.getElementById("prevBtn")?.removeAttribute("disabled"); }); + // Filter functionality const filterInput = document.getElementById("filterInput") as HTMLInputElement; @@ -81,6 +83,19 @@ window.onload = async () => { }); } }; + // Debounce function +// Debounce function + function debounce(func: Function, wait: number) { + let timeout: ReturnType; + return function executedFunction(...args: any[]) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; +} // *** Function ***// function calculateRecordsPerPage() { @@ -88,12 +103,19 @@ window.onload = async () => { } // *** Function ***// + + async function fetchColumnData() { + if (cachedColumnNames !== null) { + return cachedColumnNames; + } const response = await fetch("http://localhost:2050/columns"); const columnNames = await response.json(); + cachedColumnNames = columnNames; // Store in cache return columnNames; } + // *** Function ***// function generateTableHeader(columnNames: string[]) { const thead = document.createElement('thead'); @@ -139,7 +161,7 @@ window.onload = async () => { async function generateTable(from: number, to: number, highlightId: string | null) { const columnNames = await fetchColumnData(); const records = await fetchRowData(from, to); - + console.log(totalRecords); if (to > totalRecords) { to = totalRecords; } @@ -154,6 +176,13 @@ window.onload = async () => { table?.appendChild(thead); table?.appendChild(tbody); centerHighlightedRow(); + + // Disable or Enable the Next button based on the last record + if (to >= totalRecords - 1) { + document.getElementById("nextBtn")?.setAttribute("disabled", "true"); + } else { + document.getElementById("nextBtn")?.removeAttribute("disabled"); + } } // *** Function ***// From 26ac37a4c09fdb16da1cff4d67e7e6853f8f5355 Mon Sep 17 00:00:00 2001 From: riaan Date: Thu, 7 Sep 2023 16:15:44 +0200 Subject: [PATCH 13/27] Pagination Functionality Improvements Rev 1.8 --- app.ts | 154 ++++++++++++++++++++++++++++++++++++------------- index.html | 3 +- stylesheet.css | 18 ++++-- 3 files changed, 129 insertions(+), 46 deletions(-) diff --git a/app.ts b/app.ts index 25d4aa9a..820edd52 100644 --- a/app.ts +++ b/app.ts @@ -5,8 +5,10 @@ // *** Development Setup ***// + + // *** Global Variables ***// -const ROW_HEIGHT = 30; +const ROW_HEIGHT = 23; let currentPage = 1; let recordsPerPage = 25; let totalRecords: number; @@ -16,11 +18,14 @@ let cachedColumnNames: string[] | null = null; +// Initialize the page when the window loads window.onload = async () => { + calculateRecordsPerPage(); + await fetchTotalRecords(); + generateInitialTable(); + - calculateRecordsPerPage(); - await fetchTotalRecords(); // Re-generate the table when the window is resized window.addEventListener("resize", debounce(async () => { @@ -33,21 +38,16 @@ window.onload = async () => { const to = from + recordsPerPage; generateTable(from, to, null); } - }, 200)); + }, 250)); - //fetchColumns(); - const from = 0; - const to = recordsPerPage; - generateTable(from, to, null); - centerHighlightedRow(); // add this line -document.getElementById("prevBtn")?.addEventListener("click", () => { - const filterInput = document.getElementById("filterInput") as HTMLInputElement; - if (!filterInput.value) { - lastFilteredId = null; - } + document.getElementById("prevBtn")?.addEventListener("click", () => { + const filterInput = document.getElementById("filterInput") as HTMLInputElement; + if (!filterInput.value) { + lastFilteredId = null; + } currentPage--; const from = (currentPage - 1) * recordsPerPage; const to = from + recordsPerPage; @@ -61,6 +61,9 @@ document.getElementById("prevBtn")?.addEventListener("click", () => { } }); + + + document.getElementById("nextBtn")?.addEventListener("click", () => { const filterInput = document.getElementById("filterInput") as HTMLInputElement; if (!filterInput.value) { @@ -74,17 +77,56 @@ document.getElementById("prevBtn")?.addEventListener("click", () => { }); + + // Filter functionality - const filterInput = document.getElementById("filterInput") as HTMLInputElement; - if (filterInput) { - filterInput.addEventListener("input", function() { - const query = this.value; + let errorTimeout: number | null = null; + +const filterInput = document.getElementById("filterInput") as HTMLInputElement; +const errorMessage = document.getElementById("errorMessage"); + +if (filterInput && errorMessage) { + filterInput.addEventListener("input", function() { + const query = this.value.trim(); + + // Clear any existing timeout and error message + if (errorTimeout !== null) { + clearTimeout(errorTimeout); + } + errorMessage.textContent = ""; + + if (query === "") { + // If input is empty, just return + return; + } + + const isValidNumber = /^[0-9]+$/.test(query) && parseInt(query, 10) <= 999999; + + if (isValidNumber) { filterRecordsById(query); - }); + } else { + // Set up the delayed message + errorTimeout = setTimeout(() => { + errorMessage.textContent = "Invalid input. Please enter a number between 0 and 999999."; + }, 500); + } + }); } }; + + + + +function generateInitialTable() { + const from = 0; + const to = recordsPerPage; + generateTable(from, to, null); +} + + + + // Debounce function -// Debounce function function debounce(func: Function, wait: number) { let timeout: ReturnType; return function executedFunction(...args: any[]) { @@ -97,14 +139,23 @@ document.getElementById("prevBtn")?.addEventListener("click", () => { }; } - // *** Function ***// + + + + // Calculate the number of records to display on each page based on the window height function calculateRecordsPerPage() { - recordsPerPage = Math.floor(window.innerHeight / ROW_HEIGHT); + const headingHeight = document.getElementById('main-heading')?.offsetHeight || 0; + const paginationHeight = document.getElementById('pagination')?.offsetHeight || 0; + + const availableHeight = window.innerHeight - headingHeight - paginationHeight - 15; + + recordsPerPage = Math.floor(availableHeight / ROW_HEIGHT); } - // *** Function ***// - + + + // Fetch columns and cache them if they are not already cached async function fetchColumnData() { if (cachedColumnNames !== null) { return cachedColumnNames; @@ -116,7 +167,9 @@ document.getElementById("prevBtn")?.addEventListener("click", () => { } - // *** Function ***// + + + // Generate the header of the table function generateTableHeader(columnNames: string[]) { const thead = document.createElement('thead'); const tr = document.createElement('tr'); @@ -129,14 +182,20 @@ document.getElementById("prevBtn")?.addEventListener("click", () => { return thead; } - // *** Function ***// + + + + // Fetch a subset of row data from the server async function fetchRowData(from: number, to: number) { const response = await fetch(`http://localhost:2050/records?from=${from}&to=${to}`); const records = await response.json(); return records; } - // *** Function ***// + + + + // Generate the body of the table function generateTableRows(records: any[][], highlightId: string | null) { const tbody = document.createElement('tbody'); records.forEach((record, index) => { @@ -157,7 +216,10 @@ document.getElementById("prevBtn")?.addEventListener("click", () => { return tbody; } - // *** Function ***// + + + + // Generate the complete table async function generateTable(from: number, to: number, highlightId: string | null) { const columnNames = await fetchColumnData(); const records = await fetchRowData(from, to); @@ -175,8 +237,9 @@ document.getElementById("prevBtn")?.addEventListener("click", () => { } table?.appendChild(thead); table?.appendChild(tbody); - centerHighlightedRow(); - + if (lastFilteredId) { + centerHighlightedRow(); + } // Disable or Enable the Next button based on the last record if (to >= totalRecords - 1) { document.getElementById("nextBtn")?.setAttribute("disabled", "true"); @@ -185,41 +248,54 @@ document.getElementById("prevBtn")?.addEventListener("click", () => { } } - // *** Function ***// + + + + // Fetch the total number of records async function fetchTotalRecords() { const response = await fetch("http://localhost:2050/recordCount"); totalRecords = await response.json(); } - // *** Function ***// + + + + // Filter records by ID and regenerate the table accordingly async function filterRecordsById(query: string) { lastFilteredId = query; if (!query) { // Revert to initial state if no query generateTable(0, recordsPerPage, null); + document.getElementById("prevBtn")?.setAttribute("disabled", "true"); // Disable the Previous button here return; } let id = parseInt(query, 10); - // Assuming your IDs start from 0 and are sequential let from = Math.max(0, id - Math.floor(recordsPerPage / 2)); let to = from + recordsPerPage; - + // Update current page based on filtered ID + currentPage = Math.ceil((id + 1) / recordsPerPage); + // Enable or Disable the Previous button based on the current page + if (currentPage > 1) { + document.getElementById("prevBtn")?.removeAttribute("disabled"); // Enable the Previous button here + } else { + document.getElementById("prevBtn")?.setAttribute("disabled", "true"); // Disable the Previous button here + } to = Math.min(to, totalRecords - 1); - if (to === totalRecords - 1) { from = to - recordsPerPage + 1; } console.log(`Fetching records from ${from} to ${to} with highlight on ${id}`); - await generateTable(from, to, id.toString()); - centerHighlightedRow(); } + + + - // *** Function ***// + // Center the row that is highlighted function centerHighlightedRow() { const highlightedRow = document.querySelector(".highlighted"); - const mainContainer = document.getElementById("main-container"); // Add this line + const mainContainer = document.getElementById("main-container"); if (highlightedRow && mainContainer) { const containerHeight = mainContainer.clientHeight; diff --git a/index.html b/index.html index 3192b619..8a4731b3 100644 --- a/index.html +++ b/index.html @@ -19,10 +19,11 @@

Riaan's Table

- diff --git a/stylesheet.css b/stylesheet.css index e86c7787..58ce2d94 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -13,10 +13,9 @@ #main-container { margin: 0 auto; - padding: 20px; background-color: #fff; border-radius: 10px; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + } html, body { @@ -25,13 +24,17 @@ html, body { } /* Apply background color and text color to the table headers */ th { - border: 1px solid hsl(180, 43%, 82%); - background-color: #f7f7f7 + text-align: center; + font-size: 16px; + border: 1px solid hsl(180, 43%, 82%); + background-color: #f7f7f7 } /* Apply background color and text color to table data cells */ td { - border: 1px solid hsl(180, 44%, 86%); + font-size: 16px; + border: 1px solid hsl(180, 44%, 86%); + text-align: center; } /* Style the table itself for gridlines */ @@ -51,7 +54,10 @@ th { .highlighted-green td { background-color: #007AFF !important; } - + .pagination-1 { + text-align: center; + padding-top: 20px; + } button { padding: 10px 20px; border: none; From fd780c17408a3f374593f382524055f434b7ae53 Mon Sep 17 00:00:00 2001 From: riaan Date: Fri, 8 Sep 2023 10:23:43 +0200 Subject: [PATCH 14/27] Styling and Edge Cases Fixed Rev 1.9 --- app.ts | 115 ++++++++++++++++++++++++++++++------------ index.html | 2 +- stylesheet.css | 132 +++++++++++++++++++++++++++---------------------- 3 files changed, 158 insertions(+), 91 deletions(-) diff --git a/app.ts b/app.ts index 820edd52..232f4564 100644 --- a/app.ts +++ b/app.ts @@ -8,7 +8,7 @@ // *** Global Variables ***// -const ROW_HEIGHT = 23; +const ROW_HEIGHT = 21; let currentPage = 1; let recordsPerPage = 25; let totalRecords: number; @@ -82,35 +82,39 @@ window.onload = async () => { // Filter functionality let errorTimeout: number | null = null; -const filterInput = document.getElementById("filterInput") as HTMLInputElement; -const errorMessage = document.getElementById("errorMessage"); + const filterInput = document.getElementById("filterInput") as HTMLInputElement; + const errorMessage = document.getElementById("errorMessage"); -if (filterInput && errorMessage) { - filterInput.addEventListener("input", function() { - const query = this.value.trim(); - - // Clear any existing timeout and error message - if (errorTimeout !== null) { - clearTimeout(errorTimeout); - } - errorMessage.textContent = ""; + if (filterInput && errorMessage) { + filterInput.addEventListener("input", async function() { // Added async here to call await later + const query = this.value.trim(); - if (query === "") { - // If input is empty, just return - return; - } + // Clear any existing timeout and error message + if (errorTimeout !== null) { + clearTimeout(errorTimeout); + } + errorMessage.textContent = ""; + + if (query === "") { + // If input is empty, remove the highlight and revert the table + lastFilteredId = null; + await generateTable(0, recordsPerPage, null); // Added await here, assuming generateTable is an async function + document.getElementById("prevBtn")?.setAttribute("disabled", "true"); + return; + } - const isValidNumber = /^[0-9]+$/.test(query) && parseInt(query, 10) <= 999999; + const isValidNumber = /^[0-9]+$/.test(query) && parseInt(query, 10) <= 999999; - if (isValidNumber) { - filterRecordsById(query); - } else { - // Set up the delayed message - errorTimeout = setTimeout(() => { - errorMessage.textContent = "Invalid input. Please enter a number between 0 and 999999."; - }, 500); - } - }); + if (isValidNumber) { + lastFilteredId = query; + filterRecordsById(query); + } else { + // Set up the delayed message + errorTimeout = setTimeout(() => { + errorMessage.textContent = "Invalid input. Please enter a number between 0 and 999999."; + }, 500); + } + }); } }; @@ -146,9 +150,10 @@ function generateInitialTable() { function calculateRecordsPerPage() { const headingHeight = document.getElementById('main-heading')?.offsetHeight || 0; const paginationHeight = document.getElementById('pagination')?.offsetHeight || 0; - - const availableHeight = window.innerHeight - headingHeight - paginationHeight - 15; - + console.log(paginationHeight); + console.log(headingHeight); + const availableHeight = window.innerHeight - headingHeight - paginationHeight - 10; + console.log(availableHeight); recordsPerPage = Math.floor(availableHeight / ROW_HEIGHT); } @@ -187,13 +192,37 @@ function generateInitialTable() { // Fetch a subset of row data from the server async function fetchRowData(from: number, to: number) { + // Make sure 'to' doesn't exceed the maximum allowed record number + to = Math.min(to, 999999); + + // Make sure 'to' is not negative + if (to < 0) { + to = 0; + } + + // Make sure 'from' is not greater than 'to' + if (from > to) { + from = to; + } + + // Ensure 'from' is not negative + if (from < 0) { + from = 0; + } + const response = await fetch(`http://localhost:2050/records?from=${from}&to=${to}`); + + if (!response.ok) { + console.error(`Fetch failed: ${response.status} ${response.statusText}`); + return []; + } + const records = await response.json(); return records; } - - + + // Generate the body of the table function generateTableRows(records: any[][], highlightId: string | null) { @@ -237,6 +266,8 @@ function generateInitialTable() { } table?.appendChild(thead); table?.appendChild(tbody); + + setColumnWidths(); if (lastFilteredId) { centerHighlightedRow(); } @@ -248,7 +279,25 @@ function generateInitialTable() { } } - + function setColumnWidths(): void { + // Assuming your table has an id of "myTable" + const table = document.getElementById("myTable"); + + if (table) { + // Count the number of columns in your table + const headerCells = table.querySelectorAll("th"); + const numCols = headerCells.length; + + // Calculate the width for each column + const colWidth = 100 / numCols; + + // Set the width + headerCells.forEach((headerCell: Element) => { + (headerCell as HTMLElement).style.width = `${colWidth}%`; + }); + } + } + // Fetch the total number of records @@ -273,6 +322,8 @@ function generateInitialTable() { // Assuming your IDs start from 0 and are sequential let from = Math.max(0, id - Math.floor(recordsPerPage / 2)); let to = from + recordsPerPage; + + // Update current page based on filtered ID currentPage = Math.ceil((id + 1) / recordsPerPage); // Enable or Disable the Previous button based on the current page diff --git a/index.html b/index.html index 8a4731b3..07d4cc6b 100644 --- a/index.html +++ b/index.html @@ -11,7 +11,7 @@
-

Riaan's Table

+

Area 51's Grocery List

diff --git a/stylesheet.css b/stylesheet.css index 58ce2d94..573764ae 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,7 +1,8 @@ /* Set the background color for the entire page */ -/* Apple-like Heading */ +@import url('https://fonts.googleapis.com/css2?family=Orbitron&display=swap'); + #main-heading { - font-family: 'SF Pro Text', 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-family: 'Orbitron', sans-serif; font-size: 2.5em; font-weight: bold; text-align: center; @@ -11,73 +12,88 @@ } #main-container { - margin: 0 auto; background-color: #fff; - border-radius: 10px; - } html, body { font-family: 'SF Pro Text', 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #333; + margin-bottom: 0; } + /* Apply background color and text color to the table headers */ th { + font-family: 'Orbitron', sans-serif; text-align: center; font-size: 16px; - border: 1px solid hsl(180, 43%, 82%); - background-color: #f7f7f7 - } - - /* Apply background color and text color to table data cells */ - td { - font-size: 16px; - border: 1px solid hsl(180, 44%, 86%); + border: 1px solid #a1e3a1; + background-color: #333333; /* Semicolon added */ + color: #4CAF50; +} + +/* Apply background color and text color to table data cells */ +td { + font-family: 'Orbitron', sans-serif; + font-size: 14px; + border: 1px solid #a1e3a1; text-align: center; - } - - /* Style the table itself for gridlines */ - table { - border-collapse: collapse; /* This makes sure the grid lines are continuous */ - } + color: #333333; +} + +/* Style the table itself for gridlines */ +table { + border-collapse: collapse; +} + +#myTable { + width: 100%; + height: 100%; + border: 1px solid #a1e3a1; + border-radius: 12px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + overflow: hidden; +} + +.highlighted-green td { + background-color: #333333 !important; + color: #4CAF50 !important; /* Added this line to make the text color green */ +} + + +.pagination-1 { + text-align: center; + padding-top: 25px; + padding-bottom: 20px; + font-family: 'Orbitron', sans-serif; +} + +button { + padding: 10px 20px; + border: none; + background-color: #1e1e1e; /* Dark Grey almost Black */ + color: #00FF00; /* Bright green like old school terminals */ + border-radius: 5px; + font-family: 'Orbitron', sans-serif; + cursor: pointer; + transition: background-color 0.3s; +} + +button:disabled { + background-color: #555; /* Mid-grey for disabled buttons */ + color: #ccc; /* light grey text */ +} + +button:hover:not(:disabled) { + background-color: #333; /* Slightly lighter dark grey */ +} + +#filterInput { + padding: 10px; + border: 1px solid #00FF00; /* Bright green border */ + border-radius: 5px; + font-family: 'Orbitron', sans-serif; + color: #00FF00; /* Bright green text */ + background-color: #1e1e1e; /* Dark background */ +} - #myTable { - width: 100%; - height: 100%; - border: 1px solid hsl(180, 83%, 53%); /* Apply the border color here */ - border-radius: 12px; /* Rounded corners */ - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Subtle shadow */ - overflow: hidden; /* Makes sure rounded corners are visible */ - /* Additional styles */ - } - .highlighted-green td { - background-color: #007AFF !important; - } - .pagination-1 { - text-align: center; - padding-top: 20px; - } - button { - padding: 10px 20px; - border: none; - background-color: #007AFF; - color: #fff; - border-radius: 5px; - cursor: pointer; - transition: background-color 0.3s; - } - - button:disabled { - background-color: #ccc; - } - - button:hover:not(:disabled) { - background-color: #0056D6; - } - - #filterInput { - padding: 10px; - border: 1px solid #ccc; - border-radius: 5px; - } \ No newline at end of file From 4f6d7e99ca046a2e32343ad9e5a54a106f272a81 Mon Sep 17 00:00:00 2001 From: riaan Date: Tue, 12 Sep 2023 15:20:09 +0200 Subject: [PATCH 15/27] Added Classes to improve modularity Rev 1.10 --- app.ts | 835 +++++++++++++++++++++++++++++++++++------------------ index.html | 6 +- 2 files changed, 563 insertions(+), 278 deletions(-) diff --git a/app.ts b/app.ts index 232f4564..41779917 100644 --- a/app.ts +++ b/app.ts @@ -1,360 +1,645 @@ -// *** Development Setup ***// -// go run main.go -// npm run build -// npm run watch -// *** Development Setup ***// +// ApiManager Class +class ApiManager { + totalRecordCount: number | null; + columnNames: string[] | null; + + constructor() { + this.totalRecordCount = null; + this.columnNames = null; + } + async fetchTotalRecordCount(): Promise { + try { + const response = await fetch('http://localhost:2050/recordCount'); + if (!response.ok) { + throw new Error(`Failed to fetch total record count: ${response.statusText}`); + } + const data: number = await response.json(); + this.totalRecordCount = data; + } catch (error) { + console.error(`Error fetching total record count: ${error}`); + } + } + + async fetchColumnNames(): Promise { + try { + const response = await fetch('http://localhost:2050/columns'); + if (!response.ok) { + throw new Error(`Failed to fetch column names: ${response.statusText}`); + } + const data: string[] = await response.json(); + this.columnNames = data; + } catch (error) { + console.error(`Error fetching column names: ${error}`); + } + } + + async fetchRecords(from: number, to: number): Promise { + try { + const response = await fetch(`http://localhost:2050/records?from=${from}&to=${to}`); + if (!response.ok) { + throw new Error(`Failed to fetch records: ${response.statusText}`); + } + const data: any[][] = await response.json(); + return data; + } catch (error) { + console.error(`Error fetching records: ${error}`); + return null; + } + } + +} -// *** Global Variables ***// -const ROW_HEIGHT = 21; -let currentPage = 1; -let recordsPerPage = 25; -let totalRecords: number; -let lastFilteredId: string | null = null; -let cachedColumnNames: string[] | null = null; +// TableRenderer Class +type apiRecord = any[]; +class TableRenderer { + constructor() { + // State initialization + } + setColumnNames(columnNames: string[]): void { + try { + const thead = document.querySelector('thead'); + if (thead === null) { + throw new Error('Table header not found.'); + } + + const row = document.createElement('tr'); + for (const columnName of columnNames) { + const cell = document.createElement('th'); + cell.textContent = columnName; + row.appendChild(cell); + } + thead.appendChild(row); + } catch (error) { + if (error instanceof Error) { // Type guard + console.error(`An error occurred: ${error.message}`); + } else { + console.error(`An unknown error occurred: ${error}`); + } + } + } + + render(records: apiRecord[] | null) { + try { + if (records === null) { + throw new Error("No records to render."); + } -// Initialize the page when the window loads -window.onload = async () => { - calculateRecordsPerPage(); - await fetchTotalRecords(); - generateInitialTable(); + const tbody = document.querySelector('tbody'); + if (tbody === null) { + throw new Error('Table body not found.'); + } + + tbody.innerHTML = ''; // Clear existing rows + + records.forEach((record) => { + const row = document.createElement('tr'); + record.forEach((cell) => { + const td = document.createElement('td'); + td.textContent = cell.toString(); + row.appendChild(td); + }); + tbody.appendChild(row); + }); + } catch (error) { + console.error(`An error occurred: ${error}`); + } + } + + adjustRows(): void { + try { + const rowHeight = 20; + const headerHeight = 180; + const availableHeight = (window.innerHeight) - headerHeight ; + + let numRows = Math.floor(availableHeight / rowHeight); + + // Check for a minimum number of rows + if (numRows <= 0) { + console.log("Window size too small, setting minimum number of rows to 1"); + numRows = 1; + } + // Fetch the records for the current page based on the newly calculated numRows + const apiManager = new ApiManager(); + const currentPage = 1; // Replace with your actual current page from PaginationManager + + const from = (currentPage - 1) * numRows; + const to = from + numRows - 1; + + apiManager.fetchRecords(from, to).then(records => { + if (records !== null) { + this.render(records); + } + }).catch(error => { + console.error(`An error occurred while fetching records: ${error}`); + }); + } catch (error) { + console.error(`An error occurred: ${error}`); + } + } +} + // const records = await apiManager.fetchRecords(0, 9); + // tableRenderer.render(records); +// WindowManager Class +class WindowManager { + private timeoutId: number | null = null; + constructor(private tableRenderer: TableRenderer) {} - // Re-generate the table when the window is resized - window.addEventListener("resize", debounce(async () => { - calculateRecordsPerPage(); - if (lastFilteredId) { - const id = parseInt(lastFilteredId, 10); - filterRecordsById(id.toString()); - } else { - const from = (currentPage - 1) * recordsPerPage; - const to = from + recordsPerPage; - generateTable(from, to, null); + handleResize() { + if (this.timeoutId !== null) { + clearTimeout(this.timeoutId); } - }, 250)); - + this.timeoutId = window.setTimeout(() => { + this.tableRenderer.adjustRows(); + this.timeoutId = null; + }, 200); + } +} - document.getElementById("prevBtn")?.addEventListener("click", () => { - const filterInput = document.getElementById("filterInput") as HTMLInputElement; - if (!filterInput.value) { - lastFilteredId = null; - } - currentPage--; - const from = (currentPage - 1) * recordsPerPage; - const to = from + recordsPerPage; - generateTable(from, to, lastFilteredId); - - if (currentPage === 1) { - document.getElementById("prevBtn")?.setAttribute("disabled", "true"); - } else { - document.getElementById("prevBtn")?.removeAttribute("disabled"); - document.getElementById("nextBtn")?.removeAttribute("disabled"); - } - }); - +// PaginationManager Class +class PaginationManager { + currentPage: number = 1; - document.getElementById("nextBtn")?.addEventListener("click", () => { - const filterInput = document.getElementById("filterInput") as HTMLInputElement; - if (!filterInput.value) { - lastFilteredId = null; + incrementPage(): void { + this.currentPage += 1; + } + + decrementPage(): void { + if (this.currentPage > 1) { + this.currentPage -= 1; } - currentPage++; - const from = (currentPage - 1) * recordsPerPage; - const to = from + recordsPerPage; - generateTable(from, to, lastFilteredId); - document.getElementById("prevBtn")?.removeAttribute("disabled"); - }); + } +} + + +// main script +window.onload = async () => { + const apiManager = new ApiManager(); + const tableRenderer = new TableRenderer(); + const windowManager = new WindowManager(tableRenderer); + const paginationManager = new PaginationManager(); + + // Fetch total record count and column names + await apiManager.fetchTotalRecordCount(); + await apiManager.fetchColumnNames(); + // Set column names + if (apiManager.columnNames !== null) { + tableRenderer.setColumnNames(apiManager.columnNames); + } + // Initial fetch and render of records + tableRenderer.adjustRows(); + // Attach event listeners + window.addEventListener('resize', () => windowManager.handleResize()); + + // You can also attach listeners for 'Next Page', 'Previous Page', and 'Filter by ID' here +}; - // Filter functionality - let errorTimeout: number | null = null; - const filterInput = document.getElementById("filterInput") as HTMLInputElement; - const errorMessage = document.getElementById("errorMessage"); - if (filterInput && errorMessage) { - filterInput.addEventListener("input", async function() { // Added async here to call await later - const query = this.value.trim(); - // Clear any existing timeout and error message - if (errorTimeout !== null) { - clearTimeout(errorTimeout); - } - errorMessage.textContent = ""; - - if (query === "") { - // If input is empty, remove the highlight and revert the table - lastFilteredId = null; - await generateTable(0, recordsPerPage, null); // Added await here, assuming generateTable is an async function - document.getElementById("prevBtn")?.setAttribute("disabled", "true"); - return; - } - const isValidNumber = /^[0-9]+$/.test(query) && parseInt(query, 10) <= 999999; - if (isValidNumber) { - lastFilteredId = query; - filterRecordsById(query); - } else { - // Set up the delayed message - errorTimeout = setTimeout(() => { - errorMessage.textContent = "Invalid input. Please enter a number between 0 and 999999."; - }, 500); - } - }); - } -}; -function generateInitialTable() { - const from = 0; - const to = recordsPerPage; - generateTable(from, to, null); -} - // Debounce function - function debounce(func: Function, wait: number) { - let timeout: ReturnType; - return function executedFunction(...args: any[]) { - const later = () => { - clearTimeout(timeout); - func(...args); - }; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - }; -} - // Calculate the number of records to display on each page based on the window height - function calculateRecordsPerPage() { - const headingHeight = document.getElementById('main-heading')?.offsetHeight || 0; - const paginationHeight = document.getElementById('pagination')?.offsetHeight || 0; - console.log(paginationHeight); - console.log(headingHeight); - const availableHeight = window.innerHeight - headingHeight - paginationHeight - 10; - console.log(availableHeight); - recordsPerPage = Math.floor(availableHeight / ROW_HEIGHT); - } - // Fetch columns and cache them if they are not already cached - async function fetchColumnData() { - if (cachedColumnNames !== null) { - return cachedColumnNames; - } - const response = await fetch("http://localhost:2050/columns"); - const columnNames = await response.json(); - cachedColumnNames = columnNames; // Store in cache - return columnNames; - } - - - // Generate the header of the table - function generateTableHeader(columnNames: string[]) { - const thead = document.createElement('thead'); - const tr = document.createElement('tr'); - columnNames.forEach((name) => { - const th = document.createElement('th'); - th.textContent = name; - tr.appendChild(th); - }); - thead.appendChild(tr); - return thead; - } - // Fetch a subset of row data from the server - async function fetchRowData(from: number, to: number) { - // Make sure 'to' doesn't exceed the maximum allowed record number - to = Math.min(to, 999999); +// *** Development Setup ***// +// go run main.go +// npm run build +// npm run watch +// *** Development Setup ***// + + + + +// *** Global Variables ***// +// const ROW_HEIGHT = 21; +// let currentPage = 1; +// let recordsPerPage = 25; +// let totalRecords: number; +// let lastFilteredId: string | null = null; +// let cachedColumnNames: string[] | null = null; +// let totalPages: number; + + + + + +// // Initialize the page when the window loads +// window.onload = async () => { +// calculateRecordsPerPage(); +// await fetchTotalRecords(); +// generateInitialTable(); + + + + +// // Re-generate the table when the window is resized +// // Re-generate the table when the window is resized +// window.addEventListener("resize", debounce(async () => { +// // Find the first row and its ID. +// const firstRow = document.querySelector('#myTable tbody tr'); +// let firstRowId = 0; - // Make sure 'to' is not negative - if (to < 0) { - to = 0; - } +// if (firstRow && firstRow.id) { +// firstRowId = parseInt(firstRow.id.split('-')[1], 10); +// } - // Make sure 'from' is not greater than 'to' - if (from > to) { - from = to; - } - - // Ensure 'from' is not negative - if (from < 0) { - from = 0; - } +// console.log("In debounce (before recalculating):"); +// console.log(`First row ID: ${firstRowId}`); +// console.log(`Current page: ${currentPage}`); + +// // Recalculate the number of records per page +// calculateRecordsPerPage(); - const response = await fetch(`http://localhost:2050/records?from=${from}&to=${to}`); +// // Recalculate currentPage based on firstRowId +// currentPage = Math.floor(firstRowId / recordsPerPage) + 1; - if (!response.ok) { - console.error(`Fetch failed: ${response.status} ${response.statusText}`); - return []; - } +// console.log("In debounce (after recalculating):"); +// console.log(`First row ID should still be: ${firstRowId}`); +// console.log(`New current page: ${currentPage}`); - const records = await response.json(); - return records; - } +// // Regenerate table +// if (lastFilteredId) { +// const id = parseInt(lastFilteredId, 10); +// filterRecordsById(id.toString()); +// } else { +// generateTable(currentPage, null); // Generate the table for the current page +// } +// }, 250)); + +// // Handle Previous button click +// document.getElementById("prevBtn")?.addEventListener("click", () => { +// const filterInput = document.getElementById("filterInput") as HTMLInputElement; +// if (!filterInput.value) { +// lastFilteredId = null; +// } +// currentPage--; +// generateTable(currentPage, lastFilteredId); + +// if (currentPage === 1) { +// document.getElementById("prevBtn")?.setAttribute("disabled", "true"); +// } else { +// document.getElementById("prevBtn")?.removeAttribute("disabled"); +// document.getElementById("nextBtn")?.removeAttribute("disabled"); +// } +// }); + +// // Handle Next button click +// document.getElementById("nextBtn")?.addEventListener("click", () => { +// const filterInput = document.getElementById("filterInput") as HTMLInputElement; +// if (!filterInput.value) { +// lastFilteredId = null; +// } +// currentPage++; +// generateTable(currentPage, lastFilteredId); + +// document.getElementById("prevBtn")?.removeAttribute("disabled"); +// if (currentPage * recordsPerPage >= totalRecords) { +// document.getElementById("nextBtn")?.setAttribute("disabled", "true"); +// } +// }); + - // Generate the body of the table - function generateTableRows(records: any[][], highlightId: string | null) { - const tbody = document.createElement('tbody'); - records.forEach((record, index) => { - const tr = document.createElement('tr'); - tr.id = `row-${record[0]}`; // Assuming the ID is the first cell in each record + + +// // Filter functionality +// let errorTimeout: number | null = null; + +// const filterInput = document.getElementById("filterInput") as HTMLInputElement; +// const errorMessage = document.getElementById("errorMessage"); + +// if (filterInput && errorMessage) { +// filterInput.addEventListener("input", async function() { // Added async here to call await later +// const query = this.value.trim(); + +// // Clear any existing timeout and error message +// if (errorTimeout !== null) { +// clearTimeout(errorTimeout); +// } +// errorMessage.textContent = ""; + +// if (query === "") { +// // If input is empty, remove the highlight and revert the table +// lastFilteredId = null; +// currentPage = 1; // Resetting to the first page +// await generateTable(currentPage, null, undefined); // Use currentPage which is now 1 +// document.getElementById("prevBtn")?.setAttribute("disabled", "true"); +// return; +// } - // Highlight the row if it matches the filtered ID - if (highlightId && highlightId === record[0].toString()) { - tr.classList.add("highlighted-green"); - } - record.forEach((cell) => { - const td = document.createElement('td'); - td.textContent = cell; - tr.appendChild(td); - }); - tbody.appendChild(tr); - }); - return tbody; - } +// const isValidNumber = /^[0-9]+$/.test(query) && parseInt(query, 10) <= 999999; + +// if (isValidNumber) { +// lastFilteredId = query; +// filterRecordsById(query); +// } else { +// // Set up the delayed message +// errorTimeout = setTimeout(() => { +// errorMessage.textContent = "Invalid input. Please enter a number between 0 and 999999."; +// }, 500); +// } +// }); +// } +// }; + + + + +// function generateInitialTable() { +// generateTable(currentPage, null); +// } + + + +// function removeRowsFromTable(rowsToRemove: number) { +// const table = document.getElementById('myTable'); +// if (table) { +// const tbody = table.querySelector('tbody'); +// if (tbody) { +// // Remove the last 'rowsToRemove' rows from the table +// for (let i = 0; i < rowsToRemove; i++) { +// if (tbody.lastElementChild) { +// tbody.removeChild(tbody.lastElementChild); +// } +// } +// } +// } +// } + +// // Debounce function +// function debounce(func: Function, wait: number) { +// let timeout: ReturnType; +// return function executedFunction(...args: any[]) { +// const later = () => { +// clearTimeout(timeout); +// func(...args); +// }; +// clearTimeout(timeout); +// timeout = setTimeout(later, wait); +// }; +// } + + + + +// // Calculate the number of records to display on each page based on the window height +// function calculateRecordsPerPage() { +// const headingHeight = document.getElementById('main-heading')?.offsetHeight || 0; +// const paginationHeight = document.getElementById('pagination')?.offsetHeight || 0; +// const availableHeight = window.innerHeight - headingHeight - paginationHeight - 10; +// recordsPerPage = Math.floor(availableHeight / ROW_HEIGHT); +// totalPages = Math.ceil(totalRecords / recordsPerPage); +// console.log("In calculateRecordsPerPage:"); +// console.log(`Records per page: ${recordsPerPage}`); +// } + + + + +// // Fetch columns and cache them if they are not already cached +// async function fetchColumnData() { +// if (cachedColumnNames !== null) { +// return cachedColumnNames; +// } +// const response = await fetch("http://localhost:2050/columns"); +// const columnNames = await response.json(); +// cachedColumnNames = columnNames; // Store in cache +// return columnNames; +// } + + +// // Generate the header of the table +// function generateTableHeader(columnNames: string[]) { +// const thead = document.createElement('thead'); +// const tr = document.createElement('tr'); +// columnNames.forEach((name) => { +// const th = document.createElement('th'); +// th.textContent = name; +// tr.appendChild(th); +// }); +// thead.appendChild(tr); +// return thead; +// } - // Generate the complete table - async function generateTable(from: number, to: number, highlightId: string | null) { - const columnNames = await fetchColumnData(); - const records = await fetchRowData(from, to); - console.log(totalRecords); - if (to > totalRecords) { - to = totalRecords; - } - const thead = generateTableHeader(columnNames); - const tbody = generateTableRows(records, highlightId); // Passing highlightId here - - // Clear existing data if any - const table = document.getElementById('myTable'); - if (table) { - table.innerHTML = ""; - } - table?.appendChild(thead); - table?.appendChild(tbody); - setColumnWidths(); - if (lastFilteredId) { - centerHighlightedRow(); - } - // Disable or Enable the Next button based on the last record - if (to >= totalRecords - 1) { - document.getElementById("nextBtn")?.setAttribute("disabled", "true"); - } else { - document.getElementById("nextBtn")?.removeAttribute("disabled"); - } - } + +// // Fetch a subset of row data from the server +// async function fetchRowData(from: number, to: number) { +// // Make sure 'to' doesn't exceed the maximum allowed record number +// to = Math.min(to, 999999); + +// // Make sure 'to' is not negative +// if (to < 0) { +// to = 0; +// } + +// // Make sure 'from' is not greater than 'to' +// if (from > to) { +// from = to; +// } + +// // Ensure 'from' is not negative +// if (from < 0) { +// from = 0; +// } - function setColumnWidths(): void { - // Assuming your table has an id of "myTable" - const table = document.getElementById("myTable"); +// const response = await fetch(`http://localhost:2050/records?from=${from}&to=${to}`); - if (table) { - // Count the number of columns in your table - const headerCells = table.querySelectorAll("th"); - const numCols = headerCells.length; +// if (!response.ok) { +// console.error(`Fetch failed: ${response.status} ${response.statusText}`); +// return []; +// } + +// const records = await response.json(); +// return records; +// } - // Calculate the width for each column - const colWidth = 100 / numCols; - // Set the width - headerCells.forEach((headerCell: Element) => { - (headerCell as HTMLElement).style.width = `${colWidth}%`; - }); - } - } +// // Generate the body of the table +// function generateTableRows(records: any[][], highlightId: string | null) { +// const tbody = document.createElement('tbody'); +// records.forEach((record, index) => { +// const tr = document.createElement('tr'); +// tr.id = `row-${record[0]}`; // Assuming the ID is the first cell in each record + +// // Highlight the row if it matches the filtered ID +// if (highlightId && highlightId === record[0].toString()) { +// tr.classList.add("highlighted-green"); +// } +// record.forEach((cell) => { +// const td = document.createElement('td'); +// td.textContent = cell; +// tr.appendChild(td); +// }); +// tbody.appendChild(tr); +// }); +// return tbody; +// } + + + + +// // Generate the complete table +// async function generateTable(page: number, highlightId: string | null, updateMode: boolean = false) { +// const columnNames = await fetchColumnData(); +// const from = (page - 1) * recordsPerPage; +// let to = Math.min(page * recordsPerPage, totalRecords) - 1; +// const records = await fetchRowData(from, to); + +// const thead = generateTableHeader(columnNames); +// const tbody = generateTableRows(records, highlightId); + +// // Clear existing data if any +// const table = document.getElementById('myTable'); +// if (table) { +// if (updateMode) { +// const existingTbody = table.querySelector('tbody'); +// if (existingTbody) { +// tbody.querySelectorAll('tr').forEach((row) => { +// existingTbody.appendChild(row); +// }); +// } +// } else { +// table.innerHTML = ""; +// table.appendChild(thead); +// table.appendChild(tbody); +// } +// } +// console.log("In generateTable:"); +// console.log(`Start index: ${from}`); +// console.log(`End index: ${to}`); +// // Set column widths +// setColumnWidths(); + +// // If there is a filtered ID, you could call some logic here +// if (lastFilteredId) { +// // centerHighlightedRow(); +// } + +// // Disable or Enable the Next button based on the last record +// if (to >= totalRecords - 1) { +// document.getElementById("nextBtn")?.setAttribute("disabled", "true"); +// } else { +// document.getElementById("nextBtn")?.removeAttribute("disabled"); +// } +// } + + +// function setColumnWidths(): void { +// // Assuming your table has an id of "myTable" +// const table = document.getElementById("myTable"); + +// if (table) { +// // Count the number of columns in your table +// const headerCells = table.querySelectorAll("th"); +// const numCols = headerCells.length; + +// // Calculate the width for each column +// const colWidth = 100 / numCols; + +// // Set the width +// headerCells.forEach((headerCell: Element) => { +// (headerCell as HTMLElement).style.width = `${colWidth}%`; +// }); +// } +// } + - // Fetch the total number of records - async function fetchTotalRecords() { - const response = await fetch("http://localhost:2050/recordCount"); - totalRecords = await response.json(); - } +// // Fetch the total number of records +// async function fetchTotalRecords() { +// const response = await fetch("http://localhost:2050/recordCount"); +// totalRecords = await response.json(); +// totalPages = Math.ceil(totalRecords / recordsPerPage); +// } - // Filter records by ID and regenerate the table accordingly - async function filterRecordsById(query: string) { - lastFilteredId = query; - if (!query) { - // Revert to initial state if no query - generateTable(0, recordsPerPage, null); - document.getElementById("prevBtn")?.setAttribute("disabled", "true"); // Disable the Previous button here - return; - } - let id = parseInt(query, 10); - // Assuming your IDs start from 0 and are sequential - let from = Math.max(0, id - Math.floor(recordsPerPage / 2)); - let to = from + recordsPerPage; - - // Update current page based on filtered ID - currentPage = Math.ceil((id + 1) / recordsPerPage); - // Enable or Disable the Previous button based on the current page - if (currentPage > 1) { - document.getElementById("prevBtn")?.removeAttribute("disabled"); // Enable the Previous button here - } else { - document.getElementById("prevBtn")?.setAttribute("disabled", "true"); // Disable the Previous button here - } - to = Math.min(to, totalRecords - 1); - if (to === totalRecords - 1) { - from = to - recordsPerPage + 1; - } - console.log(`Fetching records from ${from} to ${to} with highlight on ${id}`); - await generateTable(from, to, id.toString()); - } +// // Filter records by ID and regenerate the table accordingly +// async function filterRecordsById(query: string) { +// lastFilteredId = query; +// if (!query) { +// // Revert to initial state if no query +// generateTable(1, null); // Start with the first page +// document.getElementById("prevBtn")?.setAttribute("disabled", "true"); // Disable the Previous button here +// return; +// } + +// let id = parseInt(query, 10); + +// // Calculate the current page based on the filtered ID +// currentPage = Math.ceil((id + 1) / recordsPerPage); + +// // Enable or Disable the Previous button based on the current page +// if (currentPage > 1) { +// document.getElementById("prevBtn")?.removeAttribute("disabled"); // Enable the Previous button here +// } else { +// document.getElementById("prevBtn")?.setAttribute("disabled", "true"); // Disable the Previous button here +// } + +// console.log(`Fetching records for page ${currentPage} with highlight on ${id}`); +// await generateTable(currentPage, id.toString()); +// } + - // Center the row that is highlighted - function centerHighlightedRow() { - const highlightedRow = document.querySelector(".highlighted"); - const mainContainer = document.getElementById("main-container"); +// // Center the row that is highlighted +// // function centerHighlightedRow() { +// // const highlightedRow = document.querySelector(".highlighted"); +// // const mainContainer = document.getElementById("main-container"); - if (highlightedRow && mainContainer) { - const containerHeight = mainContainer.clientHeight; - const rowTop = highlightedRow.getBoundingClientRect().top; - const rowHeight = highlightedRow.clientHeight; - const scrollPosition = rowTop + mainContainer.scrollTop - (containerHeight / 2) + (rowHeight / 2); - mainContainer.scrollTop = scrollPosition; - } - } +// // if (highlightedRow && mainContainer) { +// // const containerHeight = mainContainer.clientHeight; +// // const rowTop = highlightedRow.getBoundingClientRect().top; +// // const rowHeight = highlightedRow.clientHeight; +// // const scrollPosition = rowTop + mainContainer.scrollTop - (containerHeight / 2) + (rowHeight / 2); +// // mainContainer.scrollTop = scrollPosition; +// // } +// // } diff --git a/index.html b/index.html index 07d4cc6b..e0db2a73 100644 --- a/index.html +++ b/index.html @@ -20,9 +20,9 @@

Area 51's Grocery List

From 131916b4036284ce143c5bf558bad6ee5769c53f Mon Sep 17 00:00:00 2001 From: riaan Date: Thu, 14 Sep 2023 17:21:36 +0200 Subject: [PATCH 16/27] Improved architecture Rev 1.11 --- app.ts | 195 +++++++++++++++++++++++++++++++++++++++++-------- stylesheet.css | 5 +- 2 files changed, 168 insertions(+), 32 deletions(-) diff --git a/app.ts b/app.ts index 41779917..1798b462 100644 --- a/app.ts +++ b/app.ts @@ -1,7 +1,12 @@ -// ApiManager Class +// ****************************************************** Data ********************************************************* / + +// ApiManager Class class ApiManager { totalRecordCount: number | null; columnNames: string[] | null; + // from: number = 0; + // to: number = 0; + constructor() { this.totalRecordCount = null; @@ -9,6 +14,7 @@ class ApiManager { } async fetchTotalRecordCount(): Promise { + console.log("#2 - Executing fetchTotalRecordCount"); try { const response = await fetch('http://localhost:2050/recordCount'); if (!response.ok) { @@ -16,12 +22,14 @@ class ApiManager { } const data: number = await response.json(); this.totalRecordCount = data; + //this.to = data; } catch (error) { console.error(`Error fetching total record count: ${error}`); } } async fetchColumnNames(): Promise { + console.log("#3 - Executing fetchColumnNames"); try { const response = await fetch('http://localhost:2050/columns'); if (!response.ok) { @@ -35,6 +43,7 @@ class ApiManager { } async fetchRecords(from: number, to: number): Promise { + console.log(`#7 - Executing fetchRecords with from: ${from}, to: ${to}`); try { const response = await fetch(`http://localhost:2050/records?from=${from}&to=${to}`); if (!response.ok) { @@ -50,17 +59,53 @@ class ApiManager { } +// ****************************************************** Model ********************************************************* / + +class StateManager { + private from: number; + private to: number; + private apiManager: ApiManager; + + constructor(apiManager: ApiManager) { + this.apiManager = apiManager; + this.from = 0; // Default values, will be overwritten in initialize() + this.to = 0; // Default values, will be overwritten in initialize() + } + async initialize(): Promise { + await this.apiManager.fetchTotalRecordCount(); + console.log("# - Executing initialize"); + this.from = 0; // Assuming the first record starts at 0 + this.to = this.apiManager.totalRecordCount !== null ? this.apiManager.totalRecordCount : 0; + } + + getFrom(): number { + return this.from; + } + + setFrom(value: number): void { + this.from = value; + } + + getTo(): number { + return this.to; + } + + setTo(value: number): void { + this.to = value; + } +} + +// ****************************************************** View ********************************************************* / // TableRenderer Class type apiRecord = any[]; class TableRenderer { - constructor() { - // State initialization - } + constructor(private apiManager: ApiManager, private stateManager: StateManager) {} setColumnNames(columnNames: string[]): void { + console.log("#4 - Executing setColumnNames"); try { const thead = document.querySelector('thead'); if (thead === null) { @@ -74,6 +119,9 @@ class TableRenderer { row.appendChild(cell); } thead.appendChild(row); + + // Set column widths using the provided function + this.setColumnWidths(); } catch (error) { if (error instanceof Error) { // Type guard console.error(`An error occurred: ${error.message}`); @@ -82,9 +130,28 @@ class TableRenderer { } } } + setColumnWidths(): void { + console.log("#5 - Executing setColumnWidths"); + // Assuming your table has an id of "myTable" + const table = document.getElementById("myTable"); + + if (table) { + // Count the number of columns in your table + const headerCells = table.querySelectorAll("th"); + const numCols = headerCells.length; + + // Calculate the width for each column + const colWidth = 100 / numCols; + // Set the width + headerCells.forEach((headerCell: Element) => { + (headerCell as HTMLElement).style.width = `${colWidth}%`; + }); + } + } render(records: apiRecord[] | null) { + console.log("#8 - Executing render"); try { if (records === null) { throw new Error("No records to render."); @@ -111,28 +178,30 @@ class TableRenderer { } } - - adjustRows(): void { + + adjustRows(currentPage: number = 1): void { + console.log("#6 - Executing adjustRows"); try { const rowHeight = 20; const headerHeight = 180; const availableHeight = (window.innerHeight) - headerHeight ; let numRows = Math.floor(availableHeight / rowHeight); - + + // Use StateManager to get and set 'from' and 'to' + this.stateManager.setFrom(0); + this.stateManager.setTo(numRows - 1); + // Check for a minimum number of rows if (numRows <= 0) { console.log("Window size too small, setting minimum number of rows to 1"); numRows = 1; } - // Fetch the records for the current page based on the newly calculated numRows - const apiManager = new ApiManager(); - const currentPage = 1; // Replace with your actual current page from PaginationManager - - const from = (currentPage - 1) * numRows; - const to = from + numRows - 1; - - apiManager.fetchRecords(from, to).then(records => { + + const from = this.stateManager.getFrom(); + const to = this.stateManager.getTo(); + + this.apiManager.fetchRecords(from, to).then(records => { if (records !== null) { this.render(records); } @@ -145,51 +214,114 @@ class TableRenderer { } } - // const records = await apiManager.fetchRecords(0, 9); - // tableRenderer.render(records); -// WindowManager Class -class WindowManager { +// ****************************************************** Controller ********************************************************* / + +// WindowResizeHandler Class +class WindowResizeHandler { private timeoutId: number | null = null; - constructor(private tableRenderer: TableRenderer) {} + constructor( + private tableRenderer: TableRenderer, + private paginationManager: PaginationManager, + private stateManager: StateManager + ) {} handleResize() { + console.log("#9 - Executing handleResize"); if (this.timeoutId !== null) { clearTimeout(this.timeoutId); } this.timeoutId = window.setTimeout(() => { + const availableHeight = window.innerHeight - 180; + const numRows = Math.floor(availableHeight / 20); + + // Update the state using the StateManager + this.stateManager.setFrom(0); + this.stateManager.setTo(numRows - 1); + this.tableRenderer.adjustRows(); - this.timeoutId = null; - }, 200); + this.timeoutId = null; + }, 250); } } - - - // PaginationManager Class class PaginationManager { currentPage: number = 1; + tableRenderer: TableRenderer; + + constructor(private tableRenderer: TableRenderer, private stateManager: StateManager) { + this.tableRenderer = tableRenderer; + //this.updateButtonStates(); + } incrementPage(): void { + console.log("#10 - Executing incrementPage"); this.currentPage += 1; + + const from = this.stateManager.getFrom(); + const to = this.stateManager.getTo(); + + this.stateManager.setFrom(from + (to - from + 1)); + this.stateManager.setTo(to + (to - from + 1)); + + this.tableRenderer.adjustRows(); + this.updateButtonStates(); } decrementPage(): void { + console.log("#11 - Executing decrementPage"); if (this.currentPage > 1) { this.currentPage -= 1; + + const from = this.stateManager.getFrom(); + const to = this.stateManager.getTo(); + + // Similar logic to incrementPage to recalculate "from" and "to" + this.stateManager.setFrom(from - (to - from + 1)); + this.stateManager.setTo(to - (to - from + 1)); + + this.tableRenderer.adjustRows(); + this.updateButtonStates(); + } + } + + private updateButtonStates(): void { + console.log("#12 - Executing updateButtonstates") + const prevButton = document.getElementById("prevPage") as HTMLButtonElement; + const nextButton = document.getElementById("nextPage") as HTMLButtonElement; + + if (this.currentPage <= 1 && prevButton !== null) { + prevButton.disabled = true; + } else if (prevButton !== null) { + prevButton.disabled = false; } + + // You can add logic for the "Next" button too, based on the total number of pages. } + } // main script window.onload = async () => { - const apiManager = new ApiManager(); - const tableRenderer = new TableRenderer(); - const windowManager = new WindowManager(tableRenderer); - const paginationManager = new PaginationManager(); + console.log("#1 - Executing window.onload"); + + // Initialize Data + const apiManager = new ApiManager(); + + // Initialize Model + const stateManager = new StateManager(apiManager); + await stateManager.initialize(); // Don't forget to await! + + // Initialize View + const tableRenderer = new TableRenderer(apiManager, stateManager); + + // Initialize Controllers + const WindowResizeHandler = new WindowResizeHandler(tableRenderer, stateManager); + const paginationManager = new PaginationManager(tableRenderer, stateManager); + // Fetch total record count and column names await apiManager.fetchTotalRecordCount(); @@ -204,8 +336,9 @@ window.onload = async () => { tableRenderer.adjustRows(); // Attach event listeners - window.addEventListener('resize', () => windowManager.handleResize()); - + window.addEventListener('resize', () => WindowResizeHandler.handleResize()); + document.getElementById("prevPage")?.addEventListener("click", () => { paginationManager.decrementPage();}) + document.getElementById("nextPage")?.addEventListener("click", () => { paginationManager.incrementPage();}) // You can also attach listeners for 'Next Page', 'Previous Page', and 'Filter by ID' here }; diff --git a/stylesheet.css b/stylesheet.css index 573764ae..c85bda42 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -14,12 +14,14 @@ #main-container { margin: 0 auto; background-color: #fff; + } html, body { font-family: 'SF Pro Text', 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #333; margin-bottom: 0; + overflow: hidden; } /* Apply background color and text color to the table headers */ @@ -44,6 +46,7 @@ td { /* Style the table itself for gridlines */ table { border-collapse: collapse; + } #myTable { @@ -52,7 +55,7 @@ table { border: 1px solid #a1e3a1; border-radius: 12px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); - overflow: hidden; + } .highlighted-green td { From 3e7b865b4f2c333f291582793004e18f4fa5f934 Mon Sep 17 00:00:00 2001 From: riaan Date: Fri, 15 Sep 2023 16:29:01 +0200 Subject: [PATCH 17/27] Progress Update --- app.ts | 203 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 128 insertions(+), 75 deletions(-) diff --git a/app.ts b/app.ts index 1798b462..ba6aa12a 100644 --- a/app.ts +++ b/app.ts @@ -14,7 +14,7 @@ class ApiManager { } async fetchTotalRecordCount(): Promise { - console.log("#2 - Executing fetchTotalRecordCount"); + console.log("Function #2 - Executing fetchTotalRecordCount"); try { const response = await fetch('http://localhost:2050/recordCount'); if (!response.ok) { @@ -29,7 +29,7 @@ class ApiManager { } async fetchColumnNames(): Promise { - console.log("#3 - Executing fetchColumnNames"); + console.log("Function #3 - Executing fetchColumnNames"); try { const response = await fetch('http://localhost:2050/columns'); if (!response.ok) { @@ -62,37 +62,102 @@ class ApiManager { // ****************************************************** Model ********************************************************* / class StateManager { + private rowHeight: number; + private headerHeight: number; + private availableHeight: number; + private numRows: number; private from: number; private to: number; private apiManager: ApiManager; + private records: any[][] | null = null; + private columnNames: string[] | null; constructor(apiManager: ApiManager) { + this.rowHeight = 20; // Default value, can be updated later + this.headerHeight = 180; // Default value, can be updated later + this.availableHeight = 0; + this.numRows = 0; this.apiManager = apiManager; this.from = 0; // Default values, will be overwritten in initialize() this.to = 0; // Default values, will be overwritten in initialize() + this.columnNames = null; } async initialize(): Promise { + console.log("Function #1 - Executing initialize"); await this.apiManager.fetchTotalRecordCount(); - console.log("# - Executing initialize"); - this.from = 0; // Assuming the first record starts at 0 - this.to = this.apiManager.totalRecordCount !== null ? this.apiManager.totalRecordCount : 0; + await this.retrieveColumnNames(); + this.adjustWindowSize(); + } + + async retrieveColumnNames() { + console.log("Function # - Executing retrieveColumnNames"); + await this.apiManager.fetchColumnNames(); + if (this.apiManager.columnNames !== null) { + this.columnNames = this.apiManager.columnNames; + } + } + + getColumnNames(): string[] | null { + console.log("Function #4 - Executing getColumnNames"); + return this.columnNames; + } + + + getRecords(): any[][] | null { + console.log("Function # - Executing getRecords"); + return this.records; } + getFrom(): number { + console.log("Function # - Executing getFrom"); return this.from; } setFrom(value: number): void { + console.log("Function # - Executing setFrom"); this.from = value; } getTo(): number { + console.log("Function # - Executing getTo"); return this.to; } setTo(value: number): void { + console.log("Function # - Executing setTo"); this.to = value; } + + goToNextPage(): void { + console.log("Function # - Executing goToNextPage"); + const from = this.getFrom(); + const to = this.getTo(); + this.setFrom(from + (to - from + 1)); + this.setTo(to + (to - from + 1)); + } + + goToPreviousPage(): void { + console.log("Function # - Executing goToPreviousPage"); + const from = this.getFrom(); + const to = this.getTo(); + this.setFrom(from - (to - from + 1)); + this.setTo(to - (to - from + 1)); + } + + // Inside StateManager class + adjustWindowSize(): void { + console.log("Function # - Executing adjustWindowSize"); + this.availableHeight = window.innerHeight - this.headerHeight; + this.numRows = Math.floor(this.availableHeight / this.rowHeight); + this.setFrom(0); // Assuming the first row is always 0 + this.setTo(this.numRows - 1); + } + + async retrieveRecords() { + console.log("Function #6 - Executing retrieveRecords"); + this.records = await this.apiManager.fetchRecords(this.from, this.to); + } } // ****************************************************** View ********************************************************* / @@ -102,10 +167,15 @@ class StateManager { type apiRecord = any[]; class TableRenderer { - constructor(private apiManager: ApiManager, private stateManager: StateManager) {} + private stateManager: StateManager; + + // Constructor + constructor(stateManager: StateManager) { + this.stateManager = stateManager; + } setColumnNames(columnNames: string[]): void { - console.log("#4 - Executing setColumnNames"); + console.log("Function #5 - Executing setColumnNames"); try { const thead = document.querySelector('thead'); if (thead === null) { @@ -179,35 +249,35 @@ class TableRenderer { } - adjustRows(currentPage: number = 1): void { - console.log("#6 - Executing adjustRows"); + async adjustRows(): Promise { + console.log("Function #7 - Executing adjustRows"); try { - const rowHeight = 20; - const headerHeight = 180; - const availableHeight = (window.innerHeight) - headerHeight ; + const rowHeight = 20; + const headerHeight = 180; + const availableHeight = window.innerHeight - headerHeight; let numRows = Math.floor(availableHeight / rowHeight); - + // Use StateManager to get and set 'from' and 'to' - this.stateManager.setFrom(0); - this.stateManager.setTo(numRows - 1); - + // this.stateManager.setFrom(0); + // this.stateManager.setTo(numRows - 1); + // Check for a minimum number of rows if (numRows <= 0) { console.log("Window size too small, setting minimum number of rows to 1"); numRows = 1; } - - const from = this.stateManager.getFrom(); - const to = this.stateManager.getTo(); - - this.apiManager.fetchRecords(from, to).then(records => { - if (records !== null) { - this.render(records); - } - }).catch(error => { - console.error(`An error occurred while fetching records: ${error}`); - }); + + // Fetch the records using StateManager + await this.stateManager.retrieveRecords(); + + // Get the records from StateManager + const records = this.stateManager.getRecords(); + + // Render the records if they're available + if (records !== null) { + this.render(records); + } } catch (error) { console.error(`An error occurred: ${error}`); } @@ -226,24 +296,25 @@ class WindowResizeHandler { private stateManager: StateManager ) {} + // Inside WindowResizeHandler class handleResize() { - console.log("#9 - Executing handleResize"); + console.log("Function #8 - Executing handleResize"); + if (this.timeoutId !== null) { clearTimeout(this.timeoutId); } this.timeoutId = window.setTimeout(() => { - const availableHeight = window.innerHeight - 180; - const numRows = Math.floor(availableHeight / 20); - - // Update the state using the StateManager - this.stateManager.setFrom(0); - this.stateManager.setTo(numRows - 1); - + // Delegate the logic to adjust 'from' and 'to' to StateManager + this.stateManager.adjustToWindowSize(window.innerHeight, 20, 180); + + // Then adjust the rows in the view this.tableRenderer.adjustRows(); - this.timeoutId = null; - }, 250); + + this.timeoutId = null; + }, 250); } + } // PaginationManager Class @@ -257,31 +328,18 @@ class PaginationManager { } incrementPage(): void { - console.log("#10 - Executing incrementPage"); + console.log("Function # - Executing incrementPage"); this.currentPage += 1; - - const from = this.stateManager.getFrom(); - const to = this.stateManager.getTo(); - - this.stateManager.setFrom(from + (to - from + 1)); - this.stateManager.setTo(to + (to - from + 1)); - + this.stateManager.goToNextPage(); this.tableRenderer.adjustRows(); this.updateButtonStates(); } decrementPage(): void { - console.log("#11 - Executing decrementPage"); + console.log("Function # - Executing decrementPage"); if (this.currentPage > 1) { this.currentPage -= 1; - - const from = this.stateManager.getFrom(); - const to = this.stateManager.getTo(); - - // Similar logic to incrementPage to recalculate "from" and "to" - this.stateManager.setFrom(from - (to - from + 1)); - this.stateManager.setTo(to - (to - from + 1)); - + this.stateManager.goToPreviousPage(); this.tableRenderer.adjustRows(); this.updateButtonStates(); } @@ -303,43 +361,38 @@ class PaginationManager { } - +// ****************************************************** Main Script ********************************************************* / // main script window.onload = async () => { - console.log("#1 - Executing window.onload"); + console.log("Event #1 - Executing window.onload"); // Initialize Data const apiManager = new ApiManager(); + // Initialize Model const stateManager = new StateManager(apiManager); await stateManager.initialize(); // Don't forget to await! + //await stateManager.retrieveRecords(); // Fetch and set records from API Manager + await stateManager.retrieveColumnNames(); // Fetch and store the column names // Initialize View - const tableRenderer = new TableRenderer(apiManager, stateManager); + const tableRenderer = new TableRenderer(stateManager); + const columnNames = stateManager.getColumnNames(); + if (columnNames !== null) { + tableRenderer.setColumnNames(columnNames); + } + tableRenderer.adjustRows(); // Initialize Controllers const WindowResizeHandler = new WindowResizeHandler(tableRenderer, stateManager); const paginationManager = new PaginationManager(tableRenderer, stateManager); - - // Fetch total record count and column names - await apiManager.fetchTotalRecordCount(); - await apiManager.fetchColumnNames(); - - // Set column names - if (apiManager.columnNames !== null) { - tableRenderer.setColumnNames(apiManager.columnNames); - } - - // Initial fetch and render of records - tableRenderer.adjustRows(); - - // Attach event listeners - window.addEventListener('resize', () => WindowResizeHandler.handleResize()); - document.getElementById("prevPage")?.addEventListener("click", () => { paginationManager.decrementPage();}) - document.getElementById("nextPage")?.addEventListener("click", () => { paginationManager.incrementPage();}) - // You can also attach listeners for 'Next Page', 'Previous Page', and 'Filter by ID' here + // Attach event listeners + window.addEventListener('resize', () => WindowResizeHandler.handleResize()); + document.getElementById("prevPage")?.addEventListener("click", () => { paginationManager.decrementPage();}) + document.getElementById("nextPage")?.addEventListener("click", () => { paginationManager.incrementPage();}) + // You can also attach listeners for 'Next Page', 'Previous Page', and 'Filter by ID' here }; From 6a8c40ca34fb80de8a8e6c5339ac7f46b86f3f96 Mon Sep 17 00:00:00 2001 From: riaan Date: Mon, 18 Sep 2023 16:15:04 +0200 Subject: [PATCH 18/27] Improved architecture Rev 1.12 --- app.ts | 122 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 74 insertions(+), 48 deletions(-) diff --git a/app.ts b/app.ts index ba6aa12a..9729156d 100644 --- a/app.ts +++ b/app.ts @@ -2,19 +2,19 @@ // ApiManager Class class ApiManager { - totalRecordCount: number | null; + totalRecordCount: number; columnNames: string[] | null; // from: number = 0; // to: number = 0; constructor() { - this.totalRecordCount = null; + this.totalRecordCount = 0; this.columnNames = null; } async fetchTotalRecordCount(): Promise { - console.log("Function #2 - Executing fetchTotalRecordCount"); + console.log("Function #3 - Executing fetchTotalRecordCount"); try { const response = await fetch('http://localhost:2050/recordCount'); if (!response.ok) { @@ -29,7 +29,7 @@ class ApiManager { } async fetchColumnNames(): Promise { - console.log("Function #3 - Executing fetchColumnNames"); + console.log("Function #5 - Executing fetchColumnNames"); try { const response = await fetch('http://localhost:2050/columns'); if (!response.ok) { @@ -43,7 +43,7 @@ class ApiManager { } async fetchRecords(from: number, to: number): Promise { - console.log(`#7 - Executing fetchRecords with from: ${from}, to: ${to}`); + console.log(`Function #12.1 - Executing fetchRecords with from: ${from}, to: ${to}`); try { const response = await fetch(`http://localhost:2050/records?from=${from}&to=${to}`); if (!response.ok) { @@ -71,6 +71,7 @@ class StateManager { private apiManager: ApiManager; private records: any[][] | null = null; private columnNames: string[] | null; + private totalRecordCount = 0; constructor(apiManager: ApiManager) { this.rowHeight = 20; // Default value, can be updated later @@ -81,30 +82,37 @@ class StateManager { this.from = 0; // Default values, will be overwritten in initialize() this.to = 0; // Default values, will be overwritten in initialize() this.columnNames = null; + this.totalRecordCount = 0; } - async initialize(): Promise { + async initializeState(): Promise { console.log("Function #1 - Executing initialize"); - await this.apiManager.fetchTotalRecordCount(); + await this.fetchAndStoreTotalRecordCount(); await this.retrieveColumnNames(); this.adjustWindowSize(); } async retrieveColumnNames() { - console.log("Function # - Executing retrieveColumnNames"); + console.log("Function #4 - Executing retrieveColumnNames"); await this.apiManager.fetchColumnNames(); if (this.apiManager.columnNames !== null) { this.columnNames = this.apiManager.columnNames; } } + async fetchAndStoreTotalRecordCount(): Promise { + console.log("Function #2 - Executing fetchAndStoreTotalRecordCount"); + await this.apiManager.fetchTotalRecordCount(); + this.totalRecordCount = this.apiManager.totalRecordCount; + } + getColumnNames(): string[] | null { - console.log("Function #4 - Executing getColumnNames"); + console.log("Function #10 - Executing getColumnNames"); return this.columnNames; } getRecords(): any[][] | null { - console.log("Function # - Executing getRecords"); + console.log("Function #13 - Executing getRecords"); return this.records; } @@ -115,7 +123,7 @@ class StateManager { } setFrom(value: number): void { - console.log("Function # - Executing setFrom"); + console.log("Function #7 - Executing setFrom"); this.from = value; } @@ -125,7 +133,7 @@ class StateManager { } setTo(value: number): void { - console.log("Function # - Executing setTo"); + console.log("Function #8 - Executing setTo"); this.to = value; } @@ -147,15 +155,19 @@ class StateManager { // Inside StateManager class adjustWindowSize(): void { - console.log("Function # - Executing adjustWindowSize"); + console.log("Function #6 - Executing adjustWindowSize"); this.availableHeight = window.innerHeight - this.headerHeight; this.numRows = Math.floor(this.availableHeight / this.rowHeight); + if (this.numRows <= 0) { + console.log("Window size too small, setting minimum number of rows to 1"); + this.numRows = 1; + } this.setFrom(0); // Assuming the first row is always 0 this.setTo(this.numRows - 1); } async retrieveRecords() { - console.log("Function #6 - Executing retrieveRecords"); + console.log("Function #12 - Executing retrieveRecords"); this.records = await this.apiManager.fetchRecords(this.from, this.to); } } @@ -174,8 +186,24 @@ class TableRenderer { this.stateManager = stateManager; } - setColumnNames(columnNames: string[]): void { - console.log("Function #5 - Executing setColumnNames"); + async initialRender(stateManager: StateManager): Promise { + console.log("Function #9 - Executing initialRender"); + const columnNames = stateManager.getColumnNames(); + if (columnNames !== null) { + this.renderColumnNames(columnNames); + } + + await stateManager.retrieveRecords(); + const records = stateManager.getRecords(); + + // Render the records if they're available + if (records !== null) { + this.renderRecords(records); + } + } + + renderColumnNames(columnNames: string[]): void { + console.log("Function #11 - Executing renderColumnNames"); try { const thead = document.querySelector('thead'); if (thead === null) { @@ -201,7 +229,7 @@ class TableRenderer { } } setColumnWidths(): void { - console.log("#5 - Executing setColumnWidths"); + console.log("Function #11.1 - Executing setColumnWidths"); // Assuming your table has an id of "myTable" const table = document.getElementById("myTable"); @@ -220,8 +248,8 @@ class TableRenderer { } } - render(records: apiRecord[] | null) { - console.log("#8 - Executing render"); + renderRecords(records: apiRecord[] | null) { + console.log("Function #14 - Executing renderRecords"); try { if (records === null) { throw new Error("No records to render."); @@ -252,31 +280,31 @@ class TableRenderer { async adjustRows(): Promise { console.log("Function #7 - Executing adjustRows"); try { - const rowHeight = 20; - const headerHeight = 180; - const availableHeight = window.innerHeight - headerHeight; + // const rowHeight = 20; + // const headerHeight = 180; + // const availableHeight = window.innerHeight - headerHeight; - let numRows = Math.floor(availableHeight / rowHeight); + // let numRows = Math.floor(availableHeight / rowHeight); // Use StateManager to get and set 'from' and 'to' // this.stateManager.setFrom(0); // this.stateManager.setTo(numRows - 1); // Check for a minimum number of rows - if (numRows <= 0) { - console.log("Window size too small, setting minimum number of rows to 1"); - numRows = 1; - } + // if (numRows <= 0) { + // console.log("Window size too small, setting minimum number of rows to 1"); + // numRows = 1; + // } // Fetch the records using StateManager - await this.stateManager.retrieveRecords(); + // Get the records from StateManager const records = this.stateManager.getRecords(); // Render the records if they're available if (records !== null) { - this.render(records); + this.renderRecords(records); } } catch (error) { console.error(`An error occurred: ${error}`); @@ -292,25 +320,28 @@ class WindowResizeHandler { constructor( private tableRenderer: TableRenderer, - private paginationManager: PaginationManager, + // private paginationManager: PaginationManager, private stateManager: StateManager ) {} // Inside WindowResizeHandler class handleResize() { - console.log("Function #8 - Executing handleResize"); + console.log("Function ## - Executing handleResize"); if (this.timeoutId !== null) { clearTimeout(this.timeoutId); } - this.timeoutId = window.setTimeout(() => { + this.timeoutId = window.setTimeout(async () => { // Delegate the logic to adjust 'from' and 'to' to StateManager - this.stateManager.adjustToWindowSize(window.innerHeight, 20, 180); - - // Then adjust the rows in the view - this.tableRenderer.adjustRows(); - + this.stateManager.adjustWindowSize(); + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + // Render the records if they're available + if (records !== null) { + this.tableRenderer.renderRecords(records); + } this.timeoutId = null; }, 250); } @@ -320,7 +351,6 @@ class WindowResizeHandler { // PaginationManager Class class PaginationManager { currentPage: number = 1; - tableRenderer: TableRenderer; constructor(private tableRenderer: TableRenderer, private stateManager: StateManager) { this.tableRenderer = tableRenderer; @@ -372,24 +402,20 @@ window.onload = async () => { // Initialize Model const stateManager = new StateManager(apiManager); - await stateManager.initialize(); // Don't forget to await! - //await stateManager.retrieveRecords(); // Fetch and set records from API Manager - await stateManager.retrieveColumnNames(); // Fetch and store the column names + await stateManager.initializeState(); // Don't forget to await! + // Initialize View const tableRenderer = new TableRenderer(stateManager); - const columnNames = stateManager.getColumnNames(); - if (columnNames !== null) { - tableRenderer.setColumnNames(columnNames); - } - tableRenderer.adjustRows(); + await tableRenderer.initialRender(stateManager); + // Initialize Controllers - const WindowResizeHandler = new WindowResizeHandler(tableRenderer, stateManager); + const windowResizeHandler = new WindowResizeHandler(tableRenderer, stateManager); const paginationManager = new PaginationManager(tableRenderer, stateManager); // Attach event listeners - window.addEventListener('resize', () => WindowResizeHandler.handleResize()); + window.addEventListener('resize', () => windowResizeHandler.handleResize()); document.getElementById("prevPage")?.addEventListener("click", () => { paginationManager.decrementPage();}) document.getElementById("nextPage")?.addEventListener("click", () => { paginationManager.incrementPage();}) // You can also attach listeners for 'Next Page', 'Previous Page', and 'Filter by ID' here From ecb725af7063cd6bf2afd70551fcb714790b5258 Mon Sep 17 00:00:00 2001 From: riaan Date: Tue, 19 Sep 2023 16:19:09 +0200 Subject: [PATCH 19/27] Improved architecture Rev 1.13 --- app.ts | 143 +++++++++++++++++++++++++++++++++++++++++------------ index.html | 1 + 2 files changed, 113 insertions(+), 31 deletions(-) diff --git a/app.ts b/app.ts index 9729156d..a9af2001 100644 --- a/app.ts +++ b/app.ts @@ -105,6 +105,10 @@ class StateManager { this.totalRecordCount = this.apiManager.totalRecordCount; } + getTotalRecordCount(): number { + return this.totalRecordCount; + } + getColumnNames(): string[] | null { console.log("Function #10 - Executing getColumnNames"); return this.columnNames; @@ -118,7 +122,7 @@ class StateManager { getFrom(): number { - console.log("Function # - Executing getFrom"); + console.log("Function #18 - Executing getFrom"); return this.from; } @@ -128,7 +132,7 @@ class StateManager { } getTo(): number { - console.log("Function # - Executing getTo"); + console.log("Function #19 - Executing getTo"); return this.to; } @@ -138,20 +142,65 @@ class StateManager { } goToNextPage(): void { - console.log("Function # - Executing goToNextPage"); + console.log("Function #17 - Executing goToNextPage"); const from = this.getFrom(); const to = this.getTo(); - this.setFrom(from + (to - from + 1)); - this.setTo(to + (to - from + 1)); + const stepSize = to - from + 1; + + // Calculate the new 'from' and 'to' values + const newFrom = from + stepSize; + const newTo = to + stepSize; + + // Check that 'to' does not exceed totalRecordCount + if (newTo >= this.totalRecordCount) { + this.setTo(this.totalRecordCount - 1); + this.setFrom(newFrom); + } else { + this.setFrom(newFrom); + this.setTo(newTo); + } } + goToPreviousPage(): void { - console.log("Function # - Executing goToPreviousPage"); + console.log("Function #22 - Executing goToPreviousPage"); const from = this.getFrom(); const to = this.getTo(); - this.setFrom(from - (to - from + 1)); - this.setTo(to - (to - from + 1)); + const stepSize = to - from + 1; + + // Calculate the new 'from' and 'to' values + const newFrom = from - stepSize; + const newTo = to - stepSize; + + if (newFrom < 0) { + // Set the 'from' value to zero + this.setFrom(0); + this.setTo(newTo); + + } else { + this.setFrom(newFrom); + this.setTo(newTo); + } + } + + async searchByIdStateChange(id: number): Promise { + console.log("Function #24 - Executing searchByIdStateChange"); + + const newFrom = id; + const newTo = id + this.numRows - 1; + + // Check that 'to' does not exceed totalRecordCount + if (newTo >= this.totalRecordCount) { + this.setTo(this.totalRecordCount - 1); + } else { + this.setTo(newTo); + } + + this.setFrom(newFrom); + + await this.retrieveRecords(); } + // Inside StateManager class adjustWindowSize(): void { @@ -162,8 +211,15 @@ class StateManager { console.log("Window size too small, setting minimum number of rows to 1"); this.numRows = 1; } - this.setFrom(0); // Assuming the first row is always 0 - this.setTo(this.numRows - 1); + // Check if on the first page + if (this.from === 0) { + this.setFrom(0); // Assuming the first row is always 0 + this.setTo(this.numRows - 1); + + } else { + // If not on the first page, only adjust the 'to' value + this.setTo(this.from + this.numRows - 1); + } } async retrieveRecords() { @@ -326,7 +382,7 @@ class WindowResizeHandler { // Inside WindowResizeHandler class handleResize() { - console.log("Function ## - Executing handleResize"); + console.log("Function #15 - Executing handleResize"); if (this.timeoutId !== null) { clearTimeout(this.timeoutId); @@ -354,40 +410,65 @@ class PaginationManager { constructor(private tableRenderer: TableRenderer, private stateManager: StateManager) { this.tableRenderer = tableRenderer; + this.stateManager = stateManager //this.updateButtonStates(); } - incrementPage(): void { - console.log("Function # - Executing incrementPage"); - this.currentPage += 1; + async incrementPage(): Promise { + console.log("Function #16 - Executing incrementPage"); this.stateManager.goToNextPage(); - this.tableRenderer.adjustRows(); + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); + } this.updateButtonStates(); } - decrementPage(): void { - console.log("Function # - Executing decrementPage"); - if (this.currentPage > 1) { - this.currentPage -= 1; - this.stateManager.goToPreviousPage(); - this.tableRenderer.adjustRows(); - this.updateButtonStates(); + async decrementPage(): Promise { + console.log("Function #21 - Executing decrementPage"); + this.stateManager.goToPreviousPage(); + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); } + this.updateButtonStates(); + } + + async searchById(): Promise { + console.log("Function #23 - Executing searchById"); + const filterInput = document.getElementById('filterInput') as HTMLInputElement; + const searchValue = parseInt(filterInput.value, 10); + await this.stateManager.searchByIdStateChange(searchValue); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); + } + this.updateButtonStates(); } private updateButtonStates(): void { - console.log("#12 - Executing updateButtonstates") + console.log("Function #20 - Executing updateButtonstates"); const prevButton = document.getElementById("prevPage") as HTMLButtonElement; const nextButton = document.getElementById("nextPage") as HTMLButtonElement; - - if (this.currentPage <= 1 && prevButton !== null) { - prevButton.disabled = true; - } else if (prevButton !== null) { - prevButton.disabled = false; + + const from = this.stateManager.getFrom(); // Use the getter to get the value of `from` + const to = this.stateManager.getTo(); // Use the getter to get the value of `to` + const totalRecordCount = this.stateManager.getTotalRecordCount(); // Use a getter to get the totalRecordCount + + if (prevButton !== null) { + prevButton.disabled = from === 0; + } + + if (nextButton !== null) { + nextButton.disabled = to === totalRecordCount - 1; } - - // You can add logic for the "Next" button too, based on the total number of pages. } + } @@ -418,7 +499,7 @@ window.onload = async () => { window.addEventListener('resize', () => windowResizeHandler.handleResize()); document.getElementById("prevPage")?.addEventListener("click", () => { paginationManager.decrementPage();}) document.getElementById("nextPage")?.addEventListener("click", () => { paginationManager.incrementPage();}) - // You can also attach listeners for 'Next Page', 'Previous Page', and 'Filter by ID' here + document.getElementById('searchButton')?.addEventListener("click", () => { paginationManager.searchById();}) }; diff --git a/index.html b/index.html index e0db2a73..7e3de05b 100644 --- a/index.html +++ b/index.html @@ -23,6 +23,7 @@

Area 51's Grocery List

+
From b74badf8407abb1b87eaf92e962f5e2798c6fd13 Mon Sep 17 00:00:00 2001 From: riaan Date: Wed, 20 Sep 2023 14:59:06 +0200 Subject: [PATCH 20/27] Functionality Improvements Rev 1.14 --- app.ts | 53 +++++++++++++++++++++++++++++++++++++++----------- stylesheet.css | 15 +++++++++----- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/app.ts b/app.ts index a9af2001..0c054786 100644 --- a/app.ts +++ b/app.ts @@ -72,6 +72,7 @@ class StateManager { private records: any[][] | null = null; private columnNames: string[] | null; private totalRecordCount = 0; + highlightedId: number | null = null; constructor(apiManager: ApiManager) { this.rowHeight = 20; // Default value, can be updated later @@ -166,16 +167,17 @@ class StateManager { console.log("Function #22 - Executing goToPreviousPage"); const from = this.getFrom(); const to = this.getTo(); - const stepSize = to - from + 1; + const recordsPerPage = this.numRows; // Calculate the new 'from' and 'to' values - const newFrom = from - stepSize; - const newTo = to - stepSize; + const newFrom = from - recordsPerPage; + const newTo = newFrom + recordsPerPage - 1; + if (newFrom < 0) { // Set the 'from' value to zero this.setFrom(0); - this.setTo(newTo); + this.setTo(recordsPerPage - 1); } else { this.setFrom(newFrom); @@ -304,8 +306,9 @@ class TableRenderer { } } - renderRecords(records: apiRecord[] | null) { + renderRecords(records: apiRecord[] | null, highlightId: number | null = null) { console.log("Function #14 - Executing renderRecords"); + highlightId = highlightId ?? this.stateManager.highlightedId; // use state if highlightId is null try { if (records === null) { throw new Error("No records to render."); @@ -320,6 +323,9 @@ class TableRenderer { records.forEach((record) => { const row = document.createElement('tr'); + if (highlightId !== null && record.length > 0 && parseInt(record[0].toString(), 10) === highlightId) { + row.classList.add('highlight'); + } record.forEach((cell) => { const td = document.createElement('td'); td.textContent = cell.toString(); @@ -390,6 +396,7 @@ class WindowResizeHandler { this.timeoutId = window.setTimeout(async () => { // Delegate the logic to adjust 'from' and 'to' to StateManager + this.stateManager.adjustWindowSize(); await this.stateManager.retrieveRecords(); const records = this.stateManager.getRecords(); @@ -406,7 +413,7 @@ class WindowResizeHandler { // PaginationManager Class class PaginationManager { - currentPage: number = 1; + // currentPage: number = 1; constructor(private tableRenderer: TableRenderer, private stateManager: StateManager) { this.tableRenderer = tableRenderer; @@ -414,6 +421,11 @@ class PaginationManager { //this.updateButtonStates(); } + async navigateToHome() { + console.log("Function #25 - Navigating to Home"); + window.location.reload(); + } + async incrementPage(): Promise { console.log("Function #16 - Executing incrementPage"); this.stateManager.goToNextPage(); @@ -442,15 +454,35 @@ class PaginationManager { console.log("Function #23 - Executing searchById"); const filterInput = document.getElementById('filterInput') as HTMLInputElement; const searchValue = parseInt(filterInput.value, 10); + this.stateManager.highlightedId = searchValue; await this.stateManager.searchByIdStateChange(searchValue); const records = this.stateManager.getRecords(); if (records !== null) { - this.tableRenderer.renderRecords(records); + this.tableRenderer.renderRecords(records, searchValue); } + this.updateButtonStates(); } + setupLiveValidation(): void { + const filterInput = document.getElementById('filterInput') as HTMLInputElement; + const errorMessage = document.getElementById('errorMessage') as HTMLElement; + + filterInput.addEventListener('input', () => { + const inputValue = filterInput.value; + + if (inputValue.length === 0) { + errorMessage.textContent = ""; + } else if (inputValue.length < 1 || inputValue.length > 6 || !/^\d+$/.test(inputValue)) { + errorMessage.textContent = "Invalid input. Please enter a number between 0 and 999 999."; + } else { + errorMessage.textContent = ""; + } + }); + } + + private updateButtonStates(): void { console.log("Function #20 - Executing updateButtonstates"); const prevButton = document.getElementById("prevPage") as HTMLButtonElement; @@ -468,8 +500,6 @@ class PaginationManager { nextButton.disabled = to === totalRecordCount - 1; } } - - } // ****************************************************** Main Script ********************************************************* / @@ -484,7 +514,7 @@ window.onload = async () => { // Initialize Model const stateManager = new StateManager(apiManager); await stateManager.initializeState(); // Don't forget to await! - + // Initialize View const tableRenderer = new TableRenderer(stateManager); @@ -496,10 +526,12 @@ window.onload = async () => { const paginationManager = new PaginationManager(tableRenderer, stateManager); // Attach event listeners + paginationManager.setupLiveValidation(); window.addEventListener('resize', () => windowResizeHandler.handleResize()); document.getElementById("prevPage")?.addEventListener("click", () => { paginationManager.decrementPage();}) document.getElementById("nextPage")?.addEventListener("click", () => { paginationManager.incrementPage();}) document.getElementById('searchButton')?.addEventListener("click", () => { paginationManager.searchById();}) + document.getElementById("main-heading")?.addEventListener("click", () => { paginationManager.navigateToHome();}) }; @@ -526,7 +558,6 @@ window.onload = async () => { - // *** Development Setup ***// diff --git a/stylesheet.css b/stylesheet.css index c85bda42..6ee469ef 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -8,7 +8,8 @@ text-align: center; margin: 10px 0; color: #333; - text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1); + text-shadow: #00FF00; + cursor: pointer; } #main-container { @@ -50,6 +51,10 @@ table { } #myTable { + table-layout: fixed; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; width: 100%; height: 100%; border: 1px solid #a1e3a1; @@ -58,8 +63,8 @@ table { } -.highlighted-green td { - background-color: #333333 !important; +.highlight { + background-color: #00FF00!important; color: #4CAF50 !important; /* Added this line to make the text color green */ } @@ -67,13 +72,13 @@ table { .pagination-1 { text-align: center; padding-top: 25px; - padding-bottom: 20px; + padding-bottom: 25px; font-family: 'Orbitron', sans-serif; } button { padding: 10px 20px; - border: none; + border: 1px solid #00FF00;; background-color: #1e1e1e; /* Dark Grey almost Black */ color: #00FF00; /* Bright green like old school terminals */ border-radius: 5px; From f7cc4b2f85845b11bd80912f352d76633bd44dcc Mon Sep 17 00:00:00 2001 From: riaan Date: Thu, 21 Sep 2023 16:15:44 +0200 Subject: [PATCH 21/27] Error handling added Rev 1.15 --- app.ts | 462 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 278 insertions(+), 184 deletions(-) diff --git a/app.ts b/app.ts index 0c054786..3079d33d 100644 --- a/app.ts +++ b/app.ts @@ -1,12 +1,9 @@ // ****************************************************** Data ********************************************************* / -// ApiManager Class + class ApiManager { totalRecordCount: number; columnNames: string[] | null; - // from: number = 0; - // to: number = 0; - constructor() { this.totalRecordCount = 0; @@ -22,7 +19,6 @@ class ApiManager { } const data: number = await response.json(); this.totalRecordCount = data; - //this.to = data; } catch (error) { console.error(`Error fetching total record count: ${error}`); } @@ -75,37 +71,52 @@ class StateManager { highlightedId: number | null = null; constructor(apiManager: ApiManager) { - this.rowHeight = 20; // Default value, can be updated later - this.headerHeight = 180; // Default value, can be updated later + this.rowHeight = 20; + this.headerHeight = 180; this.availableHeight = 0; this.numRows = 0; this.apiManager = apiManager; - this.from = 0; // Default values, will be overwritten in initialize() - this.to = 0; // Default values, will be overwritten in initialize() + this.from = 0; + this.to = 0; this.columnNames = null; this.totalRecordCount = 0; } async initializeState(): Promise { console.log("Function #1 - Executing initialize"); - await this.fetchAndStoreTotalRecordCount(); - await this.retrieveColumnNames(); - this.adjustWindowSize(); + try { + await this.fetchAndStoreTotalRecordCount(); + await this.retrieveColumnNames(); + this.adjustWindowSize(); + } catch (error) { + console.error("Error in initializeState:", error); + } } + - async retrieveColumnNames() { + async retrieveColumnNames(): Promise { console.log("Function #4 - Executing retrieveColumnNames"); - await this.apiManager.fetchColumnNames(); - if (this.apiManager.columnNames !== null) { - this.columnNames = this.apiManager.columnNames; + try { + await this.apiManager.fetchColumnNames(); + + if (this.apiManager.columnNames !== null) { + this.columnNames = this.apiManager.columnNames; + } + } catch (error) { + console.error("Error in retrieveColumnNames:", error); } - } +} async fetchAndStoreTotalRecordCount(): Promise { console.log("Function #2 - Executing fetchAndStoreTotalRecordCount"); - await this.apiManager.fetchTotalRecordCount(); - this.totalRecordCount = this.apiManager.totalRecordCount; + try { + await this.apiManager.fetchTotalRecordCount(); + this.totalRecordCount = this.apiManager.totalRecordCount; + } catch (error) { + console.error("Error in fetchAndStoreTotalRecordCount:", error); + } } + getTotalRecordCount(): number { return this.totalRecordCount; } @@ -143,122 +154,154 @@ class StateManager { } goToNextPage(): void { - console.log("Function #17 - Executing goToNextPage"); - const from = this.getFrom(); - const to = this.getTo(); - const stepSize = to - from + 1; - - // Calculate the new 'from' and 'to' values - const newFrom = from + stepSize; - const newTo = to + stepSize; - - // Check that 'to' does not exceed totalRecordCount - if (newTo >= this.totalRecordCount) { - this.setTo(this.totalRecordCount - 1); - this.setFrom(newFrom); - } else { - this.setFrom(newFrom); - this.setTo(newTo); + try { + console.log("Function #17 - Executing goToNextPage"); + const from = this.getFrom(); + const to = this.getTo(); + const stepSize = to - from + 1; + + // Calculate the new 'from' and 'to' values + const newFrom = from + stepSize; + const newTo = to + stepSize; + + // Check that 'to' does not exceed totalRecordCount + if (newTo >= this.totalRecordCount) { + this.setTo(this.totalRecordCount - 1); + this.setFrom(newFrom); + } else { + this.setFrom(newFrom); + this.setTo(newTo); + } + } catch (error) { + console.error(`Unexpected error in goToNextPage: ${error instanceof Error ? error.message : error}`); } } - - goToPreviousPage(): void { - console.log("Function #22 - Executing goToPreviousPage"); - const from = this.getFrom(); - const to = this.getTo(); - const recordsPerPage = this.numRows; - - // Calculate the new 'from' and 'to' values - const newFrom = from - recordsPerPage; - const newTo = newFrom + recordsPerPage - 1; - - if (newFrom < 0) { - // Set the 'from' value to zero - this.setFrom(0); - this.setTo(recordsPerPage - 1); - } else { - this.setFrom(newFrom); - this.setTo(newTo); + goToPreviousPage(): void { + try { + console.log("Function #22 - Executing goToPreviousPage"); + const from = this.getFrom(); + const to = this.getTo(); + const recordsPerPage = this.numRows; + + // Calculate the new 'from' and 'to' values + const newFrom = from - recordsPerPage; + const newTo = newFrom + recordsPerPage - 1; + + if (newFrom < 0) { + // Set the 'from' value to zero + this.setFrom(0); + this.setTo(recordsPerPage - 1); + } else { + this.setFrom(newFrom); + this.setTo(newTo); + } + } catch (error) { + console.error(`Error in goToPreviousPage: ${error instanceof Error ? error.message : error}`); } } - async searchByIdStateChange(id: number): Promise { - console.log("Function #24 - Executing searchByIdStateChange"); - - const newFrom = id; - const newTo = id + this.numRows - 1; - // Check that 'to' does not exceed totalRecordCount - if (newTo >= this.totalRecordCount) { - this.setTo(this.totalRecordCount - 1); - } else { - this.setTo(newTo); + async searchByIdStateChange(id: number): Promise { + try { + console.log("Function #24 - Executing searchByIdStateChange"); + + const newFrom = id; + const newTo = id + this.numRows - 1; + + // Check that 'to' does not exceed totalRecordCount + if (newTo >= this.totalRecordCount) { + this.setTo(this.totalRecordCount - 1); + } else { + this.setTo(newTo); + } + + this.setFrom(newFrom); + + await this.retrieveRecords(); + } catch (error) { + console.error(`Error in searchByIdStateChange: ${error instanceof Error ? error.message : error}`); } - - this.setFrom(newFrom); - - await this.retrieveRecords(); - } - +} - // Inside StateManager class + adjustWindowSize(): void { console.log("Function #6 - Executing adjustWindowSize"); - this.availableHeight = window.innerHeight - this.headerHeight; - this.numRows = Math.floor(this.availableHeight / this.rowHeight); - if (this.numRows <= 0) { - console.log("Window size too small, setting minimum number of rows to 1"); - this.numRows = 1; - } - // Check if on the first page - if (this.from === 0) { - this.setFrom(0); // Assuming the first row is always 0 - this.setTo(this.numRows - 1); - } else { - // If not on the first page, only adjust the 'to' value - this.setTo(this.from + this.numRows - 1); + try { + if (typeof window === "undefined" || !window.innerHeight) { + throw new Error("Unable to access window dimensions"); + } + + if (!this.rowHeight) { + throw new Error("Row height is not properly configured"); + } + + this.availableHeight = window.innerHeight - this.headerHeight; + this.numRows = Math.floor(this.availableHeight / this.rowHeight); + + if (this.numRows <= 0) { + console.log("Window size too small, setting minimum number of rows to 1"); + this.numRows = 1; + } + + if (this.from === 0) { + this.setFrom(0); // Assuming the first row is always 0 + this.setTo(this.numRows - 1); + } else { + this.setTo(this.from + this.numRows - 1); + } + } catch (error) { + console.error(`Error in adjustWindowSize: ${error instanceof Error ? error.message : error}`); } - } +} + - async retrieveRecords() { - console.log("Function #12 - Executing retrieveRecords"); - this.records = await this.apiManager.fetchRecords(this.from, this.to); +async retrieveRecords(): Promise { + console.log("Function #12 - Executing retrieveRecords"); + try { + this.records = await this.apiManager.fetchRecords(this.from, this.to); + } catch (error) { + console.error(`Error retrieving records: ${error instanceof Error ? error.message : error}`); } } +} + // ****************************************************** View ********************************************************* / -// TableRenderer Class type apiRecord = any[]; class TableRenderer { private stateManager: StateManager; - // Constructor constructor(stateManager: StateManager) { this.stateManager = stateManager; } async initialRender(stateManager: StateManager): Promise { - console.log("Function #9 - Executing initialRender"); - const columnNames = stateManager.getColumnNames(); - if (columnNames !== null) { - this.renderColumnNames(columnNames); - } + try { + console.log("Function #9 - Executing initialRender"); - await stateManager.retrieveRecords(); - const records = stateManager.getRecords(); + const columnNames = stateManager.getColumnNames(); + if (columnNames !== null) { + this.renderColumnNames(columnNames); + } + + await stateManager.retrieveRecords(); + const records = stateManager.getRecords(); - // Render the records if they're available - if (records !== null) { - this.renderRecords(records); + if (records !== null) { + this.renderRecords(records); + } + } catch (error) { + console.error(`Error during initialRender: ${error}`); } - } +} + renderColumnNames(columnNames: string[]): void { console.log("Function #11 - Executing renderColumnNames"); @@ -276,10 +319,9 @@ class TableRenderer { } thead.appendChild(row); - // Set column widths using the provided function this.setColumnWidths(); } catch (error) { - if (error instanceof Error) { // Type guard + if (error instanceof Error) { console.error(`An error occurred: ${error.message}`); } else { console.error(`An unknown error occurred: ${error}`); @@ -288,23 +330,27 @@ class TableRenderer { } setColumnWidths(): void { console.log("Function #11.1 - Executing setColumnWidths"); - // Assuming your table has an id of "myTable" - const table = document.getElementById("myTable"); - - if (table) { - // Count the number of columns in your table + + try { + const table = document.getElementById("myTable"); + + if (!table) { + throw new Error('Table with id "myTable" not found.'); + } + const headerCells = table.querySelectorAll("th"); const numCols = headerCells.length; - - // Calculate the width for each column + const colWidth = 100 / numCols; - - // Set the width + headerCells.forEach((headerCell: Element) => { (headerCell as HTMLElement).style.width = `${colWidth}%`; }); + } catch (error) { + console.error(`Error setting column widths: ${error}`); } - } +} + renderRecords(records: apiRecord[] | null, highlightId: number | null = null) { console.log("Function #14 - Executing renderRecords"); @@ -319,7 +365,7 @@ class TableRenderer { throw new Error('Table body not found.'); } - tbody.innerHTML = ''; // Clear existing rows + tbody.innerHTML = ''; records.forEach((record) => { const row = document.createElement('tr'); @@ -374,96 +420,139 @@ class TableRenderer { } } -// ****************************************************** Controller ********************************************************* / +// ****************************************************** Controllers ********************************************************* / + -// WindowResizeHandler Class class WindowResizeHandler { - private timeoutId: number | null = null; + private debouncedUpdate: Function; constructor( private tableRenderer: TableRenderer, - // private paginationManager: PaginationManager, private stateManager: StateManager - ) {} + ) { + this.debouncedUpdate = this.debounce(this.updateAfterResize.bind(this), 350); + } - // Inside WindowResizeHandler class handleResize() { console.log("Function #15 - Executing handleResize"); + this.debouncedUpdate(); + } + + debounce(func: Function, delay: number): Function { + let timeout: ReturnType | null = null; + return (...args: any[]) => { + const later = () => { + timeout = null; + func(...args); + }; + if (timeout !== null) { + clearTimeout(timeout); + } + timeout = setTimeout(later, delay); + }; +} - if (this.timeoutId !== null) { - clearTimeout(this.timeoutId); - } - - this.timeoutId = window.setTimeout(async () => { - // Delegate the logic to adjust 'from' and 'to' to StateManager - + async updateAfterResize() { + try { + console.log("Update after resize"); this.stateManager.adjustWindowSize(); await this.stateManager.retrieveRecords(); const records = this.stateManager.getRecords(); - - // Render the records if they're available - if (records !== null) { - this.tableRenderer.renderRecords(records); + + if (records !== null) { + this.tableRenderer.renderRecords(records); + } + } catch (error) { + console.error(`Error in updateAfterResize: ${error instanceof Error ? error.message : error}`); } - this.timeoutId = null; - }, 250); } - } -// PaginationManager Class -class PaginationManager { - // currentPage: number = 1; + +class PaginationManager { + constructor(private tableRenderer: TableRenderer, private stateManager: StateManager) { this.tableRenderer = tableRenderer; this.stateManager = stateManager - //this.updateButtonStates(); } - async navigateToHome() { + navigateToHome(): void { console.log("Function #25 - Navigating to Home"); - window.location.reload(); - } + try { + window.location.reload(); + } catch (error) { + console.error(`Error while navigating to home: ${error instanceof Error ? error.message : error}`); + alert("Failed to reload the page. Please try again."); + } +} + async incrementPage(): Promise { - console.log("Function #16 - Executing incrementPage"); - this.stateManager.goToNextPage(); - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records); + try { + console.log("Function #16 - Executing incrementPage"); + this.stateManager.goToNextPage(); + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); + } + this.updateButtonStates(); + } catch (error) { + console.error(`Unexpected error in incrementPage: ${error instanceof Error ? error.message : error}`); } - this.updateButtonStates(); } + async decrementPage(): Promise { - console.log("Function #21 - Executing decrementPage"); - this.stateManager.goToPreviousPage(); - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records); + try { + console.log("Function #21 - Executing decrementPage"); + + this.stateManager.goToPreviousPage(); + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); + } + + this.updateButtonStates(); + } catch (error) { + console.error(`Error in decrementPage: ${error instanceof Error ? error.message : error}`); } - this.updateButtonStates(); } + async searchById(): Promise { - console.log("Function #23 - Executing searchById"); - const filterInput = document.getElementById('filterInput') as HTMLInputElement; - const searchValue = parseInt(filterInput.value, 10); - this.stateManager.highlightedId = searchValue; - await this.stateManager.searchByIdStateChange(searchValue); - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records, searchValue); + try { + console.log("Function #23 - Executing searchById"); + + const filterInput = document.getElementById('filterInput') as HTMLInputElement; + if (!filterInput) { + throw new Error('Filter input element not found.'); + } + + const searchValue = parseInt(filterInput.value, 10); + if (isNaN(searchValue)) { + throw new Error('Invalid search value or none'); + } + + this.stateManager.highlightedId = searchValue; + await this.stateManager.searchByIdStateChange(searchValue); + + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records, searchValue); + } + + this.updateButtonStates(); + } catch (error) { + console.error(`Error in searchById function: ${error instanceof Error ? error.message : error}`); } - - this.updateButtonStates(); } + setupLiveValidation(): void { const filterInput = document.getElementById('filterInput') as HTMLInputElement; @@ -484,26 +573,33 @@ class PaginationManager { private updateButtonStates(): void { - console.log("Function #20 - Executing updateButtonstates"); - const prevButton = document.getElementById("prevPage") as HTMLButtonElement; - const nextButton = document.getElementById("nextPage") as HTMLButtonElement; - - const from = this.stateManager.getFrom(); // Use the getter to get the value of `from` - const to = this.stateManager.getTo(); // Use the getter to get the value of `to` - const totalRecordCount = this.stateManager.getTotalRecordCount(); // Use a getter to get the totalRecordCount - - if (prevButton !== null) { - prevButton.disabled = from === 0; - } - - if (nextButton !== null) { - nextButton.disabled = to === totalRecordCount - 1; + try { + console.log("Function #20 - Executing updateButtonstates"); + const prevButton = document.getElementById("prevPage") as HTMLButtonElement; + const nextButton = document.getElementById("nextPage") as HTMLButtonElement; + + const from = this.stateManager.getFrom(); + const to = this.stateManager.getTo(); + const totalRecordCount = this.stateManager.getTotalRecordCount(); + + if (prevButton !== null) { + prevButton.disabled = from === 0; + } + + if (nextButton !== null) { + nextButton.disabled = to === totalRecordCount - 1; + } + } catch (error) { + console.error(`Unexpected error in updateButtonStates: ${error instanceof Error ? error.message : error}`); } } + } + // ****************************************************** Main Script ********************************************************* / -// main script + + window.onload = async () => { console.log("Event #1 - Executing window.onload"); @@ -555,8 +651,6 @@ window.onload = async () => { - - From 7b635b8b9499185f624d0437d4ed4a8bd0c36102 Mon Sep 17 00:00:00 2001 From: riaan Date: Fri, 22 Sep 2023 13:38:07 +0200 Subject: [PATCH 22/27] Event listeners moved into Class Rev 1.16 --- app.ts | 709 ++++++++++--------------------------------------- index.html | 2 - stylesheet.css | 18 +- 3 files changed, 146 insertions(+), 583 deletions(-) diff --git a/app.ts b/app.ts index 3079d33d..f821b796 100644 --- a/app.ts +++ b/app.ts @@ -1,15 +1,17 @@ // ****************************************************** Data ********************************************************* / +type CityData = [number, string, number]; class ApiManager { totalRecordCount: number; columnNames: string[] | null; - + constructor() { this.totalRecordCount = 0; this.columnNames = null; } + async fetchTotalRecordCount(): Promise { console.log("Function #3 - Executing fetchTotalRecordCount"); try { @@ -24,6 +26,7 @@ class ApiManager { } } + async fetchColumnNames(): Promise { console.log("Function #5 - Executing fetchColumnNames"); try { @@ -38,25 +41,27 @@ class ApiManager { } } - async fetchRecords(from: number, to: number): Promise { + + async fetchRecords(from: number, to: number): Promise { console.log(`Function #12.1 - Executing fetchRecords with from: ${from}, to: ${to}`); try { const response = await fetch(`http://localhost:2050/records?from=${from}&to=${to}`); if (!response.ok) { throw new Error(`Failed to fetch records: ${response.statusText}`); } - const data: any[][] = await response.json(); + const data: CityData[] = await response.json(); return data; } catch (error) { console.error(`Error fetching records: ${error}`); return null; } } - } + // ****************************************************** Model ********************************************************* / + class StateManager { private rowHeight: number; private headerHeight: number; @@ -65,9 +70,10 @@ class StateManager { private from: number; private to: number; private apiManager: ApiManager; - private records: any[][] | null = null; + private records: CityData[] | null = null; private columnNames: string[] | null; private totalRecordCount = 0; + highlightedId: number | null = null; constructor(apiManager: ApiManager) { @@ -81,6 +87,8 @@ class StateManager { this.columnNames = null; this.totalRecordCount = 0; } + + async initializeState(): Promise { console.log("Function #1 - Executing initialize"); try { @@ -106,6 +114,7 @@ class StateManager { } } + async fetchAndStoreTotalRecordCount(): Promise { console.log("Function #2 - Executing fetchAndStoreTotalRecordCount"); try { @@ -116,18 +125,19 @@ class StateManager { } } - + getTotalRecordCount(): number { return this.totalRecordCount; } + getColumnNames(): string[] | null { console.log("Function #10 - Executing getColumnNames"); return this.columnNames; } - getRecords(): any[][] | null { + getRecords(): CityData[] | null { console.log("Function #13 - Executing getRecords"); return this.records; } @@ -138,21 +148,25 @@ class StateManager { return this.from; } + setFrom(value: number): void { console.log("Function #7 - Executing setFrom"); this.from = value; } + getTo(): number { console.log("Function #19 - Executing getTo"); return this.to; } + setTo(value: number): void { console.log("Function #8 - Executing setTo"); this.to = value; } + goToNextPage(): void { try { console.log("Function #17 - Executing goToNextPage"); @@ -177,7 +191,6 @@ class StateManager { } } - goToPreviousPage(): void { try { @@ -211,16 +224,15 @@ class StateManager { const newFrom = id; const newTo = id + this.numRows - 1; - // Check that 'to' does not exceed totalRecordCount + // Checking that 'to' does not exceed totalRecordCount if (newTo >= this.totalRecordCount) { this.setTo(this.totalRecordCount - 1); } else { this.setTo(newTo); } - this.setFrom(newFrom); - await this.retrieveRecords(); + } catch (error) { console.error(`Error in searchByIdStateChange: ${error instanceof Error ? error.message : error}`); } @@ -267,14 +279,11 @@ async retrieveRecords(): Promise { console.error(`Error retrieving records: ${error instanceof Error ? error.message : error}`); } } - } // ****************************************************** View ********************************************************* / -type apiRecord = any[]; - class TableRenderer { private stateManager: StateManager; @@ -328,9 +337,10 @@ class TableRenderer { } } } + + setColumnWidths(): void { console.log("Function #11.1 - Executing setColumnWidths"); - try { const table = document.getElementById("myTable"); @@ -340,7 +350,6 @@ class TableRenderer { const headerCells = table.querySelectorAll("th"); const numCols = headerCells.length; - const colWidth = 100 / numCols; headerCells.forEach((headerCell: Element) => { @@ -352,7 +361,7 @@ class TableRenderer { } - renderRecords(records: apiRecord[] | null, highlightId: number | null = null) { + renderRecords(records: CityData[] | null, highlightId: number | null = null) { console.log("Function #14 - Executing renderRecords"); highlightId = highlightId ?? this.stateManager.highlightedId; // use state if highlightId is null try { @@ -383,43 +392,9 @@ class TableRenderer { console.error(`An error occurred: ${error}`); } } - - - async adjustRows(): Promise { - console.log("Function #7 - Executing adjustRows"); - try { - // const rowHeight = 20; - // const headerHeight = 180; - // const availableHeight = window.innerHeight - headerHeight; - - // let numRows = Math.floor(availableHeight / rowHeight); - - // Use StateManager to get and set 'from' and 'to' - // this.stateManager.setFrom(0); - // this.stateManager.setTo(numRows - 1); - - // Check for a minimum number of rows - // if (numRows <= 0) { - // console.log("Window size too small, setting minimum number of rows to 1"); - // numRows = 1; - // } - - // Fetch the records using StateManager - - - // Get the records from StateManager - const records = this.stateManager.getRecords(); - - // Render the records if they're available - if (records !== null) { - this.renderRecords(records); - } - } catch (error) { - console.error(`An error occurred: ${error}`); - } - } } + // ****************************************************** Controllers ********************************************************* / @@ -427,30 +402,37 @@ class WindowResizeHandler { private debouncedUpdate: Function; constructor( - private tableRenderer: TableRenderer, - private stateManager: StateManager + private tableRenderer: TableRenderer, + private stateManager: StateManager ) { - this.debouncedUpdate = this.debounce(this.updateAfterResize.bind(this), 350); + this.debouncedUpdate = this.debounce(this.updateAfterResize.bind(this), 350); + + // Attach event listener here + this.setupEventListeners(); + } + + private setupEventListeners(): void { + window.addEventListener('resize', () => this.handleResize()); } handleResize() { - console.log("Function #15 - Executing handleResize"); - this.debouncedUpdate(); + console.log("Function #15 - Executing handleResize"); + this.debouncedUpdate(); } - + debounce(func: Function, delay: number): Function { - let timeout: ReturnType | null = null; - return (...args: any[]) => { - const later = () => { - timeout = null; - func(...args); - }; - if (timeout !== null) { - clearTimeout(timeout); - } - timeout = setTimeout(later, delay); - }; -} + let timeout: ReturnType | null = null; + return (...args: any[]) => { + const later = () => { + timeout = null; + func(...args); + }; + if (timeout !== null) { + clearTimeout(timeout); + } + timeout = setTimeout(later, delay); + }; + } async updateAfterResize() { try { @@ -469,14 +451,52 @@ class WindowResizeHandler { } - class PaginationManager { - + private prevButton: HTMLButtonElement; + private nextButton: HTMLButtonElement; + private searchButton: HTMLButtonElement; + private mainHeading: HTMLElement; + private filterInput: HTMLInputElement; + private errorMessage: HTMLElement; + constructor(private tableRenderer: TableRenderer, private stateManager: StateManager) { - this.tableRenderer = tableRenderer; - this.stateManager = stateManager + this.tableRenderer = tableRenderer; + this.stateManager = stateManager; + + this.prevButton = document.getElementById("prevPage") as HTMLButtonElement; + this.nextButton = document.getElementById("nextPage") as HTMLButtonElement; + this.searchButton = document.getElementById('searchButton') as HTMLButtonElement; + this.mainHeading = document.getElementById("main-heading") as HTMLElement; + this.filterInput = document.getElementById('filterInput') as HTMLInputElement; + this.errorMessage = document.getElementById('errorMessage') as HTMLElement; + + // Attach event listeners + this.setupEventListeners(); + } + + private setupEventListeners(): void { + if (this.prevButton) { + this.prevButton.addEventListener("click", () => this.decrementPage()); + } + + if (this.nextButton) { + this.nextButton.addEventListener("click", () => this.incrementPage()); + } + + if (this.searchButton) { + this.searchButton.addEventListener("click", () => this.searchById()); + } + + if (this.mainHeading) { + this.mainHeading.addEventListener("click", () => this.navigateToHome()); + } + + if (this.filterInput && this.errorMessage) { + this.setupLiveValidation(); + } } + navigateToHome(): void { console.log("Function #25 - Navigating to Home"); try { @@ -485,7 +505,7 @@ class PaginationManager { console.error(`Error while navigating to home: ${error instanceof Error ? error.message : error}`); alert("Failed to reload the page. Please try again."); } -} + } async incrementPage(): Promise { @@ -526,74 +546,59 @@ class PaginationManager { async searchById(): Promise { try { - console.log("Function #23 - Executing searchById"); - - const filterInput = document.getElementById('filterInput') as HTMLInputElement; - if (!filterInput) { - throw new Error('Filter input element not found.'); - } - - const searchValue = parseInt(filterInput.value, 10); - if (isNaN(searchValue)) { - throw new Error('Invalid search value or none'); - } - - this.stateManager.highlightedId = searchValue; - await this.stateManager.searchByIdStateChange(searchValue); - - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records, searchValue); - } - - this.updateButtonStates(); + console.log("Function #23 - Executing searchById"); + + const searchValue = parseInt(this.filterInput.value, 10); + if (isNaN(searchValue)) { + throw new Error('Invalid search value or none'); + } + + this.stateManager.highlightedId = searchValue; + await this.stateManager.searchByIdStateChange(searchValue); + + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records, searchValue); + } + + this.updateButtonStates(); } catch (error) { - console.error(`Error in searchById function: ${error instanceof Error ? error.message : error}`); + console.error(`Error in searchById function: ${error instanceof Error ? error.message : error}`); } - } - +} - setupLiveValidation(): void { - const filterInput = document.getElementById('filterInput') as HTMLInputElement; - const errorMessage = document.getElementById('errorMessage') as HTMLElement; - filterInput.addEventListener('input', () => { - const inputValue = filterInput.value; +setupLiveValidation(): void { + this.filterInput.addEventListener('input', () => { + const inputValue = this.filterInput.value; - if (inputValue.length === 0) { - errorMessage.textContent = ""; - } else if (inputValue.length < 1 || inputValue.length > 6 || !/^\d+$/.test(inputValue)) { - errorMessage.textContent = "Invalid input. Please enter a number between 0 and 999 999."; - } else { - errorMessage.textContent = ""; - } - }); - } + if (inputValue.length === 0) { + this.errorMessage.textContent = ""; + } else if (inputValue.length < 1 || inputValue.length > 6 || !/^\d+$/.test(inputValue)) { + this.errorMessage.textContent = "Invalid input. Please enter a number between 0 and 999 999."; + } else { + this.errorMessage.textContent = ""; + } + }); +} - private updateButtonStates(): void { - try { +private updateButtonStates(): void { + try { console.log("Function #20 - Executing updateButtonstates"); - const prevButton = document.getElementById("prevPage") as HTMLButtonElement; - const nextButton = document.getElementById("nextPage") as HTMLButtonElement; - + const from = this.stateManager.getFrom(); const to = this.stateManager.getTo(); const totalRecordCount = this.stateManager.getTotalRecordCount(); - - if (prevButton !== null) { - prevButton.disabled = from === 0; - } - - if (nextButton !== null) { - nextButton.disabled = to === totalRecordCount - 1; - } - } catch (error) { + + this.prevButton.disabled = from === 0; + this.nextButton.disabled = to === totalRecordCount - 1; + + } catch (error) { console.error(`Unexpected error in updateButtonStates: ${error instanceof Error ? error.message : error}`); - } } - +} } @@ -605,459 +610,19 @@ window.onload = async () => { // Initialize Data const apiManager = new ApiManager(); - // Initialize Model const stateManager = new StateManager(apiManager); - await stateManager.initializeState(); // Don't forget to await! - + await stateManager.initializeState(); // Initialize View const tableRenderer = new TableRenderer(stateManager); await tableRenderer.initialRender(stateManager); - // Initialize Controllers const windowResizeHandler = new WindowResizeHandler(tableRenderer, stateManager); - const paginationManager = new PaginationManager(tableRenderer, stateManager); + const paginationManager = new PaginationManager(tableRenderer, stateManager); - // Attach event listeners - paginationManager.setupLiveValidation(); - window.addEventListener('resize', () => windowResizeHandler.handleResize()); - document.getElementById("prevPage")?.addEventListener("click", () => { paginationManager.decrementPage();}) - document.getElementById("nextPage")?.addEventListener("click", () => { paginationManager.incrementPage();}) - document.getElementById('searchButton')?.addEventListener("click", () => { paginationManager.searchById();}) - document.getElementById("main-heading")?.addEventListener("click", () => { paginationManager.navigateToHome();}) }; - - - - - - - - - - - - - - - - - - - - - - - -// *** Development Setup ***// -// go run main.go -// npm run build -// npm run watch -// *** Development Setup ***// - - - - -// *** Global Variables ***// -// const ROW_HEIGHT = 21; -// let currentPage = 1; -// let recordsPerPage = 25; -// let totalRecords: number; -// let lastFilteredId: string | null = null; -// let cachedColumnNames: string[] | null = null; -// let totalPages: number; - - - - - -// // Initialize the page when the window loads -// window.onload = async () => { -// calculateRecordsPerPage(); -// await fetchTotalRecords(); -// generateInitialTable(); - - - - -// // Re-generate the table when the window is resized -// // Re-generate the table when the window is resized -// window.addEventListener("resize", debounce(async () => { -// // Find the first row and its ID. -// const firstRow = document.querySelector('#myTable tbody tr'); -// let firstRowId = 0; - -// if (firstRow && firstRow.id) { -// firstRowId = parseInt(firstRow.id.split('-')[1], 10); -// } - -// console.log("In debounce (before recalculating):"); -// console.log(`First row ID: ${firstRowId}`); -// console.log(`Current page: ${currentPage}`); - -// // Recalculate the number of records per page -// calculateRecordsPerPage(); - -// // Recalculate currentPage based on firstRowId -// currentPage = Math.floor(firstRowId / recordsPerPage) + 1; - -// console.log("In debounce (after recalculating):"); -// console.log(`First row ID should still be: ${firstRowId}`); -// console.log(`New current page: ${currentPage}`); - -// // Regenerate table -// if (lastFilteredId) { -// const id = parseInt(lastFilteredId, 10); -// filterRecordsById(id.toString()); -// } else { -// generateTable(currentPage, null); // Generate the table for the current page -// } -// }, 250)); - - - -// // Handle Previous button click -// document.getElementById("prevBtn")?.addEventListener("click", () => { -// const filterInput = document.getElementById("filterInput") as HTMLInputElement; -// if (!filterInput.value) { -// lastFilteredId = null; -// } -// currentPage--; -// generateTable(currentPage, lastFilteredId); - -// if (currentPage === 1) { -// document.getElementById("prevBtn")?.setAttribute("disabled", "true"); -// } else { -// document.getElementById("prevBtn")?.removeAttribute("disabled"); -// document.getElementById("nextBtn")?.removeAttribute("disabled"); -// } -// }); - -// // Handle Next button click -// document.getElementById("nextBtn")?.addEventListener("click", () => { -// const filterInput = document.getElementById("filterInput") as HTMLInputElement; -// if (!filterInput.value) { -// lastFilteredId = null; -// } -// currentPage++; -// generateTable(currentPage, lastFilteredId); - -// document.getElementById("prevBtn")?.removeAttribute("disabled"); -// if (currentPage * recordsPerPage >= totalRecords) { -// document.getElementById("nextBtn")?.setAttribute("disabled", "true"); -// } -// }); - - - - - -// // Filter functionality -// let errorTimeout: number | null = null; - -// const filterInput = document.getElementById("filterInput") as HTMLInputElement; -// const errorMessage = document.getElementById("errorMessage"); - -// if (filterInput && errorMessage) { -// filterInput.addEventListener("input", async function() { // Added async here to call await later -// const query = this.value.trim(); - -// // Clear any existing timeout and error message -// if (errorTimeout !== null) { -// clearTimeout(errorTimeout); -// } -// errorMessage.textContent = ""; - -// if (query === "") { -// // If input is empty, remove the highlight and revert the table -// lastFilteredId = null; -// currentPage = 1; // Resetting to the first page -// await generateTable(currentPage, null, undefined); // Use currentPage which is now 1 -// document.getElementById("prevBtn")?.setAttribute("disabled", "true"); -// return; -// } - -// const isValidNumber = /^[0-9]+$/.test(query) && parseInt(query, 10) <= 999999; - -// if (isValidNumber) { -// lastFilteredId = query; -// filterRecordsById(query); -// } else { -// // Set up the delayed message -// errorTimeout = setTimeout(() => { -// errorMessage.textContent = "Invalid input. Please enter a number between 0 and 999999."; -// }, 500); -// } -// }); -// } -// }; - - - - -// function generateInitialTable() { -// generateTable(currentPage, null); -// } - - - -// function removeRowsFromTable(rowsToRemove: number) { -// const table = document.getElementById('myTable'); -// if (table) { -// const tbody = table.querySelector('tbody'); -// if (tbody) { -// // Remove the last 'rowsToRemove' rows from the table -// for (let i = 0; i < rowsToRemove; i++) { -// if (tbody.lastElementChild) { -// tbody.removeChild(tbody.lastElementChild); -// } -// } -// } -// } -// } - -// // Debounce function -// function debounce(func: Function, wait: number) { -// let timeout: ReturnType; -// return function executedFunction(...args: any[]) { -// const later = () => { -// clearTimeout(timeout); -// func(...args); -// }; -// clearTimeout(timeout); -// timeout = setTimeout(later, wait); -// }; -// } - - - - -// // Calculate the number of records to display on each page based on the window height -// function calculateRecordsPerPage() { -// const headingHeight = document.getElementById('main-heading')?.offsetHeight || 0; -// const paginationHeight = document.getElementById('pagination')?.offsetHeight || 0; -// const availableHeight = window.innerHeight - headingHeight - paginationHeight - 10; -// recordsPerPage = Math.floor(availableHeight / ROW_HEIGHT); -// totalPages = Math.ceil(totalRecords / recordsPerPage); -// console.log("In calculateRecordsPerPage:"); -// console.log(`Records per page: ${recordsPerPage}`); -// } - - - - -// // Fetch columns and cache them if they are not already cached -// async function fetchColumnData() { -// if (cachedColumnNames !== null) { -// return cachedColumnNames; -// } -// const response = await fetch("http://localhost:2050/columns"); -// const columnNames = await response.json(); -// cachedColumnNames = columnNames; // Store in cache -// return columnNames; -// } - - - - -// // Generate the header of the table -// function generateTableHeader(columnNames: string[]) { -// const thead = document.createElement('thead'); -// const tr = document.createElement('tr'); -// columnNames.forEach((name) => { -// const th = document.createElement('th'); -// th.textContent = name; -// tr.appendChild(th); -// }); -// thead.appendChild(tr); -// return thead; -// } - - - - -// // Fetch a subset of row data from the server -// async function fetchRowData(from: number, to: number) { -// // Make sure 'to' doesn't exceed the maximum allowed record number -// to = Math.min(to, 999999); - -// // Make sure 'to' is not negative -// if (to < 0) { -// to = 0; -// } - -// // Make sure 'from' is not greater than 'to' -// if (from > to) { -// from = to; -// } - -// // Ensure 'from' is not negative -// if (from < 0) { -// from = 0; -// } - -// const response = await fetch(`http://localhost:2050/records?from=${from}&to=${to}`); - -// if (!response.ok) { -// console.error(`Fetch failed: ${response.status} ${response.statusText}`); -// return []; -// } - -// const records = await response.json(); -// return records; -// } - - - - -// // Generate the body of the table -// function generateTableRows(records: any[][], highlightId: string | null) { -// const tbody = document.createElement('tbody'); -// records.forEach((record, index) => { -// const tr = document.createElement('tr'); -// tr.id = `row-${record[0]}`; // Assuming the ID is the first cell in each record - -// // Highlight the row if it matches the filtered ID -// if (highlightId && highlightId === record[0].toString()) { -// tr.classList.add("highlighted-green"); -// } -// record.forEach((cell) => { -// const td = document.createElement('td'); -// td.textContent = cell; -// tr.appendChild(td); -// }); -// tbody.appendChild(tr); -// }); -// return tbody; -// } - - - - -// // Generate the complete table -// async function generateTable(page: number, highlightId: string | null, updateMode: boolean = false) { -// const columnNames = await fetchColumnData(); -// const from = (page - 1) * recordsPerPage; -// let to = Math.min(page * recordsPerPage, totalRecords) - 1; -// const records = await fetchRowData(from, to); - -// const thead = generateTableHeader(columnNames); -// const tbody = generateTableRows(records, highlightId); - -// // Clear existing data if any -// const table = document.getElementById('myTable'); -// if (table) { -// if (updateMode) { -// const existingTbody = table.querySelector('tbody'); -// if (existingTbody) { -// tbody.querySelectorAll('tr').forEach((row) => { -// existingTbody.appendChild(row); -// }); -// } -// } else { -// table.innerHTML = ""; -// table.appendChild(thead); -// table.appendChild(tbody); -// } -// } -// console.log("In generateTable:"); -// console.log(`Start index: ${from}`); -// console.log(`End index: ${to}`); -// // Set column widths -// setColumnWidths(); - -// // If there is a filtered ID, you could call some logic here -// if (lastFilteredId) { -// // centerHighlightedRow(); -// } - -// // Disable or Enable the Next button based on the last record -// if (to >= totalRecords - 1) { -// document.getElementById("nextBtn")?.setAttribute("disabled", "true"); -// } else { -// document.getElementById("nextBtn")?.removeAttribute("disabled"); -// } -// } - - -// function setColumnWidths(): void { -// // Assuming your table has an id of "myTable" -// const table = document.getElementById("myTable"); - -// if (table) { -// // Count the number of columns in your table -// const headerCells = table.querySelectorAll("th"); -// const numCols = headerCells.length; - -// // Calculate the width for each column -// const colWidth = 100 / numCols; - -// // Set the width -// headerCells.forEach((headerCell: Element) => { -// (headerCell as HTMLElement).style.width = `${colWidth}%`; -// }); -// } -// } - - - -// // Fetch the total number of records -// async function fetchTotalRecords() { -// const response = await fetch("http://localhost:2050/recordCount"); -// totalRecords = await response.json(); -// totalPages = Math.ceil(totalRecords / recordsPerPage); -// } - - - - -// // Filter records by ID and regenerate the table accordingly -// async function filterRecordsById(query: string) { -// lastFilteredId = query; -// if (!query) { -// // Revert to initial state if no query -// generateTable(1, null); // Start with the first page -// document.getElementById("prevBtn")?.setAttribute("disabled", "true"); // Disable the Previous button here -// return; -// } - -// let id = parseInt(query, 10); - -// // Calculate the current page based on the filtered ID -// currentPage = Math.ceil((id + 1) / recordsPerPage); - -// // Enable or Disable the Previous button based on the current page -// if (currentPage > 1) { -// document.getElementById("prevBtn")?.removeAttribute("disabled"); // Enable the Previous button here -// } else { -// document.getElementById("prevBtn")?.setAttribute("disabled", "true"); // Disable the Previous button here -// } - -// console.log(`Fetching records for page ${currentPage} with highlight on ${id}`); -// await generateTable(currentPage, id.toString()); -// } - - - - - -// // Center the row that is highlighted -// // function centerHighlightedRow() { -// // const highlightedRow = document.querySelector(".highlighted"); -// // const mainContainer = document.getElementById("main-container"); - -// // if (highlightedRow && mainContainer) { -// // const containerHeight = mainContainer.clientHeight; -// // const rowTop = highlightedRow.getBoundingClientRect().top; -// // const rowHeight = highlightedRow.clientHeight; -// // const scrollPosition = rowTop + mainContainer.scrollTop - (containerHeight / 2) + (rowHeight / 2); -// // mainContainer.scrollTop = scrollPosition; -// // } -// // } - - diff --git a/index.html b/index.html index 7e3de05b..7bdfeae6 100644 --- a/index.html +++ b/index.html @@ -9,7 +9,6 @@
-

Area 51's Grocery List

@@ -27,6 +26,5 @@

Area 51's Grocery List

- diff --git a/stylesheet.css b/stylesheet.css index 6ee469ef..484d1cd4 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,4 +1,3 @@ -/* Set the background color for the entire page */ @import url('https://fonts.googleapis.com/css2?family=Orbitron&display=swap'); #main-heading { @@ -25,36 +24,37 @@ html, body { overflow: hidden; } -/* Apply background color and text color to the table headers */ + th { font-family: 'Orbitron', sans-serif; text-align: center; font-size: 16px; border: 1px solid #a1e3a1; - background-color: #333333; /* Semicolon added */ + background-color: #333333; color: #4CAF50; } -/* Apply background color and text color to table data cells */ + td { font-family: 'Orbitron', sans-serif; font-size: 14px; border: 1px solid #a1e3a1; text-align: center; color: #333333; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; } -/* Style the table itself for gridlines */ + table { border-collapse: collapse; - + } #myTable { table-layout: fixed; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; + width: 100%; height: 100%; border: 1px solid #a1e3a1; From e9e98533805a4f3a0ce2f8d2142fae2b08b923d3 Mon Sep 17 00:00:00 2001 From: riaan Date: Tue, 26 Sep 2023 16:46:52 +0200 Subject: [PATCH 23/27] Comments and bug fix Rev 1.17 --- app.ts | 641 ++------------------------------------------- controllers.js | 281 ++++++++++++++++++++ controllers.js.map | 1 + controllers.ts | 226 ++++++++++++++++ data.js | 136 ++++++++++ data.js.map | 1 + data.ts | 57 ++++ index.html | 5 +- model.js | 315 ++++++++++++++++++++++ model.js.map | 1 + model.ts | 241 +++++++++++++++++ views.js | 159 +++++++++++ views.js.map | 1 + views.ts | 123 +++++++++ 14 files changed, 1575 insertions(+), 613 deletions(-) create mode 100644 controllers.js create mode 100644 controllers.js.map create mode 100644 controllers.ts create mode 100644 data.js create mode 100644 data.js.map create mode 100644 data.ts create mode 100644 model.js create mode 100644 model.js.map create mode 100644 model.ts create mode 100644 views.js create mode 100644 views.js.map create mode 100644 views.ts diff --git a/app.ts b/app.ts index f821b796..a71f113a 100644 --- a/app.ts +++ b/app.ts @@ -1,628 +1,45 @@ -// ****************************************************** Data ********************************************************* / - -type CityData = [number, string, number]; - -class ApiManager { - totalRecordCount: number; - columnNames: string[] | null; - - constructor() { - this.totalRecordCount = 0; - this.columnNames = null; - } - - - async fetchTotalRecordCount(): Promise { - console.log("Function #3 - Executing fetchTotalRecordCount"); - try { - const response = await fetch('http://localhost:2050/recordCount'); - if (!response.ok) { - throw new Error(`Failed to fetch total record count: ${response.statusText}`); - } - const data: number = await response.json(); - this.totalRecordCount = data; - } catch (error) { - console.error(`Error fetching total record count: ${error}`); - } - } - - - async fetchColumnNames(): Promise { - console.log("Function #5 - Executing fetchColumnNames"); - try { - const response = await fetch('http://localhost:2050/columns'); - if (!response.ok) { - throw new Error(`Failed to fetch column names: ${response.statusText}`); - } - const data: string[] = await response.json(); - this.columnNames = data; - } catch (error) { - console.error(`Error fetching column names: ${error}`); - } - } - - - async fetchRecords(from: number, to: number): Promise { - console.log(`Function #12.1 - Executing fetchRecords with from: ${from}, to: ${to}`); - try { - const response = await fetch(`http://localhost:2050/records?from=${from}&to=${to}`); - if (!response.ok) { - throw new Error(`Failed to fetch records: ${response.statusText}`); - } - const data: CityData[] = await response.json(); - return data; - } catch (error) { - console.error(`Error fetching records: ${error}`); - return null; - } - } -} - - -// ****************************************************** Model ********************************************************* / - - -class StateManager { - private rowHeight: number; - private headerHeight: number; - private availableHeight: number; - private numRows: number; - private from: number; - private to: number; - private apiManager: ApiManager; - private records: CityData[] | null = null; - private columnNames: string[] | null; - private totalRecordCount = 0; - - highlightedId: number | null = null; - - constructor(apiManager: ApiManager) { - this.rowHeight = 20; - this.headerHeight = 180; - this.availableHeight = 0; - this.numRows = 0; - this.apiManager = apiManager; - this.from = 0; - this.to = 0; - this.columnNames = null; - this.totalRecordCount = 0; - } - - - async initializeState(): Promise { - console.log("Function #1 - Executing initialize"); - try { - await this.fetchAndStoreTotalRecordCount(); - await this.retrieveColumnNames(); - this.adjustWindowSize(); - } catch (error) { - console.error("Error in initializeState:", error); - } - } - - - async retrieveColumnNames(): Promise { - console.log("Function #4 - Executing retrieveColumnNames"); - try { - await this.apiManager.fetchColumnNames(); - - if (this.apiManager.columnNames !== null) { - this.columnNames = this.apiManager.columnNames; - } - } catch (error) { - console.error("Error in retrieveColumnNames:", error); - } -} - - - async fetchAndStoreTotalRecordCount(): Promise { - console.log("Function #2 - Executing fetchAndStoreTotalRecordCount"); - try { - await this.apiManager.fetchTotalRecordCount(); - this.totalRecordCount = this.apiManager.totalRecordCount; - } catch (error) { - console.error("Error in fetchAndStoreTotalRecordCount:", error); - } - } - - - getTotalRecordCount(): number { - return this.totalRecordCount; - } - - - getColumnNames(): string[] | null { - console.log("Function #10 - Executing getColumnNames"); - return this.columnNames; - } - - - getRecords(): CityData[] | null { - console.log("Function #13 - Executing getRecords"); - return this.records; - } - - - getFrom(): number { - console.log("Function #18 - Executing getFrom"); - return this.from; - } - - - setFrom(value: number): void { - console.log("Function #7 - Executing setFrom"); - this.from = value; - } - - - getTo(): number { - console.log("Function #19 - Executing getTo"); - return this.to; - } - - - setTo(value: number): void { - console.log("Function #8 - Executing setTo"); - this.to = value; - } - - - goToNextPage(): void { - try { - console.log("Function #17 - Executing goToNextPage"); - const from = this.getFrom(); - const to = this.getTo(); - const stepSize = to - from + 1; - - // Calculate the new 'from' and 'to' values - const newFrom = from + stepSize; - const newTo = to + stepSize; - - // Check that 'to' does not exceed totalRecordCount - if (newTo >= this.totalRecordCount) { - this.setTo(this.totalRecordCount - 1); - this.setFrom(newFrom); - } else { - this.setFrom(newFrom); - this.setTo(newTo); - } - } catch (error) { - console.error(`Unexpected error in goToNextPage: ${error instanceof Error ? error.message : error}`); - } - } - - - goToPreviousPage(): void { - try { - console.log("Function #22 - Executing goToPreviousPage"); - const from = this.getFrom(); - const to = this.getTo(); - const recordsPerPage = this.numRows; - - // Calculate the new 'from' and 'to' values - const newFrom = from - recordsPerPage; - const newTo = newFrom + recordsPerPage - 1; - - if (newFrom < 0) { - // Set the 'from' value to zero - this.setFrom(0); - this.setTo(recordsPerPage - 1); - } else { - this.setFrom(newFrom); - this.setTo(newTo); - } - } catch (error) { - console.error(`Error in goToPreviousPage: ${error instanceof Error ? error.message : error}`); - } - } - - - async searchByIdStateChange(id: number): Promise { - try { - console.log("Function #24 - Executing searchByIdStateChange"); - - const newFrom = id; - const newTo = id + this.numRows - 1; - - // Checking that 'to' does not exceed totalRecordCount - if (newTo >= this.totalRecordCount) { - this.setTo(this.totalRecordCount - 1); - } else { - this.setTo(newTo); - } - this.setFrom(newFrom); - await this.retrieveRecords(); - - } catch (error) { - console.error(`Error in searchByIdStateChange: ${error instanceof Error ? error.message : error}`); - } -} - - - adjustWindowSize(): void { - console.log("Function #6 - Executing adjustWindowSize"); - - try { - if (typeof window === "undefined" || !window.innerHeight) { - throw new Error("Unable to access window dimensions"); - } - - if (!this.rowHeight) { - throw new Error("Row height is not properly configured"); - } - - this.availableHeight = window.innerHeight - this.headerHeight; - this.numRows = Math.floor(this.availableHeight / this.rowHeight); - - if (this.numRows <= 0) { - console.log("Window size too small, setting minimum number of rows to 1"); - this.numRows = 1; - } - - if (this.from === 0) { - this.setFrom(0); // Assuming the first row is always 0 - this.setTo(this.numRows - 1); - } else { - this.setTo(this.from + this.numRows - 1); - } - } catch (error) { - console.error(`Error in adjustWindowSize: ${error instanceof Error ? error.message : error}`); - } -} - - -async retrieveRecords(): Promise { - console.log("Function #12 - Executing retrieveRecords"); - try { - this.records = await this.apiManager.fetchRecords(this.from, this.to); - } catch (error) { - console.error(`Error retrieving records: ${error instanceof Error ? error.message : error}`); - } -} -} - -// ****************************************************** View ********************************************************* / - - -class TableRenderer { - private stateManager: StateManager; - - constructor(stateManager: StateManager) { - this.stateManager = stateManager; - } - - async initialRender(stateManager: StateManager): Promise { - try { - console.log("Function #9 - Executing initialRender"); - - const columnNames = stateManager.getColumnNames(); - if (columnNames !== null) { - this.renderColumnNames(columnNames); - } - - await stateManager.retrieveRecords(); - const records = stateManager.getRecords(); - - if (records !== null) { - this.renderRecords(records); - } - } catch (error) { - console.error(`Error during initialRender: ${error}`); - } -} - - - renderColumnNames(columnNames: string[]): void { - console.log("Function #11 - Executing renderColumnNames"); - try { - const thead = document.querySelector('thead'); - if (thead === null) { - throw new Error('Table header not found.'); - } - - const row = document.createElement('tr'); - for (const columnName of columnNames) { - const cell = document.createElement('th'); - cell.textContent = columnName; - row.appendChild(cell); - } - thead.appendChild(row); - - this.setColumnWidths(); - } catch (error) { - if (error instanceof Error) { - console.error(`An error occurred: ${error.message}`); - } else { - console.error(`An unknown error occurred: ${error}`); - } - } - } - - - setColumnWidths(): void { - console.log("Function #11.1 - Executing setColumnWidths"); - try { - const table = document.getElementById("myTable"); - - if (!table) { - throw new Error('Table with id "myTable" not found.'); - } - - const headerCells = table.querySelectorAll("th"); - const numCols = headerCells.length; - const colWidth = 100 / numCols; - - headerCells.forEach((headerCell: Element) => { - (headerCell as HTMLElement).style.width = `${colWidth}%`; - }); - } catch (error) { - console.error(`Error setting column widths: ${error}`); - } -} - - - renderRecords(records: CityData[] | null, highlightId: number | null = null) { - console.log("Function #14 - Executing renderRecords"); - highlightId = highlightId ?? this.stateManager.highlightedId; // use state if highlightId is null - try { - if (records === null) { - throw new Error("No records to render."); - } - - const tbody = document.querySelector('tbody'); - if (tbody === null) { - throw new Error('Table body not found.'); - } - - tbody.innerHTML = ''; - - records.forEach((record) => { - const row = document.createElement('tr'); - if (highlightId !== null && record.length > 0 && parseInt(record[0].toString(), 10) === highlightId) { - row.classList.add('highlight'); - } - record.forEach((cell) => { - const td = document.createElement('td'); - td.textContent = cell.toString(); - row.appendChild(td); - }); - tbody.appendChild(row); - }); - } catch (error) { - console.error(`An error occurred: ${error}`); - } - } -} - - -// ****************************************************** Controllers ********************************************************* / - - -class WindowResizeHandler { - private debouncedUpdate: Function; - - constructor( - private tableRenderer: TableRenderer, - private stateManager: StateManager - ) { - this.debouncedUpdate = this.debounce(this.updateAfterResize.bind(this), 350); - - // Attach event listener here - this.setupEventListeners(); - } - - private setupEventListeners(): void { - window.addEventListener('resize', () => this.handleResize()); - } - - handleResize() { - console.log("Function #15 - Executing handleResize"); - this.debouncedUpdate(); - } - - debounce(func: Function, delay: number): Function { - let timeout: ReturnType | null = null; - return (...args: any[]) => { - const later = () => { - timeout = null; - func(...args); - }; - if (timeout !== null) { - clearTimeout(timeout); - } - timeout = setTimeout(later, delay); - }; - } - - async updateAfterResize() { - try { - console.log("Update after resize"); - this.stateManager.adjustWindowSize(); - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records); - } - } catch (error) { - console.error(`Error in updateAfterResize: ${error instanceof Error ? error.message : error}`); - } - } -} - - -class PaginationManager { - private prevButton: HTMLButtonElement; - private nextButton: HTMLButtonElement; - private searchButton: HTMLButtonElement; - private mainHeading: HTMLElement; - private filterInput: HTMLInputElement; - private errorMessage: HTMLElement; - - constructor(private tableRenderer: TableRenderer, private stateManager: StateManager) { - this.tableRenderer = tableRenderer; - this.stateManager = stateManager; - - this.prevButton = document.getElementById("prevPage") as HTMLButtonElement; - this.nextButton = document.getElementById("nextPage") as HTMLButtonElement; - this.searchButton = document.getElementById('searchButton') as HTMLButtonElement; - this.mainHeading = document.getElementById("main-heading") as HTMLElement; - this.filterInput = document.getElementById('filterInput') as HTMLInputElement; - this.errorMessage = document.getElementById('errorMessage') as HTMLElement; - - // Attach event listeners - this.setupEventListeners(); - } - - private setupEventListeners(): void { - if (this.prevButton) { - this.prevButton.addEventListener("click", () => this.decrementPage()); - } - - if (this.nextButton) { - this.nextButton.addEventListener("click", () => this.incrementPage()); - } - - if (this.searchButton) { - this.searchButton.addEventListener("click", () => this.searchById()); - } - - if (this.mainHeading) { - this.mainHeading.addEventListener("click", () => this.navigateToHome()); - } - - if (this.filterInput && this.errorMessage) { - this.setupLiveValidation(); - } - } - - - navigateToHome(): void { - console.log("Function #25 - Navigating to Home"); - try { - window.location.reload(); - } catch (error) { - console.error(`Error while navigating to home: ${error instanceof Error ? error.message : error}`); - alert("Failed to reload the page. Please try again."); - } - } - - - async incrementPage(): Promise { - try { - console.log("Function #16 - Executing incrementPage"); - this.stateManager.goToNextPage(); - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records); - } - this.updateButtonStates(); - } catch (error) { - console.error(`Unexpected error in incrementPage: ${error instanceof Error ? error.message : error}`); - } - } - - - async decrementPage(): Promise { - try { - console.log("Function #21 - Executing decrementPage"); - - this.stateManager.goToPreviousPage(); - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records); - } - - this.updateButtonStates(); - } catch (error) { - console.error(`Error in decrementPage: ${error instanceof Error ? error.message : error}`); - } - } - - - async searchById(): Promise { - try { - console.log("Function #23 - Executing searchById"); - - const searchValue = parseInt(this.filterInput.value, 10); - if (isNaN(searchValue)) { - throw new Error('Invalid search value or none'); - } - - this.stateManager.highlightedId = searchValue; - await this.stateManager.searchByIdStateChange(searchValue); - - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records, searchValue); - } - - this.updateButtonStates(); - } catch (error) { - console.error(`Error in searchById function: ${error instanceof Error ? error.message : error}`); - } -} - - -setupLiveValidation(): void { - this.filterInput.addEventListener('input', () => { - const inputValue = this.filterInput.value; - - if (inputValue.length === 0) { - this.errorMessage.textContent = ""; - } else if (inputValue.length < 1 || inputValue.length > 6 || !/^\d+$/.test(inputValue)) { - this.errorMessage.textContent = "Invalid input. Please enter a number between 0 and 999 999."; - } else { - this.errorMessage.textContent = ""; - } - }); -} - - -private updateButtonStates(): void { - try { - console.log("Function #20 - Executing updateButtonstates"); - - const from = this.stateManager.getFrom(); - const to = this.stateManager.getTo(); - const totalRecordCount = this.stateManager.getTotalRecordCount(); - - this.prevButton.disabled = from === 0; - this.nextButton.disabled = to === totalRecordCount - 1; - - } catch (error) { - console.error(`Unexpected error in updateButtonStates: ${error instanceof Error ? error.message : error}`); - } -} -} - - -// ****************************************************** Main Script ********************************************************* / - +/** + * Project Overview - MVC Architecture: + * + * This project adheres to the Data-> Model-View-Controller (MVC) design pattern, ensuring a clear separation of concerns: + * + 1. **Data Source**: + * - The foundational source from which the application retrieves its raw data. This is + * API endpoints. + * + * 2. **Model** (`StateManager`): + * - Manages the state and data of the application. + * - Interfaces with the data source to handle data retrieval, filtering, pagination, and other data-related operations. + * + * 3. **View** (`TableRenderer`): + * - Responsible for rendering and updating the user interface. + * - Renders column headers, records, and manages the visual representation. + * + * 4. **Controllers**: + * - **WindowResizeHandler**: Detects window resize events and updates the table view accordingly. + * - **PaginationManager**: Manages page navigation, searching functionalities, and live input validation. + * + */ + +/*** Main Script ***/ window.onload = async () => { console.log("Event #1 - Executing window.onload"); - // Initialize Data + // Initialize data.ts const apiManager = new ApiManager(); - // Initialize Model + // Initialize model.ts const stateManager = new StateManager(apiManager); await stateManager.initializeState(); - // Initialize View + // Initialize views.ts const tableRenderer = new TableRenderer(stateManager); await tableRenderer.initialRender(stateManager); - // Initialize Controllers - const windowResizeHandler = new WindowResizeHandler(tableRenderer, stateManager); + // Initialize controllers.ts const paginationManager = new PaginationManager(tableRenderer, stateManager); - + const windowResizeHandler = new WindowResizeHandler(tableRenderer, stateManager, paginationManager); }; diff --git a/controllers.js b/controllers.js new file mode 100644 index 00000000..4e771131 --- /dev/null +++ b/controllers.js @@ -0,0 +1,281 @@ +"use strict"; +//*** Controllers ***/ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +// Handles window resize events to update the view of the application. +var WindowResizeHandler = /** @class */ (function () { + /** + * @param {TableRenderer} tableRenderer - Used for re-rendering table data. + * @param {StateManager} stateManager - State control for retrieving/updating application data. + */ + function WindowResizeHandler(tableRenderer, stateManager, paginationManager) { + this.tableRenderer = tableRenderer; + this.stateManager = stateManager; + this.debouncedUpdate = this.debounce(this.updateAfterResize.bind(this), 350); + this.paginationManager = paginationManager; + // Attach event listener for window resize. + this.setupEventListeners(); + } + WindowResizeHandler.prototype.setupEventListeners = function () { + var _this = this; + window.addEventListener('resize', function () { return _this.handleResize(); }); + }; + WindowResizeHandler.prototype.handleResize = function () { + console.log("Function #15 - Executing handleResize"); + this.debouncedUpdate(); + }; + /** + * Debounce function to reduce the number of function calls while user is dragging the browser window. + * It delays the processing of the event until the user has stopped resizing the window for a determined amount of time. + */ + WindowResizeHandler.prototype.debounce = function (func, delay) { + var timeout = null; + return function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var later = function () { + timeout = null; + func.apply(void 0, args); + }; + if (timeout !== null) { + clearTimeout(timeout); + } + timeout = setTimeout(later, delay); + }; + }; + WindowResizeHandler.prototype.updateAfterResize = function () { + return __awaiter(this, void 0, void 0, function () { + var records, error_1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + _a.trys.push([0, 2, , 3]); + console.log("Update after resize"); + this.stateManager.adjustWindowSize(); + return [4 /*yield*/, this.stateManager.retrieveRecords()]; + case 1: + _a.sent(); + records = this.stateManager.getRecords(); + if (records !== null) { + this.tableRenderer.renderRecords(records); + } + this.paginationManager.updateButtonStates(); + return [3 /*break*/, 3]; + case 2: + error_1 = _a.sent(); + console.error("Error in updateAfterResize: " + (error_1 instanceof Error ? error_1.message : error_1)); + return [3 /*break*/, 3]; + case 3: return [2 /*return*/]; + } + }); + }); + }; + return WindowResizeHandler; +}()); +// Handles pagination and search functionalities for the application's table view. +var PaginationManager = /** @class */ (function () { + /** + * @param {TableRenderer} tableRenderer - Used for re-rendering table data. + * @param {StateManager} stateManager - State control for retrieving/updating application data. + */ + function PaginationManager(tableRenderer, stateManager) { + this.tableRenderer = tableRenderer; + this.stateManager = stateManager; + this.tableRenderer = tableRenderer; + this.stateManager = stateManager; + this.prevButton = document.getElementById("prevPage"); + this.nextButton = document.getElementById("nextPage"); + this.searchButton = document.getElementById('searchButton'); + this.mainHeading = document.getElementById("main-heading"); + this.filterInput = document.getElementById('filterInput'); + this.errorMessage = document.getElementById('errorMessage'); + // Attach event listeners for buttons and other UI elements. + this.setupEventListeners(); + } + // Attaches event listeners to the relevant DOM elements to handle user interactions. + PaginationManager.prototype.setupEventListeners = function () { + var _this = this; + if (this.prevButton) { + this.prevButton.addEventListener("click", function () { return _this.decrementPage(); }); + } + if (this.nextButton) { + this.nextButton.addEventListener("click", function () { return _this.incrementPage(); }); + } + if (this.searchButton) { + this.searchButton.addEventListener("click", function () { return _this.searchById(); }); + } + if (this.mainHeading) { + this.mainHeading.addEventListener("click", function () { return _this.navigateToHome(); }); + } + if (this.filterInput && this.errorMessage) { + this.setupLiveValidation(); + } + }; + // Navigates to the home page by reloading the window. + PaginationManager.prototype.navigateToHome = function () { + console.log("Function #25 - Navigating to Home"); + try { + window.location.reload(); + } + catch (error) { + console.error("Error while navigating to home: " + (error instanceof Error ? error.message : error)); + alert("Failed to reload the page. Please try again."); + } + }; + // Fetches the next set of records and updates the view. + PaginationManager.prototype.incrementPage = function () { + return __awaiter(this, void 0, void 0, function () { + var records, error_2; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + _a.trys.push([0, 2, , 3]); + console.log("Function #16 - Executing incrementPage"); + this.stateManager.goToNextPage(); + return [4 /*yield*/, this.stateManager.retrieveRecords()]; + case 1: + _a.sent(); + records = this.stateManager.getRecords(); + if (records !== null) { + this.tableRenderer.renderRecords(records); + } + this.updateButtonStates(); + return [3 /*break*/, 3]; + case 2: + error_2 = _a.sent(); + console.error("Unexpected error in incrementPage: " + (error_2 instanceof Error ? error_2.message : error_2)); + return [3 /*break*/, 3]; + case 3: return [2 /*return*/]; + } + }); + }); + }; + // Fetches the previous set of records and updates the view. + PaginationManager.prototype.decrementPage = function () { + return __awaiter(this, void 0, void 0, function () { + var records, error_3; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + _a.trys.push([0, 2, , 3]); + console.log("Function #21 - Executing decrementPage"); + this.stateManager.goToPreviousPage(); + return [4 /*yield*/, this.stateManager.retrieveRecords()]; + case 1: + _a.sent(); + records = this.stateManager.getRecords(); + if (records !== null) { + this.tableRenderer.renderRecords(records); + } + this.updateButtonStates(); + return [3 /*break*/, 3]; + case 2: + error_3 = _a.sent(); + console.error("Error in decrementPage: " + (error_3 instanceof Error ? error_3.message : error_3)); + return [3 /*break*/, 3]; + case 3: return [2 /*return*/]; + } + }); + }); + }; + // Searches for a record by its ID and updates the view. + PaginationManager.prototype.searchById = function () { + return __awaiter(this, void 0, void 0, function () { + var searchValue, records, error_4; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + _a.trys.push([0, 2, , 3]); + console.log("Function #23 - Executing searchById"); + searchValue = parseInt(this.filterInput.value, 10); + if (isNaN(searchValue)) { + throw new Error('Invalid search value or none'); + } + this.stateManager.setHighlightedId(searchValue); + return [4 /*yield*/, this.stateManager.searchByIdStateChange(searchValue)]; + case 1: + _a.sent(); + records = this.stateManager.getRecords(); + if (records !== null) { + this.tableRenderer.renderRecords(records, searchValue); + } + this.updateButtonStates(); + return [3 /*break*/, 3]; + case 2: + error_4 = _a.sent(); + console.error("Error in searchById function: " + (error_4 instanceof Error ? error_4.message : error_4)); + return [3 /*break*/, 3]; + case 3: return [2 /*return*/]; + } + }); + }); + }; + // Validates input for the search bar in real-time. + PaginationManager.prototype.setupLiveValidation = function () { + var _this = this; + this.filterInput.addEventListener('input', function () { + var inputValue = _this.filterInput.value; + if (inputValue.length === 0) { + _this.errorMessage.textContent = ""; + } + else if (inputValue.length < 1 || inputValue.length > 6 || !/^\d+$/.test(inputValue)) { + _this.errorMessage.textContent = "Invalid input. Please enter a number between 0 and 999 999."; + } + else { + _this.errorMessage.textContent = ""; + } + }); + }; + // Updates the state of the pagination buttons based on the current view. + PaginationManager.prototype.updateButtonStates = function () { + try { + console.log("Function #20 - Executing updateButtonstates"); + var from = this.stateManager.getFrom(); + var to = this.stateManager.getTo(); + var totalRecordCount = this.stateManager.getTotalRecordCount(); + this.prevButton.disabled = from === 0; + this.nextButton.disabled = to === totalRecordCount - 1; + } + catch (error) { + console.error("Unexpected error in updateButtonStates: " + (error instanceof Error ? error.message : error)); + } + }; + return PaginationManager; +}()); +//# sourceMappingURL=controllers.js.map \ No newline at end of file diff --git a/controllers.js.map b/controllers.js.map new file mode 100644 index 00000000..8726513e --- /dev/null +++ b/controllers.js.map @@ -0,0 +1 @@ +{"version":3,"file":"controllers.js","sourceRoot":"","sources":["controllers.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/controllers.ts b/controllers.ts new file mode 100644 index 00000000..462421e9 --- /dev/null +++ b/controllers.ts @@ -0,0 +1,226 @@ +//*** Controllers ***/ + +// Handles window resize events to update the view of the application. +class WindowResizeHandler { + private debouncedUpdate: Function; + private paginationManager: PaginationManager; + + + /** + * @param {TableRenderer} tableRenderer - Used for re-rendering table data. + * @param {StateManager} stateManager - State control for retrieving/updating application data. + */ + constructor( + private tableRenderer: TableRenderer, + private stateManager: StateManager, + paginationManager: PaginationManager + ) { + this.debouncedUpdate = this.debounce(this.updateAfterResize.bind(this), 350); + this.paginationManager = paginationManager; + + // Attach event listener for window resize. + this.setupEventListeners(); + } + + private setupEventListeners(): void { + window.addEventListener('resize', () => this.handleResize()); + } + + handleResize() { + console.log("Function #15 - Executing handleResize"); + this.debouncedUpdate(); + } + + /** + * Debounce function to reduce the number of function calls while user is dragging the browser window. + * It delays the processing of the event until the user has stopped resizing the window for a determined amount of time. + */ + debounce(func: Function, delay: number): Function { + let timeout: ReturnType | null = null; + return (...args: any[]) => { + const later = () => { + timeout = null; + func(...args); + }; + if (timeout !== null) { + clearTimeout(timeout); + } + timeout = setTimeout(later, delay); + }; + } + + async updateAfterResize() { + try { + console.log("Update after resize"); + this.stateManager.adjustWindowSize(); + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); + } + this.paginationManager.updateButtonStates(); + + } catch (error) { + console.error(`Error in updateAfterResize: ${error instanceof Error ? error.message : error}`); + } + } + } + + // Handles pagination and search functionalities for the application's table view. + class PaginationManager { + // DOM elements required for pagination and search. + private prevButton: HTMLButtonElement; + private nextButton: HTMLButtonElement; + private searchButton: HTMLButtonElement; + private mainHeading: HTMLElement; + private filterInput: HTMLInputElement; + private errorMessage: HTMLElement; + + + /** + * @param {TableRenderer} tableRenderer - Used for re-rendering table data. + * @param {StateManager} stateManager - State control for retrieving/updating application data. + */ + constructor(private tableRenderer: TableRenderer, private stateManager: StateManager) { + this.tableRenderer = tableRenderer; + this.stateManager = stateManager; + + this.prevButton = document.getElementById("prevPage") as HTMLButtonElement; + this.nextButton = document.getElementById("nextPage") as HTMLButtonElement; + this.searchButton = document.getElementById('searchButton') as HTMLButtonElement; + this.mainHeading = document.getElementById("main-heading") as HTMLElement; + this.filterInput = document.getElementById('filterInput') as HTMLInputElement; + this.errorMessage = document.getElementById('errorMessage') as HTMLElement; + + // Attach event listeners for buttons and other UI elements. + this.setupEventListeners(); + } + + // Attaches event listeners to the relevant DOM elements to handle user interactions. + private setupEventListeners(): void { + if (this.prevButton) { + this.prevButton.addEventListener("click", () => this.decrementPage()); + } + + if (this.nextButton) { + this.nextButton.addEventListener("click", () => this.incrementPage()); + } + + if (this.searchButton) { + this.searchButton.addEventListener("click", () => this.searchById()); + } + + if (this.mainHeading) { + this.mainHeading.addEventListener("click", () => this.navigateToHome()); + } + + if (this.filterInput && this.errorMessage) { + this.setupLiveValidation(); + } + } + + // Navigates to the home page by reloading the window. + navigateToHome(): void { + console.log("Function #25 - Navigating to Home"); + try { + window.location.reload(); + } catch (error) { + console.error(`Error while navigating to home: ${error instanceof Error ? error.message : error}`); + alert("Failed to reload the page. Please try again."); + } + } + + // Fetches the next set of records and updates the view. + async incrementPage(): Promise { + try { + console.log("Function #16 - Executing incrementPage"); + this.stateManager.goToNextPage(); + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); + } + this.updateButtonStates(); + } catch (error) { + console.error(`Unexpected error in incrementPage: ${error instanceof Error ? error.message : error}`); + } + } + + // Fetches the previous set of records and updates the view. + async decrementPage(): Promise { + try { + console.log("Function #21 - Executing decrementPage"); + + this.stateManager.goToPreviousPage(); + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); + } + + this.updateButtonStates(); + } catch (error) { + console.error(`Error in decrementPage: ${error instanceof Error ? error.message : error}`); + } + } + + // Searches for a record by its ID and updates the view. + async searchById(): Promise { + try { + console.log("Function #23 - Executing searchById"); + + const searchValue = parseInt(this.filterInput.value, 10); + if (isNaN(searchValue)) { + throw new Error('Invalid search value or none'); + } + + this.stateManager.setHighlightedId(searchValue); + await this.stateManager.searchByIdStateChange(searchValue); + + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records, searchValue); + } + + this.updateButtonStates(); + } catch (error) { + console.error(`Error in searchById function: ${error instanceof Error ? error.message : error}`); + } + } + + // Validates input for the search bar in real-time. + setupLiveValidation(): void { + this.filterInput.addEventListener('input', () => { + const inputValue = this.filterInput.value; + + if (inputValue.length === 0) { + this.errorMessage.textContent = ""; + } else if (inputValue.length < 1 || inputValue.length > 6 || !/^\d+$/.test(inputValue)) { + this.errorMessage.textContent = "Invalid input. Please enter a number between 0 and 999 999."; + } else { + this.errorMessage.textContent = ""; + } + }); + } + + // Updates the state of the pagination buttons based on the current view. + public updateButtonStates(): void { + try { + console.log("Function #20 - Executing updateButtonstates"); + + const from = this.stateManager.getFrom(); + const to = this.stateManager.getTo(); + const totalRecordCount = this.stateManager.getTotalRecordCount(); + + this.prevButton.disabled = from === 0; + this.nextButton.disabled = to === totalRecordCount - 1; + + } catch (error) { + console.error(`Unexpected error in updateButtonStates: ${error instanceof Error ? error.message : error}`); + } + } + } \ No newline at end of file diff --git a/data.js b/data.js new file mode 100644 index 00000000..d5990e7e --- /dev/null +++ b/data.js @@ -0,0 +1,136 @@ +"use strict"; +//*** Data ***/ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +// Manages API requests for fetching record count, column names, and data records. +var ApiManager = /** @class */ (function () { + function ApiManager() { + this.totalRecordCount = 0; + this.columnNames = null; + } + ApiManager.prototype.fetchTotalRecordCount = function () { + return __awaiter(this, void 0, void 0, function () { + var response, data, error_1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + console.log("Function #3 - Executing fetchTotalRecordCount"); + _a.label = 1; + case 1: + _a.trys.push([1, 4, , 5]); + return [4 /*yield*/, fetch('http://localhost:2050/recordCount')]; + case 2: + response = _a.sent(); + if (!response.ok) { + throw new Error("Failed to fetch total record count: " + response.statusText); + } + return [4 /*yield*/, response.json()]; + case 3: + data = _a.sent(); + this.totalRecordCount = data; + return [3 /*break*/, 5]; + case 4: + error_1 = _a.sent(); + console.error("Error fetching total record count: " + error_1); + return [3 /*break*/, 5]; + case 5: return [2 /*return*/]; + } + }); + }); + }; + ApiManager.prototype.fetchColumnNames = function () { + return __awaiter(this, void 0, void 0, function () { + var response, data, error_2; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + console.log("Function #5 - Executing fetchColumnNames"); + _a.label = 1; + case 1: + _a.trys.push([1, 4, , 5]); + return [4 /*yield*/, fetch('http://localhost:2050/columns')]; + case 2: + response = _a.sent(); + if (!response.ok) { + throw new Error("Failed to fetch column names: " + response.statusText); + } + return [4 /*yield*/, response.json()]; + case 3: + data = _a.sent(); + this.columnNames = data; + return [3 /*break*/, 5]; + case 4: + error_2 = _a.sent(); + console.error("Error fetching column names: " + error_2); + return [3 /*break*/, 5]; + case 5: return [2 /*return*/]; + } + }); + }); + }; + ApiManager.prototype.fetchRecords = function (from, to) { + return __awaiter(this, void 0, void 0, function () { + var response, data, error_3; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + console.log("Function #12.1 - Executing fetchRecords with from: " + from + ", to: " + to); + _a.label = 1; + case 1: + _a.trys.push([1, 4, , 5]); + return [4 /*yield*/, fetch("http://localhost:2050/records?from=" + from + "&to=" + to)]; + case 2: + response = _a.sent(); + if (!response.ok) { + throw new Error("Failed to fetch records: " + response.statusText); + } + return [4 /*yield*/, response.json()]; + case 3: + data = _a.sent(); + return [2 /*return*/, data]; + case 4: + error_3 = _a.sent(); + console.error("Error fetching records: " + error_3); + return [2 /*return*/, null]; + case 5: return [2 /*return*/]; + } + }); + }); + }; + return ApiManager; +}()); +//# sourceMappingURL=data.js.map \ No newline at end of file diff --git a/data.js.map b/data.js.map new file mode 100644 index 00000000..4341e37d --- /dev/null +++ b/data.js.map @@ -0,0 +1 @@ +{"version":3,"file":"data.js","sourceRoot":"","sources":["data.ts"],"names":[],"mappings":";AAAA,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIf,kFAAkF;AAClF;IAIE;QACE,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAEK,0CAAqB,GAA3B;;;;;;wBACE,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;;;;wBAE1C,qBAAM,KAAK,CAAC,mCAAmC,CAAC,EAAA;;wBAA3D,QAAQ,GAAG,SAAgD;wBACjE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BAChB,MAAM,IAAI,KAAK,CAAC,yCAAuC,QAAQ,CAAC,UAAY,CAAC,CAAC;yBAC/E;wBACoB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAApC,IAAI,GAAW,SAAqB;wBAC1C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;;;;wBAE7B,OAAO,CAAC,KAAK,CAAC,wCAAsC,OAAO,CAAC,CAAC;;;;;;KAEhE;IAEK,qCAAgB,GAAtB;;;;;;wBACE,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;;;;wBAErC,qBAAM,KAAK,CAAC,+BAA+B,CAAC,EAAA;;wBAAvD,QAAQ,GAAG,SAA4C;wBAC7D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BAChB,MAAM,IAAI,KAAK,CAAC,mCAAiC,QAAQ,CAAC,UAAY,CAAC,CAAC;yBACzE;wBACsB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAtC,IAAI,GAAa,SAAqB;wBAC5C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;;;;wBAExB,OAAO,CAAC,KAAK,CAAC,kCAAgC,OAAO,CAAC,CAAC;;;;;;KAE1D;IAEK,iCAAY,GAAlB,UAAmB,IAAY,EAAE,EAAU;;;;;;wBACzC,OAAO,CAAC,GAAG,CAAC,wDAAsD,IAAI,cAAS,EAAI,CAAC,CAAC;;;;wBAElE,qBAAM,KAAK,CAAC,wCAAsC,IAAI,YAAO,EAAI,CAAC,EAAA;;wBAA7E,QAAQ,GAAG,SAAkE;wBACnF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BAChB,MAAM,IAAI,KAAK,CAAC,8BAA4B,QAAQ,CAAC,UAAY,CAAC,CAAC;yBACpE;wBACwB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAxC,IAAI,GAAe,SAAqB;wBAC9C,sBAAO,IAAI,EAAC;;;wBAEZ,OAAO,CAAC,KAAK,CAAC,6BAA2B,OAAO,CAAC,CAAC;wBAClD,sBAAO,IAAI,EAAC;;;;;KAEf;IACH,iBAAC;AAAD,CAAC,AAnDD,IAmDC"} \ No newline at end of file diff --git a/data.ts b/data.ts new file mode 100644 index 00000000..2c6eeede --- /dev/null +++ b/data.ts @@ -0,0 +1,57 @@ +//*** Data ***/ + +type CityData = [number, string, number]; + +// Manages API requests for fetching record count, column names, and data records. +class ApiManager { + totalRecordCount: number; + columnNames: string[] | null; + + constructor() { + this.totalRecordCount = 0; + this.columnNames = null; + } + + async fetchTotalRecordCount(): Promise { + console.log("Function #3 - Executing fetchTotalRecordCount"); + try { + const response = await fetch('http://localhost:2050/recordCount'); + if (!response.ok) { + throw new Error(`Failed to fetch total record count: ${response.statusText}`); + } + const data: number = await response.json(); + this.totalRecordCount = data; + } catch (error) { + console.error(`Error fetching total record count: ${error}`); + } + } + + async fetchColumnNames(): Promise { + console.log("Function #5 - Executing fetchColumnNames"); + try { + const response = await fetch('http://localhost:2050/columns'); + if (!response.ok) { + throw new Error(`Failed to fetch column names: ${response.statusText}`); + } + const data: string[] = await response.json(); + this.columnNames = data; + } catch (error) { + console.error(`Error fetching column names: ${error}`); + } + } + + async fetchRecords(from: number, to: number): Promise { + console.log(`Function #12.1 - Executing fetchRecords with from: ${from}, to: ${to}`); + try { + const response = await fetch(`http://localhost:2050/records?from=${from}&to=${to}`); + if (!response.ok) { + throw new Error(`Failed to fetch records: ${response.statusText}`); + } + const data: CityData[] = await response.json(); + return data; + } catch (error) { + console.error(`Error fetching records: ${error}`); + return null; + } + } +} \ No newline at end of file diff --git a/index.html b/index.html index 7bdfeae6..58451d3b 100644 --- a/index.html +++ b/index.html @@ -3,10 +3,13 @@ Riaan JS Onboard Project + + + + -
diff --git a/model.js b/model.js new file mode 100644 index 00000000..fcc592c9 --- /dev/null +++ b/model.js @@ -0,0 +1,315 @@ +"use strict"; +//*** Model ***/ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +// Manages the application's state for data display, navigation, and search functionalities. +var StateManager = /** @class */ (function () { + function StateManager(apiManager) { + this.highlightedId = null; + this.records = null; + this.totalRecordCount = 0; + this.rowHeight = 20; + this.headerHeight = 180; + this.availableHeight = 0; + this.numRows = 0; + this.apiManager = apiManager; + this.from = 0; + this.to = 0; + this.columnNames = null; + this.totalRecordCount = 0; + } + StateManager.prototype.getHighlightedId = function () { + return this.highlightedId; + }; + StateManager.prototype.setHighlightedId = function (value) { + this.highlightedId = value; + }; + // Sets up initial state, fetches record count and column names, and adjusts the display window size. + StateManager.prototype.initializeState = function () { + return __awaiter(this, void 0, void 0, function () { + var error_1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + console.log("Function #1 - Executing initialize"); + _a.label = 1; + case 1: + _a.trys.push([1, 4, , 5]); + return [4 /*yield*/, this.fetchAndStoreTotalRecordCount()]; + case 2: + _a.sent(); + return [4 /*yield*/, this.retrieveColumnNames()]; + case 3: + _a.sent(); + this.adjustWindowSize(); + return [3 /*break*/, 5]; + case 4: + error_1 = _a.sent(); + console.error("Error in initializeState:", error_1); + return [3 /*break*/, 5]; + case 5: return [2 /*return*/]; + } + }); + }); + }; + StateManager.prototype.retrieveColumnNames = function () { + return __awaiter(this, void 0, void 0, function () { + var error_2; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + console.log("Function #4 - Executing retrieveColumnNames"); + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 4]); + return [4 /*yield*/, this.apiManager.fetchColumnNames()]; + case 2: + _a.sent(); + if (this.apiManager.columnNames !== null) { + this.columnNames = this.apiManager.columnNames; + } + return [3 /*break*/, 4]; + case 3: + error_2 = _a.sent(); + console.error("Error in retrieveColumnNames:", error_2); + return [3 /*break*/, 4]; + case 4: return [2 /*return*/]; + } + }); + }); + }; + StateManager.prototype.fetchAndStoreTotalRecordCount = function () { + return __awaiter(this, void 0, void 0, function () { + var error_3; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + console.log("Function #2 - Executing fetchAndStoreTotalRecordCount"); + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 4]); + return [4 /*yield*/, this.apiManager.fetchTotalRecordCount()]; + case 2: + _a.sent(); + this.totalRecordCount = this.apiManager.totalRecordCount; + return [3 /*break*/, 4]; + case 3: + error_3 = _a.sent(); + console.error("Error in fetchAndStoreTotalRecordCount:", error_3); + return [3 /*break*/, 4]; + case 4: return [2 /*return*/]; + } + }); + }); + }; + StateManager.prototype.getTotalRecordCount = function () { + return this.totalRecordCount; + }; + StateManager.prototype.getColumnNames = function () { + console.log("Function #10 - Executing getColumnNames"); + return this.columnNames; + }; + StateManager.prototype.getRecords = function () { + console.log("Function #13 - Executing getRecords"); + return this.records; + }; + StateManager.prototype.getFrom = function () { + console.log("Function #18 - Executing getFrom"); + return this.from; + }; + StateManager.prototype.setFrom = function (value) { + console.log("Function #7 - Executing setFrom"); + this.from = value; + }; + StateManager.prototype.getTo = function () { + console.log("Function #19 - Executing getTo"); + return this.to; + }; + StateManager.prototype.setTo = function (value) { + console.log("Function #8 - Executing setTo"); + this.to = value; + }; + StateManager.prototype.goToNextPage = function () { + try { + console.log("Function #17 - Executing goToNextPage"); + var from = this.getFrom(); + var to = this.getTo(); + var recordsPerPage = this.numRows; + var newFrom = from + recordsPerPage; + var newTo = newFrom + recordsPerPage - 1; + // Check that 'to' does not exceed totalRecordCount + if (newTo >= this.totalRecordCount) { + this.setTo(this.totalRecordCount - 1); + this.setFrom(this.totalRecordCount - recordsPerPage); + } + else { + this.setFrom(newFrom); + this.setTo(newTo); + } + } + catch (error) { + console.error("Unexpected error in goToNextPage: " + (error instanceof Error ? error.message : error)); + } + }; + StateManager.prototype.goToPreviousPage = function () { + try { + console.log("Function #22 - Executing goToPreviousPage"); + var from = this.getFrom(); + var to = this.getTo(); + var recordsPerPage = this.numRows; + // Calculate the new 'from' and 'to' values + var newFrom = from - recordsPerPage; + var newTo = newFrom + recordsPerPage - 1; + if (newFrom < 0) { + this.setFrom(0); + this.setTo(recordsPerPage - 1); + } + else { + this.setFrom(newFrom); + this.setTo(newTo); + } + } + catch (error) { + console.error("Error in goToPreviousPage: " + (error instanceof Error ? error.message : error)); + } + }; + StateManager.prototype.searchByIdStateChange = function (id) { + return __awaiter(this, void 0, void 0, function () { + var newFrom, newTo, recordsPerPage, error_4; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + _a.trys.push([0, 2, , 3]); + console.log("Function #24 - Executing searchByIdStateChange"); + newFrom = id; + newTo = id + this.numRows - 1; + recordsPerPage = this.numRows; + // Checking that 'to' does not exceed totalRecordCount + if (newTo >= this.totalRecordCount) { + this.setTo(this.totalRecordCount - 1); + this.setFrom(this.totalRecordCount - recordsPerPage); + } + else { + this.setTo(newTo); + this.setFrom(newFrom); + } + return [4 /*yield*/, this.retrieveRecords()]; + case 1: + _a.sent(); + return [3 /*break*/, 3]; + case 2: + error_4 = _a.sent(); + console.error("Error in searchByIdStateChange: " + (error_4 instanceof Error ? error_4.message : error_4)); + return [3 /*break*/, 3]; + case 3: return [2 /*return*/]; + } + }); + }); + }; + // Adjusts the available height based on window size and recalculates the number of rows. + StateManager.prototype.adjustWindowSize = function () { + console.log("Function #6 - Executing adjustWindowSize"); + try { + if (typeof window === "undefined" || !window.innerHeight) { + throw new Error("Unable to access window dimensions"); + } + if (!this.rowHeight) { + throw new Error("Row height is not properly configured"); + } + this.availableHeight = window.innerHeight - this.headerHeight; + this.numRows = Math.floor(this.availableHeight / this.rowHeight); + if (this.numRows <= 0) { + console.log("Window size too small, setting minimum number of rows to 1"); + this.numRows = 1; + } + // Calculating new values without modifying the state immediately. + var newFrom = this.from; + var newTo = this.from + this.numRows - 1; + // If it's the first set of records, start from 0. + if (this.from === 0) { + newFrom = 0; + newTo = this.numRows - 1; + } + // Ensure `newTo` doesn't exceed totalRecordCount and adjust `newFrom` accordingly. + if (newTo >= this.totalRecordCount) { + newTo = this.totalRecordCount - 1; + newFrom = newTo - this.numRows + 1; + } + // Check if the highlighted ID is currently between from and to. + var highlightedId = this.getHighlightedId(); // Assuming you have a method to get the highlighted ID. + if (highlightedId !== null && highlightedId >= this.from && highlightedId <= this.to) { + // If newTo would be smaller than highlightedId, adjust to keep highlightedId in view. + if (newTo < highlightedId) { + newTo = highlightedId; + newFrom = newTo - this.numRows + 1; + } + } + // Now, after all conditions have been checked, set the state. + this.setFrom(newFrom); + this.setTo(newTo); + } + catch (error) { + console.error("Error in adjustWindowSize: " + (error instanceof Error ? error.message : error)); + } + }; + StateManager.prototype.retrieveRecords = function () { + return __awaiter(this, void 0, void 0, function () { + var _a, error_5; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + console.log("Function #12 - Executing retrieveRecords"); + _b.label = 1; + case 1: + _b.trys.push([1, 3, , 4]); + _a = this; + return [4 /*yield*/, this.apiManager.fetchRecords(this.from, this.to)]; + case 2: + _a.records = _b.sent(); + return [3 /*break*/, 4]; + case 3: + error_5 = _b.sent(); + console.error("Error retrieving records: " + (error_5 instanceof Error ? error_5.message : error_5)); + return [3 /*break*/, 4]; + case 4: return [2 /*return*/]; + } + }); + }); + }; + return StateManager; +}()); +//# sourceMappingURL=model.js.map \ No newline at end of file diff --git a/model.js.map b/model.js.map new file mode 100644 index 00000000..9358331d --- /dev/null +++ b/model.js.map @@ -0,0 +1 @@ +{"version":3,"file":"model.js","sourceRoot":"","sources":["model.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/model.ts b/model.ts new file mode 100644 index 00000000..255a2603 --- /dev/null +++ b/model.ts @@ -0,0 +1,241 @@ +//*** Model ***/ + +// Manages the application's state for data display, navigation, and search functionalities. +class StateManager { + + private highlightedId: number | null = null; + private rowHeight: number; + private headerHeight: number; + private availableHeight: number; + private numRows: number; + private from: number; + private to: number; + private apiManager: ApiManager; + private records: CityData[] | null = null; + private columnNames: string[] | null; + private totalRecordCount = 0; + + constructor(apiManager: ApiManager) { + this.rowHeight = 20; + this.headerHeight = 180; + this.availableHeight = 0; + this.numRows = 0; + this.apiManager = apiManager; + this.from = 0; + this.to = 0; + this.columnNames = null; + this.totalRecordCount = 0; + } + + public getHighlightedId(): number | null { + return this.highlightedId; + } + + public setHighlightedId(value: number | null): void { + this.highlightedId = value; + } + + // Sets up initial state, fetches record count and column names, and adjusts the display window size. + async initializeState(): Promise { + console.log("Function #1 - Executing initialize"); + try { + await this.fetchAndStoreTotalRecordCount(); + await this.retrieveColumnNames(); + this.adjustWindowSize(); + } catch (error) { + console.error("Error in initializeState:", error); + } + } + + async retrieveColumnNames(): Promise { + console.log("Function #4 - Executing retrieveColumnNames"); + try { + await this.apiManager.fetchColumnNames(); + + if (this.apiManager.columnNames !== null) { + this.columnNames = this.apiManager.columnNames; + } + } catch (error) { + console.error("Error in retrieveColumnNames:", error); + } + } + + async fetchAndStoreTotalRecordCount(): Promise { + console.log("Function #2 - Executing fetchAndStoreTotalRecordCount"); + try { + await this.apiManager.fetchTotalRecordCount(); + this.totalRecordCount = this.apiManager.totalRecordCount; + } catch (error) { + console.error("Error in fetchAndStoreTotalRecordCount:", error); + } + } + + getTotalRecordCount(): number { + return this.totalRecordCount; + } + + getColumnNames(): string[] | null { + console.log("Function #10 - Executing getColumnNames"); + return this.columnNames; + } + + getRecords(): CityData[] | null { + console.log("Function #13 - Executing getRecords"); + return this.records; + } + + getFrom(): number { + console.log("Function #18 - Executing getFrom"); + return this.from; + } + + setFrom(value: number): void { + console.log("Function #7 - Executing setFrom"); + this.from = value; + } + + getTo(): number { + console.log("Function #19 - Executing getTo"); + return this.to; + } + + setTo(value: number): void { + console.log("Function #8 - Executing setTo"); + this.to = value; + } + + goToNextPage(): void { + try { + console.log("Function #17 - Executing goToNextPage"); + const from = this.getFrom(); + const to = this.getTo(); + const recordsPerPage = this.numRows; + + const newFrom = from + recordsPerPage; + const newTo = newFrom + recordsPerPage - 1; + + // Check that 'to' does not exceed totalRecordCount + if (newTo >= this.totalRecordCount) { + this.setTo(this.totalRecordCount - 1); + this.setFrom(this.totalRecordCount - recordsPerPage); + } else { + this.setFrom(newFrom); + this.setTo(newTo); + } + } catch (error) { + console.error(`Unexpected error in goToNextPage: ${error instanceof Error ? error.message : error}`); + } + } + + goToPreviousPage(): void { + try { + console.log("Function #22 - Executing goToPreviousPage"); + const from = this.getFrom(); + const to = this.getTo(); + const recordsPerPage = this.numRows; + + // Calculate the new 'from' and 'to' values + const newFrom = from - recordsPerPage; + const newTo = newFrom + recordsPerPage - 1; + + if (newFrom < 0) { + this.setFrom(0); + this.setTo(recordsPerPage - 1); + } else { + this.setFrom(newFrom); + this.setTo(newTo); + } + } catch (error) { + console.error(`Error in goToPreviousPage: ${error instanceof Error ? error.message : error}`); + } + } + + async searchByIdStateChange(id: number): Promise { + try { + console.log("Function #24 - Executing searchByIdStateChange"); + + const newFrom = id; + const newTo = id + this.numRows - 1; + const recordsPerPage = this.numRows; + + // Checking that 'to' does not exceed totalRecordCount + if (newTo >= this.totalRecordCount) { + this.setTo(this.totalRecordCount - 1); + this.setFrom(this.totalRecordCount - recordsPerPage); + } else { + this.setTo(newTo); + this.setFrom(newFrom); + } + + await this.retrieveRecords(); + + } catch (error) { + console.error(`Error in searchByIdStateChange: ${error instanceof Error ? error.message : error}`); + } + } + // Adjusts the available height based on window size and recalculates the number of rows. + adjustWindowSize(): void { + console.log("Function #6 - Executing adjustWindowSize"); + + try { + if (typeof window === "undefined" || !window.innerHeight) { + throw new Error("Unable to access window dimensions"); + } + + if (!this.rowHeight) { + throw new Error("Row height is not properly configured"); + } + + this.availableHeight = window.innerHeight - this.headerHeight; + this.numRows = Math.floor(this.availableHeight / this.rowHeight); + + if (this.numRows <= 0) { + console.log("Window size too small, setting minimum number of rows to 1"); + this.numRows = 1; + } + + // Calculating new values without modifying the state immediately. + let newFrom = this.from; + let newTo = this.from + this.numRows - 1; + + // If it's the first set of records, start from 0. + if (this.from === 0) { + newFrom = 0; + newTo = this.numRows - 1; + } + + // Ensure `newTo` doesn't exceed totalRecordCount and adjust `newFrom` accordingly. + if (newTo >= this.totalRecordCount) { + newTo = this.totalRecordCount - 1; + newFrom = newTo - this.numRows + 1; + } + + // Check if the highlighted ID is currently between from and to. + const highlightedId = this.getHighlightedId(); // Assuming you have a method to get the highlighted ID. + if (highlightedId !== null && highlightedId >= this.from && highlightedId <= this.to) { + // If newTo would be smaller than highlightedId, adjust to keep highlightedId in view. + if (newTo < highlightedId) { + newTo = highlightedId; + newFrom = newTo - this.numRows + 1; + } + } + + // Now, after all conditions have been checked, set the state. + this.setFrom(newFrom); + this.setTo(newTo); + + } catch (error) { + console.error(`Error in adjustWindowSize: ${error instanceof Error ? error.message : error}`); + } + } + + + async retrieveRecords(): Promise { + console.log("Function #12 - Executing retrieveRecords"); + try { + this.records = await this.apiManager.fetchRecords(this.from, this.to); + } catch (error) { + console.error(`Error retrieving records: ${error instanceof Error ? error.message : error}`); + } + } + } \ No newline at end of file diff --git a/views.js b/views.js new file mode 100644 index 00000000..28b7b277 --- /dev/null +++ b/views.js @@ -0,0 +1,159 @@ +"use strict"; +//*** Views ***/ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +/** + * TableRenderer is responsible for rendering data into an HTML table. + * It fetches data from the StateManager and populates the table accordingly. + */ +var TableRenderer = /** @class */ (function () { + function TableRenderer(stateManager) { + this.stateManager = stateManager; + } + /** + * Renders the initial table layout including column names and initial data set. + * @param {StateManager} stateManager - The manager to fetch state from. + */ + TableRenderer.prototype.initialRender = function (stateManager) { + return __awaiter(this, void 0, void 0, function () { + var columnNames, records, error_1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + _a.trys.push([0, 2, , 3]); + console.log("Function #9 - Executing initialRender"); + columnNames = stateManager.getColumnNames(); + if (columnNames !== null) { + this.renderColumnNames(columnNames); + } + return [4 /*yield*/, stateManager.retrieveRecords()]; + case 1: + _a.sent(); + records = stateManager.getRecords(); + if (records !== null) { + this.renderRecords(records); + } + return [3 /*break*/, 3]; + case 2: + error_1 = _a.sent(); + console.error("Error during initialRender: " + error_1); + return [3 /*break*/, 3]; + case 3: return [2 /*return*/]; + } + }); + }); + }; + TableRenderer.prototype.renderColumnNames = function (columnNames) { + console.log("Function #11 - Executing renderColumnNames"); + try { + var thead = document.querySelector('thead'); + if (thead === null) { + throw new Error('Table header not found.'); + } + var row = document.createElement('tr'); + for (var _i = 0, columnNames_1 = columnNames; _i < columnNames_1.length; _i++) { + var columnName = columnNames_1[_i]; + var cell = document.createElement('th'); + cell.textContent = columnName; + row.appendChild(cell); + } + thead.appendChild(row); + this.setColumnWidths(); + } + catch (error) { + if (error instanceof Error) { + console.error("An error occurred: " + error.message); + } + else { + console.error("An unknown error occurred: " + error); + } + } + }; + // Sets the widths of table columns evenly. + TableRenderer.prototype.setColumnWidths = function () { + console.log("Function #11.1 - Executing setColumnWidths"); + try { + var table = document.getElementById("myTable"); + if (!table) { + throw new Error('Table with id "myTable" not found.'); + } + var headerCells = table.querySelectorAll("th"); + var numCols = headerCells.length; + var colWidth_1 = 100 / numCols; + headerCells.forEach(function (headerCell) { + headerCell.style.width = colWidth_1 + "%"; + }); + } + catch (error) { + console.error("Error setting column widths: " + error); + } + }; + //Populates the table body with records. Optionally highlights a specified row if searched. + TableRenderer.prototype.renderRecords = function (records, highlightId) { + if (highlightId === void 0) { highlightId = null; } + console.log("Function #14 - Executing renderRecords"); + // Use the state's highlightedId if no highlightId is provided. + highlightId = highlightId !== null && highlightId !== void 0 ? highlightId : this.stateManager.getHighlightedId(); + try { + if (records === null) { + throw new Error("No records to render."); + } + var tbody_1 = document.querySelector('tbody'); + if (tbody_1 === null) { + throw new Error('Table body not found.'); + } + tbody_1.innerHTML = ''; + records.forEach(function (record) { + var row = document.createElement('tr'); + if (highlightId !== null && record.length > 0 && parseInt(record[0].toString(), 10) === highlightId) { + row.classList.add('highlight'); + } + record.forEach(function (cell) { + var td = document.createElement('td'); + td.textContent = cell.toString(); + row.appendChild(td); + }); + tbody_1.appendChild(row); + }); + } + catch (error) { + console.error("An error occurred: " + error); + } + }; + return TableRenderer; +}()); +//# sourceMappingURL=views.js.map \ No newline at end of file diff --git a/views.js.map b/views.js.map new file mode 100644 index 00000000..322e969a --- /dev/null +++ b/views.js.map @@ -0,0 +1 @@ +{"version":3,"file":"views.js","sourceRoot":"","sources":["views.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/views.ts b/views.ts new file mode 100644 index 00000000..7895a923 --- /dev/null +++ b/views.ts @@ -0,0 +1,123 @@ +//*** Views ***/ + +/** + * TableRenderer is responsible for rendering data into an HTML table. + * It fetches data from the StateManager and populates the table accordingly. + */ + +class TableRenderer { + private stateManager: StateManager; + + constructor(stateManager: StateManager) { + this.stateManager = stateManager; + } + + /** + * Renders the initial table layout including column names and initial data set. + * @param {StateManager} stateManager - The manager to fetch state from. + */ + async initialRender(stateManager: StateManager): Promise { + try { + console.log("Function #9 - Executing initialRender"); + + const columnNames = stateManager.getColumnNames(); + if (columnNames !== null) { + this.renderColumnNames(columnNames); + } + + await stateManager.retrieveRecords(); + const records = stateManager.getRecords(); + + if (records !== null) { + this.renderRecords(records); + } + } catch (error) { + console.error(`Error during initialRender: ${error}`); + } + } + + renderColumnNames(columnNames: string[]): void { + console.log("Function #11 - Executing renderColumnNames"); + try { + const thead = document.querySelector('thead'); + if (thead === null) { + throw new Error('Table header not found.'); + } + + const row = document.createElement('tr'); + for (const columnName of columnNames) { + const cell = document.createElement('th'); + cell.textContent = columnName; + row.appendChild(cell); + } + thead.appendChild(row); + + this.setColumnWidths(); + } catch (error) { + if (error instanceof Error) { + console.error(`An error occurred: ${error.message}`); + } else { + console.error(`An unknown error occurred: ${error}`); + } + } + } + + // Sets the widths of table columns evenly. + setColumnWidths(): void { + console.log("Function #11.1 - Executing setColumnWidths"); + try { + const table = document.getElementById("myTable"); + + if (!table) { + throw new Error('Table with id "myTable" not found.'); + } + + const headerCells = table.querySelectorAll("th"); + const numCols = headerCells.length; + const colWidth = 100 / numCols; + + headerCells.forEach((headerCell: Element) => { + (headerCell as HTMLElement).style.width = `${colWidth}%`; + }); + } catch (error) { + console.error(`Error setting column widths: ${error}`); + } + } + + + //Populates the table body with records. Optionally highlights a specified row if searched. + renderRecords(records: CityData[] | null, highlightId: number | null = null) { + console.log("Function #14 - Executing renderRecords"); + + // Use the state's highlightedId if no highlightId is provided. + highlightId = highlightId ?? this.stateManager.getHighlightedId(); + try { + if (records === null) { + throw new Error("No records to render."); + } + + const tbody = document.querySelector('tbody'); + if (tbody === null) { + throw new Error('Table body not found.'); + } + + tbody.innerHTML = ''; + + records.forEach((record) => { + const row = document.createElement('tr'); + if (highlightId !== null && record.length > 0 && parseInt(record[0].toString(), 10) === highlightId) { + row.classList.add('highlight'); + } + record.forEach((cell) => { + const td = document.createElement('td'); + td.textContent = cell.toString(); + row.appendChild(td); + }); + tbody.appendChild(row); + }); + } catch (error) { + console.error(`An error occurred: ${error}`); + } + } + } + \ No newline at end of file From 58836c3957bc691eb3c6b09887d36c7986dac6c9 Mon Sep 17 00:00:00 2001 From: riaan Date: Wed, 27 Sep 2023 15:57:37 +0200 Subject: [PATCH 24/27] Code Cleanup Rev 1.18 --- app.ts | 22 +-- controllers.js | 53 +++--- controllers.js.map | 2 +- controllers.ts | 435 +++++++++++++++++++++++-------------------- data.js | 47 ++--- data.js.map | 2 +- data.ts | 23 +-- index.html | 62 ++++--- model.js | 105 +++++------ model.js.map | 2 +- model.ts | 449 +++++++++++++++++++++++---------------------- stylesheet.css | 64 +++---- views.js | 36 ++-- views.js.map | 2 +- views.ts | 200 ++++++++++---------- 15 files changed, 772 insertions(+), 732 deletions(-) diff --git a/app.ts b/app.ts index a71f113a..62284d53 100644 --- a/app.ts +++ b/app.ts @@ -24,22 +24,22 @@ /*** Main Script ***/ window.onload = async () => { - console.log("Event #1 - Executing window.onload"); - // Initialize data.ts - const apiManager = new ApiManager(); + const apiManager = new ApiManager(); // Initialize model.ts - const stateManager = new StateManager(apiManager); - await stateManager.initializeState(); + const stateManager = new StateManager(apiManager); + await stateManager.initializeState(); // Initialize views.ts - const tableRenderer = new TableRenderer(stateManager); - await tableRenderer.initialRender(stateManager); + const tableRenderer = new TableRenderer(stateManager); + await tableRenderer.initialRender(); // Initialize controllers.ts - const paginationManager = new PaginationManager(tableRenderer, stateManager); - const windowResizeHandler = new WindowResizeHandler(tableRenderer, stateManager, paginationManager); + const paginationManager = new PaginationManager(tableRenderer, stateManager); + const windowResizeHandler = new WindowResizeHandler( + tableRenderer, + stateManager, + paginationManager + ); }; - - diff --git a/controllers.js b/controllers.js index 4e771131..f8d3acfe 100644 --- a/controllers.js +++ b/controllers.js @@ -43,25 +43,21 @@ var WindowResizeHandler = /** @class */ (function () { * @param {StateManager} stateManager - State control for retrieving/updating application data. */ function WindowResizeHandler(tableRenderer, stateManager, paginationManager) { - this.tableRenderer = tableRenderer; - this.stateManager = stateManager; this.debouncedUpdate = this.debounce(this.updateAfterResize.bind(this), 350); this.paginationManager = paginationManager; + this.tableRenderer = tableRenderer; + this.stateManager = stateManager; // Attach event listener for window resize. - this.setupEventListeners(); + this.setupEventListenersResize(); } - WindowResizeHandler.prototype.setupEventListeners = function () { + WindowResizeHandler.prototype.setupEventListenersResize = function () { var _this = this; - window.addEventListener('resize', function () { return _this.handleResize(); }); + window.addEventListener("resize", function () { return _this.handleResize(); }); }; WindowResizeHandler.prototype.handleResize = function () { - console.log("Function #15 - Executing handleResize"); this.debouncedUpdate(); }; - /** - * Debounce function to reduce the number of function calls while user is dragging the browser window. - * It delays the processing of the event until the user has stopped resizing the window for a determined amount of time. - */ + //Debounce function to reduce the number of function calls while user is dragging the browser window. WindowResizeHandler.prototype.debounce = function (func, delay) { var timeout = null; return function () { @@ -86,7 +82,6 @@ var WindowResizeHandler = /** @class */ (function () { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); - console.log("Update after resize"); this.stateManager.adjustWindowSize(); return [4 /*yield*/, this.stateManager.retrieveRecords()]; case 1: @@ -115,16 +110,14 @@ var PaginationManager = /** @class */ (function () { * @param {StateManager} stateManager - State control for retrieving/updating application data. */ function PaginationManager(tableRenderer, stateManager) { - this.tableRenderer = tableRenderer; - this.stateManager = stateManager; this.tableRenderer = tableRenderer; this.stateManager = stateManager; this.prevButton = document.getElementById("prevPage"); this.nextButton = document.getElementById("nextPage"); - this.searchButton = document.getElementById('searchButton'); + this.searchButton = document.getElementById("searchButton"); this.mainHeading = document.getElementById("main-heading"); - this.filterInput = document.getElementById('filterInput'); - this.errorMessage = document.getElementById('errorMessage'); + this.filterInput = document.getElementById("filterInput"); + this.errorMessage = document.getElementById("errorMessage"); // Attach event listeners for buttons and other UI elements. this.setupEventListeners(); } @@ -140,6 +133,14 @@ var PaginationManager = /** @class */ (function () { if (this.searchButton) { this.searchButton.addEventListener("click", function () { return _this.searchById(); }); } + if (this.filterInput) { + this.filterInput.addEventListener("keyup", function (event) { + // Check if the "Enter" key was pressed + if (event.key === "Enter") { + _this.searchById(); + } + }); + } if (this.mainHeading) { this.mainHeading.addEventListener("click", function () { return _this.navigateToHome(); }); } @@ -149,7 +150,6 @@ var PaginationManager = /** @class */ (function () { }; // Navigates to the home page by reloading the window. PaginationManager.prototype.navigateToHome = function () { - console.log("Function #25 - Navigating to Home"); try { window.location.reload(); } @@ -166,7 +166,6 @@ var PaginationManager = /** @class */ (function () { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); - console.log("Function #16 - Executing incrementPage"); this.stateManager.goToNextPage(); return [4 /*yield*/, this.stateManager.retrieveRecords()]; case 1: @@ -194,7 +193,6 @@ var PaginationManager = /** @class */ (function () { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); - console.log("Function #21 - Executing decrementPage"); this.stateManager.goToPreviousPage(); return [4 /*yield*/, this.stateManager.retrieveRecords()]; case 1: @@ -222,10 +220,9 @@ var PaginationManager = /** @class */ (function () { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); - console.log("Function #23 - Executing searchById"); searchValue = parseInt(this.filterInput.value, 10); if (isNaN(searchValue)) { - throw new Error('Invalid search value or none'); + throw new Error("Invalid search value or none"); } this.stateManager.setHighlightedId(searchValue); return [4 /*yield*/, this.stateManager.searchByIdStateChange(searchValue)]; @@ -249,13 +246,20 @@ var PaginationManager = /** @class */ (function () { // Validates input for the search bar in real-time. PaginationManager.prototype.setupLiveValidation = function () { var _this = this; - this.filterInput.addEventListener('input', function () { + if (!this.filterInput || !this.errorMessage) { + console.error("Live validation setup failed: Required elements not found."); + return; + } + this.filterInput.addEventListener("input", function () { var inputValue = _this.filterInput.value; if (inputValue.length === 0) { _this.errorMessage.textContent = ""; } - else if (inputValue.length < 1 || inputValue.length > 6 || !/^\d+$/.test(inputValue)) { - _this.errorMessage.textContent = "Invalid input. Please enter a number between 0 and 999 999."; + else if (inputValue.length < 1 || + inputValue.length > 6 || + !/^\d+$/.test(inputValue)) { + _this.errorMessage.textContent = + "Invalid input. Please enter a number between 0 and 999 999."; } else { _this.errorMessage.textContent = ""; @@ -265,7 +269,6 @@ var PaginationManager = /** @class */ (function () { // Updates the state of the pagination buttons based on the current view. PaginationManager.prototype.updateButtonStates = function () { try { - console.log("Function #20 - Executing updateButtonstates"); var from = this.stateManager.getFrom(); var to = this.stateManager.getTo(); var totalRecordCount = this.stateManager.getTotalRecordCount(); diff --git a/controllers.js.map b/controllers.js.map index 8726513e..060e8034 100644 --- a/controllers.js.map +++ b/controllers.js.map @@ -1 +1 @@ -{"version":3,"file":"controllers.js","sourceRoot":"","sources":["controllers.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"controllers.js","sourceRoot":"","sources":["controllers.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/controllers.ts b/controllers.ts index 462421e9..cf6bc07d 100644 --- a/controllers.ts +++ b/controllers.ts @@ -2,225 +2,266 @@ // Handles window resize events to update the view of the application. class WindowResizeHandler { - private debouncedUpdate: Function; - private paginationManager: PaginationManager; - - - /** - * @param {TableRenderer} tableRenderer - Used for re-rendering table data. - * @param {StateManager} stateManager - State control for retrieving/updating application data. - */ - constructor( - private tableRenderer: TableRenderer, - private stateManager: StateManager, - paginationManager: PaginationManager - ) { - this.debouncedUpdate = this.debounce(this.updateAfterResize.bind(this), 350); - this.paginationManager = paginationManager; - - // Attach event listener for window resize. - this.setupEventListeners(); + private debouncedUpdate: Function; + private paginationManager: PaginationManager; + private tableRenderer: TableRenderer; + private stateManager: StateManager; + + /** + * @param {TableRenderer} tableRenderer - Used for re-rendering table data. + * @param {StateManager} stateManager - State control for retrieving/updating application data. + */ + + constructor( + tableRenderer: TableRenderer, + stateManager: StateManager, + paginationManager: PaginationManager + ) { + this.debouncedUpdate = this.debounce( + this.updateAfterResize.bind(this), + 350 + ); + this.paginationManager = paginationManager; + this.tableRenderer = tableRenderer; + this.stateManager = stateManager; + + // Attach event listener for window resize. + this.setupEventListenersResize(); + } + + private setupEventListenersResize(): void { + window.addEventListener("resize", () => this.handleResize()); + } + + handleResize(): void { + this.debouncedUpdate(); + } + + //Debounce function to reduce the number of function calls while user is dragging the browser window. + debounce(func: Function, delay: number): Function { + let timeout: ReturnType | null = null; + return (...args: any[]) => { + const later = () => { + timeout = null; + func(...args); + }; + if (timeout !== null) { + clearTimeout(timeout); + } + timeout = setTimeout(later, delay); + }; + } + + async updateAfterResize(): Promise { + try { + this.stateManager.adjustWindowSize(); + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); + } + this.paginationManager.updateButtonStates(); + } catch (error) { + console.error( + `Error in updateAfterResize: ${ + error instanceof Error ? error.message : error + }` + ); } - - private setupEventListeners(): void { - window.addEventListener('resize', () => this.handleResize()); + } +} + +// Handles pagination and search functionalities for the application's table view. +class PaginationManager { + // DOM elements required for pagination and search. + private prevButton: HTMLButtonElement; + private nextButton: HTMLButtonElement; + private searchButton: HTMLButtonElement; + private mainHeading: HTMLElement; + private filterInput: HTMLInputElement; + private errorMessage: HTMLElement; + + /** + * @param {TableRenderer} tableRenderer - Used for re-rendering table data. + * @param {StateManager} stateManager - State control for retrieving/updating application data. + */ + + constructor( + private tableRenderer: TableRenderer, + private stateManager: StateManager + ) { + this.prevButton = document.getElementById("prevPage") as HTMLButtonElement; + this.nextButton = document.getElementById("nextPage") as HTMLButtonElement; + this.searchButton = document.getElementById( + "searchButton" + ) as HTMLButtonElement; + this.mainHeading = document.getElementById("main-heading") as HTMLElement; + this.filterInput = document.getElementById( + "filterInput" + ) as HTMLInputElement; + this.errorMessage = document.getElementById("errorMessage") as HTMLElement; + + // Attach event listeners for buttons and other UI elements. + this.setupEventListeners(); + } + + // Attaches event listeners to the relevant DOM elements to handle user interactions. + private setupEventListeners(): void { + if (this.prevButton) { + this.prevButton.addEventListener("click", () => this.decrementPage()); } - - handleResize() { - console.log("Function #15 - Executing handleResize"); - this.debouncedUpdate(); + + if (this.nextButton) { + this.nextButton.addEventListener("click", () => this.incrementPage()); } - - /** - * Debounce function to reduce the number of function calls while user is dragging the browser window. - * It delays the processing of the event until the user has stopped resizing the window for a determined amount of time. - */ - debounce(func: Function, delay: number): Function { - let timeout: ReturnType | null = null; - return (...args: any[]) => { - const later = () => { - timeout = null; - func(...args); - }; - if (timeout !== null) { - clearTimeout(timeout); - } - timeout = setTimeout(later, delay); - }; + + if (this.searchButton) { + this.searchButton.addEventListener("click", () => this.searchById()); } - - async updateAfterResize() { - try { - console.log("Update after resize"); - this.stateManager.adjustWindowSize(); - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records); + + if (this.filterInput) { + this.filterInput.addEventListener("keyup", (event) => { + // Check if the "Enter" key was pressed + if (event.key === "Enter") { + this.searchById(); } - this.paginationManager.updateButtonStates(); - - } catch (error) { - console.error(`Error in updateAfterResize: ${error instanceof Error ? error.message : error}`); - } + }); } - } - - // Handles pagination and search functionalities for the application's table view. - class PaginationManager { - // DOM elements required for pagination and search. - private prevButton: HTMLButtonElement; - private nextButton: HTMLButtonElement; - private searchButton: HTMLButtonElement; - private mainHeading: HTMLElement; - private filterInput: HTMLInputElement; - private errorMessage: HTMLElement; - - - /** - * @param {TableRenderer} tableRenderer - Used for re-rendering table data. - * @param {StateManager} stateManager - State control for retrieving/updating application data. - */ - constructor(private tableRenderer: TableRenderer, private stateManager: StateManager) { - this.tableRenderer = tableRenderer; - this.stateManager = stateManager; - - this.prevButton = document.getElementById("prevPage") as HTMLButtonElement; - this.nextButton = document.getElementById("nextPage") as HTMLButtonElement; - this.searchButton = document.getElementById('searchButton') as HTMLButtonElement; - this.mainHeading = document.getElementById("main-heading") as HTMLElement; - this.filterInput = document.getElementById('filterInput') as HTMLInputElement; - this.errorMessage = document.getElementById('errorMessage') as HTMLElement; - - // Attach event listeners for buttons and other UI elements. - this.setupEventListeners(); + + if (this.mainHeading) { + this.mainHeading.addEventListener("click", () => this.navigateToHome()); } - - // Attaches event listeners to the relevant DOM elements to handle user interactions. - private setupEventListeners(): void { - if (this.prevButton) { - this.prevButton.addEventListener("click", () => this.decrementPage()); - } - - if (this.nextButton) { - this.nextButton.addEventListener("click", () => this.incrementPage()); - } - - if (this.searchButton) { - this.searchButton.addEventListener("click", () => this.searchById()); - } - - if (this.mainHeading) { - this.mainHeading.addEventListener("click", () => this.navigateToHome()); - } - - if (this.filterInput && this.errorMessage) { - this.setupLiveValidation(); - } + + if (this.filterInput && this.errorMessage) { + this.setupLiveValidation(); } - - // Navigates to the home page by reloading the window. - navigateToHome(): void { - console.log("Function #25 - Navigating to Home"); - try { - window.location.reload(); - } catch (error) { - console.error(`Error while navigating to home: ${error instanceof Error ? error.message : error}`); - alert("Failed to reload the page. Please try again."); - } + } + + // Navigates to the home page by reloading the window. + navigateToHome(): void { + try { + window.location.reload(); + } catch (error) { + console.error( + `Error while navigating to home: ${ + error instanceof Error ? error.message : error + }` + ); + alert("Failed to reload the page. Please try again."); } - - // Fetches the next set of records and updates the view. - async incrementPage(): Promise { - try { - console.log("Function #16 - Executing incrementPage"); - this.stateManager.goToNextPage(); - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records); - } - this.updateButtonStates(); - } catch (error) { - console.error(`Unexpected error in incrementPage: ${error instanceof Error ? error.message : error}`); + } + + // Fetches the next set of records and updates the view. + async incrementPage(): Promise { + try { + this.stateManager.goToNextPage(); + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); } + this.updateButtonStates(); + } catch (error) { + console.error( + `Unexpected error in incrementPage: ${ + error instanceof Error ? error.message : error + }` + ); } - - // Fetches the previous set of records and updates the view. - async decrementPage(): Promise { - try { - console.log("Function #21 - Executing decrementPage"); - - this.stateManager.goToPreviousPage(); - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records); - } - - this.updateButtonStates(); - } catch (error) { - console.error(`Error in decrementPage: ${error instanceof Error ? error.message : error}`); + } + + // Fetches the previous set of records and updates the view. + async decrementPage(): Promise { + try { + this.stateManager.goToPreviousPage(); + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); } + + this.updateButtonStates(); + } catch (error) { + console.error( + `Error in decrementPage: ${ + error instanceof Error ? error.message : error + }` + ); } - - // Searches for a record by its ID and updates the view. - async searchById(): Promise { - try { - console.log("Function #23 - Executing searchById"); - - const searchValue = parseInt(this.filterInput.value, 10); - if (isNaN(searchValue)) { - throw new Error('Invalid search value or none'); - } - - this.stateManager.setHighlightedId(searchValue); - await this.stateManager.searchByIdStateChange(searchValue); - - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records, searchValue); - } - - this.updateButtonStates(); - } catch (error) { - console.error(`Error in searchById function: ${error instanceof Error ? error.message : error}`); + } + + // Searches for a record by its ID and updates the view. + async searchById(): Promise { + try { + const searchValue = parseInt(this.filterInput.value, 10); + if (isNaN(searchValue)) { + throw new Error("Invalid search value or none"); } + + this.stateManager.setHighlightedId(searchValue); + await this.stateManager.searchByIdStateChange(searchValue); + + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records, searchValue); + } + + this.updateButtonStates(); + } catch (error) { + console.error( + `Error in searchById function: ${ + error instanceof Error ? error.message : error + }` + ); + } } - + // Validates input for the search bar in real-time. setupLiveValidation(): void { - this.filterInput.addEventListener('input', () => { - const inputValue = this.filterInput.value; - - if (inputValue.length === 0) { - this.errorMessage.textContent = ""; - } else if (inputValue.length < 1 || inputValue.length > 6 || !/^\d+$/.test(inputValue)) { - this.errorMessage.textContent = "Invalid input. Please enter a number between 0 and 999 999."; - } else { - this.errorMessage.textContent = ""; - } + if (!this.filterInput || !this.errorMessage) { + console.error( + "Live validation setup failed: Required elements not found." + ); + return; + } + + this.filterInput.addEventListener("input", () => { + const inputValue = this.filterInput.value; + + if (inputValue.length === 0) { + this.errorMessage.textContent = ""; + } else if ( + inputValue.length < 1 || + inputValue.length > 6 || + !/^\d+$/.test(inputValue) + ) { + this.errorMessage.textContent = + "Invalid input. Please enter a number between 0 and 999 999."; + } else { + this.errorMessage.textContent = ""; + } }); } - + // Updates the state of the pagination buttons based on the current view. public updateButtonStates(): void { try { - console.log("Function #20 - Executing updateButtonstates"); - - const from = this.stateManager.getFrom(); - const to = this.stateManager.getTo(); - const totalRecordCount = this.stateManager.getTotalRecordCount(); - - this.prevButton.disabled = from === 0; - this.nextButton.disabled = to === totalRecordCount - 1; - + const from = this.stateManager.getFrom(); + const to = this.stateManager.getTo(); + const totalRecordCount = this.stateManager.getTotalRecordCount(); + + this.prevButton.disabled = from === 0; + this.nextButton.disabled = to === totalRecordCount - 1; } catch (error) { - console.error(`Unexpected error in updateButtonStates: ${error instanceof Error ? error.message : error}`); + console.error( + `Unexpected error in updateButtonStates: ${ + error instanceof Error ? error.message : error + }` + ); } } - } \ No newline at end of file +} diff --git a/data.js b/data.js index d5990e7e..0e70942d 100644 --- a/data.js +++ b/data.js @@ -48,26 +48,23 @@ var ApiManager = /** @class */ (function () { return __generator(this, function (_a) { switch (_a.label) { case 0: - console.log("Function #3 - Executing fetchTotalRecordCount"); - _a.label = 1; + _a.trys.push([0, 3, , 4]); + return [4 /*yield*/, fetch("http://localhost:2050/recordCount")]; case 1: - _a.trys.push([1, 4, , 5]); - return [4 /*yield*/, fetch('http://localhost:2050/recordCount')]; - case 2: response = _a.sent(); if (!response.ok) { throw new Error("Failed to fetch total record count: " + response.statusText); } return [4 /*yield*/, response.json()]; - case 3: + case 2: data = _a.sent(); this.totalRecordCount = data; - return [3 /*break*/, 5]; - case 4: + return [3 /*break*/, 4]; + case 3: error_1 = _a.sent(); console.error("Error fetching total record count: " + error_1); - return [3 /*break*/, 5]; - case 5: return [2 /*return*/]; + return [3 /*break*/, 4]; + case 4: return [2 /*return*/]; } }); }); @@ -78,26 +75,23 @@ var ApiManager = /** @class */ (function () { return __generator(this, function (_a) { switch (_a.label) { case 0: - console.log("Function #5 - Executing fetchColumnNames"); - _a.label = 1; + _a.trys.push([0, 3, , 4]); + return [4 /*yield*/, fetch("http://localhost:2050/columns")]; case 1: - _a.trys.push([1, 4, , 5]); - return [4 /*yield*/, fetch('http://localhost:2050/columns')]; - case 2: response = _a.sent(); if (!response.ok) { throw new Error("Failed to fetch column names: " + response.statusText); } return [4 /*yield*/, response.json()]; - case 3: + case 2: data = _a.sent(); this.columnNames = data; - return [3 /*break*/, 5]; - case 4: + return [3 /*break*/, 4]; + case 3: error_2 = _a.sent(); console.error("Error fetching column names: " + error_2); - return [3 /*break*/, 5]; - case 5: return [2 /*return*/]; + return [3 /*break*/, 4]; + case 4: return [2 /*return*/]; } }); }); @@ -108,25 +102,22 @@ var ApiManager = /** @class */ (function () { return __generator(this, function (_a) { switch (_a.label) { case 0: - console.log("Function #12.1 - Executing fetchRecords with from: " + from + ", to: " + to); - _a.label = 1; - case 1: - _a.trys.push([1, 4, , 5]); + _a.trys.push([0, 3, , 4]); return [4 /*yield*/, fetch("http://localhost:2050/records?from=" + from + "&to=" + to)]; - case 2: + case 1: response = _a.sent(); if (!response.ok) { throw new Error("Failed to fetch records: " + response.statusText); } return [4 /*yield*/, response.json()]; - case 3: + case 2: data = _a.sent(); return [2 /*return*/, data]; - case 4: + case 3: error_3 = _a.sent(); console.error("Error fetching records: " + error_3); return [2 /*return*/, null]; - case 5: return [2 /*return*/]; + case 4: return [2 /*return*/]; } }); }); diff --git a/data.js.map b/data.js.map index 4341e37d..8fb8202d 100644 --- a/data.js.map +++ b/data.js.map @@ -1 +1 @@ -{"version":3,"file":"data.js","sourceRoot":"","sources":["data.ts"],"names":[],"mappings":";AAAA,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIf,kFAAkF;AAClF;IAIE;QACE,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAEK,0CAAqB,GAA3B;;;;;;wBACE,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;;;;wBAE1C,qBAAM,KAAK,CAAC,mCAAmC,CAAC,EAAA;;wBAA3D,QAAQ,GAAG,SAAgD;wBACjE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BAChB,MAAM,IAAI,KAAK,CAAC,yCAAuC,QAAQ,CAAC,UAAY,CAAC,CAAC;yBAC/E;wBACoB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAApC,IAAI,GAAW,SAAqB;wBAC1C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;;;;wBAE7B,OAAO,CAAC,KAAK,CAAC,wCAAsC,OAAO,CAAC,CAAC;;;;;;KAEhE;IAEK,qCAAgB,GAAtB;;;;;;wBACE,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;;;;wBAErC,qBAAM,KAAK,CAAC,+BAA+B,CAAC,EAAA;;wBAAvD,QAAQ,GAAG,SAA4C;wBAC7D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BAChB,MAAM,IAAI,KAAK,CAAC,mCAAiC,QAAQ,CAAC,UAAY,CAAC,CAAC;yBACzE;wBACsB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAtC,IAAI,GAAa,SAAqB;wBAC5C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;;;;wBAExB,OAAO,CAAC,KAAK,CAAC,kCAAgC,OAAO,CAAC,CAAC;;;;;;KAE1D;IAEK,iCAAY,GAAlB,UAAmB,IAAY,EAAE,EAAU;;;;;;wBACzC,OAAO,CAAC,GAAG,CAAC,wDAAsD,IAAI,cAAS,EAAI,CAAC,CAAC;;;;wBAElE,qBAAM,KAAK,CAAC,wCAAsC,IAAI,YAAO,EAAI,CAAC,EAAA;;wBAA7E,QAAQ,GAAG,SAAkE;wBACnF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BAChB,MAAM,IAAI,KAAK,CAAC,8BAA4B,QAAQ,CAAC,UAAY,CAAC,CAAC;yBACpE;wBACwB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAxC,IAAI,GAAe,SAAqB;wBAC9C,sBAAO,IAAI,EAAC;;;wBAEZ,OAAO,CAAC,KAAK,CAAC,6BAA2B,OAAO,CAAC,CAAC;wBAClD,sBAAO,IAAI,EAAC;;;;;KAEf;IACH,iBAAC;AAAD,CAAC,AAnDD,IAmDC"} \ No newline at end of file +{"version":3,"file":"data.js","sourceRoot":"","sources":["data.ts"],"names":[],"mappings":";AAAA,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIf,kFAAkF;AAClF;IAIE;QACE,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAEK,0CAAqB,GAA3B;;;;;;;wBAEqB,qBAAM,KAAK,CAAC,mCAAmC,CAAC,EAAA;;wBAA3D,QAAQ,GAAG,SAAgD;wBACjE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BAChB,MAAM,IAAI,KAAK,CACb,yCAAuC,QAAQ,CAAC,UAAY,CAC7D,CAAC;yBACH;wBACoB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAApC,IAAI,GAAW,SAAqB;wBAC1C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;;;;wBAE7B,OAAO,CAAC,KAAK,CAAC,wCAAsC,OAAO,CAAC,CAAC;;;;;;KAEhE;IAEK,qCAAgB,GAAtB;;;;;;;wBAEqB,qBAAM,KAAK,CAAC,+BAA+B,CAAC,EAAA;;wBAAvD,QAAQ,GAAG,SAA4C;wBAC7D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BAChB,MAAM,IAAI,KAAK,CAAC,mCAAiC,QAAQ,CAAC,UAAY,CAAC,CAAC;yBACzE;wBACsB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAtC,IAAI,GAAa,SAAqB;wBAC5C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;;;;wBAExB,OAAO,CAAC,KAAK,CAAC,kCAAgC,OAAO,CAAC,CAAC;;;;;;KAE1D;IAEK,iCAAY,GAAlB,UAAmB,IAAY,EAAE,EAAU;;;;;;;wBAEtB,qBAAM,KAAK,CAC1B,wCAAsC,IAAI,YAAO,EAAI,CACtD,EAAA;;wBAFK,QAAQ,GAAG,SAEhB;wBACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BAChB,MAAM,IAAI,KAAK,CAAC,8BAA4B,QAAQ,CAAC,UAAY,CAAC,CAAC;yBACpE;wBACwB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAxC,IAAI,GAAe,SAAqB;wBAC9C,sBAAO,IAAI,EAAC;;;wBAEZ,OAAO,CAAC,KAAK,CAAC,6BAA2B,OAAO,CAAC,CAAC;wBAClD,sBAAO,IAAI,EAAC;;;;;KAEf;IACH,iBAAC;AAAD,CAAC,AApDD,IAoDC"} \ No newline at end of file diff --git a/data.ts b/data.ts index 2c6eeede..81ad8af8 100644 --- a/data.ts +++ b/data.ts @@ -6,18 +6,19 @@ type CityData = [number, string, number]; class ApiManager { totalRecordCount: number; columnNames: string[] | null; - + constructor() { this.totalRecordCount = 0; this.columnNames = null; } async fetchTotalRecordCount(): Promise { - console.log("Function #3 - Executing fetchTotalRecordCount"); try { - const response = await fetch('http://localhost:2050/recordCount'); + const response = await fetch("http://localhost:2050/recordCount"); if (!response.ok) { - throw new Error(`Failed to fetch total record count: ${response.statusText}`); + throw new Error( + `Failed to fetch total record count: ${response.statusText}` + ); } const data: number = await response.json(); this.totalRecordCount = data; @@ -25,11 +26,10 @@ class ApiManager { console.error(`Error fetching total record count: ${error}`); } } - + async fetchColumnNames(): Promise { - console.log("Function #5 - Executing fetchColumnNames"); try { - const response = await fetch('http://localhost:2050/columns'); + const response = await fetch("http://localhost:2050/columns"); if (!response.ok) { throw new Error(`Failed to fetch column names: ${response.statusText}`); } @@ -39,11 +39,12 @@ class ApiManager { console.error(`Error fetching column names: ${error}`); } } - + async fetchRecords(from: number, to: number): Promise { - console.log(`Function #12.1 - Executing fetchRecords with from: ${from}, to: ${to}`); try { - const response = await fetch(`http://localhost:2050/records?from=${from}&to=${to}`); + const response = await fetch( + `http://localhost:2050/records?from=${from}&to=${to}` + ); if (!response.ok) { throw new Error(`Failed to fetch records: ${response.statusText}`); } @@ -54,4 +55,4 @@ class ApiManager { return null; } } -} \ No newline at end of file +} diff --git a/index.html b/index.html index 58451d3b..04227c3d 100644 --- a/index.html +++ b/index.html @@ -1,33 +1,37 @@ - - Riaan JS Onboard Project - - - - - - - - - -
-
-

Area 51's Grocery List

- - - - - - -
- - + diff --git a/model.js b/model.js index fcc592c9..2e83c6a8 100644 --- a/model.js +++ b/model.js @@ -65,23 +65,20 @@ var StateManager = /** @class */ (function () { return __generator(this, function (_a) { switch (_a.label) { case 0: - console.log("Function #1 - Executing initialize"); - _a.label = 1; - case 1: - _a.trys.push([1, 4, , 5]); + _a.trys.push([0, 3, , 4]); return [4 /*yield*/, this.fetchAndStoreTotalRecordCount()]; - case 2: + case 1: _a.sent(); return [4 /*yield*/, this.retrieveColumnNames()]; - case 3: + case 2: _a.sent(); this.adjustWindowSize(); - return [3 /*break*/, 5]; - case 4: + return [3 /*break*/, 4]; + case 3: error_1 = _a.sent(); console.error("Error in initializeState:", error_1); - return [3 /*break*/, 5]; - case 5: return [2 /*return*/]; + return [3 /*break*/, 4]; + case 4: return [2 /*return*/]; } }); }); @@ -92,22 +89,19 @@ var StateManager = /** @class */ (function () { return __generator(this, function (_a) { switch (_a.label) { case 0: - console.log("Function #4 - Executing retrieveColumnNames"); - _a.label = 1; - case 1: - _a.trys.push([1, 3, , 4]); + _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this.apiManager.fetchColumnNames()]; - case 2: + case 1: _a.sent(); if (this.apiManager.columnNames !== null) { this.columnNames = this.apiManager.columnNames; } - return [3 /*break*/, 4]; - case 3: + return [3 /*break*/, 3]; + case 2: error_2 = _a.sent(); console.error("Error in retrieveColumnNames:", error_2); - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; + return [3 /*break*/, 3]; + case 3: return [2 /*return*/]; } }); }); @@ -118,20 +112,17 @@ var StateManager = /** @class */ (function () { return __generator(this, function (_a) { switch (_a.label) { case 0: - console.log("Function #2 - Executing fetchAndStoreTotalRecordCount"); - _a.label = 1; - case 1: - _a.trys.push([1, 3, , 4]); + _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this.apiManager.fetchTotalRecordCount()]; - case 2: + case 1: _a.sent(); this.totalRecordCount = this.apiManager.totalRecordCount; - return [3 /*break*/, 4]; - case 3: + return [3 /*break*/, 3]; + case 2: error_3 = _a.sent(); console.error("Error in fetchAndStoreTotalRecordCount:", error_3); - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; + return [3 /*break*/, 3]; + case 3: return [2 /*return*/]; } }); }); @@ -140,38 +131,31 @@ var StateManager = /** @class */ (function () { return this.totalRecordCount; }; StateManager.prototype.getColumnNames = function () { - console.log("Function #10 - Executing getColumnNames"); return this.columnNames; }; StateManager.prototype.getRecords = function () { - console.log("Function #13 - Executing getRecords"); return this.records; }; StateManager.prototype.getFrom = function () { - console.log("Function #18 - Executing getFrom"); return this.from; }; StateManager.prototype.setFrom = function (value) { - console.log("Function #7 - Executing setFrom"); this.from = value; }; StateManager.prototype.getTo = function () { - console.log("Function #19 - Executing getTo"); return this.to; }; StateManager.prototype.setTo = function (value) { - console.log("Function #8 - Executing setTo"); this.to = value; }; StateManager.prototype.goToNextPage = function () { try { - console.log("Function #17 - Executing goToNextPage"); var from = this.getFrom(); var to = this.getTo(); var recordsPerPage = this.numRows; var newFrom = from + recordsPerPage; var newTo = newFrom + recordsPerPage - 1; - // Check that 'to' does not exceed totalRecordCount + // Check that 'to' does not exceed totalRecordCount. if (newTo >= this.totalRecordCount) { this.setTo(this.totalRecordCount - 1); this.setFrom(this.totalRecordCount - recordsPerPage); @@ -187,13 +171,12 @@ var StateManager = /** @class */ (function () { }; StateManager.prototype.goToPreviousPage = function () { try { - console.log("Function #22 - Executing goToPreviousPage"); var from = this.getFrom(); var to = this.getTo(); var recordsPerPage = this.numRows; - // Calculate the new 'from' and 'to' values var newFrom = from - recordsPerPage; var newTo = newFrom + recordsPerPage - 1; + // Check that 'from' does not exceed 0. if (newFrom < 0) { this.setFrom(0); this.setTo(recordsPerPage - 1); @@ -214,11 +197,10 @@ var StateManager = /** @class */ (function () { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); - console.log("Function #24 - Executing searchByIdStateChange"); newFrom = id; newTo = id + this.numRows - 1; recordsPerPage = this.numRows; - // Checking that 'to' does not exceed totalRecordCount + // Checking that 'to' does not exceed totalRecordCount. if (newTo >= this.totalRecordCount) { this.setTo(this.totalRecordCount - 1); this.setFrom(this.totalRecordCount - recordsPerPage); @@ -242,15 +224,25 @@ var StateManager = /** @class */ (function () { }; // Adjusts the available height based on window size and recalculates the number of rows. StateManager.prototype.adjustWindowSize = function () { - console.log("Function #6 - Executing adjustWindowSize"); try { if (typeof window === "undefined" || !window.innerHeight) { throw new Error("Unable to access window dimensions"); } + // Determine the dynamic height of the header and pagination. + var mainHeadingElement = document.getElementById("main-heading"); + var paginationElement = document.getElementById("pagination"); + if (mainHeadingElement && paginationElement) { + this.headerHeight = + mainHeadingElement.clientHeight + paginationElement.clientHeight; + } + else { + console.error("Could not find main-heading and/or pagination elements"); + } if (!this.rowHeight) { throw new Error("Row height is not properly configured"); } - this.availableHeight = window.innerHeight - this.headerHeight; + this.availableHeight = + window.innerHeight - this.headerHeight - this.rowHeight * 2; this.numRows = Math.floor(this.availableHeight / this.rowHeight); if (this.numRows <= 0) { console.log("Window size too small, setting minimum number of rows to 1"); @@ -259,19 +251,23 @@ var StateManager = /** @class */ (function () { // Calculating new values without modifying the state immediately. var newFrom = this.from; var newTo = this.from + this.numRows - 1; - // If it's the first set of records, start from 0. + // If it's the first set of records ("first page"), start from 0 and populate the whole window size. if (this.from === 0) { newFrom = 0; newTo = this.numRows - 1; } - // Ensure `newTo` doesn't exceed totalRecordCount and adjust `newFrom` accordingly. + // Ensure `newTo` doesn't exceed totalRecordCount and adjust `newFrom` accordingly, + // meaning populate the whole window size. if (newTo >= this.totalRecordCount) { newTo = this.totalRecordCount - 1; newFrom = newTo - this.numRows + 1; } - // Check if the highlighted ID is currently between from and to. - var highlightedId = this.getHighlightedId(); // Assuming you have a method to get the highlighted ID. - if (highlightedId !== null && highlightedId >= this.from && highlightedId <= this.to) { + // Check if the highlighted ID is currently between from and to, + // too enable priority functionality (always visible in the window). + var highlightedId = this.getHighlightedId(); + if (highlightedId !== null && + highlightedId >= this.from && + highlightedId <= this.to) { // If newTo would be smaller than highlightedId, adjust to keep highlightedId in view. if (newTo < highlightedId) { newTo = highlightedId; @@ -292,20 +288,17 @@ var StateManager = /** @class */ (function () { return __generator(this, function (_b) { switch (_b.label) { case 0: - console.log("Function #12 - Executing retrieveRecords"); - _b.label = 1; - case 1: - _b.trys.push([1, 3, , 4]); + _b.trys.push([0, 2, , 3]); _a = this; return [4 /*yield*/, this.apiManager.fetchRecords(this.from, this.to)]; - case 2: + case 1: _a.records = _b.sent(); - return [3 /*break*/, 4]; - case 3: + return [3 /*break*/, 3]; + case 2: error_5 = _b.sent(); console.error("Error retrieving records: " + (error_5 instanceof Error ? error_5.message : error_5)); - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; + return [3 /*break*/, 3]; + case 3: return [2 /*return*/]; } }); }); diff --git a/model.js.map b/model.js.map index 9358331d..6d69cf68 100644 --- a/model.js.map +++ b/model.js.map @@ -1 +1 @@ -{"version":3,"file":"model.js","sourceRoot":"","sources":["model.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"model.js","sourceRoot":"","sources":["model.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/model.ts b/model.ts index 255a2603..27d4de0f 100644 --- a/model.ts +++ b/model.ts @@ -2,240 +2,259 @@ // Manages the application's state for data display, navigation, and search functionalities. class StateManager { + private highlightedId: number | null = null; + private rowHeight: number; + private headerHeight: number; + private availableHeight: number; + private numRows: number; + private from: number; + private to: number; + private apiManager: ApiManager; + private records: CityData[] | null = null; + private columnNames: string[] | null; + private totalRecordCount = 0; - private highlightedId: number | null = null; - private rowHeight: number; - private headerHeight: number; - private availableHeight: number; - private numRows: number; - private from: number; - private to: number; - private apiManager: ApiManager; - private records: CityData[] | null = null; - private columnNames: string[] | null; - private totalRecordCount = 0; - - constructor(apiManager: ApiManager) { - this.rowHeight = 20; - this.headerHeight = 180; - this.availableHeight = 0; - this.numRows = 0; - this.apiManager = apiManager; - this.from = 0; - this.to = 0; - this.columnNames = null; - this.totalRecordCount = 0; + constructor(apiManager: ApiManager) { + this.rowHeight = 20; + this.headerHeight = 180; + this.availableHeight = 0; + this.numRows = 0; + this.apiManager = apiManager; + this.from = 0; + this.to = 0; + this.columnNames = null; + this.totalRecordCount = 0; + } + + public getHighlightedId(): number | null { + return this.highlightedId; + } + + public setHighlightedId(value: number | null): void { + this.highlightedId = value; + } + + // Sets up initial state, fetches record count and column names, and adjusts the display window size. + async initializeState(): Promise { + try { + await this.fetchAndStoreTotalRecordCount(); + await this.retrieveColumnNames(); + this.adjustWindowSize(); + } catch (error) { + console.error("Error in initializeState:", error); } - - public getHighlightedId(): number | null { - return this.highlightedId; + } + + async retrieveColumnNames(): Promise { + try { + await this.apiManager.fetchColumnNames(); + + if (this.apiManager.columnNames !== null) { + this.columnNames = this.apiManager.columnNames; + } + } catch (error) { + console.error("Error in retrieveColumnNames:", error); } + } - public setHighlightedId(value: number | null): void { - this.highlightedId = value; + async fetchAndStoreTotalRecordCount(): Promise { + try { + await this.apiManager.fetchTotalRecordCount(); + this.totalRecordCount = this.apiManager.totalRecordCount; + } catch (error) { + console.error("Error in fetchAndStoreTotalRecordCount:", error); } + } + + getTotalRecordCount(): number { + return this.totalRecordCount; + } - // Sets up initial state, fetches record count and column names, and adjusts the display window size. - async initializeState(): Promise { - console.log("Function #1 - Executing initialize"); - try { - await this.fetchAndStoreTotalRecordCount(); - await this.retrieveColumnNames(); - this.adjustWindowSize(); - } catch (error) { - console.error("Error in initializeState:", error); + getColumnNames(): string[] | null { + return this.columnNames; + } + + getRecords(): CityData[] | null { + return this.records; + } + + getFrom(): number { + return this.from; + } + + setFrom(value: number): void { + this.from = value; + } + + getTo(): number { + return this.to; + } + + setTo(value: number): void { + this.to = value; + } + + goToNextPage(): void { + try { + const from = this.getFrom(); + const to = this.getTo(); + const recordsPerPage = this.numRows; + + const newFrom = from + recordsPerPage; + const newTo = newFrom + recordsPerPage - 1; + + // Check that 'to' does not exceed totalRecordCount. + if (newTo >= this.totalRecordCount) { + this.setTo(this.totalRecordCount - 1); + this.setFrom(this.totalRecordCount - recordsPerPage); + } else { + this.setFrom(newFrom); + this.setTo(newTo); } + } catch (error) { + console.error( + `Unexpected error in goToNextPage: ${ + error instanceof Error ? error.message : error + }` + ); } - - async retrieveColumnNames(): Promise { - console.log("Function #4 - Executing retrieveColumnNames"); - try { - await this.apiManager.fetchColumnNames(); - - if (this.apiManager.columnNames !== null) { - this.columnNames = this.apiManager.columnNames; - } - } catch (error) { - console.error("Error in retrieveColumnNames:", error); - } } - - async fetchAndStoreTotalRecordCount(): Promise { - console.log("Function #2 - Executing fetchAndStoreTotalRecordCount"); - try { - await this.apiManager.fetchTotalRecordCount(); - this.totalRecordCount = this.apiManager.totalRecordCount; - } catch (error) { - console.error("Error in fetchAndStoreTotalRecordCount:", error); + + goToPreviousPage(): void { + try { + const from = this.getFrom(); + const to = this.getTo(); + const recordsPerPage = this.numRows; + + const newFrom = from - recordsPerPage; + const newTo = newFrom + recordsPerPage - 1; + + // Check that 'from' does not exceed 0. + if (newFrom < 0) { + this.setFrom(0); + this.setTo(recordsPerPage - 1); + } else { + this.setFrom(newFrom); + this.setTo(newTo); } + } catch (error) { + console.error( + `Error in goToPreviousPage: ${ + error instanceof Error ? error.message : error + }` + ); } - - getTotalRecordCount(): number { - return this.totalRecordCount; - } - - getColumnNames(): string[] | null { - console.log("Function #10 - Executing getColumnNames"); - return this.columnNames; - } - - getRecords(): CityData[] | null { - console.log("Function #13 - Executing getRecords"); - return this.records; - } - - getFrom(): number { - console.log("Function #18 - Executing getFrom"); - return this.from; - } - - setFrom(value: number): void { - console.log("Function #7 - Executing setFrom"); - this.from = value; - } - - getTo(): number { - console.log("Function #19 - Executing getTo"); - return this.to; - } - - setTo(value: number): void { - console.log("Function #8 - Executing setTo"); - this.to = value; - } - - goToNextPage(): void { - try { - console.log("Function #17 - Executing goToNextPage"); - const from = this.getFrom(); - const to = this.getTo(); - const recordsPerPage = this.numRows; - - const newFrom = from + recordsPerPage; - const newTo = newFrom + recordsPerPage - 1; - - // Check that 'to' does not exceed totalRecordCount - if (newTo >= this.totalRecordCount) { - this.setTo(this.totalRecordCount - 1); - this.setFrom(this.totalRecordCount - recordsPerPage); - } else { - this.setFrom(newFrom); - this.setTo(newTo); - } - } catch (error) { - console.error(`Unexpected error in goToNextPage: ${error instanceof Error ? error.message : error}`); + } + + async searchByIdStateChange(id: number): Promise { + try { + const newFrom = id; + const newTo = id + this.numRows - 1; + const recordsPerPage = this.numRows; + + // Checking that 'to' does not exceed totalRecordCount. + if (newTo >= this.totalRecordCount) { + this.setTo(this.totalRecordCount - 1); + this.setFrom(this.totalRecordCount - recordsPerPage); + } else { + this.setTo(newTo); + this.setFrom(newFrom); } + + await this.retrieveRecords(); + } catch (error) { + console.error( + `Error in searchByIdStateChange: ${ + error instanceof Error ? error.message : error + }` + ); } - - goToPreviousPage(): void { - try { - console.log("Function #22 - Executing goToPreviousPage"); - const from = this.getFrom(); - const to = this.getTo(); - const recordsPerPage = this.numRows; - - // Calculate the new 'from' and 'to' values - const newFrom = from - recordsPerPage; - const newTo = newFrom + recordsPerPage - 1; - - if (newFrom < 0) { - this.setFrom(0); - this.setTo(recordsPerPage - 1); - } else { - this.setFrom(newFrom); - this.setTo(newTo); - } - } catch (error) { - console.error(`Error in goToPreviousPage: ${error instanceof Error ? error.message : error}`); + } + // Adjusts the available height based on window size and recalculates the number of rows. + adjustWindowSize(): void { + try { + if (typeof window === "undefined" || !window.innerHeight) { + throw new Error("Unable to access window dimensions"); } - } - - async searchByIdStateChange(id: number): Promise { - try { - console.log("Function #24 - Executing searchByIdStateChange"); - - const newFrom = id; - const newTo = id + this.numRows - 1; - const recordsPerPage = this.numRows; - - // Checking that 'to' does not exceed totalRecordCount - if (newTo >= this.totalRecordCount) { - this.setTo(this.totalRecordCount - 1); - this.setFrom(this.totalRecordCount - recordsPerPage); - } else { - this.setTo(newTo); - this.setFrom(newFrom); - } - - await this.retrieveRecords(); - - } catch (error) { - console.error(`Error in searchByIdStateChange: ${error instanceof Error ? error.message : error}`); + + // Determine the dynamic height of the header and pagination. + const mainHeadingElement = document.getElementById("main-heading"); + const paginationElement = document.getElementById("pagination"); + + if (mainHeadingElement && paginationElement) { + this.headerHeight = + mainHeadingElement.clientHeight + paginationElement.clientHeight; + } else { + console.error("Could not find main-heading and/or pagination elements"); } - } - // Adjusts the available height based on window size and recalculates the number of rows. - adjustWindowSize(): void { - console.log("Function #6 - Executing adjustWindowSize"); - - try { - if (typeof window === "undefined" || !window.innerHeight) { - throw new Error("Unable to access window dimensions"); - } - - if (!this.rowHeight) { - throw new Error("Row height is not properly configured"); - } - - this.availableHeight = window.innerHeight - this.headerHeight; - this.numRows = Math.floor(this.availableHeight / this.rowHeight); - - if (this.numRows <= 0) { - console.log("Window size too small, setting minimum number of rows to 1"); - this.numRows = 1; - } - - // Calculating new values without modifying the state immediately. - let newFrom = this.from; - let newTo = this.from + this.numRows - 1; - - // If it's the first set of records, start from 0. - if (this.from === 0) { - newFrom = 0; - newTo = this.numRows - 1; - } - - // Ensure `newTo` doesn't exceed totalRecordCount and adjust `newFrom` accordingly. - if (newTo >= this.totalRecordCount) { - newTo = this.totalRecordCount - 1; - newFrom = newTo - this.numRows + 1; - } - - // Check if the highlighted ID is currently between from and to. - const highlightedId = this.getHighlightedId(); // Assuming you have a method to get the highlighted ID. - if (highlightedId !== null && highlightedId >= this.from && highlightedId <= this.to) { - // If newTo would be smaller than highlightedId, adjust to keep highlightedId in view. - if (newTo < highlightedId) { - newTo = highlightedId; - newFrom = newTo - this.numRows + 1; - } - } - - // Now, after all conditions have been checked, set the state. - this.setFrom(newFrom); - this.setTo(newTo); - - } catch (error) { - console.error(`Error in adjustWindowSize: ${error instanceof Error ? error.message : error}`); + if (!this.rowHeight) { + throw new Error("Row height is not properly configured"); + } + + this.availableHeight = + window.innerHeight - this.headerHeight - this.rowHeight * 2; + this.numRows = Math.floor(this.availableHeight / this.rowHeight); + + if (this.numRows <= 0) { + console.log( + "Window size too small, setting minimum number of rows to 1" + ); + this.numRows = 1; + } + + // Calculating new values without modifying the state immediately. + let newFrom = this.from; + let newTo = this.from + this.numRows - 1; + + // If it's the first set of records ("first page"), start from 0 and populate the whole window size. + if (this.from === 0) { + newFrom = 0; + newTo = this.numRows - 1; } + + // Ensure `newTo` doesn't exceed totalRecordCount and adjust `newFrom` accordingly, + // meaning populate the whole window size. + if (newTo >= this.totalRecordCount) { + newTo = this.totalRecordCount - 1; + newFrom = newTo - this.numRows + 1; + } + + // Check if the highlighted ID is currently between from and to, + // too enable priority functionality (always visible in the window). + const highlightedId = this.getHighlightedId(); + if ( + highlightedId !== null && + highlightedId >= this.from && + highlightedId <= this.to + ) { + // If newTo would be smaller than highlightedId, adjust to keep highlightedId in view. + if (newTo < highlightedId) { + newTo = highlightedId; + newFrom = newTo - this.numRows + 1; + } + } + + // Now, after all conditions have been checked, set the state. + this.setFrom(newFrom); + this.setTo(newTo); + } catch (error) { + console.error( + `Error in adjustWindowSize: ${ + error instanceof Error ? error.message : error + }` + ); + } } - - + async retrieveRecords(): Promise { - console.log("Function #12 - Executing retrieveRecords"); try { - this.records = await this.apiManager.fetchRecords(this.from, this.to); + this.records = await this.apiManager.fetchRecords(this.from, this.to); } catch (error) { - console.error(`Error retrieving records: ${error instanceof Error ? error.message : error}`); + console.error( + `Error retrieving records: ${ + error instanceof Error ? error.message : error + }` + ); } } - } \ No newline at end of file +} diff --git a/stylesheet.css b/stylesheet.css index 484d1cd4..8c1c87b9 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,44 +1,42 @@ -@import url('https://fonts.googleapis.com/css2?family=Orbitron&display=swap'); +@import url("https://fonts.googleapis.com/css2?family=Orbitron&display=swap"); #main-heading { - font-family: 'Orbitron', sans-serif; + font-family: "Orbitron", sans-serif; font-size: 2.5em; font-weight: bold; text-align: center; margin: 10px 0; color: #333; - text-shadow: #00FF00; + text-shadow: #00ff00; cursor: pointer; } #main-container { margin: 0 auto; background-color: #fff; - } -html, body { - font-family: 'SF Pro Text', 'Helvetica Neue', Helvetica, Arial, sans-serif; +html, +body { + font-family: "SF Pro Text", "Helvetica Neue", Helvetica, Arial, sans-serif; color: #333; margin-bottom: 0; overflow: hidden; } - th { - font-family: 'Orbitron', sans-serif; + font-family: "Orbitron", sans-serif; text-align: center; font-size: 16px; - border: 1px solid #a1e3a1; - background-color: #333333; - color: #4CAF50; + border: 1px solid #a1e3a1; + background-color: #333333; + color: #4caf50; } - td { - font-family: 'Orbitron', sans-serif; + font-family: "Orbitron", sans-serif; font-size: 14px; - border: 1px solid #a1e3a1; + border: 1px solid #a1e3a1; text-align: center; color: #333333; text-overflow: ellipsis; @@ -46,62 +44,58 @@ td { white-space: nowrap; } - table { border-collapse: collapse; - } #myTable { table-layout: fixed; - + width: 100%; height: 100%; - border: 1px solid #a1e3a1; + border: 1px solid #a1e3a1; border-radius: 12px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); - } .highlight { - background-color: #00FF00!important; - color: #4CAF50 !important; /* Added this line to make the text color green */ + background-color: #00ff00 !important; + color: #4caf50 !important; /* Added this line to make the text color green */ } - .pagination-1 { text-align: center; padding-top: 25px; padding-bottom: 25px; - font-family: 'Orbitron', sans-serif; + font-family: "Orbitron", sans-serif; + /* white-space:nowrap; */ } button { padding: 10px 20px; - border: 1px solid #00FF00;; - background-color: #1e1e1e; /* Dark Grey almost Black */ - color: #00FF00; /* Bright green like old school terminals */ + border: 1px solid #00ff00; + background-color: #1e1e1e; /* Dark Grey almost Black */ + color: #00ff00; /* Bright green like old school terminals */ border-radius: 5px; - font-family: 'Orbitron', sans-serif; + font-family: "Orbitron", sans-serif; cursor: pointer; transition: background-color 0.3s; } button:disabled { - background-color: #555; /* Mid-grey for disabled buttons */ - color: #ccc; /* light grey text */ + background-color: #555; /* Mid-grey for disabled buttons */ + color: #ccc; /* light grey text */ } button:hover:not(:disabled) { - background-color: #333; /* Slightly lighter dark grey */ + background-color: #333; /* Slightly lighter dark grey */ } #filterInput { padding: 10px; - border: 1px solid #00FF00; /* Bright green border */ + border: 1px solid #00ff00; /* Bright green border */ border-radius: 5px; - font-family: 'Orbitron', sans-serif; - color: #00FF00; /* Bright green text */ - background-color: #1e1e1e; /* Dark background */ + font-family: "Orbitron", sans-serif; + color: #00ff00; /* Bright green text */ + background-color: #1e1e1e; /* Dark background */ } - diff --git a/views.js b/views.js index 28b7b277..015c311c 100644 --- a/views.js +++ b/views.js @@ -48,22 +48,21 @@ var TableRenderer = /** @class */ (function () { * Renders the initial table layout including column names and initial data set. * @param {StateManager} stateManager - The manager to fetch state from. */ - TableRenderer.prototype.initialRender = function (stateManager) { + TableRenderer.prototype.initialRender = function () { return __awaiter(this, void 0, void 0, function () { var columnNames, records, error_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); - console.log("Function #9 - Executing initialRender"); - columnNames = stateManager.getColumnNames(); + columnNames = this.stateManager.getColumnNames(); if (columnNames !== null) { this.renderColumnNames(columnNames); } - return [4 /*yield*/, stateManager.retrieveRecords()]; + return [4 /*yield*/, this.stateManager.retrieveRecords()]; case 1: _a.sent(); - records = stateManager.getRecords(); + records = this.stateManager.getRecords(); if (records !== null) { this.renderRecords(records); } @@ -78,16 +77,15 @@ var TableRenderer = /** @class */ (function () { }); }; TableRenderer.prototype.renderColumnNames = function (columnNames) { - console.log("Function #11 - Executing renderColumnNames"); try { - var thead = document.querySelector('thead'); + var thead = document.querySelector("thead"); if (thead === null) { - throw new Error('Table header not found.'); + throw new Error("Table header not found."); } - var row = document.createElement('tr'); + var row = document.createElement("tr"); for (var _i = 0, columnNames_1 = columnNames; _i < columnNames_1.length; _i++) { var columnName = columnNames_1[_i]; - var cell = document.createElement('th'); + var cell = document.createElement("th"); cell.textContent = columnName; row.appendChild(cell); } @@ -105,7 +103,6 @@ var TableRenderer = /** @class */ (function () { }; // Sets the widths of table columns evenly. TableRenderer.prototype.setColumnWidths = function () { - console.log("Function #11.1 - Executing setColumnWidths"); try { var table = document.getElementById("myTable"); if (!table) { @@ -125,25 +122,26 @@ var TableRenderer = /** @class */ (function () { //Populates the table body with records. Optionally highlights a specified row if searched. TableRenderer.prototype.renderRecords = function (records, highlightId) { if (highlightId === void 0) { highlightId = null; } - console.log("Function #14 - Executing renderRecords"); // Use the state's highlightedId if no highlightId is provided. highlightId = highlightId !== null && highlightId !== void 0 ? highlightId : this.stateManager.getHighlightedId(); try { if (records === null) { throw new Error("No records to render."); } - var tbody_1 = document.querySelector('tbody'); + var tbody_1 = document.querySelector("tbody"); if (tbody_1 === null) { - throw new Error('Table body not found.'); + throw new Error("Table body not found."); } - tbody_1.innerHTML = ''; + tbody_1.innerHTML = ""; records.forEach(function (record) { - var row = document.createElement('tr'); - if (highlightId !== null && record.length > 0 && parseInt(record[0].toString(), 10) === highlightId) { - row.classList.add('highlight'); + var row = document.createElement("tr"); + if (highlightId !== null && + record.length > 0 && + parseInt(record[0].toString(), 10) === highlightId) { + row.classList.add("highlight"); } record.forEach(function (cell) { - var td = document.createElement('td'); + var td = document.createElement("td"); td.textContent = cell.toString(); row.appendChild(td); }); diff --git a/views.js.map b/views.js.map index 322e969a..09816b2a 100644 --- a/views.js.map +++ b/views.js.map @@ -1 +1 @@ -{"version":3,"file":"views.js","sourceRoot":"","sources":["views.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"views.js","sourceRoot":"","sources":["views.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/views.ts b/views.ts index 7895a923..601b020e 100644 --- a/views.ts +++ b/views.ts @@ -6,118 +6,114 @@ */ class TableRenderer { - private stateManager: StateManager; - - constructor(stateManager: StateManager) { - this.stateManager = stateManager; - } - - /** - * Renders the initial table layout including column names and initial data set. - * @param {StateManager} stateManager - The manager to fetch state from. - */ - async initialRender(stateManager: StateManager): Promise { - try { - console.log("Function #9 - Executing initialRender"); - - const columnNames = stateManager.getColumnNames(); - if (columnNames !== null) { - this.renderColumnNames(columnNames); - } - - await stateManager.retrieveRecords(); - const records = stateManager.getRecords(); - - if (records !== null) { - this.renderRecords(records); - } - } catch (error) { - console.error(`Error during initialRender: ${error}`); + private stateManager: StateManager; + + constructor(stateManager: StateManager) { + this.stateManager = stateManager; + } + + /** + * Renders the initial table layout including column names and initial data set. + * @param {StateManager} stateManager - The manager to fetch state from. + */ + async initialRender(): Promise { + try { + const columnNames = this.stateManager.getColumnNames(); + if (columnNames !== null) { + this.renderColumnNames(columnNames); } + + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.renderRecords(records); + } + } catch (error) { + console.error(`Error during initialRender: ${error}`); + } } - - renderColumnNames(columnNames: string[]): void { - console.log("Function #11 - Executing renderColumnNames"); - try { - const thead = document.querySelector('thead'); - if (thead === null) { - throw new Error('Table header not found.'); - } - - const row = document.createElement('tr'); - for (const columnName of columnNames) { - const cell = document.createElement('th'); - cell.textContent = columnName; - row.appendChild(cell); - } - thead.appendChild(row); - - this.setColumnWidths(); - } catch (error) { - if (error instanceof Error) { - console.error(`An error occurred: ${error.message}`); - } else { - console.error(`An unknown error occurred: ${error}`); - } + + renderColumnNames(columnNames: string[]): void { + try { + const thead = document.querySelector("thead"); + if (thead === null) { + throw new Error("Table header not found."); + } + + const row = document.createElement("tr"); + for (const columnName of columnNames) { + const cell = document.createElement("th"); + cell.textContent = columnName; + row.appendChild(cell); + } + thead.appendChild(row); + + this.setColumnWidths(); + } catch (error) { + if (error instanceof Error) { + console.error(`An error occurred: ${error.message}`); + } else { + console.error(`An unknown error occurred: ${error}`); } } + } - // Sets the widths of table columns evenly. - setColumnWidths(): void { - console.log("Function #11.1 - Executing setColumnWidths"); - try { - const table = document.getElementById("myTable"); - - if (!table) { - throw new Error('Table with id "myTable" not found.'); - } - - const headerCells = table.querySelectorAll("th"); - const numCols = headerCells.length; - const colWidth = 100 / numCols; - - headerCells.forEach((headerCell: Element) => { - (headerCell as HTMLElement).style.width = `${colWidth}%`; - }); - } catch (error) { - console.error(`Error setting column widths: ${error}`); + // Sets the widths of table columns evenly. + setColumnWidths(): void { + try { + const table = document.getElementById("myTable"); + + if (!table) { + throw new Error('Table with id "myTable" not found.'); } + + const headerCells = table.querySelectorAll("th"); + const numCols = headerCells.length; + const colWidth = 100 / numCols; + + headerCells.forEach((headerCell: Element) => { + (headerCell as HTMLElement).style.width = `${colWidth}%`; + }); + } catch (error) { + console.error(`Error setting column widths: ${error}`); + } } - - //Populates the table body with records. Optionally highlights a specified row if searched. - renderRecords(records: CityData[] | null, highlightId: number | null = null) { - console.log("Function #14 - Executing renderRecords"); + //Populates the table body with records. Optionally highlights a specified row if searched. + renderRecords(records: CityData[] | null, highlightId: number | null = null) { + // Use the state's highlightedId if no highlightId is provided. + highlightId = highlightId ?? this.stateManager.getHighlightedId(); + try { + if (records === null) { + throw new Error("No records to render."); + } - // Use the state's highlightedId if no highlightId is provided. - highlightId = highlightId ?? this.stateManager.getHighlightedId(); - try { - if (records === null) { - throw new Error("No records to render."); - } - - const tbody = document.querySelector('tbody'); - if (tbody === null) { - throw new Error('Table body not found.'); + const tbody = document.querySelector("tbody"); + if (tbody === null) { + throw new Error("Table body not found."); + } + + tbody.innerHTML = ""; + + records.forEach((record) => { + const row = document.createElement("tr"); + if ( + highlightId !== null && + record.length > 0 && + parseInt(record[0].toString(), 10) === highlightId + ) { + row.classList.add("highlight"); } - - tbody.innerHTML = ''; - - records.forEach((record) => { - const row = document.createElement('tr'); - if (highlightId !== null && record.length > 0 && parseInt(record[0].toString(), 10) === highlightId) { - row.classList.add('highlight'); - } - record.forEach((cell) => { - const td = document.createElement('td'); - td.textContent = cell.toString(); - row.appendChild(td); - }); - tbody.appendChild(row); + record.forEach((cell) => { + const td = document.createElement("td"); + td.textContent = cell.toString(); + row.appendChild(td); }); - } catch (error) { - console.error(`An error occurred: ${error}`); - } + tbody.appendChild(row); + }); + } catch (error) { + console.error(`An error occurred: ${error}`); } } - \ No newline at end of file +} From 9e0c21969e76527c25e4442b85186a17f13f5ebe Mon Sep 17 00:00:00 2001 From: riaan Date: Fri, 29 Sep 2023 15:04:51 +0200 Subject: [PATCH 25/27] Added .js files to gitignore Rev 1.19 --- .gitignore | 9 + app.ts | 33 +-- controllers.js | 16 +- controllers.js.map | 2 +- controllers.ts | 526 +++++++++++++++++++++++---------------------- data.js.map | 2 +- data.ts | 98 +++++---- index.html | 72 ++++--- model.js | 3 +- model.js.map | 2 +- model.ts | 516 ++++++++++++++++++++++---------------------- stylesheet.css | 119 +++++----- views.js.map | 2 +- views.ts | 223 +++++++++---------- 14 files changed, 834 insertions(+), 789 deletions(-) diff --git a/.gitignore b/.gitignore index 0872c36c..39ddd198 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,12 @@ /node_modules app.js app.js.map +controllers.js +controllers.js.map +data.js +data.js.map +model.js +model.js.map +views.js +views.js.map +.vscode/settings.json diff --git a/app.ts b/app.ts index 62284d53..7c168f79 100644 --- a/app.ts +++ b/app.ts @@ -24,22 +24,25 @@ /*** Main Script ***/ window.onload = async () => { - // Initialize data.ts - const apiManager = new ApiManager(); + // Initialize data.ts + const apiManager = new ApiManager(); - // Initialize model.ts - const stateManager = new StateManager(apiManager); - await stateManager.initializeState(); + // Initialize model.ts + const stateManager = new StateManager(apiManager); + await stateManager.initializeState(); - // Initialize views.ts - const tableRenderer = new TableRenderer(stateManager); - await tableRenderer.initialRender(); + // Initialize views.ts + const tableRenderer = new TableRenderer(stateManager); + await tableRenderer.initialRender(); - // Initialize controllers.ts - const paginationManager = new PaginationManager(tableRenderer, stateManager); - const windowResizeHandler = new WindowResizeHandler( - tableRenderer, - stateManager, - paginationManager - ); + // Initialize controllers.ts + const paginationManager = new PaginationManager( + tableRenderer, + stateManager + ); + const windowResizeHandler = new WindowResizeHandler( + tableRenderer, + stateManager, + paginationManager + ); }; diff --git a/controllers.js b/controllers.js index f8d3acfe..2e645c25 100644 --- a/controllers.js +++ b/controllers.js @@ -125,13 +125,19 @@ var PaginationManager = /** @class */ (function () { PaginationManager.prototype.setupEventListeners = function () { var _this = this; if (this.prevButton) { - this.prevButton.addEventListener("click", function () { return _this.decrementPage(); }); + this.prevButton.addEventListener("click", function () { + return _this.decrementPage(); + }); } if (this.nextButton) { - this.nextButton.addEventListener("click", function () { return _this.incrementPage(); }); + this.nextButton.addEventListener("click", function () { + return _this.incrementPage(); + }); } if (this.searchButton) { - this.searchButton.addEventListener("click", function () { return _this.searchById(); }); + this.searchButton.addEventListener("click", function () { + return _this.searchById(); + }); } if (this.filterInput) { this.filterInput.addEventListener("keyup", function (event) { @@ -142,7 +148,9 @@ var PaginationManager = /** @class */ (function () { }); } if (this.mainHeading) { - this.mainHeading.addEventListener("click", function () { return _this.navigateToHome(); }); + this.mainHeading.addEventListener("click", function () { + return _this.navigateToHome(); + }); } if (this.filterInput && this.errorMessage) { this.setupLiveValidation(); diff --git a/controllers.js.map b/controllers.js.map index 060e8034..38acc6b0 100644 --- a/controllers.js.map +++ b/controllers.js.map @@ -1 +1 @@ -{"version":3,"file":"controllers.js","sourceRoot":"","sources":["controllers.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"controllers.js","sourceRoot":"","sources":["controllers.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/controllers.ts b/controllers.ts index cf6bc07d..05773ce6 100644 --- a/controllers.ts +++ b/controllers.ts @@ -2,266 +2,276 @@ // Handles window resize events to update the view of the application. class WindowResizeHandler { - private debouncedUpdate: Function; - private paginationManager: PaginationManager; - private tableRenderer: TableRenderer; - private stateManager: StateManager; - - /** - * @param {TableRenderer} tableRenderer - Used for re-rendering table data. - * @param {StateManager} stateManager - State control for retrieving/updating application data. - */ - - constructor( - tableRenderer: TableRenderer, - stateManager: StateManager, - paginationManager: PaginationManager - ) { - this.debouncedUpdate = this.debounce( - this.updateAfterResize.bind(this), - 350 - ); - this.paginationManager = paginationManager; - this.tableRenderer = tableRenderer; - this.stateManager = stateManager; - - // Attach event listener for window resize. - this.setupEventListenersResize(); - } - - private setupEventListenersResize(): void { - window.addEventListener("resize", () => this.handleResize()); - } - - handleResize(): void { - this.debouncedUpdate(); - } - - //Debounce function to reduce the number of function calls while user is dragging the browser window. - debounce(func: Function, delay: number): Function { - let timeout: ReturnType | null = null; - return (...args: any[]) => { - const later = () => { - timeout = null; - func(...args); - }; - if (timeout !== null) { - clearTimeout(timeout); - } - timeout = setTimeout(later, delay); - }; - } - - async updateAfterResize(): Promise { - try { - this.stateManager.adjustWindowSize(); - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records); - } - this.paginationManager.updateButtonStates(); - } catch (error) { - console.error( - `Error in updateAfterResize: ${ - error instanceof Error ? error.message : error - }` - ); - } - } + private debouncedUpdate: Function; + private paginationManager: PaginationManager; + private tableRenderer: TableRenderer; + private stateManager: StateManager; + + /** + * @param {TableRenderer} tableRenderer - Used for re-rendering table data. + * @param {StateManager} stateManager - State control for retrieving/updating application data. + */ + + constructor( + tableRenderer: TableRenderer, + stateManager: StateManager, + paginationManager: PaginationManager + ) { + this.debouncedUpdate = this.debounce( + this.updateAfterResize.bind(this), + 350 + ); + this.paginationManager = paginationManager; + this.tableRenderer = tableRenderer; + this.stateManager = stateManager; + + // Attach event listener for window resize. + this.setupEventListenersResize(); + } + + private setupEventListenersResize(): void { + window.addEventListener("resize", () => this.handleResize()); + } + + handleResize(): void { + this.debouncedUpdate(); + } + + //Debounce function to reduce the number of function calls while user is dragging the browser window. + debounce(func: Function, delay: number): Function { + let timeout: ReturnType | null = null; + return (...args: any[]) => { + const later = () => { + timeout = null; + func(...args); + }; + if (timeout !== null) { + clearTimeout(timeout); + } + timeout = setTimeout(later, delay); + }; + } + + async updateAfterResize(): Promise { + try { + this.stateManager.adjustWindowSize(); + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); + } + this.paginationManager.updateButtonStates(); + } catch (error) { + console.error( + `Error in updateAfterResize: ${error instanceof Error ? error.message : error + }` + ); + } + } } // Handles pagination and search functionalities for the application's table view. class PaginationManager { - // DOM elements required for pagination and search. - private prevButton: HTMLButtonElement; - private nextButton: HTMLButtonElement; - private searchButton: HTMLButtonElement; - private mainHeading: HTMLElement; - private filterInput: HTMLInputElement; - private errorMessage: HTMLElement; - - /** - * @param {TableRenderer} tableRenderer - Used for re-rendering table data. - * @param {StateManager} stateManager - State control for retrieving/updating application data. - */ - - constructor( - private tableRenderer: TableRenderer, - private stateManager: StateManager - ) { - this.prevButton = document.getElementById("prevPage") as HTMLButtonElement; - this.nextButton = document.getElementById("nextPage") as HTMLButtonElement; - this.searchButton = document.getElementById( - "searchButton" - ) as HTMLButtonElement; - this.mainHeading = document.getElementById("main-heading") as HTMLElement; - this.filterInput = document.getElementById( - "filterInput" - ) as HTMLInputElement; - this.errorMessage = document.getElementById("errorMessage") as HTMLElement; - - // Attach event listeners for buttons and other UI elements. - this.setupEventListeners(); - } - - // Attaches event listeners to the relevant DOM elements to handle user interactions. - private setupEventListeners(): void { - if (this.prevButton) { - this.prevButton.addEventListener("click", () => this.decrementPage()); - } - - if (this.nextButton) { - this.nextButton.addEventListener("click", () => this.incrementPage()); - } - - if (this.searchButton) { - this.searchButton.addEventListener("click", () => this.searchById()); - } - - if (this.filterInput) { - this.filterInput.addEventListener("keyup", (event) => { - // Check if the "Enter" key was pressed - if (event.key === "Enter") { - this.searchById(); - } - }); - } - - if (this.mainHeading) { - this.mainHeading.addEventListener("click", () => this.navigateToHome()); - } - - if (this.filterInput && this.errorMessage) { - this.setupLiveValidation(); - } - } - - // Navigates to the home page by reloading the window. - navigateToHome(): void { - try { - window.location.reload(); - } catch (error) { - console.error( - `Error while navigating to home: ${ - error instanceof Error ? error.message : error - }` - ); - alert("Failed to reload the page. Please try again."); - } - } - - // Fetches the next set of records and updates the view. - async incrementPage(): Promise { - try { - this.stateManager.goToNextPage(); - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records); - } - this.updateButtonStates(); - } catch (error) { - console.error( - `Unexpected error in incrementPage: ${ - error instanceof Error ? error.message : error - }` - ); - } - } - - // Fetches the previous set of records and updates the view. - async decrementPage(): Promise { - try { - this.stateManager.goToPreviousPage(); - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records); - } - - this.updateButtonStates(); - } catch (error) { - console.error( - `Error in decrementPage: ${ - error instanceof Error ? error.message : error - }` - ); - } - } - - // Searches for a record by its ID and updates the view. - async searchById(): Promise { - try { - const searchValue = parseInt(this.filterInput.value, 10); - if (isNaN(searchValue)) { - throw new Error("Invalid search value or none"); - } - - this.stateManager.setHighlightedId(searchValue); - await this.stateManager.searchByIdStateChange(searchValue); - - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records, searchValue); - } - - this.updateButtonStates(); - } catch (error) { - console.error( - `Error in searchById function: ${ - error instanceof Error ? error.message : error - }` - ); - } - } - - // Validates input for the search bar in real-time. - setupLiveValidation(): void { - if (!this.filterInput || !this.errorMessage) { - console.error( - "Live validation setup failed: Required elements not found." - ); - return; - } - - this.filterInput.addEventListener("input", () => { - const inputValue = this.filterInput.value; - - if (inputValue.length === 0) { - this.errorMessage.textContent = ""; - } else if ( - inputValue.length < 1 || - inputValue.length > 6 || - !/^\d+$/.test(inputValue) - ) { - this.errorMessage.textContent = - "Invalid input. Please enter a number between 0 and 999 999."; - } else { - this.errorMessage.textContent = ""; - } - }); - } - - // Updates the state of the pagination buttons based on the current view. - public updateButtonStates(): void { - try { - const from = this.stateManager.getFrom(); - const to = this.stateManager.getTo(); - const totalRecordCount = this.stateManager.getTotalRecordCount(); - - this.prevButton.disabled = from === 0; - this.nextButton.disabled = to === totalRecordCount - 1; - } catch (error) { - console.error( - `Unexpected error in updateButtonStates: ${ - error instanceof Error ? error.message : error - }` - ); - } - } + // DOM elements required for pagination and search. + private prevButton: HTMLButtonElement; + private nextButton: HTMLButtonElement; + private searchButton: HTMLButtonElement; + private mainHeading: HTMLElement; + private filterInput: HTMLInputElement; + private errorMessage: HTMLElement; + + /** + * @param {TableRenderer} tableRenderer - Used for re-rendering table data. + * @param {StateManager} stateManager - State control for retrieving/updating application data. + */ + + constructor( + private tableRenderer: TableRenderer, + private stateManager: StateManager + ) { + this.prevButton = document.getElementById( + "prevPage" + ) as HTMLButtonElement; + this.nextButton = document.getElementById( + "nextPage" + ) as HTMLButtonElement; + this.searchButton = document.getElementById( + "searchButton" + ) as HTMLButtonElement; + this.mainHeading = document.getElementById( + "main-heading" + ) as HTMLElement; + this.filterInput = document.getElementById( + "filterInput" + ) as HTMLInputElement; + this.errorMessage = document.getElementById( + "errorMessage" + ) as HTMLElement; + + // Attach event listeners for buttons and other UI elements. + this.setupEventListeners(); + } + + // Attaches event listeners to the relevant DOM elements to handle user interactions. + private setupEventListeners(): void { + if (this.prevButton) { + this.prevButton.addEventListener("click", () => + this.decrementPage() + ); + } + + if (this.nextButton) { + this.nextButton.addEventListener("click", () => + this.incrementPage() + ); + } + + if (this.searchButton) { + this.searchButton.addEventListener("click", () => + this.searchById() + ); + } + + if (this.filterInput) { + this.filterInput.addEventListener("keyup", (event) => { + // Check if the "Enter" key was pressed + if (event.key === "Enter") { + this.searchById(); + } + }); + } + + if (this.mainHeading) { + this.mainHeading.addEventListener("click", () => + this.navigateToHome() + ); + } + + if (this.filterInput && this.errorMessage) { + this.setupLiveValidation(); + } + } + + // Navigates to the home page by reloading the window. + navigateToHome(): void { + try { + window.location.reload(); + } catch (error) { + console.error( + `Error while navigating to home: ${error instanceof Error ? error.message : error + }` + ); + alert("Failed to reload the page. Please try again."); + } + } + + // Fetches the next set of records and updates the view. + async incrementPage(): Promise { + try { + this.stateManager.goToNextPage(); + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); + } + this.updateButtonStates(); + } catch (error) { + console.error( + `Unexpected error in incrementPage: ${error instanceof Error ? error.message : error + }` + ); + } + } + + // Fetches the previous set of records and updates the view. + async decrementPage(): Promise { + try { + this.stateManager.goToPreviousPage(); + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); + } + + this.updateButtonStates(); + } catch (error) { + console.error( + `Error in decrementPage: ${error instanceof Error ? error.message : error + }` + ); + } + } + + // Searches for a record by its ID and updates the view. + async searchById(): Promise { + try { + const searchValue = parseInt(this.filterInput.value, 10); + if (isNaN(searchValue)) { + throw new Error("Invalid search value or none"); + } + + this.stateManager.setHighlightedId(searchValue); + await this.stateManager.searchByIdStateChange(searchValue); + + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records, searchValue); + } + + this.updateButtonStates(); + } catch (error) { + console.error( + `Error in searchById function: ${error instanceof Error ? error.message : error + }` + ); + } + } + + // Validates input for the search bar in real-time. + setupLiveValidation(): void { + if (!this.filterInput || !this.errorMessage) { + console.error( + "Live validation setup failed: Required elements not found." + ); + return; + } + + this.filterInput.addEventListener("input", () => { + const inputValue = this.filterInput.value; + + if (inputValue.length === 0) { + this.errorMessage.textContent = ""; + } else if ( + inputValue.length < 1 || + inputValue.length > 6 || + !/^\d+$/.test(inputValue) + ) { + this.errorMessage.textContent = + "Invalid input. Please enter a number between 0 and 999 999."; + } else { + this.errorMessage.textContent = ""; + } + }); + } + + // Updates the state of the pagination buttons based on the current view. + public updateButtonStates(): void { + try { + const from = this.stateManager.getFrom(); + const to = this.stateManager.getTo(); + const totalRecordCount = this.stateManager.getTotalRecordCount(); + + this.prevButton.disabled = from === 0; + this.nextButton.disabled = to === totalRecordCount - 1; + } catch (error) { + console.error( + `Unexpected error in updateButtonStates: ${error instanceof Error ? error.message : error + }` + ); + } + } } diff --git a/data.js.map b/data.js.map index 8fb8202d..8b31eb12 100644 --- a/data.js.map +++ b/data.js.map @@ -1 +1 @@ -{"version":3,"file":"data.js","sourceRoot":"","sources":["data.ts"],"names":[],"mappings":";AAAA,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIf,kFAAkF;AAClF;IAIE;QACE,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAEK,0CAAqB,GAA3B;;;;;;;wBAEqB,qBAAM,KAAK,CAAC,mCAAmC,CAAC,EAAA;;wBAA3D,QAAQ,GAAG,SAAgD;wBACjE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BAChB,MAAM,IAAI,KAAK,CACb,yCAAuC,QAAQ,CAAC,UAAY,CAC7D,CAAC;yBACH;wBACoB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAApC,IAAI,GAAW,SAAqB;wBAC1C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;;;;wBAE7B,OAAO,CAAC,KAAK,CAAC,wCAAsC,OAAO,CAAC,CAAC;;;;;;KAEhE;IAEK,qCAAgB,GAAtB;;;;;;;wBAEqB,qBAAM,KAAK,CAAC,+BAA+B,CAAC,EAAA;;wBAAvD,QAAQ,GAAG,SAA4C;wBAC7D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BAChB,MAAM,IAAI,KAAK,CAAC,mCAAiC,QAAQ,CAAC,UAAY,CAAC,CAAC;yBACzE;wBACsB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAtC,IAAI,GAAa,SAAqB;wBAC5C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;;;;wBAExB,OAAO,CAAC,KAAK,CAAC,kCAAgC,OAAO,CAAC,CAAC;;;;;;KAE1D;IAEK,iCAAY,GAAlB,UAAmB,IAAY,EAAE,EAAU;;;;;;;wBAEtB,qBAAM,KAAK,CAC1B,wCAAsC,IAAI,YAAO,EAAI,CACtD,EAAA;;wBAFK,QAAQ,GAAG,SAEhB;wBACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BAChB,MAAM,IAAI,KAAK,CAAC,8BAA4B,QAAQ,CAAC,UAAY,CAAC,CAAC;yBACpE;wBACwB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAxC,IAAI,GAAe,SAAqB;wBAC9C,sBAAO,IAAI,EAAC;;;wBAEZ,OAAO,CAAC,KAAK,CAAC,6BAA2B,OAAO,CAAC,CAAC;wBAClD,sBAAO,IAAI,EAAC;;;;;KAEf;IACH,iBAAC;AAAD,CAAC,AApDD,IAoDC"} \ No newline at end of file +{"version":3,"file":"data.js","sourceRoot":"","sources":["data.ts"],"names":[],"mappings":";AAAA,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIf,kFAAkF;AAClF;IAIC;QACC,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IACzB,CAAC;IAEK,0CAAqB,GAA3B;;;;;;;wBAEmB,qBAAM,KAAK,CAAC,mCAAmC,CAAC,EAAA;;wBAA3D,QAAQ,GAAG,SAAgD;wBACjE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BACjB,MAAM,IAAI,KAAK,CACd,yCAAuC,QAAQ,CAAC,UAAY,CAC5D,CAAC;yBACF;wBACoB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAApC,IAAI,GAAW,SAAqB;wBAC1C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;;;;wBAE7B,OAAO,CAAC,KAAK,CAAC,wCAAsC,OAAO,CAAC,CAAC;;;;;;KAE9D;IAEK,qCAAgB,GAAtB;;;;;;;wBAEmB,qBAAM,KAAK,CAAC,+BAA+B,CAAC,EAAA;;wBAAvD,QAAQ,GAAG,SAA4C;wBAC7D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BACjB,MAAM,IAAI,KAAK,CACd,mCAAiC,QAAQ,CAAC,UAAY,CACtD,CAAC;yBACF;wBACsB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAtC,IAAI,GAAa,SAAqB;wBAC5C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;;;;wBAExB,OAAO,CAAC,KAAK,CAAC,kCAAgC,OAAO,CAAC,CAAC;;;;;;KAExD;IAEK,iCAAY,GAAlB,UAAmB,IAAY,EAAE,EAAU;;;;;;;wBAExB,qBAAM,KAAK,CAC3B,wCAAsC,IAAI,YAAO,EAAI,CACrD,EAAA;;wBAFK,QAAQ,GAAG,SAEhB;wBACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BACjB,MAAM,IAAI,KAAK,CACd,8BAA4B,QAAQ,CAAC,UAAY,CACjD,CAAC;yBACF;wBACwB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAxC,IAAI,GAAe,SAAqB;wBAC9C,sBAAO,IAAI,EAAC;;;wBAEZ,OAAO,CAAC,KAAK,CAAC,6BAA2B,OAAO,CAAC,CAAC;wBAClD,sBAAO,IAAI,EAAC;;;;;KAEb;IACF,iBAAC;AAAD,CAAC,AAxDD,IAwDC"} \ No newline at end of file diff --git a/data.ts b/data.ts index 81ad8af8..2fe54e5c 100644 --- a/data.ts +++ b/data.ts @@ -4,55 +4,59 @@ type CityData = [number, string, number]; // Manages API requests for fetching record count, column names, and data records. class ApiManager { - totalRecordCount: number; - columnNames: string[] | null; + totalRecordCount: number; + columnNames: string[] | null; - constructor() { - this.totalRecordCount = 0; - this.columnNames = null; - } + constructor() { + this.totalRecordCount = 0; + this.columnNames = null; + } - async fetchTotalRecordCount(): Promise { - try { - const response = await fetch("http://localhost:2050/recordCount"); - if (!response.ok) { - throw new Error( - `Failed to fetch total record count: ${response.statusText}` - ); - } - const data: number = await response.json(); - this.totalRecordCount = data; - } catch (error) { - console.error(`Error fetching total record count: ${error}`); - } - } + async fetchTotalRecordCount(): Promise { + try { + const response = await fetch("http://localhost:2050/recordCount"); + if (!response.ok) { + throw new Error( + `Failed to fetch total record count: ${response.statusText}` + ); + } + const data: number = await response.json(); + this.totalRecordCount = data; + } catch (error) { + console.error(`Error fetching total record count: ${error}`); + } + } - async fetchColumnNames(): Promise { - try { - const response = await fetch("http://localhost:2050/columns"); - if (!response.ok) { - throw new Error(`Failed to fetch column names: ${response.statusText}`); - } - const data: string[] = await response.json(); - this.columnNames = data; - } catch (error) { - console.error(`Error fetching column names: ${error}`); - } - } + async fetchColumnNames(): Promise { + try { + const response = await fetch("http://localhost:2050/columns"); + if (!response.ok) { + throw new Error( + `Failed to fetch column names: ${response.statusText}` + ); + } + const data: string[] = await response.json(); + this.columnNames = data; + } catch (error) { + console.error(`Error fetching column names: ${error}`); + } + } - async fetchRecords(from: number, to: number): Promise { - try { - const response = await fetch( - `http://localhost:2050/records?from=${from}&to=${to}` - ); - if (!response.ok) { - throw new Error(`Failed to fetch records: ${response.statusText}`); - } - const data: CityData[] = await response.json(); - return data; - } catch (error) { - console.error(`Error fetching records: ${error}`); - return null; - } - } + async fetchRecords(from: number, to: number): Promise { + try { + const response = await fetch( + `http://localhost:2050/records?from=${from}&to=${to}` + ); + if (!response.ok) { + throw new Error( + `Failed to fetch records: ${response.statusText}` + ); + } + const data: CityData[] = await response.json(); + return data; + } catch (error) { + console.error(`Error fetching records: ${error}`); + return null; + } + } } diff --git a/index.html b/index.html index 04227c3d..ed2fa3c9 100644 --- a/index.html +++ b/index.html @@ -1,37 +1,41 @@ - - Riaan JS Onboard Project - - - - - - - - - -
- -

Area 51's Grocery List

- - - - - - -
- -
- + + Riaan JS Onboard Project + + + + + + + + + +
+ +

Area 51's Grocery List

+ + + + + + +
+ +
+ diff --git a/model.js b/model.js index 2e83c6a8..0402bc9f 100644 --- a/model.js +++ b/model.js @@ -233,7 +233,8 @@ var StateManager = /** @class */ (function () { var paginationElement = document.getElementById("pagination"); if (mainHeadingElement && paginationElement) { this.headerHeight = - mainHeadingElement.clientHeight + paginationElement.clientHeight; + mainHeadingElement.clientHeight + + paginationElement.clientHeight; } else { console.error("Could not find main-heading and/or pagination elements"); diff --git a/model.js.map b/model.js.map index 6d69cf68..970e0724 100644 --- a/model.js.map +++ b/model.js.map @@ -1 +1 @@ -{"version":3,"file":"model.js","sourceRoot":"","sources":["model.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"model.js","sourceRoot":"","sources":["model.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/model.ts b/model.ts index 27d4de0f..7c3f4e33 100644 --- a/model.ts +++ b/model.ts @@ -2,259 +2,265 @@ // Manages the application's state for data display, navigation, and search functionalities. class StateManager { - private highlightedId: number | null = null; - private rowHeight: number; - private headerHeight: number; - private availableHeight: number; - private numRows: number; - private from: number; - private to: number; - private apiManager: ApiManager; - private records: CityData[] | null = null; - private columnNames: string[] | null; - private totalRecordCount = 0; - - constructor(apiManager: ApiManager) { - this.rowHeight = 20; - this.headerHeight = 180; - this.availableHeight = 0; - this.numRows = 0; - this.apiManager = apiManager; - this.from = 0; - this.to = 0; - this.columnNames = null; - this.totalRecordCount = 0; - } - - public getHighlightedId(): number | null { - return this.highlightedId; - } - - public setHighlightedId(value: number | null): void { - this.highlightedId = value; - } - - // Sets up initial state, fetches record count and column names, and adjusts the display window size. - async initializeState(): Promise { - try { - await this.fetchAndStoreTotalRecordCount(); - await this.retrieveColumnNames(); - this.adjustWindowSize(); - } catch (error) { - console.error("Error in initializeState:", error); - } - } - - async retrieveColumnNames(): Promise { - try { - await this.apiManager.fetchColumnNames(); - - if (this.apiManager.columnNames !== null) { - this.columnNames = this.apiManager.columnNames; - } - } catch (error) { - console.error("Error in retrieveColumnNames:", error); - } - } - - async fetchAndStoreTotalRecordCount(): Promise { - try { - await this.apiManager.fetchTotalRecordCount(); - this.totalRecordCount = this.apiManager.totalRecordCount; - } catch (error) { - console.error("Error in fetchAndStoreTotalRecordCount:", error); - } - } - - getTotalRecordCount(): number { - return this.totalRecordCount; - } - - getColumnNames(): string[] | null { - return this.columnNames; - } - - getRecords(): CityData[] | null { - return this.records; - } - - getFrom(): number { - return this.from; - } - - setFrom(value: number): void { - this.from = value; - } - - getTo(): number { - return this.to; - } - - setTo(value: number): void { - this.to = value; - } - - goToNextPage(): void { - try { - const from = this.getFrom(); - const to = this.getTo(); - const recordsPerPage = this.numRows; - - const newFrom = from + recordsPerPage; - const newTo = newFrom + recordsPerPage - 1; - - // Check that 'to' does not exceed totalRecordCount. - if (newTo >= this.totalRecordCount) { - this.setTo(this.totalRecordCount - 1); - this.setFrom(this.totalRecordCount - recordsPerPage); - } else { - this.setFrom(newFrom); - this.setTo(newTo); - } - } catch (error) { - console.error( - `Unexpected error in goToNextPage: ${ - error instanceof Error ? error.message : error - }` - ); - } - } - - goToPreviousPage(): void { - try { - const from = this.getFrom(); - const to = this.getTo(); - const recordsPerPage = this.numRows; - - const newFrom = from - recordsPerPage; - const newTo = newFrom + recordsPerPage - 1; - - // Check that 'from' does not exceed 0. - if (newFrom < 0) { - this.setFrom(0); - this.setTo(recordsPerPage - 1); - } else { - this.setFrom(newFrom); - this.setTo(newTo); - } - } catch (error) { - console.error( - `Error in goToPreviousPage: ${ - error instanceof Error ? error.message : error - }` - ); - } - } - - async searchByIdStateChange(id: number): Promise { - try { - const newFrom = id; - const newTo = id + this.numRows - 1; - const recordsPerPage = this.numRows; - - // Checking that 'to' does not exceed totalRecordCount. - if (newTo >= this.totalRecordCount) { - this.setTo(this.totalRecordCount - 1); - this.setFrom(this.totalRecordCount - recordsPerPage); - } else { - this.setTo(newTo); - this.setFrom(newFrom); - } - - await this.retrieveRecords(); - } catch (error) { - console.error( - `Error in searchByIdStateChange: ${ - error instanceof Error ? error.message : error - }` - ); - } - } - // Adjusts the available height based on window size and recalculates the number of rows. - adjustWindowSize(): void { - try { - if (typeof window === "undefined" || !window.innerHeight) { - throw new Error("Unable to access window dimensions"); - } - - // Determine the dynamic height of the header and pagination. - const mainHeadingElement = document.getElementById("main-heading"); - const paginationElement = document.getElementById("pagination"); - - if (mainHeadingElement && paginationElement) { - this.headerHeight = - mainHeadingElement.clientHeight + paginationElement.clientHeight; - } else { - console.error("Could not find main-heading and/or pagination elements"); - } - if (!this.rowHeight) { - throw new Error("Row height is not properly configured"); - } - - this.availableHeight = - window.innerHeight - this.headerHeight - this.rowHeight * 2; - this.numRows = Math.floor(this.availableHeight / this.rowHeight); - - if (this.numRows <= 0) { - console.log( - "Window size too small, setting minimum number of rows to 1" - ); - this.numRows = 1; - } - - // Calculating new values without modifying the state immediately. - let newFrom = this.from; - let newTo = this.from + this.numRows - 1; - - // If it's the first set of records ("first page"), start from 0 and populate the whole window size. - if (this.from === 0) { - newFrom = 0; - newTo = this.numRows - 1; - } - - // Ensure `newTo` doesn't exceed totalRecordCount and adjust `newFrom` accordingly, - // meaning populate the whole window size. - if (newTo >= this.totalRecordCount) { - newTo = this.totalRecordCount - 1; - newFrom = newTo - this.numRows + 1; - } - - // Check if the highlighted ID is currently between from and to, - // too enable priority functionality (always visible in the window). - const highlightedId = this.getHighlightedId(); - if ( - highlightedId !== null && - highlightedId >= this.from && - highlightedId <= this.to - ) { - // If newTo would be smaller than highlightedId, adjust to keep highlightedId in view. - if (newTo < highlightedId) { - newTo = highlightedId; - newFrom = newTo - this.numRows + 1; - } - } - - // Now, after all conditions have been checked, set the state. - this.setFrom(newFrom); - this.setTo(newTo); - } catch (error) { - console.error( - `Error in adjustWindowSize: ${ - error instanceof Error ? error.message : error - }` - ); - } - } - - async retrieveRecords(): Promise { - try { - this.records = await this.apiManager.fetchRecords(this.from, this.to); - } catch (error) { - console.error( - `Error retrieving records: ${ - error instanceof Error ? error.message : error - }` - ); - } - } + private highlightedId: number | null = null; + private rowHeight: number; + private headerHeight: number; + private availableHeight: number; + private numRows: number; + private from: number; + private to: number; + private apiManager: ApiManager; + private records: CityData[] | null = null; + private columnNames: string[] | null; + private totalRecordCount = 0; + + constructor(apiManager: ApiManager) { + this.rowHeight = 20; + this.headerHeight = 180; + this.availableHeight = 0; + this.numRows = 0; + this.apiManager = apiManager; + this.from = 0; + this.to = 0; + this.columnNames = null; + this.totalRecordCount = 0; + } + + public getHighlightedId(): number | null { + return this.highlightedId; + } + + public setHighlightedId(value: number | null): void { + this.highlightedId = value; + } + + // Sets up initial state, fetches record count and column names, and adjusts the display window size. + async initializeState(): Promise { + try { + await this.fetchAndStoreTotalRecordCount(); + await this.retrieveColumnNames(); + this.adjustWindowSize(); + } catch (error) { + console.error("Error in initializeState:", error); + } + } + + async retrieveColumnNames(): Promise { + try { + await this.apiManager.fetchColumnNames(); + + if (this.apiManager.columnNames !== null) { + this.columnNames = this.apiManager.columnNames; + } + } catch (error) { + console.error("Error in retrieveColumnNames:", error); + } + } + + async fetchAndStoreTotalRecordCount(): Promise { + try { + await this.apiManager.fetchTotalRecordCount(); + this.totalRecordCount = this.apiManager.totalRecordCount; + } catch (error) { + console.error("Error in fetchAndStoreTotalRecordCount:", error); + } + } + + getTotalRecordCount(): number { + return this.totalRecordCount; + } + + getColumnNames(): string[] | null { + return this.columnNames; + } + + getRecords(): CityData[] | null { + return this.records; + } + + getFrom(): number { + return this.from; + } + + setFrom(value: number): void { + this.from = value; + } + + getTo(): number { + return this.to; + } + + setTo(value: number): void { + this.to = value; + } + + goToNextPage(): void { + try { + const from = this.getFrom(); + const to = this.getTo(); + const recordsPerPage = this.numRows; + + const newFrom = from + recordsPerPage; + const newTo = newFrom + recordsPerPage - 1; + + // Check that 'to' does not exceed totalRecordCount. + if (newTo >= this.totalRecordCount) { + this.setTo(this.totalRecordCount - 1); + this.setFrom(this.totalRecordCount - recordsPerPage); + } else { + this.setFrom(newFrom); + this.setTo(newTo); + } + } catch (error) { + console.error( + `Unexpected error in goToNextPage: ${ + error instanceof Error ? error.message : error + }` + ); + } + } + + goToPreviousPage(): void { + try { + const from = this.getFrom(); + const to = this.getTo(); + const recordsPerPage = this.numRows; + + const newFrom = from - recordsPerPage; + const newTo = newFrom + recordsPerPage - 1; + + // Check that 'from' does not exceed 0. + if (newFrom < 0) { + this.setFrom(0); + this.setTo(recordsPerPage - 1); + } else { + this.setFrom(newFrom); + this.setTo(newTo); + } + } catch (error) { + console.error( + `Error in goToPreviousPage: ${ + error instanceof Error ? error.message : error + }` + ); + } + } + + async searchByIdStateChange(id: number): Promise { + try { + const newFrom = id; + const newTo = id + this.numRows - 1; + const recordsPerPage = this.numRows; + + // Checking that 'to' does not exceed totalRecordCount. + if (newTo >= this.totalRecordCount) { + this.setTo(this.totalRecordCount - 1); + this.setFrom(this.totalRecordCount - recordsPerPage); + } else { + this.setTo(newTo); + this.setFrom(newFrom); + } + + await this.retrieveRecords(); + } catch (error) { + console.error( + `Error in searchByIdStateChange: ${ + error instanceof Error ? error.message : error + }` + ); + } + } + // Adjusts the available height based on window size and recalculates the number of rows. + adjustWindowSize(): void { + try { + if (typeof window === "undefined" || !window.innerHeight) { + throw new Error("Unable to access window dimensions"); + } + + // Determine the dynamic height of the header and pagination. + const mainHeadingElement = document.getElementById("main-heading"); + const paginationElement = document.getElementById("pagination"); + + if (mainHeadingElement && paginationElement) { + this.headerHeight = + mainHeadingElement.clientHeight + + paginationElement.clientHeight; + } else { + console.error( + "Could not find main-heading and/or pagination elements" + ); + } + if (!this.rowHeight) { + throw new Error("Row height is not properly configured"); + } + + this.availableHeight = + window.innerHeight - this.headerHeight - this.rowHeight * 2; + this.numRows = Math.floor(this.availableHeight / this.rowHeight); + + if (this.numRows <= 0) { + console.log( + "Window size too small, setting minimum number of rows to 1" + ); + this.numRows = 1; + } + + // Calculating new values without modifying the state immediately. + let newFrom = this.from; + let newTo = this.from + this.numRows - 1; + + // If it's the first set of records ("first page"), start from 0 and populate the whole window size. + if (this.from === 0) { + newFrom = 0; + newTo = this.numRows - 1; + } + + // Ensure `newTo` doesn't exceed totalRecordCount and adjust `newFrom` accordingly, + // meaning populate the whole window size. + if (newTo >= this.totalRecordCount) { + newTo = this.totalRecordCount - 1; + newFrom = newTo - this.numRows + 1; + } + + // Check if the highlighted ID is currently between from and to, + // too enable priority functionality (always visible in the window). + const highlightedId = this.getHighlightedId(); + if ( + highlightedId !== null && + highlightedId >= this.from && + highlightedId <= this.to + ) { + // If newTo would be smaller than highlightedId, adjust to keep highlightedId in view. + if (newTo < highlightedId) { + newTo = highlightedId; + newFrom = newTo - this.numRows + 1; + } + } + + // Now, after all conditions have been checked, set the state. + this.setFrom(newFrom); + this.setTo(newTo); + } catch (error) { + console.error( + `Error in adjustWindowSize: ${ + error instanceof Error ? error.message : error + }` + ); + } + } + + async retrieveRecords(): Promise { + try { + this.records = await this.apiManager.fetchRecords( + this.from, + this.to + ); + } catch (error) { + console.error( + `Error retrieving records: ${ + error instanceof Error ? error.message : error + }` + ); + } + } } diff --git a/stylesheet.css b/stylesheet.css index 8c1c87b9..90760bd5 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,101 +1,98 @@ -@import url("https://fonts.googleapis.com/css2?family=Orbitron&display=swap"); - #main-heading { - font-family: "Orbitron", sans-serif; - font-size: 2.5em; - font-weight: bold; - text-align: center; - margin: 10px 0; - color: #333; - text-shadow: #00ff00; - cursor: pointer; + font-family: "Agency FB", sans-serif; + font-size: 2.5em; + font-weight: bold; + text-align: center; + margin: 10px 0; + color: #333; + text-shadow: #00ff00; + cursor: pointer; } #main-container { - margin: 0 auto; - background-color: #fff; + margin: 0 auto; + background-color: #fff; } html, body { - font-family: "SF Pro Text", "Helvetica Neue", Helvetica, Arial, sans-serif; - color: #333; - margin-bottom: 0; - overflow: hidden; + font-family: "SF Pro Text", "Helvetica Neue", Helvetica, Arial, sans-serif; + color: #333; + margin-bottom: 0; + overflow: hidden; } th { - font-family: "Orbitron", sans-serif; - text-align: center; - font-size: 16px; - border: 1px solid #a1e3a1; - background-color: #333333; - color: #4caf50; + font-family: "Agency FB", sans-serif; + text-align: center; + font-size: 16px; + border: 1px solid #a1e3a1; + background-color: #333333; + color: #4caf50; } td { - font-family: "Orbitron", sans-serif; - font-size: 14px; - border: 1px solid #a1e3a1; - text-align: center; - color: #333333; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; + font-family: "Agency FB", sans-serif; + font-size: 14px; + border: 1px solid #a1e3a1; + text-align: center; + color: #333333; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; } table { - border-collapse: collapse; + border-collapse: collapse; } #myTable { - table-layout: fixed; + table-layout: fixed; - width: 100%; - height: 100%; - border: 1px solid #a1e3a1; - border-radius: 12px; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + width: 100%; + height: 100%; + border: 1px solid #a1e3a1; + border-radius: 12px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .highlight { - background-color: #00ff00 !important; - color: #4caf50 !important; /* Added this line to make the text color green */ + background-color: #00ff00; + color: #4caf50; } .pagination-1 { - text-align: center; - padding-top: 25px; - padding-bottom: 25px; - font-family: "Orbitron", sans-serif; - /* white-space:nowrap; */ + text-align: center; + padding-top: 25px; + padding-bottom: 25px; + font-family: "Agency FB", sans-serif; } button { - padding: 10px 20px; - border: 1px solid #00ff00; - background-color: #1e1e1e; /* Dark Grey almost Black */ - color: #00ff00; /* Bright green like old school terminals */ - border-radius: 5px; - font-family: "Orbitron", sans-serif; - cursor: pointer; - transition: background-color 0.3s; + padding: 10px 20px; + border: 1px solid #00ff00; + background-color: #1e1e1e; + color: #00ff00; + border-radius: 5px; + font-family: "Agency FB", sans-serif; + cursor: pointer; + transition: background-color 0.3s; } button:disabled { - background-color: #555; /* Mid-grey for disabled buttons */ - color: #ccc; /* light grey text */ + background-color: #555; + color: #ccc; } button:hover:not(:disabled) { - background-color: #333; /* Slightly lighter dark grey */ + background-color: #333; } #filterInput { - padding: 10px; - border: 1px solid #00ff00; /* Bright green border */ - border-radius: 5px; - font-family: "Orbitron", sans-serif; - color: #00ff00; /* Bright green text */ - background-color: #1e1e1e; /* Dark background */ + padding: 10px; + border: 1px solid #00ff00; + border-radius: 5px; + font-family: "Agency FB", sans-serif; + color: #00ff00; + background-color: #1e1e1e; } diff --git a/views.js.map b/views.js.map index 09816b2a..aac1caad 100644 --- a/views.js.map +++ b/views.js.map @@ -1 +1 @@ -{"version":3,"file":"views.js","sourceRoot":"","sources":["views.ts"],"names":[],"mappings":";AAAA,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEhB;;;GAGG;AAEH;IAGE,uBAAY,YAA0B;QACpC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACnC,CAAC;IAED;;;OAGG;IACG,qCAAa,GAAnB;;;;;;;wBAEU,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;wBACvD,IAAI,WAAW,KAAK,IAAI,EAAE;4BACxB,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;yBACrC;wBAED,qBAAM,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,EAAA;;wBAAzC,SAAyC,CAAC;wBACpC,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;wBAE/C,IAAI,OAAO,KAAK,IAAI,EAAE;4BACpB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;yBAC7B;;;;wBAED,OAAO,CAAC,KAAK,CAAC,iCAA+B,OAAO,CAAC,CAAC;;;;;;KAEzD;IAED,yCAAiB,GAAjB,UAAkB,WAAqB;QACrC,IAAI;YACF,IAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAC9C,IAAI,KAAK,KAAK,IAAI,EAAE;gBAClB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;aAC5C;YAED,IAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YACzC,KAAyB,UAAW,EAAX,2BAAW,EAAX,yBAAW,EAAX,IAAW,EAAE;gBAAjC,IAAM,UAAU,oBAAA;gBACnB,IAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;gBAC1C,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;gBAC9B,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;aACvB;YACD,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YAEvB,IAAI,CAAC,eAAe,EAAE,CAAC;SACxB;QAAC,OAAO,KAAK,EAAE;YACd,IAAI,KAAK,YAAY,KAAK,EAAE;gBAC1B,OAAO,CAAC,KAAK,CAAC,wBAAsB,KAAK,CAAC,OAAS,CAAC,CAAC;aACtD;iBAAM;gBACL,OAAO,CAAC,KAAK,CAAC,gCAA8B,KAAO,CAAC,CAAC;aACtD;SACF;IACH,CAAC;IAED,2CAA2C;IAC3C,uCAAe,GAAf;QACE,IAAI;YACF,IAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;YAEjD,IAAI,CAAC,KAAK,EAAE;gBACV,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;aACvD;YAED,IAAM,WAAW,GAAG,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACjD,IAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC;YACnC,IAAM,UAAQ,GAAG,GAAG,GAAG,OAAO,CAAC;YAE/B,WAAW,CAAC,OAAO,CAAC,UAAC,UAAmB;gBACrC,UAA0B,CAAC,KAAK,CAAC,KAAK,GAAM,UAAQ,MAAG,CAAC;YAC3D,CAAC,CAAC,CAAC;SACJ;QAAC,OAAO,KAAK,EAAE;YACd,OAAO,CAAC,KAAK,CAAC,kCAAgC,KAAO,CAAC,CAAC;SACxD;IACH,CAAC;IAED,2FAA2F;IAC3F,qCAAa,GAAb,UAAc,OAA0B,EAAE,WAAiC;QAAjC,4BAAA,EAAA,kBAAiC;QACzE,+DAA+D;QAC/D,WAAW,GAAG,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC;QAClE,IAAI;YACF,IAAI,OAAO,KAAK,IAAI,EAAE;gBACpB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;aAC1C;YAED,IAAM,OAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAC9C,IAAI,OAAK,KAAK,IAAI,EAAE;gBAClB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;aAC1C;YAED,OAAK,CAAC,SAAS,GAAG,EAAE,CAAC;YAErB,OAAO,CAAC,OAAO,CAAC,UAAC,MAAM;gBACrB,IAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;gBACzC,IACE,WAAW,KAAK,IAAI;oBACpB,MAAM,CAAC,MAAM,GAAG,CAAC;oBACjB,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC,KAAK,WAAW,EAClD;oBACA,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;iBAChC;gBACD,MAAM,CAAC,OAAO,CAAC,UAAC,IAAI;oBAClB,IAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;oBACxC,EAAE,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACjC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;gBACtB,CAAC,CAAC,CAAC;gBACH,OAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC;SACJ;QAAC,OAAO,KAAK,EAAE;YACd,OAAO,CAAC,KAAK,CAAC,wBAAsB,KAAO,CAAC,CAAC;SAC9C;IACH,CAAC;IACH,oBAAC;AAAD,CAAC,AA/GD,IA+GC"} \ No newline at end of file +{"version":3,"file":"views.js","sourceRoot":"","sources":["views.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/views.ts b/views.ts index 601b020e..81e1d1c2 100644 --- a/views.ts +++ b/views.ts @@ -6,114 +6,117 @@ */ class TableRenderer { - private stateManager: StateManager; - - constructor(stateManager: StateManager) { - this.stateManager = stateManager; - } - - /** - * Renders the initial table layout including column names and initial data set. - * @param {StateManager} stateManager - The manager to fetch state from. - */ - async initialRender(): Promise { - try { - const columnNames = this.stateManager.getColumnNames(); - if (columnNames !== null) { - this.renderColumnNames(columnNames); - } - - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.renderRecords(records); - } - } catch (error) { - console.error(`Error during initialRender: ${error}`); - } - } - - renderColumnNames(columnNames: string[]): void { - try { - const thead = document.querySelector("thead"); - if (thead === null) { - throw new Error("Table header not found."); - } - - const row = document.createElement("tr"); - for (const columnName of columnNames) { - const cell = document.createElement("th"); - cell.textContent = columnName; - row.appendChild(cell); - } - thead.appendChild(row); - - this.setColumnWidths(); - } catch (error) { - if (error instanceof Error) { - console.error(`An error occurred: ${error.message}`); - } else { - console.error(`An unknown error occurred: ${error}`); - } - } - } - - // Sets the widths of table columns evenly. - setColumnWidths(): void { - try { - const table = document.getElementById("myTable"); - - if (!table) { - throw new Error('Table with id "myTable" not found.'); - } - - const headerCells = table.querySelectorAll("th"); - const numCols = headerCells.length; - const colWidth = 100 / numCols; - - headerCells.forEach((headerCell: Element) => { - (headerCell as HTMLElement).style.width = `${colWidth}%`; - }); - } catch (error) { - console.error(`Error setting column widths: ${error}`); - } - } - - //Populates the table body with records. Optionally highlights a specified row if searched. - renderRecords(records: CityData[] | null, highlightId: number | null = null) { - // Use the state's highlightedId if no highlightId is provided. - highlightId = highlightId ?? this.stateManager.getHighlightedId(); - try { - if (records === null) { - throw new Error("No records to render."); - } - - const tbody = document.querySelector("tbody"); - if (tbody === null) { - throw new Error("Table body not found."); - } - - tbody.innerHTML = ""; - - records.forEach((record) => { - const row = document.createElement("tr"); - if ( - highlightId !== null && - record.length > 0 && - parseInt(record[0].toString(), 10) === highlightId - ) { - row.classList.add("highlight"); - } - record.forEach((cell) => { - const td = document.createElement("td"); - td.textContent = cell.toString(); - row.appendChild(td); - }); - tbody.appendChild(row); - }); - } catch (error) { - console.error(`An error occurred: ${error}`); - } - } + private stateManager: StateManager; + + constructor(stateManager: StateManager) { + this.stateManager = stateManager; + } + + /** + * Renders the initial table layout including column names and initial data set. + * @param {StateManager} stateManager - The manager to fetch state from. + */ + async initialRender(): Promise { + try { + const columnNames = this.stateManager.getColumnNames(); + if (columnNames !== null) { + this.renderColumnNames(columnNames); + } + + await this.stateManager.retrieveRecords(); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.renderRecords(records); + } + } catch (error) { + console.error(`Error during initialRender: ${error}`); + } + } + + renderColumnNames(columnNames: string[]): void { + try { + const thead = document.querySelector("thead"); + if (thead === null) { + throw new Error("Table header not found."); + } + + const row = document.createElement("tr"); + for (const columnName of columnNames) { + const cell = document.createElement("th"); + cell.textContent = columnName; + row.appendChild(cell); + } + thead.appendChild(row); + + this.setColumnWidths(); + } catch (error) { + if (error instanceof Error) { + console.error(`An error occurred: ${error.message}`); + } else { + console.error(`An unknown error occurred: ${error}`); + } + } + } + + // Sets the widths of table columns evenly. + setColumnWidths(): void { + try { + const table = document.getElementById("myTable"); + + if (!table) { + throw new Error('Table with id "myTable" not found.'); + } + + const headerCells = table.querySelectorAll("th"); + const numCols = headerCells.length; + const colWidth = 100 / numCols; + + headerCells.forEach((headerCell: Element) => { + (headerCell as HTMLElement).style.width = `${colWidth}%`; + }); + } catch (error) { + console.error(`Error setting column widths: ${error}`); + } + } + + //Populates the table body with records. Optionally highlights a specified row if searched. + renderRecords( + records: CityData[] | null, + highlightId: number | null = null + ) { + // Use the state's highlightedId if no highlightId is provided. + highlightId = highlightId ?? this.stateManager.getHighlightedId(); + try { + if (records === null) { + throw new Error("No records to render."); + } + + const tbody = document.querySelector("tbody"); + if (tbody === null) { + throw new Error("Table body not found."); + } + + tbody.innerHTML = ""; + + records.forEach((record) => { + const row = document.createElement("tr"); + if ( + highlightId !== null && + record.length > 0 && + parseInt(record[0].toString(), 10) === highlightId + ) { + row.classList.add("highlight"); + } + record.forEach((cell) => { + const td = document.createElement("td"); + td.textContent = cell.toString(); + row.appendChild(td); + }); + tbody.appendChild(row); + }); + } catch (error) { + console.error(`An error occurred: ${error}`); + } + } } From c316caa9cbec7f2e1d3ba4f51b50c0e9234fd991 Mon Sep 17 00:00:00 2001 From: riaan Date: Fri, 6 Oct 2023 14:50:33 +0200 Subject: [PATCH 26/27] Progress Save Rev 1.20 --- controllers.js | 103 ++++++++++++++++++------------ controllers.js.map | 2 +- controllers.ts | 153 ++++++++++++++++++++++++++++----------------- data.js | 2 +- data.js.map | 2 +- data.ts | 2 +- model.js | 6 +- model.js.map | 2 +- model.ts | 14 ++++- views.js | 2 +- views.js.map | 2 +- views.ts | 3 +- 12 files changed, 183 insertions(+), 110 deletions(-) diff --git a/controllers.js b/controllers.js index 2e645c25..b20ee039 100644 --- a/controllers.js +++ b/controllers.js @@ -1,5 +1,5 @@ "use strict"; -//*** Controllers ***/ +/*** Controllers ***/ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -36,14 +36,14 @@ var __generator = (this && this.__generator) || function (thisArg, body) { if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; -// Handles window resize events to update the view of the application. +/** Handles window resize events to update the view of the application. */ var WindowResizeHandler = /** @class */ (function () { /** * @param {TableRenderer} tableRenderer - Used for re-rendering table data. * @param {StateManager} stateManager - State control for retrieving/updating application data. */ function WindowResizeHandler(tableRenderer, stateManager, paginationManager) { - this.debouncedUpdate = this.debounce(this.updateAfterResize.bind(this), 350); + this.debouncedUpdate = this.debounce(this.updateAfterResize.bind(this), 250); this.paginationManager = paginationManager; this.tableRenderer = tableRenderer; this.stateManager = stateManager; @@ -57,7 +57,7 @@ var WindowResizeHandler = /** @class */ (function () { WindowResizeHandler.prototype.handleResize = function () { this.debouncedUpdate(); }; - //Debounce function to reduce the number of function calls while user is dragging the browser window. + // Debounce function to reduce the number of function calls while user is dragging the browser window. WindowResizeHandler.prototype.debounce = function (func, delay) { var timeout = null; return function () { @@ -77,13 +77,16 @@ var WindowResizeHandler = /** @class */ (function () { }; WindowResizeHandler.prototype.updateAfterResize = function () { return __awaiter(this, void 0, void 0, function () { - var records, error_1; + var records; return __generator(this, function (_a) { switch (_a.label) { case 0: - _a.trys.push([0, 2, , 3]); this.stateManager.adjustWindowSize(); - return [4 /*yield*/, this.stateManager.retrieveRecords()]; + return [4 /*yield*/, this.stateManager.retrieveRecords().catch(function (error) { + console.error("Error retrieving records: " + (error instanceof Error ? error.message : error)); + alert("An error occurred while retrieving records. Please try again later."); + return; + })]; case 1: _a.sent(); records = this.stateManager.getRecords(); @@ -91,19 +94,14 @@ var WindowResizeHandler = /** @class */ (function () { this.tableRenderer.renderRecords(records); } this.paginationManager.updateButtonStates(); - return [3 /*break*/, 3]; - case 2: - error_1 = _a.sent(); - console.error("Error in updateAfterResize: " + (error_1 instanceof Error ? error_1.message : error_1)); - return [3 /*break*/, 3]; - case 3: return [2 /*return*/]; + return [2 /*return*/]; } }); }); }; return WindowResizeHandler; }()); -// Handles pagination and search functionalities for the application's table view. +/** Handles pagination and search functionalities for the application's table view. */ var PaginationManager = /** @class */ (function () { /** * @param {TableRenderer} tableRenderer - Used for re-rendering table data. @@ -112,16 +110,36 @@ var PaginationManager = /** @class */ (function () { function PaginationManager(tableRenderer, stateManager) { this.tableRenderer = tableRenderer; this.stateManager = stateManager; - this.prevButton = document.getElementById("prevPage"); - this.nextButton = document.getElementById("nextPage"); - this.searchButton = document.getElementById("searchButton"); - this.mainHeading = document.getElementById("main-heading"); - this.filterInput = document.getElementById("filterInput"); - this.errorMessage = document.getElementById("errorMessage"); + // DOM elements required for pagination and search. + this.prevButton = null; + this.nextButton = null; + this.searchButton = null; + this.mainHeading = null; + this.filterInput = null; + this.errorMessage = null; + this.initializeDOMElements(); // Attach event listeners for buttons and other UI elements. this.setupEventListeners(); } - // Attaches event listeners to the relevant DOM elements to handle user interactions. + PaginationManager.prototype.initializeDOMElements = function () { + this.prevButton = this.retrieveElement("prevPage", "button"); + this.nextButton = this.retrieveElement("nextPage", "button"); + this.searchButton = this.retrieveElement("searchButton", "button"); + this.mainHeading = this.retrieveElement("main-heading", "heading"); + this.filterInput = this.retrieveElement("filterInput", "input box"); + this.errorMessage = this.retrieveElement("errorMessage", "error message"); + }; + PaginationManager.prototype.retrieveElement = function (id, description) { + var element = document.getElementById(id); + if (!element) { + console.error("Element with ID '" + id + "' not found"); + if (description) { + alert("A critical " + description + " is missing on the page. Some functionalities might not work as expected."); + } + } + return element; + }; + /** Attaches event listeners to the relevant DOM elements to handle user interactions. */ PaginationManager.prototype.setupEventListeners = function () { var _this = this; if (this.prevButton) { @@ -141,7 +159,6 @@ var PaginationManager = /** @class */ (function () { } if (this.filterInput) { this.filterInput.addEventListener("keyup", function (event) { - // Check if the "Enter" key was pressed if (event.key === "Enter") { _this.searchById(); } @@ -156,7 +173,7 @@ var PaginationManager = /** @class */ (function () { this.setupLiveValidation(); } }; - // Navigates to the home page by reloading the window. + /** Navigates to the home page by reloading the window.*/ PaginationManager.prototype.navigateToHome = function () { try { window.location.reload(); @@ -166,10 +183,10 @@ var PaginationManager = /** @class */ (function () { alert("Failed to reload the page. Please try again."); } }; - // Fetches the next set of records and updates the view. + /** Fetches the next set of records and updates the view. */ PaginationManager.prototype.incrementPage = function () { return __awaiter(this, void 0, void 0, function () { - var records, error_2; + var records, error_1; return __generator(this, function (_a) { switch (_a.label) { case 0: @@ -185,18 +202,18 @@ var PaginationManager = /** @class */ (function () { this.updateButtonStates(); return [3 /*break*/, 3]; case 2: - error_2 = _a.sent(); - console.error("Unexpected error in incrementPage: " + (error_2 instanceof Error ? error_2.message : error_2)); + error_1 = _a.sent(); + console.error("Unexpected error in incrementPage: " + (error_1 instanceof Error ? error_1.message : error_1)); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }; - // Fetches the previous set of records and updates the view. + /** Fetches the previous set of records and updates the view. */ PaginationManager.prototype.decrementPage = function () { return __awaiter(this, void 0, void 0, function () { - var records, error_3; + var records, error_2; return __generator(this, function (_a) { switch (_a.label) { case 0: @@ -212,22 +229,25 @@ var PaginationManager = /** @class */ (function () { this.updateButtonStates(); return [3 /*break*/, 3]; case 2: - error_3 = _a.sent(); - console.error("Error in decrementPage: " + (error_3 instanceof Error ? error_3.message : error_3)); + error_2 = _a.sent(); + console.error("Error in decrementPage: " + (error_2 instanceof Error ? error_2.message : error_2)); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }; - // Searches for a record by its ID and updates the view. + /** Searches for a record by its ID and updates the view. */ PaginationManager.prototype.searchById = function () { return __awaiter(this, void 0, void 0, function () { - var searchValue, records, error_4; + var searchValue, records, error_3; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); + if (!this.filterInput) { + throw new Error("Filter input element is missing"); + } searchValue = parseInt(this.filterInput.value, 10); if (isNaN(searchValue)) { throw new Error("Invalid search value or none"); @@ -243,15 +263,16 @@ var PaginationManager = /** @class */ (function () { this.updateButtonStates(); return [3 /*break*/, 3]; case 2: - error_4 = _a.sent(); - console.error("Error in searchById function: " + (error_4 instanceof Error ? error_4.message : error_4)); + error_3 = _a.sent(); + console.error("Error in searchById function: " + (error_3 instanceof Error ? error_3.message : error_3)); + alert("A Serious Error ocurred, please try again later"); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }; - // Validates input for the search bar in real-time. + /** Validates input for the search bar in real-time. */ PaginationManager.prototype.setupLiveValidation = function () { var _this = this; if (!this.filterInput || !this.errorMessage) { @@ -259,7 +280,8 @@ var PaginationManager = /** @class */ (function () { return; } this.filterInput.addEventListener("input", function () { - var inputValue = _this.filterInput.value; + var inputValue = _this.filterInput.value; // The "!" here asserts non-null, because I already checked for null above. + var maxValue = _this.stateManager.getTotalRecordCount() - 1; if (inputValue.length === 0) { _this.errorMessage.textContent = ""; } @@ -267,16 +289,19 @@ var PaginationManager = /** @class */ (function () { inputValue.length > 6 || !/^\d+$/.test(inputValue)) { _this.errorMessage.textContent = - "Invalid input. Please enter a number between 0 and 999 999."; + "Invalid input. Please enter a number between 0 and " + maxValue + "."; } else { _this.errorMessage.textContent = ""; } }); }; - // Updates the state of the pagination buttons based on the current view. + /** Updates the state of the pagination buttons based on the current view. */ PaginationManager.prototype.updateButtonStates = function () { try { + if (!this.prevButton || !this.nextButton) { + throw new Error("Button elements are missing"); + } var from = this.stateManager.getFrom(); var to = this.stateManager.getTo(); var totalRecordCount = this.stateManager.getTotalRecordCount(); diff --git a/controllers.js.map b/controllers.js.map index 38acc6b0..f3cf8e8a 100644 --- a/controllers.js.map +++ b/controllers.js.map @@ -1 +1 @@ -{"version":3,"file":"controllers.js","sourceRoot":"","sources":["controllers.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"controllers.js","sourceRoot":"","sources":["controllers.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/controllers.ts b/controllers.ts index 05773ce6..8997585f 100644 --- a/controllers.ts +++ b/controllers.ts @@ -1,6 +1,6 @@ -//*** Controllers ***/ +/*** Controllers ***/ -// Handles window resize events to update the view of the application. +/** Handles window resize events to update the view of the application. */ class WindowResizeHandler { private debouncedUpdate: Function; private paginationManager: PaginationManager; @@ -19,7 +19,7 @@ class WindowResizeHandler { ) { this.debouncedUpdate = this.debounce( this.updateAfterResize.bind(this), - 350 + 250 ); this.paginationManager = paginationManager; this.tableRenderer = tableRenderer; @@ -37,7 +37,7 @@ class WindowResizeHandler { this.debouncedUpdate(); } - //Debounce function to reduce the number of function calls while user is dragging the browser window. + // Debounce function to reduce the number of function calls while user is dragging the browser window. debounce(func: Function, delay: number): Function { let timeout: ReturnType | null = null; return (...args: any[]) => { @@ -53,67 +53,95 @@ class WindowResizeHandler { } async updateAfterResize(): Promise { - try { - this.stateManager.adjustWindowSize(); - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); - - if (records !== null) { - this.tableRenderer.renderRecords(records); - } - this.paginationManager.updateButtonStates(); - } catch (error) { + this.stateManager.adjustWindowSize(); + await this.stateManager.retrieveRecords().catch((error) => { console.error( - `Error in updateAfterResize: ${error instanceof Error ? error.message : error + `Error retrieving records: ${ + error instanceof Error ? error.message : error }` ); + alert( + "An error occurred while retrieving records. Please try again later." + ); + return; + }); + + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); } + this.paginationManager.updateButtonStates(); } } -// Handles pagination and search functionalities for the application's table view. +/** Handles pagination and search functionalities for the application's table view. */ class PaginationManager { // DOM elements required for pagination and search. - private prevButton: HTMLButtonElement; - private nextButton: HTMLButtonElement; - private searchButton: HTMLButtonElement; - private mainHeading: HTMLElement; - private filterInput: HTMLInputElement; - private errorMessage: HTMLElement; + private prevButton: HTMLButtonElement | null = null; + private nextButton: HTMLButtonElement | null = null; + private searchButton: HTMLButtonElement | null = null; + private mainHeading: HTMLElement | null = null; + private filterInput: HTMLInputElement | null = null; + private errorMessage: HTMLElement | null = null; /** * @param {TableRenderer} tableRenderer - Used for re-rendering table data. * @param {StateManager} stateManager - State control for retrieving/updating application data. */ - constructor( private tableRenderer: TableRenderer, private stateManager: StateManager ) { - this.prevButton = document.getElementById( - "prevPage" + this.initializeDOMElements(); + // Attach event listeners for buttons and other UI elements. + this.setupEventListeners(); + } + + private initializeDOMElements(): void { + this.prevButton = this.retrieveElement( + "prevPage", + "button" ) as HTMLButtonElement; - this.nextButton = document.getElementById( - "nextPage" + this.nextButton = this.retrieveElement( + "nextPage", + "button" ) as HTMLButtonElement; - this.searchButton = document.getElementById( - "searchButton" + this.searchButton = this.retrieveElement( + "searchButton", + "button" ) as HTMLButtonElement; - this.mainHeading = document.getElementById( - "main-heading" + this.mainHeading = this.retrieveElement( + "main-heading", + "heading" ) as HTMLElement; - this.filterInput = document.getElementById( - "filterInput" + this.filterInput = this.retrieveElement( + "filterInput", + "input box" ) as HTMLInputElement; - this.errorMessage = document.getElementById( - "errorMessage" + this.errorMessage = this.retrieveElement( + "errorMessage", + "error message" ) as HTMLElement; + } - // Attach event listeners for buttons and other UI elements. - this.setupEventListeners(); + private retrieveElement( + id: string, + description?: string + ): HTMLElement | null { + const element = document.getElementById(id); + if (!element) { + console.error(`Element with ID '${id}' not found`); + if (description) { + alert( + `A critical ${description} is missing on the page. Some functionalities might not work as expected.` + ); + } + } + return element; } - // Attaches event listeners to the relevant DOM elements to handle user interactions. + /** Attaches event listeners to the relevant DOM elements to handle user interactions. */ private setupEventListeners(): void { if (this.prevButton) { this.prevButton.addEventListener("click", () => @@ -135,7 +163,6 @@ class PaginationManager { if (this.filterInput) { this.filterInput.addEventListener("keyup", (event) => { - // Check if the "Enter" key was pressed if (event.key === "Enter") { this.searchById(); } @@ -153,20 +180,21 @@ class PaginationManager { } } - // Navigates to the home page by reloading the window. + /** Navigates to the home page by reloading the window.*/ navigateToHome(): void { try { window.location.reload(); } catch (error) { console.error( - `Error while navigating to home: ${error instanceof Error ? error.message : error + `Error while navigating to home: ${ + error instanceof Error ? error.message : error }` ); alert("Failed to reload the page. Please try again."); } } - // Fetches the next set of records and updates the view. + /** Fetches the next set of records and updates the view. */ async incrementPage(): Promise { try { this.stateManager.goToNextPage(); @@ -179,13 +207,14 @@ class PaginationManager { this.updateButtonStates(); } catch (error) { console.error( - `Unexpected error in incrementPage: ${error instanceof Error ? error.message : error + `Unexpected error in incrementPage: ${ + error instanceof Error ? error.message : error }` ); } } - // Fetches the previous set of records and updates the view. + /** Fetches the previous set of records and updates the view. */ async decrementPage(): Promise { try { this.stateManager.goToPreviousPage(); @@ -199,15 +228,20 @@ class PaginationManager { this.updateButtonStates(); } catch (error) { console.error( - `Error in decrementPage: ${error instanceof Error ? error.message : error + `Error in decrementPage: ${ + error instanceof Error ? error.message : error }` ); } } - // Searches for a record by its ID and updates the view. + /** Searches for a record by its ID and updates the view. */ async searchById(): Promise { try { + if (!this.filterInput) { + throw new Error("Filter input element is missing"); + } + const searchValue = parseInt(this.filterInput.value, 10); if (isNaN(searchValue)) { throw new Error("Invalid search value or none"); @@ -225,13 +259,15 @@ class PaginationManager { this.updateButtonStates(); } catch (error) { console.error( - `Error in searchById function: ${error instanceof Error ? error.message : error + `Error in searchById function: ${ + error instanceof Error ? error.message : error }` ); + alert("A Serious Error ocurred, please try again later"); } } - // Validates input for the search bar in real-time. + /** Validates input for the search bar in real-time. */ setupLiveValidation(): void { if (!this.filterInput || !this.errorMessage) { console.error( @@ -241,26 +277,30 @@ class PaginationManager { } this.filterInput.addEventListener("input", () => { - const inputValue = this.filterInput.value; - + const inputValue = this.filterInput!.value; // The "!" here asserts non-null, because I already checked for null above. + const maxValue = this.stateManager.getTotalRecordCount() - 1; if (inputValue.length === 0) { - this.errorMessage.textContent = ""; + this.errorMessage!.textContent = ""; } else if ( inputValue.length < 1 || inputValue.length > 6 || !/^\d+$/.test(inputValue) ) { - this.errorMessage.textContent = - "Invalid input. Please enter a number between 0 and 999 999."; + this.errorMessage!.textContent = + `Invalid input. Please enter a number between 0 and ${maxValue}.`; } else { - this.errorMessage.textContent = ""; + this.errorMessage!.textContent = ""; } }); } - // Updates the state of the pagination buttons based on the current view. + /** Updates the state of the pagination buttons based on the current view. */ public updateButtonStates(): void { try { + if (!this.prevButton || !this.nextButton) { + throw new Error("Button elements are missing"); + } + const from = this.stateManager.getFrom(); const to = this.stateManager.getTo(); const totalRecordCount = this.stateManager.getTotalRecordCount(); @@ -269,7 +309,8 @@ class PaginationManager { this.nextButton.disabled = to === totalRecordCount - 1; } catch (error) { console.error( - `Unexpected error in updateButtonStates: ${error instanceof Error ? error.message : error + `Unexpected error in updateButtonStates: ${ + error instanceof Error ? error.message : error }` ); } diff --git a/data.js b/data.js index 0e70942d..ce9cdd29 100644 --- a/data.js +++ b/data.js @@ -36,7 +36,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; -// Manages API requests for fetching record count, column names, and data records. +/** Manages API requests for fetching record count, column names, and data records.*/ var ApiManager = /** @class */ (function () { function ApiManager() { this.totalRecordCount = 0; diff --git a/data.js.map b/data.js.map index 8b31eb12..3ae66c64 100644 --- a/data.js.map +++ b/data.js.map @@ -1 +1 @@ -{"version":3,"file":"data.js","sourceRoot":"","sources":["data.ts"],"names":[],"mappings":";AAAA,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIf,kFAAkF;AAClF;IAIC;QACC,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IACzB,CAAC;IAEK,0CAAqB,GAA3B;;;;;;;wBAEmB,qBAAM,KAAK,CAAC,mCAAmC,CAAC,EAAA;;wBAA3D,QAAQ,GAAG,SAAgD;wBACjE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BACjB,MAAM,IAAI,KAAK,CACd,yCAAuC,QAAQ,CAAC,UAAY,CAC5D,CAAC;yBACF;wBACoB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAApC,IAAI,GAAW,SAAqB;wBAC1C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;;;;wBAE7B,OAAO,CAAC,KAAK,CAAC,wCAAsC,OAAO,CAAC,CAAC;;;;;;KAE9D;IAEK,qCAAgB,GAAtB;;;;;;;wBAEmB,qBAAM,KAAK,CAAC,+BAA+B,CAAC,EAAA;;wBAAvD,QAAQ,GAAG,SAA4C;wBAC7D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BACjB,MAAM,IAAI,KAAK,CACd,mCAAiC,QAAQ,CAAC,UAAY,CACtD,CAAC;yBACF;wBACsB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAtC,IAAI,GAAa,SAAqB;wBAC5C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;;;;wBAExB,OAAO,CAAC,KAAK,CAAC,kCAAgC,OAAO,CAAC,CAAC;;;;;;KAExD;IAEK,iCAAY,GAAlB,UAAmB,IAAY,EAAE,EAAU;;;;;;;wBAExB,qBAAM,KAAK,CAC3B,wCAAsC,IAAI,YAAO,EAAI,CACrD,EAAA;;wBAFK,QAAQ,GAAG,SAEhB;wBACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BACjB,MAAM,IAAI,KAAK,CACd,8BAA4B,QAAQ,CAAC,UAAY,CACjD,CAAC;yBACF;wBACwB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAxC,IAAI,GAAe,SAAqB;wBAC9C,sBAAO,IAAI,EAAC;;;wBAEZ,OAAO,CAAC,KAAK,CAAC,6BAA2B,OAAO,CAAC,CAAC;wBAClD,sBAAO,IAAI,EAAC;;;;;KAEb;IACF,iBAAC;AAAD,CAAC,AAxDD,IAwDC"} \ No newline at end of file +{"version":3,"file":"data.js","sourceRoot":"","sources":["data.ts"],"names":[],"mappings":";AAAA,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIf,qFAAqF;AACrF;IAIC;QACC,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IACzB,CAAC;IAEK,0CAAqB,GAA3B;;;;;;;wBAEmB,qBAAM,KAAK,CAAC,mCAAmC,CAAC,EAAA;;wBAA3D,QAAQ,GAAG,SAAgD;wBACjE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BACjB,MAAM,IAAI,KAAK,CACd,yCAAuC,QAAQ,CAAC,UAAY,CAC5D,CAAC;yBACF;wBACoB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAApC,IAAI,GAAW,SAAqB;wBAC1C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;;;;wBAE7B,OAAO,CAAC,KAAK,CAAC,wCAAsC,OAAO,CAAC,CAAC;;;;;;KAE9D;IAEK,qCAAgB,GAAtB;;;;;;;wBAEmB,qBAAM,KAAK,CAAC,+BAA+B,CAAC,EAAA;;wBAAvD,QAAQ,GAAG,SAA4C;wBAC7D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BACjB,MAAM,IAAI,KAAK,CACd,mCAAiC,QAAQ,CAAC,UAAY,CACtD,CAAC;yBACF;wBACsB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAtC,IAAI,GAAa,SAAqB;wBAC5C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;;;;wBAExB,OAAO,CAAC,KAAK,CAAC,kCAAgC,OAAO,CAAC,CAAC;;;;;;KAExD;IAEK,iCAAY,GAAlB,UAAmB,IAAY,EAAE,EAAU;;;;;;;wBAExB,qBAAM,KAAK,CAC3B,wCAAsC,IAAI,YAAO,EAAI,CACrD,EAAA;;wBAFK,QAAQ,GAAG,SAEhB;wBACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BACjB,MAAM,IAAI,KAAK,CACd,8BAA4B,QAAQ,CAAC,UAAY,CACjD,CAAC;yBACF;wBACwB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAxC,IAAI,GAAe,SAAqB;wBAC9C,sBAAO,IAAI,EAAC;;;wBAEZ,OAAO,CAAC,KAAK,CAAC,6BAA2B,OAAO,CAAC,CAAC;wBAClD,sBAAO,IAAI,EAAC;;;;;KAEb;IACF,iBAAC;AAAD,CAAC,AAxDD,IAwDC"} \ No newline at end of file diff --git a/data.ts b/data.ts index 2fe54e5c..2dc41e88 100644 --- a/data.ts +++ b/data.ts @@ -2,7 +2,7 @@ type CityData = [number, string, number]; -// Manages API requests for fetching record count, column names, and data records. +/** Manages API requests for fetching record count, column names, and data records.*/ class ApiManager { totalRecordCount: number; columnNames: string[] | null; diff --git a/model.js b/model.js index 0402bc9f..c7d86e16 100644 --- a/model.js +++ b/model.js @@ -36,7 +36,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; -// Manages the application's state for data display, navigation, and search functionalities. +/** Manages the application's state for data display, navigation, and search functionalities. */ var StateManager = /** @class */ (function () { function StateManager(apiManager) { this.highlightedId = null; @@ -58,7 +58,7 @@ var StateManager = /** @class */ (function () { StateManager.prototype.setHighlightedId = function (value) { this.highlightedId = value; }; - // Sets up initial state, fetches record count and column names, and adjusts the display window size. + /** Sets up initial state, fetches record count and column names, and adjusts the display window size. */ StateManager.prototype.initializeState = function () { return __awaiter(this, void 0, void 0, function () { var error_1; @@ -222,7 +222,7 @@ var StateManager = /** @class */ (function () { }); }); }; - // Adjusts the available height based on window size and recalculates the number of rows. + /** Adjusts the available height based on window size and recalculates the number of rows. */ StateManager.prototype.adjustWindowSize = function () { try { if (typeof window === "undefined" || !window.innerHeight) { diff --git a/model.js.map b/model.js.map index 970e0724..f3247cfb 100644 --- a/model.js.map +++ b/model.js.map @@ -1 +1 @@ -{"version":3,"file":"model.js","sourceRoot":"","sources":["model.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"model.js","sourceRoot":"","sources":["model.ts"],"names":[],"mappings":";AAAA,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEhB,gGAAgG;AAChG;IAaC,sBAAY,UAAsB;QAZ1B,kBAAa,GAAkB,IAAI,CAAC;QAQpC,YAAO,GAAsB,IAAI,CAAC;QAElC,qBAAgB,GAAG,CAAC,CAAC;QAG5B,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QACpB,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC;QACxB,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QACZ,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;IAC3B,CAAC;IAEM,uCAAgB,GAAvB;QACC,OAAO,IAAI,CAAC,aAAa,CAAC;IAC3B,CAAC;IAEM,uCAAgB,GAAvB,UAAwB,KAAoB;QAC3C,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;IAC5B,CAAC;IAED,yGAAyG;IACnG,sCAAe,GAArB;;;;;;;wBAEE,qBAAM,IAAI,CAAC,6BAA6B,EAAE,EAAA;;wBAA1C,SAA0C,CAAC;wBAC3C,qBAAM,IAAI,CAAC,mBAAmB,EAAE,EAAA;;wBAAhC,SAAgC,CAAC;wBACjC,IAAI,CAAC,gBAAgB,EAAE,CAAC;;;;wBAExB,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,OAAK,CAAC,CAAC;;;;;;KAEnD;IAEK,0CAAmB,GAAzB;;;;;;;wBAEE,qBAAM,IAAI,CAAC,UAAU,CAAC,gBAAgB,EAAE,EAAA;;wBAAxC,SAAwC,CAAC;wBAEzC,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,KAAK,IAAI,EAAE;4BACzC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;yBAC/C;;;;wBAED,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,OAAK,CAAC,CAAC;;;;;;KAEvD;IAEK,oDAA6B,GAAnC;;;;;;;wBAEE,qBAAM,IAAI,CAAC,UAAU,CAAC,qBAAqB,EAAE,EAAA;;wBAA7C,SAA6C,CAAC;wBAC9C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC;;;;wBAEzD,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,OAAK,CAAC,CAAC;;;;;;KAEjE;IAED,0CAAmB,GAAnB;QACC,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC9B,CAAC;IAED,qCAAc,GAAd;QACC,OAAO,IAAI,CAAC,WAAW,CAAC;IACzB,CAAC;IAED,iCAAU,GAAV;QACC,OAAO,IAAI,CAAC,OAAO,CAAC;IACrB,CAAC;IAED,8BAAO,GAAP;QACC,OAAO,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IAED,8BAAO,GAAP,UAAQ,KAAa;QACpB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;IACnB,CAAC;IAED,4BAAK,GAAL;QACC,OAAO,IAAI,CAAC,EAAE,CAAC;IAChB,CAAC;IAED,4BAAK,GAAL,UAAM,KAAa;QAClB,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC;IACjB,CAAC;IAED,mCAAY,GAAZ;QACC,IAAI;YACH,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YAC5B,IAAM,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YACxB,IAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC;YAEpC,IAAM,OAAO,GAAG,IAAI,GAAG,cAAc,CAAC;YACtC,IAAM,KAAK,GAAG,OAAO,GAAG,cAAc,GAAG,CAAC,CAAC;YAE3C,oDAAoD;YACpD,IAAI,KAAK,IAAI,IAAI,CAAC,gBAAgB,EAAE;gBACnC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC;gBACtC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAG,cAAc,CAAC,CAAC;aACrD;iBAAM;gBACN,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBACtB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;aAClB;SACD;QAAC,OAAO,KAAK,EAAE;YACf,OAAO,CAAC,KAAK,CACZ,wCACC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAC7C,CACF,CAAC;SACF;IACF,CAAC;IAED,uCAAgB,GAAhB;QACC,IAAI;YACH,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YAC5B,IAAM,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YACxB,IAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC;YAEpC,IAAM,OAAO,GAAG,IAAI,GAAG,cAAc,CAAC;YACtC,IAAM,KAAK,GAAG,OAAO,GAAG,cAAc,GAAG,CAAC,CAAC;YAE3C,uCAAuC;YACvC,IAAI,OAAO,GAAG,CAAC,EAAE;gBAChB,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBAChB,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC;aAC/B;iBAAM;gBACN,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBACtB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;aAClB;SACD;QAAC,OAAO,KAAK,EAAE;YACf,OAAO,CAAC,KAAK,CACZ,iCACC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAC7C,CACF,CAAC;SACF;IACF,CAAC;IAEK,4CAAqB,GAA3B,UAA4B,EAAU;;;;;;;wBAE9B,OAAO,GAAG,EAAE,CAAC;wBACb,KAAK,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;wBAC9B,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC;wBAEpC,uDAAuD;wBACvD,IAAI,KAAK,IAAI,IAAI,CAAC,gBAAgB,EAAE;4BACnC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC;4BACtC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAG,cAAc,CAAC,CAAC;yBACrD;6BAAM;4BACN,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;4BAClB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;yBACtB;wBAED,qBAAM,IAAI,CAAC,eAAe,EAAE,EAAA;;wBAA5B,SAA4B,CAAC;;;;wBAE7B,OAAO,CAAC,KAAK,CACZ,sCACC,OAAK,YAAY,KAAK,CAAC,CAAC,CAAC,OAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAK,CAC7C,CACF,CAAC;;;;;;KAEH;IAED,6FAA6F;IAC7F,uCAAgB,GAAhB;QACC,IAAI;YACH,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;gBACzD,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;aACtD;YAED,6DAA6D;YAC7D,IAAM,kBAAkB,GAAG,QAAQ,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;YACnE,IAAM,iBAAiB,GAAG,QAAQ,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;YAEhE,IAAI,kBAAkB,IAAI,iBAAiB,EAAE;gBAC5C,IAAI,CAAC,YAAY;oBAChB,kBAAkB,CAAC,YAAY;wBAC/B,iBAAiB,CAAC,YAAY,CAAC;aAChC;iBAAM;gBACN,OAAO,CAAC,KAAK,CACZ,wDAAwD,CACxD,CAAC;aACF;YACD,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;gBACpB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;aACzD;YAED,IAAI,CAAC,eAAe;gBACnB,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;YAC7D,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;YAEjE,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,EAAE;gBACtB,OAAO,CAAC,GAAG,CACV,4DAA4D,CAC5D,CAAC;gBACF,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;aACjB;YAED,kEAAkE;YAClE,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC;YACxB,IAAI,KAAK,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;YAEzC,oGAAoG;YACpG,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,EAAE;gBACpB,OAAO,GAAG,CAAC,CAAC;gBACZ,KAAK,GAAG,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;aACzB;YAED,mFAAmF;YACnF,0CAA0C;YAC1C,IAAI,KAAK,IAAI,IAAI,CAAC,gBAAgB,EAAE;gBACnC,KAAK,GAAG,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;gBAClC,OAAO,GAAG,KAAK,GAAG,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;aACnC;YAED,gEAAgE;YAChE,oEAAoE;YACpE,IAAM,aAAa,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC9C,IACC,aAAa,KAAK,IAAI;gBACtB,aAAa,IAAI,IAAI,CAAC,IAAI;gBAC1B,aAAa,IAAI,IAAI,CAAC,EAAE,EACvB;gBACD,sFAAsF;gBACtF,IAAI,KAAK,GAAG,aAAa,EAAE;oBAC1B,KAAK,GAAG,aAAa,CAAC;oBACtB,OAAO,GAAG,KAAK,GAAG,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;iBACnC;aACD;YAED,8DAA8D;YAC9D,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACtB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;SAClB;QAAC,OAAO,KAAK,EAAE;YACf,OAAO,CAAC,KAAK,CACZ,iCACC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAC7C,CACF,CAAC;SACF;IACF,CAAC;IAEK,sCAAe,GAArB;;;;;;;wBAEE,KAAA,IAAI,CAAA;wBAAW,qBAAM,IAAI,CAAC,UAAU,CAAC,YAAY,CAChD,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,EAAE,CACP,EAAA;;wBAHD,GAAK,OAAO,GAAG,SAGd,CAAC;;;;wBAEF,OAAO,CAAC,KAAK,CACZ,gCACC,OAAK,YAAY,KAAK,CAAC,CAAC,CAAC,OAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAK,CAC7C,CACF,CAAC;;;;;;KAEH;IAQF,mBAAC;AAAD,CAAC,AA9QD,IA8QC"} \ No newline at end of file diff --git a/model.ts b/model.ts index 7c3f4e33..e748ec5c 100644 --- a/model.ts +++ b/model.ts @@ -1,6 +1,6 @@ //*** Model ***/ -// Manages the application's state for data display, navigation, and search functionalities. +/** Manages the application's state for data display, navigation, and search functionalities. */ class StateManager { private highlightedId: number | null = null; private rowHeight: number; @@ -34,7 +34,7 @@ class StateManager { this.highlightedId = value; } - // Sets up initial state, fetches record count and column names, and adjusts the display window size. + /** Sets up initial state, fetches record count and column names, and adjusts the display window size. */ async initializeState(): Promise { try { await this.fetchAndStoreTotalRecordCount(); @@ -170,7 +170,8 @@ class StateManager { ); } } - // Adjusts the available height based on window size and recalculates the number of rows. + + /** Adjusts the available height based on window size and recalculates the number of rows. */ adjustWindowSize(): void { try { if (typeof window === "undefined" || !window.innerHeight) { @@ -263,4 +264,11 @@ class StateManager { ); } } + + + + + + + } diff --git a/views.js b/views.js index 015c311c..27a8b8c7 100644 --- a/views.js +++ b/views.js @@ -101,7 +101,7 @@ var TableRenderer = /** @class */ (function () { } } }; - // Sets the widths of table columns evenly. + /** Sets the widths of table columns evenly. */ TableRenderer.prototype.setColumnWidths = function () { try { var table = document.getElementById("myTable"); diff --git a/views.js.map b/views.js.map index aac1caad..5f423f54 100644 --- a/views.js.map +++ b/views.js.map @@ -1 +1 @@ -{"version":3,"file":"views.js","sourceRoot":"","sources":["views.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"views.js","sourceRoot":"","sources":["views.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/views.ts b/views.ts index 81e1d1c2..63ceee80 100644 --- a/views.ts +++ b/views.ts @@ -4,7 +4,6 @@ * TableRenderer is responsible for rendering data into an HTML table. * It fetches data from the StateManager and populates the table accordingly. */ - class TableRenderer { private stateManager: StateManager; @@ -59,7 +58,7 @@ class TableRenderer { } } - // Sets the widths of table columns evenly. + /** Sets the widths of table columns evenly. */ setColumnWidths(): void { try { const table = document.getElementById("myTable"); From ff34019e7820d6b092d8ef30844ac57cb6c156b5 Mon Sep 17 00:00:00 2001 From: riaan Date: Tue, 10 Oct 2023 09:38:04 +0200 Subject: [PATCH 27/27] Fritz Reviews Finished Rev 1.21 --- controllers.js | 317 ------------------------------------------- controllers.js.map | 1 - controllers.ts | 137 ++++++++++--------- data.js | 127 ------------------ data.js.map | 1 - data.ts | 84 +++++++----- model.js | 309 ------------------------------------------ model.js.map | 1 - model.ts | 328 +++++++++++++++++++++------------------------ views.js | 157 ---------------------- views.js.map | 1 - views.ts | 115 ++++++++-------- 12 files changed, 325 insertions(+), 1253 deletions(-) delete mode 100644 controllers.js delete mode 100644 controllers.js.map delete mode 100644 data.js delete mode 100644 data.js.map delete mode 100644 model.js delete mode 100644 model.js.map delete mode 100644 views.js delete mode 100644 views.js.map diff --git a/controllers.js b/controllers.js deleted file mode 100644 index b20ee039..00000000 --- a/controllers.js +++ /dev/null @@ -1,317 +0,0 @@ -"use strict"; -/*** Controllers ***/ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -/** Handles window resize events to update the view of the application. */ -var WindowResizeHandler = /** @class */ (function () { - /** - * @param {TableRenderer} tableRenderer - Used for re-rendering table data. - * @param {StateManager} stateManager - State control for retrieving/updating application data. - */ - function WindowResizeHandler(tableRenderer, stateManager, paginationManager) { - this.debouncedUpdate = this.debounce(this.updateAfterResize.bind(this), 250); - this.paginationManager = paginationManager; - this.tableRenderer = tableRenderer; - this.stateManager = stateManager; - // Attach event listener for window resize. - this.setupEventListenersResize(); - } - WindowResizeHandler.prototype.setupEventListenersResize = function () { - var _this = this; - window.addEventListener("resize", function () { return _this.handleResize(); }); - }; - WindowResizeHandler.prototype.handleResize = function () { - this.debouncedUpdate(); - }; - // Debounce function to reduce the number of function calls while user is dragging the browser window. - WindowResizeHandler.prototype.debounce = function (func, delay) { - var timeout = null; - return function () { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - var later = function () { - timeout = null; - func.apply(void 0, args); - }; - if (timeout !== null) { - clearTimeout(timeout); - } - timeout = setTimeout(later, delay); - }; - }; - WindowResizeHandler.prototype.updateAfterResize = function () { - return __awaiter(this, void 0, void 0, function () { - var records; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - this.stateManager.adjustWindowSize(); - return [4 /*yield*/, this.stateManager.retrieveRecords().catch(function (error) { - console.error("Error retrieving records: " + (error instanceof Error ? error.message : error)); - alert("An error occurred while retrieving records. Please try again later."); - return; - })]; - case 1: - _a.sent(); - records = this.stateManager.getRecords(); - if (records !== null) { - this.tableRenderer.renderRecords(records); - } - this.paginationManager.updateButtonStates(); - return [2 /*return*/]; - } - }); - }); - }; - return WindowResizeHandler; -}()); -/** Handles pagination and search functionalities for the application's table view. */ -var PaginationManager = /** @class */ (function () { - /** - * @param {TableRenderer} tableRenderer - Used for re-rendering table data. - * @param {StateManager} stateManager - State control for retrieving/updating application data. - */ - function PaginationManager(tableRenderer, stateManager) { - this.tableRenderer = tableRenderer; - this.stateManager = stateManager; - // DOM elements required for pagination and search. - this.prevButton = null; - this.nextButton = null; - this.searchButton = null; - this.mainHeading = null; - this.filterInput = null; - this.errorMessage = null; - this.initializeDOMElements(); - // Attach event listeners for buttons and other UI elements. - this.setupEventListeners(); - } - PaginationManager.prototype.initializeDOMElements = function () { - this.prevButton = this.retrieveElement("prevPage", "button"); - this.nextButton = this.retrieveElement("nextPage", "button"); - this.searchButton = this.retrieveElement("searchButton", "button"); - this.mainHeading = this.retrieveElement("main-heading", "heading"); - this.filterInput = this.retrieveElement("filterInput", "input box"); - this.errorMessage = this.retrieveElement("errorMessage", "error message"); - }; - PaginationManager.prototype.retrieveElement = function (id, description) { - var element = document.getElementById(id); - if (!element) { - console.error("Element with ID '" + id + "' not found"); - if (description) { - alert("A critical " + description + " is missing on the page. Some functionalities might not work as expected."); - } - } - return element; - }; - /** Attaches event listeners to the relevant DOM elements to handle user interactions. */ - PaginationManager.prototype.setupEventListeners = function () { - var _this = this; - if (this.prevButton) { - this.prevButton.addEventListener("click", function () { - return _this.decrementPage(); - }); - } - if (this.nextButton) { - this.nextButton.addEventListener("click", function () { - return _this.incrementPage(); - }); - } - if (this.searchButton) { - this.searchButton.addEventListener("click", function () { - return _this.searchById(); - }); - } - if (this.filterInput) { - this.filterInput.addEventListener("keyup", function (event) { - if (event.key === "Enter") { - _this.searchById(); - } - }); - } - if (this.mainHeading) { - this.mainHeading.addEventListener("click", function () { - return _this.navigateToHome(); - }); - } - if (this.filterInput && this.errorMessage) { - this.setupLiveValidation(); - } - }; - /** Navigates to the home page by reloading the window.*/ - PaginationManager.prototype.navigateToHome = function () { - try { - window.location.reload(); - } - catch (error) { - console.error("Error while navigating to home: " + (error instanceof Error ? error.message : error)); - alert("Failed to reload the page. Please try again."); - } - }; - /** Fetches the next set of records and updates the view. */ - PaginationManager.prototype.incrementPage = function () { - return __awaiter(this, void 0, void 0, function () { - var records, error_1; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 2, , 3]); - this.stateManager.goToNextPage(); - return [4 /*yield*/, this.stateManager.retrieveRecords()]; - case 1: - _a.sent(); - records = this.stateManager.getRecords(); - if (records !== null) { - this.tableRenderer.renderRecords(records); - } - this.updateButtonStates(); - return [3 /*break*/, 3]; - case 2: - error_1 = _a.sent(); - console.error("Unexpected error in incrementPage: " + (error_1 instanceof Error ? error_1.message : error_1)); - return [3 /*break*/, 3]; - case 3: return [2 /*return*/]; - } - }); - }); - }; - /** Fetches the previous set of records and updates the view. */ - PaginationManager.prototype.decrementPage = function () { - return __awaiter(this, void 0, void 0, function () { - var records, error_2; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 2, , 3]); - this.stateManager.goToPreviousPage(); - return [4 /*yield*/, this.stateManager.retrieveRecords()]; - case 1: - _a.sent(); - records = this.stateManager.getRecords(); - if (records !== null) { - this.tableRenderer.renderRecords(records); - } - this.updateButtonStates(); - return [3 /*break*/, 3]; - case 2: - error_2 = _a.sent(); - console.error("Error in decrementPage: " + (error_2 instanceof Error ? error_2.message : error_2)); - return [3 /*break*/, 3]; - case 3: return [2 /*return*/]; - } - }); - }); - }; - /** Searches for a record by its ID and updates the view. */ - PaginationManager.prototype.searchById = function () { - return __awaiter(this, void 0, void 0, function () { - var searchValue, records, error_3; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 2, , 3]); - if (!this.filterInput) { - throw new Error("Filter input element is missing"); - } - searchValue = parseInt(this.filterInput.value, 10); - if (isNaN(searchValue)) { - throw new Error("Invalid search value or none"); - } - this.stateManager.setHighlightedId(searchValue); - return [4 /*yield*/, this.stateManager.searchByIdStateChange(searchValue)]; - case 1: - _a.sent(); - records = this.stateManager.getRecords(); - if (records !== null) { - this.tableRenderer.renderRecords(records, searchValue); - } - this.updateButtonStates(); - return [3 /*break*/, 3]; - case 2: - error_3 = _a.sent(); - console.error("Error in searchById function: " + (error_3 instanceof Error ? error_3.message : error_3)); - alert("A Serious Error ocurred, please try again later"); - return [3 /*break*/, 3]; - case 3: return [2 /*return*/]; - } - }); - }); - }; - /** Validates input for the search bar in real-time. */ - PaginationManager.prototype.setupLiveValidation = function () { - var _this = this; - if (!this.filterInput || !this.errorMessage) { - console.error("Live validation setup failed: Required elements not found."); - return; - } - this.filterInput.addEventListener("input", function () { - var inputValue = _this.filterInput.value; // The "!" here asserts non-null, because I already checked for null above. - var maxValue = _this.stateManager.getTotalRecordCount() - 1; - if (inputValue.length === 0) { - _this.errorMessage.textContent = ""; - } - else if (inputValue.length < 1 || - inputValue.length > 6 || - !/^\d+$/.test(inputValue)) { - _this.errorMessage.textContent = - "Invalid input. Please enter a number between 0 and " + maxValue + "."; - } - else { - _this.errorMessage.textContent = ""; - } - }); - }; - /** Updates the state of the pagination buttons based on the current view. */ - PaginationManager.prototype.updateButtonStates = function () { - try { - if (!this.prevButton || !this.nextButton) { - throw new Error("Button elements are missing"); - } - var from = this.stateManager.getFrom(); - var to = this.stateManager.getTo(); - var totalRecordCount = this.stateManager.getTotalRecordCount(); - this.prevButton.disabled = from === 0; - this.nextButton.disabled = to === totalRecordCount - 1; - } - catch (error) { - console.error("Unexpected error in updateButtonStates: " + (error instanceof Error ? error.message : error)); - } - }; - return PaginationManager; -}()); -//# sourceMappingURL=controllers.js.map \ No newline at end of file diff --git a/controllers.js.map b/controllers.js.map deleted file mode 100644 index f3cf8e8a..00000000 --- a/controllers.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"controllers.js","sourceRoot":"","sources":["controllers.ts"],"names":[],"mappings":";AAAA,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAErB,0EAA0E;AAC1E;IAMC;;;OAGG;IAEH,6BACC,aAA4B,EAC5B,YAA0B,EAC1B,iBAAoC;QAEpC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,QAAQ,CACnC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EACjC,GAAG,CACH,CAAC;QACF,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAC3C,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QAEjC,2CAA2C;QAC3C,IAAI,CAAC,yBAAyB,EAAE,CAAC;IAClC,CAAC;IAEO,uDAAyB,GAAjC;QAAA,iBAEC;QADA,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,cAAM,OAAA,KAAI,CAAC,YAAY,EAAE,EAAnB,CAAmB,CAAC,CAAC;IAC9D,CAAC;IAED,0CAAY,GAAZ;QACC,IAAI,CAAC,eAAe,EAAE,CAAC;IACxB,CAAC;IAED,sGAAsG;IACtG,sCAAQ,GAAR,UAAS,IAAc,EAAE,KAAa;QACrC,IAAI,OAAO,GAAyC,IAAI,CAAC;QACzD,OAAO;YAAC,cAAc;iBAAd,UAAc,EAAd,qBAAc,EAAd,IAAc;gBAAd,yBAAc;;YACrB,IAAM,KAAK,GAAG;gBACb,OAAO,GAAG,IAAI,CAAC;gBACf,IAAI,eAAI,IAAI,EAAE;YACf,CAAC,CAAC;YACF,IAAI,OAAO,KAAK,IAAI,EAAE;gBACrB,YAAY,CAAC,OAAO,CAAC,CAAC;aACtB;YACD,OAAO,GAAG,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACpC,CAAC,CAAC;IACH,CAAC;IAEK,+CAAiB,GAAvB;;;;;;wBACC,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC;wBACrC,qBAAM,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,CAAC,KAAK,CAAC,UAAC,KAAK;gCACrD,OAAO,CAAC,KAAK,CACZ,gCACC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAC7C,CACF,CAAC;gCACF,KAAK,CACJ,qEAAqE,CACrE,CAAC;gCACF,OAAO;4BACR,CAAC,CAAC,EAAA;;wBAVF,SAUE,CAAC;wBAEG,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;wBAE/C,IAAI,OAAO,KAAK,IAAI,EAAE;4BACrB,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;yBAC1C;wBACD,IAAI,CAAC,iBAAiB,CAAC,kBAAkB,EAAE,CAAC;;;;;KAC5C;IACF,0BAAC;AAAD,CAAC,AAxED,IAwEC;AAED,sFAAsF;AACtF;IASC;;;OAGG;IACH,2BACS,aAA4B,EAC5B,YAA0B;QAD1B,kBAAa,GAAb,aAAa,CAAe;QAC5B,iBAAY,GAAZ,YAAY,CAAc;QAdnC,mDAAmD;QAC3C,eAAU,GAA6B,IAAI,CAAC;QAC5C,eAAU,GAA6B,IAAI,CAAC;QAC5C,iBAAY,GAA6B,IAAI,CAAC;QAC9C,gBAAW,GAAuB,IAAI,CAAC;QACvC,gBAAW,GAA4B,IAAI,CAAC;QAC5C,iBAAY,GAAuB,IAAI,CAAC;QAU/C,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC7B,4DAA4D;QAC5D,IAAI,CAAC,mBAAmB,EAAE,CAAC;IAC5B,CAAC;IAEO,iDAAqB,GAA7B;QACC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,eAAe,CACrC,UAAU,EACV,QAAQ,CACa,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,eAAe,CACrC,UAAU,EACV,QAAQ,CACa,CAAC;QACvB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,eAAe,CACvC,cAAc,EACd,QAAQ,CACa,CAAC;QACvB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,eAAe,CACtC,cAAc,EACd,SAAS,CACM,CAAC;QACjB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,eAAe,CACtC,aAAa,EACb,WAAW,CACS,CAAC;QACtB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,eAAe,CACvC,cAAc,EACd,eAAe,CACA,CAAC;IAClB,CAAC;IAEO,2CAAe,GAAvB,UACC,EAAU,EACV,WAAoB;QAEpB,IAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,EAAE;YACb,OAAO,CAAC,KAAK,CAAC,sBAAoB,EAAE,gBAAa,CAAC,CAAC;YACnD,IAAI,WAAW,EAAE;gBAChB,KAAK,CACJ,gBAAc,WAAW,8EAA2E,CACpG,CAAC;aACF;SACD;QACD,OAAO,OAAO,CAAC;IAChB,CAAC;IAED,yFAAyF;IACjF,+CAAmB,GAA3B;QAAA,iBAoCC;QAnCA,IAAI,IAAI,CAAC,UAAU,EAAE;YACpB,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,OAAO,EAAE;gBACzC,OAAA,KAAI,CAAC,aAAa,EAAE;YAApB,CAAoB,CACpB,CAAC;SACF;QAED,IAAI,IAAI,CAAC,UAAU,EAAE;YACpB,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,OAAO,EAAE;gBACzC,OAAA,KAAI,CAAC,aAAa,EAAE;YAApB,CAAoB,CACpB,CAAC;SACF;QAED,IAAI,IAAI,CAAC,YAAY,EAAE;YACtB,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,OAAO,EAAE;gBAC3C,OAAA,KAAI,CAAC,UAAU,EAAE;YAAjB,CAAiB,CACjB,CAAC;SACF;QAED,IAAI,IAAI,CAAC,WAAW,EAAE;YACrB,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,UAAC,KAAK;gBAChD,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,EAAE;oBAC1B,KAAI,CAAC,UAAU,EAAE,CAAC;iBAClB;YACF,CAAC,CAAC,CAAC;SACH;QAED,IAAI,IAAI,CAAC,WAAW,EAAE;YACrB,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE;gBAC1C,OAAA,KAAI,CAAC,cAAc,EAAE;YAArB,CAAqB,CACrB,CAAC;SACF;QAED,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,YAAY,EAAE;YAC1C,IAAI,CAAC,mBAAmB,EAAE,CAAC;SAC3B;IACF,CAAC;IAED,yDAAyD;IACzD,0CAAc,GAAd;QACC,IAAI;YACH,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;SACzB;QAAC,OAAO,KAAK,EAAE;YACf,OAAO,CAAC,KAAK,CACZ,sCACC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAC7C,CACF,CAAC;YACF,KAAK,CAAC,8CAA8C,CAAC,CAAC;SACtD;IACF,CAAC;IAED,4DAA4D;IACtD,yCAAa,GAAnB;;;;;;;wBAEE,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC;wBACjC,qBAAM,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,EAAA;;wBAAzC,SAAyC,CAAC;wBACpC,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;wBAE/C,IAAI,OAAO,KAAK,IAAI,EAAE;4BACrB,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;yBAC1C;wBACD,IAAI,CAAC,kBAAkB,EAAE,CAAC;;;;wBAE1B,OAAO,CAAC,KAAK,CACZ,yCACC,OAAK,YAAY,KAAK,CAAC,CAAC,CAAC,OAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAK,CAC7C,CACF,CAAC;;;;;;KAEH;IAED,gEAAgE;IAC1D,yCAAa,GAAnB;;;;;;;wBAEE,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC;wBACrC,qBAAM,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,EAAA;;wBAAzC,SAAyC,CAAC;wBACpC,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;wBAE/C,IAAI,OAAO,KAAK,IAAI,EAAE;4BACrB,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;yBAC1C;wBAED,IAAI,CAAC,kBAAkB,EAAE,CAAC;;;;wBAE1B,OAAO,CAAC,KAAK,CACZ,8BACC,OAAK,YAAY,KAAK,CAAC,CAAC,CAAC,OAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAK,CAC7C,CACF,CAAC;;;;;;KAEH;IAED,4DAA4D;IACtD,sCAAU,GAAhB;;;;;;;wBAEE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;4BACtB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;yBACnD;wBAEK,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;wBACzD,IAAI,KAAK,CAAC,WAAW,CAAC,EAAE;4BACvB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;yBAChD;wBAED,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;wBAChD,qBAAM,IAAI,CAAC,YAAY,CAAC,qBAAqB,CAAC,WAAW,CAAC,EAAA;;wBAA1D,SAA0D,CAAC;wBAErD,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;wBAE/C,IAAI,OAAO,KAAK,IAAI,EAAE;4BACrB,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;yBACvD;wBAED,IAAI,CAAC,kBAAkB,EAAE,CAAC;;;;wBAE1B,OAAO,CAAC,KAAK,CACZ,oCACC,OAAK,YAAY,KAAK,CAAC,CAAC,CAAC,OAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAK,CAC7C,CACF,CAAC;wBACF,KAAK,CAAC,iDAAiD,CAAC,CAAC;;;;;;KAE1D;IAED,uDAAuD;IACvD,+CAAmB,GAAnB;QAAA,iBAwBC;QAvBA,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;YAC5C,OAAO,CAAC,KAAK,CACZ,4DAA4D,CAC5D,CAAC;YACF,OAAO;SACP;QAED,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE;YAC1C,IAAM,UAAU,GAAG,KAAI,CAAC,WAAY,CAAC,KAAK,CAAC,CAAC,2EAA2E;YACvH,IAAM,QAAQ,GAAG,KAAI,CAAC,YAAY,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;YAC7D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE;gBAC5B,KAAI,CAAC,YAAa,CAAC,WAAW,GAAG,EAAE,CAAC;aACpC;iBAAM,IACN,UAAU,CAAC,MAAM,GAAG,CAAC;gBACrB,UAAU,CAAC,MAAM,GAAG,CAAC;gBACrB,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EACxB;gBACD,KAAI,CAAC,YAAa,CAAC,WAAW;oBAC7B,wDAAsD,QAAQ,MAAG,CAAC;aACnE;iBAAM;gBACN,KAAI,CAAC,YAAa,CAAC,WAAW,GAAG,EAAE,CAAC;aACpC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,6EAA6E;IACtE,8CAAkB,GAAzB;QACC,IAAI;YACH,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;gBACzC,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;aAC/C;YAED,IAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;YACzC,IAAM,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;YACrC,IAAM,gBAAgB,GAAG,IAAI,CAAC,YAAY,CAAC,mBAAmB,EAAE,CAAC;YAEjE,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG,IAAI,KAAK,CAAC,CAAC;YACtC,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG,EAAE,KAAK,gBAAgB,GAAG,CAAC,CAAC;SACvD;QAAC,OAAO,KAAK,EAAE;YACf,OAAO,CAAC,KAAK,CACZ,8CACC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAC7C,CACF,CAAC;SACF;IACF,CAAC;IACF,wBAAC;AAAD,CAAC,AA/OD,IA+OC"} \ No newline at end of file diff --git a/controllers.ts b/controllers.ts index 8997585f..1300963e 100644 --- a/controllers.ts +++ b/controllers.ts @@ -12,7 +12,7 @@ class WindowResizeHandler { * @param {StateManager} stateManager - State control for retrieving/updating application data. */ - constructor( + constructor ( tableRenderer: TableRenderer, stateManager: StateManager, paginationManager: PaginationManager @@ -34,9 +34,18 @@ class WindowResizeHandler { } handleResize(): void { - this.debouncedUpdate(); + try { + this.debouncedUpdate(); + } catch (error) { + console.error( + `Error in handleResize: ${ + error instanceof Error ? error.message : error + }` + ); + alert("An error occurred while resizing. Please try again."); + } } - + // Debounce function to reduce the number of function calls while user is dragging the browser window. debounce(func: Function, delay: number): Function { let timeout: ReturnType | null = null; @@ -89,7 +98,7 @@ class PaginationManager { * @param {TableRenderer} tableRenderer - Used for re-rendering table data. * @param {StateManager} stateManager - State control for retrieving/updating application data. */ - constructor( + constructor ( private tableRenderer: TableRenderer, private stateManager: StateManager ) { @@ -196,75 +205,81 @@ class PaginationManager { /** Fetches the next set of records and updates the view. */ async incrementPage(): Promise { - try { - this.stateManager.goToNextPage(); - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); + this.stateManager.goToNextPage(); - if (records !== null) { - this.tableRenderer.renderRecords(records); - } - this.updateButtonStates(); - } catch (error) { + await this.stateManager.retrieveRecords().catch((error) => { console.error( - `Unexpected error in incrementPage: ${ + `Error in retrieveRecords while incrementing page: ${ error instanceof Error ? error.message : error }` ); + alert("Failed to increment the page. Please contact support."); + }); + + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); } + this.updateButtonStates(); } /** Fetches the previous set of records and updates the view. */ async decrementPage(): Promise { - try { - this.stateManager.goToPreviousPage(); - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); + this.stateManager.goToPreviousPage(); - if (records !== null) { - this.tableRenderer.renderRecords(records); - } - - this.updateButtonStates(); - } catch (error) { + await this.stateManager.retrieveRecords().catch((error) => { console.error( - `Error in decrementPage: ${ + `Error in retrieveRecords while decrementing page: ${ error instanceof Error ? error.message : error }` ); + alert("Failed to decrement the page. Please contact support."); + }); + + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.tableRenderer.renderRecords(records); } + + this.updateButtonStates(); } /** Searches for a record by its ID and updates the view. */ async searchById(): Promise { - try { - if (!this.filterInput) { - throw new Error("Filter input element is missing"); - } + if (!this.filterInput) { + alert("Filter input element is missing"); + return; + } - const searchValue = parseInt(this.filterInput.value, 10); - if (isNaN(searchValue)) { - throw new Error("Invalid search value or none"); - } + const searchValue = parseInt(this.filterInput.value, 10); + if (isNaN(searchValue)) { + alert("Invalid search value or none"); + return; + } - this.stateManager.setHighlightedId(searchValue); - await this.stateManager.searchByIdStateChange(searchValue); + this.stateManager.setHighlightedId(searchValue); - const records = this.stateManager.getRecords(); + await this.stateManager + .searchByIdStateChange(searchValue) + .catch((error) => { + console.error( + `Error in searchByIdStateChange: ${ + error instanceof Error ? error.message : error + }` + ); + alert("A serious error occurred, please try again later"); + return; + }); - if (records !== null) { - this.tableRenderer.renderRecords(records, searchValue); - } + const records = this.stateManager.getRecords(); - this.updateButtonStates(); - } catch (error) { - console.error( - `Error in searchById function: ${ - error instanceof Error ? error.message : error - }` - ); - alert("A Serious Error ocurred, please try again later"); + if (records !== null) { + this.tableRenderer.renderRecords(records, searchValue); } + + this.updateButtonStates(); } /** Validates input for the search bar in real-time. */ @@ -286,8 +301,7 @@ class PaginationManager { inputValue.length > 6 || !/^\d+$/.test(inputValue) ) { - this.errorMessage!.textContent = - `Invalid input. Please enter a number between 0 and ${maxValue}.`; + this.errorMessage!.textContent = `Invalid input. Please enter a number between 0 and ${maxValue}.`; } else { this.errorMessage!.textContent = ""; } @@ -296,23 +310,16 @@ class PaginationManager { /** Updates the state of the pagination buttons based on the current view. */ public updateButtonStates(): void { - try { - if (!this.prevButton || !this.nextButton) { - throw new Error("Button elements are missing"); - } + if (!this.prevButton || !this.nextButton) { + alert("Button elements are missing"); + return; + } - const from = this.stateManager.getFrom(); - const to = this.stateManager.getTo(); - const totalRecordCount = this.stateManager.getTotalRecordCount(); + const from = this.stateManager.getFrom(); + const to = this.stateManager.getTo(); + const totalRecordCount = this.stateManager.getTotalRecordCount(); - this.prevButton.disabled = from === 0; - this.nextButton.disabled = to === totalRecordCount - 1; - } catch (error) { - console.error( - `Unexpected error in updateButtonStates: ${ - error instanceof Error ? error.message : error - }` - ); - } + this.prevButton.disabled = from === 0; + this.nextButton.disabled = to === totalRecordCount - 1; } } diff --git a/data.js b/data.js deleted file mode 100644 index ce9cdd29..00000000 --- a/data.js +++ /dev/null @@ -1,127 +0,0 @@ -"use strict"; -//*** Data ***/ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -/** Manages API requests for fetching record count, column names, and data records.*/ -var ApiManager = /** @class */ (function () { - function ApiManager() { - this.totalRecordCount = 0; - this.columnNames = null; - } - ApiManager.prototype.fetchTotalRecordCount = function () { - return __awaiter(this, void 0, void 0, function () { - var response, data, error_1; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 3, , 4]); - return [4 /*yield*/, fetch("http://localhost:2050/recordCount")]; - case 1: - response = _a.sent(); - if (!response.ok) { - throw new Error("Failed to fetch total record count: " + response.statusText); - } - return [4 /*yield*/, response.json()]; - case 2: - data = _a.sent(); - this.totalRecordCount = data; - return [3 /*break*/, 4]; - case 3: - error_1 = _a.sent(); - console.error("Error fetching total record count: " + error_1); - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; - } - }); - }); - }; - ApiManager.prototype.fetchColumnNames = function () { - return __awaiter(this, void 0, void 0, function () { - var response, data, error_2; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 3, , 4]); - return [4 /*yield*/, fetch("http://localhost:2050/columns")]; - case 1: - response = _a.sent(); - if (!response.ok) { - throw new Error("Failed to fetch column names: " + response.statusText); - } - return [4 /*yield*/, response.json()]; - case 2: - data = _a.sent(); - this.columnNames = data; - return [3 /*break*/, 4]; - case 3: - error_2 = _a.sent(); - console.error("Error fetching column names: " + error_2); - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; - } - }); - }); - }; - ApiManager.prototype.fetchRecords = function (from, to) { - return __awaiter(this, void 0, void 0, function () { - var response, data, error_3; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 3, , 4]); - return [4 /*yield*/, fetch("http://localhost:2050/records?from=" + from + "&to=" + to)]; - case 1: - response = _a.sent(); - if (!response.ok) { - throw new Error("Failed to fetch records: " + response.statusText); - } - return [4 /*yield*/, response.json()]; - case 2: - data = _a.sent(); - return [2 /*return*/, data]; - case 3: - error_3 = _a.sent(); - console.error("Error fetching records: " + error_3); - return [2 /*return*/, null]; - case 4: return [2 /*return*/]; - } - }); - }); - }; - return ApiManager; -}()); -//# sourceMappingURL=data.js.map \ No newline at end of file diff --git a/data.js.map b/data.js.map deleted file mode 100644 index 3ae66c64..00000000 --- a/data.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"data.js","sourceRoot":"","sources":["data.ts"],"names":[],"mappings":";AAAA,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIf,qFAAqF;AACrF;IAIC;QACC,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IACzB,CAAC;IAEK,0CAAqB,GAA3B;;;;;;;wBAEmB,qBAAM,KAAK,CAAC,mCAAmC,CAAC,EAAA;;wBAA3D,QAAQ,GAAG,SAAgD;wBACjE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BACjB,MAAM,IAAI,KAAK,CACd,yCAAuC,QAAQ,CAAC,UAAY,CAC5D,CAAC;yBACF;wBACoB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAApC,IAAI,GAAW,SAAqB;wBAC1C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;;;;wBAE7B,OAAO,CAAC,KAAK,CAAC,wCAAsC,OAAO,CAAC,CAAC;;;;;;KAE9D;IAEK,qCAAgB,GAAtB;;;;;;;wBAEmB,qBAAM,KAAK,CAAC,+BAA+B,CAAC,EAAA;;wBAAvD,QAAQ,GAAG,SAA4C;wBAC7D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BACjB,MAAM,IAAI,KAAK,CACd,mCAAiC,QAAQ,CAAC,UAAY,CACtD,CAAC;yBACF;wBACsB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAtC,IAAI,GAAa,SAAqB;wBAC5C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;;;;wBAExB,OAAO,CAAC,KAAK,CAAC,kCAAgC,OAAO,CAAC,CAAC;;;;;;KAExD;IAEK,iCAAY,GAAlB,UAAmB,IAAY,EAAE,EAAU;;;;;;;wBAExB,qBAAM,KAAK,CAC3B,wCAAsC,IAAI,YAAO,EAAI,CACrD,EAAA;;wBAFK,QAAQ,GAAG,SAEhB;wBACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;4BACjB,MAAM,IAAI,KAAK,CACd,8BAA4B,QAAQ,CAAC,UAAY,CACjD,CAAC;yBACF;wBACwB,qBAAM,QAAQ,CAAC,IAAI,EAAE,EAAA;;wBAAxC,IAAI,GAAe,SAAqB;wBAC9C,sBAAO,IAAI,EAAC;;;wBAEZ,OAAO,CAAC,KAAK,CAAC,6BAA2B,OAAO,CAAC,CAAC;wBAClD,sBAAO,IAAI,EAAC;;;;;KAEb;IACF,iBAAC;AAAD,CAAC,AAxDD,IAwDC"} \ No newline at end of file diff --git a/data.ts b/data.ts index 2dc41e88..524067a8 100644 --- a/data.ts +++ b/data.ts @@ -1,62 +1,74 @@ //*** Data ***/ -type CityData = [number, string, number]; +type CityData = (number | string)[]; /** Manages API requests for fetching record count, column names, and data records.*/ class ApiManager { totalRecordCount: number; columnNames: string[] | null; - constructor() { + constructor () { this.totalRecordCount = 0; this.columnNames = null; } async fetchTotalRecordCount(): Promise { - try { - const response = await fetch("http://localhost:2050/recordCount"); - if (!response.ok) { - throw new Error( - `Failed to fetch total record count: ${response.statusText}` - ); + const response = await fetch("http://localhost:2050/recordCount").catch( + (error) => { + console.error(`Network error fetching record count: ${error}`); + throw error; } - const data: number = await response.json(); - this.totalRecordCount = data; - } catch (error) { - console.error(`Error fetching total record count: ${error}`); + ); + + if (!response.ok) { + const errorMessage = `Failed to fetch total record count: ${response.statusText}`; + console.error(errorMessage); + throw new Error(errorMessage); } + + const data: number = await response.json().catch((error) => { + console.error(`Error parsing JSON for record count: ${error}`); + throw error; + }); + + this.totalRecordCount = data; } async fetchColumnNames(): Promise { - try { - const response = await fetch("http://localhost:2050/columns"); - if (!response.ok) { - throw new Error( - `Failed to fetch column names: ${response.statusText}` - ); + const response = await fetch("http://localhost:2050/columns").catch( + (error) => { + console.error(`Network error fetching column names: ${error}`); + throw error; } - const data: string[] = await response.json(); - this.columnNames = data; - } catch (error) { - console.error(`Error fetching column names: ${error}`); + ); + + if (!response.ok) { + const errorMessage = `Failed to fetch column names: ${response.statusText}`; + console.error(errorMessage); + throw new Error(errorMessage); } + + const data: string[] = await response.json().catch((error) => { + console.error(`Error parsing JSON for column names: ${error}`); + throw error; + }); + + this.columnNames = data; } async fetchRecords(from: number, to: number): Promise { - try { - const response = await fetch( - `http://localhost:2050/records?from=${from}&to=${to}` - ); - if (!response.ok) { - throw new Error( - `Failed to fetch records: ${response.statusText}` - ); - } - const data: CityData[] = await response.json(); - return data; - } catch (error) { - console.error(`Error fetching records: ${error}`); - return null; + const response = await fetch( + `http://localhost:2050/records?from=${from}&to=${to}` + ).catch((error) => { + console.error(`Network error fetching records: ${error}`); + throw error; + }); + + if (!response.ok) { + throw new Error(`Failed to fetch records: ${response.statusText}`); } + + const data: CityData[] = await response.json(); + return data; } } diff --git a/model.js b/model.js deleted file mode 100644 index c7d86e16..00000000 --- a/model.js +++ /dev/null @@ -1,309 +0,0 @@ -"use strict"; -//*** Model ***/ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -/** Manages the application's state for data display, navigation, and search functionalities. */ -var StateManager = /** @class */ (function () { - function StateManager(apiManager) { - this.highlightedId = null; - this.records = null; - this.totalRecordCount = 0; - this.rowHeight = 20; - this.headerHeight = 180; - this.availableHeight = 0; - this.numRows = 0; - this.apiManager = apiManager; - this.from = 0; - this.to = 0; - this.columnNames = null; - this.totalRecordCount = 0; - } - StateManager.prototype.getHighlightedId = function () { - return this.highlightedId; - }; - StateManager.prototype.setHighlightedId = function (value) { - this.highlightedId = value; - }; - /** Sets up initial state, fetches record count and column names, and adjusts the display window size. */ - StateManager.prototype.initializeState = function () { - return __awaiter(this, void 0, void 0, function () { - var error_1; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 3, , 4]); - return [4 /*yield*/, this.fetchAndStoreTotalRecordCount()]; - case 1: - _a.sent(); - return [4 /*yield*/, this.retrieveColumnNames()]; - case 2: - _a.sent(); - this.adjustWindowSize(); - return [3 /*break*/, 4]; - case 3: - error_1 = _a.sent(); - console.error("Error in initializeState:", error_1); - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; - } - }); - }); - }; - StateManager.prototype.retrieveColumnNames = function () { - return __awaiter(this, void 0, void 0, function () { - var error_2; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 2, , 3]); - return [4 /*yield*/, this.apiManager.fetchColumnNames()]; - case 1: - _a.sent(); - if (this.apiManager.columnNames !== null) { - this.columnNames = this.apiManager.columnNames; - } - return [3 /*break*/, 3]; - case 2: - error_2 = _a.sent(); - console.error("Error in retrieveColumnNames:", error_2); - return [3 /*break*/, 3]; - case 3: return [2 /*return*/]; - } - }); - }); - }; - StateManager.prototype.fetchAndStoreTotalRecordCount = function () { - return __awaiter(this, void 0, void 0, function () { - var error_3; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 2, , 3]); - return [4 /*yield*/, this.apiManager.fetchTotalRecordCount()]; - case 1: - _a.sent(); - this.totalRecordCount = this.apiManager.totalRecordCount; - return [3 /*break*/, 3]; - case 2: - error_3 = _a.sent(); - console.error("Error in fetchAndStoreTotalRecordCount:", error_3); - return [3 /*break*/, 3]; - case 3: return [2 /*return*/]; - } - }); - }); - }; - StateManager.prototype.getTotalRecordCount = function () { - return this.totalRecordCount; - }; - StateManager.prototype.getColumnNames = function () { - return this.columnNames; - }; - StateManager.prototype.getRecords = function () { - return this.records; - }; - StateManager.prototype.getFrom = function () { - return this.from; - }; - StateManager.prototype.setFrom = function (value) { - this.from = value; - }; - StateManager.prototype.getTo = function () { - return this.to; - }; - StateManager.prototype.setTo = function (value) { - this.to = value; - }; - StateManager.prototype.goToNextPage = function () { - try { - var from = this.getFrom(); - var to = this.getTo(); - var recordsPerPage = this.numRows; - var newFrom = from + recordsPerPage; - var newTo = newFrom + recordsPerPage - 1; - // Check that 'to' does not exceed totalRecordCount. - if (newTo >= this.totalRecordCount) { - this.setTo(this.totalRecordCount - 1); - this.setFrom(this.totalRecordCount - recordsPerPage); - } - else { - this.setFrom(newFrom); - this.setTo(newTo); - } - } - catch (error) { - console.error("Unexpected error in goToNextPage: " + (error instanceof Error ? error.message : error)); - } - }; - StateManager.prototype.goToPreviousPage = function () { - try { - var from = this.getFrom(); - var to = this.getTo(); - var recordsPerPage = this.numRows; - var newFrom = from - recordsPerPage; - var newTo = newFrom + recordsPerPage - 1; - // Check that 'from' does not exceed 0. - if (newFrom < 0) { - this.setFrom(0); - this.setTo(recordsPerPage - 1); - } - else { - this.setFrom(newFrom); - this.setTo(newTo); - } - } - catch (error) { - console.error("Error in goToPreviousPage: " + (error instanceof Error ? error.message : error)); - } - }; - StateManager.prototype.searchByIdStateChange = function (id) { - return __awaiter(this, void 0, void 0, function () { - var newFrom, newTo, recordsPerPage, error_4; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 2, , 3]); - newFrom = id; - newTo = id + this.numRows - 1; - recordsPerPage = this.numRows; - // Checking that 'to' does not exceed totalRecordCount. - if (newTo >= this.totalRecordCount) { - this.setTo(this.totalRecordCount - 1); - this.setFrom(this.totalRecordCount - recordsPerPage); - } - else { - this.setTo(newTo); - this.setFrom(newFrom); - } - return [4 /*yield*/, this.retrieveRecords()]; - case 1: - _a.sent(); - return [3 /*break*/, 3]; - case 2: - error_4 = _a.sent(); - console.error("Error in searchByIdStateChange: " + (error_4 instanceof Error ? error_4.message : error_4)); - return [3 /*break*/, 3]; - case 3: return [2 /*return*/]; - } - }); - }); - }; - /** Adjusts the available height based on window size and recalculates the number of rows. */ - StateManager.prototype.adjustWindowSize = function () { - try { - if (typeof window === "undefined" || !window.innerHeight) { - throw new Error("Unable to access window dimensions"); - } - // Determine the dynamic height of the header and pagination. - var mainHeadingElement = document.getElementById("main-heading"); - var paginationElement = document.getElementById("pagination"); - if (mainHeadingElement && paginationElement) { - this.headerHeight = - mainHeadingElement.clientHeight + - paginationElement.clientHeight; - } - else { - console.error("Could not find main-heading and/or pagination elements"); - } - if (!this.rowHeight) { - throw new Error("Row height is not properly configured"); - } - this.availableHeight = - window.innerHeight - this.headerHeight - this.rowHeight * 2; - this.numRows = Math.floor(this.availableHeight / this.rowHeight); - if (this.numRows <= 0) { - console.log("Window size too small, setting minimum number of rows to 1"); - this.numRows = 1; - } - // Calculating new values without modifying the state immediately. - var newFrom = this.from; - var newTo = this.from + this.numRows - 1; - // If it's the first set of records ("first page"), start from 0 and populate the whole window size. - if (this.from === 0) { - newFrom = 0; - newTo = this.numRows - 1; - } - // Ensure `newTo` doesn't exceed totalRecordCount and adjust `newFrom` accordingly, - // meaning populate the whole window size. - if (newTo >= this.totalRecordCount) { - newTo = this.totalRecordCount - 1; - newFrom = newTo - this.numRows + 1; - } - // Check if the highlighted ID is currently between from and to, - // too enable priority functionality (always visible in the window). - var highlightedId = this.getHighlightedId(); - if (highlightedId !== null && - highlightedId >= this.from && - highlightedId <= this.to) { - // If newTo would be smaller than highlightedId, adjust to keep highlightedId in view. - if (newTo < highlightedId) { - newTo = highlightedId; - newFrom = newTo - this.numRows + 1; - } - } - // Now, after all conditions have been checked, set the state. - this.setFrom(newFrom); - this.setTo(newTo); - } - catch (error) { - console.error("Error in adjustWindowSize: " + (error instanceof Error ? error.message : error)); - } - }; - StateManager.prototype.retrieveRecords = function () { - return __awaiter(this, void 0, void 0, function () { - var _a, error_5; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - _b.trys.push([0, 2, , 3]); - _a = this; - return [4 /*yield*/, this.apiManager.fetchRecords(this.from, this.to)]; - case 1: - _a.records = _b.sent(); - return [3 /*break*/, 3]; - case 2: - error_5 = _b.sent(); - console.error("Error retrieving records: " + (error_5 instanceof Error ? error_5.message : error_5)); - return [3 /*break*/, 3]; - case 3: return [2 /*return*/]; - } - }); - }); - }; - return StateManager; -}()); -//# sourceMappingURL=model.js.map \ No newline at end of file diff --git a/model.js.map b/model.js.map deleted file mode 100644 index f3247cfb..00000000 --- a/model.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"model.js","sourceRoot":"","sources":["model.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/model.ts b/model.ts index e748ec5c..8c203daa 100644 --- a/model.ts +++ b/model.ts @@ -14,7 +14,7 @@ class StateManager { private columnNames: string[] | null; private totalRecordCount = 0; - constructor(apiManager: ApiManager) { + constructor (apiManager: ApiManager) { this.rowHeight = 20; this.headerHeight = 180; this.availableHeight = 0; @@ -36,36 +36,49 @@ class StateManager { /** Sets up initial state, fetches record count and column names, and adjusts the display window size. */ async initializeState(): Promise { + await this.fetchAndStoreTotalRecordCount().catch((error) => { + console.error("Error in fetchAndStoreTotalRecordCount:", error); + return; + }); + + await this.retrieveColumnNames().catch((error) => { + console.error("Error in retrieveColumnNames:", error); + return; + }); + try { - await this.fetchAndStoreTotalRecordCount(); - await this.retrieveColumnNames(); this.adjustWindowSize(); } catch (error) { - console.error("Error in initializeState:", error); + console.error( + `Error in adjustWindowSize: ${ + error instanceof Error ? error.message : error + }` + ); + alert("An error occurred while adjusting the window size. Please try again."); } } - + async retrieveColumnNames(): Promise { - try { - await this.apiManager.fetchColumnNames(); + await this.apiManager.fetchColumnNames().catch((error) => { + console.error( + "Error fetching column names from apiManager:",error); + throw error; + }); - if (this.apiManager.columnNames !== null) { - this.columnNames = this.apiManager.columnNames; - } - } catch (error) { - console.error("Error in retrieveColumnNames:", error); + if (this.apiManager.columnNames !== null) { + this.columnNames = this.apiManager.columnNames; } } async fetchAndStoreTotalRecordCount(): Promise { - try { - await this.apiManager.fetchTotalRecordCount(); - this.totalRecordCount = this.apiManager.totalRecordCount; - } catch (error) { - console.error("Error in fetchAndStoreTotalRecordCount:", error); - } + await this.apiManager.fetchTotalRecordCount().catch(error => { + console.error("Error fetching total record count from apiManager:", error); + throw error; + }); + + this.totalRecordCount = this.apiManager.totalRecordCount; } - + getTotalRecordCount(): number { return this.totalRecordCount; } @@ -95,180 +108,139 @@ class StateManager { } goToNextPage(): void { - try { - const from = this.getFrom(); - const to = this.getTo(); - const recordsPerPage = this.numRows; - - const newFrom = from + recordsPerPage; - const newTo = newFrom + recordsPerPage - 1; - - // Check that 'to' does not exceed totalRecordCount. - if (newTo >= this.totalRecordCount) { - this.setTo(this.totalRecordCount - 1); - this.setFrom(this.totalRecordCount - recordsPerPage); - } else { - this.setFrom(newFrom); - this.setTo(newTo); - } - } catch (error) { - console.error( - `Unexpected error in goToNextPage: ${ - error instanceof Error ? error.message : error - }` - ); + const from = this.getFrom(); + const to = this.getTo(); + const recordsPerPage = this.numRows; + + const newFrom = from + recordsPerPage; + const newTo = newFrom + recordsPerPage - 1; + + // Check that 'to' does not exceed totalRecordCount. + if (newTo >= this.totalRecordCount) { + this.setTo(this.totalRecordCount - 1); + this.setFrom(this.totalRecordCount - recordsPerPage); + } else { + this.setFrom(newFrom); + this.setTo(newTo); } } - + goToPreviousPage(): void { - try { - const from = this.getFrom(); - const to = this.getTo(); - const recordsPerPage = this.numRows; - - const newFrom = from - recordsPerPage; - const newTo = newFrom + recordsPerPage - 1; - - // Check that 'from' does not exceed 0. - if (newFrom < 0) { - this.setFrom(0); - this.setTo(recordsPerPage - 1); - } else { - this.setFrom(newFrom); - this.setTo(newTo); - } - } catch (error) { - console.error( - `Error in goToPreviousPage: ${ - error instanceof Error ? error.message : error - }` - ); + const from = this.getFrom(); + const to = this.getTo(); + const recordsPerPage = this.numRows; + + const newFrom = from - recordsPerPage; + const newTo = newFrom + recordsPerPage - 1; + + // Check that 'from' does not exceed 0. + if (newFrom < 0) { + this.setFrom(0); + this.setTo(recordsPerPage - 1); + } else { + this.setFrom(newFrom); + this.setTo(newTo); } } - + async searchByIdStateChange(id: number): Promise { - try { - const newFrom = id; - const newTo = id + this.numRows - 1; - const recordsPerPage = this.numRows; - - // Checking that 'to' does not exceed totalRecordCount. - if (newTo >= this.totalRecordCount) { - this.setTo(this.totalRecordCount - 1); - this.setFrom(this.totalRecordCount - recordsPerPage); - } else { - this.setTo(newTo); - this.setFrom(newFrom); - } - - await this.retrieveRecords(); - } catch (error) { - console.error( - `Error in searchByIdStateChange: ${ - error instanceof Error ? error.message : error - }` - ); + const newFrom = id; + const newTo = id + this.numRows - 1; + const recordsPerPage = this.numRows; + + // Checking that 'to' does not exceed totalRecordCount. + if (newTo >= this.totalRecordCount) { + this.setTo(this.totalRecordCount - 1); + this.setFrom(this.totalRecordCount - recordsPerPage); + } else { + this.setTo(newTo); + this.setFrom(newFrom); } + + await this.retrieveRecords().catch(error => { + console.error("Error retrieving records in searchByIdStateChange:", error); + throw error; + }); } /** Adjusts the available height based on window size and recalculates the number of rows. */ adjustWindowSize(): void { - try { - if (typeof window === "undefined" || !window.innerHeight) { - throw new Error("Unable to access window dimensions"); - } - - // Determine the dynamic height of the header and pagination. - const mainHeadingElement = document.getElementById("main-heading"); - const paginationElement = document.getElementById("pagination"); - - if (mainHeadingElement && paginationElement) { - this.headerHeight = - mainHeadingElement.clientHeight + - paginationElement.clientHeight; - } else { - console.error( - "Could not find main-heading and/or pagination elements" - ); - } - if (!this.rowHeight) { - throw new Error("Row height is not properly configured"); - } - - this.availableHeight = - window.innerHeight - this.headerHeight - this.rowHeight * 2; - this.numRows = Math.floor(this.availableHeight / this.rowHeight); - - if (this.numRows <= 0) { - console.log( - "Window size too small, setting minimum number of rows to 1" - ); - this.numRows = 1; - } - - // Calculating new values without modifying the state immediately. - let newFrom = this.from; - let newTo = this.from + this.numRows - 1; - - // If it's the first set of records ("first page"), start from 0 and populate the whole window size. - if (this.from === 0) { - newFrom = 0; - newTo = this.numRows - 1; - } - - // Ensure `newTo` doesn't exceed totalRecordCount and adjust `newFrom` accordingly, - // meaning populate the whole window size. - if (newTo >= this.totalRecordCount) { - newTo = this.totalRecordCount - 1; + if (typeof window === "undefined" || !window.innerHeight) { + throw new Error("Unable to access window dimensions"); + } + + // Determine the dynamic height of the header and pagination. + const mainHeadingElement = document.getElementById("main-heading"); + const paginationElement = document.getElementById("pagination"); + + if (mainHeadingElement && paginationElement) { + this.headerHeight = + mainHeadingElement.clientHeight + + paginationElement.clientHeight; + } else { + throw new Error("Could not find main-heading and/or pagination elements"); + } + + if (!this.rowHeight) { + throw new Error("Row height is not properly configured"); + } + + this.availableHeight = + window.innerHeight - this.headerHeight - this.rowHeight * 2; + this.numRows = Math.floor(this.availableHeight / this.rowHeight); + + if (this.numRows <= 0) { + console.log("Window size too small, setting minimum number of rows to 1"); + this.numRows = 1; + } + + // Calculating new values without modifying the state immediately. + let newFrom = this.from; + let newTo = this.from + this.numRows - 1; + + // If it's the first set of records ("first page"), start from 0 and populate the whole window size. + if (this.from === 0) { + newFrom = 0; + newTo = this.numRows - 1; + } + + // Ensure `newTo` doesn't exceed totalRecordCount and adjust `newFrom` accordingly, + // meaning populate the whole window size. + if (newTo >= this.totalRecordCount) { + newTo = this.totalRecordCount - 1; + newFrom = newTo - this.numRows + 1; + } + + // Check if the highlighted ID is currently between from and to, + // to enable priority functionality (always visible in the window). + const highlightedId = this.getHighlightedId(); + if ( + highlightedId !== null && + highlightedId >= this.from && + highlightedId <= this.to + ) { + // If newTo would be smaller than highlightedId, adjust to keep highlightedId in view. + if (newTo < highlightedId) { + newTo = highlightedId; newFrom = newTo - this.numRows + 1; } - - // Check if the highlighted ID is currently between from and to, - // too enable priority functionality (always visible in the window). - const highlightedId = this.getHighlightedId(); - if ( - highlightedId !== null && - highlightedId >= this.from && - highlightedId <= this.to - ) { - // If newTo would be smaller than highlightedId, adjust to keep highlightedId in view. - if (newTo < highlightedId) { - newTo = highlightedId; - newFrom = newTo - this.numRows + 1; - } - } - - // Now, after all conditions have been checked, set the state. - this.setFrom(newFrom); - this.setTo(newTo); - } catch (error) { - console.error( - `Error in adjustWindowSize: ${ - error instanceof Error ? error.message : error - }` - ); } + + // Now, after all conditions have been checked, set the state. + this.setFrom(newFrom); + this.setTo(newTo); } - + async retrieveRecords(): Promise { - try { - this.records = await this.apiManager.fetchRecords( - this.from, - this.to - ); - } catch (error) { - console.error( - `Error retrieving records: ${ - error instanceof Error ? error.message : error - }` - ); - } + this.records = await this.apiManager + .fetchRecords(this.from, this.to) + .catch((error) => { + console.error( + `Error fetching records: ${ + error instanceof Error ? error.message : error + }` + ); + throw error; + }); } - - - - - - - } diff --git a/views.js b/views.js deleted file mode 100644 index 27a8b8c7..00000000 --- a/views.js +++ /dev/null @@ -1,157 +0,0 @@ -"use strict"; -//*** Views ***/ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -/** - * TableRenderer is responsible for rendering data into an HTML table. - * It fetches data from the StateManager and populates the table accordingly. - */ -var TableRenderer = /** @class */ (function () { - function TableRenderer(stateManager) { - this.stateManager = stateManager; - } - /** - * Renders the initial table layout including column names and initial data set. - * @param {StateManager} stateManager - The manager to fetch state from. - */ - TableRenderer.prototype.initialRender = function () { - return __awaiter(this, void 0, void 0, function () { - var columnNames, records, error_1; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 2, , 3]); - columnNames = this.stateManager.getColumnNames(); - if (columnNames !== null) { - this.renderColumnNames(columnNames); - } - return [4 /*yield*/, this.stateManager.retrieveRecords()]; - case 1: - _a.sent(); - records = this.stateManager.getRecords(); - if (records !== null) { - this.renderRecords(records); - } - return [3 /*break*/, 3]; - case 2: - error_1 = _a.sent(); - console.error("Error during initialRender: " + error_1); - return [3 /*break*/, 3]; - case 3: return [2 /*return*/]; - } - }); - }); - }; - TableRenderer.prototype.renderColumnNames = function (columnNames) { - try { - var thead = document.querySelector("thead"); - if (thead === null) { - throw new Error("Table header not found."); - } - var row = document.createElement("tr"); - for (var _i = 0, columnNames_1 = columnNames; _i < columnNames_1.length; _i++) { - var columnName = columnNames_1[_i]; - var cell = document.createElement("th"); - cell.textContent = columnName; - row.appendChild(cell); - } - thead.appendChild(row); - this.setColumnWidths(); - } - catch (error) { - if (error instanceof Error) { - console.error("An error occurred: " + error.message); - } - else { - console.error("An unknown error occurred: " + error); - } - } - }; - /** Sets the widths of table columns evenly. */ - TableRenderer.prototype.setColumnWidths = function () { - try { - var table = document.getElementById("myTable"); - if (!table) { - throw new Error('Table with id "myTable" not found.'); - } - var headerCells = table.querySelectorAll("th"); - var numCols = headerCells.length; - var colWidth_1 = 100 / numCols; - headerCells.forEach(function (headerCell) { - headerCell.style.width = colWidth_1 + "%"; - }); - } - catch (error) { - console.error("Error setting column widths: " + error); - } - }; - //Populates the table body with records. Optionally highlights a specified row if searched. - TableRenderer.prototype.renderRecords = function (records, highlightId) { - if (highlightId === void 0) { highlightId = null; } - // Use the state's highlightedId if no highlightId is provided. - highlightId = highlightId !== null && highlightId !== void 0 ? highlightId : this.stateManager.getHighlightedId(); - try { - if (records === null) { - throw new Error("No records to render."); - } - var tbody_1 = document.querySelector("tbody"); - if (tbody_1 === null) { - throw new Error("Table body not found."); - } - tbody_1.innerHTML = ""; - records.forEach(function (record) { - var row = document.createElement("tr"); - if (highlightId !== null && - record.length > 0 && - parseInt(record[0].toString(), 10) === highlightId) { - row.classList.add("highlight"); - } - record.forEach(function (cell) { - var td = document.createElement("td"); - td.textContent = cell.toString(); - row.appendChild(td); - }); - tbody_1.appendChild(row); - }); - } - catch (error) { - console.error("An error occurred: " + error); - } - }; - return TableRenderer; -}()); -//# sourceMappingURL=views.js.map \ No newline at end of file diff --git a/views.js.map b/views.js.map deleted file mode 100644 index 5f423f54..00000000 --- a/views.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"views.js","sourceRoot":"","sources":["views.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/views.ts b/views.ts index 63ceee80..6b8dd3ac 100644 --- a/views.ts +++ b/views.ts @@ -7,7 +7,7 @@ class TableRenderer { private stateManager: StateManager; - constructor(stateManager: StateManager) { + constructor (stateManager: StateManager) { this.stateManager = stateManager; } @@ -16,45 +16,50 @@ class TableRenderer { * @param {StateManager} stateManager - The manager to fetch state from. */ async initialRender(): Promise { - try { - const columnNames = this.stateManager.getColumnNames(); - if (columnNames !== null) { - this.renderColumnNames(columnNames); - } + const columnNames = this.stateManager.getColumnNames(); + if (columnNames !== null) { + this.renderColumnNames(columnNames); + } - await this.stateManager.retrieveRecords(); - const records = this.stateManager.getRecords(); + await this.stateManager.retrieveRecords().catch((error) => { + console.error("Error retrieving records in initialRender:", error); + throw error; + }); - if (records !== null) { - this.renderRecords(records); - } - } catch (error) { - console.error(`Error during initialRender: ${error}`); + const records = this.stateManager.getRecords(); + + if (records !== null) { + this.renderRecords(records); } } renderColumnNames(columnNames: string[]): void { - try { - const thead = document.querySelector("thead"); - if (thead === null) { - throw new Error("Table header not found."); - } + const thead = document.querySelector("thead"); + if (thead === null) { + throw new Error("Table header not found."); + } - const row = document.createElement("tr"); - for (const columnName of columnNames) { - const cell = document.createElement("th"); - cell.textContent = columnName; - row.appendChild(cell); - } - thead.appendChild(row); + const row = document.createElement("tr"); + for (const columnName of columnNames) { + const cell = document.createElement("th"); + cell.textContent = columnName; + row.appendChild(cell); + } + thead.appendChild(row); + try { this.setColumnWidths(); } catch (error) { if (error instanceof Error) { - console.error(`An error occurred: ${error.message}`); + console.error( + `An error occurred in setColumnWidths: ${error.message}` + ); } else { - console.error(`An unknown error occurred: ${error}`); + console.error( + `An unknown error occurred in setColumnWidths: ${error}` + ); } + throw error; } } @@ -79,43 +84,33 @@ class TableRenderer { } } - //Populates the table body with records. Optionally highlights a specified row if searched. - renderRecords( - records: CityData[] | null, - highlightId: number | null = null - ) { + /** Populates the table body with records. Optionally highlights a specified row if searched. */ + renderRecords(records: CityData[], highlightId: number | null = null) { // Use the state's highlightedId if no highlightId is provided. highlightId = highlightId ?? this.stateManager.getHighlightedId(); - try { - if (records === null) { - throw new Error("No records to render."); - } - const tbody = document.querySelector("tbody"); - if (tbody === null) { - throw new Error("Table body not found."); - } + const tbody = document.querySelector("tbody"); + if (tbody === null) { + throw new Error("Table body not found."); + } - tbody.innerHTML = ""; - - records.forEach((record) => { - const row = document.createElement("tr"); - if ( - highlightId !== null && - record.length > 0 && - parseInt(record[0].toString(), 10) === highlightId - ) { - row.classList.add("highlight"); - } - record.forEach((cell) => { - const td = document.createElement("td"); - td.textContent = cell.toString(); - row.appendChild(td); - }); - tbody.appendChild(row); - }); - } catch (error) { - console.error(`An error occurred: ${error}`); + tbody.innerHTML = ""; + + for (const record of records) { + const row = document.createElement("tr"); + if ( + highlightId !== null && + record.length > 0 && + parseInt(record[0].toString(), 10) === highlightId + ) { + row.classList.add("highlight"); + } + for (const cell of record) { + const td = document.createElement("td"); + td.textContent = cell.toString(); + row.appendChild(td); + } + tbody.appendChild(row); } } }