Skip to content
Merged
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
84 changes: 49 additions & 35 deletions cypress/integration/column.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
describe('Column', function () {
before(function () {
beforeEach(function () {
cy.visit('/');
});

Expand Down Expand Up @@ -68,48 +68,62 @@ describe('Column', function () {
.and('match', /9\dpx/);
});

it('keeps sticky columns pinned while scrolling horizontally', function () {
const expectPinned = (actual, expected) => {
expect(actual).to.be.closeTo(expected, 1);
};
it('pins a column from the dropdown menu', function () {
cy.clickDropdown(2);
cy.clickDropdownItem(2, 'Stick to left');

cy.window().then(win => win.datatable.getColumn(2))
.its('sticky')
.should('eq', true);

cy.get('.dt-scrollable').then(($scrollable) => {
const scrollable = $scrollable[0];
const stickyBodyCell = Cypress.$('.dt-cell--2-0')[0];
const initialStickyBodyLeft = stickyBodyCell.getBoundingClientRect().left;

scrollable.scrollLeft = 220;
scrollable.dispatchEvent(new Event('scroll'));

cy.wait(50).then(() => {
const nextStickyBodyLeft = stickyBodyCell.getBoundingClientRect().left;
expect(nextStickyBodyLeft).to.be.closeTo(initialStickyBodyLeft, 1);
});
});
});

it('keeps sticky columns pinned while scrolling horizontally', function () {
cy.get('.dt-scrollable').then(($scrollable) => {
const scrollable = $scrollable[0];
const stickyCheckboxBodyCell = Cypress.$('.dt-cell--0-0')[0];
const stickyCheckboxHeaderCell = Cypress.$('.dt-cell--header-0')[0];
const stickySerialBodyCell = Cypress.$('.dt-cell--1-0')[0];
const stickySerialHeaderCell = Cypress.$('.dt-cell--header-1')[0];
const stickyCustomBodyCell = Cypress.$('.dt-cell--2-0')[0];
const stickyCustomHeaderCell = Cypress.$('.dt-cell--header-2')[0];
const regularBodyCell = Cypress.$('.dt-cell--4-0')[0];

const initialStickyCheckboxBodyLeft = stickyCheckboxBodyCell.getBoundingClientRect().left;
const initialStickyCheckboxHeaderLeft = stickyCheckboxHeaderCell.getBoundingClientRect().left;
const initialStickySerialBodyLeft = stickySerialBodyCell.getBoundingClientRect().left;
const initialStickySerialHeaderLeft = stickySerialHeaderCell.getBoundingClientRect().left;
const initialStickyCustomBodyLeft = stickyCustomBodyCell.getBoundingClientRect().left;
const initialStickyCustomHeaderLeft = stickyCustomHeaderCell.getBoundingClientRect().left;
const initialRegularBodyLeft = regularBodyCell.getBoundingClientRect().left;
const checkboxBodyCell = Cypress.$('.dt-cell--0-0')[0];
const checkboxHeaderCell = Cypress.$('.dt-cell--header-0')[0];
const serialBodyCell = Cypress.$('.dt-cell--1-0')[0];
const serialHeaderCell = Cypress.$('.dt-cell--header-1')[0];
const officeBodyCell = Cypress.$('.dt-cell--4-0')[0];
const officeHeaderCell = Cypress.$('.dt-cell--header-4')[0];
const nameBodyCell = Cypress.$('.dt-cell--2-0')[0];

const initialCheckboxLeft = checkboxBodyCell.getBoundingClientRect().left;
const initialSerialLeft = serialBodyCell.getBoundingClientRect().left;
const initialNameLeft = nameBodyCell.getBoundingClientRect().left;

scrollable.scrollLeft = 220;
scrollable.dispatchEvent(new Event('scroll'));

cy.wait(50).then(() => {
const nextStickyCheckboxBodyLeft = stickyCheckboxBodyCell.getBoundingClientRect().left;
const nextStickyCheckboxHeaderLeft = stickyCheckboxHeaderCell.getBoundingClientRect().left;
const nextStickySerialBodyLeft = stickySerialBodyCell.getBoundingClientRect().left;
const nextStickySerialHeaderLeft = stickySerialHeaderCell.getBoundingClientRect().left;
const nextStickyCustomBodyLeft = stickyCustomBodyCell.getBoundingClientRect().left;
const nextStickyCustomHeaderLeft = stickyCustomHeaderCell.getBoundingClientRect().left;
const nextRegularBodyLeft = regularBodyCell.getBoundingClientRect().left;

expectPinned(nextStickyCheckboxBodyLeft, initialStickyCheckboxBodyLeft);
expectPinned(nextStickyCheckboxHeaderLeft, initialStickyCheckboxHeaderLeft);
expectPinned(nextStickySerialBodyLeft, initialStickySerialBodyLeft);
expectPinned(nextStickySerialHeaderLeft, initialStickySerialHeaderLeft);
expectPinned(nextStickyCustomBodyLeft, initialStickyCustomBodyLeft);
expectPinned(nextStickyCustomHeaderLeft, initialStickyCustomHeaderLeft);
expect(nextRegularBodyLeft).to.be.lessThan(initialRegularBodyLeft);
const nextCheckboxBodyLeft = checkboxBodyCell.getBoundingClientRect().left;
const nextCheckboxHeaderLeft = checkboxHeaderCell.getBoundingClientRect().left;
const nextSerialBodyLeft = serialBodyCell.getBoundingClientRect().left;
const nextSerialHeaderLeft = serialHeaderCell.getBoundingClientRect().left;
const nextOfficeBodyLeft = officeBodyCell.getBoundingClientRect().left;
const nextOfficeHeaderLeft = officeHeaderCell.getBoundingClientRect().left;
const nextNameLeft = nameBodyCell.getBoundingClientRect().left;

expect(nextCheckboxBodyLeft).to.be.closeTo(initialCheckboxLeft, 1);
expect(nextSerialBodyLeft).to.be.closeTo(initialSerialLeft, 1);
expect(nextCheckboxHeaderLeft).to.be.closeTo(nextCheckboxBodyLeft, 1);
expect(nextSerialHeaderLeft).to.be.closeTo(nextSerialBodyLeft, 1);
expect(nextOfficeHeaderLeft).to.be.closeTo(nextOfficeBodyLeft, 1);
expect(nextNameLeft).to.be.lessThan(initialNameLeft);
});
});
});
Expand Down
6 changes: 3 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ <h1>Frappe DataTable</h1>

function buildData() {
columns = [
{ name: "Name", width: 150, sticky: true },
{ name: "Position", width: 200 },
{ name: "Office", sticky: true },
{ name: "Name", width: 150},
{ name: "Position", width: 200},
{ name: "Office", sticky: true},
{ name: "Extn." },
{
name: "Start Date",
Expand Down
39 changes: 38 additions & 1 deletion src/columnmanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export default class ColumnManager {
});

$.on(this.$dropdownList, 'click', '.dt-dropdown__list-item', (e, $item) => {
if (!this._dropdownActiveColIndex) return;
if (this._dropdownActiveColIndex == null) return;
const dropdownItems = this.options.headerDropdown;
const { index } = $.data($item);
const colIndex = this._dropdownActiveColIndex;
Expand All @@ -108,6 +108,11 @@ export default class ColumnManager {
_this.hideDropdown();
}

this.stickDropdownIndex = this.options.headerDropdown
.findIndex(item => item.stickyAction === 'stick');
this.unstickDropdownIndex = this.options.headerDropdown
.findIndex(item => item.stickyAction === 'unstick');

this.hideDropdown();
}

Expand All @@ -124,6 +129,7 @@ export default class ColumnManager {
const $cell = $.closest('.dt-cell', e.target);
const { colIndex } = $.data($cell);
this._dropdownActiveColIndex = colIndex;
this.updateStickyDropdownItems(this.getColumn(colIndex));
}

hideDropdown() {
Expand Down Expand Up @@ -304,6 +310,20 @@ export default class ColumnManager {
});
}

setColumnSticky(colIndex, sticky) {
const column = this.getColumn(colIndex);
if (!column || column.sticky === sticky) {
return;
}

this.instance.freeze();
this.datamanager.updateColumn(colIndex, { sticky });

this.refreshHeader();
this.rowmanager.refreshRows()
.then(() => this.instance.unfreeze());
}

switchColumn(oldIndex, newIndex) {
this.instance.freeze();
this.datamanager.switchColumn(oldIndex, newIndex)
Expand Down Expand Up @@ -493,4 +513,21 @@ export default class ColumnManager {
toggleDropdownItem(index) {
$('.dt-dropdown__list', this.instance.dropdownContainer).children[index].classList.toggle('dt-hidden');
}

updateStickyDropdownItems(column) {
if (!column) return;
if (this.stickDropdownIndex === -1 || this.unstickDropdownIndex === -1) return;

const stickItem = this.$dropdownList.children[this.stickDropdownIndex];
const unstickItem = this.$dropdownList.children[this.unstickDropdownIndex];
if (!(stickItem && unstickItem)) return;

if (column.sticky) {
stickItem.classList.add('dt-hidden');
unstickItem.classList.remove('dt-hidden');
} else {
stickItem.classList.remove('dt-hidden');
unstickItem.classList.add('dt-hidden');
}
}
}
4 changes: 4 additions & 0 deletions src/datatable.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ class DataTable {
this.columnmanager.removeColumn(colIndex);
}

setColumnSticky(colIndex, sticky) {
this.columnmanager.setColumnSticky(colIndex, sticky);
}

scrollToLastColumn() {
this.datatableWrapper.scrollLeft = 9999;
}
Expand Down
16 changes: 16 additions & 0 deletions src/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@ export default function getDefaultOptions(instance) {
action: function (column) {
this.removeColumn(column.colIndex);
}
},
{
label: instance.translate('Stick to left'),
stickyAction: 'stick',
display: 'hidden',
action: function (column) {
this.setColumnSticky(column.colIndex, true);
}
},
{
label: instance.translate('Unstick from left'),
stickyAction: 'unstick',
display: 'hidden',
action: function (column) {
this.setColumnSticky(column.colIndex, false);
}
}
],
events: {
Expand Down
2 changes: 2 additions & 0 deletions src/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"Sort Descending": "Absteigend sortieren",
"Reset sorting": "Sortierung zurücksetzen",
"Remove column": "Spalte entfernen",
"Stick to left": "Links anheften",
"Unstick from left": "Linke Anheftung lösen",
"No Data": "Keine Daten",
"{count} cells copied": {
"1": "{count} Zelle kopiert",
Expand Down
2 changes: 2 additions & 0 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"Sort Descending": "Sort Descending",
"Reset sorting": "Reset sorting",
"Remove column": "Remove column",
"Stick to left": "Stick to left",
"Unstick from left": "Unstick from left",
"No Data": "No Data",
"{count} cells copied": {
"1": "{count} cell copied",
Expand Down
2 changes: 2 additions & 0 deletions src/translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"Sort Descending": "Trier par ordre décroissant",
"Reset sorting": "Réinitialiser le tri",
"Remove column": "Supprimer colonne",
"Stick to left": "Épingler à gauche",
"Unstick from left": "Désépingler de la gauche",
"No Data": "Pas de données",
"{count} cells copied": {
"1": "{count} cellule copiée",
Expand Down
2 changes: 2 additions & 0 deletions src/translations/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"Sort Descending": "Ordinamento decrescente",
"Reset sorting": "Azzeramento ordinamento",
"Remove column": "Rimuovi colonna",
"Stick to left": "Blocca a sinistra",
"Unstick from left": "Sblocca dalla sinistra",
"No Data": "Nessun dato",
"{count} cells copied": {
"1": "Copiato {count} cella",
Expand Down
Loading