Skip to content

Updated Project#47

Open
ThokozaniNqwili wants to merge 33 commits into
IMQS:masterfrom
ThokozaniNqwili:master
Open

Updated Project#47
ThokozaniNqwili wants to merge 33 commits into
IMQS:masterfrom
ThokozaniNqwili:master

Conversation

@ThokozaniNqwili

Copy link
Copy Markdown

No description provided.

Comment thread app.ts Outdated
Comment thread app.ts Outdated
}
}

let resizeTimeout: number;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another global variable

Comment thread app.ts
Comment thread app.ts Outdated
$('#page').empty();
$('#page').append(`Showing record: ${firstNumber} - ${count}`);
$('#loader').hide()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove space

Comment thread app.ts
Comment thread app.ts Outdated
}
if (records[r].includes(inputValue)) {

lastRow.css('background-color', '#DDC0B4'); // hightlights the searched row

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove spaces around

Comment thread app.ts Outdated
}
fetchColumns()

async function adjustRowsByScreenHeight(): Promise<number> { // calculates the number of rows that can fit the screen

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this an async?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a mistake because of my understanding, I will work on it.

Comment thread app.ts Outdated
if (firstNumber < 0) {
firstNumber = 0;
lastNumber = firstNumber + (calculatedRows - 1);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move the else on the same line as the } please

Comment thread app.ts Outdated
lastNumber = firstNumber

}
if (!lastNumber) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this and the else does exactly the same

Comment thread app.ts Outdated
@@ -0,0 +1,199 @@
import { ajax, css } from "jquery";
var firstNumber: number = 0;
var lastNumber: number;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be nice to have a default

Comment thread index.html Outdated
</table>


<script src="app.js"></script>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can move script tag into the head tag

@DevinFledermaus DevinFledermaus left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments as initial changes

Comment thread app.ts Outdated
@@ -0,0 +1,183 @@
import { ajax, css } from "jquery";
let firstNumber: number = 0;
let lastNumber: number = 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to set the variable and the type, either give a type, or set it

Comment thread app.ts Outdated
if (!recordCount.ok) {
throw new Error('Failed to fetch record count');
}
const data = await recordCount.json()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const data = await recordCount.json()
const data = JSON.parse(recordCount)

Comment thread app.ts Outdated
.then((columns: string[]) => {
const colArray = columns;

for (let c = 0; c < colArray.length; c++) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use for..of loop please

Comment thread app.ts Outdated
if (calculatedRows === 0) {
lastNumber = firstNumber
}
if (firstNumber < 0) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else if and move in the same line as }

Comment thread app.ts Outdated
if (firstRow) { // checks if the first row exists
const cells = firstRow.querySelectorAll("td");
const firstRecord: string[] = [];
cells.forEach((cell) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather make use of a for..of loop, even a for loop is fine, but for of is preferred

Comment thread app.ts Outdated
import { ajax, css } from "jquery";
let firstNumber = 0;
let lastNumber = 0;
let backend: string = "http://localhost:2050";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try for 2 global variables

Comment thread app.ts Outdated
} catch (error) {
throw new Error('Error fetching the record count')
};
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for ; after declaring a function

Comment thread app.ts Outdated
Comment on lines +55 to +56
const jsonText = await response.text();
const columns: string[] = await JSON.parse(jsonText);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const jsonText = await response.text();
const columns: string[] = await JSON.parse(jsonText);
const columns: string[] = JSON.parse(response.text());

Comment thread app.ts Outdated
};
};

function adjustRowsByScreenHeight() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to use the function keyword and provide a return type

