diff --git a/05-dom-document-loading/1-notification/index.js b/05-dom-document-loading/1-notification/index.js index 2a95c5e..79bd10a 100644 --- a/05-dom-document-loading/1-notification/index.js +++ b/05-dom-document-loading/1-notification/index.js @@ -1,5 +1,6 @@ export default class NotificationMessage { static lastShownNotification; + timerId; constructor(messageText = '', props = {}) { const { @@ -45,7 +46,7 @@ export default class NotificationMessage { } hide() { - setTimeout(() => this.remove(), this.duration); + this.timerId = setTimeout(() => this.remove(), this.duration); } remove() { @@ -54,5 +55,6 @@ export default class NotificationMessage { destroy() { this.remove(); + clearTimeout(this.timerId); } } diff --git a/05-dom-document-loading/2-sortable-table-v1/index.js b/05-dom-document-loading/2-sortable-table-v1/index.js index d40b94b..93f2152 100644 --- a/05-dom-document-loading/2-sortable-table-v1/index.js +++ b/05-dom-document-loading/2-sortable-table-v1/index.js @@ -1,6 +1,172 @@ export default class SortableTable { + subElements = {}; + orderValue; + fieldValue; + constructor(headerConfig = [], data = []) { + this.headerConfig = headerConfig; + this.data = data; + this.element = this.createElement(this.createTemplate()); + this.selectSubElements(); + } + + createElement(template) { + const element = document.createElement("div"); + element.innerHTML = template; + return element.firstElementChild; + } + + selectSubElements() { + this.element.querySelectorAll('[data-element]').forEach(element => { + this.subElements[element.dataset.element] = element; + }); + } + + createTableHeaderArrowTemplate() { + return ` + + `; + } + + createTableHeaderCellTemplate(columnData) { + const isSortable = columnData.sortable && this.orderValue && columnData.id === this.fieldValue; + const dataOrder = isSortable ? `data-order="${this.orderValue}"` : ''; + return ` +
+ ${columnData.title} + ${isSortable ? this.createTableHeaderArrowTemplate() : ''} +
+ `; + } + + createTableHeaderTemplate() { + return this.headerConfig.map(headerColumn => ( + this.createTableHeaderCellTemplate(headerColumn) + )).join(''); + } + + createTableBodyCellTemplate(product, columnConfig) { + const id = columnConfig.id; + + if (columnConfig.template) { + return columnConfig.template(product); + } + return ( + ` +
${product[id]}
+ ` + ); + } + + createTableBodyRowTemplate(product) { + return ( + ` + + ${this.headerConfig.map(column => this.createTableBodyCellTemplate(product, column)).join('')} + + ` + ); + } + + createTableBodyTemplate(data) { + return data.map((product) => ( + this.createTableBodyRowTemplate(product) + )).join(''); + } + + createTemplate() { + return ( + ` +
+
+ ${this.createTableHeaderTemplate()} +
+
+ ${this.createTableBodyTemplate(this.data)} +
+
+ +
+
+

No products satisfies your filter criteria

+ +
+
+
+ ` + ); + } + + sortByType(sortType) { + if (sortType === 'number') { + return this.sortNumbers(this.data, this.fieldValue, this.orderValue); + } + if (sortType === 'string') { + return this.sortStrings(this.data, this.fieldValue, this.orderValue); + } + } + + sortNumbers(data) { + if (this.orderValue === 'asc') { + return [...data].sort((a, b) => a[this.fieldValue] - b[this.fieldValue]); + } + if (this.orderValue === 'desc') { + return [...data].sort((a, b) => b[this.fieldValue] - a[this.fieldValue]); + } + return [...data]; + } + + sortStrings(data) { + if (this.orderValue === 'asc') { + return [...data].sort( + (a, b) => { + return a[this.fieldValue].localeCompare(b[this.fieldValue], ['ru', 'en'], { caseFirst: "upper" }); + }); + } + if (this.orderValue === 'desc') { + return [...data].sort( + (a, b) => { + return b[this.fieldValue].localeCompare(a[this.fieldValue], ['ru', 'en'], { caseFirst: "upper" }); + }); + } + return [...data]; + } + + sort(fieldValue, orderValue) { + this.fieldValue = fieldValue; + this.orderValue = orderValue; + + this.setDataOrderAttribute(orderValue); + + const sortType = this.headerConfig.find(obj => obj.id === fieldValue).sortType; + const sortedData = this.sortByType(sortType); + + this.updateTemplate(sortedData); + } + + setDataOrderAttribute() { + const sortableElems = document.body.querySelectorAll('.sortable-table__cell'); + for (let element of sortableElems) { + element.setAttribute('data-order', this.orderValue); + } + } + + updateTemplate(sortedData) { + this.subElements.header.innerHTML = this.createTableHeaderTemplate(); + this.subElements.body.innerHTML = this.createTableBodyTemplate(sortedData); + } + + remove() { + this.element.remove(); + } + destroy() { + this.remove(); } }