diff --git a/cypress/integration/column.js b/cypress/integration/column.js
index 94f7c97..bab33c4 100644
--- a/cypress/integration/column.js
+++ b/cypress/integration/column.js
@@ -1,5 +1,5 @@
describe('Column', function () {
- before(function () {
+ beforeEach(function () {
cy.visit('/');
});
@@ -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);
});
});
});
diff --git a/index.html b/index.html
index bd545dd..a7868c6 100644
--- a/index.html
+++ b/index.html
@@ -151,9 +151,9 @@
Frappe DataTable
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",
diff --git a/src/columnmanager.js b/src/columnmanager.js
index 93344da..d27d9ac 100644
--- a/src/columnmanager.js
+++ b/src/columnmanager.js
@@ -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;
@@ -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();
}
@@ -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() {
@@ -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)
@@ -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');
+ }
+ }
}
diff --git a/src/datatable.js b/src/datatable.js
index c34ebc3..6d1f62a 100644
--- a/src/datatable.js
+++ b/src/datatable.js
@@ -222,6 +222,10 @@ class DataTable {
this.columnmanager.removeColumn(colIndex);
}
+ setColumnSticky(colIndex, sticky) {
+ this.columnmanager.setColumnSticky(colIndex, sticky);
+ }
+
scrollToLastColumn() {
this.datatableWrapper.scrollLeft = 9999;
}
diff --git a/src/defaults.js b/src/defaults.js
index 359f8e8..b815f8e 100644
--- a/src/defaults.js
+++ b/src/defaults.js
@@ -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: {
diff --git a/src/translations/de.json b/src/translations/de.json
index 0e667df..584e3af 100644
--- a/src/translations/de.json
+++ b/src/translations/de.json
@@ -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",
diff --git a/src/translations/en.json b/src/translations/en.json
index 8029868..ce674a1 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -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",
diff --git a/src/translations/fr.json b/src/translations/fr.json
index 194ec10..3540ef9 100644
--- a/src/translations/fr.json
+++ b/src/translations/fr.json
@@ -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",
diff --git a/src/translations/it.json b/src/translations/it.json
index a7308c1..2454edf 100644
--- a/src/translations/it.json
+++ b/src/translations/it.json
@@ -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",