Comment thread app.ts Outdated
async function displayRecords(): Promise<void> {
try {
$('#loader').show();
let count = await fetchRecordCount() - 1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still not done

Comment thread app.ts Outdated
Comment on lines +100 to +108
try {
const response = await fetch(`${backend}/records?from=${from}&to=${to}`);
if (!response.ok) {
throw new Error("Sorry, there's a problem with the network");
}
return response.json();
} catch (error) {
throw new Error('Error fetching records from server');
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for the async anymore, and can remove the try and catch

Suggested change
try {
const response = await fetch(`${backend}/records?from=${from}&to=${to}`);
if (!response.ok) {
throw new Error("Sorry, there's a problem with the network");
}
return response.json();
} catch (error) {
throw new Error('Error fetching records from server');
};
return fetch(`${backend}/records?from=${from}&to=${to}`)
.then(res => {
if (!res.ok) {
throw "Sorry, there's a problem with the network";
}
return res.json();
}).catch(err => {
throw 'Error fetching records from server ' + err;
});

Comment thread app.ts Outdated
Comment on lines +1 to +2
import { ajax, css } from "jquery";
class GlobalVariables {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please leave an empty line between your imports and class definitions.

Comment thread app.ts Outdated
Comment on lines +6 to +8
resizeTimeout = 0;
//fetches the number of records from localhost
fetchRecordCount(): Promise<number> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please leave and empty line between your class attributes and your functions.

Comment thread app.ts Outdated
Comment on lines +3 to +6
firstNumber = 0;
lastNumber = 0;
backend = "http://localhost:2050";
resizeTimeout = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a type to each of these variables.

Comment thread app.ts Outdated
lastNumber = 0;
backend = "http://localhost:2050";
resizeTimeout = 0;
//fetches the number of records from localhost

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change this to a javadoc style comment. and instead of saying localhost, rather say "the backend attribute on this class"

Comment thread app.ts Outdated
//fetches the number of records from localhost
fetchRecordCount(): Promise<number> {
return fetch(`${this.backend}/recordCount`)
.then((res) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either remove the () around the res, or specify the correct type for res

Comment thread app.ts Outdated
let inputValue = $('#searchInput').val() as number;
$('#page').empty();
//calls to calculate the range once button is clicked
await updateRecordsAndResize(inputValue);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function can throw an error, please catch it and handle it.

Comment thread app.ts Outdated
rightArrow();
})
$('.arrow-left').on('click', () => {
leftArrow();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function can throw and error, please catch it and handle it.

Comment thread style.css Outdated
}

.loader-spinner {
border: calc(200px / 10) solid #97694F;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calc is really really really bad, please don't use it.

Comment thread style.css Outdated
justify-content: center;
align-items: center;
z-index: 9999;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something happend with your formatting here.

Comment thread style.css Outdated
height: 100px;
animation: spin 2s linear infinite;
background-color: #f7e7ce;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatting issue here.

@CelesteNaude CelesteNaude left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make sure that all events that the user can fire off is debounced, i.e. search, resize, and buttons.

Comment thread app.ts Outdated
@@ -0,0 +1,265 @@
import { ajax, css } from "jquery";

class Myclass {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move the class into a separate file.

Comment thread app.ts Outdated
Comment on lines +168 to +170
const halfRange = Math.floor(calculatedRows / 2);
myClass.firstNumber = Math.max(0, inputValue - halfRange);
myClass.lastNumber = Math.min(recordCount, myClass.firstNumber + (calculatedRows - 1));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, you show the searched record in the middle of the grid and highlight it. In IMQS we show the most relevant record we're searching for at the top of the grid without formatting. But you can still keep the formatting because it's cool.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Soooooo... I can't find an example that @CelesteNaude is talking about... I can only find two examples where we do it the way that you are doing it. But that has a lot to do with the fact that most of the time we filter instead of search.

(BTW @CelesteNaude, the two places is user-management, where we highlight and scroll to the user you just edited and the grids on the map, when you click on something on the map, and highlight and scroll to the feature you clicked on)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This I remember from the advice that was given to me for my own onboarding project, weird.

Comment thread app.ts Outdated
/** determines te value in the last row */
const lastID = parseFloat(lastRecord[0]);
/** checks if the last value is within range */
if (0 <= lastID && lastID <= (recordCount)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need the () around recordCount

Comment thread app.ts Outdated
}
/** determines te value in the first row */
const firstID = parseFloat(firstRecord[0]);
if (0 <= firstID && firstID <= (recordCount)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Comment thread app.ts Outdated
@@ -0,0 +1,230 @@
import { ajax, css } from "jquery";

const myClass = new Myclass();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Global variables are bad, please remove them.

Comment thread app.ts Outdated
@@ -0,0 +1,230 @@
import { ajax, css } from "jquery";

const myClass = new Myclass();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also... please... please give it a better name... This name creates the idea that the Dev that made it isn't even aware of what it is used for.

Comment thread app.ts Outdated
const myClass = new Myclass();

/** Initializes the table head */
function createTable(): Promise<string[]> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is the right name for your function. It seems to be adding headings to a dom element with the class head. Which does not sound like it is "creating a table".

I also don't know how I feel about returning an array of strings? Or anything for that matter. In my head a create* function is either creating something and returning it, or creating something somewhere and returning a reference to it. With the "returning a reference" being completely optional, and I your case I don't think you should be returning anything.

Comment thread app.ts Outdated
}

/** calculates the number of rows that can fit the screen */
const calculatingRows = (): number => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... why make a constant variable that points to a function? You can just make a function. Please change this to just be a normal function.

Comment thread app.ts Outdated
}
})
.catch(err => {
throw new Error('Error occured while resizing' + err);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the last line of defense, you have to handle the error.

Comment thread myClass.ts Outdated
@@ -0,0 +1,48 @@
class Myclass {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned, please rename the class

Comment thread myClass.ts Outdated
Comment on lines +2 to +3
firstNumber: number = 0;
lastNumber: number = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two values are not being used in this class... Maybe you forgot to add methods using them? Or maybe they should not be in this class?

Comment thread myClass.ts Outdated
firstNumber: number = 0;
lastNumber: number = 0;
backend: string = "http://localhost:2050";
resizeTimeout: number = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This value is not being used in this class... Maybe you forgot to add methods that uses it? or maybe it should not be in this class?

Comment thread myClass.ts Outdated
}

/** fetches records from backend */
fetchRecords(from: number, to: number): Promise<any[]> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use any

Comment thread myClass.ts
resizeTimeout: number = 0;

/** fetches the number of records from backend */
fetchRecordCount(): Promise<number> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You saaaaay number... yet you return res.json()... something is not adding up.

Comment thread app.ts Outdated
if (this.firstNumber < 0) {
this.firstNumber = 0;
} else {
this.firstNumber = this.firstNumber;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting this.firstNumber equal to this.firstNumber? Sjoe 😢 Is the else then even necessary?

Comment thread app.ts Outdated
});

$('#searchInput').on('keydown', (event) => {
if (event.key === 'e' || event.key === 'E') {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rather make use of regex to stop the user from entering anything besides a digit.

Comment thread app.ts Outdated
Comment on lines +243 to +245
if (inputValue.includes('.')) {
$('#searchInput').val(inputValue.replace('.', ''));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With regex then these checks won't be necessary since you know the user could only type in digits.

Comment thread app.ts Outdated
}

/** calculates the number of rows that can fit the screen */
calculatingRows(): number {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
calculatingRows(): number {
getNumberOfRows(): number {

With a function name like that it is more descriptive of what it does. calculatingRows sounds like a boolean check like isCalculatingRows? Rather give it the verb of what it is going to do. I mean, since this function returns something how about get? How it got it is not maybe important. It calculated it, someone else calculated it? We just want the number of rows.

Comment thread app.ts Outdated
Comment on lines +164 to +172
const lastID = parseFloat(cells[0].textContent || "");
// checks if the last value is within range
if (0 <= lastID && lastID <= this.recordCount) {
// calculates the first number of the page
this.firstNumber = lastID + 1;
const calculatedRows = this.calculatingRows();
// calculates the last number of the page
this.lastNumber = this.firstNumber + (calculatedRows - 1);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way I understand this function, you only need this part of the logic. You don't have to go and find the last child. You know what it is because you set it in this.lastNumber, right? Replace lastID with this.lastNumber and then you can remove the rest and just call this.updateAndDisplayRecords afterward.

Comment thread app.ts Outdated
Comment on lines +185 to +190
const firstID = parseFloat(cells[0].textContent || "");
if (0 <= firstID && firstID <= this.recordCount) {
const calculatedRows = this.calculatingRows();
this.lastNumber = firstID - 1;
this.firstNumber = this.lastNumber - (calculatedRows - 1);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar comment to the rightArrow function's comment. You don't have to rely on the HTML. You are the point of truth. Also, maybe a more descriptive function name instead of rightArrow and leftArrow? I mean, what does the function do? Navigate back and forth. Verbs instead.

Comment thread style.css Outdated
.showRecords {
top: 0.8%;
right: 0;
padding: 1rem;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather make use of px instead of rem

Comment thread app.ts Outdated
if (inputValue !== '') {
errorMessage = 'Failed to search, reload the page and search again';
$('#loader').show();
this.searchRecordsAndResize();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not call this outside of updateAndDisplayRecords.
Call both this.searchRecordsAndResize and then this.updateAndDisplayRecords in your search input event?

@FritzOnFire FritzOnFire left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always try and handle errors as late as possible, otherwise your code will not be very portable and reusable.

Comment thread app.ts Outdated
this.firstNumber = 0;
this.lastNumber = 0;
this.recordCount = 0;
this.initialize();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not recommend calling functions that can throw errors in a constructor... You could technically still handle the errors, but the rest of your code would think everything went fine, when it very much did not.

Please call this initialize after creating a new instance of RecordManager

Comment thread app.ts Outdated
Comment on lines +16 to +27
this.createTableHeader();
dataManager.fetchRecordCount()
.then(count => {
this.recordCount = count - 1;
this.updateAndDisplayRecords();
this.recordEventHandlers();
this.handleResize();
})
.catch(err => {
alert('Error fetching and displaying the table records, reload the page');
throw err;
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So... two things.

  1. Returning a promise makes catching errors much much easier for the calling function, so i would recommend always doing it. BUT

  2. Here you are kicking off two async function calls that do not depend on each other, which is beautiful :) This is a great way to speed up an app, but the calling function still needs to be able to handle the error of the function that you are not waiting for. And so now I will be breaking my own rule about not commenting exact code on an onboarding project. This is how you can wait on multiple async functions at the same time:

Suggested change
this.createTableHeader();
dataManager.fetchRecordCount()
.then(count => {
this.recordCount = count - 1;
this.updateAndDisplayRecords();
this.recordEventHandlers();
this.handleResize();
})
.catch(err => {
alert('Error fetching and displaying the table records, reload the page');
throw err;
});
let p: Promise<void>[] = [];
p.push(this.createTableHeader());
let frcp = dataManager.fetchRecordCount()
.then(count => {
this.recordCount = count - 1;
this.updateAndDisplayRecords();
this.recordEventHandlers();
this.handleResize();
})
.catch(err => {
alert('Error fetching and displaying the table records, reload the page');
throw err;
});
p.push(frcp);
return Promise.all(p);

Comment thread app.ts Outdated
Comment on lines +25 to +26
alert('Error fetching and displaying the table records, reload the page');
throw err;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

???

So you handle the error... and then you throw it anyway meaning that you have to handle it again later?

Please do not handle the error here, as who ever is calling initialize needs to know that we failed to initialize and they need to react accordingly.

Comment thread app.ts Outdated
Comment on lines +39 to +40
alert('Error creating table heading');
throw err;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar comment as before about handling and then throwing again.

Comment thread app.ts Outdated
Comment on lines +67 to +68
alert('Error to fetch and display records, reload the page');
throw err;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar comment as before about handling and then throwing again.

Comment thread app.ts Outdated
$('#btnSearch').on('click', (event) => {
event.preventDefault();
this.searchRecordsAndResize();
this.updateAndDisplayRecords();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to handle the error being thrown by updateAndDisplayRecords

Comment thread dataManager.ts Outdated
if (!res.ok) {
throw 'Failed to fetch record count';
}
return res.json();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return res.json();
return res.text();

Comment thread dataManager.ts Outdated
return res.json();
})
.then(totalRecords => {
if(typeof totalRecords !== 'number'){

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice touch :) Now I kinda feel bad for asking you to not use json.

Comment thread dataManager.ts

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very creative way to hide the fact that you are using a global variable called backend. While there is nothing wrong with using static, and even making a class like this, as there truly is a time and a place for everything, its just unfortunately not in this on boarding project. Please remove all the static labels in this class.

This is basically as bad as turning off asynchronous requests in javascript for this project (I have only seen it once, and I am unable to find out how to do it, but I know it exists).

Comment thread index.html Outdated
<p>Hello</p>
<div id="loader">
<div class="loader-spinner"></div>
</div>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your formatting is a bit off here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants