Refactor CSS to use BEM style

This commit is contained in:
Faris Ansari 2018-04-21 19:07:11 +05:30
parent 1f6174b232
commit fde1b7bcc9
9 changed files with 306 additions and 375 deletions

View File

@ -23,7 +23,7 @@
<input type="checkbox" id="input-large-data" /> <input type="checkbox" id="input-large-data" />
<span>Large Data</span> <span>Large Data</span>
</label> </label>
<section style="font-size: 12px; width: 60%"> <section style="font-size: 12px; width: 60%; margin: 0 auto;">
</section> </section>

View File

@ -88,13 +88,13 @@ const prodCSS = merge(devCSS, {
// docs // docs
const docJS = merge(devIIFE, { const docJS = merge(devIIFE, {
output: { output: {
file: 'docs/assets/frappe-datatable.js' file: 'docs/assets/js/frappe-datatable.js'
} }
}); });
const docCSS = merge(devCSS, { const docCSS = merge(devCSS, {
output: { output: {
file: 'docs/assets/frappe-datatable.css' file: 'docs/assets/css/frappe-datatable.css'
} }
}); });

View File

@ -26,7 +26,7 @@ export default class BodyRenderer {
const rows = this.datamanager.getRowsForView(); const rows = this.datamanager.getRowsForView();
this.bodyScrollable.innerHTML = ` this.bodyScrollable.innerHTML = `
<table class="data-table-body"> <table class="dt-body">
${this.getBodyHTML(rows)} ${this.getBodyHTML(rows)}
</table> </table>
`; `;
@ -40,13 +40,13 @@ export default class BodyRenderer {
let initialData = this.getDataForClusterize(rows); let initialData = this.getDataForClusterize(rows);
if (initialData.length === 0) { if (initialData.length === 0) {
initialData = [`<tr class="no-data"><td>${this.options.noDataMessage}</td></tr>`]; initialData = [`<div class="dt-scrollable__no-data">${this.options.noDataMessage}</div>`];
} }
if (!this.clusterize) { if (!this.clusterize) {
// empty body // empty body
this.bodyScrollable.innerHTML = ` this.bodyScrollable.innerHTML = `
<table class="data-table-body"> <table class="dt-body">
${this.getBodyHTML([])} ${this.getBodyHTML([])}
</table> </table>
`; `;
@ -87,7 +87,7 @@ export default class BodyRenderer {
} }
showToastMessage(message) { showToastMessage(message) {
this.instance.toastMessage.innerHTML = `<span>${message}</span>`; this.instance.toastMessage.innerHTML = `<span class="dt-toast__message">${message}</span>`;
} }
clearToastMessage() { clearToastMessage() {

View File

@ -5,7 +5,6 @@ import {
linkProperties linkProperties
} from './utils'; } from './utils';
import $ from './dom'; import $ from './dom';
import { getDropdownHTML } from './columnmanager';
export default class CellManager { export default class CellManager {
constructor(instance) { constructor(instance) {
@ -40,7 +39,7 @@ export default class CellManager {
bindEditCell() { bindEditCell() {
this.$editingCell = null; this.$editingCell = null;
$.on(this.bodyScrollable, 'dblclick', '.data-table-cell', (e, cell) => { $.on(this.bodyScrollable, 'dblclick', '.dt-cell', (e, cell) => {
this.activateEditing(cell); this.activateEditing(cell);
}); });
@ -115,7 +114,7 @@ export default class CellManager {
if (this.options.inlineFilters) { if (this.options.inlineFilters) {
this.keyboard.on('ctrl+f', (e) => { this.keyboard.on('ctrl+f', (e) => {
const $cell = $.closest('.data-table-cell', e.target); const $cell = $.closest('.dt-cell', e.target);
const { colIndex } = $.data($cell); const { colIndex } = $.data($cell);
this.activateFilter(colIndex); this.activateFilter(colIndex);
@ -155,7 +154,7 @@ export default class CellManager {
bindMouseEvents() { bindMouseEvents() {
let mouseDown = null; let mouseDown = null;
$.on(this.bodyScrollable, 'mousedown', '.data-table-cell', (e) => { $.on(this.bodyScrollable, 'mousedown', '.dt-cell', (e) => {
mouseDown = true; mouseDown = true;
this.focusCell($(e.delegatedTarget)); this.focusCell($(e.delegatedTarget));
}); });
@ -169,15 +168,15 @@ export default class CellManager {
this.selectArea($(e.delegatedTarget)); this.selectArea($(e.delegatedTarget));
}; };
$.on(this.bodyScrollable, 'mousemove', '.data-table-cell', throttle(selectArea, 50)); $.on(this.bodyScrollable, 'mousemove', '.dt-cell', throttle(selectArea, 50));
} }
bindTreeEvents() { bindTreeEvents() {
$.on(this.bodyScrollable, 'click', '.toggle', (e, $toggle) => { $.on(this.bodyScrollable, 'click', '.dt-tree-node__toggle', (e, $toggle) => {
const $cell = $.closest('.data-table-cell', $toggle); const $cell = $.closest('.dt-cell', $toggle);
const { rowIndex } = $.data($cell); const { rowIndex } = $.data($cell);
if ($cell.classList.contains('tree-close')) { if ($cell.classList.contains('dt-cell--tree-close')) {
this.rowmanager.openSingleNode(rowIndex); this.rowmanager.openSingleNode(rowIndex);
} else { } else {
this.rowmanager.closeSingleNode(rowIndex); this.rowmanager.closeSingleNode(rowIndex);
@ -214,11 +213,11 @@ export default class CellManager {
} }
if (this.$focusedCell) { if (this.$focusedCell) {
this.$focusedCell.classList.remove('selected'); this.$focusedCell.classList.remove('dt-cell--focus');
} }
this.$focusedCell = $cell; this.$focusedCell = $cell;
$cell.classList.add('selected'); $cell.classList.add('dt-cell--focus');
// so that keyboard nav works // so that keyboard nav works
$cell.focus(); $cell.focus();
@ -232,8 +231,8 @@ export default class CellManager {
rowIndex rowIndex
} = $.data($cell); } = $.data($cell);
const _colIndex = this.datamanager.getColumnIndexById('_rowIndex'); const _colIndex = this.datamanager.getColumnIndexById('_rowIndex');
const colHeaderSelector = `.data-table-header .data-table-cell[data-col-index="${colIndex}"]`; const colHeaderSelector = `.dt-header .dt-cell[data-col-index="${colIndex}"]`;
const rowHeaderSelector = `.data-table-cell[data-row-index="${rowIndex}"][data-col-index="${_colIndex}"]`; const rowHeaderSelector = `.dt-cell[data-row-index="${rowIndex}"][data-col-index="${_colIndex}"]`;
if (this.lastHeaders) { if (this.lastHeaders) {
$.removeStyle(this.lastHeaders, 'backgroundColor'); $.removeStyle(this.lastHeaders, 'backgroundColor');
@ -300,7 +299,7 @@ export default class CellManager {
if (!cells) return false; if (!cells) return false;
this.clearSelection(); this.clearSelection();
cells.map(index => this.getCell$(...index)).map($cell => $cell.classList.add('highlight')); cells.map(index => this.getCell$(...index)).map($cell => $cell.classList.add('dt-cell--highlight'));
return true; return true;
} }
@ -358,8 +357,8 @@ export default class CellManager {
} }
clearSelection() { clearSelection() {
$.each('.data-table-cell.highlight', this.bodyScrollable) $.each('.dt-cell--highlight', this.bodyScrollable)
.map(cell => cell.classList.remove('highlight')); .map(cell => cell.classList.remove('dt-cell--highlight'));
this.$selectionCursor = null; this.$selectionCursor = null;
} }
@ -398,9 +397,9 @@ export default class CellManager {
} }
this.$editingCell = $cell; this.$editingCell = $cell;
$cell.classList.add('editing'); $cell.classList.add('dt-cell--editing');
const $editCell = $('.edit-cell', $cell); const $editCell = $('.dt-cell__edit', $cell);
$editCell.innerHTML = ''; $editCell.innerHTML = '';
const editor = this.getEditor(colIndex, rowIndex, cell.content, $editCell); const editor = this.getEditor(colIndex, rowIndex, cell.content, $editCell);
@ -417,7 +416,7 @@ export default class CellManager {
if (this.$focusedCell) this.$focusedCell.focus(); if (this.$focusedCell) this.$focusedCell.focus();
if (!this.$editingCell) return; if (!this.$editingCell) return;
this.$editingCell.classList.remove('editing'); this.$editingCell.classList.remove('dt-cell--editing');
this.$editingCell = null; this.$editingCell = null;
} }
@ -443,7 +442,7 @@ export default class CellManager {
getDefaultEditor(parent) { getDefaultEditor(parent) {
const $input = $.create('input', { const $input = $.create('input', {
class: 'input-style', class: 'dt-input',
type: 'text', type: 'text',
inside: parent inside: parent
}); });
@ -557,7 +556,7 @@ export default class CellManager {
const colIndex = this.columnmanager.getFirstColumnIndex(); const colIndex = this.columnmanager.getFirstColumnIndex();
const $cell = this.getCell$(colIndex, rowIndex); const $cell = this.getCell$(colIndex, rowIndex);
if ($cell) { if ($cell) {
$cell.classList[flag ? 'remove' : 'add']('tree-close'); $cell.classList[flag ? 'remove' : 'add']('dt-cell--tree-close');
} }
} }
@ -576,7 +575,7 @@ export default class CellManager {
} = $.data($cell); } = $.data($cell);
let $aboveRow = $cell.parentElement.previousElementSibling; let $aboveRow = $cell.parentElement.previousElementSibling;
while ($aboveRow && $aboveRow.classList.contains('hide')) { while ($aboveRow && $aboveRow.classList.contains('dt-row--hide')) {
$aboveRow = $aboveRow.previousElementSibling; $aboveRow = $aboveRow.previousElementSibling;
} }
@ -590,7 +589,7 @@ export default class CellManager {
} = $.data($cell); } = $.data($cell);
let $belowRow = $cell.parentElement.nextElementSibling; let $belowRow = $cell.parentElement.nextElementSibling;
while ($belowRow && $belowRow.classList.contains('hide')) { while ($belowRow && $belowRow.classList.contains('dt-row--hide')) {
$belowRow = $belowRow.nextElementSibling; $belowRow = $belowRow.nextElementSibling;
} }
@ -631,7 +630,7 @@ export default class CellManager {
} }
getRowHeight() { getRowHeight() {
return $.style($('.data-table-row', this.bodyScrollable), 'height'); return $.style($('.dt-row', this.bodyScrollable), 'height');
} }
scrollToCell($cell) { scrollToCell($cell) {
@ -662,8 +661,13 @@ export default class CellManager {
isFilter isFilter
}); });
const className = [
'dt-cell',
isHeader ? 'dt-cell--header' : ''
].join(' ');
return ` return `
<td class="data-table-cell noselect" ${dataAttr} tabindex="0"> <td class="${className}" ${dataAttr} tabindex="0">
${this.getCellContent(cell)} ${this.getCellContent(cell)}
</td> </td>
`; `;
@ -682,10 +686,10 @@ export default class CellManager {
const sortIndicator = sortable ? '<span class="sort-indicator"></span>' : ''; const sortIndicator = sortable ? '<span class="sort-indicator"></span>' : '';
const resizable = isHeader && cell.resizable !== false; const resizable = isHeader && cell.resizable !== false;
const resizeColumn = resizable ? '<span class="column-resizer"></span>' : ''; const resizeColumn = resizable ? '<span class="dt-cell__resize-handle"></span>' : '';
const hasDropdown = isHeader && cell.dropdown !== false; const hasDropdown = isHeader && cell.dropdown !== false;
const dropdown = hasDropdown ? `<div class="data-table-dropdown">${getDropdownHTML()}</div>` : ''; const dropdown = hasDropdown ? this.columnmanager.getDropdownHTML() : '';
const customFormatter = cell.format || (cell.column && cell.column.format) || null; const customFormatter = cell.format || (cell.column && cell.column.format) || null;
@ -706,14 +710,15 @@ export default class CellManager {
const firstColumnIndex = this.datamanager.getColumnIndexById('_rowIndex') + 1; const firstColumnIndex = this.datamanager.getColumnIndexById('_rowIndex') + 1;
if (firstColumnIndex === cell.colIndex) { if (firstColumnIndex === cell.colIndex) {
const padding = ((cell.indent || 0) + 1) * 1.5; const padding = ((cell.indent || 0) + 1) * 1.5;
const toggleHTML = addToggle ? `<span class="toggle" style="left: ${padding - 1.5}rem"></span>` : ''; const toggleHTML = addToggle ?
contentHTML = `<span class="tree-node" style="padding-left: ${padding}rem"> `<span class="dt-tree-node__toggle" style="left: ${padding - 1.5}rem"></span>` : '';
contentHTML = `<span class="dt-tree-node" style="padding-left: ${padding}rem">
${toggleHTML}${contentHTML}</span>`; ${toggleHTML}${contentHTML}</span>`;
} }
} }
return ` return `
<div class="content ellipsis"> <div class="dt-cell__content">
${contentHTML} ${contentHTML}
${sortIndicator} ${sortIndicator}
${resizeColumn} ${resizeColumn}
@ -724,12 +729,10 @@ export default class CellManager {
} }
getEditCellHTML() { getEditCellHTML() {
return ` return '<div class="dt-cell__edit"></div>';
<div class="edit-cell"></div>
`;
} }
selector(colIndex, rowIndex) { selector(colIndex, rowIndex) {
return `.data-table-cell[data-col-index="${colIndex}"][data-row-index="${rowIndex}"]`; return `.dt-cell[data-col-index="${colIndex}"][data-row-index="${rowIndex}"]`;
} }
} }

View File

@ -21,7 +21,6 @@ export default class ColumnManager {
]); ]);
this.bindEvents(); this.bindEvents();
getDropdownHTML = getDropdownHTML.bind(this, this.options.dropdownButton);
} }
renderHeader() { renderHeader() {
@ -31,11 +30,11 @@ export default class ColumnManager {
refreshHeader() { refreshHeader() {
const columns = this.datamanager.getColumns(); const columns = this.datamanager.getColumns();
const $cols = $.each('.data-table-cell[data-is-header]', this.header); const $cols = $.each('.dt-cell[data-is-header]', this.header);
const refreshHTML = const refreshHTML =
// first init // first init
!$('.data-table-cell', this.header) || !$('.dt-cell', this.header) ||
// deleted column // deleted column
columns.length < $cols.length; columns.length < $cols.length;
@ -43,7 +42,7 @@ export default class ColumnManager {
// refresh html // refresh html
$('thead', this.header).innerHTML = this.getHeaderHTML(columns); $('thead', this.header).innerHTML = this.getHeaderHTML(columns);
this.$filterRow = $('.data-table-row[data-is-filter]', this.header); this.$filterRow = $('.dt-row[data-is-filter]', this.header);
if (this.$filterRow) { if (this.$filterRow) {
$.style(this.$filterRow, { display: 'none' }); $.style(this.$filterRow, { display: 'none' });
} }
@ -89,12 +88,15 @@ export default class ColumnManager {
bindDropdown() { bindDropdown() {
let $activeDropdown; let $activeDropdown;
$.on(this.header, 'click', '.data-table-dropdown-toggle', (e, $button) => { let activeClass = 'dt-dropdown--active';
const $dropdown = $.closest('.data-table-dropdown', $button); let toggleClass = '.dt-dropdown__toggle';
if (!$dropdown.classList.contains('is-active')) { $.on(this.header, 'click', toggleClass, (e, $button) => {
const $dropdown = $.closest('.dt-dropdown', $button);
if (!$dropdown.classList.contains(activeClass)) {
deactivateDropdown(); deactivateDropdown();
$dropdown.classList.add('is-active'); $dropdown.classList.add(activeClass);
$activeDropdown = $dropdown; $activeDropdown = $dropdown;
} else { } else {
deactivateDropdown(); deactivateDropdown();
@ -102,14 +104,14 @@ export default class ColumnManager {
}); });
$.on(document.body, 'click', (e) => { $.on(document.body, 'click', (e) => {
if (e.target.matches('.data-table-dropdown-toggle')) return; if (e.target.matches(toggleClass)) return;
deactivateDropdown(); deactivateDropdown();
}); });
const dropdownItems = this.options.headerDropdown; const dropdownItems = this.options.headerDropdown;
$.on(this.header, 'click', '.data-table-dropdown-list > div', (e, $item) => { $.on(this.header, 'click', '.dt-dropdown__list-item', (e, $item) => {
const $col = $.closest('.data-table-cell', $item); const $col = $.closest('.dt-cell', $item);
const { const {
index index
} = $.data($item); } = $.data($item);
@ -122,7 +124,7 @@ export default class ColumnManager {
}); });
function deactivateDropdown(e) { function deactivateDropdown(e) {
$activeDropdown && $activeDropdown.classList.remove('is-active'); $activeDropdown && $activeDropdown.classList.remove(activeClass);
$activeDropdown = null; $activeDropdown = null;
} }
} }
@ -131,8 +133,8 @@ export default class ColumnManager {
let isDragging = false; let isDragging = false;
let $resizingCell, startWidth, startX; let $resizingCell, startWidth, startX;
$.on(this.header, 'mousedown', '.data-table-cell .column-resizer', (e, $handle) => { $.on(this.header, 'mousedown', '.dt-cell .dt-cell__resize-handle', (e, $handle) => {
document.body.classList.add('data-table-resize'); document.body.classList.add('dt-resize');
const $cell = $handle.parentNode.parentNode; const $cell = $handle.parentNode.parentNode;
$resizingCell = $cell; $resizingCell = $cell;
const { const {
@ -145,12 +147,12 @@ export default class ColumnManager {
} }
isDragging = true; isDragging = true;
startWidth = $.style($('.content', $resizingCell), 'width'); startWidth = $.style($('.dt-cell__content', $resizingCell), 'width');
startX = e.pageX; startX = e.pageX;
}); });
$.on(document.body, 'mouseup', (e) => { $.on(document.body, 'mouseup', (e) => {
document.body.classList.remove('data-table-resize'); document.body.classList.remove('dt-resize');
if (!$resizingCell) return; if (!$resizingCell) return;
isDragging = false; isDragging = false;
@ -188,10 +190,10 @@ export default class ColumnManager {
$.off(document.body, 'mousemove', initialize); $.off(document.body, 'mousemove', initialize);
return; return;
} }
const ready = $('.data-table-cell', this.header); const ready = $('.dt-cell', this.header);
if (!ready) return; if (!ready) return;
const $parent = $('.data-table-row', this.header); const $parent = $('.dt-row', this.header);
this.sortable = Sortable.create($parent, { this.sortable = Sortable.create($parent, {
onEnd: (e) => { onEnd: (e) => {
@ -208,7 +210,8 @@ export default class ColumnManager {
this.switchColumn(oldIndex, newIndex); this.switchColumn(oldIndex, newIndex);
}, },
preventOnFilter: false, preventOnFilter: false,
filter: '.column-resizer, .data-table-dropdown', filter: '.dt-cell__resize-handle, .dt-dropdown',
chosenClass: 'dt-cell--dragging',
animation: 150 animation: 150
}); });
}; };
@ -216,49 +219,6 @@ export default class ColumnManager {
$.on(document.body, 'mousemove', initialize); $.on(document.body, 'mousemove', initialize);
} }
bindSortColumn() {
$.on(this.header, 'click', '.data-table-cell .column-title', (e, span) => {
const $cell = span.closest('.data-table-cell');
let {
colIndex,
sortOrder = 'none'
} = $.data($cell);
const col = this.getColumn(colIndex);
if (col && col.sortable === false) {
return;
}
// reset sort indicator
$('.sort-indicator', this.header).textContent = '';
$.each('.data-table-cell', this.header).map($cell => {
$.data($cell, {
sortOrder: 'none'
});
});
let nextSortOrder, textContent;
if (sortOrder === 'none') {
nextSortOrder = 'asc';
textContent = '▲';
} else if (sortOrder === 'asc') {
nextSortOrder = 'desc';
textContent = '▼';
} else if (sortOrder === 'desc') {
nextSortOrder = 'none';
textContent = '';
}
$.data($cell, {
sortOrder: nextSortOrder
});
$('.sort-indicator', $cell).textContent = textContent;
this.sortColumn(colIndex, nextSortOrder);
});
}
sortColumn(colIndex, nextSortOrder) { sortColumn(colIndex, nextSortOrder) {
this.instance.freeze(); this.instance.freeze();
this.sortRows(colIndex, nextSortOrder) this.sortRows(colIndex, nextSortOrder)
@ -326,14 +286,14 @@ export default class ColumnManager {
focusFilter(colIndex) { focusFilter(colIndex) {
if (!this.isFilterShown) return; if (!this.isFilterShown) return;
const $filterInput = $(`[data-col-index="${colIndex}"] .data-table-filter`, this.$filterRow); const $filterInput = $(`[data-col-index="${colIndex}"] .dt-filter`, this.$filterRow);
$filterInput.focus(); $filterInput.focus();
} }
bindFilter() { bindFilter() {
if (!this.options.inlineFilters) return; if (!this.options.inlineFilters) return;
const handler = e => { const handler = e => {
const $filterCell = $.closest('.data-table-cell', e.target); const $filterCell = $.closest('.dt-cell', e.target);
const { const {
colIndex colIndex
} = $.data($filterCell); } = $.data($filterCell);
@ -348,7 +308,7 @@ export default class ColumnManager {
this.rowmanager.showRows(rowsToShow); this.rowmanager.showRows(rowsToShow);
}); });
}; };
$.on(this.header, 'keydown', '.data-table-filter', debounce(handler, 300)); $.on(this.header, 'keydown', '.dt-filter', debounce(handler, 300));
} }
sortRows(colIndex, sortOrder) { sortRows(colIndex, sortOrder) {
@ -370,7 +330,11 @@ export default class ColumnManager {
let columnWidth = width || this.getColumn(colIndex).width; let columnWidth = width || this.getColumn(colIndex).width;
let index = this._columnWidthMap[colIndex]; let index = this._columnWidthMap[colIndex];
const selector = `[data-col-index="${colIndex}"] .content, [data-col-index="${colIndex}"] .edit-cell`; const selector = [
`[data-col-index="${colIndex}"] .dt-cell__content`,
`[data-col-index="${colIndex}"] .dt-cell__edit`
].join(', ');
const styles = { const styles = {
width: columnWidth + 'px' width: columnWidth + 'px'
}; };
@ -385,7 +349,7 @@ export default class ColumnManager {
setColumnHeaderWidth(colIndex) { setColumnHeaderWidth(colIndex) {
colIndex = +colIndex; colIndex = +colIndex;
this.$columnMap = this.$columnMap || []; this.$columnMap = this.$columnMap || [];
const selector = `.data-table-header [data-col-index="${colIndex}"] .content`; const selector = `.dt-header [data-col-index="${colIndex}"] .dt-cell__content`;
const { const {
width width
} = this.getColumn(colIndex); } = this.getColumn(colIndex);
@ -409,7 +373,7 @@ export default class ColumnManager {
} }
getHeaderCell$(colIndex) { getHeaderCell$(colIndex) {
return $(`.data-table-cell[data-col-index="${colIndex}"]`, this.header); return $(`.dt-cell[data-col-index="${colIndex}"]`, this.header);
} }
getLastColumnIndex() { getLastColumnIndex() {
@ -421,20 +385,19 @@ export default class ColumnManager {
return columns.findIndex(column => column.content.includes('Sr. No')); return columns.findIndex(column => column.content.includes('Sr. No'));
} }
getDropdownHTML() {
const { dropdownButton, headerDropdown: dropdownItems } = this.options;
return `
<div class="dt-dropdown">
<div class="dt-dropdown__toggle">${dropdownButton}</div>
<div class="dt-dropdown__list">
${dropdownItems.map((d, i) => `
<div class="dt-dropdown__list-item" data-index="${i}">${d.label}</div>
`).join('')}
</div>
</div>
`;
};
} }
// eslint-disable-next-line
var getDropdownHTML = function getDropdownHTML(dropdownButton = 'v') {
// add dropdown buttons
const dropdownItems = this.options.headerDropdown;
return `<div class="data-table-dropdown-toggle">${dropdownButton}</div>
<div class="data-table-dropdown-list">
${dropdownItems.map((d, i) => `<div data-index="${i}">${d.label}</div>`).join('')}
</div>
`;
};
export {
getDropdownHTML
};

View File

@ -64,25 +64,25 @@ class DataTable {
prepareDom() { prepareDom() {
this.wrapper.innerHTML = ` this.wrapper.innerHTML = `
<div class="data-table"> <div class="datatable">
<table class="data-table-header"> <table class="dt-header">
</table> </table>
<div class="body-scrollable"> <div class="dt-scrollable">
</div> </div>
<div class="freeze-container"> <div class="dt-freeze">
<span>${this.options.freezeMessage}</span> <span class="dt-freeze__message">
${this.options.freezeMessage}
</span>
</div> </div>
<div class="data-table-footer"> <div class="dt-toast"></div>
</div>
<div class="toast-message"></div>
</div> </div>
`; `;
this.datatableWrapper = $('.data-table', this.wrapper); this.datatableWrapper = $('.datatable', this.wrapper);
this.header = $('.data-table-header', this.wrapper); this.header = $('.dt-header', this.wrapper);
this.bodyScrollable = $('.body-scrollable', this.wrapper); this.bodyScrollable = $('.dt-scrollable', this.wrapper);
this.freezeContainer = $('.freeze-container', this.wrapper); this.freezeContainer = $('.dt-freeze', this.wrapper);
this.toastMessage = $('.toast-message', this.wrapper); this.toastMessage = $('.dt-toast', this.wrapper);
} }
refresh(data, columns) { refresh(data, columns) {

View File

@ -39,8 +39,8 @@ export default class RowManager {
// map of checked rows // map of checked rows
this.checkMap = []; this.checkMap = [];
$.on(this.wrapper, 'click', '.data-table-cell[data-col-index="0"] [type="checkbox"]', (e, $checkbox) => { $.on(this.wrapper, 'click', '.dt-cell[data-col-index="0"] [type="checkbox"]', (e, $checkbox) => {
const $cell = $checkbox.closest('.data-table-cell'); const $cell = $checkbox.closest('.dt-cell');
const { const {
rowIndex, rowIndex,
isHeader isHeader
@ -92,7 +92,7 @@ export default class RowManager {
checkRow(rowIndex, toggle) { checkRow(rowIndex, toggle) {
const value = toggle ? 1 : 0; const value = toggle ? 1 : 0;
const selector = rowIndex => const selector = rowIndex =>
`.data-table-cell[data-row-index="${rowIndex}"][data-col-index="0"] [type="checkbox"]`; `.dt-cell[data-row-index="${rowIndex}"][data-col-index="0"] [type="checkbox"]`;
// update internal map // update internal map
this.checkMap[rowIndex] = value; this.checkMap[rowIndex] = value;
// set checkbox value explicitly // set checkbox value explicitly
@ -116,7 +116,7 @@ export default class RowManager {
this.checkMap = []; this.checkMap = [];
} }
// set checkbox value // set checkbox value
$.each('.data-table-cell[data-col-index="0"] [type="checkbox"]', this.bodyScrollable) $.each('.dt-cell[data-col-index="0"] [type="checkbox"]', this.bodyScrollable)
.map(input => { .map(input => {
input.checked = toggle; input.checked = toggle;
}); });
@ -140,34 +140,34 @@ export default class RowManager {
const $row = this.getRow$(rowIndex); const $row = this.getRow$(rowIndex);
if (!$row) return; if (!$row) return;
if (!toggle && this.bodyScrollable.classList.contains('row-highlight-all')) { if (!toggle && this.bodyScrollable.classList.contains('dt-scrollable--highlight-all')) {
$row.classList.add('row-unhighlight'); $row.classList.add('dt-row--unhighlight');
return; return;
} }
if (toggle && $row.classList.contains('row-unhighlight')) { if (toggle && $row.classList.contains('dt-row--unhighlight')) {
$row.classList.remove('row-unhighlight'); $row.classList.remove('dt-row--unhighlight');
} }
this._highlightedRows = this._highlightedRows || {}; this._highlightedRows = this._highlightedRows || {};
if (toggle) { if (toggle) {
$row.classList.add('row-highlight'); $row.classList.add('dt-row--highlight');
this._highlightedRows[rowIndex] = $row; this._highlightedRows[rowIndex] = $row;
} else { } else {
$row.classList.remove('row-highlight'); $row.classList.remove('dt-row--highlight');
delete this._highlightedRows[rowIndex]; delete this._highlightedRows[rowIndex];
} }
} }
highlightAll(toggle = true) { highlightAll(toggle = true) {
if (toggle) { if (toggle) {
this.bodyScrollable.classList.add('row-highlight-all'); this.bodyScrollable.classList.add('dt-scrollable--highlight-all');
} else { } else {
this.bodyScrollable.classList.remove('row-highlight-all'); this.bodyScrollable.classList.remove('dt-scrollable--highlight-all');
for (const rowIndex in this._highlightedRows) { for (const rowIndex in this._highlightedRows) {
const $row = this._highlightedRows[rowIndex]; const $row = this._highlightedRows[rowIndex];
$row.classList.remove('row-highlight'); $row.classList.remove('dt-row--highlight');
} }
this._highlightedRows = {}; this._highlightedRows = {};
} }
@ -177,7 +177,7 @@ export default class RowManager {
rowIndices = ensureArray(rowIndices); rowIndices = ensureArray(rowIndices);
rowIndices.map(rowIndex => { rowIndices.map(rowIndex => {
const $tr = this.getRow$(rowIndex); const $tr = this.getRow$(rowIndex);
$tr.classList.add('hide'); $tr.classList.add('dt-row--hide');
}); });
} }
@ -185,7 +185,7 @@ export default class RowManager {
rowIndices = ensureArray(rowIndices); rowIndices = ensureArray(rowIndices);
rowIndices.map(rowIndex => { rowIndices.map(rowIndex => {
const $tr = this.getRow$(rowIndex); const $tr = this.getRow$(rowIndex);
$tr.classList.remove('hide'); $tr.classList.remove('dt-row--hide');
}); });
} }
@ -268,7 +268,7 @@ export default class RowManager {
} }
return ` return `
<tr class="data-table-row" ${dataAttr}> <tr class="dt-row" ${dataAttr}>
${row.map(cell => this.cellmanager.getCellHTML(cell)).join('')} ${row.map(cell => this.cellmanager.getCellHTML(cell)).join('')}
</tr> </tr>
`; `;
@ -276,10 +276,10 @@ export default class RowManager {
getFilterInput(props) { getFilterInput(props) {
const dataAttr = makeDataAttributeString(props); const dataAttr = makeDataAttributeString(props);
return `<input class="data-table-filter input-style" type="text" ${dataAttr} />`; return `<input class="dt-filter dt-input" type="text" ${dataAttr} />`;
} }
selector(rowIndex) { selector(rowIndex) {
return `.data-table-row[data-row-index="${rowIndex}"]`; return `.dt-row[data-row-index="${rowIndex}"]`;
} }
} }

View File

@ -1,11 +1,9 @@
/* This file is processed by postcss */
/* variables */
:root { :root {
--border-color: #d1d8dd; --border-color: #d1d8dd;
--primary-color: rgb(82, 146, 247); --primary-color: rgb(82, 146, 247);
--light-bg: #f5f7fa; --light-bg: #f5f7fa;
--light-red: #FD8B8B; --light-red: #FD8B8B;
--light-yellow: #fffce7;
--orange: rgb(255, 160, 10); --orange: rgb(255, 160, 10);
--text-color: #000000; --text-color: #000000;
--text-light: #dfe2e5; --text-light: #dfe2e5;
@ -15,275 +13,242 @@
--spacer-3: 1rem; --spacer-3: 1rem;
--border-radius: 3px; --border-radius: 3px;
--cell-bg: #fff;
} }
.data-table { .datatable {
/* resets */ *, *::after, *::before {
*, *::after, *::before {
box-sizing: border-box; box-sizing: border-box;
} }
}
button, input { .datatable {
overflow: visible;
font-family: inherit;
font-size: inherit;
line-height: inherit;
margin: 0;
padding: 0;
}
.input-style {
outline: none;
width: 100%;
border: none;
}
*, *:focus {
outline: none;
border-radius: 0px;
box-shadow: none;
}
/* styling */
position: relative; position: relative;
overflow: auto; overflow: auto;
table {
border-collapse: collapse;
}
table td {
padding: 0;
border: 1px solid var(--border-color);
}
thead td {
border-bottom-width: 1px;
}
.freeze-container {
display: flex;
justify-content: center;
align-content: center;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: var(--light-bg);
opacity: 0.5;
font-size: 2em;
span {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
}
.hide {
display: none;
}
.toast-message {
position: absolute;
bottom: var(--spacer-3);
left: 50%;
transform: translateX(-50%);
span {
display: inline-block;
background-color: rgba(0, 0, 0, 0.8);
color: var(--text-light);
border-radius: var(--border-radius);
padding: var(--spacer-2) var(--spacer-3);
}
}
} }
.body-scrollable { .dt-header {
max-height: 500px; border-collapse: collapse;
overflow: auto;
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);
&.row-highlight-all .data-table-row:not(.row-unhighlight) {
background-color: var(--light-bg);
}
.no-data td {
text-align: center;
padding: var(--spacer-2);
}
}
.data-table-header {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
background-color: white; background-color: var(--cell-bg);
font-weight: bold; }
.content span:not(.column-resizer) { .dt-body {
cursor: pointer; border-collapse: collapse;
}
.dt-scrollable {
max-height: 40vw;
overflow: auto;
border-bottom: 1px solid var(--border-color);
&--highlight-all {
background-color: var(--light-yellow);
} }
.column-resizer { &__no-data {
text-align: center;
padding: var(--spacer-3);
border-left: 1px solid var(--border-color);
border-right: 1px solid var(--border-color);
}
}
.dt-row {
&--highlight {
background-color: var(--light-yellow);
}
&--unhighlight {
background-color: var(--cell-bg);
}
&--hide {
display: none; display: none;
position: absolute; }
right: 0; }
top: 0;
width: var(--spacer-1); .dt-cell {
border: 1px solid var(--border-color);
position: relative;
outline: none;
padding: 0;
&__content {
padding: var(--spacer-2);
border: 2px solid transparent;
height: 100%; height: 100%;
background-color: var(--primary-color); user-select: none;
cursor: col-resize; text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
} }
.data-table-dropdown { &__edit {
display: none;
padding: var(--spacer-2);
background-color: var(--cell-bg);
border: 2px solid var(--orange);
z-index: 1;
height: 100%;
}
&__resize-handle {
opacity: 0;
position: absolute; position: absolute;
right: 10px; right: -3px;
display: inline-flex; top: 0;
vertical-align: top; width: 5px;
text-align: left; height: 100%;
cursor: col-resize;
z-index: 1;
}
&.is-active { &--editing &__content {
.data-table-dropdown-list { display: none;
display: block; }
}
.data-table-dropdown-toggle { &--editing &__edit {
display: block; display: block;
} }
&--focus &__content {
border-color: var(--primary-color);
}
&--highlight {
background-color: var(--light-bg);
}
&--dragging {
background-color: var(--light-bg);
}
&--header &__content {
padding-right: var(--spacer-3);
font-weight: bold;
}
&--header:hover .dt-dropdown__toggle {
opacity: 1;
}
&--tree-close {
.dt-tree-node__toggle:before {
content: '►';
} }
} }
}
.data-table-dropdown-toggle { .dt-dropdown {
display: none; position: absolute;
background-color: transparent; right: 10px;
border: none; display: inline-flex;
vertical-align: top;
text-align: left;
font-weight: normal;
cursor: pointer;
&__toggle {
opacity: 0;
} }
.data-table-dropdown-list { &__list {
display: none; display: none;
font-weight: normal;
position: absolute; position: absolute;
min-width: 8rem; min-width: 8rem;
top: 100%; top: 100%;
right: 0; right: 0;
z-index: 1; z-index: 1;
background-color: white; background-color: var(--cell-bg);
border-radius: var(--border-radius); border-radius: var(--border-radius);
padding: var(--spacer-2) 0;
box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1);
padding-bottom: var(--spacer-2); }
padding-top: var(--spacer-2);
&> div { &__list-item {
padding: var(--spacer-2) var(--spacer-3); padding: var(--spacer-2) var(--spacer-3);
&:hover { &:hover {
background-color: var(--light-bg); background-color: var(--light-bg);
}
} }
} }
.data-table-cell.remove-column { &--active &__list {
background-color: var(--light-red); display: block;
transition: 300ms background-color ease-in-out;
}
.data-table-cell.sortable-chosen {
background-color: var(--light-bg);
} }
} }
.data-table-cell { .dt-tree-node {
display: inline-block;
position: relative; position: relative;
.content { &__toggle {
padding: var(--spacer-2);
border: 2px solid transparent;
height: 100%;
&.ellipsis {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
.edit-cell {
display: none;
padding: var(--spacer-2);
background-color: #fff;
z-index: 1;
height: 100%;
}
&.selected .content {
border: 2px solid var(--primary-color);
}
&.editing {
.content {
display: none;
}
.edit-cell {
border: 2px solid var(--orange);
display: block;
}
}
&.highlight {
background-color: var(--light-bg);
}
&:hover .column-resizer {
display: inline-block;
}
&:hover .data-table-dropdown-toggle {
display: block;
}
.tree-node {
display: inline-block;
position: relative;
}
.toggle {
display: inline-block; display: inline-block;
position: absolute; position: absolute;
font-size: 10px;
padding: 0 4px; padding: 0 4px;
cursor: pointer; cursor: pointer;
} }
.toggle:before { &__toggle:before {
content: '▼'; content: '▼';
} }
} }
.data-table-cell.tree-close { .dt-toast {
.toggle:before { position: absolute;
content: '►'; bottom: var(--spacer-3);
left: 50%;
transform: translateX(-50%);
&__message {
display: inline-block;
background-color: rgba(0, 0, 0, 0.8);
color: var(--text-light);
border-radius: var(--border-radius);
padding: var(--spacer-2) var(--spacer-3);
} }
} }
.data-table-row { .dt-input {
&.row-highlight { outline: none;
background-color: var(--light-bg); width: 100%;
} border: none;
overflow: visible;
font-family: inherit;
font-size: inherit;
line-height: inherit;
margin: 0;
padding: 0;
} }
.noselect { .dt-freeze {
-webkit-touch-callout: none; display: flex;
-webkit-user-select: none; justify-content: center;
-khtml-user-select: none; align-content: center;
-moz-user-select: none; position: absolute;
-ms-user-select: none; left: 0;
user-select: none; right: 0;
top: 0;
bottom: 0;
background-color: var(--light-bg);
opacity: 0.5;
font-size: 2em;
&__message {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
} }
body.data-table-resize { body.dt-resize {
cursor: col-resize; cursor: col-resize;
} }

View File

@ -15,7 +15,7 @@ export default class Style {
'getColumn' 'getColumn'
]); ]);
this.scopeClass = 'datatable-instance-' + instance.constructor.instances; this.scopeClass = 'dt-instance-' + instance.constructor.instances;
instance.datatableWrapper.classList.add(this.scopeClass); instance.datatableWrapper.classList.add(this.scopeClass);
const styleEl = document.createElement('style'); const styleEl = document.createElement('style');
@ -103,7 +103,7 @@ export default class Style {
const nonResizableColumnsSelector = this.datamanager.getColumns() const nonResizableColumnsSelector = this.datamanager.getColumns()
.filter(col => col.resizable === false) .filter(col => col.resizable === false)
.map(col => col.colIndex) .map(col => col.colIndex)
.map(i => `.data-table-header [data-col-index="${i}"]`) .map(i => `.dt-header [data-col-index="${i}"]`)
.join(); .join();
this.setStyle(nonResizableColumnsSelector, { this.setStyle(nonResizableColumnsSelector, {
@ -112,8 +112,8 @@ export default class Style {
} }
setupMinWidth() { setupMinWidth() {
$.each('.data-table-cell[data-is-header]', this.header).map(col => { $.each('.dt-cell[data-is-header]', this.header).map(col => {
const width = $.style($('.content', col), 'width'); const width = $.style($('.dt-cell__content', col), 'width');
const { const {
colIndex colIndex
} = $.data(col); } = $.data(col);
@ -127,16 +127,16 @@ export default class Style {
} }
setupNaturalColumnWidth() { setupNaturalColumnWidth() {
if (!$('.data-table-row')) return; if (!$('.dt-row')) return;
// set initial width as naturally calculated by table's first row // set initial width as naturally calculated by table's first row
$.each('.data-table-row[data-row-index="0"] .data-table-cell', this.bodyScrollable).map($cell => { $.each('.dt-row[data-row-index="0"] .dt-cell', this.bodyScrollable).map($cell => {
const { const {
colIndex colIndex
} = $.data($cell); } = $.data($cell);
const column = this.datamanager.getColumn(colIndex); const column = this.datamanager.getColumn(colIndex);
let naturalWidth = $.style($('.content', $cell), 'width'); let naturalWidth = $.style($('.dt-cell__content', $cell), 'width');
if (column.id === '_rowIndex') { if (column.id === '_rowIndex') {
naturalWidth = this.getRowIndexColumnWidth(naturalWidth); naturalWidth = this.getRowIndexColumnWidth(naturalWidth);
@ -222,7 +222,7 @@ export default class Style {
setDefaultCellHeight() { setDefaultCellHeight() {
if (this.options.dynamicRowHeight) return; if (this.options.dynamicRowHeight) return;
if (this.__cellHeightSet) return; if (this.__cellHeightSet) return;
const $firstCell = $('.data-table-cell[data-is-header]', this.instance.header); const $firstCell = $('.dt-cell[data-is-header]', this.instance.header);
if (!$firstCell) return; if (!$firstCell) return;
const height = this.options.cellHeight || $.style($firstCell, 'height'); const height = this.options.cellHeight || $.style($firstCell, 'height');
@ -233,10 +233,10 @@ export default class Style {
} }
setCellHeight(height) { setCellHeight(height) {
this.setStyle('.data-table-cell .content', { this.setStyle('.dt-cell .dt-cell__content', {
height: height + 'px' height: height + 'px'
}); });
this.setStyle('.data-table-cell .edit-cell', { this.setStyle('.dt-cell .dt-cell__edit', {
height: height + 'px' height: height + 'px'
}); });
} }
@ -273,7 +273,7 @@ export default class Style {
width: width + 'px' width: width + 'px'
}); });
const $body = $('.data-table-body', this.bodyScrollable); const $body = $('.dt-body', this.bodyScrollable);
if ($body) { if ($body) {
$.style($body, { $.style($body, {
@ -294,7 +294,7 @@ export default class Style {
getColumnHeaderElement(colIndex) { getColumnHeaderElement(colIndex) {
colIndex = +colIndex; colIndex = +colIndex;
if (colIndex < 0) return null; if (colIndex < 0) return null;
return $(`.data-table-cell[data-col-index="${colIndex}"]`, this.header); return $(`.dt-cell[data-col-index="${colIndex}"]`, this.header);
} }
getRowIndexColumnWidth(baseWidth) { getRowIndexColumnWidth(baseWidth) {