diff --git a/src/app/examples/grid-base-row-editing.component.ts b/src/app/examples/grid-base-row-editing.component.ts
index 1f07c44d7..bf989fc92 100644
--- a/src/app/examples/grid-base-row-editing.component.ts
+++ b/src/app/examples/grid-base-row-editing.component.ts
@@ -1,6 +1,6 @@
-
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
+import { SlickCustomTooltip } from '@slickgrid-universal/custom-tooltip-plugin';
import { Subscription } from 'rxjs';
import {
@@ -198,6 +198,7 @@ export class GridBaseRowEditingComponent implements OnInit {
deleteButtonPrompt: 'Are you sure you want to delete this row?',
},
},
+ externalResources: [new SlickCustomTooltip()],
};
}
diff --git a/src/app/examples/grid-composite-editor.component.ts b/src/app/examples/grid-composite-editor.component.ts
index 1cc4c0f8f..f1ba71401 100644
--- a/src/app/examples/grid-composite-editor.component.ts
+++ b/src/app/examples/grid-composite-editor.component.ts
@@ -1,6 +1,7 @@
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ExcelExportService } from '@slickgrid-universal/excel-export';
+import { SlickCustomTooltip } from '@slickgrid-universal/custom-tooltip-plugin';
import { SlickCompositeEditor, SlickCompositeEditorComponent } from '@slickgrid-universal/composite-editor-component';
import {
@@ -64,7 +65,7 @@ const customEditableInputFormatter: Formatter = (_row, _cell, value, columnDef,
const gridOptions = grid && grid.getOptions && grid.getOptions();
const isEditableLine = gridOptions.editable && columnDef.editor;
value = (value === null || value === undefined) ? '' : value;
- return isEditableLine ? { text: value, addClasses: 'editable-field', toolTip: 'Click to Edit' } : value;
+ return isEditableLine ? { text: value, addClasses: 'editable-field' } : value;
};
// you can create custom validator to pass to an inline editor
@@ -131,7 +132,8 @@ export class GridCompositeEditorComponent implements OnDestroy, OnInit {
prepareGrid() {
this.columnDefinitions = [
{
- id: 'title', name: 'Title', field: 'title', sortable: true, type: FieldType.string, minWidth: 75,
+ id: 'title', name: ' Title ',
+ field: 'title', sortable: true, type: FieldType.string, minWidth: 75,
cssClass: 'text-uppercase fw-bold', columnGroup: 'Common Factor',
filterable: true, filter: { model: Filters.compoundInputText },
editor: {
@@ -397,7 +399,7 @@ export class GridCompositeEditorComponent implements OnDestroy, OnInit {
excelExportOptions: {
exportWithFormatter: false
},
- externalResources: [new ExcelExportService(), this.compositeEditorInstance],
+ externalResources: [new ExcelExportService(), new SlickCustomTooltip(), this.compositeEditorInstance],
enableFiltering: true,
rowSelectionOptions: {
// True (Single Selection), False (Multiple Selections)
diff --git a/src/app/examples/grid-custom-tooltip.component.scss b/src/app/examples/grid-custom-tooltip.component.scss
index 86e6ab70a..62073ee39 100644
--- a/src/app/examples/grid-custom-tooltip.component.scss
+++ b/src/app/examples/grid-custom-tooltip.component.scss
@@ -35,6 +35,9 @@ $slick-button-border-color: #ababab !default;
// it's preferable to use CSS Variables (or SASS) but if you want to change colors of your tooltip for 1 column in particular you can do it this way
// e.g. change css of 5th column 4 (zero index: l4)
+.l4 {
+ --slick-tooltip-color: #fff;
+}
.l4 .header-tooltip-title,
.l4 .headerrow-tooltip-title {
color: #ffffff;
diff --git a/src/app/examples/grid-custom-tooltip.component.ts b/src/app/examples/grid-custom-tooltip.component.ts
index 0b95d8bd6..6d757b4f3 100644
--- a/src/app/examples/grid-custom-tooltip.component.ts
+++ b/src/app/examples/grid-custom-tooltip.component.ts
@@ -110,6 +110,7 @@ export class GridCustomTooltipComponent implements OnInit {
// define tooltip options here OR for the entire grid via the grid options (cell tooltip options will have precedence over grid options)
customTooltip: {
useRegularTooltip: true, // note regular tooltip will try to find a "title" attribute in the cell formatter (it won't work without a cell formatter)
+ useRegularTooltipFromCellTextOnly: true,
},
},
{
@@ -158,7 +159,12 @@ export class GridCustomTooltipComponent implements OnInit {
formatter: Formatters.percentCompleteBar,
sortable: true, filterable: true,
filter: { model: Filters.slider, operator: '>=' },
- customTooltip: { useRegularTooltip: true, },
+ customTooltip: {
+ position: 'center',
+ formatter: (_row, _cell, value) => typeof value === 'string' && value.includes('%') ? value : `${value}%`,
+ headerFormatter: undefined,
+ headerRowFormatter: undefined
+ },
},
{
id: 'start', name: 'Start', field: 'start', sortable: true,
@@ -434,12 +440,12 @@ export class GridCustomTooltipComponent implements OnInit {
tooltipFormatter(row: number, cell: number, value: any, column: Column, dataContext: any, grid: SlickGrid) {
const tooltipTitle = 'Custom Tooltip';
- const effortDrivenHtml = Formatters.checkmarkMaterial(row, cell, dataContext.effortDriven, column, dataContext, grid);
+ const effortDrivenHtml = Formatters.checkmarkMaterial(row, cell, dataContext.effortDriven, column, dataContext, grid) as HTMLElement;
return `
-
+
`;
}
@@ -449,9 +455,9 @@ export class GridCustomTooltipComponent implements OnInit {
// use a 2nd Formatter to get the percent completion
// any properties provided from the `asyncPost` will end up in the `__params` property (unless a different prop name is provided via `asyncParamsPropName`)
- const completionBar = Formatters.percentCompleteBarWithText(row, cell, dataContext.percentComplete, column, dataContext, grid);
+ const completionBar = Formatters.percentCompleteBarWithText(row, cell, dataContext.percentComplete, column, dataContext, grid) as HTMLElement;
const out = `
-
+
`;
diff --git a/test/cypress/e2e/example30.cy.ts b/test/cypress/e2e/example30.cy.ts
index 605b90ee5..8ad8b9053 100644
--- a/test/cypress/e2e/example30.cy.ts
+++ b/test/cypress/e2e/example30.cy.ts
@@ -2,7 +2,7 @@ import { changeTimezone, zeroPadding } from '../plugins/utilities';
describe('Example 30 Composite Editor Modal', () => {
const fullPreTitles = ['', 'Common Factor', 'Analysis', 'Period', 'Item', ''];
- const fullTitles = ['', 'Title', 'Duration', 'Cost', '% Complete', 'Complexity', 'Start', 'Completed', 'Finish', 'Product', 'Country of Origin', 'Action'];
+ const fullTitles = ['', ' Title ', 'Duration', 'Cost', '% Complete', 'Complexity', 'Start', 'Completed', 'Finish', 'Product', 'Country of Origin', 'Action'];
const GRID_ROW_HEIGHT = 35;
const EDITABLE_CELL_RGB_COLOR = 'rgba(227, 240, 251, 0.57)';
@@ -32,6 +32,23 @@ describe('Example 30 Composite Editor Modal', () => {
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
+ it('should display 2 different tooltips when hovering icons on "Title" column', () => {
+ cy.get('.slick-column-name').as('title-column');
+ cy.get('@title-column')
+ .find('.fa-exclamation-triangle')
+ .trigger('mouseover');
+
+ cy.get('.slick-custom-tooltip').should('be.visible');
+ cy.get('.slick-custom-tooltip .tooltip-body').contains('Task must always be followed by a number');
+
+ cy.get('@title-column')
+ .find('.fa-info-circle')
+ .trigger('mouseover');
+
+ cy.get('.slick-custom-tooltip').should('be.visible');
+ cy.get('.slick-custom-tooltip .tooltip-body').contains('Title is always rendered as UPPERCASE');
+ });
+
it('should have "TASK 0" (uppercase) incremented by 1 after each row', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).contains('TASK 0', { matchCase: false })
.should('have.css', 'text-transform', 'uppercase');
@@ -88,10 +105,10 @@ describe('Example 30 Composite Editor Modal', () => {
});
it('should not be able to change the "Finish" dates on first 2 rows', () => {
- cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(8)`).should('contain', '').click(); // this date should also always be initially empty
+ cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(8)`).should('contain', '').click({ force: true }); // this date should also always be initially empty
cy.get(`.flatpickr-day.today:visible`).should('not.exist');
- cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(8)`).should('contain', '').click(); // this date should also always be initially empty
+ cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(8)`).should('contain', '').click({ force: true }); // this date should also always be initially empty
cy.get(`.flatpickr-day.today:visible`).should('not.exist');
});
@@ -288,7 +305,7 @@ describe('Example 30 Composite Editor Modal', () => {
cy.get('.slick-editor-modal').should('not.exist');
});
- it('should have new TASK 8888 displayed on first row', () => {
+ it('should have new TASK 8899 displayed on first row', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).contains('TASK 8899', { matchCase: false });
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(2)`).should('contain', '33 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(4)`).should('contain', '17');
diff --git a/test/cypress/e2e/example32.cy.ts b/test/cypress/e2e/example32.cy.ts
index 5c46b9e42..da0c447a2 100644
--- a/test/cypress/e2e/example32.cy.ts
+++ b/test/cypress/e2e/example32.cy.ts
@@ -36,6 +36,9 @@ describe('Example 32 - Regular & Custom Tooltips', () => {
cy.get('.slick-custom-tooltip').should('be.visible');
cy.get('.slick-custom-tooltip').contains('Task 2 - (async tooltip)');
+ cy.get('.tooltip-2cols-row:nth(0)').find('div:nth(0)').contains('Completion:');
+ cy.get('.tooltip-2cols-row:nth(0)').find('div').should('have.class', 'percent-complete-bar-with-text');
+
cy.get('.tooltip-2cols-row:nth(1)').find('div:nth(0)').contains('Lifespan:');
cy.get('.tooltip-2cols-row:nth(1)').find('div:nth(1)').contains(/\d+$/); // use regexp to make sure it's a number
@@ -167,7 +170,7 @@ describe('Example 32 - Regular & Custom Tooltips', () => {
it('should mouse over header-row (filter) 2nd column Title and expect a tooltip to show rendered from an headerRowFormatter', () => {
cy.get(`.slick-headerrow-columns .slick-headerrow-column:nth(1)`).as('checkbox0-filter');
- cy.get('@checkbox0-filter').trigger('mouseenter');
+ cy.get('@checkbox0-filter').trigger('mouseover');
cy.get('.slick-custom-tooltip').should('be.visible');
cy.get('.slick-custom-tooltip').contains('Custom Tooltip - Header Row (filter)');
@@ -180,7 +183,7 @@ describe('Example 32 - Regular & Custom Tooltips', () => {
it('should mouse over header-row (filter) Finish column and NOT expect any tooltip to show since it is disabled on that column', () => {
cy.get(`.slick-headerrow-columns .slick-headerrow-column:nth(8)`).as('finish-filter');
- cy.get('@finish-filter').trigger('mouseenter');
+ cy.get('@finish-filter').trigger('mouseover');
cy.get('.slick-custom-tooltip').should('not.exist');
cy.get('@finish-filter').trigger('mouseout');
@@ -188,7 +191,7 @@ describe('Example 32 - Regular & Custom Tooltips', () => {
it('should mouse over header-row (filter) Prerequisite column and expect to see tooltip of selected filter options', () => {
cy.get(`.slick-headerrow-columns .slick-headerrow-column:nth(10)`).as('checkbox10-header');
- cy.get('@checkbox10-header').trigger('mouseenter');
+ cy.get('@checkbox10-header').trigger('mouseover');
cy.get('.filter-prerequisites .ms-choice span').contains('15 of 500 selected');
cy.get('.slick-custom-tooltip').should('be.visible');
@@ -199,7 +202,7 @@ describe('Example 32 - Regular & Custom Tooltips', () => {
it('should mouse over header title on 1st column with checkbox and NOT expect any tooltip to show since it is disabled on that column', () => {
cy.get(`.slick-header-columns .slick-header-column:nth(0)`).as('checkbox-header');
- cy.get('@checkbox-header').trigger('mouseenter');
+ cy.get('@checkbox-header').trigger('mouseover');
cy.get('.slick-custom-tooltip').should('not.exist');
cy.get('@checkbox-header').trigger('mouseout');
@@ -207,7 +210,7 @@ describe('Example 32 - Regular & Custom Tooltips', () => {
it('should mouse over header title on 2nd column with Title name and expect a tooltip to show rendered from an headerFormatter', () => {
cy.get(`.slick-header-columns .slick-header-column:nth(1)`).as('checkbox0-header');
- cy.get('@checkbox0-header').trigger('mouseenter');
+ cy.get('@checkbox0-header').trigger('mouseover');
cy.get('.slick-custom-tooltip').should('be.visible');
cy.get('.slick-custom-tooltip').contains('Custom Tooltip - Header');
@@ -220,7 +223,7 @@ describe('Example 32 - Regular & Custom Tooltips', () => {
it('should mouse over header title on 2nd column with Finish name and NOT expect any tooltip to show since it is disabled on that column', () => {
cy.get(`.slick-header-columns .slick-header-column:nth(8)`).as('finish-header');
- cy.get('@finish-header').trigger('mouseenter');
+ cy.get('@finish-header').trigger('mouseover');
cy.get('.slick-custom-tooltip').should('not.exist');
cy.get('@finish-header').trigger('mouseout');
diff --git a/test/cypress/e2e/example35.cy.ts b/test/cypress/e2e/example35.cy.ts
index 34f371b3e..6a5c94660 100644
--- a/test/cypress/e2e/example35.cy.ts
+++ b/test/cypress/e2e/example35.cy.ts
@@ -22,7 +22,7 @@ describe('Example 35 - Row Based Editing', () => {
it('should only allow to toggle a single row into editmode on single mode', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click();
- cy.get('.action-btns--edit').eq(1).click();
+ cy.get('.action-btns--edit:nth(0)').click({ force: true });
cy.get('.slick-row.slick-rbe-editmode').should('have.length', 1);
});
@@ -30,22 +30,22 @@ describe('Example 35 - Row Based Editing', () => {
it('should allow to toggle a multiple rows into editmode on multiple mode', () => {
cy.reload();
cy.get('[data-test="single-multi-toggle"]').click();
- cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click();
- cy.get('.action-btns--edit').eq(1).click();
- cy.get('.action-btns--edit').eq(2).click();
+ cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click({ force: true });
+ cy.get('.action-btns--edit').eq(1).click({ force: true });
+ cy.get('.action-btns--edit').eq(2).click({ force: true });
cy.get('.slick-row.slick-rbe-editmode').should('have.length', 3);
});
it('should not display editor in rows not being in editmode', () => {
cy.reload();
- cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l2.r2`).click();
+ cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l2.r2`).click({ force: true });
cy.get('input').should('have.length', 0);
- cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click();
+ cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click({ force: true });
- cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l2.r2`).click();
+ cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l2.r2`).click({ force: true });
cy.get('input').should('have.length', 1);
});
@@ -53,7 +53,7 @@ describe('Example 35 - Row Based Editing', () => {
it('should highlight modified cells and maintain proper index on sorting', () => {
cy.reload();
- cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click();
+ cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click({ force: true });
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l0.r0`).click().type('abc{enter}');
cy.get('.slick-cell').first().should('have.class', 'slick-rbe-unsaved-cell');
@@ -66,7 +66,7 @@ describe('Example 35 - Row Based Editing', () => {
it('should stay in editmode if saving failed', () => {
cy.reload();
- cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click();
+ cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click({ force: true });
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l1.r1`).click().type('50{enter}');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l2.r2`).click().type('50');
@@ -83,12 +83,12 @@ describe('Example 35 - Row Based Editing', () => {
it('should save changes on update button click', () => {
cy.reload();
- cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click();
+ cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click({ force: true });
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l1.r1`).click().type('30{enter}');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l2.r2`).type('30');
- cy.get('.action-btns--update').first().click();
+ cy.get('.action-btns--update').first().click({ force: true });
cy.get('[data-test="fetch-result"]')
.should('contain', 'success');
@@ -98,27 +98,27 @@ describe('Example 35 - Row Based Editing', () => {
});
it('should cleanup status when starting a new edit mode', () => {
- cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click();
+ cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click({ force: true });
cy.get('[data-test="fetch-result"]').should('be.empty');
- cy.get('.action-btns--cancel').first().click();
+ cy.get('.action-btns--cancel').first().click({ force: true });
});
it('should revert changes on cancel click', () => {
- cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click();
+ cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] .action-btns--edit`).click({ force: true });
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l1.r1`).click().type('50{enter}');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l2.r2`).type('50{enter}');
- cy.get('.action-btns--cancel').first().click();
+ cy.get('.action-btns--cancel').first().click({ force: true });
cy.get('.slick-cell.l1.r1').first().should('contain', '30');
cy.get('.slick-cell.l2.r2').first().should('contain', '30');
});
it('should delete a row when clicking it', () => {
- cy.get('.action-btns--delete').first().click();
+ cy.get('.action-btns--delete').first().click({ force: true });
cy.on('window:confirm', () => true);
@@ -143,20 +143,25 @@ describe('Example 35 - Row Based Editing', () => {
cy.get('[data-test="toggle-language"]').click();
cy.get('[data-test="selected-locale"]').should('contain', 'fr.json');
- // this seems to be a bug in Cypress, it doesn't seem to be able to click on the button
- // but at least it triggers a rerender, which makes it refetch the actual button instead of a cached one
- cy.get('.action-btns--update').first().click({ force: true });
+ cy.get('.action-btns--edit').first().click({ force: true });
- cy.get('.action-btns--update')
- .first()
- .should(($btn) => {
- expect($btn.attr('title')).to.equal('Mettre à jour la ligne actuelle');
- });
+ cy.get('.action-btns--cancel').first().as('cancel-btn');
+ cy.get('@cancel-btn').should(($btn) => {
+ expect($btn.attr('title')).to.equal('Annuler la ligne actuelle');
+ });
+ cy.get('@cancel-btn').trigger('mouseover', { position: 'top' });
+ cy.get('.slick-custom-tooltip').should('be.visible');
+ cy.get('.slick-custom-tooltip .tooltip-body').contains('Annuler la ligne actuelle');
- cy.get('.action-btns--cancel')
- .first()
- .should(($btn) => {
- expect($btn.attr('title')).to.equal('Annuler la ligne actuelle');
- });
+ cy.get('.action-btns--update').first().as('update-btn');
+ cy.get('@update-btn').should(($btn) => {
+ expect($btn.attr('title')).to.equal('Mettre à jour la ligne actuelle');
+ });
+
+ cy.get('@update-btn').trigger('mouseover', { position: 'top' });
+
+ cy.get('.slick-custom-tooltip').should('be.visible');
+ cy.get('.slick-custom-tooltip .tooltip-body').contains('Mettre à jour la ligne actuelle');
+ cy.get('@update-btn').first().click({ force: true });
});
-});
+});
\ No newline at end of file
diff --git a/test/mockSlickEvent.ts b/test/mockSlickEvent.ts
index 9fc14c95e..ded7a7a0a 100644
--- a/test/mockSlickEvent.ts
+++ b/test/mockSlickEvent.ts
@@ -1,4 +1,4 @@
-import { Handler, SlickEvent, SlickEventData } from '@slickgrid-universal/common';
+import type { Handler, SlickEvent, SlickEventData } from '@slickgrid-universal/common';
type MergeTypes = { [key in keyof A]: key extends keyof B ? B[key] : A[key]; } & B;
// @ts-ignore