Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
1. Replace `<your_account>` with your GitHub username in the link
- [DEMO LINK](https://<your_account>.github.io/js_employees_table_DOM/)
- [DEMO LINK](https://Banderos14.github.io/js_employees_table_DOM/)
2. Follow [this instructions](https://mate-academy.github.io/layout_task-guideline/)
- Run `npm run test` command to test your code;
- Run `npm run test:only -- -n` to run fast test ignoring linter;
Expand Down Expand Up @@ -44,11 +44,11 @@ Start table:
```
- Add qa attributes for each input field:
```
data-qa="name"
data-qa="position"
data-qa="office"
data-qa="age"
data-qa="salary"
data-qa="name"
data-qa="position"
data-qa="office"
data-qa="age"
data-qa="salary"
```
- Select should have 6 options: `Tokyo`, `Singapore`, `London`, `New York`, `Edinburgh`, `San Francisco`.
- Use texts for labels and buttons from the screenshot below.
Expand All @@ -64,7 +64,7 @@ Start table:
- Notification titles and descriptions are up to you.
- Add qa attribute for notification: `data-qa="notification"` and class `error`/`success` depending on the result.

##### Implement editing of table cells by double-clicking on them (optional).
##### Implement editing of table cells by double-clicking on them (optional).
- Double click on the cell of the table, which should remove the text, and append input with `cell-input` class.
- The input value should be replaced by the input text.
- Only one cell can be edited at a time.
Expand Down
307 changes: 306 additions & 1 deletion src/scripts/main.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,308 @@
'use strict';

// write code here
const thead = document.querySelector('thead');
const tbody = document.querySelector('tbody');

// -1 потому что мы изначально не делаем никакое действие сортировки
let currentColumn = -1;
// asc - ascending
let currentDirection = 'asc';

thead.addEventListener('click', (e) => {
if (e.target.tagName !== 'TH') {
return;
}

const rows = Array.from(tbody.querySelectorAll('tr'));
const index = Array.from(e.target.parentNode.children).indexOf(e.target);

if (currentColumn === index) {
currentDirection = currentDirection === 'asc' ? 'desc' : 'asc';
} else {
currentColumn = index;
currentDirection = 'asc';
}

rows.sort((a, b) => {
let valueA = a.children[index].textContent.trim();
let valueB = b.children[index].textContent.trim();

if (index === 3 || index === 4) {
valueA = Number(valueA.replace(/[$,]/g, ''));
valueB = Number(valueB.replace(/[$,]/g, ''));
} else {
valueA = valueA.toLowerCase();
valueB = valueB.toLowerCase();
}

if (valueA < valueB) {
return currentDirection === 'asc' ? -1 : 1;
}

if (valueA > valueB) {
return currentDirection === 'asc' ? 1 : -1;
}

return 0;
});

tbody.append(...rows);
});

tbody.addEventListener('click', (e) => {
const row = e.target.closest('tr');

if (!row) {
return;
}

const activeRow = tbody.querySelector('.active');

if (activeRow) {
activeRow.classList.remove('active');
}

row.classList.add('active');
});

// Notification
function showNotification(message, type) {
const old = document.querySelector('[data-qa="notification"]');

if (old) {
old.remove();
}

const notification = document.createElement('div');

notification.dataset.qa = 'notification';
notification.classList.add('notification');
notification.classList.add(type);
notification.textContent = message;

document.body.append(notification);
}

// Новое поле
const form = document.createElement('form');

form.classList.add('new-employee-form');

// Name
const nameLabel = document.createElement('label');

nameLabel.textContent = 'Name: ';

const nameInput = document.createElement('input');

nameInput.name = 'name';
nameInput.type = 'text';
nameInput.dataset.qa = 'name';

nameLabel.append(nameInput);
form.append(nameLabel);

// Position
const positionLabel = document.createElement('label');

positionLabel.textContent = 'Position: ';

const positionInput = document.createElement('input');

positionInput.name = 'position';
positionInput.type = 'text';
positionInput.dataset.qa = 'position';

positionLabel.append(positionInput);
form.append(positionLabel);

// Office
const officeLabel = document.createElement('label');

officeLabel.textContent = 'Office: ';

const officeSelect = document.createElement('select');

officeSelect.name = 'office';
officeSelect.dataset.qa = 'office';

const defaultOfficeOption = document.createElement('option');

defaultOfficeOption.value = '';
defaultOfficeOption.textContent = 'Select office';

officeSelect.append(defaultOfficeOption);

const offices = [
'Tokyo',
'Singapore',
'London',
'New York',
'Edinburgh',
'San Francisco',
];

offices.forEach((office) => {
const option = document.createElement('option');

option.value = office;
option.textContent = office;

officeSelect.append(option);
Comment thread
Banderos14 marked this conversation as resolved.
});

officeLabel.append(officeSelect);
form.append(officeLabel);

// Age
const ageLabel = document.createElement('label');

ageLabel.textContent = 'Age: ';

const ageInput = document.createElement('input');

ageInput.name = 'age';
ageInput.type = 'number';
ageInput.dataset.qa = 'age';

ageLabel.append(ageInput);
form.append(ageLabel);

// Salary
const salaryLabel = document.createElement('label');

salaryLabel.textContent = 'Salary: ';

const salaryInput = document.createElement('input');

salaryInput.name = 'salary';
salaryInput.type = 'number';
salaryInput.dataset.qa = 'salary';

salaryLabel.append(salaryInput);
form.append(salaryLabel);

const submitButton = document.createElement('button');

submitButton.type = 'submit';
submitButton.textContent = 'Save to table';

form.append(submitButton);

form.addEventListener('submit', (e) => {
e.preventDefault();

const nameEmployer = nameInput.value.trim();
const position = positionInput.value.trim();
const office = officeSelect.value;
const age = Number(ageInput.value);
const salary = salaryInput.value.trim();

if (nameEmployer.length < 4) {
showNotification('Name is too short', 'error');

return;
}

if (!position) {
showNotification('Position is required', 'error');

return;
}

if (!office) {
showNotification('Office is required', 'error');

return;
}

if (age < 18 || age > 90) {
showNotification('Age is invalid', 'error');

return;
}

if (!salary) {
showNotification('Salary is required', 'error');

Comment thread
Banderos14 marked this conversation as resolved.
return;
Comment thread
Banderos14 marked this conversation as resolved.
}

const tr = document.createElement('tr');

const tdName = document.createElement('td');

tdName.textContent = nameEmployer;

const tdPosition = document.createElement('td');

tdPosition.textContent = position;

const tdOffice = document.createElement('td');

tdOffice.textContent = office;

const tdAge = document.createElement('td');

tdAge.textContent = age;

const tdSalary = document.createElement('td');

tdSalary.textContent = `$${Number(salary).toLocaleString()}`;

tr.append(tdName, tdPosition, tdOffice, tdAge, tdSalary);
tbody.append(tr);

form.reset();
showNotification('Employee added', 'success');
});

document.body.append(form);
Comment thread
Banderos14 marked this conversation as resolved.

// Редактирование ячеек
let editingCell = null;

tbody.addEventListener('dblclick', (e) => {
const cell = e.target.closest('td');

if (!cell) {
return;
}

if (cell.querySelector('input')) {
return;
}

if (editingCell) {
return;
}

editingCell = cell;

const initialValue = cell.textContent.trim();
const input = document.createElement('input');

input.classList.add('cell-input');
input.value = initialValue;

cell.textContent = '';
cell.append(input);
input.focus();

function saveCellValue() {
const newValue = input.value.trim();

cell.textContent = newValue || initialValue;
editingCell = null;
}

input.addEventListener('blur', () => {
saveCellValue();
});

input.addEventListener('keydown', (eventInput) => {
if (eventInput.key === 'Enter') {
input.blur();
}
});
});
Loading