initial commit

This commit is contained in:
equippedcoding-master
2025-09-17 09:37:06 -05:00
parent 86108ca47e
commit e2c98790b2
55389 changed files with 6206730 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = false
trim_trailing_whitespace = true
+3
View File
@@ -0,0 +1,3 @@
*.css text=auto
*.js text=auto
*.htm* text=auto
+31
View File
@@ -0,0 +1,31 @@
.env
.gitk*
.idea/*
.DS_Store
*.backup
*.exe
*.pdb
*.bak
*.esproj
*.sln
.vs*
.eslintcache
node_modules/*
src/models/*.js
src/plugins/*.js
src/controls/*.js
src/models/*.js
src/*.js
dist/browser/models/*
SlickgridRelease*
nuget*
testresult.xml
yarn-error.log
yarn.lock
tsconfig.tsbuildinfo
# IDE - VSCode
.vscode/*
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
+30
View File
@@ -0,0 +1,30 @@
.DS_Store
.env
.editorconfig
.eslintignore
.eslintrc
.gitk*
.gitattributes
.github
.idea/*
.vscode
*.backup
*.exe
*.pdb
*.nuspec
CHANGELOG.md
CODE_OF_CONDUCT.md
CONTRIBUTING.md
nuget*
cypress.json
cypress/*
lib
node_modules
examples
SlickgridRelease*
scripts
tests
testresult.xml
tsconfig.json
tsconfig.tsbuildinfo
package-lock.json
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,76 @@
# SlickGrid Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at email.ben.mcintyre@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
+26
View File
@@ -0,0 +1,26 @@
# Contributing
We'd love for you to contribute and to make this project even better than it is today! If this interests you, please make sure to follow the steps below before creating a Pull Request.
Before accepting any Pull Request, we would like to remind you to follow the following steps:
1. Install all dependencies
```sh
npm install
```
2. Run a full build
```sh
npm run build:prod
```
3. Fix any Linting or TypeScript issues (if any) returned by the build process
4. Run all Cypress E2E tests
```bash
npm run dev # run a local development server on port 8080 in watch mode (or `npm run serve` without watch)
npm run cypress # open Cypress UI tool
```
5. If you completed step 2 and 3, then the final step would be to proceed with your Pull Request
- **NOTE** even though the `dist/` folder is included in Git for portability, you could choose (we actually strongly recommend) that you ignore/disregard these files from being included in your Pull Request.
+20
View File
@@ -0,0 +1,20 @@
Copyright (c) 2009-present Michael Leibman and Ben McIntyre, http://github.com/6pac/slickgrid
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+104
View File
@@ -0,0 +1,104 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
[![NPM downloads](https://img.shields.io/npm/dm/slickgrid.svg)](https://npmjs.org/package/slickgrid)
[![jsdelivr hits/month](https://data.jsdelivr.com/v1/package/npm/slickgrid/badge)](https://www.jsdelivr.com/package/npm/slickgrid)
[![Cypress.io](https://img.shields.io/badge/tested%20with-Cypress-04C38E.svg)](https://www.cypress.io/)
[![npm](https://img.shields.io/npm/v/slickgrid.svg?logo=npm&logoColor=fff&label=npm)](https://npmjs.org/package/slickgrid)
[![Actions Status](https://github.com/6pac/SlickGrid/workflows/CI%20Build/badge.svg)](https://github.com/6pac/SlickGrid/actions)
## This is the 6pac SlickGrid repo
Check out the NEW SlickGrid Website! http://slickgrid.net/
This is the acknowledged and most active fork of SlickGrid.
It aims to be a viable alternative master repo, building on the legacy of the [mleibman/SlickGrid](https://github.com/mleibman/SlickGrid) master branch, keeping dependencies up to date and applying, safe core patches and enhancements to keep the project up to date.
We extended the project from the original SlickGrid foundation while also including the following changes:
- added a few more Plugins: RowDetail, CellMenu, ContextMenu, GridMenu, CustomTooltip, GridState
- merged [X-SlickGrid](https://github.com/ddomingues/X-SlickGrid) code into the project to bring Frozen Columns/Rows (aka Pinning)
- removed jQueryUI requirement in [v3](https://github.com/6pac/SlickGrid/wiki/Major-version-3.0----Removal-of-jQueryUI-requirement-(replaced-by-SortableJS)) (replaced it with [SortableJS](https://sortablejs.github.io/Sortable/))
- removed jQuery requirement in [v4](https://github.com/6pac/SlickGrid/wiki/Major-version-4.0---Removal-of-jQuery-requirement)
- modernized the project in [v5](https://github.com/6pac/SlickGrid/wiki/Major-version-5.0-%E2%80%90-ES6-ESM-and-TypeScript-Support) by migrating to TypeScript (we kept IIFE and added ES6/ESM build targets) and we also gave SlickGrid a fresh and more modern look via a new Alpine Theme (CSS/SASS)
- the project now has only 1 required small dependency which is [SortableJS](https://sortablejs.github.io/Sortable/)
### Vite Demo
You can also see a [ViteJS](https://vite.dev/) demo in the [./vite-demo](https://github.com/6pac/SlickGrid/tree/master/vite-demo) folder (also available via the Stackblitz link below). This Vite demo was created mostly to test the project ESM build and also the SASS imports as well, it could also be used to provide bug repro.
### Stackblitz
You can also try out the Vite demo (mentioned just above) live via Stackblitz. It can also be use to provide a repro when you openening any new bug/feature requests.
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/6pac/SlickGrid/tree/master/vite-demo)
> Note: the Stackblitz demo only includes couple of examples, note however that there are a lot more example in the **[Examples](https://github.com/6pac/SlickGrid/wiki/Examples)** Wiki page
### Examples
Check out the **[Examples](https://github.com/6pac/SlickGrid/wiki/Examples)** Wiki for a full list of examples demonstrating new features and use cases, such as dynamic grid creation and editors with third party controls.
Also take a look at the [Wiki](https://github.com/6pac/SlickGrid/wiki) and [Releases](https://github.com/6pac/SlickGrid/releases) for documentation and recent news.
_For a basic TypeScript example, take a look at the v5.0 Annoucement & Migration guide shown below and also the [TypeScript Example Wiki](https://github.com/6pac/SlickGrid/wiki/TypeScript-Examples)._
Below is one of the available examples available in Stackblitz (which is mentioned just above)
![Realtime Trading Demo](https://github.com/user-attachments/assets/a098b242-88e5-418d-a40b-3a8e44e93ca4)
### Installation
There are multiple ways to use and install SlickGrid, you can use it as a standalone `<script>` (IIFE) or install it through NPM and then `import` or `require` SlickGrid (`import` is preferred for tree shaking).
```sh
# Alpine style from CDN
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/slickgrid@5.14.0/dist/styles/css/slick-alpine-theme.min.css">
# standalone scripts (IIFE) from CDN
<script src="https://cdn.jsdelivr.net/npm/slickgrid@5.14.0/dist/browser/slick.core.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/slickgrid@5.14.0/dist/browser/slick.interactions.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/slickgrid@5.14.0/dist/browser/slick.grid.min.js"></script>
<script>
const grid = new Slick.Grid("#myGrid", dataView, columns, options);
</script>
---
# or install from NPM
npm install slickgrid
<script type="module">
import 'slickgrid/dist/styles/css/slick-alpine-theme.css';
import { SlickGrid, SlickDataView } from 'slickgrid';
const dataView = new SlickDataView({ inlineFilters: true });
const grid = new SlickGrid("#myGrid", dataView, columns, options);
</script>
```
For more CDN links, like controls and plugins, just headover to [jsDevlivr - SlickGrid](https://www.jsdelivr.com/package/npm/slickgrid) for the full list and click on the "Files" tab (or use this jsdelivr CDN link ["dist/browser"](https://www.jsdelivr.com/package/npm/slickgrid?tab=files&path=dist%2Fbrowser)).
### Contributions
See [Contributing Guide](https://github.com/6pac/SlickGrid/blob/master/CONTRIBUTING.md)
### E2E Tests with Cypress
A lot of our Examples now have [Cypress](https://www.cypress.io/) E2E (end to end) tests in the browser. You can see [here](https://github.com/6pac/SlickGrid/tree/master/cypress/e2e) the complete list of Examples that now have E2E tests. The biggest advantage is that these tests are executed in the [GitHub Actions](https://github.com/features/actions) Workflow (CI) for every Pull Request and that is to avoid committing changes that might break the library. We currently have tests for over 35+ examples with about 400 tests.
We welcome any new contributions and if you wish to add Cypress E2E tests, all you need to do is to clone the repo and run the following commands
```bash
npm install # install all npm packages
npm run dev # run a local development server on port 8080 in watch mode (or `npm run serve` without watch)
npm run cypress # open Cypress UI tool
```
Once the Cypress UI is open, you can then click on "Run all Specs" to execute all E2E browser tests.
## Migrations
| SlickGrid | Migration Guide | Description |
| --------- | --------------- | ----------- |
| 3.x | [Announcing v3.0](https://github.com/6pac/SlickGrid/wiki/Major-version-3.0----Removal-of-jQueryUI-requirement-(replaced-by-SortableJS)) | dropping [jQueryUI](https://jqueryui.com/) requirement and replaced it with [SortableJS](https://sortablejs.github.io/Sortable/) which is a lot more modern and touch friendly |
| 4.x | [Announcing v4.0](https://github.com/6pac/SlickGrid/wiki/Major-version-4.0---Removal-of-jQuery-requirement) | dropping [jQuery](https://jquery.com/) requirement, SlickGrid is now using browser native code |
| 5.x | [Announcing v5.0](https://github.com/6pac/SlickGrid/wiki/Major-version-5.0-%E2%80%90-ES6-ESM-and-TypeScript-Support) | project modernization, we added TypeScript with ES6, ESM builds and also a new Alpine Theme |
## CSP Compliance
The library is now, at least for the most part, CSP (Content Security Policy) compliant since `v5.5.0`, however there are some exceptions to be aware of. When using any html strings as template (for example with Custom Formatter returning an html string), you will not be fully compliant unless you return `TrustedHTML`. You can achieve this by using the `sanitizer` method in combo with [DOMPurify](https://github.com/cure53/DOMPurify) to return [`TrustedHTML`](https://developer.mozilla.org/en-US/docs/Web/API/TrustedHTML) and for more info, you can take a look at the [CSP Compliance](https://github.com/6pac/SlickGrid/wiki/CSP-Compliance) Wiki.
### Quick Little Fun Survey ✨
We are conducting a small little poll for fun, it is a single question survey about our latest releases. Thanks for taking the time to participate.
**[What do you think was the most exciting change(s) for you?](https://github.com/6pac/SlickGrid/discussions/853)**
@@ -0,0 +1,19 @@
import { defineConfig } from 'cypress';
import plugins from './plugins/index';
export default defineConfig({
video: false,
viewportWidth: 1200,
viewportHeight: 900,
e2e: {
experimentalRunAllSpecs: true,
testIsolation: false,
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
setupNodeEvents(on, config) {
return plugins(on, config);
},
baseUrl: 'http://localhost:8080',
},
});
@@ -0,0 +1,113 @@
describe('Example 0070 - Grid State using Local Storage', () => {
const originalTitles = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-0070-plugin-state.html`);
cy.get('h2 + p').should('contain', 'Slick.State');
cy.clearLocalStorage();
cy.get('[data-test="clear-storage"]').click();
});
it('should have exact Column Titles in the grid', () => {
cy.get('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(originalTitles[index]));
});
it('should sort ascending column "D"', () => {
cy.get('.slick-header-columns .slick-header-column:nth(3)')
.click({ force: true });
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(3)')
.find('.slick-sort-indicator.slick-sort-indicator-asc')
.should('be.visible');
});
it('should drag column "A" to be after column "C" in the grid', () => {
const expectedTitles = ['A', 'C', 'D', 'B', 'E', 'F', 'G', 'H', 'I', 'J'];
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(1)')
.contains('B')
.drag('.slick-header-column:nth(3)');
cy.get('.slick-header-column:nth(3)').contains('B');
cy.get('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(expectedTitles[index]));
});
it('should resize 1st column and make it wider', () => {
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(1)')
.should('contain', 'C');
cy.get('.slick-resizable-handle:nth(1)')
.trigger('mousedown', { which: 1, force: true })
.trigger('mousemove', 'bottomRight');
cy.get('.slick-header-column:nth(2)')
.trigger('mousemove', 'bottomRight')
.trigger('mouseup', 'bottomRight', { which: 1, force: true });
cy.get('.slick-header-column:nth(1)')
.should(($el) => {
const expectedWidth = 170; // calculate with a calculated width including a (+/-)5px precision
expect($el.width()).greaterThan(expectedWidth - 5);
expect($el.width()).lessThan(expectedWidth + 5);
});
});
it('should reload the page', () => {
cy.reload().wait(50);
});
it('should reload page and expect same columns orders, 2nd column wider and 3rd column sorted ascending', () => {
const expectedTitles = ['A', 'C', 'D', 'B', 'E', 'F', 'G', 'H', 'I', 'J'];
cy.get('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(expectedTitles[index]));
cy.get('.slick-header-column:nth(1)')
.should(($el) => {
const expectedWidth = 170; // calculate with a calculated width including a (+/-)5px precision
expect($el.width()).greaterThan(expectedWidth - 5);
expect($el.width()).lessThan(expectedWidth + 5);
});
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(2)')
.find('.slick-sort-indicator.slick-sort-indicator-asc')
.should('be.visible');
});
it('should clear local storage & reload the page', () => {
cy.clearLocalStorage();
cy.get('[data-test="clear-storage"]').click();
cy.reload().wait(50);
});
it('should expect grid to be reset to default', () => {
cy.get('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(originalTitles[index]));
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(2)')
.find('.slick-sort-indicator.slick-sort-indicator-asc')
.should('not.exist');
});
});
@@ -0,0 +1,302 @@
import { getScrollDistanceWhenDragOutsideGrid } from '../support/drag';
describe('Example - Auto scroll when dragging', { retries: 1 }, () => {
// NOTE: everywhere there's a * 2 is because we have a top+bottom (frozen rows) containers even after Unfreeze Columns/Rows
const cellWidth = 80;
const cellHeight = 25;
const scrollbarDimension = 17;
const fullTitles = ['#', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Cost', 'Effort Driven'];
for (let i = 0; i < 30; i++) {
fullTitles.push('Mock' + i);
}
it('should load Example', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-auto-scroll-when-dragging.html`);
});
it('should have exact column titles on grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
cy.get('#myGrid2')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should select border shown in cell selection model, and hidden in row selection model when dragging', { scrollBehavior: false }, function () {
cy.getNthCell(0, 1, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell1')
.dragStart();
cy.get('#myGrid .slick-range-decorator').should('be.exist').and('have.css', 'border-color').and('not.equal', 'none');
cy.get('@cell1')
.dragCell(0, 5)
.dragEnd('#myGrid');
cy.get('#myGrid .slick-range-decorator').should('not.be.exist');
cy.get('#myGrid .slick-cell.selected').should('have.length', 6);
cy.getNthCell(0, 1, '', { parentSelector: '#myGrid2', rowHeight: cellHeight })
.as('cell2')
.dragStart();
cy.get('#myGrid2 .slick-range-decorator').should('be.exist').and('have.css', 'border-style').and('equal', 'none');
cy.get('@cell2')
.dragCell(5, 1)
.dragEnd('#myGrid2');
cy.get('#myGrid2 .slick-range-decorator').should('not.be.exist');
cy.get('#myGrid2 .slick-row:nth-child(-n+6)')
.children(':not(.cell-unselectable)')
.each(($child) => expect($child.attr('class')).to.include('selected'));
});
function testScroll() {
return getScrollDistanceWhenDragOutsideGrid('#myGrid', 'topLeft', 'right', 0, 1).then(cellScrollDistance => {
return getScrollDistanceWhenDragOutsideGrid('#myGrid2', 'topLeft', 'bottom', 0, 1).then(rowScrollDistance => {
return cy.wrap({
cell: {
scrollBefore: cellScrollDistance.scrollLeftBefore,
scrollAfter: cellScrollDistance.scrollLeftAfter
},
row: {
scrollBefore: rowScrollDistance.scrollTopBefore,
scrollAfter: rowScrollDistance.scrollTopAfter
}
});
});
});
}
it('should auto scroll take effect to display the selecting element when dragging', { scrollBehavior: false }, function () {
testScroll().then(scrollDistance => {
expect(scrollDistance.cell.scrollBefore).to.be.lessThan(scrollDistance.cell.scrollAfter);
expect(scrollDistance.row.scrollBefore).to.be.lessThan(scrollDistance.row.scrollAfter);
});
cy.get('#isAutoScroll').click();
cy.get('#setOptions').click();
testScroll().then(scrollDistance => {
expect(scrollDistance.cell.scrollBefore).to.be.equal(scrollDistance.cell.scrollAfter);
expect(scrollDistance.row.scrollBefore).to.be.equal(scrollDistance.row.scrollAfter);
});
cy.get('#setDefaultOption').click();
cy.get('#isAutoScroll').should('have.value', 'on');
});
function getIntervalUntilRow16Displayed(selector, px) {
const viewportSelector = (selector + ' .slick-viewport:first');
cy.getNthCell(0, 1, '', { parentSelector: selector, rowHeight: cellHeight })
.dragStart();
return cy.get(viewportSelector).invoke('scrollTop').then(scrollBefore => {
cy.dragOutside('bottom', 0, px, { parentSelector: selector, rowHeight: cellHeight });
const start = performance.now();
cy.get(selector + ' .slick-row:not(.slick-group) >.cell-unselectable')
.contains('16', { timeout: 10000 }) // actually #15 will be selected
.should('not.be.hidden');
return cy.get(viewportSelector).invoke('scrollTop').then(scrollAfter => {
cy.dragEnd(selector);
const interval = performance.now() - start;
expect(scrollBefore).to.be.lessThan(scrollAfter);
cy.get(viewportSelector).scrollTo(0, 0, { ensureScrollable: false });
return cy.wrap(interval);
});
});
}
function testInterval(px) {
return getIntervalUntilRow16Displayed('#myGrid', px).then(intervalCell => {
return getIntervalUntilRow16Displayed('#myGrid2', px).then(intervalRow => {
return cy.wrap({
cell: intervalCell,
row: intervalRow
});
});
});
}
it('should MIN interval take effect when auto scroll: 30ms -> 90ms', { scrollBehavior: false }, function () {
// By default the MIN interval to show next cell is 30ms.
testInterval(300).then(defaultInterval => {
// Setting the interval to 90ms (3 times of the default).
cy.get('#minIntervalToShowNextCell').type('{selectall}90'); // 30ms -> 90ms
cy.get('#setOptions').click();
// Ideally if we scrolling to same row by MIN interval, the used time should be 3 times slower than default.
// Considering the threshold, 1.5 times slower than default is expected
testInterval(300).then(newInterval => {
// max scrolling speed is slower than before
expect(newInterval.cell).to.be.greaterThan(1.5 * defaultInterval.cell);
expect(newInterval.row).to.be.greaterThan(1.5 * defaultInterval.row);
cy.get('#setDefaultOption').click();
cy.get('#minIntervalToShowNextCell').should('have.value', '30');
});
});
});
it.skip('should MAX interval take effect when auto scroll: 600ms -> 200ms', { scrollBehavior: false }, function () {
// By default the MAX interval to show next cell is 600ms.
testInterval(0).then(defaultInterval => {
// Setting the interval to 200ms (1/3 of the default).
cy.get('#maxIntervalToShowNextCell').type('{selectall}200'); // 600ms -> 200ms
cy.get('#setOptions').click();
// Ideally if we scrolling to same row by MAX interval, the used time should be 3 times faster than default.
// Considering the threshold, 1.5 times faster than default is expected
testInterval(0).then(newInterval => {
// min scrolling speed is quicker than before
expect(1.5 * newInterval.cell).to.be.lessThan(defaultInterval.cell);
expect(1.5 * newInterval.row).to.be.lessThan(defaultInterval.row);
cy.get('#setDefaultOption').click();
cy.get('#maxIntervalToShowNextCell').should('have.value', '600');
});
});
});
it('should Delay per Px take effect when auto scroll: 5ms/px -> 50ms/px', { scrollBehavior: false }, function () {
const allowedDiff = 0.5;
// By default the Delay per Px is 5ms/px.
testInterval(scrollbarDimension).then(defaultInterval => {
// Setting to 50ms/px (10 times of the default).
cy.get('#accelerateInterval').type('{selectall}50'); // 5ms/px -> 50ms/px
cy.get('#setOptions').click();
// Ideally if we scrolling to same row, and set cursor to 17px, the new interval will be set to MIN interval (Math.max(30, 600 - 50 * 17) = 30ms),
// and the used time should be around 17 times faster than default.
// Considering the threshold, 5 times faster than default is expected
testInterval(scrollbarDimension).then(newInterval => {
// scrolling speed is quicker than before
expect((5 - allowedDiff) * newInterval.cell).to.be.lessThan(defaultInterval.cell);
expect((5 - allowedDiff) * newInterval.row).to.be.lessThan(defaultInterval.row);
cy.get('#setDefaultOption').click();
cy.get('#accelerateInterval').should('have.value', '5');
});
});
});
it('should have a frozen grid with 4 containers with 2 columns on the left and 3 rows on the top after click Set/Clear Frozen button', () => {
cy.get('#myGrid [style="top: 0px;"]').should('have.length', 1);
cy.get('#myGrid2 [style="top: 0px;"]').should('have.length', 1);
cy.get('#toggleFrozen').click();
cy.get('#myGrid [style="top: 0px;"]').should('have.length', 2 * 2);
cy.get('#myGrid2 [style="top: 0px;"]').should('have.length', 2 * 2);
cy.get('#myGrid .grid-canvas-left > [style="top: 0px;"]').children().should('have.length', 2 * 2);
cy.get('#myGrid2 .grid-canvas-left > [style="top: 0px;"]').children().should('have.length', 2 * 2);
cy.get('#myGrid .grid-canvas-top').children().should('have.length', 3 * 2);
cy.get('#myGrid2 .grid-canvas-top').children().should('have.length', 3 * 2);
});
function resetScrollInFrozen() {
cy.get('#myGrid .slick-viewport:last').scrollTo(0, 0);
cy.get('#myGrid2 .slick-viewport:last').scrollTo(0, 0);
}
it('should auto scroll to display the selecting element when dragging in frozen grid', { scrollBehavior: false }, () => {
// top left - to bottomRight
getScrollDistanceWhenDragOutsideGrid('#myGrid', 'topLeft', 'bottomRight', 0, 1).then(result => {
expect(result.scrollTopBefore).to.be.equal(result.scrollTopAfter);
expect(result.scrollLeftBefore).to.be.equal(result.scrollLeftAfter);
});
getScrollDistanceWhenDragOutsideGrid('#myGrid2', 'topLeft', 'bottomRight', 0, 1).then(result => {
expect(result.scrollTopBefore).to.be.equal(result.scrollTopAfter);
expect(result.scrollLeftBefore).to.be.equal(result.scrollLeftAfter);
});
// top right - to bottomRight
getScrollDistanceWhenDragOutsideGrid('#myGrid', 'topRight', 'bottomRight', 0, 0).then(result => {
expect(result.scrollTopBefore).to.be.equal(result.scrollTopAfter);
expect(result.scrollLeftBefore).to.be.lessThan(result.scrollLeftAfter);
});
getScrollDistanceWhenDragOutsideGrid('#myGrid2', 'topRight', 'bottomRight', 0, 0).then(result => {
expect(result.scrollTopBefore).to.be.equal(result.scrollTopAfter);
expect(result.scrollLeftBefore).to.be.lessThan(result.scrollLeftAfter);
});
resetScrollInFrozen();
// bottom left - to bottomRight
getScrollDistanceWhenDragOutsideGrid('#myGrid', 'bottomLeft', 'bottomRight', 0, 1).then(result => {
expect(result.scrollTopBefore).to.be.lessThan(result.scrollTopAfter);
expect(result.scrollLeftBefore).to.be.equal(result.scrollLeftAfter);
});
getScrollDistanceWhenDragOutsideGrid('#myGrid2', 'bottomLeft', 'bottomRight', 0, 1).then(result => {
expect(result.scrollTopBefore).to.be.lessThan(result.scrollTopAfter);
expect(result.scrollLeftBefore).to.be.equal(result.scrollLeftAfter);
});
resetScrollInFrozen();
// bottom right - to bottomRight
getScrollDistanceWhenDragOutsideGrid('#myGrid', 'bottomRight', 'bottomRight', 0, 0).then(result => {
expect(result.scrollTopBefore).to.be.lessThan(result.scrollTopAfter);
expect(result.scrollLeftBefore).to.be.lessThan(result.scrollLeftAfter);
});
getScrollDistanceWhenDragOutsideGrid('#myGrid2', 'bottomRight', 'bottomRight', 0, 0).then(result => {
expect(result.scrollTopBefore).to.be.lessThan(result.scrollTopAfter);
expect(result.scrollLeftBefore).to.be.lessThan(result.scrollLeftAfter);
});
resetScrollInFrozen();
cy.get('#myGrid .slick-viewport-bottom.slick-viewport-right').scrollTo(cellWidth * 3, cellHeight * 3);
cy.get('#myGrid2 .slick-viewport-bottom.slick-viewport-right').scrollTo(cellWidth * 3, cellHeight * 3);
// bottom right - to topLeft
getScrollDistanceWhenDragOutsideGrid('#myGrid', 'bottomRight', 'topLeft', 8, 4, 100).then(result => {
expect(result.scrollTopBefore).to.be.greaterThan(result.scrollTopAfter);
expect(result.scrollLeftBefore).to.be.greaterThan(result.scrollLeftAfter);
});
getScrollDistanceWhenDragOutsideGrid('#myGrid2', 'bottomRight', 'topLeft', 8, 4, 100).then(result => {
expect(result.scrollTopBefore).to.be.greaterThan(result.scrollTopAfter);
expect(result.scrollLeftBefore).to.be.greaterThan(result.scrollLeftAfter);
});
resetScrollInFrozen();
});
it('should have a frozen & grouping by Duration grid after click Set/Clear grouping by Duration button', { scrollBehavior: false }, () => {
cy.get('#toggleGroup').trigger('click');
cy.get('#myGrid [style="top: 0px;"]').should('have.length', 2 * 2);
cy.get('#myGrid2 [style="top: 0px;"]').should('have.length', 2 * 2);
cy.get('#myGrid .grid-canvas-top.grid-canvas-left').contains('Duration');
cy.get('#myGrid2 .grid-canvas-top.grid-canvas-left').contains('Duration');
});
function testDragInGrouping(selector) {
cy.getNthCell(7, 0, 'bottomRight', { parentSelector: selector, rowHeight: cellHeight })
.dragStart();
cy.get(selector + ' .slick-viewport:last').as('viewport').invoke('scrollTop').then(scrollBefore => {
cy.dragOutside('bottom', 400, 300, { parentSelector: selector, rowHeight: cellHeight });
cy.get('@viewport').invoke('scrollTop').then(scrollAfter => {
expect(scrollBefore).to.be.lessThan(scrollAfter);
cy.dragEnd(selector);
cy.get(selector + ' [style="top: 350px;"].slick-group').should('not.be.hidden');;
});
});
}
it('should auto scroll to display the selecting element even unselectable cell exist in grouping grid', { scrollBehavior: false }, () => {
testDragInGrouping('#myGrid');
testDragInGrouping('#myGrid2');
});
it('should reset to default grid when click Set/Clear Frozen button and Set/Clear grouping button', () => {
cy.get('#toggleFrozen').trigger('click');
cy.get('#toggleGroup').trigger('click');
cy.get('#myGrid [style="top: 0px;"]').should('have.length', 1);
cy.get('#myGrid2 [style="top: 0px;"]').should('have.length', 1);
});
});
@@ -0,0 +1,55 @@
describe('Example AutoTooltips Plugin', () => {
const GRID_ROW_HEIGHT = 25;
const originalTitles = ['Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-autotooltips.html`);
cy.get('ul > li').should('contain', 'AutoTooltips plugin');
});
it('should have exact Column Titles in the grid', () => {
cy.get('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(originalTitles[index]));
});
it('should resize "Start" date column and make it smaller than text length and hover over cell to see tooltip', () => {
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(3)')
.should('contain', 'Start');
cy.get('.slick-resizable-handle:nth(3)')
.trigger('mousedown', { which: 1, force: true })
.trigger('mousemove', 'bottomRight');
cy.get('.slick-header-column:nth(2)')
.trigger('mousemove', 'bottomRight')
.trigger('mouseup', 'bottomRight', { which: 1, force: true });
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l3.r3`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l3.r3`).trigger('mouseover');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l3.r3`).should('have.attr', 'title', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell.l3.r3`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell.l3.r3`).trigger('mouseover');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell.l3.r3`).should('have.attr', 'title', '01/01/2009');
});
it('should hover over "Finish" cell to see tooltip', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l4.r4`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l4.r4`).trigger('mouseover');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l4.r4`).should('not.have.attr', 'title', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l4.r4`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l4.r4`).trigger('mouseover');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l4.r4`).should('not.have.attr', 'title', '01/05/2009');
});
});
@@ -0,0 +1,448 @@
describe('Example - Checkbox Header Row', () => {
const withTitleRowTitles = ['Sel', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
const withoutTitleRowTitles = ['', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
let selectedIdsCount = 0;
beforeEach(() => {
// create a console.log spy for later use
cy.window().then((win) => {
cy.spy(win.console, 'log');
});
});
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-checkbox-header-row.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('Using a fixed header row to implement column-level filters with Checkbox Selector');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
});
it('should select a single row and display new and previous selected rows in the console (previous should be empty)', () => {
cy.get('.slick-row:nth(3) .slick-cell:nth(0) input[type=checkbox]')
.click({ force: true });
cy.get('#selectedRows')
.contains('3');
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('Previously Selected Rows: ');
expect(win.console.log).to.be.calledWith('Selected Rows: 3');
});
});
it('should select a second row and display new and previous selected rows in the console (previous should be empty)', () => {
cy.get('.slick-row:nth(6) .slick-cell:nth(0) input[type=checkbox]')
.click({ force: true });
cy.get('#selectedRows')
.contains('3,7');
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('Previously Selected Rows: 3');
expect(win.console.log).to.be.calledWith('Selected Rows: 3,7');
});
});
it('should unselect first row and display previous and new selected rows', () => {
cy.get('.slick-cell-checkboxsel.selected:nth(0) input[type=checkbox]')
.click({ force: true });
cy.get('#selectedRows')
.contains('7');
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('Previously Selected Rows: 3,7');
expect(win.console.log).to.be.calledWith('Selected Rows: 7');
});
});
it('should click on Select All and display previous and new selected rows', () => {
const expectedRows = '1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,149';
cy.get('#filter-checkbox-selectall-container input[type=checkbox]')
.click({ force: true });
cy.get('#selectedRows')
.contains(expectedRows);
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('Previously Selected Rows: 7');
expect(win.console.log).to.be.calledWith(`Selected Rows: ${expectedRows}`);
});
});
it('should click on Select All again and expect no new selected rows', () => {
const expectedPreviousRows = '1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,133,135,137,139,141,143,145,147,149';
cy.get('#filter-checkbox-selectall-container input[type=checkbox]')
.click({ force: true });
cy.get('#selectedRows')
.invoke('text').then((text => {
expect(text.trim()).to.eq('');
}));
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith(`Previously Selected Rows: ${expectedPreviousRows}`);
expect(win.console.log).to.be.calledWith('Selected Rows: ');
});
});
it('should display "Showing page 1 of 6" text after changing Pagination to 25 items per page', () => {
cy.get('.sgi-lightbulb')
.click();
cy.get('.slick-pager-settings-expanded')
.should('be.visible');
cy.get('.slick-pager-settings-expanded')
.contains('25')
.click();
cy.get('.slick-pager-status')
.contains('Showing page 1 of 6');
});
it('should change row selection across multiple pages, first page should have 2 selected', () => {
cy.get('[data-test="set-dynamic-rows"]').click();
// Row index 3, 5 and 21 (last one will be on 2nd page)
cy.get('input[type="checkbox"]:checked').should('have.length', 2); // 2x in current page and 1x in next page
cy.get('[style="top: 75px;"] > .slick-cell:nth(0) input[type="checkbox"]').should('be.checked');
cy.get('[style="top: 125px;"] > .slick-cell:nth(0) input[type="checkbox"]').should('be.checked');
});
it('should go to next page and expect 1 row selected in that second page', () => {
cy.get('.sgi-chevron-right')
.click();
cy.get('input[type="checkbox"]:checked').should('have.length', 1); // only 1x row in page 2
cy.get('[style="top: 100px;"] > .slick-cell:nth(0) input[type="checkbox"]').should('be.checked');
});
it('should click on "Select All" checkbox and expect all rows selected in current page', () => {
const expectedRows = '1,3,5,7,9,11,13,15,17,19,21,23';
// go back to 1st page
cy.get('.sgi-chevron-left')
.click();
cy.get('#filter-checkbox-selectall-container input[type=checkbox]')
.click({ force: true });
cy.get('#selectedRows')
.contains(expectedRows);
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(4);
expect(win.console.log).to.be.calledWith('Previously Selected Rows: 3,5'); // from previous test
expect(win.console.log).to.be.calledWith(`Selected Rows: ${expectedRows}`);
});
});
it('should go to next page and still expect all rows selected in current page', () => {
cy.get('.sgi-chevron-right')
.click();
cy.get('.slick-cell-checkboxsel input:checked')
.should('have.length', 13);
});
it('should go to last page and still expect all rows selected in current page', () => {
cy.get('.sgi-chevron-end')
.click();
cy.get('.slick-cell-checkboxsel input:checked').should('have.length', 13);
cy.get('.slick-pager-status')
.contains('Showing page 6 of 6');
cy.get('#selectedRows')
.should('contain', '0,2,4,6,8,10,12,14,16,18,20,22,24');
cy.get('#selectedIds')
.should('contain', '9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107');
});
it('should uncheck first checkbox and expect the "Select All" button to be unchecked', () => {
cy.get('#filter-checkbox-selectall-container input[type=checkbox]')
.should('be.checked');
cy.get('.slick-row:nth(0) .slick-cell:nth(0) input[type=checkbox]')
.click({ force: true });
cy.get('#filter-checkbox-selectall-container input[type=checkbox]')
.should('not.be.checked');
cy.get('.slick-cell-checkboxsel input:checked')
.should('have.length', 12);
cy.get('#selectedRows')
.should('contain', '2,4,6,8,10,12,14,16,18,20,22,24');
cy.get('#selectedIds')
.should('contain', '9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,135,137,139,141,143,145,147,149,151,153,155,157');
});
it('should go back to first page and still expect all rows selected in current page', () => {
cy.get('.sgi-chevron-start')
.click();
cy.get('#filter-checkbox-selectall-container input[type=checkbox]')
.should('not.be.checked');
cy.get('.slick-cell-checkboxsel input:checked')
.should('have.length', 12);
cy.get('.slick-pager-status')
.contains('Showing page 1 of 6');
cy.get('#selectedRows')
.should('contain', '1,3,5,7,9,11,13,15,17,19,21,23');
cy.get('#selectedIds')
.should('contain', '9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,129,131,135,137,139,141,143,145,147,149,151,153,155,157');
});
it('should go back to last page then re-select the first row and expect "Select All" to be checked', () => {
cy.get('.sgi-chevron-end')
.click();
cy.get('.slick-row:nth(0) .slick-cell:nth(0) input[type=checkbox]')
.click({ force: true });
cy.get('#filter-checkbox-selectall-container input[type=checkbox]')
.should('be.checked');
cy.get('.slick-cell-checkboxsel input:checked')
.should('have.length', 13);
cy.get('.slick-pager-status')
.contains('Showing page 6 of 6');
cy.get('#selectedRows')
.should('contain', '0,2,4,6,8,10,12,14,16,18,20,22,24');
cy.get('#selectedIds')
.should('contain', '9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99,101,103,105,107');
});
it('should have lower count of selected Ids after filtering data', () => {
let prevSelectedIdsCount = 0;
let newSelectedIdsCount = 0;
let prevSelectedRowsCount = 0;
let newSelectedRowsCount = 0;
cy.get('#idsCount')
.then($elm => {
console.log($elm);
prevSelectedIdsCount = +$elm[0].textContent;
expect(prevSelectedIdsCount).to.be.greaterThan(0);
});
cy.get('#rowsCount')
.then($elm => {
console.log($elm);
prevSelectedRowsCount = +$elm[0].textContent;
expect(prevSelectedRowsCount).to.be.greaterThan(0);
expect(prevSelectedIdsCount).not.to.be.eq(prevSelectedRowsCount);
});
cy.get('.slick-pager-status')
.should('not.contain', 'Showing page 1 of 1');
cy.get('#myGrid')
.find('.slick-headerrow-column.l1.r1')
.find('input')
.type('5');
cy.get('#idsCount')
.then($elm => {
newSelectedIdsCount = +$elm[0].textContent;
expect(newSelectedIdsCount).to.be.lessThan(prevSelectedIdsCount);
});
cy.get('#rowsCount')
.then($elm => {
newSelectedRowsCount = +$elm[0].textContent;
});
cy.get('.slick-pager-status')
.then($elm => {
const pagerInfo = $elm[0].textContent;
if (pagerInfo === 'Showing page 1 of 1') {
expect(newSelectedIdsCount).to.be.eq(newSelectedRowsCount);
}
});
});
it('should clear all filters and expect 75 rows to be selected', () => {
cy.get('[data-test="clear-filters"]').click();
cy.get('.slick-headerrow-column')
.children()
.each(($child) => expect($child.text()).to.eq(''));
cy.get('#idsCount')
.then($elm => {
const newSelectedIdsCount = +$elm[0].textContent;
expect(newSelectedIdsCount).to.be.eq(75);
});
});
it('should clear all filters & clear all row selections', () => {
cy.get('[data-test="clear-filters"]').click();
cy.get('.slick-headerrow-column')
.children()
.each(($child) => expect($child.text()).to.eq(''));
cy.get('#filter-checkbox-selectall-container input[type=checkbox]')
.click({ force: true });
cy.get('#rowsCount')
.then($elm => {
const newSelectedRowsCount = +$elm[0].textContent;
expect(newSelectedRowsCount).to.be.eq(0);
});
cy.get('#idsCount')
.then($elm => {
selectedIdsCount = +$elm[0].textContent;
expect(selectedIdsCount).to.be.eq(0);
});
});
it('should filter data with text having "5" to show on a single page and then click on "Select All" checkbox', () => {
cy.get('#myGrid')
.find('.slick-headerrow-column.l1.r1')
.find('input')
.type('5');
cy.get('.slick-pager-status')
.should('contain', 'Showing page 1 of 1');
cy.get('#filter-checkbox-selectall-container input[type=checkbox]')
.click({ force: true });
cy.get('#idsCount')
.then($elm => {
selectedIdsCount = +$elm[0].textContent;
expect(selectedIdsCount).to.be.greaterThan(0);
});
});
it('should remove filter and not expect "Select All" checkbox to be selected but still expect same selected Ids', () => {
let newSelectedIdsCount = 0;
cy.get('[data-test="clear-filters"]').click();
cy.get('.slick-headerrow-column')
.children()
.each(($child) => expect($child.text()).to.eq(''));
cy.get('#idsCount')
.then($elm => {
newSelectedIdsCount = +$elm[0].textContent;
expect(newSelectedIdsCount).to.be.eq(selectedIdsCount);
});
cy.get('#rowsCount')
.then($elm => {
const newSelectedRowsCount = +$elm[0].textContent;
expect(newSelectedRowsCount).not.to.be.eq(newSelectedIdsCount);
});
cy.get('#filter-checkbox-selectall-container input[type=checkbox]')
.should('not.be.checked');
});
it('should sort and expect same selected Ids as previous test', () => {
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(1)')
.click();
cy.get('#idsCount')
.then($elm => {
expect(+$elm[0].textContent).to.be.eq(selectedIdsCount);
});
});
it('should revert back to the same filter as before and still expect the same selected Ids to be selected again', () => {
cy.get('#myGrid')
.find('.slick-headerrow-column.l1.r1')
.find('input')
.type('5');
cy.get('.slick-pager-status')
.should('contain', 'Showing page 1 of 1');
cy.get('#idsCount')
.then($elm => {
selectedIdsCount = +$elm[0].textContent;
expect(selectedIdsCount).to.be.greaterThan(0);
});
cy.get('#filter-checkbox-selectall-container input[type=checkbox]')
.should('be.checked');
});
it('should show Select All checkbox in header column titles row', () => {
cy.get('[data-test="toggle-select-all-row"]').click();
cy.get('#myGrid [data-id=_checkbox_selector] input[type=checkbox]')
.should('exist');
cy.get('.slick-header-column:nth(0)')
.find('.slick-column-name')
.should('not.contain', 'Sel');
cy.get('[data-test="toggle-select-all"]')
.click();
cy.get('.slick-header-column:nth(0)')
.find('.slick-column-name')
.should('contain', 'Sel');
cy.get('#myGrid [data-id=_checkbox_selector] input[type=checkbox]')
.should('not.exist');
cy.get('[data-test="toggle-select-all"]')
.click();
cy.get('.slick-header-column:nth(0)')
.find('.slick-column-name')
.should('not.contain', 'Sel');
cy.get('#myGrid [data-id=_checkbox_selector] input[type=checkbox]')
.should('exist');
});
it('should toggle back Select All to show under filter row and expect back "Sel" column name to show again', () => {
cy.get('.slick-header-column:nth(0)')
.find('.slick-column-name')
.should('not.contain', 'Sel');
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(withoutTitleRowTitles[index]));
cy.get('[data-test="toggle-select-all-row"]').click();
cy.get('.slick-header-column:nth(0)')
.find('.slick-column-name')
.should('contain', 'Sel');
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(withTitleRowTitles[index]));
});
});
@@ -0,0 +1,98 @@
describe('Example - Checkbox Row Select', () => {
const titles = ['', 'A', 'B', 'C', 'D', 'E'];
const GRID_ROW_HEIGHT = 25;
describe('Grid 1', () => {
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-checkbox-row-select.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('Checkbox row select column');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should be able to select 5th row of first grid by clicking "Select row 5" button', () => {
cy.get('#selectRow5')
.click();
cy.get('#myGrid')
.find('.slick-cell-checkboxsel input:checked')
.should('have.length', 1);
// the entire row (all 6x cells) should be selected
cy.get('#myGrid')
.find('.slick-cell.selected')
.should('have.length', 6);
});
it('should be able to select first 2 rows and now expect 3 rows selected', () => {
cy.get(`.slick-row[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) input[type=checkbox]`).click();
cy.get(`.slick-row[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0) input[type=checkbox]`).click();
cy.get('#myGrid')
.find('.slick-cell-checkboxsel input:checked')
.should('have.length', 3);
});
it('should be able to unselect 5th row of first grid by clicking "Unselect row 5" button', () => {
cy.get('#unselectRow5')
.click();
cy.get(`.slick-row[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(0) input[type=checkbox]`)
.should('not.be.checked');
cy.get('#myGrid')
.find('.slick-cell-checkboxsel input:checked')
.should('have.length', 2);
});
it('should be able to unselect all rows by clicking "Unselect all rows" button', () => {
cy.get('#unselectAllRows')
.click();
cy.get('#myGrid')
.find('.slick-cell-checkboxsel input:checked')
.should('have.length', 0);
});
it('should be able select all rows by clicking on the Select All checkbox', () => {
cy.get('#myGrid [data-id=_checkbox_selector]')
.click();
cy.get('#myGrid')
.find('.slick-cell-checkboxsel input:checked')
.should('have.length.greaterThan', 10);
});
it('should be able to unselect all rows by clicking "Unselect all rows" button', () => {
cy.get('#unselectAllRows')
.click();
cy.get('#myGrid')
.find('.slick-cell-checkboxsel input:checked')
.should('have.length', 0);
});
it('should be able to click on "toggle show/hide Select All" button and expect Select All checkbox to be toggled', () => {
cy.get('#myGrid [data-id=_checkbox_selector] input[type=checkbox]')
.should('exist');
cy.get('[data-test="toggle-select-all"]')
.click();
cy.get('#myGrid [data-id=_checkbox_selector] input[type=checkbox]')
.should('not.exist');
cy.get('[data-test="toggle-select-all"]')
.click();
cy.get('#myGrid [data-id=_checkbox_selector] input[type=checkbox]')
.should('exist');
});
});
});
@@ -0,0 +1,45 @@
describe('Example - Column Span & Header Grouping', { retries: 1 }, () => {
// NOTE: everywhere there's a * 2 is because we have a top+bottom (frozen rows) containers even after Unfreeze Columns/Rows
const GRID_ROW_HEIGHT = 25;
const fullTitles = ['Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
for (let i = 0; i < 30; i++) {
fullTitles.push(`Mock${i}`);
}
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-colspan.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('column span');
});
it('should have exact column titles', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should expect 1st row to be 1 column spanned to the entire width', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('not.exist');
});
it('should expect 2nd row to be 4 columns and not be spanned', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 1');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', '5 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(2)`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(3)`).contains(/(true|false)/);
});
it('should expect 3rd row to be 1 column spanned to the entire width', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 2');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).should('not.exist');
});
it('should expect 4th row to be 4 columns and not be spanned', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 3');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).should('contain', '5 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(2)`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(3)`).contains(/(true|false)/);
});
});
@@ -0,0 +1,330 @@
describe('Example - Composite Editor Modal with Create/Edit/Mass-Update/Mass-Selection', () => {
const GRID_ROW_HEIGHT = 25;
const titles = ['', 'Title', 'Description', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
beforeEach(() => {
// create a console.log spy for later use
cy.window().then((win) => {
cy.spy(win.console, 'log');
});
});
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-composite-editor-modal-dialog.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('Composite Editor Modal - Edit Form');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should expect first row to include "Task 0" and other specific properties', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(3)`).should('contain', '5 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(5)`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(6)`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('exist');
});
it('should open the Edit Modal and expect same data to include "Task 0" and other specific properties', () => {
cy.get('[data-test=edit-button]').click();
cy.get('.modal-header > h5').contains('Editing Task 0');
cy.get('.item-details-label.editor-title').contains('Title');
cy.get('[data-editorid=title] input')
.invoke('val')
.then(text => expect(text).to.eq('Task 0'));
cy.get('[data-editorid=duration] input')
.invoke('val')
.then(text => expect(text).to.eq('5'));
cy.get('[data-editorid=start] input')
.invoke('val')
.then(text => expect(text).to.eq('01/01/2009'));
cy.get('[data-editorid=finish] input')
.invoke('val')
.then(text => expect(text).to.eq('01/05/2009'));
});
it('Should try to change "Duration" below 5 and expect it to become invalid', () => {
cy.get('[data-editorid=duration] input')
.type('2');
cy.get('[data-action=save]').click();
cy.get('.item-details-validation.editor-duration')
.should('have.text', 'Duration must be at least 5 days when "Effort-Driven" is enabled');
cy.get('.modified')
.should('have.length', 1);
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(1);
expect(win.console.log).to.be.calledWith('composite editor input changed', { duration: 2 });
});
});
it('Should try to change "Duration" over 5 and expect it to become valid', () => {
cy.get('[data-editorid=duration] input')
.type('7')
.blur();
cy.get('.item-details-validation.editor-duration')
.should('have.text', '');
cy.get('.modified')
.should('have.length', 1);
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(1);
expect(win.console.log).to.be.calledWith('composite editor input changed', { duration: 27 });
});
});
it('Should change a few more values in the Edit Modal then expect the updated data in the grid after Saving', () => {
cy.get('[data-editorid=title] input')
.type('Task 0000');
cy.get('[data-editorid=desc] textarea')
.type('some description');
cy.get('[data-editorid=effort-driven] input')
.click();
cy.get('.modified')
.should('have.length', 4);
cy.get('[data-action=save]').click();
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(4);
expect(win.console.log).to.be.calledWith('composite editor input changed', { duration: 27, title: 'Task 0000', description: 'some description', effortDriven: false });
});
cy.wait(10);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 0000');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(3)`).should('contain', '27 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(5)`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(6)`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('have.length', 0);
});
it('should open the Mass Update try to change "Duration" below 5 and expect it to become invalid', () => {
cy.get('[data-test="mass-update-button"]').click();
cy.get('.modal-header > h5').contains('Mass Update (all rows)');
cy.get('[data-editorid=effort-driven] input')
.click();
cy.get('[data-editorid=duration] input')
.type('2');
cy.get('[data-action="mass-update"]').click();
cy.get('.item-details-validation.editor-duration')
.should('have.text', 'Duration must be at least 5 days when "Effort-Driven" is enabled');
cy.get('.modified')
.should('have.length', 2);
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('composite editor input changed', { duration: 2, effortDriven: true });
});
});
it('Should try to change "Duration" over 5 and expect it to become valid', () => {
cy.get('[data-editorid=duration] input')
.type('7')
.blur();
cy.get('.item-details-validation.editor-duration')
.should('have.text', '');
cy.get('.modified')
.should('have.length', 2);
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(1);
expect(win.console.log).to.be.calledWith('composite editor input changed', { duration: 27, effortDriven: true });
});
cy.get('[data-action="mass-update"]').click();
});
it('Should expect to see "Duration" of "27 days" and "Effort-Driven" to be enabled accross the entire grid', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 0000');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(3)`).should('contain', '27 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 1');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(3)`).should('contain', '27 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 2');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(3)`).should('contain', '27 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 3');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(3)`).should('contain', '27 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 4');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(3)`).should('contain', '27 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 5}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 5');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 5}px;"] > .slick-cell:nth(3)`).should('contain', '27 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 5}px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('have.length', 1);
});
it('Should expect an Alert about missing row selection before executing Mass Selection', () => {
const alertStub = cy.stub();
cy.on('window:alert', alertStub);
cy.get('[data-test="mass-selection-button"]')
.click()
.then(() => {
expect(alertStub.getCall(0)).to.be.calledWith(`You must select some rows before trying to apply new value(s)`);
});
});
it('Should select row 2 and 3 and change ', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0)`).click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0)`).click();
cy.get('[data-test="mass-selection-button"]').click();
cy.get('.modal-header > h5').contains('Update on Current Selection');
cy.get('[data-editorid=duration] input')
.type('7');
cy.get('[data-editorid=start] input:visible[type=text]')
.focus()
.type('02/02/2020')
.type('{Enter}');
cy.get('[data-editorid=effort-driven] input')
.click();
cy.get('.modified')
.should('have.length', 3);
cy.get('[data-action="mass-selection"]').click();
});
it('Should expect to see "Duration" of "27 days" and "Effort-Driven" to be enabled accross the entire grid', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 0000');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(3)`).should('contain', '27 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 1');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(3)`).should('contain', '7 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(5)`).should('contain', '02/02/2020');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 2');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(3)`).should('contain', '7 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(5)`).should('contain', '02/02/2020');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 3');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(3)`).should('contain', '27 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 4');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(3)`).should('contain', '27 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 5}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 5');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 5}px;"] > .slick-cell:nth(3)`).should('contain', '27 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 5}px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('have.length', 1);
});
it('Should open a Create Modal window and click on Effort-Driven then expect 3 validation errors', () => {
cy.get('[data-test=create-button]').click();
cy.get('.modal-header > h5').contains('Inserting New Task');
cy.get('[data-editorid=effort-driven] input')
.click();
cy.get('[data-editorid=effort-driven] input')
.click();
cy.get('.modified')
.should('have.length', 1);
cy.get('[data-action=save]').click();
cy.get('.item-details-validation.editor-title')
.should('have.text', 'This is a required field');
cy.get('.item-details-validation.editor-duration')
.should('have.text', 'Duration must be at least 5 days when "Effort-Driven" is enabled');
cy.get('.item-details-validation.editor-percent')
.should('have.text', 'Please enter a valid positive number');
});
it('Should fill in the Create Item form then expect the new data to show up in the grid after Saving', () => {
cy.get('[data-test=create-button]').click();
cy.get('.modal-header > h5').contains('Inserting New Task');
cy.get('[data-editorid=title] input')
.type('Task 8899');
cy.get('[data-editorid=desc] textarea')
.type('random text');
cy.get('[data-editorid=duration] input')
.type('9');
cy.get('[data-editorid=percent] input[type=text]')
.type('44');
cy.get('[data-editorid=start] input:visible[type=text]')
.focus()
.type('02/02/2020')
.type('{Enter}');
cy.get('[data-editorid=effort-driven] input')
.click();
cy.get('[data-editorid=effort-driven] input')
.click();
cy.get('.modified')
.should('have.length', 5);
cy.get('[data-action=save]').click();
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(7);
expect(win.console.log).to.be.calledWith('composite editor input changed', {
description: 'random text', duration: 9, effortDriven: true, start: '02/02/2020', title: 'Task 8899'
});
});
});
it('Should expect to see "Duration" of "27 days" and "Effort-Driven" to be enabled accross the entire grid', () => {
cy.get(`[style="top: 12500px;"] > .slick-cell:nth(1)`).should('contain', 'Task 8899');
cy.get(`[style="top: 12500px;"] > .slick-cell:nth(2)`).should('contain', 'random text');
cy.get(`[style="top: 12500px;"] > .slick-cell:nth(3)`).should('contain', '9 days');
cy.get(`[style="top: 12500px;"] > .slick-cell:nth(4)`).each($cell => {
const htmlText = $cell.html();
expect(htmlText).to.eq('<span class="percent-complete-bar" style="background:silver;width:44%" title="44%"></span>');
});
cy.get(`[style="top: 12500px;"] > .slick-cell:nth(5)`).should('contain', '02/02/2020');
cy.get(`[style="top: 12500px;"] > .slick-cell:nth(6)`).should('contain', '');
cy.get(`[style="top: 12500px;"] > .slick-cell:nth(7)`).find('.sgi-check').should('have.length', 1);
});
});
@@ -0,0 +1,45 @@
describe('Example CSP Header - with Column Span & Header Grouping', () => {
// NOTE: everywhere there's a * 2 is because we have a top+bottom (frozen rows) containers even after Unfreeze Columns/Rows
const GRID_ROW_HEIGHT = 25;
const fullTitles = ['Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
for (let i = 0; i < 30; i++) {
fullTitles.push(`Mock${i}`);
}
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-csp-header.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('CSP header');
});
it('should have exact column titles', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should expect 1st row to be 1 column spanned to the entire width', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('not.exist');
});
it('should expect 2nd row to be 4 columns and not be spanned', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 1');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', '5 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(2)`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(3)`).contains(/(true|false)/);
});
it('should expect 3rd row to be 1 column spanned to the entire width', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 2');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).should('not.exist');
});
it('should expect 4th row to be 4 columns and not be spanned', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 3');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).should('contain', '5 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(2)`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(3)`).contains(/(true|false)/);
});
});
@@ -0,0 +1,211 @@
describe('Example - Draggable Grouping', { retries: 1 }, () => {
// NOTE: everywhere there's a * 2 is because we have a top+bottom (frozen rows) containers even after Unfreeze Columns/Rows
const GRID_ROW_HEIGHT = 25;
const fullTitles = ['#', 'Title', 'Duration', 'Start', 'Finish', 'Cost', 'Effort-Driven'];
for (let i = 0; i < 30; i++) {
fullTitles.push(`Mock${i}`);
}
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-draggable-grouping.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('Draggable Grouping feature');
});
it('should have exact column titles in grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should have 6x draggable icons', () => {
cy.get('.slick-column-groupable')
.should('have.length', 6);
cy.get('.slick-column-groupable.sgi-drag-vertical')
.should('have.length', 6);
});
describe('Grouping Tests', () => {
it('should "Group by Duration & sort groups by value" then Collapse All and expect only group titles', () => {
cy.get('[data-test="add-50k-rows-btn"]').click();
cy.get('[data-test="group-duration-sort-value-btn"]').click();
cy.get('[data-test="collapse-all-btn"]').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 1');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 2');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 3');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 4');
});
it('should click on Expand All columns and expect 1st row as grouping title and 2nd row as a regular row', () => {
cy.get('[data-test="add-50k-rows-btn"]').click();
cy.get('[data-test="group-duration-sort-value-btn"]').click();
cy.get('[data-test="expand-all-btn"]').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', 'Task');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(2)`).should('contain', '0');
});
it('should show 1 column title (Duration) shown in the pre-header section', () => {
cy.get('.slick-dropped-grouping:nth(0) div').contains('Duration');
});
it('should "Group by Duration then Effort-Driven" and expect 1st row to be expanded, 2nd row to be expanded and 3rd row to be a regular row', () => {
cy.get('[data-test="group-duration-effort-btn"]').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"].slick-group-level-1 .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"].slick-group-level-1 .slick-group-title`).should('contain', 'Effort-Driven: False');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).should('contain', 'Task');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(2)`).should('contain', '0');
});
it('should show 2 column titles (Duration, Effort-Driven) shown in the pre-header section', () => {
cy.get('.slick-dropped-grouping:nth(0) div').contains('Duration');
cy.get('.slick-dropped-grouping:nth(1) div').contains('Effort-Driven');
});
it('should be able to drag and swap pre-header grouped column titles (Effort-Driven, Duration)', () => {
cy.get('.slick-dropped-grouping:nth(0) div')
.contains('Duration')
.drag('.slick-dropped-grouping:nth(1) div');
cy.get('.slick-dropped-grouping:nth(0) div').contains('Effort-Driven');
cy.get('.slick-dropped-grouping:nth(1) div').contains('Duration');
});
it('should expect the grouping to be swapped as well in the grid', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: False');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"].slick-group-level-1 .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"].slick-group-level-1 .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).should('contain', 'Task');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(2)`).should('contain', '0');
});
it('should use the preheader Toggle All button and expect all groups to now be collapsed', () => {
cy.get('.slick-preheader-panel .slick-group-toggle-all').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: False');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: True');
});
it('should expand all rows with "Expand All" and expect all the Groups to be expanded and the Toogle All icon to be collapsed', () => {
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.rightclick({ force: true });
cy.get('[data-test="expand-all-btn"]')
.click();
cy.get('#myGrid')
.find('.slick-group-toggle.collapsed')
.should('have.length', 0);
cy.get('#myGrid')
.find('.slick-group-toggle.expanded')
.should(($rows) => expect($rows).to.have.length.greaterThan(0));
cy.get('.slick-group-toggle-all.expanded')
.should('exist');
});
it('should collapse all rows with "Collapse All" and expect all the Groups to be collapsed and the Toogle All icon to be collapsed', () => {
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.rightclick({ force: true });
cy.get('[data-test="collapse-all-btn"]')
.click();
cy.get('#myGrid')
.find('.slick-group-toggle.expanded')
.should('have.length', 0);
cy.get('#myGrid')
.find('.slick-group-toggle.collapsed')
.should(($rows) => expect($rows).to.have.length.greaterThan(0));
cy.get('.slick-group-toggle-all.collapsed')
.should('exist');
});
it('should use the preheader Toggle All button and expect all groups to now be expanded', () => {
cy.get('.slick-preheader-panel .slick-group-toggle-all').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: False');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.expanded`)
.should('have.css', 'marginLeft').and('eq', `0px`);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0) .slick-group-toggle.expanded`)
.should('have.css', 'marginLeft').and('eq', `15px`);
});
it('should use the preheader Toggle All button again and expect all groups to now be collapsed', () => {
cy.get('.slick-preheader-panel .slick-group-toggle-all').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: False');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: True');
});
it('should clear all groups with "Clear all Grouping" and expect all the Groups to be collapsed and the Toogle All icon to be collapsed', () => {
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.rightclick({ force: true });
cy.get('[data-test="clear-grouping-btn"]')
.click();
cy.get('#myGrid')
.find('.slick-group-toggle-all')
.should('be.hidden');
cy.get('#myGrid')
.find('.slick-placeholder')
.should('be.visible')
.should('have.text', 'Drop a column header here to group by the column :)');
});
it('should add 500 items and expect 500 of 500 items displayed', () => {
cy.get('[data-test="add-500-rows-btn"]')
.click();
cy.get('.slick-pager-status')
.contains('Showing all 500 rows');
});
});
describe('Pagination', () => {
it('should be able to destroy pager (pagination)', () => {
cy.get('.slick-pager')
.should('exist');
cy.get('[data-test="destroy-pager"]')
.click();
cy.get('.slick-pager')
.should('not.exist');
});
});
});
@@ -0,0 +1,255 @@
describe('Example - Draggable Grouping', { retries: 1 }, () => {
// NOTE: everywhere there's a * 2 is because we have a top+bottom (frozen rows) containers even after Unfreeze Columns/Rows
const GRID_ROW_HEIGHT = 25;
const preHeaders = ['', 'Common Factor', 'Period', 'Analysis', ''];
const fullTitles = ['#', 'Title', 'Duration', 'Start', 'Finish', 'Cost', 'Effort-Driven'];
for (let i = 0; i < 30; i++) {
fullTitles.push(`Mock${i}`);
}
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-draggable-header-grouping.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('Draggable Grouping feature');
});
it('should have exact column (pre-header) grouping titles in grid', () => {
cy.get('#myGrid')
.find('.slick-preheader-panel .slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(preHeaders[index]));
});
it('should have exact column titles in grid', () => {
cy.get('#myGrid')
.find('.slick-header:not(.slick-preheader-panel) .slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should have 6x draggable icons', () => {
cy.get('.slick-column-groupable')
.should('have.length', 6);
cy.get('.slick-column-groupable.sgi-drag-vertical')
.should('have.length', 6);
});
describe('Grouping Tests', () => {
it('should "Group by Duration & sort groups by value" then Collapse All and expect only group titles', () => {
cy.get('[data-test="add-50k-rows-btn"]').click();
cy.get('[data-test="group-duration-sort-value-btn"]').click();
cy.get('[data-test="collapse-all-btn"]').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 1');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 2');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 3');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 4');
});
it('should click on Expand All columns and expect 1st row as grouping title and 2nd row as a regular row', () => {
cy.get('[data-test="add-50k-rows-btn"]').click();
cy.get('[data-test="group-duration-sort-value-btn"]').click();
cy.get('[data-test="expand-all-btn"]').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', 'Task');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(2)`).should('contain', '0');
});
it('should show 1 column title (Duration) shown in the pre-header section', () => {
cy.get('.slick-dropped-grouping:nth(0) div').contains('Duration');
});
it('should "Group by Duration then Effort-Driven" and expect 1st row to be expanded, 2nd row to be expanded and 3rd row to be a regular row', () => {
cy.get('[data-test="group-duration-effort-btn"]').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"].slick-group-level-1 .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"].slick-group-level-1 .slick-group-title`).should('contain', 'Effort-Driven: False');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).should('contain', 'Task');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(2)`).should('contain', '0');
});
it('should show 2 column titles (Duration, Effort-Driven) shown in the pre-header section', () => {
cy.get('.slick-dropped-grouping:nth(0) div').contains('Duration');
cy.get('.slick-dropped-grouping:nth(1) div').contains('Effort-Driven');
});
it('should be able to drag and swap pre-header grouped column titles (Effort-Driven, Duration)', () => {
cy.get('.slick-dropped-grouping:nth(0) div')
.contains('Duration')
.drag('.slick-dropped-grouping:nth(1) div');
cy.get('.slick-dropped-grouping:nth(0) div').contains('Effort-Driven');
cy.get('.slick-dropped-grouping:nth(1) div').contains('Duration');
});
it('should expect the grouping to be swapped as well in the grid', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: False');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"].slick-group-level-1 .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"].slick-group-level-1 .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).should('contain', 'Task');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(2)`).should('contain', '0');
});
it('should use the topheader Toggle All button and expect all groups to now be collapsed', () => {
cy.get('.slick-topheader-panel .slick-group-toggle-all').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: False');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: True');
});
it('should expand all rows with "Expand All" and expect all the Groups to be expanded and the Toogle All icon to be collapsed', () => {
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.rightclick({ force: true });
cy.get('[data-test="expand-all-btn"]')
.click();
cy.get('#myGrid')
.find('.slick-group-toggle.collapsed')
.should('have.length', 0);
cy.get('#myGrid')
.find('.slick-group-toggle.expanded')
.should(($rows) => expect($rows).to.have.length.greaterThan(0));
cy.get('.slick-group-toggle-all.expanded')
.should('exist');
});
it('should collapse all rows with "Collapse All" and expect all the Groups to be collapsed and the Toogle All icon to be collapsed', () => {
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.rightclick({ force: true });
cy.get('[data-test="collapse-all-btn"]')
.click();
cy.get('#myGrid')
.find('.slick-group-toggle.expanded')
.should('have.length', 0);
cy.get('#myGrid')
.find('.slick-group-toggle.collapsed')
.should(($rows) => expect($rows).to.have.length.greaterThan(0));
cy.get('.slick-group-toggle-all.collapsed')
.should('exist');
});
it('should use the topheader Toggle All button and expect all groups to now be expanded', () => {
cy.get('.slick-topheader-panel .slick-group-toggle-all').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: False');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.expanded`)
.should('have.css', 'marginLeft').and('eq', `0px`);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0) .slick-group-toggle.expanded`)
.should('have.css', 'marginLeft').and('eq', `15px`);
});
it('should use the topheader Toggle All button again and expect all groups to now be collapsed', () => {
cy.get('.slick-topheader-panel .slick-group-toggle-all').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: False');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: True');
});
it('should clear all groups with "Clear all Grouping" and expect all the Groups to be collapsed and the Toogle All icon to be collapsed', () => {
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.rightclick({ force: true });
cy.get('[data-test="clear-grouping-btn"]')
.click();
cy.get('#myGrid')
.find('.slick-group-toggle-all')
.should('be.hidden');
cy.get('#myGrid')
.find('.slick-placeholder')
.should('be.visible')
.should('have.text', 'Drop a column header here to group by the column :)');
});
it('should add 500 items and expect last row to be Task 500', () => {
cy.get('[data-test="add-500-rows-btn"]')
.click();
cy.get('#myGrid')
.find('.slick-viewport-top.slick-viewport-left')
.scrollTo('bottom')
.wait(10);
cy.get(`#myGrid [style="top: ${GRID_ROW_HEIGHT * 499}px;"] > .slick-cell:nth(1)`).should('have.text', 'Task 499');
});
it('should add 50K items and expect last row to be Task 50,000', () => {
cy.get('[data-test="add-50k-rows-btn"]')
.click();
cy.get('#myGrid')
.find('.slick-viewport-top.slick-viewport-left')
.scrollTo('bottom')
.wait(10);
// cy.get(`#myGrid [style="top: ${GRID_ROW_HEIGHT * 49999}px;"] > .slick-cell:nth(1)`).should('have.text', 'Task 49999');
cy.get(`#myGrid [style="top: 1.24998e+06px;"] > .slick-cell:nth(1)`).should('have.text', 'Task 49999');
});
it('should be able to call column picker from the pre-header', () => {
const preHeadersWithoutId = ['Common Factor', 'Period', 'Analysis', ''];
const titlesWithoutId = ['Title', 'Duration', 'Start', 'Finish', 'Cost', 'Effort-Driven'];
cy.get('#myGrid')
.find('.slick-preheader-panel .slick-header-column:nth(1)')
.trigger('mouseover')
.trigger('contextmenu')
.invoke('show');
cy.get('.slick-columnpicker')
.find('.slick-columnpicker-list')
.children()
.each(($child, index) => {
if (index <= 5) {
expect($child.text()).to.eq(fullTitles[index]);
}
});
cy.get('.slick-columnpicker')
.find('.slick-columnpicker-list')
.children('li:nth-child(1)')
.children('label')
.should('contain', '#')
.click();
cy.get('#myGrid')
.find('.slick-preheader-panel .slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(preHeadersWithoutId[index]));
cy.get('#myGrid')
.find('.slick-header:not(.slick-preheader-panel) .slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titlesWithoutId[index]));
});
});
});
@@ -0,0 +1,122 @@
describe('Example 1 - Basic Grid', () => {
const GRID_ROW_HEIGHT = 25;
const fullTitles = ['Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
it('should display Example 1 with Basic Basic', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example1-simple.html`);
cy.get('h2').should('contain', 'Demonstrates:');
cy.contains('basic grid with minimal configuration');
});
it('should have exact Column Titles in grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should resize all columns and make them wider', () => {
// resize EffortDriven column
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(5)')
.should('contain', 'Effort Driven');
cy.get('.slick-resizable-handle:nth(5)')
.trigger('mousedown', { which: 1, force: true, pageX: 500, pageY: 25 })
.trigger('mousemove', { which: 1, force: true, pageX: 600, pageY: 25 })
.trigger('mouseup', { force: true });
// resize Finish column
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(4)')
.should('contain', 'Finish');
cy.get('.slick-resizable-handle:nth(4)')
.trigger('mousedown', { which: 1, force: true })
.trigger('mousemove', 'bottomRight');
cy.get('.slick-header-column:nth(5)')
.trigger('mousemove', 'bottomRight')
.trigger('mouseup', 'bottomRight', { which: 1, force: true });
// resize Start column
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(3)')
.should('contain', 'Start');
cy.get('.slick-resizable-handle:nth(3)')
.trigger('mousedown', { which: 1, force: true })
.trigger('mousemove', 'bottomRight');
cy.get('.slick-header-column:nth(5)')
.trigger('mousemove', 'bottomRight')
.trigger('mouseup', 'bottomRight', { which: 1, force: true });
// resize %Complete column
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(2)')
.should('contain', '% Complete');
cy.get('.slick-resizable-handle:nth(2)')
.trigger('mousedown', { which: 1, force: true })
.trigger('mousemove', 'bottomRight');
cy.get('.slick-header-column:nth(4)')
.trigger('mousemove', 'bottomRight')
.trigger('mouseup', 'bottomRight', { which: 1, force: true });
// resize Duration column
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(1)')
.should('contain', 'Duration');
cy.get('.slick-resizable-handle:nth(1)')
.trigger('mousedown', { which: 1, force: true })
.trigger('mousemove', { which: 1, force: true, pageX: 250, pageY: 25 })
.trigger('mouseup', { force: true });
// resize Title column
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(0)')
.should('contain', 'Title');
cy.get('.slick-resizable-handle:nth(0)')
.trigger('mousedown', { which: 1, force: true })
.trigger('mousemove', { which: 1, force: true, pageX: 80, pageY: 25 })
.trigger('mouseup', { force: true });
});
it('should scroll horizontally completely to the right and expect all cell to be rendered', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l1`).should('contain', '5 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l2`).contains(/[0-9]*/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 15}px;"] > .slick-cell.l1`).should('contain', '5 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 15}px;"] > .slick-cell.l2`).contains(/[0-9]*/);
// scroll to right
cy.get('.slick-viewport-top.slick-viewport-left')
.scrollTo('100%', '0%', { duration: 1500 });
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l3`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l4`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l2`).contains(/[true|false]*/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 15}px;"] > .slick-cell.l3`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 15}px;"] > .slick-cell.l4`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 15}px;"] > .slick-cell.l2`).contains(/[true|false]*/);
});
it('should scroll vertically to the middle of the grid and expect all cell to be rendered', () => {
// scroll to right
cy.get('.slick-viewport-top.slick-viewport-left')
.scrollTo('100%', '40%', { duration: 1500 });
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 195}px;"] > .slick-cell.l3`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 195}px;"] > .slick-cell.l4`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 195}px;"] > .slick-cell.l2`).contains(/[true|false]*/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 210}px;"] > .slick-cell.l3`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 210}px;"] > .slick-cell.l4`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 210}px;"] > .slick-cell.l2`).contains(/[true|false]*/);
});
});
@@ -0,0 +1,31 @@
describe('Example - Excel-compatible spreadsheet and Cell Selection', { retries: 0 }, () => {
const cellHeight = 25;
it('should load Example', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-excel-compatible-spreadsheet.html`);
});
it('should click on cell B2, copy value, ArrowDown, paste value, ArrowRight, and expect to be in column C', () => {
cy.getCell(2, 2, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_B2')
.click();
cy.get('.slick-cell.active')
.realPress(['Control', 'C']);
cy.get('.slick-cell.active')
.type('{downarrow}');
cy.get('.slick-cell.active')
.realPress(['Control', 'V']);
cy.get('.slick-cell.active')
.type('{rightarrow}');
cy.get('#myGrid .slick-cell.l3.r3.selected')
.should('have.length', 1);
cy.getCell(3, 2, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.should('have.text', '3');
});
});
@@ -0,0 +1,141 @@
describe('Example - Row Grouping Titles', () => {
const fullPreTitles = ['', 'Common Factor', 'Period', 'Analysis'];
const fullTitles = ['#', 'Title', 'Duration', 'Start', 'Finish', '% Complete', 'Effort Driven'];
it('should display Example Frozen Columns & Column Group', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-frozen-columns-and-column-group.html`);
cy.get('h2').should('contain', 'Demonstrates:');
cy.contains('Frozen columns with extra header row grouping columns into categories');
});
it('should have exact Column Pre-Header & Column Header Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns:nth(0)')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullPreTitles[index]));
cy.get('#myGrid')
.find('.slick-header-columns:nth(1)')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should have a frozen grid on page load with 3 columns on the left and 4 columns on the right', () => {
cy.get('[style="top: 0px;"]').should('have.length', 2);
cy.get('.grid-canvas-left > [style="top: 0px;"]').children().should('have.length', 3);
cy.get('.grid-canvas-right > [style="top: 0px;"]').children().should('have.length', 4);
cy.get('.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(0)').should('contain', '0');
cy.get('.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', 'Task 0');
cy.get('.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(2)').should('contain', '5 days');
cy.get('.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(0)').should('contain', '01/01/2009');
cy.get('.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', '01/05/2009');
});
it('should have exact Column Pre-Header & Column Header Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns:nth(0)')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullPreTitles[index]));
cy.get('#myGrid')
.find('.slick-header-columns:nth(1)')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should click on the "Remove Frozen Columns" button to switch to a regular grid without frozen columns and expect 7 columns on the left container', () => {
cy.contains('Remove Frozen Columns')
.click({ force: true });
cy.get('[style="top: 0px;"]').should('have.length', 1);
cy.get('.grid-canvas-left > [style="top: 0px;"]').children().should('have.length', 7);
cy.get('.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(0)').should('contain', '0');
cy.get('.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', 'Task 0');
cy.get('.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(2)').should('contain', '5 days');
cy.get('.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(3)').should('contain', '01/01/2009');
cy.get('.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(4)').should('contain', '01/05/2009');
});
it('should have exact Column Pre-Header & Column Header Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns:nth(0)')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullPreTitles[index]));
cy.get('#myGrid')
.find('.slick-header-columns:nth(1)')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should click on the "Set 3 Frozen Columns" button to switch frozen columns grid and expect 3 frozen columns on the left and 4 columns on the right', () => {
cy.contains('Set 3 Frozen Columns')
.click({ force: true });
cy.get('[style="top: 0px;"]').should('have.length', 2);
cy.get('.grid-canvas-left > [style="top: 0px;"]').children().should('have.length', 3);
cy.get('.grid-canvas-right > [style="top: 0px;"]').children().should('have.length', 4);
cy.get('.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(0)').should('contain', '0');
cy.get('.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', 'Task 0');
cy.get('.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(2)').should('contain', '5 days');
cy.get('.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(0)').should('contain', '01/01/2009');
cy.get('.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', '01/05/2009');
});
it('should have exact Column Pre-Header & Column Header Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns:nth(0)')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullPreTitles[index]));
cy.get('#myGrid')
.find('.slick-header-columns:nth(1)')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should be able to call column picker from the pre-header', () => {
const fullPreTitlesWithoutId = ['Common Factor', 'Period', 'Period', 'Analysis'];
const fullTitlesWithoutId = ['Title', 'Duration', 'Start', 'Finish', '% Complete', 'Effort Driven'];
const fullTitlesWithGroup = ['#', 'Common Factor - Title', 'Common Factor - Duration', 'Period - Start', 'Period - Finish', 'Analysis - % Complete', 'Analysis - Effort Driven'];
cy.get('#myGrid')
.find('.slick-preheader-panel .slick-header-column:nth(1)')
.trigger('mouseover')
.trigger('contextmenu')
.invoke('show');
cy.get('.slick-columnpicker')
.find('.slick-columnpicker-list')
.children()
.each(($child, index) => {
if (index <= 6) {
expect($child.text()).to.eq(fullTitlesWithGroup[index]);
}
});
cy.get('.slick-columnpicker')
.find('.slick-columnpicker-list')
.children('li:nth-child(1)')
.children('label')
.should('contain', '#')
.click();
cy.get('.slick-columnpicker > button.close > .close').click();
cy.get('#myGrid')
.find('.slick-preheader-panel .slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullPreTitlesWithoutId[index]));
cy.get('#myGrid')
.find('.slick-header:not(.slick-preheader-panel) .slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitlesWithoutId[index]));
});
});
@@ -0,0 +1,109 @@
describe('Example - Frozen Columns & Rows', { retries: 1 }, () => {
// NOTE: everywhere there's a * 2 is because we have a top+bottom (frozen rows) containers even after Unfreeze Columns/Rows
const fullTitles = ['#', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven', 'Title1', 'Title2', 'Title3', 'Title4'];
it('should load Example', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-frozen-columns-and-rows.html`);
});
it('should have exact column titles on 1st grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should have exact Column Header Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns:nth(0)')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should have a frozen grid with 4 containers on page load with 3 columns on the left and 6 columns on the right', () => {
cy.get('[style="top: 0px;"]').should('have.length', 2 * 2);
cy.get('.grid-canvas-left > [style="top: 0px;"]').children().should('have.length', 3 * 2);
cy.get('.grid-canvas-right > [style="top: 0px;"]').children().should('have.length', 8 * 2);
// top-left
cy.get('.grid-canvas-top.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(0)').should('contain', '');
cy.get('.grid-canvas-top.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', 'Task 0');
// top-right
cy.get('.grid-canvas-top.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', '01/01/2009');
cy.get('.grid-canvas-top.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(2)').should('contain', '01/05/2009');
cy.get('.grid-canvas-top.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(4)').should('contain', '0');
// bottom-left
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', 'Task 5');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="top: 25px;"] > .slick-cell:nth(1)').should('contain', 'Task 6');
// bottom-right
cy.get('.grid-canvas-bottom.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', '01/01/2009');
cy.get('.grid-canvas-bottom.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(2)').should('contain', '01/05/2009');
cy.get('.grid-canvas-bottom.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(4)').should('contain', '5');
cy.get('.grid-canvas-bottom.grid-canvas-right > [style="top: 25px;"] > .slick-cell:nth(4)').should('contain', '6');
});
it('should change frozen row and increment by 1 and expect changes to be reflected in the grid', () => {
cy.get('input#frozenRow').type('{backspace}7');
cy.get('button#setFrozenRow').click();
cy.get('[style="top: 0px;"]').should('have.length', 2 * 2);
cy.get('.grid-canvas-left > [style="top: 0px;"]').children().should('have.length', 3 * 2);
cy.get('.grid-canvas-right > [style="top: 0px;"]').children().should('have.length', 8 * 2);
// top-left
cy.get('.grid-canvas-top.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(0)').should('contain', '');
cy.get('.grid-canvas-top.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', 'Task 0');
// top-right
cy.get('.grid-canvas-top.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', '01/01/2009');
cy.get('.grid-canvas-top.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(2)').should('contain', '01/05/2009');
cy.get('.grid-canvas-top.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(4)').should('contain', '0');
// bottom-left
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', 'Task 7');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="top: 25px;"] > .slick-cell:nth(1)').should('contain', 'Task 8');
// bottom-right
cy.get('.grid-canvas-bottom.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', '01/01/2009');
cy.get('.grid-canvas-bottom.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(2)').should('contain', '01/05/2009');
cy.get('.grid-canvas-bottom.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(4)').should('contain', '7');
cy.get('.grid-canvas-bottom.grid-canvas-right > [style="top: 25px;"] > .slick-cell:nth(4)').should('contain', '8');
});
it('should change frozen column and increment by 1 and expect changes to be reflected in the grid', () => {
cy.get('input#frozenColumn').type('{backspace}3');
cy.get('button#setFrozenColumn').click();
cy.get('[style="top: 0px;"]').should('have.length', 2 * 2);
cy.get('.grid-canvas-left > [style="top: 0px;"]').children().should('have.length', 4 * 2);
cy.get('.grid-canvas-right > [style="top: 0px;"]').children().should('have.length', 7 * 2);
// top-left
cy.get('.grid-canvas-top.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(0)').should('contain', '');
cy.get('.grid-canvas-top.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', 'Task 0');
// top-right
cy.get('.grid-canvas-top.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(0)').should('contain', '01/01/2009');
cy.get('.grid-canvas-top.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', '01/05/2009');
cy.get('.grid-canvas-top.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(3)').should('contain', '0');
// bottom-left
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', 'Task 7');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="top: 25px;"] > .slick-cell:nth(1)').should('contain', 'Task 8');
// bottom-right
cy.get('.grid-canvas-bottom.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(0)').should('contain', '01/01/2009');
cy.get('.grid-canvas-bottom.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(1)').should('contain', '01/05/2009');
cy.get('.grid-canvas-bottom.grid-canvas-right > [style="top: 0px;"] > .slick-cell:nth(3)').should('contain', '7');
cy.get('.grid-canvas-bottom.grid-canvas-right > [style="top: 25px;"] > .slick-cell:nth(3)').should('contain', '8');
});
it('should click on "Select first 10 rows" button and expect first few rows to be selected', () => {
cy.get('button#btnSelectRows').click();
cy.get('.selected').should('have.length', 10 * 11); // 10 rows * 11 columns
});
});
@@ -0,0 +1,92 @@
describe('Example - Frozen Rows', { retries: 1 }, () => {
// NOTE: everywhere there's a * 2 is because we have a top+bottom (frozen rows) containers even after Unfreeze Columns/Rows
const fullTitles = ['#', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven', 'Title1', 'Title2', 'Title3', 'Title4'];
it('should load Example', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-frozen-rows.html`);
});
it('should have exact column titles on 1st grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should have exact Column Header Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns:nth(0)')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should have a frozen grid with 4 containers on page load with 3 columns on the left and 6 columns on the right', () => {
cy.get('[style="transform: translateY(0px);"]').should('have.length', 2); // top + bottom
cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]').children().should('have.length', 11 * 2);
// top-left
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(2)').should('contain', '5 days');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(4)').should('contain', '01/01/2009');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(5)').should('contain', '01/05/2009');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(7)').should('contain', '0');
// bottom-left
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 49995');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(2)').should('contain', '5 days');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(4)').should('contain', '01/01/2009');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(5)').should('contain', '01/05/2009');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(7)').should('contain', '49995');
});
it('should change frozen row and increment by 1 and expect changes to be reflected in the grid', () => {
cy.get('input#frozenRow').type('{backspace}7');
cy.get('button#setFrozenRow').click();
cy.get('[style="transform: translateY(0px);"]').should('have.length', 2); // top + bottom
cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]').children().should('have.length', 11 * 2);
// top-left
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(2)').should('contain', '5 days');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(4)').should('contain', '01/01/2009');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(5)').should('contain', '01/05/2009');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(7)').should('contain', '0');
// bottom-left
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 49993');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(2)').should('contain', '5 days');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(4)').should('contain', '01/01/2009');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(5)').should('contain', '01/05/2009');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(7)').should('contain', '49993');
});
it('should uncheck "frozen bottom rows" and set it', () => {
cy.get('input#frozenBottomRows').uncheck();
cy.get('button#setFrozenBottomRows').click();
cy.get('[style="transform: translateY(0px);"]').should('have.length', 2); // top + bottom
cy.get('.grid-canvas-left > [style="transform: translateY(0px);"]').children().should('have.length', 11 * 2);
// top-left
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 0');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(2)').should('contain', '5 days');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(4)').should('contain', '01/01/2009');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(5)').should('contain', '01/05/2009');
cy.get('.grid-canvas-top.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(7)').should('contain', '0');
// bottom-left
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(0)').should('contain', '');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(1)').should('contain', 'Task 7');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(2)').should('contain', '5 days');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(4)').should('contain', '01/01/2009');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(5)').should('contain', '01/05/2009');
cy.get('.grid-canvas-bottom.grid-canvas-left > [style="transform: translateY(0px);"] > .slick-cell:nth(7)').should('contain', '7');
});
});
@@ -0,0 +1,421 @@
import '@4tw/cypress-drag-drop';
describe('Example - Grid Menu', () => {
const fullTitles = ['', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
beforeEach(() => {
// create a console.log spy for later use
cy.window().then((win) => {
cy.spy(win.console, 'log');
});
});
it('should display Example Grid Menu', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-grid-menu.html`);
cy.get('h2').should('contain', 'Demonstrates:');
cy.contains('This example demonstrates using the Slick.Controls.GridMenu ');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should open the Grid Menu and expect onBeforeMenuShow then onAfterMenuShow to show in the console log', () => {
cy.get('#myGrid')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('Before the Grid Menu is shown');
expect(win.console.log).to.be.calledWith('After the Grid Menu is shown');
});
});
it('should have the Grid Menu already opened and expect a title for "Custom Commands" and for "Columns"', () => {
cy.get('.slick-gridmenu-command-list')
.find('.title')
.contains('Custom Commands');
cy.get('.slick-gridmenu')
.find('.title')
.contains('Columns');
cy.get('#myGrid')
.get('.slick-gridmenu:visible')
.find('span.close')
.click({ force: true });
});
it('should click on the Grid Menu to hide the column "A"', () => {
const expectedTitleList = ['', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']; // without "A"
cy.get('#myGrid')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.get('#myGrid')
.get('.slick-gridmenu:visible')
.find('.slick-gridmenu-list')
.children('li:visible:nth(0)')
.children('label')
.should('contain', 'A')
.click({ force: true });
cy.get('#myGrid')
.get('.slick-gridmenu:visible')
.find('span.close')
.click({ force: true });
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(expectedTitleList[index]));
});
it('should click on the External Grid Menu to show the column "A" as 1st column again', () => {
cy.get('button')
.contains('Grid Menu')
.click({ force: true });
cy.get('#myGrid')
.get('.slick-gridmenu:visible')
.find('.slick-gridmenu-list')
.children('li:visible:nth(0)')
.children('label')
.should('contain', 'A')
.click({ force: true });
cy.get('[data-dismiss=slick-gridmenu]')
.click({ force: true });
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should click on "Help" and expect an Alert to show the Help text', () => {
cy.on('window:alert', (str) => {
expect(str).to.equal(`Command: help`);
});
cy.get('.slick-gridmenu-item')
.contains('Help')
.click({ force: true });
});
it('should toggle Filter Row and expect the row to be hidden', () => {
cy.get('.slick-gridmenu-item')
.contains('Toggle Filter Row')
.click({ force: true });
cy.get('#myGrid')
.find('.slick-pane-left')
.find('.slick-headerrow')
.should('be.hidden');
});
it('should toggle Filter Row and expect the row to be shown again', () => {
cy.get('.slick-gridmenu-item')
.contains('Toggle Filter Row')
.click({ force: true });
cy.get('#myGrid')
.find('.slick-pane-left')
.find('.slick-headerrow')
.should('be.visible');
});
it('should toggle Top Panel and expect the row to show up', () => {
cy.get('.slick-gridmenu-item.italic')
.find('.slick-gridmenu-content.orange')
.contains('Toggle Top Panel')
.click({ force: true });
cy.get('#myGrid')
.find('.slick-pane-left')
.find('.slick-top-panel-scroller')
.should('be.visible');
});
it('should toggle Top Panel and expect the row to be hide', () => {
cy.get('.slick-gridmenu-item')
.contains('Toggle Top Panel')
.click({ force: true });
cy.get('#myGrid')
.find('.slick-pane-left')
.find('.slick-top-panel-scroller')
.should('be.hidden');
});
it('should filter column "#" with value 9 and expect only 1 row in the grid with value 9', () => {
cy.get('.grid-canvas')
.find('.slick-row')
.should('be.visible');
cy.get('#myGrid')
.find('.slick-headerrow-column.l0.r0')
.find('input')
.type('9');
cy.get('#myGrid')
.find('.slick-row')
.should('have.length', 1);
});
it('should open the Grid Menu and click on Clear Filter and expect multiple rows now showing in the grid', () => {
cy.get('#myGrid')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.get('.slick-gridmenu-item')
.find('.slick-gridmenu-content.red')
.contains('Clear Filters')
.click({ force: true });
cy.get('.grid-canvas')
.find('.slick-row')
.should('be.visible');
cy.get('#myGrid')
.find('.slick-row')
.its('length')
.should('be.gt', 1);
});
it('should drag column "A" to be after column "C" and expect this to be reflected in the Grid Menu', () => {
const expectedGridMenuList = ['B', 'C', 'A', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'Force fit columns', 'Synchronous resize']; // without "A"
cy.get('.slick-header-column:nth(1)')
.drag('.slick-header-column:nth(3)');
cy.get('button')
.contains('Grid Menu')
.click({ force: true });
cy.get('#myGrid')
.get('.slick-gridmenu:visible')
.find('.slick-gridmenu-list')
.children('li:visible')
.each(($child, index) => expect($child.text()).to.eq(expectedGridMenuList[index]));
cy.get('#myGrid')
.get('.slick-gridmenu:visible')
.find('span.close')
.click();
});
it('should toggle start filtering and not be able to toggle Filter Row when filters are entered', () => {
cy.get('.slick-gridmenu')
.should('be.hidden');
cy.get('.slick-headerrow-column:nth(2)')
.find('input')
.type('8');
cy.get('#myGrid')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.get('.slick-gridmenu-item.slick-gridmenu-item-disabled')
.contains('Toggle Filter Row')
.should('exist');
cy.get('#myGrid')
.find('.slick-pane-left')
.find('.slick-headerrow')
.should('not.be.hidden');
cy.get('#myGrid')
.get('.slick-gridmenu:visible')
.find('span.close')
.click({ force: true });
});
it('should remove filter and be able to toggle Filter Row', () => {
cy.get('.slick-gridmenu')
.should('be.hidden');
cy.get('.slick-headerrow-column:nth(2)')
.find('input')
.clear();
cy.get('#myGrid')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.get('.slick-gridmenu-item')
.contains('Toggle Filter Row')
.should('be.visible')
.click({ force: true });
cy.get('#myGrid')
.find('.slick-pane-left')
.find('.slick-headerrow')
.should('be.hidden');
});
it('should expect "Clear Sorting" command to become hidden from Grid Menu when disabling feature', () => {
cy.get('#toggle-sorting')
.click();
cy.get('#myGrid')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.get('.slick-gridmenu-item')
.contains('Clear Sorting')
.should('not.be.visible')
.click({ force: true });
});
it('should expect "Clear Sorting" command to become visible agaom in Grid Menu when toggling feature again', () => {
cy.get('#toggle-sorting')
.click();
cy.get('#myGrid')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.get('.slick-gridmenu-item')
.contains('Clear Sorting')
.should('be.visible')
.click({ force: true });
});
it('should be able to open Grid Menu and click on Export->Text and expect alert triggered with Text Export', () => {
const subCommands1 = ['Text', 'Excel'];
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('#myGrid')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.get('.slick-gridmenu.slick-menu-level-0 .slick-gridmenu-command-list')
.find('.slick-gridmenu-item')
.contains('Export')
.click();
cy.get('.slick-gridmenu.slick-menu-level-1 .slick-gridmenu-command-list')
.should('exist')
.find('.slick-gridmenu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
cy.get('.slick-gridmenu.slick-menu-level-1 .slick-gridmenu-command-list')
.find('.slick-gridmenu-item')
.contains('Text')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Exporting as Text'));
});
it('should be able to open Grid Menu and click on Export->Excel->xls and expect alert triggered with Excel (xls) Export', () => {
const subCommands1 = ['Text', 'Excel'];
const subCommands2 = ['Excel (csv)', 'Excel (xls)'];
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('#myGrid')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.get('.slick-gridmenu.slick-menu-level-0 .slick-gridmenu-command-list')
.find('.slick-gridmenu-item')
.contains('Export')
.click();
cy.get('.slick-gridmenu.slick-menu-level-1 .slick-gridmenu-command-list')
.should('exist')
.find('.slick-gridmenu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
cy.get('.slick-submenu').should('have.length', 1);
cy.get('.slick-gridmenu.slick-menu-level-1 .slick-gridmenu-command-list')
.find('.slick-gridmenu-item')
.contains('Excel')
.click();
cy.get('.slick-gridmenu.slick-menu-level-2 .slick-gridmenu-command-list').as('subMenuList2');
cy.get('@subMenuList2')
.find('.slick-menu-title')
.contains('available formats');
cy.get('@subMenuList2')
.should('exist')
.find('.slick-gridmenu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands2[index]));
cy.get('.slick-submenu').should('have.length', 2);
cy.get('.slick-gridmenu.slick-menu-level-2 .slick-gridmenu-command-list')
.find('.slick-gridmenu-item')
.contains('Excel (xls)')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Exporting as Excel (xls)'));
cy.get('.slick-submenu').should('have.length', 0);
});
it('should open Export->Excel context sub-menu then open Feedback->ContactUs sub-menus and expect previous Export menu to no longer exists', () => {
const subCommands1 = ['Text', 'Excel'];
const subCommands2 = ['Request update from supplier', '', 'Contact Us'];
const subCommands2_1 = ['Email us', 'Chat with us', 'Book an appointment'];
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('#myGrid')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.get('.slick-gridmenu.slick-menu-level-0 .slick-gridmenu-command-list')
.find('.slick-gridmenu-item')
.contains('Export')
.click();
cy.get('.slick-gridmenu.slick-menu-level-1 .slick-gridmenu-command-list')
.should('exist')
.find('.slick-gridmenu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
// click different sub-menu
cy.get('.slick-gridmenu.slick-menu-level-0')
.find('.slick-gridmenu-item')
.contains('Feedback')
.should('exist')
.trigger('mouseover'); // mouseover or click should work
cy.get('.slick-submenu').should('have.length', 1);
cy.get('.slick-gridmenu.slick-menu-level-1')
.should('exist')
.find('.slick-gridmenu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands2[index]));
// click on Feedback->ContactUs
cy.get('.slick-gridmenu.slick-menu-level-1.dropleft') // left align
.find('.slick-gridmenu-item')
.contains('Contact Us')
.should('exist')
.click();
cy.get('.slick-submenu').should('have.length', 2);
cy.get('.slick-gridmenu.slick-menu-level-2.dropright') // right align
.should('exist')
.find('.slick-gridmenu-item')
.each(($command, index) => expect($command.text()).to.eq(subCommands2_1[index]));
cy.get('.slick-gridmenu.slick-menu-level-2');
cy.get('.slick-gridmenu.slick-menu-level-2 .slick-gridmenu-command-list')
.find('.slick-gridmenu-item')
.contains('Chat with us')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Command: contact-chat'));
cy.get('.slick-submenu').should('have.length', 0);
});
});
@@ -0,0 +1,81 @@
describe('Example - Grouping & Aggregators (ESM)', { retries: 1 }, () => {
// NOTE: everywhere there's a * 2 is because we have a top+bottom (frozen rows) containers even after Unfreeze Columns/Rows
const GRID_ROW_HEIGHT = 28;
const fullTitles = ['#', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Cost', 'Effort-Driven'];
for (let i = 0; i < 30; i++) {
fullTitles.push(`Mock${i}`);
}
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-grouping-esm.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('Grouping & Aggregator features');
});
it('should have exact column titles on 1st grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
describe('Grouping Tests', () => {
it('should "Group by Duration & sort groups by value" then Collapse All and expect only group titles', () => {
cy.get('[data-test="add-50k-rows-btn"]').click();
cy.get('[data-test="group-duration-sort-value-btn"]').click();
cy.get('[data-test="collapse-all-btn"]').click();
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 1');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 2}px);"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 2');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 3}px);"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 3');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 4}px);"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 4');
});
it('should click on Expand All columns and expect 1st row as grouping title and 2nd row as a regular row', () => {
cy.get('[data-test="add-50k-rows-btn"]').click();
cy.get('[data-test="group-duration-sort-value-btn"]').click();
cy.get('[data-test="expand-all-btn"]').click();
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"] > .slick-cell:nth(1)`).should('contain', 'Task');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"] > .slick-cell:nth(2)`).should('contain', '0');
});
it('should "Group by Duration then Effort-Driven" and expect 1st row to be expanded, 2nd row to be collapsed and 3rd row to have group totals', () => {
cy.get('[data-test="group-duration-effort-btn"]').click();
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"].slick-group-level-1 .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"].slick-group-level-1 .slick-group-title`).should('contain', 'Effort-Driven: False');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 2}px);"].slick-group-level-1 .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 2}px);"].slick-group-level-1 .slick-group-title`).should('contain', 'Effort-Driven: True');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 3}px);"].slick-group-totals.slick-group-level-0 .slick-cell:nth(2)`).should('contain', 'total: 0');
});
it('should "Group by Duration then Effort-Driven then Percent" and expect fist 2 rows to be expanded, 3rd row to be collapsed then 4th row to have group total', () => {
cy.get('[data-test="group-duration-effort-percent-btn"]').click();
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"].slick-group-level-1 .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"].slick-group-level-1 .slick-group-title`).should('contain', 'Effort-Driven: False');
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 2}px);"].slick-group-level-2 .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 2}px);"].slick-group-level-2 .slick-group-title`).contains(/^% Complete: [0-9]/);
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 3}px);"].slick-group-totals.slick-group-level-2 .slick-cell:nth(3)`).contains(/^avg: [0-9]%$/);
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 3}px);"].slick-group-totals.slick-group-level-2`)
.find('.slick-cell:nth(3)').contains('avg: ');
});
});
});
@@ -0,0 +1,81 @@
describe('Example - Grouping & Aggregators', { retries: 1 }, () => {
// NOTE: everywhere there's a * 2 is because we have a top+bottom (frozen rows) containers even after Unfreeze Columns/Rows
const GRID_ROW_HEIGHT = 25;
const fullTitles = ['#', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Cost', 'Effort-Driven'];
for (let i = 0; i < 30; i++) {
fullTitles.push(`Mock${i}`);
}
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-grouping.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('Grouping & Aggregator features');
});
it('should have exact column titles on 1st grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
describe('Grouping Tests', () => {
it('should "Group by Duration & sort groups by value" then Collapse All and expect only group titles', () => {
cy.get('[data-test="add-50k-rows-btn"]').click();
cy.get('[data-test="group-duration-sort-value-btn"]').click();
cy.get('[data-test="collapse-all-btn"]').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 1');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 2');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 3');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 4');
});
it('should click on Expand All columns and expect 1st row as grouping title and 2nd row as a regular row', () => {
cy.get('[data-test="add-50k-rows-btn"]').click();
cy.get('[data-test="group-duration-sort-value-btn"]').click();
cy.get('[data-test="expand-all-btn"]').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', 'Task');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(2)`).should('contain', '0');
});
it('should "Group by Duration then Effort-Driven" and expect 1st row to be expanded, 2nd row to be collapsed and 3rd row to have group totals', () => {
cy.get('[data-test="group-duration-effort-btn"]').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"].slick-group-level-1 .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"].slick-group-level-1 .slick-group-title`).should('contain', 'Effort-Driven: False');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"].slick-group-level-1 .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"].slick-group-level-1 .slick-group-title`).should('contain', 'Effort-Driven: True');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"].slick-group-totals.slick-group-level-0 .slick-cell:nth(2)`).should('contain', 'total: 0');
});
it('should "Group by Duration then Effort-Driven then Percent" and expect fist 2 rows to be expanded, 3rd row to be collapsed then 4th row to have group total', () => {
cy.get('[data-test="group-duration-effort-percent-btn"]').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"].slick-group-level-0 > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"].slick-group-level-1 .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"].slick-group-level-1 .slick-group-title`).should('contain', 'Effort-Driven: False');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"].slick-group-level-2 .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"].slick-group-level-2 .slick-group-title`).contains(/^% Complete: [0-9]/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"].slick-group-totals.slick-group-level-2 .slick-cell:nth(3)`).contains(/^avg: [0-9]%$/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"].slick-group-totals.slick-group-level-2`)
.find('.slick-cell:nth(3)').contains('avg: ');
});
});
});
@@ -0,0 +1,87 @@
describe('Example - Infinite Scroll', () => {
const GRID_ROW_HEIGHT = 25;
const titles = ['#', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-infinite-scroll-esm.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + p').contains('This page demonstrates Infinite Scroll using DataView.');
cy.get('.grid-header > label')
.should('contain', 'SlickGrid - Infinite Scroll');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should expect first row to include "Task 0" and other specific properties', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(2)`).should('contain', '5 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(3) .percent-complete-bar`).should('exist');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(4)`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(5)`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(6)`).find('.sgi.sgi-check').should('have.length', 1);
});
it('should scroll to bottom of the grid and expect next batch of 50 items appended to current dataset for a total of 100 items', () => {
cy.get('[data-test="itemCount"]')
.should('have.text', '50');
cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left')
.scrollTo('bottom');
cy.get('[data-test="itemCount"]')
.should('have.text', '100');
});
it('should scroll to bottom of the grid again and expect 50 more items for a total of now 150 items', () => {
cy.get('[data-test="itemCount"]')
.should('have.text', '100');
cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left')
.scrollTo('bottom');
cy.get('[data-test="itemCount"]')
.should('have.text', '150');
});
it('should disable onSort for data reset and expect same dataset length of 150 items after sorting by Title', () => {
cy.get('[data-test="onsort-off"]').click();
cy.get('[data-id="title"]')
.click();
cy.get('[data-test="itemCount"]')
.should('have.text', '150');
cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left')
.scrollTo('top');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 1');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 10');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 100');
});
it('should enable onSort for data reset and expect dataset to be reset to 50 items after sorting by Title', () => {
cy.get('[data-test="onsort-on"]').click();
cy.get('[data-id="title"]')
.click();
cy.get('[data-test="itemCount"]')
.should('have.text', '50');
cy.get('.slick-viewport.slick-viewport-top.slick-viewport-left')
.scrollTo('top');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 9');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 8');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 7');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 6');
});
});
@@ -0,0 +1,271 @@
describe('Example - Multi Grid on a Page', () => {
const fullTitles = ['Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
it('should display Example Multi-grid Basic', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-multi-grid-basic.html`);
cy.get('h2').should('contain', 'Demonstrates:');
cy.contains('Two basic Grids with minimal configuration');
});
it('should have exact same Column Titles in both grids', () => {
cy.get('#myGrid01')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
cy.get('#myGrid02')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should open the Grid Menu on 1st Grid and expect all Columns to be checked', () => {
let gridUid = '';
cy.get('#myGrid01')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.get('#myGrid01')
.should(($grid) => {
const classes = $grid.prop('className').split(' ');
gridUid = classes.find(className => /slickgrid_.*/.test(className));
expect(gridUid).to.not.be.null;
})
.then(() => {
cy.get(`.slick-gridmenu.${gridUid}`)
.find('.slick-gridmenu-list')
.children('li')
.each(($child, index) => {
if (index <= 5) {
const $input = $child.children('input');
const $label = $child.children('label');
expect($input.prop('checked')).to.eq(true);
expect($label.text()).to.eq(fullTitles[index]);
}
});
});
});
it('should then hide "Title" column from same 1st Grid and expect the column to be removed from 1st Grid', () => {
const newColumnList = ['Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
cy.get('#myGrid01')
.get('.slick-gridmenu:visible')
.find('.slick-gridmenu-list')
.children('li:visible:nth(0)')
.children('label')
.should('contain', 'Title')
.click({ force: true });
cy.get('#myGrid01')
.get('.slick-gridmenu:visible')
.find('span.close')
.click({ force: true });
cy.get('#myGrid01')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(newColumnList[index]));
});
it('should open the Grid Menu off 2nd Grid and expect all Columns to still be all checked', () => {
let gridUid = '';
cy.get('#myGrid02')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.get('#myGrid02')
.should(($grid) => {
const classes = $grid.prop('className').split(' ');
gridUid = classes.find(className => /slickgrid_.*/.test(className));
expect(gridUid).to.not.be.null;
})
.then(() => {
cy.get(`.slick-gridmenu.${gridUid}`)
.find('.slick-gridmenu-list')
.children('li')
.each(($child, index) => {
if (index <= 5) {
const $input = $child.children('input');
const $label = $child.children('label');
expect($input.prop('checked')).to.eq(true);
expect($label.text()).to.eq(fullTitles[index]);
}
});
});
});
it('should then hide "% Complete" column from this same 2nd Grid and expect the column to be removed from 2nd Grid', () => {
const newColumnList = ['Title', 'Duration', 'Start', 'Finish', 'Effort Driven'];
cy.get('#myGrid02')
.get('.slick-gridmenu:visible')
.find('.slick-gridmenu-list')
.children('li:visible:nth(2)')
.children('label')
.should('contain', '% Complete')
.click({ force: true });
cy.get('#myGrid02')
.get('.slick-gridmenu:visible')
.find('span.close')
.click({ force: true });
cy.get('#myGrid02')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(newColumnList[index]));
});
it('should go back to 1st Grid and open its Grid Menu and we expect this grid to stil have the "Title" column be hidden (unchecked)', () => {
cy.get('#myGrid01')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.get('.slick-gridmenu-list')
.children('li')
.each(($child, index) => {
if (index <= 5) {
const $input = $child.children('input');
const $label = $child.children('label');
if ($label.text() === 'Title') {
expect($input.prop('checked')).to.eq(false);
} else {
expect($input.prop('checked')).to.eq(true);
}
expect($label.text()).to.eq(fullTitles[index]);
}
});
});
it('should hide "Start" column from 1st Grid and expect to have 2 hidden columns (Title, Start)', () => {
const newColumnList = ['Duration', '% Complete', 'Finish', 'Effort Driven'];
cy.get('#myGrid01')
.get('.slick-gridmenu:visible')
.find('.slick-gridmenu-list')
.children('li:visible:nth(3)')
.children('label')
.should('contain', 'Start')
.click({ force: true });
cy.get('#myGrid01')
.get('.slick-gridmenu:visible')
.find('span.close')
.click({ force: true });
cy.get('#myGrid01')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(newColumnList[index]));
});
it('should open Column Picker of 2nd Grid and show the "% Complete" column back to visible', () => {
cy.get('#myGrid02')
.find('.slick-header-column')
.first()
.trigger('mouseover')
.trigger('contextmenu')
.invoke('show');
cy.get('.slick-columnpicker')
.find('.slick-columnpicker-list')
.children()
.each(($child, index) => {
if (index <= 5) {
expect($child.text()).to.eq(fullTitles[index]);
}
});
cy.get('.slick-columnpicker')
.find('.slick-columnpicker-list')
.children('li:nth-child(3)')
.children('label')
.should('contain', '% Complete')
.click();
cy.get('#myGrid02')
.find('.slick-header-columns')
.children()
.each(($child, index) => {
if (index <= 5) {
expect($child.text()).to.eq(fullTitles[index]);
}
});
cy.get('#myGrid02')
.get('.slick-columnpicker:visible')
.find('span.close')
.trigger('click')
.click();
});
it('should open the Grid Menu on 2nd Grid and expect all Columns to be checked', () => {
let gridUid = '';
cy.get('#myGrid02')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.get('#myGrid02')
.should(($grid) => {
const classes = $grid.prop('className').split(' ');
gridUid = classes.find(className => /slickgrid_.*/.test(className));
expect(gridUid).to.not.be.null;
})
.then(() => {
cy.get(`.slick-gridmenu.${gridUid}`)
.find('.slick-gridmenu-list')
.children('li')
.each(($child, index) => {
if (index <= 5) {
const $input = $child.children('input');
const $label = $child.children('label');
expect($input.prop('checked')).to.eq(true);
expect($label.text()).to.eq(fullTitles[index]);
}
});
});
});
it('should still expect 1st Grid to be unchanged from previous state and still have only 4 columns shown', () => {
const newColumnList = ['Duration', '% Complete', 'Finish', 'Effort Driven'];
cy.get('#myGrid01')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(newColumnList[index]));
});
it('should open the Grid Menu on 1st Grid and also expect to only have 4 columns checked (visible)', () => {
let gridUid = '';
cy.get('#myGrid01')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.get('#myGrid01')
.should(($grid) => {
const classes = $grid.prop('className').split(' ');
gridUid = classes.find(className => /slickgrid_.*/.test(className));
expect(gridUid).to.not.be.null;
})
.then(() => {
cy.get(`.slick-gridmenu.${gridUid}`)
.find('.slick-gridmenu-list')
.children('li')
.each(($child, index) => {
if (index <= 5) {
const $input = $child.children('input');
const $label = $child.children('label');
if ($label.text() === 'Title' || $label.text() === 'Start') {
expect($input.prop('checked')).to.eq(false);
} else {
expect($input.prop('checked')).to.eq(true);
}
expect($label.text()).to.eq(fullTitles[index]);
}
});
});
cy.get('#myGrid01')
.get('.slick-gridmenu:visible')
.find('span.close')
.click({ force: true });
});
});
@@ -0,0 +1,91 @@
describe('Example - Optimizing Updates', () => {
const titles = ['#', 'Severity', 'Time', 'Message'];
it('should display Example Multi-grid Basic', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-optimizing-updates.html`);
cy.get('h2').should('contain', 'Demonstrates:');
cy.contains('This page demonstrates how the bulk update operations ');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should show initial rows', () => {
cy.get('#pager')
.find('.slick-pager-status')
.should('contain', 'Showing all 300 rows');
});
it('should update the rows on inefficient click', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-optimizing-updates.html`);
cy.get('#myGrid')
.find('.slick-row')
.each(($child) => {
const message = $child.find('.cell-message').text();
const number = parseInt(message.substring('Log Entry '.length));
expect(number).to.be.lessThan(1000);
});
cy.get('.options-panel button')
.contains('inefficient')
.click();
cy.get('#myGrid')
.find('.slick-row')
.each(($child) => {
const message = $child.find('.cell-message').text();
const number = parseInt(message.substring('Log Entry '.length));
expect(number).to.be.greaterThan(90000);
});
});
it('should update the rows on efficient click', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-optimizing-updates.html`);
cy.get('#myGrid')
.find('.slick-row')
.each(($child) => {
const message = $child.find('.cell-message').text();
const number = parseInt(message.substring('Log Entry '.length));
expect(number).to.be.lessThan(1000);
});
cy.get('.options-panel button')
.contains('efficient')
.click();
cy.get('#myGrid')
.find('.slick-row')
.each(($child) => {
const message = $child.find('.cell-message').text();
const number = parseInt(message.substring('Log Entry '.length));
expect(number).to.be.greaterThan(90000);
});
});
it('should need less time on efficient than inefficient', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-optimizing-updates.html`);
cy.get('#duration').invoke('text', '').should('be.empty');
cy.get('.options-panel button')
.contains('(inefficient)')
.click();
cy.get('#duration').should('not.be.empty').then($duration => {
const inEfficientTime = parseInt($duration.text());
cy.get('#duration').invoke('text', '').should('be.empty');
cy.get('.options-panel button')
.contains('(efficient)')
.click();
cy.get('#duration').should('not.be.empty').then($duration2 => {
const efficientTime = parseInt($duration2.text());
expect(efficientTime).to.be.lessThan(inEfficientTime / 2);
});
});
});
});
@@ -0,0 +1,918 @@
describe('Example - Context Menu & Cell Menu', () => {
const fullTitles = ['#', 'Title', '% Complete', 'Start', 'Finish', 'Priority', 'Effort Driven', 'Action'];
beforeEach(() => {
// create a console.log spy for later use
cy.window().then((win) => {
cy.spy(win.console, 'log');
});
});
it('should display Example Context Menu & Cell Menu', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-plugin-contextmenu.html`);
cy.get('h2').should('contain', 'Demonstrates:');
cy.get('h2 span').should('contain', 'Slick.Plugins.ContextMenu / Slick.Plugins.CellMenu');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should have first row with "Task 0" and a Priority set to "Low" with the Action cell disabled and not clickable', () => {
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.contains('Task 0');
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(5)')
.contains('Low');
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(6) .sgi-check')
.should('exist');
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7) .disabled')
.contains('Action');
cy.get('.slick-cell-menu')
.should('not.exist');
});
it('should open the Context Menu and expect onBeforeMenuShow then onAfterMenuShow to show in the console log', () => {
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.contains('Task 0');
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.rightclick();
cy.get('.slick-context-menu-command-list')
.should('exist');
cy.get('.slick-context-menu-option-list')
.should('not.exist');
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('Before the global Context Menu is shown');
expect(win.console.log).to.be.calledWith('After the Context Menu is shown');
});
});
it('should expect the Context Menu to not have the "Help" menu when there is Effort Driven set to True', () => {
const commands = ['Copy Cell Value', 'Delete Row', '', 'Command (always disabled)', '', 'Export', 'Feedback'];
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.contains('Task 0');
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.rightclick();
cy.get('.slick-context-menu.dropright .slick-context-menu-command-list')
.find('.slick-context-menu-item')
.each(($command, index) => {
expect($command.text()).to.contain(commands[index]);
expect($command.text()).not.include('Help');
});
});
it('should expect the Context Menu to not have the "Help" menu when there is Effort Driven set to True', () => {
const commands = ['Copy Cell Value', 'Delete Row', '', 'Command (always disabled)', '', 'Export', 'Feedback'];
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.contains('Task 0');
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.rightclick();
cy.get('.slick-context-menu.dropright .slick-context-menu-command-list')
.find('.slick-context-menu-item')
.each(($command, index) => {
expect($command.text()).to.contain(commands[index]);
expect($command.text()).not.include('Help');
});
});
it('should be able to click on the Context Menu (x) close button, on top right corner, to close the menu', () => {
cy.get('.slick-context-menu.dropright')
.should('exist');
cy.get('.slick-context-menu button.close')
.click();
});
it('should change "Task 0" Priority to "High" with Context Menu and expect the Action Menu to become clickable and usable', () => {
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.contains('Task 0');
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(5)')
.rightclick();
cy.get('.slick-context-menu-command-list')
.should('not.exist');
cy.get('.slick-context-menu-option-list')
.should('exist');
cy.get('.slick-context-menu .slick-context-menu-option-list')
.contains('High')
.click();
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu.dropleft')
.should('exist');
});
it('should expect a "Command 2" to be disabled and not clickable (menu will remain open), in that same Action menu', () => {
cy.get('.slick-cell-menu .slick-cell-menu-item.slick-cell-menu-item-disabled')
.contains('Command 2')
.click({ force: true });
cy.get('.slick-cell-menu.dropleft')
.should('exist');
});
it('should change the Effort Driven to "False" in that same Action and then expect the "Command 2" to be enabled and clickable', () => {
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('.slick-cell-menu.slick-menu-level-0 .slick-cell-menu-option-list')
.find('.slick-cell-menu-item')
.contains('False')
.click();
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu .slick-cell-menu-item')
.contains('Command 2')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Command 2'));
});
it('should change the Effort Driven to "True" by using sub-options in that same Action and then expect the "Command 2" to be disabled and not clickable and "Delete Row" to not be shown', () => {
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu.slick-menu-level-0 .slick-cell-menu-option-list')
.find('.slick-cell-menu-item')
.contains('Sub-Options')
.click();
cy.get('.slick-cell-menu.slick-menu-level-1 .slick-cell-menu-option-list').as('subMenuList');
cy.get('@subMenuList')
.find('.slick-menu-title')
.contains('Set Effort Driven');
cy.get('@subMenuList')
.find('.slick-cell-menu-item')
.contains('True')
.click();
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu .slick-cell-menu-item.slick-cell-menu-item-disabled')
.contains('Command 2');
cy.get('.slick-cell-menu .slick-cell-menu-item')
.contains('Delete Row')
.should('not.exist');
});
it('should change the Effort Driven back to "False" by using sub-options in that same Action and then expect the "Command 2" to enabled and clickable and also show "Delete Row" command', () => {
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu.slick-menu-level-0 .slick-cell-menu-option-list')
.find('.slick-cell-menu-item')
.contains('Sub-Options')
.click();
cy.get('.slick-cell-menu.slick-menu-level-1 .slick-cell-menu-option-list')
.find('.slick-cell-menu-item')
.contains('False')
.click();
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu .slick-cell-menu-item')
.contains('Delete Row')
.should('exist');
cy.get('.slick-cell-menu .slick-cell-menu-item')
.contains('Command 2')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Command 2'));
});
it('should expect the Context Menu now have the "Help" menu when Effort Driven is set to False', () => {
const commands = ['Copy Cell Value', 'Delete Row', '', 'Help', 'Command (always disabled)', '', 'Export', 'Feedback'];
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.contains('Task 0');
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(6)')
.rightclick();
cy.get('.slick-context-menu.dropleft .slick-context-menu-command-list')
.find('.slick-context-menu-item')
.each(($command, index) => expect($command.text()).to.contain(commands[index]));
cy.get('.slick-context-menu button.close')
.click();
});
it('should open the Cell Menu and expect onBeforeMenuShow then onAfterMenuShow to show in the console log', () => {
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu.dropleft')
.should('exist');
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('Before the Cell Menu is shown');
expect(win.console.log).to.be.calledWith('After the Cell Menu is shown');
});
});
it('should be able to click on the Action Cell Menu (x) close button, on top right corner, to close the menu', () => {
cy.get('.slick-cell-menu.dropleft')
.should('exist');
cy.get('.slick-cell-menu button.close')
.click();
cy.get('.slick-cell-menu.dropleft')
.should('not.exist');
});
it('should be able to open Cell Menu and click on Export->Text sub-commands to see 1 cell menu + 1 sub-menu then clicking on Text should call alert action', () => {
const subCommands = ['Text', 'Excel'];
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu.slick-menu-level-0 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Export')
.trigger('mouseover'); // mouseover or click should work
cy.get('.slick-cell-menu.slick-menu-level-1 .slick-cell-menu-command-list')
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.eq(subCommands[index]));
cy.get('.slick-cell-menu.slick-menu-level-1 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Text')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Exporting as Text'));
});
it('should be able to open Cell Menu and click on Export->Text and expect alert triggered with Text Export', () => {
const subCommands1 = ['Text', 'Excel'];
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu.slick-menu-level-0 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Export')
.click();
cy.get('.slick-cell-menu.slick-menu-level-1 .slick-cell-menu-command-list')
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
cy.get('.slick-cell-menu.slick-menu-level-1 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Text')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Exporting as Text'));
});
it('should be able to open Cell Menu and click on Export->Excel-> sub-commands to see 1 cell menu + 1 sub-menu then clicking on Text should call alert action', () => {
const subCommands1 = ['Text', 'Excel'];
const subCommands2 = ['Excel (csv)', 'Excel (xls)'];
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu.slick-menu-level-0 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Export')
.click();
cy.get('.slick-cell-menu.slick-menu-level-1 .slick-cell-menu-command-list')
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.eq(subCommands1[index]));
cy.get('.slick-cell-menu.slick-menu-level-1 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Excel')
.click();
cy.get('.slick-cell-menu.slick-menu-level-2 .slick-cell-menu-command-list').as('subMenuList2');
cy.get('@subMenuList2')
.find('.slick-menu-title')
.contains('available formats');
cy.get('@subMenuList2')
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.eq(subCommands2[index]));
cy.get('.slick-cell-menu.slick-menu-level-2 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Excel (xls)')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Exporting as Excel (xls)'));
});
it('should open Export->Excel sub-menu & open again Sub-Options on top and expect sub-menu to be recreated with that Sub-Options list instead of the Export->Excel list', () => {
const subCommands1 = ['Text', 'Excel'];
const subCommands2 = ['Excel (csv)', 'Excel (xls)'];
const subOptions = ['True', 'False'];
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu.slick-menu-level-0 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Export')
.click();
cy.get('.slick-cell-menu.slick-menu-level-1 .slick-cell-menu-command-list')
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.eq(subCommands1[index]));
cy.get('.slick-cell-menu.slick-menu-level-1 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Excel')
.click();
cy.get('.slick-cell-menu.slick-menu-level-2 .slick-cell-menu-command-list')
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.eq(subCommands2[index]));
cy.get('.slick-cell-menu.slick-menu-level-0 .slick-cell-menu-option-list')
.find('.slick-cell-menu-item')
.contains('Sub-Options')
.click();
cy.get('.slick-cell-menu.slick-menu-level-1 .slick-cell-menu-option-list').as('optionSubList2');
cy.get('@optionSubList2')
.find('.slick-menu-title')
.contains('Set Effort Driven');
cy.get('@optionSubList2')
.should('exist')
.find('.slick-cell-menu-item')
.each(($option, index) => expect($option.text()).to.eq(subOptions[index]));
});
it('should open Export->Excel sub-menu then open Feedback->ContactUs sub-menus and expect previous Export menu to no longer exists', () => {
const subCommands1 = ['Text', 'Excel'];
const subCommands2 = ['Request update from supplier', '', 'Contact Us'];
const subCommands2_1 = ['Email us', 'Chat with us', 'Book an appointment'];
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu.slick-menu-level-0 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Export')
.click();
cy.get('.slick-cell-menu.slick-menu-level-1 .slick-cell-menu-command-list')
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
// click different sub-menu
cy.get('.slick-cell-menu.slick-menu-level-0')
.find('.slick-cell-menu-item')
.contains('Feedback')
.should('exist')
.trigger('mouseover'); // mouseover or click should work
cy.get('.slick-submenu').should('have.length', 1);
cy.get('.slick-cell-menu.slick-menu-level-1')
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands2[index]));
// click on Feedback->ContactUs
cy.get('.slick-cell-menu.slick-menu-level-1.dropleft') // left align
.find('.slick-cell-menu-item')
.contains('Contact Us')
.should('exist')
.click();
cy.get('.slick-submenu').should('have.length', 2);
cy.get('.slick-cell-menu.slick-menu-level-2.dropright') // right align
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.eq(subCommands2_1[index]));
cy.get('.slick-cell-menu.slick-menu-level-2');
cy.get('.slick-cell-menu.slick-menu-level-2 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Chat with us')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Command: contact-chat'));
});
it('should click on the "Show Commands & Priority Options" button and see both list when opening Context Menu', () => {
cy.get('button')
.contains('Show Commands & Priority Options')
.click();
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(5)')
.rightclick();
cy.get('.slick-context-menu .slick-context-menu-option-list')
.should('exist')
.contains('High');
cy.get('.slick-context-menu-command-list')
.find('.slick-context-menu-item.bold')
.find('.slick-context-menu-content.red')
.should('exist')
.contains('Delete Row');
cy.get('.slick-context-menu button.close')
.click();
});
it('should click on the "Show Priority Options Only" button and see both list when opening Context Menu & selecting "Medium" option should be reflected in the grid cell and expect "Action" cell menu to be disabled', () => {
cy.get('button')
.contains('Show Priority Options Only')
.click();
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(5)')
.rightclick();
cy.get('.slick-context-menu-command-list')
.should('not.exist');
cy.get('.slick-context-menu .slick-context-menu-option-list')
.should('exist')
.contains('Medium')
.click();
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(5)')
.contains('Medium');
cy.get('.slick-row .slick-cell:nth(7)')
.find('.cell-menu-dropdown.disabled')
.should('exist');
});
it('should reopen Context Menu then select "High" option from sub-menu and expect "Action" cell menu to be reenabled', () => {
const subOptions = ['Low', 'Medium', 'High'];
cy.get('button')
.contains('Show Priority Options Only')
.click();
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(5)')
.rightclick();
cy.get('.slick-context-menu.slick-menu-level-0 .slick-context-menu-option-list')
.find('.slick-context-menu-item')
.contains('Sub-Options (demo)')
.click();
cy.get('.slick-context-menu.slick-menu-level-1 .slick-context-menu-option-list').as('subMenuList');
cy.get('@subMenuList')
.find('.slick-menu-title')
.contains('Set Priority');
cy.get('@subMenuList')
.should('exist')
.find('.slick-context-menu-item')
.each(($command, index) => expect($command.text()).to.eq(subOptions[index]));
cy.get('@subMenuList')
.find('.slick-context-menu-item')
.contains('High')
.click();
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(5)')
.contains('High');
cy.get('.slick-row .slick-cell:nth(7)')
.find('.cell-menu-dropdown.disabled')
.should('not.exist');
});
it('should click on the "Show Actions Commands & Effort Options" button and see both list when opening Action Cell Menu', () => {
cy.get('button')
.contains('Show Actions Commands & Effort Options')
.click();
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu .slick-cell-menu-option-list')
.should('exist')
.contains('True');
cy.get('.slick-cell-menu-command-list')
.should('exist')
.contains('Delete Row');
cy.get('.slick-cell-menu button.close')
.click();
});
it('should open the Action Cell Menu and expect the Effort Driven "null" option when this Effort is set to False', () => {
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu.dropleft')
.should('exist');
cy.get('.slick-cell-menu')
.find('.slick-cell-menu-option-list')
.find('.slick-cell-menu-content.italic')
.contains('null');
});
it('should open the Action Cell Menu and not expect the Effort Driven "null" option when this Effort is set to True', () => {
cy.get('.slick-cell-menu.dropleft')
.should('exist');
cy.get('.slick-cell-menu')
.find('.slick-cell-menu-option-list')
.contains('True')
.click();
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu')
.each($row => {
expect($row.text()).not.include('null');
});
});
it('should reset Effort Driven to False for the next test to include all commands', () => {
cy.get('.slick-cell-menu')
.find('.slick-cell-menu-option-list')
.contains('False')
.click();
});
it('should click on the "Show Action Commands Only" button and see both list when opening Cell Menu', () => {
const commands = ['Command 1', 'Command 2', 'Delete Row', '', 'Help', 'Disabled Command', '', 'Export', 'Feedback'];
cy.get('button')
.contains('Show Action Commands Only')
.click();
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu .slick-cell-menu-command-list')
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.eq(commands[index]));
cy.get('.slick-cell-menu-option-list')
.should('not.exist');
cy.get('.slick-cell-menu button.close')
.click();
});
it('should be able to delete first row by using the "Delete Row" command from the Context Menu', () => {
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.contains('Task 0');
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.rightclick();
cy.get('.slick-context-menu .slick-context-menu-command-list')
.find('.slick-context-menu-item.bold')
.find('.slick-context-menu-content.red')
.should('exist')
.contains('Delete Row')
.click();
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.each($row => {
expect($row.text()).not.include('Task 0');
});
});
it('should be able to delete the 3rd row "Task 3" by using the "Delete Row" command from the Action Cell Menu', () => {
cy.get('#myGrid')
.find('.slick-row:nth(2) .slick-cell:nth(1)')
.contains('Task 3');
cy.get('#myGrid')
.find('.slick-row:nth(2) .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });
cy.get('.slick-cell-menu .slick-cell-menu-command-list')
.find('.slick-cell-menu-item.bold')
.find('.slick-cell-menu-content.red')
.should('exist')
.contains('Delete Row')
.click();
cy.get('#myGrid')
.find('.slick-row:nth(2) .slick-cell:nth(1)')
.each($row => {
expect($row.text()).not.include('Task 3');
});
});
it('should check Context Menu "menuUsabilityOverride" condition and expect to not be able to open Context Menu from rows than are >= to Task 21', () => {
cy.get('#myGrid')
.find('.slick-row:nth(21) .slick-cell:nth(1)')
.rightclick();
cy.get('.slick-context-menu .slick-context-menu-command-list')
.should('not.exist');
});
it('should scroll back to top row and be able to open Context Menu', () => {
cy.get('.slick-viewport-top.slick-viewport-left')
.scrollTo('top')
.wait(10);
cy.get('#myGrid')
.find('.slick-row:nth(1) .slick-cell:nth(1)')
.rightclick();
cy.get('.slick-context-menu .slick-context-menu-command-list')
.should('exist');
cy.get('.slick-context-menu button.close')
.click();
});
it('should be able to open Context Menu and click on Export->Text and expect alert triggered with Text Export', () => {
const subCommands1 = ['Text', 'Excel'];
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.rightclick();
cy.get('.slick-context-menu.slick-menu-level-0 .slick-context-menu-command-list')
.find('.slick-context-menu-item')
.contains('Export')
.click();
cy.get('.slick-context-menu.slick-menu-level-1 .slick-context-menu-command-list')
.should('exist')
.find('.slick-context-menu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
cy.get('.slick-context-menu.slick-menu-level-1 .slick-context-menu-command-list')
.find('.slick-context-menu-item')
.contains('Text')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Exporting as Text'));
});
it('should be able to open Context Menu and click on Export->Excel-> sub-commands to see 1 context menu + 1 sub-menu then clicking on Text should call alert action', () => {
const subCommands1 = ['Text', 'Excel'];
const subCommands2 = ['Excel (csv)', 'Excel (xls)'];
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.rightclick();
cy.get('.slick-context-menu.slick-menu-level-0 .slick-context-menu-command-list')
.find('.slick-context-menu-item')
.contains('Export')
.click();
cy.get('.slick-context-menu.slick-menu-level-1 .slick-context-menu-command-list')
.should('exist')
.find('.slick-context-menu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
cy.get('.slick-context-menu.slick-menu-level-1 .slick-context-menu-command-list')
.find('.slick-context-menu-item')
.contains('Excel')
.click();
cy.get('.slick-context-menu.slick-menu-level-2 .slick-context-menu-command-list').as('subMenuList2');
cy.get('@subMenuList2')
.find('.slick-menu-title')
.contains('available formats');
cy.get('@subMenuList2')
.should('exist')
.find('.slick-context-menu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands2[index]));
cy.get('.slick-context-menu.slick-menu-level-2 .slick-context-menu-command-list')
.find('.slick-context-menu-item')
.contains('Excel (xls)')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Exporting as Excel (xls)'));
});
it('should open Export->Excel sub-menu & open again Sub-Options on top and expect sub-menu to be recreated with that Sub-Options list instead of the Export->Excel list', () => {
const subCommands1 = ['Text', 'Excel'];
const subCommands2 = ['Excel (csv)', 'Excel (xls)'];
const subOptions = ['Low', 'Medium', 'High'];
cy.get('button')
.contains('Show Commands & Priority Options')
.click();
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(5)')
.rightclick();
cy.get('.slick-context-menu.slick-menu-level-0 .slick-context-menu-command-list')
.find('.slick-context-menu-item')
.contains('Export')
.click();
cy.get('.slick-context-menu.slick-menu-level-1 .slick-context-menu-command-list')
.should('exist')
.find('.slick-context-menu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
cy.get('.slick-context-menu.slick-menu-level-1 .slick-context-menu-command-list')
.find('.slick-context-menu-item')
.contains('Excel')
.click();
cy.get('.slick-context-menu.slick-menu-level-2 .slick-context-menu-command-list')
.should('exist')
.find('.slick-context-menu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands2[index]));
cy.get('.slick-context-menu.slick-menu-level-0 .slick-context-menu-option-list')
.find('.slick-context-menu-item')
.contains('Sub-Options')
.click();
cy.get('.slick-context-menu.slick-menu-level-1 .slick-context-menu-option-list').as('optionSubList2');
cy.get('@optionSubList2')
.find('.slick-menu-title')
.contains('Set Priority');
cy.get('@optionSubList2')
.should('exist')
.find('.slick-context-menu-item')
.each(($option, index) => expect($option.text()).to.contain(subOptions[index]));
});
it('should open Export->Excel context sub-menu then open Feedback->ContactUs sub-menus and expect previous Export menu to no longer exists', () => {
const subCommands1 = ['Text', 'Excel'];
const subCommands2 = ['Request update from supplier', '', 'Contact Us'];
const subCommands2_1 = ['Email us', 'Chat with us', 'Book an appointment'];
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(2)')
.rightclick();
cy.get('.slick-context-menu.slick-menu-level-0 .slick-context-menu-command-list')
.find('.slick-context-menu-item')
.contains('Export')
.click();
cy.get('.slick-context-menu.slick-menu-level-1 .slick-context-menu-command-list')
.should('exist')
.find('.slick-context-menu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands1[index]));
// click different sub-menu
cy.get('.slick-context-menu.slick-menu-level-0')
.find('.slick-context-menu-item')
.contains('Feedback')
.should('exist')
.trigger('mouseover'); // mouseover or click should work
cy.get('.slick-submenu').should('have.length', 1);
cy.get('.slick-context-menu.slick-menu-level-1')
.should('exist')
.find('.slick-context-menu-item')
.each(($command, index) => expect($command.text()).to.contain(subCommands2[index]));
// click on Feedback->ContactUs
cy.get('.slick-context-menu.slick-menu-level-1.dropright') // right align
.find('.slick-context-menu-item')
.contains('Contact Us')
.should('exist')
.click();
cy.get('.slick-submenu').should('have.length', 2);
cy.get('.slick-context-menu.slick-menu-level-2.dropleft') // left align
.should('exist')
.find('.slick-context-menu-item')
.each(($command, index) => expect($command.text()).to.eq(subCommands2_1[index]));
cy.get('.slick-context-menu.slick-menu-level-2');
cy.get('.slick-context-menu.slick-menu-level-2 .slick-context-menu-command-list')
.find('.slick-context-menu-item')
.contains('Chat with us')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Command: contact-chat'));
cy.get('.slick-submenu').should('have.length', 0);
});
});
@@ -0,0 +1,182 @@
describe('Example - Custom Tooltip', () => {
const GRID_ROW_HEIGHT = 25;
const titles = ['', 'Title', 'Description', 'Description 2', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-plugin-custom-tooltip.html`);
cy.get('h2').contains('Demonstrates: Slick.Plugins.CustomTooltip');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should change server delay to 10ms for faster testing', () => {
cy.get('#server-delay').type('{backspace}{backspace}{backspace}10');
cy.get('#set-delay-btn').click();
});
it('should mouse over 1st row checkbox column and NOT expect any tooltip to show since it is disabled on that column', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`).as('checkbox0-cell');
cy.get('@checkbox0-cell').trigger('mouseover');
cy.get('.slick-custom-tooltip').should('not.exist');
cy.get('@checkbox0-cell').trigger('mouseout');
});
it('should mouse over Task 1 cell and expect async tooltip to show', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).as('task1-cell');
cy.get('@task1-cell').should('contain', 'Task 1');
cy.get('@task1-cell').trigger('mouseover');
cy.get('.slick-custom-tooltip').contains('loading...');
cy.wait(10);
cy.get('.slick-custom-tooltip').should('be.visible');
cy.get('.slick-custom-tooltip').contains('Task 1 - (async tooltip)');
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
cy.get('.tooltip-2cols-row:nth(2)').find('div:nth(0)').contains('Ratio:');
cy.get('.tooltip-2cols-row:nth(2)').find('div:nth(1)').contains(/\d+$/); // use regexp to make sure it's a number
cy.get('@task1-cell').trigger('mouseout');
});
it('should mouse over Task 5 cell and expect async tooltip to show', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 5}px;"] > .slick-cell:nth(1)`).as('task5-cell');
cy.get('@task5-cell').should('contain', 'Task 5');
cy.get('@task5-cell').trigger('mouseover');
cy.get('.slick-custom-tooltip').contains('loading...');
cy.wait(10);
cy.get('.slick-custom-tooltip').should('be.visible');
cy.get('.slick-custom-tooltip').contains('Task 5 - (async tooltip)');
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
cy.get('.tooltip-2cols-row:nth(2)').find('div:nth(0)').contains('Ratio:');
cy.get('.tooltip-2cols-row:nth(2)').find('div:nth(1)').contains(/\d+$/); // use regexp to make sure it's a number
cy.get('@task5-cell').trigger('mouseout');
});
it('should mouse over 6th row Description and expect full cell content to show in a tooltip because cell has ellipsis and is too long for the cell itself', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 5}px;"] > .slick-cell:nth(2)`).as('desc5-cell');
cy.get('@desc5-cell').should('contain', 'This is a sample task description.');
cy.get('@desc5-cell').trigger('mouseover');
cy.get('.slick-custom-tooltip').should('be.visible');
cy.get('.slick-custom-tooltip').should('not.contain', `regular tooltip (from title attribute)\nTask 5 cell value:\nThis is a sample task description.\nIt can be multiline\n\nAnother line...`);
cy.get('.slick-custom-tooltip').should('contain', `This is a sample task description.\nIt can be multiline\n\nAnother line...`);
cy.get('@desc5-cell').trigger('mouseout');
});
it('should mouse over 6th row Description 2 and expect regular tooltip title + concatenated full cell content when using "useRegularTooltipFromFormatterOnly: true"', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 5}px;"] > .slick-cell:nth(3)`).as('desc2-5-cell');
cy.get('@desc2-5-cell').should('contain', 'This is a sample task description.');
cy.get('@desc2-5-cell').trigger('mouseover');
cy.get('.slick-custom-tooltip').should('be.visible');
cy.get('.slick-custom-tooltip').should('contain', `regular tooltip (from title attribute)\nTask 5 cell value:\nThis is a sample task description.\nIt can be multiline\n\nAnother line...`);
cy.get('@desc2-5-cell').trigger('mouseout');
});
it('should mouse over 6th row Duration and expect a custom tooltip shown with 4 label/value pairs displayed', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 5}px;"] > .slick-cell:nth(4)`).as('duration5-cell');
cy.get('@duration5-cell').should('contain', '5 days');
cy.get('@duration5-cell').trigger('mouseover');
cy.get('.slick-custom-tooltip').should('be.visible');
cy.get('.slick-custom-tooltip').contains('Custom Tooltip');
cy.get('.tooltip-2cols-row:nth(0)').find('div:nth(0)').contains('Id:');
cy.get('.tooltip-2cols-row:nth(0)').find('div:nth(1)').contains('5');
cy.get('.tooltip-2cols-row:nth(1)').find('div:nth(0)').contains('Title:');
cy.get('.tooltip-2cols-row:nth(1)').find('div:nth(1)').contains('Task 5');
cy.get('.tooltip-2cols-row:nth(2)').find('div:nth(0)').contains('Completion:');
cy.get('.tooltip-2cols-row:nth(2)').find('div:nth(1)').find('.percent-complete-bar').should('exist');
cy.get('.tooltip-2cols-row:nth(3)').find('div:nth(0)').contains('Effort Driven:');
cy.get('.tooltip-2cols-row:nth(3)').find('div:nth(1)').find('.sgi-check').should('exist');
cy.get('@duration5-cell').trigger('mouseout');
});
it('should mouse over % Complete cell of Task 5 and expect regular tooltip to show with content "x %" where x is a number', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 5}px;"] > .slick-cell:nth(5)`).as('percentage-cell');
cy.get('@percentage-cell').find('.percent-complete-bar').should('exist');
cy.get('@percentage-cell').trigger('mouseover');
cy.get('.slick-custom-tooltip').should('be.visible');
cy.get('.slick-custom-tooltip').contains(/\d+%$/);
cy.get('@percentage-cell').trigger('mouseout');
});
it('should mouse over header-row (filter) 1st column checkbox and NOT expect any tooltip to show since it is disabled on that column', () => {
cy.get(`.slick-headerrow-columns .slick-headerrow-column:nth(0)`).as('checkbox0-filter');
cy.get('@checkbox0-filter').trigger('mouseenter');
cy.get('.slick-custom-tooltip').should('not.exist');
cy.get('@checkbox0-filter').trigger('mouseleave');
});
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('.slick-custom-tooltip').should('be.visible');
cy.get('.slick-custom-tooltip').contains('Custom Tooltip - Header Row (filter)');
cy.get('.tooltip-2cols-row:nth(0)').find('div:nth(0)').contains('Column:');
cy.get('.tooltip-2cols-row:nth(0)').find('div:nth(1)').contains('title');
cy.get('@checkbox0-filter').trigger('mouseleave');
});
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(7)`).as('finish-filter');
cy.get('@finish-filter').trigger('mouseenter');
cy.get('.slick-custom-tooltip').should('not.exist');
cy.get('@finish-filter').trigger('mouseleave');
});
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('.slick-custom-tooltip').should('not.exist');
cy.get('@checkbox-header').trigger('mouseleave');
});
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('.slick-custom-tooltip').should('be.visible');
cy.get('.slick-custom-tooltip').contains('Custom Tooltip - Header');
cy.get('.tooltip-2cols-row:nth(0)').find('div:nth(0)').contains('Column:');
cy.get('.tooltip-2cols-row:nth(0)').find('div:nth(1)').contains('Title');
cy.get('@checkbox0-header').trigger('mouseleave');
});
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(7)`).as('finish-header');
cy.get('@finish-header').trigger('mouseenter');
cy.get('.slick-custom-tooltip').should('not.exist');
cy.get('@finish-header').trigger('mouseleave');
});
});
@@ -0,0 +1,183 @@
describe('Example - Header Button', () => {
const titles = ['Resize me!', 'Hover me!', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
beforeEach(() => {
// create a console.log spy for later use
cy.window().then((win) => {
cy.spy(win.console, 'log');
});
});
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-plugin-headerbuttons.html`);
cy.get('p').contains('This example demonstrates using the Slick.Plugins.HeaderButtons plugin');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should go over the 3rd column "C" and expect to see negative number in red after clicking on the orange header button', () => {
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(2)')
.should('contain', 'C');
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(2)')
.find('.slick-header-button.sgi-lightbulb.color-orange')
.should('exist')
.click();
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(1);
expect(win.console.log).to.be.calledWith(`execute a callback action to "toggle-highlight" on column C`);
});
cy.get('#myGrid')
.find('.slick-row')
.each(($row, index) => {
if (index > 10) {
return; // check only the first 10 rows is enough
}
cy.wrap($row).children('.slick-cell:nth(2)')
.each($cell => {
const numberValue = $cell.text();
const htmlValue = $cell.html();
if (+numberValue < 0) {
expect(htmlValue).to.eq(`<div style="color:red; font-weight:bold;">${numberValue}</div>`);
} else {
expect(htmlValue).to.eq(numberValue);
}
});
});
});
it('should go over the 5th column "E" and not find the orange header button', () => {
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(4)')
.should('contain', 'E');
// column E should not have the icon
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(4)')
.find('.slick-header-button')
.should('not.exist');
});
it('should go over the last column "J" and expect to find the orange header button, however it should be unusable and number should not display as red', () => {
cy.get('.slick-viewport-top.slick-viewport-left')
.scrollTo('right')
.wait(50);
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(9)')
.should('contain', 'J');
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(9)')
.find('.slick-header-button.sgi-lightbulb.color-orange')
.should('exist')
.click();
cy.get('#myGrid')
.find('.slick-row')
.each(($row, index) => {
if (index > 10) {
return;
}
cy.wrap($row).children('.slick-cell:nth(9)')
.each($cell => expect($cell.html()).to.eq($cell.text()));
});
});
it('should resize 1st column and make it wider', () => {
cy.get('.slick-viewport-top.slick-viewport-left')
.scrollTo('left')
.wait(50);
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(0)')
.should('contain', 'Resize me!');
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(0)')
.find('.slick-header-button:nth(3)')
.should('be.hidden');
// Cypress does not yet support the .hover() method and because of that we need to manually resize the element
// this is not ideal since it only resizes the cell not the entire column but it's enough to test the functionality
cy.get('.slick-header-column:nth(0)')
// resize the 1st column
.each($elm => $elm.width(140))
.find('.slick-resizable-handle')
.should('be.visible')
.invoke('show');
cy.get('.slick-header-column:nth(0)')
.should($el => expect(parseInt(`${$el.width()}`, 10)).to.eq(140));
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(0)')
.find('.slick-header-button')
.should('have.length', 4);
});
it('should click on first "Red Tag Day" header button and expect an alert with that text when clicked', (done) => {
const stub = cy.stub();
cy.on('window:alert', stub);
cy.on('window:alert', (text) => {
expect(text).to.eq('command: Red Tag Day');
done();
});
// header buttons are displayed in inverse mode by default,
// so we need to start at the end
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(0)')
.find('.slick-header-button:nth(3)')
.click();
});
it('should click on second "Write a comment!" header button and expect an alert with that text when clicked', (done) => {
const stub = cy.stub();
cy.on('window:alert', stub);
cy.on('window:alert', (text) => {
expect(text).to.eq('Write a comment!');
done();
});
// header buttons are displayed in inverse mode by default
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(0)')
.find('.slick-header-button:nth(2)')
.click();
});
it('should go on the 2nd column "Hover me!" and expect the header button to appear only when doing hover over it', () => {
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(1)')
.should('contain', 'Hover me!');
cy.get('.slick-header-columns')
.children('.slick-header-column:nth(1)')
.find('.slick-header-button.slick-header-button-hidden')
.should('be.hidden')
.should('have.css', 'width', '0px');
// hover is not yet implemented in Cypress, so the following test won't work until then
// cy.get('.slick-header-columns')
// .children('.slick-header-column:nth(1)')
// .trigger('mouseover')
// .hover()
// .find('.slick-header-button')
// .should('have.css', 'width', '15px');
});
});
@@ -0,0 +1,258 @@
describe('Example - Header Menu', () => {
const titles = ['Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
beforeEach(() => {
// create a console.log spy for later use
cy.window().then((win) => {
cy.spy(win.console, 'log');
});
});
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-plugin-headermenu.html`);
cy.get('p').contains('This example demonstrates using the Slick.Plugins.HeaderMenu');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should open the Header Menu on the "Title" column and expect onBeforeMenuShow then onAfterMenuShow to show in the console log', () => {
cy.get('#myGrid')
.find('.slick-header-column')
.first()
.trigger('mouseover')
.children('.slick-header-menubutton')
.should('be.hidden')
.invoke('show')
.click();
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('Before the Header Menu is shown');
expect(win.console.log).to.be.calledWith('After the Header Menu is shown');
});
});
it('should open the Header Menu on the "Title" column and expect Sort & Hide commands to be disabled', () => {
cy.get('.slick-header-menuitem.slick-header-menuitem-disabled')
.contains('Sort Ascending')
.should('exist');
cy.get('.slick-header-menuitem.slick-header-menuitem-disabled')
.contains('Sort Descending')
.should('exist');
cy.get('.slick-header-menuitem.slick-header-menuitem-disabled')
.contains('Hide')
.should('exist');
});
it(`should be still be able to click on the Help button and expect an alert`, () => {
const alertStub = cy.stub();
cy.on('window:alert', alertStub);
cy.get('.slick-header-menuitem.bold')
.find('.slick-header-menucontent.blue')
.contains('Help')
.click()
.then(() => expect(alertStub.getCall(0)).to.be.calledWith('Command: help'));
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(1);
expect(win.console.log).to.be.calledWith('execute an action on Help');
});
});
it('should hover over the "Duration" column and expect Sort commands to be enabled', () => {
cy.get('#myGrid')
.find('.slick-header-column:nth(1)')
.trigger('mouseover')
.children('.slick-header-menubutton')
.should('be.hidden')
.invoke('show')
.click();
cy.get('.slick-header-menuitem.slick-header-menuitem')
.contains('Sort Ascending')
.should('exist');
cy.get('.slick-header-menuitem.slick-header-menuitem')
.contains('Sort Descending')
.should('exist');
cy.get('.slick-header-menuitem.slick-header-menuitem-disabled')
.contains('Hide')
.should('exist');
});
it('should execute "Sort Ascending" command from the left opened menu', () => {
cy.get('.slick-header-menu')
.should('exist');
cy.get('.slick-header-menuitem.slick-header-menuitem')
.contains('Sort Ascending')
.click();
cy.get('.slick-header-column:nth(1).slick-header-sortable.slick-header-column-sorted')
.find('.slick-sort-indicator.slick-sort-indicator-asc')
.should('exist');
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.contains('0 days');
});
it('should hover over "% Complete" and not expect to find the Help menu', () => {
cy.get('#myGrid')
.find('.slick-header-column:nth(2)')
.trigger('mouseover')
.children('.slick-header-menubutton')
.should('be.hidden')
.invoke('show')
.click();
cy.get('.slick-header-menu')
.should('exist');
cy.get('.slick-header-menuitem.slick-header-menuitem')
.contains('Help')
.should('not.exist');
});
it('should execute "Sort Descending" command from the menu left open and expect 2 sort icons afterward', () => {
cy.get('.slick-header-menu')
.should('exist');
cy.get('.slick-header-menuitem.slick-header-menuitem')
.contains('Sort Descending')
.click();
cy.get('.slick-header-column:nth(1).slick-header-sortable.slick-header-column-sorted')
.find('.slick-sort-indicator.slick-sort-indicator-asc')
.should('exist');
cy.get('.slick-header-column:nth(2).slick-header-sortable.slick-header-column-sorted')
.find('.slick-sort-indicator.slick-sort-indicator-desc')
.should('exist');
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(1)')
.contains('0 days');
cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(2)')
.each($row => {
expect(+$row.text()).to.be.greaterThan(60);
});
});
it('should hover over the "Effort Driven" column and expect Sort & Hide commands to be disabled', () => {
cy.get('#myGrid')
.find('.slick-header-column:nth(5)')
.trigger('mouseover')
.children('.slick-header-menubutton')
.should('be.hidden')
.invoke('show')
.click();
cy.get('.slick-header-menuitem.slick-header-menuitem-disabled')
.contains('Sort Ascending')
.should('exist');
cy.get('.slick-header-menuitem.slick-header-menuitem-disabled')
.contains('Sort Descending')
.should('exist');
cy.get('.slick-header-menuitem.slick-header-menuitem-disabled')
.contains('Hide')
.should('exist');
});
it('should open Freeze/Pinning sub-menu with 2 options expect it to be aligned to left then trigger alert when command is clicked', () => {
const subCommands = ['Freeze Columns', 'Unfreeze all Columns'];
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('.slick-header-menuitem.slick-header-menuitem')
.contains('Freeze/Pinning')
.should('exist')
.click();
cy.get('.slick-header-menu.slick-menu-level-1.dropleft')
.should('exist')
.find('.slick-header-menuitem')
.each(($command, index) => expect($command.text()).to.eq(subCommands[index]));
cy.get('.slick-header-menu.slick-menu-level-1')
.find('.slick-header-menuitem')
.contains('Freeze Columns')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Command: freeze-columns'));
});
it('should open Freeze/Pinning sub-menu and expect 2 options, then open Feedback->ContactUs sub-menus and expect previous Freeze menu to no longer exists', () => {
const subCommands1 = ['Freeze Columns', 'Unfreeze all Columns'];
const subCommands2 = ['Column is great', 'Column is not useful', '', 'Contact Us'];
const subCommands2_1 = ['Email us', 'Chat with us', 'Book an appointment'];
const stub = cy.stub();
cy.on('window:alert', stub);
cy.get('#myGrid')
.find('.slick-header-column:nth(5)')
.trigger('mouseover')
.children('.slick-header-menubutton')
.invoke('show')
.click();
cy.get('.slick-header-menu.slick-menu-level-0')
.find('.slick-header-menuitem.slick-header-menuitem')
.contains('Freeze/Pinning')
.should('exist')
.click();
cy.get('.slick-submenu').should('have.length', 1);
cy.get('.slick-header-menu.slick-menu-level-1.dropleft') // left align
.should('exist')
.find('.slick-header-menuitem')
.each(($command, index) => expect($command.text()).to.eq(subCommands1[index]));
// click different sub-menu
cy.get('.slick-header-menu.slick-menu-level-0')
.find('.slick-header-menuitem.slick-header-menuitem')
.contains('Feedback')
.should('exist')
.trigger('mouseover'); // mouseover or click should work
cy.get('.slick-submenu').should('have.length', 1);
cy.get('.slick-header-menu.slick-menu-level-1')
.should('exist')
.find('.slick-header-menuitem')
.each(($command, index) => expect($command.text()).to.eq(subCommands2[index]));
// click on Feedback->ContactUs
cy.get('.slick-header-menu.slick-menu-level-1.dropleft') // left align
.find('.slick-header-menuitem.slick-header-menuitem')
.contains('Contact Us')
.should('exist')
.click();
cy.get('.slick-submenu').should('have.length', 2);
cy.get('.slick-header-menu.slick-menu-level-2.dropright') // right align
.should('exist')
.find('.slick-header-menuitem')
.each(($command, index) => expect($command.text()).to.eq(subCommands2_1[index]));
cy.get('.slick-header-menu.slick-menu-level-2')
.find('.slick-header-menuitem')
.contains('Chat with us')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Command: contact-chat'));
cy.get('.slick-submenu').should('have.length', 0);
});
});
@@ -0,0 +1,161 @@
describe('Example - Row Detail/Row Move/Checkbox Selector Plugins', () => {
const fullTitles = ['', '', '', '#', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
it('should display Example Row Detail/Row Move/Checkbox Selector Plugins', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-row-detail-selection-and-move.html`);
cy.get('h2').should('contain', 'Demonstrates:');
cy.get('h3').should('contain', 'The following three Plugins used together');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should open the Row Detail of the 2nd row and expect to find some details', () => {
cy.get('.slick-cell.detailView-toggle:nth(3)')
.click()
.wait(250);
cy.get('.slick-cell + .dynamic-cell-detail .innerDetailView_3')
.find('h2')
.should('contain', 'Task 3');
cy.get('input[id="assignee_3"]')
.should('exist');
cy.get('input[type="checkbox"]:checked')
.should('have.length', 0);
});
it('should drag opened Row Detail to another valid position in the grid', () => {
cy.get('[style="top: 25px;"] > .slick-cell.cell-reorder').as('moveIconTask1');
cy.get('[style="top: 75px;"] > .slick-cell.cell-reorder').as('moveIconTask3');
cy.get('[style="top: 100px;"]').as('expandIconTask4');
cy.get('@moveIconTask3')
.trigger('mousedown', { button: 0, force: true })
.trigger('mousemove', 'bottomRight');
cy.get('[style="top: 100px;"]')
.trigger('mousemove', 'bottomRight', { force: true });
cy.get('[style="top: 100px;"]')
.trigger('mouseup', 'bottomRight', { force: true });
cy.get('input[type="checkbox"]:checked')
.should('have.length', 0);
});
it('should expect row to be moved to another row index', () => {
cy.get('.slick-viewport-top.slick-viewport-left')
.scrollTo('top');
cy.get('[style="top: 0px;"] > .slick-cell:nth(4)').should('contain', 'Task 0');
cy.get('[style="top: 25px;"] > .slick-cell:nth(4)').should('contain', 'Task 1');
cy.get('[style="top: 50px;"] > .slick-cell:nth(4)').should('contain', 'Task 2');
cy.get('[style="top: 75px;"] > .slick-cell:nth(4)').should('contain', 'Task 4');
cy.get('[style="top: 100px;"] > .slick-cell:nth(4)').should('contain', 'Task 3');
cy.get('input[type="checkbox"]:checked')
.should('have.length', 0);
});
it('should try moving a row to an invalid target and expect nothing moved (same rows as prior test)', () => {
cy.get('[style="top: 25px;"] > .slick-cell.cell-reorder').as('moveIconTask1');
cy.get('[style="top: 100px;"]').as('expandIconTask4');
cy.get('@moveIconTask1')
.trigger('mousedown', { button: 0, force: true })
.trigger('mousemove', 'bottomRight');
cy.get('[style="top: 75px;"]')
.trigger('mousemove', 'topRight', { force: true });
cy.get('[style="top: 75px;"]')
.trigger('mouseup', 'topRight', { force: true });
cy.get('input[type="checkbox"]:checked')
.should('have.length', 0);
});
it('should select 2 rows (Task 1,3), then move row and expect the 2 rows to still be selected without any other rows', () => {
cy.get('[style="top: 25px;"] > .slick-cell:nth(2)').click();
cy.get('[style="top: 100px;"] > .slick-cell:nth(2)').click();
cy.get('[style="top: 25px;"] > .slick-cell.cell-reorder').as('moveIconTask1');
cy.get('[style="top: 150px;"]').as('moveIconTask3');
cy.get('@moveIconTask1').should('have.length', 1);
cy.get('@moveIconTask1')
.trigger('mousedown', { button: 0, force: true })
.trigger('mousemove', 'bottomRight');
cy.get('@moveIconTask3')
.trigger('mousemove', 'bottomRight', { force: true })
.trigger('mouseup', 'bottomRight', { force: true });
cy.get('[style="top: 0px;"] > .slick-cell:nth(4)').should('contain', 'Task 0');
cy.get('[style="top: 25px;"] > .slick-cell:nth(4)').should('contain', 'Task 2');
cy.get('[style="top: 50px;"] > .slick-cell:nth(4)').should('contain', 'Task 4');
cy.get('[style="top: 75px;"] > .slick-cell:nth(4)').should('contain', 'Task 3');
cy.get('[style="top: 100px;"] > .slick-cell:nth(4)').should('contain', 'Task 5');
cy.get('[style="top: 125px;"] > .slick-cell:nth(4)').should('contain', 'Task 6');
cy.get('[style="top: 150px;"] > .slick-cell:nth(4)').should('contain', 'Task 1');
// Task 4 and 3 should be selected
cy.get('input[type="checkbox"]:checked').should('have.length', 2);
cy.get('[style="top: 75px;"] > .slick-cell:nth(2) input[type="checkbox"]:checked').should('have.length', 1);
cy.get('[style="top: 150px;"] > .slick-cell:nth(2) input[type="checkbox"]:checked').should('have.length', 1);
});
it('should click on "Single Row Move OFF", then drag a row and expect both selected rows to be moved together', () => {
cy.contains('Single Row Move OFF').click();
cy.get('[style="top: 175px;"] > .slick-cell.cell-reorder').as('moveIconTask7');
cy.get('[style="top: 75px;"] > .slick-cell.cell-reorder').as('moveIconTask3');
cy.get('@moveIconTask3').should('have.length', 1);
cy.get('@moveIconTask3')
.trigger('mousedown', { button: 0, force: true })
.trigger('mousemove', 'bottomRight');
cy.get('[style="top: 200px;"]')
.trigger('mousemove', 'bottomRight', { force: true })
.trigger('mouseup', 'bottomRight', { force: true });
cy.get('[style="top: 0px;"] > .slick-cell:nth(4)').should('contain', 'Task 0');
cy.get('[style="top: 25px;"] > .slick-cell:nth(4)').should('contain', 'Task 2');
cy.get('[style="top: 50px;"] > .slick-cell:nth(4)').should('contain', 'Task 4');
cy.get('[style="top: 75px;"] > .slick-cell:nth(4)').should('contain', 'Task 5');
cy.get('[style="top: 100px;"] > .slick-cell:nth(4)').should('contain', 'Task 6');
cy.get('[style="top: 125px;"] > .slick-cell:nth(4)').should('contain', 'Task 7');
cy.get('[style="top: 150px;"] > .slick-cell:nth(4)').should('contain', 'Task 8');
cy.get('[style="top: 175px;"] > .slick-cell:nth(4)').should('contain', 'Task 3');
cy.get('[style="top: 200px;"] > .slick-cell:nth(4)').should('contain', 'Task 1');
// Task 1 and 3 should be selected
cy.get('input[type="checkbox"]:checked').should('have.length', 2);
cy.get('[style="top: 175px;"] > .slick-cell:nth(2) input[type="checkbox"]:checked').should('have.length', 1);
cy.get('[style="top: 200px;"] > .slick-cell:nth(2) input[type="checkbox"]:checked').should('have.length', 1);
});
it('should open the Task 3 Row Detail and still expect same detail', () => {
cy.get('[style="top: 175px;"] > .slick-cell:nth(4)').should('contain', 'Task 3');
cy.get('[style="top: 175px;"] > .slick-cell:nth(0)')
.click()
.wait(250);
cy.get('.slick-cell + .dynamic-cell-detail .innerDetailView_3')
.find('h2')
.should('contain', 'Task 3');
cy.get('input[id="assignee_3"]')
.should('exist');
});
});
@@ -0,0 +1,169 @@
describe('Example - Spreadsheet with DataView and Cell Selection', { retries: 0 }, () => {
const cellHeight = 25;
const titles = [
'', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
'Z', 'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK'
];
it('should load Example', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-spreadsheet-dataview.html`);
});
it('should have exact column titles on grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => {
if (index < titles.length) {
expect($child.text()).to.eq(titles[index]);
}
});
});
describe('no Pagination - showing all', () => {
it('should click on cell B10 and ArrowUp 3 times and ArrowDown 1 time and expect cell selection B8-B10', () => {
cy.getCell(10, 2, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_B10')
.click();
cy.get('@cell_B10')
.type('{shift}{uparrow}{uparrow}{uparrow}{downarrow}');
cy.get('.slick-cell.l2.r2.selected')
.should('have.length', 3);
cy.get('#selectionRange')
.should('have.text', '{"fromRow":8,"fromCell":2,"toCell":2,"toRow":10}');
});
it('should click on cell D10 then PageDown 2 times w/selection D10-D46 ', () => {
cy.getCell(10, 4, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_D10')
.click();
cy.get('@cell_D10')
.type('{shift}{pagedown}{pagedown}');
cy.get('#selectionRange')
.should('have.text', '{"fromRow":10,"fromCell":4,"toCell":4,"toRow":46}');
});
it('should click on cell D10 then PageDown 3 times then PageUp 1 time w/selection D10-D46', () => {
cy.getCell(10, 4, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_D10')
.click();
cy.get('@cell_D10')
.type('{shift}{pagedown}{pagedown}{pagedown}{pageup}');
cy.get('#selectionRange')
.should('have.text', '{"fromRow":10,"fromCell":4,"toCell":4,"toRow":46}');
});
it('should click on cell E46 then Shift+End key with full row horizontal selection E46-CV46', () => {
cy.getCell(46, 5, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_E46')
.click();
cy.get('@cell_E46')
.type('{shift}{end}');
cy.get('#selectionRange')
.should('have.text', '{"fromRow":46,"fromCell":5,"toCell":100,"toRow":46}');
});
it('should click on cell CP54 then Ctrl+Shift+End keys with selection E46-CV99', () => {
cy.getCell(54, 94, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_CP54')
.click();
cy.get('@cell_CP54')
.type('{ctrl}{shift}{end}');
cy.get('#selectionRange')
.should('have.text', '{"fromRow":54,"fromCell":94,"toCell":100,"toRow":99}');
});
it('should click on cell CP95 then Ctrl+Shift+Home keys with selection C0-CP95', () => {
cy.getCell(95, 98, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_CP95')
.click();
cy.get('@cell_CP95')
.type('{ctrl}{shift}{home}');
cy.get('#selectionRange')
.should('have.text', '{"fromRow":0,"fromCell":0,"toCell":98,"toRow":95}');
});
it('should click on cell CR5 then Ctrl+Home keys and expect to scroll back to cell A0 without any selection range', () => {
cy.getCell(5, 95, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_CR95')
.click();
cy.get('@cell_CR95')
.type('{ctrl}{home}');
cy.get('#selectionRange')
.should('have.text', '');
});
});
describe('with Pagination', () => {
it('should show Page of size 25', () => {
cy.get('.slick-pager-settings .sgi-lightbulb').click();
cy.get('[data-val="25"]').click();
});
it('should click on cell B14 then Shift+End with selection B14-24', () => {
cy.getCell(14, 2, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_B14')
.click();
cy.get('@cell_B14')
.type('{shift}{end}');
cy.get('#selectionRange')
.should('have.text', '{"fromRow":14,"fromCell":2,"toCell":100,"toRow":14}');
});
it('should click on cell CS14 then Shift+Home with selection A14-CS14', () => {
cy.getCell(14, 97, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_CS14')
.click();
cy.get('@cell_CS14')
.type('{shift}{home}');
cy.get('#selectionRange')
.should('have.text', '{"fromRow":14,"fromCell":0,"toCell":97,"toRow":14}');
});
it('should click on cell CN3 then Shift+PageDown multiple times with current page selection starting at E3 w/selection E3-24', () => {
cy.getCell(3, 95, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_CN3')
.click();
cy.get('@cell_CN3')
.type('{shift}{pagedown}{pagedown}{pagedown}');
cy.get('#selectionRange')
.should('have.text', '{"fromRow":3,"fromCell":95,"toCell":95,"toRow":24}');
});
it('should change to 2nd page then click on cell CN41 then Shift+PageUp multiple times with current page selection w/selection D25-41', () => {
cy.get('.slick-pager .sgi-chevron-right').click();
cy.getCell(15, 92, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_CN41')
.click();
cy.get('@cell_CN41')
.type('{shift}{pageup}{pageup}{pageup}');
cy.get('#selectionRange')
.should('have.text', '{"fromRow":0,"fromCell":92,"toCell":92,"toRow":15}');
});
});
});
@@ -0,0 +1,110 @@
describe('Example - Spreadsheet and Cell Selection', { retries: 0 }, () => {
const cellHeight = 25;
const titles = [
'', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
'Z', 'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK'
];
it('should load Example', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-spreadsheet.html`);
});
it('should have exact column titles on grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => {
if (index < titles.length) {
expect($child.text()).to.eq(titles[index]);
}
});
});
it('should click on cell B10 and ArrowUp 3 times and ArrowDown 1 time and expect cell selection B8-B10', () => {
cy.getCell(10, 2, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_B10')
.click();
cy.get('@cell_B10')
.type('{shift}{uparrow}{uparrow}{uparrow}{downarrow}');
cy.get('.slick-cell.l2.r2.selected')
.should('have.length', 3);
cy.get('#selectionRange')
.should('have.text', '{"fromRow":8,"fromCell":2,"toCell":2,"toRow":10}');
});
it('should click on cell D10 then PageDown 2 times w/selection D10-D46 ', () => {
cy.getCell(10, 4, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_D10')
.click();
cy.get('@cell_D10')
.type('{shift}{pagedown}{pagedown}');
cy.get('#selectionRange')
.should('have.text', '{"fromRow":10,"fromCell":4,"toCell":4,"toRow":46}');
});
it('should click on cell D10 then PageDown 3 times then PageUp 1 time w/selection D10-D46', () => {
cy.getCell(10, 4, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_D10')
.click();
cy.get('@cell_D10')
.type('{shift}{pagedown}{pagedown}{pagedown}{pageup}');
cy.get('#selectionRange')
.should('have.text', '{"fromRow":10,"fromCell":4,"toCell":4,"toRow":46}');
});
it('should click on cell E46 then Shift+End key with full row horizontal selection E46-CV46', () => {
cy.getCell(46, 5, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_E46')
.click();
cy.get('@cell_E46')
.type('{shift}{end}');
cy.get('#selectionRange')
.should('have.text', '{"fromRow":46,"fromCell":5,"toCell":100,"toRow":46}');
});
it('should click on cell CP54 then Ctrl+Shift+End keys with selection E46-CV99', () => {
cy.getCell(54, 94, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_CP54')
.click();
cy.get('@cell_CP54')
.type('{ctrl}{shift}{end}');
cy.get('#selectionRange')
.should('have.text', '{"fromRow":54,"fromCell":94,"toCell":100,"toRow":99}');
});
it('should click on cell CP95 then Ctrl+Shift+Home keys with selection C0-CP95', () => {
cy.getCell(95, 98, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_CP95')
.click();
cy.get('@cell_CP95')
.type('{ctrl}{shift}{home}');
cy.get('#selectionRange')
.should('have.text', '{"fromRow":0,"fromCell":0,"toCell":98,"toRow":95}');
});
it('should click on cell CR5 then Ctrl+Home keys and expect to scroll back to cell A0 without any selection range', () => {
cy.getCell(5, 95, '', { parentSelector: '#myGrid', rowHeight: cellHeight })
.as('cell_CR95')
.click();
cy.get('@cell_CR95')
.type('{ctrl}{home}');
cy.get('#selectionRange')
.should('have.text', '');
});
});
@@ -0,0 +1,77 @@
describe('Example - Real-Time Trading Platform', () => {
const titles = ['Currency', 'Symbol', 'Market', 'Company', 'Type', 'Change', 'Price', 'Qty', 'Amount', 'Price History', 'Execution Timestamp'];
const GRID_ROW_HEIGHT = 28;
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-trading-esm.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('High Frequency Update - Realtime Trading Platform');
});
it('should have exact column titles on 1st grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should check first 5 rows and expect certain data', () => {
for (let i = 0; i < 5; i++) {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * i}px;"] > .slick-cell:nth(0)`).contains(/AUD|CAD|USD$/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * i}px;"] > .slick-cell:nth(4)`).contains(/Buy|Sell$/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * i}px;"] > .slick-cell:nth(5)`).contains(/\$\(?[0-9.]*\)?/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * i}px;"] > .slick-cell:nth(6)`).contains(/\$[0-9.]*/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * i}px;"] > .slick-cell:nth(7)`).contains(/\d$/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * i}px;"] > .slick-cell:nth(8)`).contains(/\$[0-9.]*/);
}
});
it('should find multiple green & pink backgrounds to show gains & losses when in real-time mode', () => {
cy.get('#refreshRateSlider').invoke('val', 5).trigger('change');
cy.get('.changed-gain').should('have.length.gt', 2);
cy.get('.changed-loss').should('have.length.gt', 2);
});
it('should NOT find any green neither pink backgrounds when in real-time is stopped', () => {
cy.get('#highlightDuration').type('{backspace}');
cy.get('#btnStopSimulation').click();
cy.wait(5);
cy.get('.changed-gain').should('have.length', 0);
cy.get('.changed-loss').should('have.length', 0);
cy.wait(1);
cy.get('.changed-gain').should('have.length', 0);
cy.get('.changed-loss').should('have.length', 0);
});
it('should Group by "Currency" and expect 3 groups with Totals when collapsed', () => {
cy.get('[data-test="group-currency-btn"]').click();
cy.get('[data-test="collapse-all-btn"]').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Currency: AUD');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(8)`).contains(/\$[0-9,.]*/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Currency: CAD');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(8)`).contains(/\$[0-9,.]*/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Currency: USD');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 5}px;"] > .slick-cell:nth(8)`).contains(/\$[0-9,.]*/);
});
it('should clear Grouping and expect regular trading row from non specific currency', () => {
cy.get('[data-test="clear-grouping-btn"]').click();
for (let i = 0; i < 5; i++) {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * i}px;"] > .slick-cell:nth(0)`).contains(/AUD|CAD|USD$/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * i}px;"] > .slick-cell:nth(4)`).contains(/Buy|Sell$/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * i}px;"] > .slick-cell:nth(5)`).contains(/\$\(?[0-9.]*\)?/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * i}px;"] > .slick-cell:nth(6)`).contains(/\$[0-9.]*/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * i}px;"] > .slick-cell:nth(7)`).contains(/\d$/);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * i}px;"] > .slick-cell:nth(8)`).contains(/\$[0-9.]*/);
}
});
});
@@ -0,0 +1,140 @@
describe('Example - Web Component with PubSub Service instead of SlickEvent (ESM)', () => {
const titles = ['#', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
beforeEach(() => {
// create a console.log spy for later use
cy.window().then((win) => {
cy.spy(win.console, 'log');
});
});
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example-web-component-pubsub-esm.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('a filtered Model (DataView) as a data source instead of a simple array');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should display the text "Showing all 50000 rows" without Pagination', () => {
const expectedRows = ['Task 0', 'Task 1', 'Task 2', 'Task 3', 'Task 4'];
cy.get('.slick-pager-status')
.contains('Showing all 50000 rows');
cy.get('#myGrid')
.find('.slick-row')
.each(($row, index) => {
if (index > expectedRows.length - 1) {
return;
}
cy.wrap($row).children('.slick-cell:nth(1)')
.first()
.should('contain', expectedRows[index]);
});
});
it('Should display "Showing page 1 of 1000" text after changing Pagination to 50 items per page', () => {
cy.get('.sgi-lightbulb')
.click();
cy.get('.slick-pager-settings-expanded')
.should('be.visible');
cy.get('.slick-pager-settings-expanded')
.contains('50')
.click();
cy.get('.slick-pager-status')
.contains('Showing page 1 of 1000');
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('on Before Paging Info Changed - Previous Paging:: ', { pageSize: 0, pageNum: 0, totalRows: 50000, totalPages: 1 });
expect(win.console.log).to.be.calledWith('on After Paging Info Changed - New Paging:: ', { pageSize: 50, pageNum: 0, totalRows: 50000, totalPages: 1000 });
});
});
it('Should display "Showing page 2 of 1000" text after clicking on next page', () => {
const expectedRows = ['Task 50', 'Task 51', 'Task 52', 'Task 53', 'Task 54'];
cy.get('.sgi-chevron-start.sgi-state-disabled');
cy.get('.sgi-chevron-left.sgi-state-disabled');
cy.get('.sgi-chevron-right')
.click();
cy.get('.slick-pager-status')
.contains('Showing page 2 of 1000');
cy.get('#myGrid')
.find('.slick-row')
.each(($row, index) => {
if (index > expectedRows.length - 1) {
return;
}
cy.wrap($row).children('.slick-cell:nth(1)')
.first()
.should('contain', expectedRows[index]);
});
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('on Before Paging Info Changed - Previous Paging:: ', { pageSize: 50, pageNum: 0, totalRows: 50000, totalPages: 1000 });
expect(win.console.log).to.be.calledWith('on After Paging Info Changed - New Paging:: ', { pageSize: 50, pageNum: 1, totalRows: 50000, totalPages: 1000 });
});
});
it('Should display "Showing page 1000 of 1000" text after clicking on last page', () => {
const expectedRows = ['Task 49950', 'Task 49951', 'Task 49952', 'Task 49953', 'Task 49954'];
cy.get('.sgi-chevron-end')
.click();
cy.get('.slick-pager-status')
.contains('Showing page 1000 of 1000');
cy.get('#myGrid')
.find('.slick-row')
.each(($row, index) => {
if (index > expectedRows.length - 1) {
return;
}
cy.wrap($row).children('.slick-cell:nth(1)')
.first()
.should('contain', expectedRows[index]);
});
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('on Before Paging Info Changed - Previous Paging:: ', { pageSize: 50, pageNum: 1, totalRows: 50000, totalPages: 1000 });
expect(win.console.log).to.be.calledWith('on After Paging Info Changed - New Paging:: ', { pageSize: 50, pageNum: 999, totalRows: 50000, totalPages: 1000 });
});
});
it('Should display console log when opening Grid Menu', () => {
cy.get('#myGrid')
.find('button.slick-gridmenu-button')
.click({ force: true });
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(1);
expect(win.console.log).to.be.calledWith('Grid Menu onBeforeMenuShow::');
});
cy.get('#myGrid')
.get('.slick-gridmenu:visible')
.find('span.close')
.click();
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('Grid Menu onMenuClose:: slick-gridmenu');
});
});
});
@@ -0,0 +1,48 @@
describe('Example 0070 - Grid State using Local Storage', () => {
const titles = ['Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example15-auto-resize.html`);
cy.get('h2 + p').should('contain', 'Slick.Plugins.Resizer');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should have grid with size that is not 800 by 600px', () => {
cy.get('#myGrid')
.should($el => {
expect(parseInt(`${$el.width()}`, 10)).to.greaterThan(900);
expect(parseInt(`${$el.height()}`, 10)).not.to.eq(600);
});
});
it('should resize the grid to 800 by 600px when clicking on "Fixed Dimension" button', () => {
cy.get('[data-test="fixed-dimension"]')
.click();
cy.get('#myGrid')
.should($el => {
expect(parseInt(`${$el.width()}`, 10)).to.gte(797);
expect(parseInt(`${$el.width()}`, 10)).to.lte(802);
expect(parseInt(`${$el.height()}`, 10)).to.gte(598);
expect(parseInt(`${$el.height()}`, 10)).to.lte(602);
});
});
it('should auto-resize the grid when clicking on "auto-resize" button', () => {
cy.get('[data-test="auto-resize"]')
.click();
cy.get('#myGrid')
.should($el => {
expect(parseInt(`${$el.width()}`, 10)).to.greaterThan(900);
expect(parseInt(`${$el.height()}`, 10)).not.to.eq(600);
});
});
});
@@ -0,0 +1,79 @@
describe('Example - Row Detail/Row Move/Checkbox Selector Plugins', () => {
const GRID_ROW_HEIGHT = 25;
const fullTitles = ['', '#', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
it('should display Example Row Detail/Row Move/Checkbox Selector Plugins', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example16-row-detail.html`);
cy.get('h2').should('contain', 'Demonstrates:');
cy.get('li').should('contain', 'RowDetailView Plugin');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
it('should open the 1st Row Detail of the 2nd row and expect to find some details', () => {
cy.get('.slick-cell.detailView-toggle:nth(1)')
.click()
.wait(50);
cy.get('.slick-cell + .dynamic-cell-detail .detailViewContainer_1')
.find('h4')
.should('contain', 'Task 1');
cy.get('input[id="assignee_1"]')
.should('exist');
cy.get('input[type="checkbox"]:checked')
.should('have.length', 0);
});
it('should open the 2nd Row Detail of the 4th row and expect to find some details', () => {
cy.get(`.slick-row[style="top: ${GRID_ROW_HEIGHT * 10}px;"] .slick-cell:nth(1)`)
.click()
.wait(50);
cy.get('.slick-cell + .dynamic-cell-detail .detailViewContainer_3')
.find('h4')
.should('contain', 'Task 3');
cy.get('input[id="assignee_3"]')
.should('exist');
cy.get('input[type="checkbox"]:checked')
.should('have.length', 0);
});
it('should be able to collapse all row details', () => {
cy.get('.dynamic-cell-detail').should('have.length', 2);
cy.get('[data-test="collapse-all-btn"]').click();
cy.get('.dynamic-cell-detail').should('have.length', 0);
});
it('should open the Task 3 Row Detail and still expect same detail', () => {
cy.get(`.slick-row[style="top: ${GRID_ROW_HEIGHT * 3}px;"] .slick-cell:nth(1)`)
.click()
.wait(50);
cy.get('.dynamic-cell-detail').should('have.length', 1);
cy.get('.slick-cell + .dynamic-cell-detail .innerDetailView_3')
.find('h4')
.should('contain', 'Task 3');
cy.get('input[id="assignee_3"]')
.should('exist');
});
it('should click on "click me" and expect an Alert to show the Help text', () => {
cy.on('window:alert', (str) => {
expect(str).to.contain('Assignee is');
});
cy.contains('Click Me')
.click();
});
});
@@ -0,0 +1,106 @@
describe('Example3 Editing', () => {
const titles = ['Title', 'Description', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
const GRID_ROW_HEIGHT = 28;
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example3-editing.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('adding basic keyboard navigation and editing');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should be able to edit "Description" by double-clicking on first row and expect no more editable cell', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'This is a sample');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).click();
cy.get('.slick-large-editor-text').should('have.length', 0);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).dblclick();
cy.get('.slick-large-editor-text').should('have.length', 1);
cy.get('.slick-large-editor-text textarea')
.type('Something else');
cy.get('.slick-large-editor-text')
.contains('Save')
.click();
cy.get('.slick-large-editor-text').should('have.length', 0);
});
it('should click on "Auto-Edit ON" button', () => {
cy.get('[data-test="auto-edit-on-btn"]')
.click();
});
it('should be able to edit "Description" by clicking once on second row and expect next row to become editable after clicking "Save" button', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', 'This is a sample');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).click();
cy.get('.slick-large-editor-text').should('have.length', 1);
cy.get('.slick-large-editor-text textarea')
.type('Second Row!');
cy.get('.slick-large-editor-text')
.contains('Save')
.click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', 'Second Row!');
cy.get('.slick-large-editor-text').should('have.length', 1);
cy.get('.slick-large-editor-text textarea')
.invoke('val')
.then(text => expect(text).to.eq('This is a sample task description.\n It can be multiline'));
});
it('should click on "Auto-Commit ON" button', () => {
cy.get('[data-test="auto-commit-on-btn"]')
.click();
});
it('should be able to edit "Description" by clicking once on second row and expect next row and not expect next line to become editable', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).should('contain', 'This is a sample');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).click();
cy.get('.slick-large-editor-text').should('have.length', 1);
cy.get('.slick-large-editor-text textarea')
.type('Third Row Text');
cy.get('.slick-large-editor-text')
.contains('Save')
.click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).should('contain', 'Third Row Text');
cy.get('.slick-large-editor-text').should('have.length', 0);
});
it('should click on "Auto-Commit OFF" button', () => {
cy.get('[data-test="auto-commit-off-btn"]')
.click();
});
it('should be able to edit "Description" and expect once again that the next line will become editable', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).should('contain', 'This is a sample');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).click();
cy.get('.slick-large-editor-text').should('have.length', 1);
cy.get('.slick-large-editor-text textarea')
.type('Fourth Row');
cy.get('.slick-large-editor-text')
.contains('Save')
.click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).should('contain', 'Fourth Row');
cy.get('.slick-large-editor-text').should('have.length', 1);
cy.get('.slick-large-editor-text textarea')
.invoke('val')
.then(text => expect(text).to.eq('This is a sample task description.\n It can be multiline'));
});
});
@@ -0,0 +1,144 @@
describe('Example3 Editing', () => {
const titles = ['Title', 'Description', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
const GRID_ROW_HEIGHT = 25;
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example3b-editing-with-undo.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('Using "editCommandHandler" option to intercept edit commands and implement undo support');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should be able to edit "Description" by double-clicking on first row and expect no more editable cell', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'This is a sample');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).click();
cy.get('.slick-large-editor-text').should('have.length', 0);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).dblclick();
cy.get('.slick-large-editor-text').should('have.length', 1);
cy.get('.slick-large-editor-text textarea')
.type('Something else');
cy.get('.slick-large-editor-text')
.contains('Save')
.click();
cy.get('.slick-large-editor-text').should('have.length', 0);
});
it('should click on "Auto-Edit ON" button', () => {
cy.get('[data-test="auto-edit-on-btn"]').click();
});
it('should be able to edit "Description" by clicking once on second row and expect next row to become editable after clicking "Save" button', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', 'This is a sample');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).click();
cy.get('.slick-large-editor-text').should('have.length', 1);
cy.get('.slick-large-editor-text textarea')
.type('Second Row!');
cy.get('.slick-large-editor-text')
.contains('Save')
.click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', 'Second Row!');
cy.get('.slick-large-editor-text').should('have.length', 1);
cy.get('.slick-large-editor-text textarea')
.invoke('val')
.then(text => expect(text).to.eq('This is a sample task description.\n It can be multiline'));
});
it('should click on Cancel button of next editor', () => {
cy.get('.slick-btn-default#cancel').click();
cy.get('.slick-large-editor-text textarea').should('not.exist');
});
it('should undo last edit and expect the description to be opened as well when clicking the associated last undo with editor button', () => {
cy.get('[data-test=undo-open-editor-btn]').click();
cy.get('.slick-large-editor-text').should('have.length', 1);
cy.get('.slick-large-editor-text textarea')
.invoke('val')
.then(text => expect(text).to.eq('This is a sample task description.\n It can be multiline'));
});
it('should click on Cancel button of next editor', () => {
cy.get('.slick-btn-default#cancel').click();
cy.get('.slick-large-editor-text textarea').should('not.exist');
});
it('should be able to edit "Description" and expect once again that the next line will become editable', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).should('contain', 'This is a sample');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).click();
cy.get('.slick-large-editor-text').should('have.length', 1);
cy.get('.slick-large-editor-text textarea')
.type('Fourth Row');
cy.get('.slick-large-editor-text')
.contains('Save')
.click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).should('contain', 'Fourth Row');
cy.get('.slick-large-editor-text').should('have.length', 1);
cy.get('.slick-large-editor-text textarea')
.invoke('val')
.then(text => expect(text).to.eq('This is a sample task description.\n It can be multiline'));
});
it('should change Task 4 description and then click on Cancel button of next editor', () => {
cy.get('.slick-large-editor-text textarea')
.type('Fifth Row');
cy.get('.slick-large-editor-text')
.contains('Save')
.click();
cy.get('.slick-btn-default#cancel').click();
cy.get('.slick-large-editor-text textarea').should('not.exist');
});
it('should expect Task 0,3,4 to have descriptions other than original text', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 3');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 4');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('not.contain', 'This is a sample');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).should('not.contain', 'This is a sample');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(1)`).should('not.contain', 'This is a sample');
});
it('should click undo edits twice and expect Task 3-4 to be undoned but Task 0 to still be changed', () => {
cy.get('[data-test=undo-open-editor-btn]')
.click()
.click();
cy.get('.slick-large-editor-text').should('have.length', 1);
cy.get('.slick-large-editor-text textarea')
.invoke('val')
.then(text => expect(text).to.eq('This is a sample task description.\n It can be multiline'));
});
it('should cancel any opened textarea editor', () => {
cy.get('.slick-btn-default#cancel').click();
cy.get('.slick-large-editor-text textarea').should('not.exist');
});
it('should expect Task 3-4 to have descriptions other than original text', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 3');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 4');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('not.contain', 'This is a sample');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'Something else');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).should('contain', 'This is a sample');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(1)`).should('contain', 'This is a sample');
});
});
@@ -0,0 +1,165 @@
describe('Example 4 - Model (ESM)', () => {
const GRID_ROW_HEIGHT = 28;
const titles = ['#', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
beforeEach(() => {
// create a console.log spy for later use
cy.window().then((win) => {
cy.spy(win.console, 'log');
});
});
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example4-model-esm.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('a filtered Model (DataView) as a data source instead of a simple array');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should expect first row to include "Task 0" and other specific properties', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(2)`).should('contain', '5 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(3) .percent-complete-bar`).should('exist');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(4)`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(5)`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(6)`).find('.sgi.sgi-checkbox-intermediate').should('have.length', 1);
});
it('should display the text "Showing all 50000 rows" without Pagination', () => {
const expectedRows = ['Task 0', 'Task 1', 'Task 2', 'Task 3', 'Task 4'];
cy.get('.slick-pager-status')
.contains('Showing all 50000 rows');
cy.get('#myGrid')
.find('.slick-row')
.each(($row, index) => {
if (index > expectedRows.length - 1) {
return;
}
cy.wrap($row).children('.slick-cell:nth(1)')
.first()
.should('contain', expectedRows[index]);
});
});
it('Should display "Showing page 1 of 1000" text after changing Pagination to 50 items per page', () => {
cy.get('.sgi-lightbulb')
.click();
cy.get('.slick-pager-settings-expanded')
.should('be.visible');
cy.get('.slick-pager-settings-expanded')
.contains('50')
.click();
cy.get('.slick-pager-status')
.contains('Showing page 1 of 1000');
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('on Before Paging Info Changed - Previous Paging:: ', { pageSize: 0, pageNum: 0, totalRows: 50000, totalPages: 1 });
expect(win.console.log).to.be.calledWith('on After Paging Info Changed - New Paging:: ', { pageSize: 50, pageNum: 0, totalRows: 50000, totalPages: 1000 });
});
});
it('Should display "Showing page 2 of 1000" text after clicking on next page', () => {
const expectedRows = ['Task 50', 'Task 51', 'Task 52', 'Task 53', 'Task 54'];
cy.get('.sgi-chevron-start.sgi-state-disabled');
cy.get('.sgi-chevron-left.sgi-state-disabled');
cy.get('.sgi-chevron-right')
.click();
cy.get('.slick-pager-status')
.contains('Showing page 2 of 1000');
cy.get('#myGrid')
.find('.slick-row')
.each(($row, index) => {
if (index > expectedRows.length - 1) {
return;
}
cy.wrap($row).children('.slick-cell:nth(1)')
.first()
.should('contain', expectedRows[index]);
});
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('on Before Paging Info Changed - Previous Paging:: ', { pageSize: 50, pageNum: 0, totalRows: 50000, totalPages: 1000 });
expect(win.console.log).to.be.calledWith('on After Paging Info Changed - New Paging:: ', { pageSize: 50, pageNum: 1, totalRows: 50000, totalPages: 1000 });
});
});
it('Should display "Showing page 1000 of 1000" text after clicking on last page', () => {
const expectedRows = ['Task 49950', 'Task 49951', 'Task 49952', 'Task 49953', 'Task 49954'];
cy.get('.sgi-chevron-end')
.click();
cy.get('.slick-pager-status')
.contains('Showing page 1000 of 1000');
cy.get('#myGrid')
.find('.slick-row')
.each(($row, index) => {
if (index > expectedRows.length - 1) {
return;
}
cy.wrap($row).children('.slick-cell:nth(1)')
.first()
.should('contain', expectedRows[index]);
});
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('on Before Paging Info Changed - Previous Paging:: ', { pageSize: 50, pageNum: 1, totalRows: 50000, totalPages: 1000 });
expect(win.console.log).to.be.calledWith('on After Paging Info Changed - New Paging:: ', { pageSize: 50, pageNum: 999, totalRows: 50000, totalPages: 1000 });
});
});
it('should expect first row to include "Task 49950" and other specific properties', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 49950');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(2)`).should('contain', '5 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(3) .percent-complete-bar`).should('exist');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(4)`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(5)`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(6)`).find('.sgi.sgi-checkbox-intermediate').should('have.length', 1);
});
it('should remove pagination and scroll back to top', () => {
cy.get('.slick-pager-settings-expanded')
.should('be.visible');
cy.get('.slick-pager-settings-expanded')
.contains('All')
.click();
cy.get('.slick-pager-status')
.contains('Showing all 50000 rows');
});
it('should expect "Task 19" row to be editable', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 19}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 19').click();
cy.get('.slick-large-editor-text textarea').type('Task 2222');
cy.get('.slick-large-editor-text #save').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 19}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 2222');
});
it('should expect "Task 18" row to NOT be editable when "onBeforeEditCell" returns false', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 18}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 18').click();
cy.get('.slick-large-editor-text textarea').should('not.exist');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 18}px;"] > .slick-cell:nth(2)`).should('contain', '5 days').click();
cy.get('.editor-text').should('not.exist');
});
});
@@ -0,0 +1,138 @@
describe('Example 4 - HTML Formatters', () => {
const GRID_ROW_HEIGHT = 25;
const titles = ['#', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
beforeEach(() => {
// create a console.log spy for later use
cy.window().then((win) => {
cy.spy(win.console, 'log');
});
});
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example4-model-html-formatters.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('a filtered Model (DataView) as a data source instead of a simple array');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should expect first row to include "Task 0" and other specific properties', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(2)`).should('contain', '5 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(3) .percent-complete-bar`).should('exist');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(4)`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(5)`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(6)`).find('.sgi.sgi-checkbox-intermediate').should('have.length', 1);
});
it('should display the text "Showing all 50000 rows" without Pagination', () => {
const expectedRows = ['Task 0', 'Task 1', 'Task 2', 'Task 3', 'Task 4'];
cy.get('.slick-pager-status')
.contains('Showing all 50000 rows');
cy.get('#myGrid')
.find('.slick-row')
.each(($row, index) => {
if (index > expectedRows.length - 1) {
return;
}
cy.wrap($row).children('.slick-cell:nth(1)')
.first()
.should('contain', expectedRows[index]);
});
});
it('Should display "Showing page 1 of 1000" text after changing Pagination to 50 items per page', () => {
cy.get('.sgi-lightbulb')
.click();
cy.get('.slick-pager-settings-expanded')
.should('be.visible');
cy.get('.slick-pager-settings-expanded')
.contains('50')
.click();
cy.get('.slick-pager-status')
.contains('Showing page 1 of 1000');
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('on Before Paging Info Changed - Previous Paging:: ', { pageSize: 0, pageNum: 0, totalRows: 50000, totalPages: 1 });
expect(win.console.log).to.be.calledWith('on After Paging Info Changed - New Paging:: ', { pageSize: 50, pageNum: 0, totalRows: 50000, totalPages: 1000 });
});
});
it('Should display "Showing page 2 of 1000" text after clicking on next page', () => {
const expectedRows = ['Task 50', 'Task 51', 'Task 52', 'Task 53', 'Task 54'];
cy.get('.sgi-chevron-start.sgi-state-disabled');
cy.get('.sgi-chevron-left.sgi-state-disabled');
cy.get('.sgi-chevron-right')
.click();
cy.get('.slick-pager-status')
.contains('Showing page 2 of 1000');
cy.get('#myGrid')
.find('.slick-row')
.each(($row, index) => {
if (index > expectedRows.length - 1) {
return;
}
cy.wrap($row).children('.slick-cell:nth(1)')
.first()
.should('contain', expectedRows[index]);
});
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('on Before Paging Info Changed - Previous Paging:: ', { pageSize: 50, pageNum: 0, totalRows: 50000, totalPages: 1000 });
expect(win.console.log).to.be.calledWith('on After Paging Info Changed - New Paging:: ', { pageSize: 50, pageNum: 1, totalRows: 50000, totalPages: 1000 });
});
});
it('Should display "Showing page 1000 of 1000" text after clicking on last page', () => {
const expectedRows = ['Task 49950', 'Task 49951', 'Task 49952', 'Task 49953', 'Task 49954'];
cy.get('.sgi-chevron-end')
.click();
cy.get('.slick-pager-status')
.contains('Showing page 1000 of 1000');
cy.get('#myGrid')
.find('.slick-row')
.each(($row, index) => {
if (index > expectedRows.length - 1) {
return;
}
cy.wrap($row).children('.slick-cell:nth(1)')
.first()
.should('contain', expectedRows[index]);
});
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('on Before Paging Info Changed - Previous Paging:: ', { pageSize: 50, pageNum: 1, totalRows: 50000, totalPages: 1000 });
expect(win.console.log).to.be.calledWith('on After Paging Info Changed - New Paging:: ', { pageSize: 50, pageNum: 999, totalRows: 50000, totalPages: 1000 });
});
});
it('should expect first row to include "Task 49950" and other specific properties', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 49950');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(2)`).should('contain', '5 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(3) .percent-complete-bar`).should('exist');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(4)`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(5)`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(6)`).find('.sgi.sgi-checkbox-intermediate').should('have.length', 1);
});
});
@@ -0,0 +1,138 @@
describe('Example 4 - Model', () => {
const GRID_ROW_HEIGHT = 25;
const titles = ['#', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
beforeEach(() => {
// create a console.log spy for later use
cy.window().then((win) => {
cy.spy(win.console, 'log');
});
});
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/examples/example4-model.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('a filtered Model (DataView) as a data source instead of a simple array');
});
it('should have exact Column Titles in the grid', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(titles[index]));
});
it('should expect first row to include "Task 0" and other specific properties', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(2)`).should('contain', '5 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(3) .percent-complete-bar`).should('exist');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(4)`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(5)`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(6)`).find('.sgi.sgi-checkbox-intermediate').should('have.length', 1);
});
it('should display the text "Showing all 50000 rows" without Pagination', () => {
const expectedRows = ['Task 0', 'Task 1', 'Task 2', 'Task 3', 'Task 4'];
cy.get('.slick-pager-status')
.contains('Showing all 50000 rows');
cy.get('#myGrid')
.find('.slick-row')
.each(($row, index) => {
if (index > expectedRows.length - 1) {
return;
}
cy.wrap($row).children('.slick-cell:nth(1)')
.first()
.should('contain', expectedRows[index]);
});
});
it('Should display "Showing page 1 of 1000" text after changing Pagination to 50 items per page', () => {
cy.get('.sgi-lightbulb')
.click();
cy.get('.slick-pager-settings-expanded')
.should('be.visible');
cy.get('.slick-pager-settings-expanded')
.contains('50')
.click();
cy.get('.slick-pager-status')
.contains('Showing page 1 of 1000');
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('on Before Paging Info Changed - Previous Paging:: ', { pageSize: 0, pageNum: 0, totalRows: 50000, totalPages: 1 });
expect(win.console.log).to.be.calledWith('on After Paging Info Changed - New Paging:: ', { pageSize: 50, pageNum: 0, totalRows: 50000, totalPages: 1000 });
});
});
it('Should display "Showing page 2 of 1000" text after clicking on next page', () => {
const expectedRows = ['Task 50', 'Task 51', 'Task 52', 'Task 53', 'Task 54'];
cy.get('.sgi-chevron-start.sgi-state-disabled');
cy.get('.sgi-chevron-left.sgi-state-disabled');
cy.get('.sgi-chevron-right')
.click();
cy.get('.slick-pager-status')
.contains('Showing page 2 of 1000');
cy.get('#myGrid')
.find('.slick-row')
.each(($row, index) => {
if (index > expectedRows.length - 1) {
return;
}
cy.wrap($row).children('.slick-cell:nth(1)')
.first()
.should('contain', expectedRows[index]);
});
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('on Before Paging Info Changed - Previous Paging:: ', { pageSize: 50, pageNum: 0, totalRows: 50000, totalPages: 1000 });
expect(win.console.log).to.be.calledWith('on After Paging Info Changed - New Paging:: ', { pageSize: 50, pageNum: 1, totalRows: 50000, totalPages: 1000 });
});
});
it('Should display "Showing page 1000 of 1000" text after clicking on last page', () => {
const expectedRows = ['Task 49950', 'Task 49951', 'Task 49952', 'Task 49953', 'Task 49954'];
cy.get('.sgi-chevron-end')
.click();
cy.get('.slick-pager-status')
.contains('Showing page 1000 of 1000');
cy.get('#myGrid')
.find('.slick-row')
.each(($row, index) => {
if (index > expectedRows.length - 1) {
return;
}
cy.wrap($row).children('.slick-cell:nth(1)')
.first()
.should('contain', expectedRows[index]);
});
cy.window().then((win) => {
expect(win.console.log).to.have.callCount(2);
expect(win.console.log).to.be.calledWith('on Before Paging Info Changed - Previous Paging:: ', { pageSize: 50, pageNum: 1, totalRows: 50000, totalPages: 1000 });
expect(win.console.log).to.be.calledWith('on After Paging Info Changed - New Paging:: ', { pageSize: 50, pageNum: 999, totalRows: 50000, totalPages: 1000 });
});
});
it('should expect first row to include "Task 49950" and other specific properties', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 49950');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(2)`).should('contain', '5 days');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(3) .percent-complete-bar`).should('exist');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(4)`).should('contain', '01/01/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(5)`).should('contain', '01/05/2009');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(6)`).find('.sgi.sgi-checkbox-intermediate').should('have.length', 1);
});
});
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}
@@ -0,0 +1,17 @@
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
export default (_on: any, _config: any) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
};
@@ -0,0 +1,75 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
import '@4tw/cypress-drag-drop';
import 'cypress-real-events';
import { convertPosition } from './common';
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Cypress {
interface Chainable {
// triggerHover: (elements: NodeListOf<HTMLElement>) => void;
convertPosition(viewport: string): Chainable<HTMLElement | JQuery<HTMLElement> | { x: string; y: string; }>;
getCell(row: number, col: number, viewport?: string, options?: { parentSelector?: string, rowHeight?: number; }): Chainable<HTMLElement | JQuery<HTMLElement>>;
getNthCell(row: number, nthCol: number, viewport?: string, options?: { parentSelector?: string, rowHeight?: number; }): Chainable<HTMLElement | JQuery<HTMLElement>>;
restoreLocalStorage(): Chainable<HTMLElement | JQuery<HTMLElement>>;
saveLocalStorage(): Chainable<HTMLElement | JQuery<HTMLElement>>;
}
}
}
// convert position like 'topLeft' to the object { x: 'left|right', y: 'top|bottom' }
Cypress.Commands.add('convertPosition', (viewport = 'topLeft') => cy.wrap(convertPosition(viewport)));
Cypress.Commands.add('getCell', (row, col, viewport = 'topLeft', { parentSelector = '', rowHeight = 25 } = {}) => {
const position = convertPosition(viewport);
const canvasSelectorX = position.x ? `.grid-canvas-${position.x}` : '';
const canvasSelectorY = position.y ? `.grid-canvas-${position.y}` : '';
return cy.get(`${parentSelector} ${canvasSelectorX}${canvasSelectorY} [style="top: ${row * rowHeight}px;"] > .slick-cell.l${col}.r${col}`);
});
Cypress.Commands.add('getNthCell', (row, nthCol, viewport = 'topLeft', { parentSelector = '', rowHeight = 25 } = {}) => {
const position = convertPosition(viewport);
const canvasSelectorX = position.x ? `.grid-canvas-${position.x}` : '';
const canvasSelectorY = position.y ? `.grid-canvas-${position.y}` : '';
return cy.get(`${parentSelector} ${canvasSelectorX}${canvasSelectorY} [style="top: ${row * rowHeight}px;"] > .slick-cell:nth(${nthCol})`);
});
const LOCAL_STORAGE_MEMORY = {};
Cypress.Commands.add('saveLocalStorage', () => {
Object.keys(localStorage).forEach(key => {
LOCAL_STORAGE_MEMORY[key] = localStorage[key];
});
});
Cypress.Commands.add('restoreLocalStorage', () => {
Object.keys(LOCAL_STORAGE_MEMORY).forEach(key => {
localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]);
});
});
@@ -0,0 +1,47 @@
/**
* @typedef {('left'|'right')} xAllowed
* @typedef {('top'|'bottom')} yAllowed
*
* Define allowed input position
* @typedef {(xAllowed|yAllowed|'topLeft'|'topRight'|'bottomLeft'|'bottomRight')} AllowedInputPosition
*
* Define position object
* @typedef {Object} Position
* @property {xAllowed} x - horizontal
* @property {yAllowed} y - vertical
*/
/**
* Enum for position values
* @constant
* @enum {(xAllowed|yAllowed)}
*/
const POSITION = Object.freeze({
TOP: 'top',
BOTTOM: 'bottom',
LEFT: 'left',
RIGHT: 'right'
});
/**
* Convert position string to object
*
* @param {AllowedInputPosition} position
* @returns {Position}
*/
export function convertPosition(position) {
let x = '';
let y = '';
const _position = position.toLowerCase();
if (_position.includes(POSITION.LEFT)) {
x = POSITION.LEFT;
} else if (_position.includes(POSITION.RIGHT)) {
x = POSITION.RIGHT;
}
if (_position.includes(POSITION.TOP)) {
y = POSITION.TOP;
} else if (_position.includes(POSITION.BOTTOM)) {
y = POSITION.BOTTOM;
}
return { x, y };
}
@@ -0,0 +1,82 @@
import { convertPosition } from './common';
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Cypress {
interface Chainable {
// triggerHover: (elements: NodeListOf<HTMLElement>) => void;
dragOutside(viewport?: string, ms?: number, px?: number, options?: { parentSelector?: string, scrollbarDimension?: number; rowHeight?: number; }): Chainable<HTMLElement>;
dragStart(options?: { cellWidth?: number; cellHeight?: number; }): Chainable<HTMLElement>;
dragCell(addRow: number, addCell: number, options?: { cellWidth?: number; cellHeight?: number; }): Chainable<HTMLElement>;
dragEnd(gridSelector?: string): Chainable<HTMLElement>;
}
}
}
// @ts-ignore
Cypress.Commands.add('dragStart', { prevSubject: true }, (subject, { cellWidth = 80, cellHeight = 25 } = {}) => {
return cy.wrap(subject).click({ force: true })
.trigger('mousedown', { which: 1 })
.trigger('mousemove', cellWidth / 3, cellHeight / 3);
});
// use a different command name than "drag" so that it doesn't conflict with the "@4tw/cypress-drag-drop" lib
// @ts-ignore
Cypress.Commands.add('dragCell', { prevSubject: true }, (subject, addRow, addCell, { cellWidth = 80, cellHeight = 25 } = {}) => {
return cy.wrap(subject).trigger('mousemove', cellWidth * (addCell + 0.5), cellHeight * (addRow + 0.5), { force: true });
});
Cypress.Commands.add('dragOutside', (viewport = 'topLeft', ms = 0, px = 0, { parentSelector = 'div[class^="slickgrid_"]', scrollbarDimension = 17 } = {}) => {
const $parent = cy.$$(parentSelector);
const gridWidth = $parent.width();
const gridHeight = $parent.height();
let x = gridWidth / 2;
let y = gridHeight / 2;
const position = convertPosition(viewport);
if (position.x === 'left') {
x = -px;
} else if (position.x === 'right') {
x = gridWidth - scrollbarDimension + 3 + px;
}
if (position.y === 'top') {
y = -px;
} else if (position.y === 'bottom') {
y = gridHeight - scrollbarDimension + 3 + px;
}
cy.get(parentSelector).trigger('mousemove', x, y, { force: true });
if (ms) {
cy.wait(ms);
}
return;
});
Cypress.Commands.add('dragEnd', { prevSubject: 'optional' }, (subject, gridSelector = 'div[class^="slickgrid_"]') => {
cy.get(gridSelector).trigger('mouseup', { force: true });
return;
});
export function getScrollDistanceWhenDragOutsideGrid(selector, viewport, dragDirection, fromRow, fromCol, px = 100) {
return (cy as any).convertPosition(viewport).then((_viewportPosition: { x: number; y: number; }) => {
const viewportSelector = `${selector} .slick-viewport-${_viewportPosition.x}.slick-viewport-${_viewportPosition.y}`;
(cy as any).getNthCell(fromRow, fromCol, viewport, { parentSelector: selector })
.dragStart();
return cy.get(viewportSelector).then($viewport => {
const scrollTopBefore = $viewport.scrollTop();
const scrollLeftBefore = $viewport.scrollLeft();
cy.dragOutside(dragDirection, 300, px, { parentSelector: selector });
return cy.get(viewportSelector).then($viewportAfter => {
cy.dragEnd(selector);
const scrollTopAfter = $viewportAfter.scrollTop();
const scrollLeftAfter = $viewportAfter.scrollLeft();
cy.get(viewportSelector).scrollTo(0, 0, { ensureScrollable: false });
return cy.wrap({
scrollTopBefore,
scrollLeftBefore,
scrollTopAfter,
scrollLeftAfter
});
});
});
});
}
@@ -0,0 +1,20 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands';
// Alternatively you can use CommonJS syntax:
// require('./commands')
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "es5",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"lib": ["es5", "dom"],
"types": ["@4tw/cypress-drag-drop", "cypress", "node", "cypress-real-events"],
"jsx": "preserve"
},
"include": ["**/*.ts"]
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,161 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
// src/controls/slick.columnmenu.ts
var BindingEventService = Slick.BindingEventService, SlickEvent = Slick.Event, Utils = Slick.Utils, SlickColumnMenu = class {
constructor(columns, grid, options) {
this.columns = columns;
this.grid = grid;
// --
// public API
__publicField(this, "onColumnsChanged", new SlickEvent("onColumnsChanged"));
// --
// protected props
__publicField(this, "_gridUid");
__publicField(this, "_columnTitleElm");
__publicField(this, "_listElm");
__publicField(this, "_menuElm");
__publicField(this, "_columnCheckboxes", []);
__publicField(this, "_bindingEventService", new BindingEventService());
__publicField(this, "_options");
__publicField(this, "_defaults", {
fadeSpeed: 250,
// the last 2 checkboxes titles
hideForceFitButton: !1,
hideSyncResizeButton: !1,
forceFitTitle: "Force fit columns",
syncResizeTitle: "Synchronous resize",
headerColumnValueExtractor: (columnDef) => Utils.getHtmlStringOutput(columnDef.name || "", "innerHTML")
});
this._gridUid = grid.getUID(), this._options = Utils.extend({}, this._defaults, options), this.init(this.grid);
}
init(grid) {
var _a, _b;
Utils.addSlickEventPubSubWhenDefined(grid.getPubSubService(), this), grid.onHeaderContextMenu.subscribe(this.handleHeaderContextMenu.bind(this)), grid.onColumnsReordered.subscribe(this.updateColumnOrder.bind(this)), this._menuElm = document.createElement("div"), this._menuElm.className = `slick-columnpicker ${this._gridUid}`, this._menuElm.style.display = "none", document.body.appendChild(this._menuElm);
let buttonElm = document.createElement("button");
buttonElm.type = "button", buttonElm.className = "close", buttonElm.dataset.dismiss = "slick-columnpicker", buttonElm.ariaLabel = "Close";
let spanCloseElm = document.createElement("span");
if (spanCloseElm.className = "close", spanCloseElm.ariaHidden = "true", spanCloseElm.textContent = "\xD7", buttonElm.appendChild(spanCloseElm), this._menuElm.appendChild(buttonElm), this._options.columnPickerTitle || (_a = this._options.columnPicker) != null && _a.columnTitle) {
let columnTitle = this._options.columnPickerTitle || ((_b = this._options.columnPicker) == null ? void 0 : _b.columnTitle);
this._columnTitleElm = document.createElement("div"), this._columnTitleElm.className = "slick-gridmenu-custom", this._columnTitleElm.textContent = columnTitle || "", this._menuElm.appendChild(this._columnTitleElm);
}
this._bindingEventService.bind(this._menuElm, "click", this.updateColumn.bind(this)), this._listElm = document.createElement("span"), this._listElm.className = "slick-columnpicker-list", this._bindingEventService.bind(document.body, "mousedown", this.handleBodyMouseDown.bind(this)), this._bindingEventService.bind(document.body, "beforeunload", this.destroy.bind(this));
}
destroy() {
var _a, _b;
this.grid.onHeaderContextMenu.unsubscribe(this.handleHeaderContextMenu.bind(this)), this.grid.onColumnsReordered.unsubscribe(this.updateColumnOrder.bind(this)), this._bindingEventService.unbindAll(), (_a = this._listElm) == null || _a.remove(), (_b = this._menuElm) == null || _b.remove();
}
handleBodyMouseDown(e) {
(this._menuElm !== e.target && !(this._menuElm && this._menuElm.contains(e.target)) || e.target.className === "close") && (this._menuElm.setAttribute("aria-expanded", "false"), this._menuElm.style.display = "none");
}
handleHeaderContextMenu(e) {
var _a, _b, _c, _d, _e, _f;
e.preventDefault(), Utils.emptyElement(this._listElm), this.updateColumnOrder(), this._columnCheckboxes = [];
let columnId, columnLabel, excludeCssClass;
for (let i = 0; i < this.columns.length; i++) {
columnId = this.columns[i].id;
let colName = this.columns[i].name instanceof HTMLElement ? this.columns[i].name.innerHTML : this.columns[i].name || "";
excludeCssClass = this.columns[i].excludeFromColumnPicker ? "hidden" : "";
let liElm = document.createElement("li");
liElm.className = excludeCssClass, liElm.ariaLabel = colName;
let checkboxElm = document.createElement("input");
checkboxElm.type = "checkbox", checkboxElm.id = `${this._gridUid}colpicker-${columnId}`, checkboxElm.dataset.columnid = String(this.columns[i].id), liElm.appendChild(checkboxElm), this._columnCheckboxes.push(checkboxElm), Utils.isDefined(this.grid.getColumnIndex(columnId)) && !this.columns[i].hidden && (checkboxElm.checked = !0), columnLabel = (_b = (_a = this._options) == null ? void 0 : _a.columnPicker) != null && _b.headerColumnValueExtractor ? this._options.columnPicker.headerColumnValueExtractor(this.columns[i], this._options) : this._defaults.headerColumnValueExtractor(this.columns[i], this._options);
let labelElm = document.createElement("label");
labelElm.htmlFor = `${this._gridUid}colpicker-${columnId}`, this.grid.applyHtmlCode(labelElm, columnLabel), liElm.appendChild(labelElm), this._listElm.appendChild(liElm);
}
if (this._options.columnPicker && (!this._options.columnPicker.hideForceFitButton || !this._options.columnPicker.hideSyncResizeButton) && this._listElm.appendChild(document.createElement("hr")), !((_c = this._options.columnPicker) != null && _c.hideForceFitButton)) {
let forceFitTitle = ((_d = this._options.columnPicker) == null ? void 0 : _d.forceFitTitle) || this._options.forceFitTitle, liElm = document.createElement("li");
liElm.ariaLabel = forceFitTitle || "", this._listElm.appendChild(liElm);
let forceFitCheckboxElm = document.createElement("input");
forceFitCheckboxElm.type = "checkbox", forceFitCheckboxElm.id = `${this._gridUid}colpicker-forcefit`, forceFitCheckboxElm.dataset.option = "autoresize", liElm.appendChild(forceFitCheckboxElm);
let labelElm = document.createElement("label");
labelElm.htmlFor = `${this._gridUid}colpicker-forcefit`, labelElm.textContent = forceFitTitle || "", liElm.appendChild(labelElm), this.grid.getOptions().forceFitColumns && (forceFitCheckboxElm.checked = !0);
}
if (!((_e = this._options.columnPicker) != null && _e.hideSyncResizeButton)) {
let syncResizeTitle = ((_f = this._options.columnPicker) == null ? void 0 : _f.syncResizeTitle) || this._options.syncResizeTitle, liElm = document.createElement("li");
liElm.ariaLabel = syncResizeTitle || "", this._listElm.appendChild(liElm);
let syncResizeCheckboxElm = document.createElement("input");
syncResizeCheckboxElm.type = "checkbox", syncResizeCheckboxElm.id = `${this._gridUid}colpicker-syncresize`, syncResizeCheckboxElm.dataset.option = "syncresize", liElm.appendChild(syncResizeCheckboxElm);
let labelElm = document.createElement("label");
labelElm.htmlFor = `${this._gridUid}colpicker-syncresize`, labelElm.textContent = syncResizeTitle || "", liElm.appendChild(labelElm), this.grid.getOptions().syncColumnCellResize && (syncResizeCheckboxElm.checked = !0);
}
this.repositionMenu(e);
}
repositionMenu(event) {
var _a;
let targetEvent = ((_a = event == null ? void 0 : event.touches) == null ? void 0 : _a[0]) || event;
this._menuElm.style.top = `${targetEvent.pageY - 10}px`, this._menuElm.style.left = `${targetEvent.pageX - 10}px`, this._menuElm.style.maxHeight = `${window.innerHeight - targetEvent.clientY}px`, this._menuElm.style.display = "block", this._menuElm.setAttribute("aria-expanded", "true"), this._menuElm.appendChild(this._listElm);
}
updateColumnOrder() {
let current = this.grid.getColumns().slice(0), ordered = new Array(this.columns.length);
for (let i = 0; i < ordered.length; i++)
this.grid.getColumnIndex(this.columns[i].id) === void 0 ? ordered[i] = this.columns[i] : ordered[i] = current.shift();
this.columns = ordered;
}
/** Update the Titles of each sections (command, customTitle, ...) */
updateAllTitles(pickerOptions) {
this.grid.applyHtmlCode(this._columnTitleElm, pickerOptions.columnTitle);
}
updateColumn(e) {
if (e.target.dataset.option === "autoresize") {
let previousVisibleColumns = this.getVisibleColumns(), isChecked = e.target.checked;
this.grid.setOptions({ forceFitColumns: isChecked }), this.grid.setColumns(previousVisibleColumns);
return;
}
if (e.target.dataset.option === "syncresize") {
e.target.checked ? this.grid.setOptions({ syncColumnCellResize: !0 }) : this.grid.setOptions({ syncColumnCellResize: !1 });
return;
}
if (e.target.type === "checkbox") {
let isChecked = e.target.checked, columnId = e.target.dataset.columnid || "", visibleColumns = [];
if (this._columnCheckboxes.forEach((columnCheckbox, idx) => {
this.columns[idx].hidden !== void 0 && (this.columns[idx].hidden = !columnCheckbox.checked), columnCheckbox.checked && visibleColumns.push(this.columns[idx]);
}), !visibleColumns.length) {
e.target.checked = !0;
return;
}
this.grid.setColumns(visibleColumns), this.onColumnsChanged.notify({ columnId, showing: isChecked, allColumns: this.columns, columns: this.columns, visibleColumns, grid: this.grid });
}
}
/** @deprecated because of a typo @use `setColumnVisibility()` instead */
setColumnVisibiliy(idxOrId, show) {
this.setColumnVisibility(idxOrId, show);
}
setColumnVisibility(idxOrId, show) {
let idx = typeof idxOrId == "number" ? idxOrId : this.getColumnIndexbyId(idxOrId), visibleColumns = this.getVisibleColumns(), col = this.columns[idx];
if (show)
col.hidden = !1, visibleColumns.splice(idx, 0, col);
else {
let newVisibleColumns = [];
for (let i = 0; i < visibleColumns.length; i++)
visibleColumns[i].id !== col.id && newVisibleColumns.push(visibleColumns[i]);
visibleColumns = newVisibleColumns;
}
this.grid.setColumns(visibleColumns), this.onColumnsChanged.notify({ columnId: col.id, showing: show, allColumns: this.columns, columns: this.columns, visibleColumns, grid: this.grid });
}
getAllColumns() {
return this.columns;
}
getColumnbyId(id) {
for (let i = 0; i < this.columns.length; i++)
if (this.columns[i].id === id)
return this.columns[i];
return null;
}
getColumnIndexbyId(id) {
for (let i = 0; i < this.columns.length; i++)
if (this.columns[i].id === id)
return i;
return -1;
}
/** visible columns, we can simply get them directly from the grid */
getVisibleColumns() {
return this.grid.getColumns();
}
};
window.Slick && (window.Slick.Controls = window.Slick.Controls || {}, window.Slick.Controls.ColumnPicker = SlickColumnMenu);
})();
//# sourceMappingURL=slick.columnmenu.js.map
@@ -0,0 +1,171 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
// src/controls/slick.columnpicker.ts
var BindingEventService = Slick.BindingEventService, SlickEvent = Slick.Event, Utils = Slick.Utils, SlickColumnPicker = class {
constructor(columns, grid, gridOptions) {
this.columns = columns;
this.grid = grid;
// --
// public API
__publicField(this, "onColumnsChanged", new SlickEvent("onColumnsChanged"));
// --
// protected props
__publicField(this, "_gridUid");
__publicField(this, "_columnTitleElm");
__publicField(this, "_listElm");
__publicField(this, "_menuElm");
__publicField(this, "_columnCheckboxes", []);
__publicField(this, "_bindingEventService", new BindingEventService());
__publicField(this, "_gridOptions");
__publicField(this, "_defaults", {
fadeSpeed: 250,
// the last 2 checkboxes titles
hideForceFitButton: !1,
hideSyncResizeButton: !1,
forceFitTitle: "Force fit columns",
syncResizeTitle: "Synchronous resize",
headerColumnValueExtractor: (columnDef) => Utils.getHtmlStringOutput(columnDef.name || "", "innerHTML")
});
this._gridUid = grid.getUID(), this._gridOptions = Utils.extend({}, this._defaults, gridOptions), this.init(this.grid);
}
init(grid) {
var _a, _b;
Utils.addSlickEventPubSubWhenDefined(grid.getPubSubService(), this), grid.onColumnsReordered.subscribe(this.updateColumnOrder.bind(this)), grid.onHeaderContextMenu.subscribe(this.handleHeaderContextMenu.bind(this)), grid.onPreHeaderContextMenu.subscribe((e) => {
["slick-column-name", "slick-header-column"].some((className) => {
var _a2;
return (_a2 = e.target) == null ? void 0 : _a2.classList.contains(className);
}) && this.handleHeaderContextMenu(e);
}), this._menuElm = document.createElement("div"), this._menuElm.className = `slick-columnpicker ${this._gridUid}`, this._menuElm.style.display = "none", document.body.appendChild(this._menuElm);
let buttonElm = document.createElement("button");
buttonElm.type = "button", buttonElm.className = "close", buttonElm.dataset.dismiss = "slick-columnpicker", buttonElm.ariaLabel = "Close";
let spanCloseElm = document.createElement("span");
if (spanCloseElm.className = "close", spanCloseElm.ariaHidden = "true", spanCloseElm.textContent = "\xD7", buttonElm.appendChild(spanCloseElm), this._menuElm.appendChild(buttonElm), this._gridOptions.columnPickerTitle || (_a = this._gridOptions.columnPicker) != null && _a.columnTitle) {
let columnTitle = this._gridOptions.columnPickerTitle || ((_b = this._gridOptions.columnPicker) == null ? void 0 : _b.columnTitle);
this._columnTitleElm = document.createElement("div"), this._columnTitleElm.className = "slick-gridmenu-custom", this._columnTitleElm.textContent = columnTitle || "", this._menuElm.appendChild(this._columnTitleElm);
}
this._bindingEventService.bind(this._menuElm, "click", this.updateColumn.bind(this)), this._listElm = document.createElement("span"), this._listElm.className = "slick-columnpicker-list", this._bindingEventService.bind(document.body, "mousedown", this.handleBodyMouseDown.bind(this)), this._bindingEventService.bind(document.body, "beforeunload", this.destroy.bind(this));
}
destroy() {
var _a, _b;
this.grid.onPreHeaderContextMenu.unsubscribe(this.handleHeaderContextMenu.bind(this)), this.grid.onHeaderContextMenu.unsubscribe(this.handleHeaderContextMenu.bind(this)), this.grid.onColumnsReordered.unsubscribe(this.updateColumnOrder.bind(this)), this._bindingEventService.unbindAll(), (_a = this._listElm) == null || _a.remove(), (_b = this._menuElm) == null || _b.remove();
}
handleBodyMouseDown(e) {
var _a;
(this._menuElm !== e.target && !((_a = this._menuElm) != null && _a.contains(e.target)) || e.target.className === "close") && (this._menuElm.setAttribute("aria-expanded", "false"), this._menuElm.style.display = "none");
}
handleHeaderContextMenu(e) {
var _a, _b, _c, _d, _e, _f;
e.preventDefault(), Utils.emptyElement(this._listElm), this.updateColumnOrder(), this._columnCheckboxes = [];
let columnId, columnLabel, excludeCssClass;
for (let i = 0; i < this.columns.length; i++) {
columnId = this.columns[i].id;
let colName = this.columns[i].name instanceof HTMLElement ? this.columns[i].name.innerHTML : this.columns[i].name || "";
excludeCssClass = this.columns[i].excludeFromColumnPicker ? "hidden" : "";
let liElm = document.createElement("li");
liElm.className = excludeCssClass, liElm.ariaLabel = colName;
let checkboxElm = document.createElement("input");
checkboxElm.type = "checkbox", checkboxElm.id = `${this._gridUid}colpicker-${columnId}`, checkboxElm.dataset.columnid = String(this.columns[i].id), liElm.appendChild(checkboxElm), this._columnCheckboxes.push(checkboxElm), Utils.isDefined(this.grid.getColumnIndex(columnId)) && !this.columns[i].hidden && (checkboxElm.checked = !0), columnLabel = (_b = (_a = this._gridOptions) == null ? void 0 : _a.columnPicker) != null && _b.headerColumnValueExtractor ? this._gridOptions.columnPicker.headerColumnValueExtractor(this.columns[i], this._gridOptions) : this._defaults.headerColumnValueExtractor(this.columns[i], this._gridOptions);
let labelElm = document.createElement("label");
labelElm.htmlFor = `${this._gridUid}colpicker-${columnId}`, this.grid.applyHtmlCode(labelElm, columnLabel), liElm.appendChild(labelElm), this._listElm.appendChild(liElm);
}
if (this._gridOptions.columnPicker && (!this._gridOptions.columnPicker.hideForceFitButton || !this._gridOptions.columnPicker.hideSyncResizeButton) && this._listElm.appendChild(document.createElement("hr")), !((_c = this._gridOptions.columnPicker) != null && _c.hideForceFitButton)) {
let forceFitTitle = ((_d = this._gridOptions.columnPicker) == null ? void 0 : _d.forceFitTitle) || this._gridOptions.forceFitTitle, liElm = document.createElement("li");
liElm.ariaLabel = forceFitTitle || "", this._listElm.appendChild(liElm);
let forceFitCheckboxElm = document.createElement("input");
forceFitCheckboxElm.type = "checkbox", forceFitCheckboxElm.id = `${this._gridUid}colpicker-forcefit`, forceFitCheckboxElm.dataset.option = "autoresize", liElm.appendChild(forceFitCheckboxElm);
let labelElm = document.createElement("label");
labelElm.htmlFor = `${this._gridUid}colpicker-forcefit`, labelElm.textContent = forceFitTitle || "", liElm.appendChild(labelElm), this.grid.getOptions().forceFitColumns && (forceFitCheckboxElm.checked = !0);
}
if (!((_e = this._gridOptions.columnPicker) != null && _e.hideSyncResizeButton)) {
let syncResizeTitle = ((_f = this._gridOptions.columnPicker) == null ? void 0 : _f.syncResizeTitle) || this._gridOptions.syncResizeTitle, liElm = document.createElement("li");
liElm.ariaLabel = syncResizeTitle || "", this._listElm.appendChild(liElm);
let syncResizeCheckboxElm = document.createElement("input");
syncResizeCheckboxElm.type = "checkbox", syncResizeCheckboxElm.id = `${this._gridUid}colpicker-syncresize`, syncResizeCheckboxElm.dataset.option = "syncresize", liElm.appendChild(syncResizeCheckboxElm);
let labelElm = document.createElement("label");
labelElm.htmlFor = `${this._gridUid}colpicker-syncresize`, labelElm.textContent = syncResizeTitle || "", liElm.appendChild(labelElm), this.grid.getOptions().syncColumnCellResize && (syncResizeCheckboxElm.checked = !0);
}
this.repositionMenu(e);
}
repositionMenu(event) {
var _a, _b;
let targetEvent = (_b = (_a = event == null ? void 0 : event.touches) == null ? void 0 : _a[0]) != null ? _b : event;
if (this._menuElm) {
this._menuElm.style.display = "block";
let gridPos = this.grid.getGridPosition(), menuWidth = this._menuElm.clientWidth || 0, menuOffsetLeft = targetEvent.pageX || 0;
gridPos != null && gridPos.width && menuOffsetLeft + menuWidth >= gridPos.width && (menuOffsetLeft = menuOffsetLeft - menuWidth), this._menuElm.style.top = `${targetEvent.pageY - 10}px`, this._menuElm.style.left = `${menuOffsetLeft}px`, this._menuElm.style.maxHeight = `${window.innerHeight - targetEvent.clientY}px`, this._menuElm.setAttribute("aria-expanded", "true"), this._menuElm.appendChild(this._listElm);
}
}
updateColumnOrder() {
let current = this.grid.getColumns().slice(0), ordered = new Array(this.columns.length);
for (let i = 0; i < ordered.length; i++)
this.grid.getColumnIndex(this.columns[i].id) === void 0 ? ordered[i] = this.columns[i] : ordered[i] = current.shift();
this.columns = ordered;
}
/** Update the Titles of each sections (command, customTitle, ...) */
updateAllTitles(pickerOptions) {
this.grid.applyHtmlCode(this._columnTitleElm, pickerOptions.columnTitle);
}
updateColumn(e) {
if (e.target.dataset.option === "autoresize") {
let previousVisibleColumns = this.getVisibleColumns(), isChecked = e.target.checked || !1;
this.grid.setOptions({ forceFitColumns: isChecked }), this.grid.setColumns(previousVisibleColumns);
return;
}
if (e.target.dataset.option === "syncresize") {
e.target.checked ? this.grid.setOptions({ syncColumnCellResize: !0 }) : this.grid.setOptions({ syncColumnCellResize: !1 });
return;
}
if (e.target.type === "checkbox") {
let isChecked = e.target.checked, columnId = e.target.dataset.columnid || "", visibleColumns = [];
if (this._columnCheckboxes.forEach((columnCheckbox, idx) => {
this.columns[idx].hidden !== void 0 && (this.columns[idx].hidden = !columnCheckbox.checked), columnCheckbox.checked && visibleColumns.push(this.columns[idx]);
}), !visibleColumns.length) {
e.target.checked = !0;
return;
}
this.grid.setColumns(visibleColumns), this.onColumnsChanged.notify({ columnId, showing: isChecked, allColumns: this.columns, columns: this.columns, visibleColumns, grid: this.grid });
}
}
/** @deprecated because of a typo @use `setColumnVisibility()` instead */
setColumnVisibiliy(idxOrId, show) {
this.setColumnVisibility(idxOrId, show);
}
setColumnVisibility(idxOrId, show) {
let idx = typeof idxOrId == "number" ? idxOrId : this.getColumnIndexbyId(idxOrId), visibleColumns = this.getVisibleColumns(), col = this.columns[idx];
if (show)
col.hidden = !1, visibleColumns.splice(idx, 0, col);
else {
let newVisibleColumns = [];
for (let i = 0; i < visibleColumns.length; i++)
visibleColumns[i].id !== col.id && newVisibleColumns.push(visibleColumns[i]);
visibleColumns = newVisibleColumns;
}
this.grid.setColumns(visibleColumns), this.onColumnsChanged.notify({ columnId: col.id, showing: show, allColumns: this.columns, columns: this.columns, visibleColumns, grid: this.grid });
}
getAllColumns() {
return this.columns;
}
getColumnbyId(id) {
for (let i = 0; i < this.columns.length; i++)
if (this.columns[i].id === id)
return this.columns[i];
return null;
}
getColumnIndexbyId(id) {
for (let i = 0; i < this.columns.length; i++)
if (this.columns[i].id === id)
return i;
return -1;
}
/** visible columns, we can simply get them directly from the grid */
getVisibleColumns() {
return this.grid.getColumns();
}
};
window.Slick && (window.Slick.Controls = window.Slick.Controls || {}, window.Slick.Controls.ColumnPicker = SlickColumnPicker);
})();
//# sourceMappingURL=slick.columnpicker.js.map
@@ -0,0 +1,338 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
// src/controls/slick.gridmenu.ts
var BindingEventService = Slick.BindingEventService, SlickEvent = Slick.Event, Utils = Slick.Utils, SlickGridMenu = class {
constructor(columns, grid, gridOptions) {
this.columns = columns;
this.grid = grid;
// --
// public API
__publicField(this, "onAfterMenuShow", new SlickEvent("onAfterMenuShow"));
__publicField(this, "onBeforeMenuShow", new SlickEvent("onBeforeMenuShow"));
__publicField(this, "onMenuClose", new SlickEvent("onMenuClose"));
__publicField(this, "onCommand", new SlickEvent("onCommand"));
__publicField(this, "onColumnsChanged", new SlickEvent("onColumnsChanged"));
// --
// protected props
__publicField(this, "_bindingEventService");
__publicField(this, "_gridOptions");
__publicField(this, "_gridUid");
__publicField(this, "_isMenuOpen", !1);
__publicField(this, "_columnCheckboxes", []);
__publicField(this, "_columnTitleElm");
__publicField(this, "_commandTitleElm");
__publicField(this, "_commandListElm");
__publicField(this, "_headerElm", null);
__publicField(this, "_listElm");
__publicField(this, "_buttonElm");
__publicField(this, "_menuElm");
__publicField(this, "_subMenuParentId", "");
__publicField(this, "_gridMenuOptions", null);
__publicField(this, "_defaults", {
showButton: !0,
hideForceFitButton: !1,
hideSyncResizeButton: !1,
forceFitTitle: "Force fit columns",
marginBottom: 15,
menuWidth: 18,
contentMinWidth: 0,
resizeOnShowHeaderRow: !1,
subMenuOpenByEvent: "mouseover",
syncResizeTitle: "Synchronous resize",
useClickToRepositionMenu: !0,
headerColumnValueExtractor: (columnDef) => Utils.getHtmlStringOutput(columnDef.name || "", "innerHTML")
});
this._gridUid = grid.getUID(), this._gridOptions = gridOptions, this._gridMenuOptions = Utils.extend({}, this._defaults, gridOptions.gridMenu), this._bindingEventService = new BindingEventService(), grid.onSetOptions.subscribe((_e, args) => {
if (args && args.optionsBefore && args.optionsAfter) {
let switchedFromRegularToFrozen = args.optionsBefore.frozenColumn >= 0 && args.optionsAfter.frozenColumn === -1, switchedFromFrozenToRegular = args.optionsBefore.frozenColumn === -1 && args.optionsAfter.frozenColumn >= 0;
(switchedFromRegularToFrozen || switchedFromFrozenToRegular) && this.recreateGridMenu();
}
}), this.init(this.grid);
}
init(grid) {
var _a, _b;
this._gridOptions = grid.getOptions(), Utils.addSlickEventPubSubWhenDefined(grid.getPubSubService(), this), this.createGridMenu(), ((_a = this._gridMenuOptions) != null && _a.customItems || (_b = this._gridMenuOptions) != null && _b.customTitle) && console.warn('[SlickGrid] Grid Menu "customItems" and "customTitle" were deprecated to align with other Menu plugins, please use "commandItems" and "commandTitle" instead.'), grid.onBeforeDestroy.subscribe(this.destroy.bind(this));
}
setOptions(newOptions) {
this._gridMenuOptions = Utils.extend({}, this._gridMenuOptions, newOptions);
}
createGridMenu() {
var _a, _b, _c, _d, _e, _f;
let gridMenuWidth = ((_a = this._gridMenuOptions) == null ? void 0 : _a.menuWidth) || this._defaults.menuWidth;
if (this._gridOptions && this._gridOptions.hasOwnProperty("frozenColumn") && this._gridOptions.frozenColumn >= 0 ? this._headerElm = document.querySelector(`.${this._gridUid} .slick-header-right`) : this._headerElm = document.querySelector(`.${this._gridUid} .slick-header-left`), this._headerElm.style.width = `calc(100% - ${gridMenuWidth}px)`, (Utils.isDefined((_b = this._gridMenuOptions) == null ? void 0 : _b.resizeOnShowHeaderRow) ? this._gridMenuOptions.resizeOnShowHeaderRow : this._defaults.resizeOnShowHeaderRow) && this._gridOptions.showHeaderRow) {
let headerRow = document.querySelector(`.${this._gridUid}.slick-headerrow`);
headerRow && (headerRow.style.width = `calc(100% - ${gridMenuWidth}px)`);
}
if (((_c = this._gridMenuOptions) == null ? void 0 : _c.showButton) !== void 0 ? this._gridMenuOptions.showButton : this._defaults.showButton) {
if (this._buttonElm = document.createElement("button"), this._buttonElm.className = "slick-gridmenu-button", this._buttonElm.ariaLabel = "Grid Menu", (_d = this._gridMenuOptions) != null && _d.iconCssClass)
this._buttonElm.classList.add(...Utils.classNameToList(this._gridMenuOptions.iconCssClass));
else {
let iconImageElm = document.createElement("img");
iconImageElm.src = (_e = this._gridMenuOptions) != null && _e.iconImage ? this._gridMenuOptions.iconImage : "../images/drag-handle.png", this._buttonElm.appendChild(iconImageElm);
}
let buttonContainerTarget = ((_f = this._gridMenuOptions) == null ? void 0 : _f.iconButtonContainer) === "preheader" ? "firstChild" : "lastChild";
this._headerElm.parentElement.insertBefore(this._buttonElm, this._headerElm.parentElement[buttonContainerTarget]), this._bindingEventService.bind(this._buttonElm, "click", this.showGridMenu.bind(this));
}
this._menuElm = this.createMenu(0), this.populateColumnPicker(), document.body.appendChild(this._menuElm), this._bindingEventService.bind(document.body, "mousedown", this.handleBodyMouseDown.bind(this)), this._bindingEventService.bind(document.body, "beforeunload", this.destroy.bind(this));
}
/** Create the menu or sub-menu(s) but without the column picker which is a separate single process */
createMenu(level = 0, item) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
let maxHeight = isNaN((_a = this._gridMenuOptions) == null ? void 0 : _a.maxHeight) ? (_b = this._gridMenuOptions) == null ? void 0 : _b.maxHeight : `${(_d = (_c = this._gridMenuOptions) == null ? void 0 : _c.maxHeight) != null ? _d : 0}px`, width = isNaN((_e = this._gridMenuOptions) == null ? void 0 : _e.width) ? (_f = this._gridMenuOptions) == null ? void 0 : _f.width : `${(_h = (_g = this._gridMenuOptions) == null ? void 0 : _g.maxWidth) != null ? _h : 0}px`, subMenuCommand = item == null ? void 0 : item.command, subMenuId = level === 1 && subMenuCommand ? subMenuCommand.replaceAll(" ", "") : "";
subMenuId && (this._subMenuParentId = subMenuId), level > 1 && (subMenuId = this._subMenuParentId);
let menuClasses = `slick-gridmenu slick-menu-level-${level} ${this._gridUid}`, bodyMenuElm = document.body.querySelector(`.slick-gridmenu.slick-menu-level-${level}${this.getGridUidSelector()}`);
if (bodyMenuElm) {
if (bodyMenuElm.dataset.subMenuParent === subMenuId)
return bodyMenuElm;
this.destroySubMenus();
}
let menuElm = document.createElement("div");
menuElm.role = "menu", menuElm.className = menuClasses, level > 0 && (menuElm.classList.add("slick-submenu"), subMenuId && (menuElm.dataset.subMenuParent = subMenuId)), menuElm.ariaLabel = level > 1 ? "SubMenu" : "Grid Menu", width && (menuElm.style.width = width), maxHeight && (menuElm.style.maxHeight = maxHeight), menuElm.style.display = "none";
let closeButtonElm = null;
if (level === 0) {
closeButtonElm = document.createElement("button"), closeButtonElm.type = "button", closeButtonElm.className = "close", closeButtonElm.dataset.dismiss = "slick-gridmenu", closeButtonElm.ariaLabel = "Close";
let spanCloseElm = document.createElement("span");
spanCloseElm.className = "close", spanCloseElm.ariaHidden = "true", spanCloseElm.textContent = "\xD7", closeButtonElm.appendChild(spanCloseElm), menuElm.appendChild(closeButtonElm);
}
this._commandListElm = document.createElement("div"), this._commandListElm.className = `slick-gridmenu-custom slick-gridmenu-command-list slick-menu-level-${level}`, this._commandListElm.role = "menu", menuElm.appendChild(this._commandListElm);
let commandItems = (_n = (_m = (_k = (_i = item == null ? void 0 : item.commandItems) != null ? _i : item == null ? void 0 : item.customItems) != null ? _k : (_j = this._gridMenuOptions) == null ? void 0 : _j.commandItems) != null ? _m : (_l = this._gridMenuOptions) == null ? void 0 : _l.customItems) != null ? _n : [];
return commandItems.length > 0 && item && level > 0 && this.addSubMenuTitleWhenExists(item, this._commandListElm), this.populateCommandsMenu(commandItems, this._commandListElm, { grid: this.grid, level }), level++, menuElm;
}
/** Destroy the plugin by unsubscribing every events & also delete the menu DOM elements */
destroy() {
var _a;
this.onAfterMenuShow.unsubscribe(), this.onBeforeMenuShow.unsubscribe(), this.onMenuClose.unsubscribe(), this.onCommand.unsubscribe(), this.onColumnsChanged.unsubscribe(), this.grid.onColumnsReordered.unsubscribe(this.updateColumnOrder.bind(this)), this.grid.onBeforeDestroy.unsubscribe(), this.grid.onSetOptions.unsubscribe(), this._bindingEventService.unbindAll(), (_a = this._menuElm) == null || _a.remove(), this.deleteMenu();
}
/** Delete the menu DOM element but without unsubscribing any events */
deleteMenu() {
var _a, _b;
this._bindingEventService.unbindAll();
let gridMenuElm = document.querySelector(`div.slick-gridmenu.${this._gridUid}`);
gridMenuElm && (gridMenuElm.style.display = "none"), this._headerElm && (this._headerElm.style.width = "100%"), (_a = this._buttonElm) == null || _a.remove(), (_b = this._menuElm) == null || _b.remove();
}
/** Close and destroy all previously opened sub-menus */
destroySubMenus() {
this._bindingEventService.unbindAll("sub-menu"), document.querySelectorAll(`.slick-gridmenu.slick-submenu${this.getGridUidSelector()}`).forEach((subElm) => subElm.remove());
}
/** Construct the custom command menu items. */
populateCommandsMenu(commandItems, commandListElm, args) {
var _a, _b, _c, _d;
let level = (args == null ? void 0 : args.level) || 0, isSubMenu = level > 0;
!isSubMenu && ((_a = this._gridMenuOptions) != null && _a.commandTitle || (_b = this._gridMenuOptions) != null && _b.customTitle) && (this._commandTitleElm = document.createElement("div"), this._commandTitleElm.className = "title", this.grid.applyHtmlCode(this._commandTitleElm, this.grid.sanitizeHtmlString(this._gridMenuOptions.commandTitle || this._gridMenuOptions.customTitle)), commandListElm.appendChild(this._commandTitleElm));
for (let i = 0, ln = commandItems.length; i < ln; i++) {
let addClickListener = !0, item = commandItems[i], callbackArgs = {
grid: this.grid,
menu: this._menuElm,
columns: this.columns,
visibleColumns: this.getVisibleColumns()
}, isItemVisible = this.runOverrideFunctionWhenExists(item.itemVisibilityOverride, callbackArgs), isItemUsable = this.runOverrideFunctionWhenExists(item.itemUsabilityOverride, callbackArgs);
if (!isItemVisible)
continue;
Object.prototype.hasOwnProperty.call(item, "itemUsabilityOverride") && (item.disabled = !isItemUsable);
let liElm = document.createElement("div");
liElm.className = "slick-gridmenu-item", liElm.role = "menuitem", (item.divider || item === "divider") && (liElm.classList.add("slick-gridmenu-item-divider"), addClickListener = !1), item.disabled && liElm.classList.add("slick-gridmenu-item-disabled"), item.hidden && liElm.classList.add("slick-gridmenu-item-hidden"), item.cssClass && liElm.classList.add(...Utils.classNameToList(item.cssClass)), item.tooltip && (liElm.title = item.tooltip || "");
let iconElm = document.createElement("div");
iconElm.className = "slick-gridmenu-icon", liElm.appendChild(iconElm), item.iconCssClass && iconElm.classList.add(...Utils.classNameToList(item.iconCssClass)), item.iconImage && (iconElm.style.backgroundImage = `url(${item.iconImage})`);
let textElm = document.createElement("span");
if (textElm.className = "slick-gridmenu-content", this.grid.applyHtmlCode(textElm, this.grid.sanitizeHtmlString(item.title || "")), liElm.appendChild(textElm), item.textCssClass && textElm.classList.add(...Utils.classNameToList(item.textCssClass)), commandListElm.appendChild(liElm), addClickListener) {
let eventGroup = isSubMenu ? "sub-menu" : "parent-menu";
this._bindingEventService.bind(liElm, "click", this.handleMenuItemClick.bind(this, item, level), void 0, eventGroup);
}
if (((_c = this._gridMenuOptions) == null ? void 0 : _c.subMenuOpenByEvent) === "mouseover" && this._bindingEventService.bind(liElm, "mouseover", (e) => {
item.commandItems || item.customItems ? this.repositionSubMenu(item, level, e) : isSubMenu || this.destroySubMenus();
}), item.commandItems || item.customItems) {
let chevronElm = document.createElement("span");
chevronElm.className = "sub-item-chevron", (_d = this._gridMenuOptions) != null && _d.subItemChevronClass ? chevronElm.classList.add(...Utils.classNameToList(this._gridMenuOptions.subItemChevronClass)) : chevronElm.textContent = "\u2B9E", liElm.classList.add("slick-submenu-item"), liElm.appendChild(chevronElm);
continue;
}
}
}
/** Build the column picker, the code comes almost untouched from the file "slick.columnpicker.js" */
populateColumnPicker() {
var _a;
this.grid.onColumnsReordered.subscribe(this.updateColumnOrder.bind(this)), (_a = this._gridMenuOptions) != null && _a.columnTitle && (this._columnTitleElm = document.createElement("div"), this._columnTitleElm.className = "title", this.grid.applyHtmlCode(this._columnTitleElm, this.grid.sanitizeHtmlString(this._gridMenuOptions.columnTitle)), this._menuElm.appendChild(this._columnTitleElm)), this._bindingEventService.bind(this._menuElm, "click", this.updateColumn.bind(this)), this._listElm = document.createElement("span"), this._listElm.className = "slick-gridmenu-list", this._listElm.role = "menu";
}
/** Delete and then Recreate the Grid Menu (for example when we switch from regular to a frozen grid) */
recreateGridMenu() {
this.deleteMenu(), this.init(this.grid);
}
showGridMenu(e) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
let targetEvent = e.touches ? e.touches[0] : e;
e.preventDefault(), Utils.emptyElement(this._listElm), Utils.emptyElement(this._commandListElm);
let commandItems = (_d = (_c = (_a = this._gridMenuOptions) == null ? void 0 : _a.commandItems) != null ? _c : (_b = this._gridMenuOptions) == null ? void 0 : _b.customItems) != null ? _d : [];
this.populateCommandsMenu(commandItems, this._commandListElm, { grid: this.grid, level: 0 }), this.updateColumnOrder(), this._columnCheckboxes = [];
let callbackArgs = {
grid: this.grid,
menu: this._menuElm,
allColumns: this.columns,
visibleColumns: this.getVisibleColumns()
};
if (this._gridMenuOptions && !this.runOverrideFunctionWhenExists(this._gridMenuOptions.menuUsabilityOverride, callbackArgs) || typeof e.stopPropagation == "function" && this.onBeforeMenuShow.notify(callbackArgs, e, this).getReturnValue() === !1)
return;
let columnId, columnLabel, excludeCssClass;
for (let i = 0; i < this.columns.length; i++) {
columnId = this.columns[i].id, excludeCssClass = this.columns[i].excludeFromGridMenu ? "hidden" : "";
let colName = this.columns[i].name instanceof HTMLElement ? this.columns[i].name.innerHTML : this.columns[i].name || "", liElm = document.createElement("li");
liElm.className = excludeCssClass, liElm.ariaLabel = colName;
let checkboxElm = document.createElement("input");
checkboxElm.type = "checkbox", checkboxElm.id = `${this._gridUid}-gridmenu-colpicker-${columnId}`, checkboxElm.dataset.columnid = String(this.columns[i].id), liElm.appendChild(checkboxElm), Utils.isDefined(this.grid.getColumnIndex(this.columns[i].id)) && !this.columns[i].hidden && (checkboxElm.checked = !0), this._columnCheckboxes.push(checkboxElm), columnLabel = (_e = this._gridMenuOptions) != null && _e.headerColumnValueExtractor ? this._gridMenuOptions.headerColumnValueExtractor(this.columns[i], this._gridOptions) : this._defaults.headerColumnValueExtractor(this.columns[i]);
let labelElm = document.createElement("label");
labelElm.htmlFor = `${this._gridUid}-gridmenu-colpicker-${columnId}`, this.grid.applyHtmlCode(labelElm, this.grid.sanitizeHtmlString(Utils.getHtmlStringOutput(columnLabel || ""))), liElm.appendChild(labelElm), this._listElm.appendChild(liElm);
}
if (this._gridMenuOptions && (!this._gridMenuOptions.hideForceFitButton || !this._gridMenuOptions.hideSyncResizeButton) && this._listElm.appendChild(document.createElement("hr")), !((_f = this._gridMenuOptions) != null && _f.hideForceFitButton)) {
let forceFitTitle = ((_g = this._gridMenuOptions) == null ? void 0 : _g.forceFitTitle) || this._defaults.forceFitTitle, liElm = document.createElement("li");
liElm.ariaLabel = forceFitTitle, liElm.role = "menuitem", this._listElm.appendChild(liElm);
let forceFitCheckboxElm = document.createElement("input");
forceFitCheckboxElm.type = "checkbox", forceFitCheckboxElm.id = `${this._gridUid}-gridmenu-colpicker-forcefit`, forceFitCheckboxElm.dataset.option = "autoresize", liElm.appendChild(forceFitCheckboxElm);
let labelElm = document.createElement("label");
labelElm.htmlFor = `${this._gridUid}-gridmenu-colpicker-forcefit`, labelElm.textContent = forceFitTitle, liElm.appendChild(labelElm), this.grid.getOptions().forceFitColumns && (forceFitCheckboxElm.checked = !0);
}
if (!((_h = this._gridMenuOptions) != null && _h.hideSyncResizeButton)) {
let syncResizeTitle = ((_i = this._gridMenuOptions) == null ? void 0 : _i.syncResizeTitle) || this._defaults.syncResizeTitle, liElm = document.createElement("li");
liElm.ariaLabel = syncResizeTitle, this._listElm.appendChild(liElm);
let syncResizeCheckboxElm = document.createElement("input");
syncResizeCheckboxElm.type = "checkbox", syncResizeCheckboxElm.id = `${this._gridUid}-gridmenu-colpicker-syncresize`, syncResizeCheckboxElm.dataset.option = "syncresize", liElm.appendChild(syncResizeCheckboxElm);
let labelElm = document.createElement("label");
labelElm.htmlFor = `${this._gridUid}-gridmenu-colpicker-syncresize`, labelElm.textContent = syncResizeTitle, liElm.appendChild(labelElm), this.grid.getOptions().syncColumnCellResize && (syncResizeCheckboxElm.checked = !0);
}
let buttonElm = e.target.nodeName === "BUTTON" ? e.target : e.target.querySelector("button");
buttonElm || (buttonElm = e.target.parentElement), this._menuElm.style.display = "block", this._menuElm.style.opacity = "0", this.repositionMenu(e, this._menuElm, buttonElm);
let menuMarginBottom = ((_j = this._gridMenuOptions) == null ? void 0 : _j.marginBottom) !== void 0 ? this._gridMenuOptions.marginBottom : this._defaults.marginBottom;
((_k = this._gridMenuOptions) == null ? void 0 : _k.height) !== void 0 ? this._menuElm.style.height = `${this._gridMenuOptions.height}px` : this._menuElm.style.maxHeight = `${window.innerHeight - targetEvent.clientY - menuMarginBottom}px`, this._menuElm.style.display = "block", this._menuElm.style.opacity = "1", this._menuElm.appendChild(this._listElm), this._isMenuOpen = !0, typeof e.stopPropagation == "function" && this.onAfterMenuShow.notify(callbackArgs, e, this).getReturnValue();
}
getGridUidSelector() {
let gridUid = this.grid.getUID() || "";
return gridUid ? `.${gridUid}` : "";
}
handleBodyMouseDown(e) {
var _a;
let isMenuClicked = !1;
(_a = this._menuElm) != null && _a.contains(e.target) && (isMenuClicked = !0), isMenuClicked || document.querySelectorAll(`.slick-gridmenu.slick-submenu${this.getGridUidSelector()}`).forEach((subElm) => {
subElm.contains(e.target) && (isMenuClicked = !0);
}), (this._menuElm !== e.target && !isMenuClicked && !e.defaultPrevented && this._isMenuOpen || e.target.className === "close") && this.hideMenu(e);
}
handleMenuItemClick(item, level = 0, e) {
var _a;
if (item !== "divider" && !item.disabled && !item.divider) {
let command = item.command || "";
if (Utils.isDefined(command) && !item.commandItems && !item.customItems) {
let callbackArgs = {
grid: this.grid,
command,
item,
allColumns: this.columns,
visibleColumns: this.getVisibleColumns()
};
this.onCommand.notify(callbackArgs, e, this), typeof item.action == "function" && item.action.call(this, e, callbackArgs), !!!((_a = this._gridMenuOptions) != null && _a.leaveOpen) && !e.defaultPrevented && this.hideMenu(e), e.preventDefault(), e.stopPropagation();
} else item.commandItems || item.customItems ? this.repositionSubMenu(item, level, e) : this.destroySubMenus();
}
}
hideMenu(e) {
if (this._menuElm) {
let callbackArgs = {
grid: this.grid,
menu: this._menuElm,
allColumns: this.columns,
visibleColumns: this.getVisibleColumns()
};
if (this._isMenuOpen && this.onMenuClose.notify(callbackArgs, e, this).getReturnValue() === !1)
return;
this._isMenuOpen = !1, Utils.hide(this._menuElm);
}
this.destroySubMenus();
}
/** Update the Titles of each sections (command, commandTitle, ...) */
updateAllTitles(gridMenuOptions) {
this._commandTitleElm && this.grid.applyHtmlCode(this._commandTitleElm, this.grid.sanitizeHtmlString(gridMenuOptions.commandTitle || gridMenuOptions.customTitle || "")), this._columnTitleElm && this.grid.applyHtmlCode(this._columnTitleElm, this.grid.sanitizeHtmlString(gridMenuOptions.columnTitle || ""));
}
addSubMenuTitleWhenExists(item, commandOrOptionMenu) {
if (item !== "divider" && (item != null && item.subMenuTitle)) {
let subMenuTitleElm = document.createElement("div");
subMenuTitleElm.className = "slick-menu-title", subMenuTitleElm.textContent = item.subMenuTitle;
let subMenuTitleClass = item.subMenuTitleCssClass;
subMenuTitleClass && subMenuTitleElm.classList.add(...Utils.classNameToList(subMenuTitleClass)), commandOrOptionMenu.appendChild(subMenuTitleElm);
}
}
repositionSubMenu(item, level, e) {
e.target.classList.contains("slick-cell") && this.destroySubMenus();
let subMenuElm = this.createMenu(level + 1, item);
subMenuElm.style.display = "block", document.body.appendChild(subMenuElm), this.repositionMenu(e, subMenuElm);
}
/**
* Reposition the menu drop (up/down) and the side (left/right)
* @param {*} event
*/
repositionMenu(e, menuElm, buttonElm) {
var _a, _b, _c, _d;
let targetEvent = e.touches ? e.touches[0] : e, isSubMenu = menuElm.classList.contains("slick-submenu"), parentElm = isSubMenu ? e.target.closest(".slick-gridmenu-item") : targetEvent.target, menuIconOffset = Utils.offset(buttonElm || this._buttonElm), menuWidth = menuElm.offsetWidth, useClickToRepositionMenu = ((_a = this._gridMenuOptions) == null ? void 0 : _a.useClickToRepositionMenu) !== void 0 ? this._gridMenuOptions.useClickToRepositionMenu : this._defaults.useClickToRepositionMenu, contentMinWidth = (_b = this._gridMenuOptions) != null && _b.contentMinWidth ? this._gridMenuOptions.contentMinWidth : this._defaults.contentMinWidth, currentMenuWidth = contentMinWidth > menuWidth ? contentMinWidth : menuWidth + 5, menuOffsetTop = useClickToRepositionMenu && targetEvent.pageY > 0 ? targetEvent.pageY : menuIconOffset.top + 10, menuOffsetLeft = useClickToRepositionMenu && targetEvent.pageX > 0 ? targetEvent.pageX : menuIconOffset.left + 10;
if (isSubMenu && parentElm) {
let parentOffset = Utils.offset(parentElm);
menuOffsetLeft = (_c = parentOffset == null ? void 0 : parentOffset.left) != null ? _c : 0, menuOffsetTop = (_d = parentOffset == null ? void 0 : parentOffset.top) != null ? _d : 0;
let gridPos = this.grid.getGridPosition(), subMenuPosCalc = menuOffsetLeft + Number(menuWidth);
isSubMenu && (subMenuPosCalc += parentElm.clientWidth);
let browserWidth = document.documentElement.clientWidth;
(subMenuPosCalc >= gridPos.width || subMenuPosCalc >= browserWidth ? "left" : "right") === "left" ? (menuElm.classList.remove("dropright"), menuElm.classList.add("dropleft"), menuOffsetLeft -= menuWidth) : (menuElm.classList.remove("dropleft"), menuElm.classList.add("dropright"), isSubMenu && (menuOffsetLeft += parentElm.offsetWidth));
} else
menuOffsetTop += 10, menuOffsetLeft = menuOffsetLeft - currentMenuWidth + 10;
menuElm.style.top = `${menuOffsetTop}px`, menuElm.style.left = `${menuOffsetLeft}px`, contentMinWidth > 0 && (this._menuElm.style.minWidth = `${contentMinWidth}px`);
}
updateColumnOrder() {
let current = this.grid.getColumns().slice(0), ordered = new Array(this.columns.length);
for (let i = 0; i < ordered.length; i++)
this.grid.getColumnIndex(this.columns[i].id) === void 0 ? ordered[i] = this.columns[i] : ordered[i] = current.shift();
this.columns = ordered;
}
updateColumn(e) {
if (e.target.dataset.option === "autoresize") {
let previousVisibleColumns = this.getVisibleColumns(), isChecked = e.target.checked;
this.grid.setOptions({ forceFitColumns: isChecked }), this.grid.setColumns(previousVisibleColumns);
return;
}
if (e.target.dataset.option === "syncresize") {
this.grid.setOptions({ syncColumnCellResize: !!e.target.checked });
return;
}
if (e.target.type === "checkbox") {
let isChecked = e.target.checked, columnId = e.target.dataset.columnid || "", visibleColumns = [];
if (this._columnCheckboxes.forEach((columnCheckbox, idx) => {
columnCheckbox.checked && (this.columns[idx].hidden && (this.columns[idx].hidden = !1), visibleColumns.push(this.columns[idx]));
}), !visibleColumns.length) {
e.target.checked = !0;
return;
}
let callbackArgs = {
columnId,
showing: isChecked,
grid: this.grid,
allColumns: this.columns,
columns: visibleColumns,
visibleColumns: this.getVisibleColumns()
};
this.grid.setColumns(visibleColumns), this.onColumnsChanged.notify(callbackArgs, e, this);
}
}
getAllColumns() {
return this.columns;
}
/** visible columns, we can simply get them directly from the grid */
getVisibleColumns() {
return this.grid.getColumns();
}
/**
* Method that user can pass to override the default behavior.
* In order word, user can choose or an item is (usable/visible/enable) by providing his own logic.
* @param overrideFn: override function callback
* @param args: multiple arguments provided to the override (cell, row, columnDef, dataContext, grid)
*/
runOverrideFunctionWhenExists(overrideFn, args) {
return typeof overrideFn == "function" ? overrideFn.call(this, args) : !0;
}
};
window.Slick && (window.Slick.Controls = window.Slick.Controls || {}, window.Slick.Controls.GridMenu = SlickGridMenu);
})();
//# sourceMappingURL=slick.gridmenu.js.map
@@ -0,0 +1,133 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
// src/controls/slick.pager.ts
var BindingEventService = Slick.BindingEventService, SlickGlobalEditorLock = Slick.GlobalEditorLock, Utils = Slick.Utils, SlickGridPager = class {
constructor(dataView, grid, selectorOrElm, options) {
this.dataView = dataView;
this.grid = grid;
// --
// public API
// --
// protected props
__publicField(this, "_container");
// the container might be a string, a jQuery object or a native element
__publicField(this, "_statusElm");
__publicField(this, "_bindingEventService");
__publicField(this, "_options");
__publicField(this, "_defaults", {
showAllText: "Showing all {rowCount} rows",
showPageText: "Showing page {pageNum} of {pageCount}",
showCountText: "From {countBegin} to {countEnd} of {rowCount} rows",
showCount: !1,
pagingOptions: [
{ data: 0, name: "All", ariaLabel: "Show All Pages" },
{ data: -1, name: "Auto", ariaLabel: "Auto Page Size" },
{ data: 25, name: "25", ariaLabel: "Show 25 rows per page" },
{ data: 50, name: "50", ariaLabel: "Show 50 rows per page" },
{ data: 100, name: "100", ariaLabel: "Show 100 rows per page" }
],
showPageSizes: !1
});
this._container = this.getContainerElement(selectorOrElm), this._options = Utils.extend(!0, {}, this._defaults, options), this._bindingEventService = new BindingEventService(), this.init();
}
init() {
this.constructPagerUI(), this.updatePager(this.dataView.getPagingInfo()), this.dataView.onPagingInfoChanged.subscribe((_e, pagingInfo) => {
this.updatePager(pagingInfo);
});
}
/** Destroy function when element is destroyed */
destroy() {
this.setPageSize(0), this._bindingEventService.unbindAll(), Utils.emptyElement(this._container);
}
getNavState() {
let cannotLeaveEditMode = !SlickGlobalEditorLock.commitCurrentEdit(), pagingInfo = this.dataView.getPagingInfo(), lastPage = pagingInfo.totalPages - 1;
return {
canGotoFirst: !cannotLeaveEditMode && pagingInfo.pageSize !== 0 && pagingInfo.pageNum > 0,
canGotoLast: !cannotLeaveEditMode && pagingInfo.pageSize !== 0 && pagingInfo.pageNum !== lastPage,
canGotoPrev: !cannotLeaveEditMode && pagingInfo.pageSize !== 0 && pagingInfo.pageNum > 0,
canGotoNext: !cannotLeaveEditMode && pagingInfo.pageSize !== 0 && pagingInfo.pageNum < lastPage,
pagingInfo
};
}
setPageSize(n) {
this.dataView.setRefreshHints({
isFilterUnchanged: !0
}), this.dataView.setPagingOptions({ pageSize: n });
}
gotoFirst() {
this.getNavState().canGotoFirst && this.dataView.setPagingOptions({ pageNum: 0 });
}
gotoLast() {
let state = this.getNavState();
state.canGotoLast && this.dataView.setPagingOptions({ pageNum: state.pagingInfo.totalPages - 1 });
}
gotoPrev() {
let state = this.getNavState();
state.canGotoPrev && this.dataView.setPagingOptions({ pageNum: state.pagingInfo.pageNum - 1 });
}
gotoNext() {
let state = this.getNavState();
state.canGotoNext && this.dataView.setPagingOptions({ pageNum: state.pagingInfo.pageNum + 1 });
}
getContainerElement(selectorOrElm) {
return typeof selectorOrElm == "string" ? document.querySelector(selectorOrElm) : typeof selectorOrElm == "object" && selectorOrElm[0] ? selectorOrElm[0] : selectorOrElm;
}
constructPagerUI() {
let container = this.getContainerElement(this._container);
if (!container || container.jquery && !container[0])
return;
let navElm = document.createElement("span");
navElm.className = "slick-pager-nav";
let settingsElm = document.createElement("span");
settingsElm.className = "slick-pager-settings", this._statusElm = document.createElement("span"), this._statusElm.className = "slick-pager-status";
let pagerSettingsElm = document.createElement("span");
pagerSettingsElm.className = "slick-pager-settings-expanded", pagerSettingsElm.textContent = "Show: ";
for (let o = 0; o < this._options.pagingOptions.length; o++) {
let p = this._options.pagingOptions[o], anchorElm = document.createElement("a");
anchorElm.textContent = p.name, anchorElm.ariaLabel = p.ariaLabel, anchorElm.dataset.val = String(p.data), pagerSettingsElm.appendChild(anchorElm), this._bindingEventService.bind(anchorElm, "click", (e) => {
let pagesize = e.target.dataset.val;
if (pagesize !== void 0)
if (Number(pagesize) === -1) {
let vp = this.grid.getViewport();
this.setPageSize(vp.bottom - vp.top);
} else
this.setPageSize(parseInt(pagesize));
});
}
pagerSettingsElm.style.display = this._options.showPageSizes ? "block" : "none", settingsElm.appendChild(pagerSettingsElm);
let displayPaginationContainer = document.createElement("span"), displayIconElm = document.createElement("span");
displayPaginationContainer.className = "sgi-container", displayIconElm.ariaLabel = "Show Pagination Options", displayIconElm.role = "button", displayIconElm.className = "sgi sgi-lightbulb", displayPaginationContainer.appendChild(displayIconElm), this._bindingEventService.bind(displayIconElm, "click", () => {
let styleDisplay = pagerSettingsElm.style.display;
pagerSettingsElm.style.display = styleDisplay === "none" ? "inline-flex" : "none";
}), settingsElm.appendChild(displayPaginationContainer), [
{ key: "start", ariaLabel: "First Page", callback: this.gotoFirst },
{ key: "left", ariaLabel: "Previous Page", callback: this.gotoPrev },
{ key: "right", ariaLabel: "Next Page", callback: this.gotoNext },
{ key: "end", ariaLabel: "Last Page", callback: this.gotoLast }
].forEach((pageBtn) => {
let iconElm = document.createElement("span");
iconElm.className = "sgi-container";
let innerIconElm = document.createElement("span");
innerIconElm.role = "button", innerIconElm.ariaLabel = pageBtn.ariaLabel, innerIconElm.className = `sgi sgi-chevron-${pageBtn.key}`, this._bindingEventService.bind(innerIconElm, "click", pageBtn.callback.bind(this)), iconElm.appendChild(innerIconElm), navElm.appendChild(iconElm);
});
let slickPagerElm = document.createElement("div");
slickPagerElm.className = "slick-pager", slickPagerElm.appendChild(navElm), slickPagerElm.appendChild(this._statusElm), slickPagerElm.appendChild(settingsElm), container.appendChild(slickPagerElm);
}
updatePager(pagingInfo) {
var _a, _b, _c, _d;
if (!this._container || this._container.jquery && !this._container[0])
return;
let state = this.getNavState();
if (this._container.querySelectorAll(".slick-pager-nav span").forEach((pagerIcon) => pagerIcon.classList.remove("sgi-state-disabled")), state.canGotoFirst || (_a = this._container.querySelector(".sgi-chevron-start")) == null || _a.classList.add("sgi-state-disabled"), state.canGotoLast || (_b = this._container.querySelector(".sgi-chevron-end")) == null || _b.classList.add("sgi-state-disabled"), state.canGotoNext || (_c = this._container.querySelector(".sgi-chevron-right")) == null || _c.classList.add("sgi-state-disabled"), state.canGotoPrev || (_d = this._container.querySelector(".sgi-chevron-left")) == null || _d.classList.add("sgi-state-disabled"), pagingInfo.pageSize === 0 ? this._statusElm.textContent = this._options.showAllText.replace("{rowCount}", pagingInfo.totalRows + "").replace("{pageCount}", pagingInfo.totalPages + "") : this._statusElm.textContent = this._options.showPageText.replace("{pageNum}", pagingInfo.pageNum + 1 + "").replace("{pageCount}", pagingInfo.totalPages + ""), this._options.showCount && pagingInfo.pageSize !== 0) {
let pageBegin = pagingInfo.pageNum * pagingInfo.pageSize, currentText = this._statusElm.textContent;
currentText && (currentText += " - "), this._statusElm.textContent = currentText + this._options.showCountText.replace("{rowCount}", String(pagingInfo.totalRows)).replace("{countBegin}", String(pageBegin + 1)).replace("{countEnd}", String(Math.min(pageBegin + pagingInfo.pageSize, pagingInfo.totalRows)));
}
}
};
window.Slick && (window.Slick.Controls = window.Slick.Controls || {}, window.Slick.Controls.Pager = SlickGridPager);
})();
//# sourceMappingURL=slick.pager.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["../../src/slick.formatters.ts"],
"sourcesContent": ["import type { Formatter } from './models/index.js';\r\nimport { Utils as Utils_ } from './slick.core.js';\r\n\r\n// for (iife) load Slick methods from global Slick object, or use imports for (esm)\r\nconst Utils = IIFE_ONLY ? Slick.Utils : Utils_;\r\n\r\n/***\r\n * Contains basic SlickGrid formatters.\r\n *\r\n * NOTE: These are merely examples. You will most likely need to implement something more\r\n * robust/extensible/localizable/etc. for your use!\r\n *\r\n * @module Formatters\r\n * @namespace Slick\r\n */\r\n\r\nexport const PercentCompleteFormatter: Formatter = (_row, _cell, value) => {\r\n if (!Utils.isDefined(value) || value === '') {\r\n return '-';\r\n } else if (value < 50) {\r\n return `<span style=\"color:red;font-weight:bold;\">${value}%</span>`;\r\n } else {\r\n return `<span style=\"color:green\">${value}%</span>`;\r\n }\r\n};\r\n\r\nexport const PercentCompleteBarFormatter: Formatter = (_row, _cell, value) => {\r\n if (!Utils.isDefined(value) || value === '') {\r\n return '';\r\n }\r\n\r\n let color;\r\n\r\n if (value < 30) {\r\n color = 'red';\r\n } else if (value < 70) {\r\n color = 'silver';\r\n } else {\r\n color = 'green';\r\n }\r\n\r\n return `<span class=\"percent-complete-bar\" style=\"background:${color};width:${value}%\" title=\"${value}%\"></span>`;\r\n};\r\n\r\nexport const YesNoFormatter: Formatter = (_row, _cell, value) => {\r\n return value ? 'Yes' : 'No';\r\n};\r\n\r\nexport const CheckboxFormatter: Formatter = (_row, _cell, value) => {\r\n return `<span class=\"sgi sgi-checkbox-${value ? 'intermediate' : 'blank-outline'}\"></span>`;\r\n};\r\n\r\nexport const CheckmarkFormatter: Formatter = (_row, _cell, value) => {\r\n return value ? `<span class=\"sgi sgi-check\"></span>` : '';\r\n};\r\n\r\nexport const Formatters = {\r\n PercentComplete: PercentCompleteFormatter,\r\n PercentCompleteBar: PercentCompleteBarFormatter,\r\n YesNo: YesNoFormatter,\r\n Checkmark: CheckmarkFormatter,\r\n Checkbox: CheckboxFormatter\r\n};\r\n\r\n// extend Slick namespace on window object when building as iife\r\nif (IIFE_ONLY && window.Slick) {\r\n Utils.extend(Slick, {\r\n Formatters\r\n });\r\n}\r\n\r\n"],
"mappings": ";;;AAIA,MAAM,QAAoB,MAAM,OAYnB,2BAAsC,CAAC,MAAM,OAAO,UAC3D,CAAC,MAAM,UAAU,KAAK,KAAK,UAAU,KAChC,MACE,QAAQ,KACV,6CAA6C,KAAK,aAElD,6BAA6B,KAAK,YAIhC,8BAAyC,CAAC,MAAM,OAAO,UAAU;AAC5E,QAAI,CAAC,MAAM,UAAU,KAAK,KAAK,UAAU;AACvC,aAAO;AAGT,QAAI;AAEJ,WAAI,QAAQ,KACV,QAAQ,QACC,QAAQ,KACjB,QAAQ,WAER,QAAQ,SAGH,wDAAwD,KAAK,UAAU,KAAK,aAAa,KAAK;AAAA,EACvG,GAEa,iBAA4B,CAAC,MAAM,OAAO,UAC9C,QAAQ,QAAQ,MAGZ,oBAA+B,CAAC,MAAM,OAAO,UACjD,iCAAiC,QAAQ,iBAAiB,eAAe,aAGrE,qBAAgC,CAAC,MAAM,OAAO,UAClD,QAAQ,wCAAwC,IAG5C,aAAa;AAAA,IACxB,iBAAiB;AAAA,IACjB,oBAAoB;AAAA,IACpB,OAAO;AAAA,IACP,WAAW;AAAA,IACX,UAAU;AAAA,EACZ;AAGA,EAAiB,OAAO,SACtB,MAAM,OAAO,OAAO;AAAA,IAClB;AAAA,EACF,CAAC;",
"names": []
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["../../src/slick.remotemodel.ts"],
"sourcesContent": ["import type { ColumnSort } from './models/index.js';\r\n\r\n/***\r\n * A sample AJAX data store implementation.\r\n * Right now, it's hooked up to load search results from Octopart, but can\r\n * easily be extended to support any JSONP-compatible backend that accepts paging parameters.\r\n */\r\nexport class SlickRemoteModel {\r\n // private\r\n protected PAGESIZE = 50;\r\n protected data: any = { length: 0 };\r\n protected searchstr = '';\r\n protected sortcol: ColumnSort | null = null;\r\n protected sortdir = 1;\r\n protected h_request?: number;\r\n protected req: any = null; // ajax request\r\n\r\n // events\r\n onDataLoading = new Slick.Event('onDataLoading');\r\n onDataLoaded = new Slick.Event('onDataLoaded');\r\n\r\n constructor() {\r\n if (!(window.$ || window.jQuery) || !window.$.jsonp) {\r\n throw new Error('SlickRemoteModel requires both jQuery and jQuery jsonp library to be loaded.');\r\n }\r\n this.init();\r\n }\r\n\r\n init() { }\r\n\r\n isDataLoaded(from: number, to: number) {\r\n for (let i = from; i <= to; i++) {\r\n if (this.data[i] === undefined || this.data[i] === null) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n clear() {\r\n for (const key in this.data) {\r\n delete this.data[key];\r\n }\r\n this.data.length = 0;\r\n }\r\n\r\n ensureData(from: number, to: number) {\r\n if (this.req) {\r\n this.req.abort();\r\n for (let i = this.req.fromPage; i <= this.req.toPage; i++) {\r\n this.data[i * this.PAGESIZE] = undefined;\r\n }\r\n }\r\n\r\n if (from < 0) {\r\n from = 0;\r\n }\r\n\r\n if (this.data.length > 0) {\r\n to = Math.min(to, this.data.length - 1);\r\n }\r\n\r\n let fromPage = Math.floor(from / this.PAGESIZE);\r\n let toPage = Math.floor(to / this.PAGESIZE);\r\n\r\n while (this.data[fromPage * this.PAGESIZE] !== undefined && fromPage < toPage) {\r\n fromPage++;\r\n }\r\n\r\n while (this.data[toPage * this.PAGESIZE] !== undefined && fromPage < toPage) {\r\n toPage--;\r\n }\r\n\r\n if (fromPage > toPage || ((fromPage === toPage) && this.data[fromPage * this.PAGESIZE] !== undefined)) {\r\n // TODO: look-ahead\r\n this.onDataLoaded.notify({ from, to });\r\n return;\r\n }\r\n\r\n let url = 'http://octopart.com/api/v3/parts/search?apikey=68b25f31&include[]=short_description&show[]=uid&show[]=manufacturer&show[]=mpn&show[]=brand&show[]=octopart_url&show[]=short_description&q=' + this.searchstr + '&start=' + (fromPage * this.PAGESIZE) + '&limit=' + (((toPage - fromPage) * this.PAGESIZE) + this.PAGESIZE);\r\n\r\n if (this.sortcol !== null) {\r\n url += ('&sortby=' + this.sortcol + ((this.sortdir > 0) ? '+asc' : '+desc'));\r\n }\r\n\r\n if (this.h_request) {\r\n window.clearTimeout(this.h_request);\r\n }\r\n\r\n this.h_request = window.setTimeout(() => {\r\n for (let i = fromPage; i <= toPage; i++) {\r\n this.data[i * this.PAGESIZE] = null; // null indicates a 'requested but not available yet'\r\n }\r\n this.onDataLoading.notify({ from, to });\r\n\r\n this.req = window.$.jsonp({\r\n url,\r\n callbackParameter: 'callback',\r\n cache: true,\r\n success: this.onSuccess,\r\n error: () => this.onError(fromPage, toPage)\r\n });\r\n this.req.fromPage = fromPage;\r\n this.req.toPage = toPage;\r\n }, 50);\r\n }\r\n\r\n protected onError(fromPage: number | string, toPage: number | string) {\r\n alert('error loading pages ' + fromPage + ' to ' + toPage);\r\n }\r\n\r\n protected onSuccess(resp: any) {\r\n const from = resp.request.start, to = from + resp.results.length;\r\n this.data.length = Math.min(parseInt(resp.hits), 1000); // limitation of the API\r\n\r\n for (let i = 0; i < resp.results.length; i++) {\r\n const item = resp.results[i].item;\r\n this.data[from + i] = item;\r\n this.data[from + i].index = from + i;\r\n }\r\n\r\n this.req = null;\r\n this.onDataLoaded.notify({ from, to });\r\n }\r\n\r\n reloadData(from: number, to: number) {\r\n for (let i = from; i <= to; i++) {\r\n delete this.data[i];\r\n }\r\n this.ensureData(from, to);\r\n }\r\n\r\n\r\n setSort(column: ColumnSort, dir: number) {\r\n this.sortcol = column;\r\n this.sortdir = dir;\r\n this.clear();\r\n }\r\n\r\n setSearch(str: string) {\r\n this.searchstr = str;\r\n this.clear();\r\n }\r\n}\r\n\r\n// extend Slick namespace on window object when building as iife\r\nif (IIFE_ONLY && window.Slick) {\r\n window.Slick.Data = window.Slick.Data || {};\r\n window.Slick.Data.RemoteModel = SlickRemoteModel;\r\n}"],
"mappings": ";;;;;;;AAOO,MAAM,mBAAN,MAAuB;AAAA,IAc5B,cAAc;AAZd;AAAA,0BAAU,YAAW;AACrB,0BAAU,QAAY,EAAE,QAAQ,EAAE;AAClC,0BAAU,aAAY;AACtB,0BAAU,WAA6B;AACvC,0BAAU,WAAU;AACpB,0BAAU;AACV,0BAAU,OAAW;AAGrB;AAAA;AAAA,2CAAgB,IAAI,MAAM,MAAM,eAAe;AAC/C,0CAAe,IAAI,MAAM,MAAM,cAAc;AAG3C,UAAI,EAAE,OAAO,KAAK,OAAO,WAAW,CAAC,OAAO,EAAE;AAC5C,cAAM,IAAI,MAAM,8EAA8E;AAEhG,WAAK,KAAK;AAAA,IACZ;AAAA,IAEA,OAAO;AAAA,IAAE;AAAA,IAET,aAAa,MAAc,IAAY;AACrC,eAAS,IAAI,MAAM,KAAK,IAAI;AAC1B,YAAI,KAAK,KAAK,CAAC,MAAM,UAAa,KAAK,KAAK,CAAC,MAAM;AACjD,iBAAO;AAIX,aAAO;AAAA,IACT;AAAA,IAEA,QAAQ;AACN,eAAW,OAAO,KAAK;AACrB,eAAO,KAAK,KAAK,GAAG;AAEtB,WAAK,KAAK,SAAS;AAAA,IACrB;AAAA,IAEA,WAAW,MAAc,IAAY;AACnC,UAAI,KAAK,KAAK;AACZ,aAAK,IAAI,MAAM;AACf,iBAAS,IAAI,KAAK,IAAI,UAAU,KAAK,KAAK,IAAI,QAAQ;AACpD,eAAK,KAAK,IAAI,KAAK,QAAQ,IAAI;AAAA,MAEnC;AAEA,MAAI,OAAO,MACT,OAAO,IAGL,KAAK,KAAK,SAAS,MACrB,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,CAAC;AAGxC,UAAI,WAAW,KAAK,MAAM,OAAO,KAAK,QAAQ,GAC1C,SAAS,KAAK,MAAM,KAAK,KAAK,QAAQ;AAE1C,aAAO,KAAK,KAAK,WAAW,KAAK,QAAQ,MAAM,UAAa,WAAW;AACrE;AAGF,aAAO,KAAK,KAAK,SAAS,KAAK,QAAQ,MAAM,UAAa,WAAW;AACnE;AAGF,UAAI,WAAW,UAAY,aAAa,UAAW,KAAK,KAAK,WAAW,KAAK,QAAQ,MAAM,QAAY;AAErG,aAAK,aAAa,OAAO,EAAE,MAAM,GAAG,CAAC;AACrC;AAAA,MACF;AAEA,UAAI,MAAM,+LAA+L,KAAK,YAAY,YAAa,WAAW,KAAK,WAAY,cAAe,SAAS,YAAY,KAAK,WAAY,KAAK;AAE7T,MAAI,KAAK,YAAY,SACnB,OAAQ,aAAa,KAAK,WAAY,KAAK,UAAU,IAAK,SAAS,WAGjE,KAAK,aACP,OAAO,aAAa,KAAK,SAAS,GAGpC,KAAK,YAAY,OAAO,WAAW,MAAM;AACvC,iBAAS,IAAI,UAAU,KAAK,QAAQ;AAClC,eAAK,KAAK,IAAI,KAAK,QAAQ,IAAI;AAEjC,aAAK,cAAc,OAAO,EAAE,MAAM,GAAG,CAAC,GAEtC,KAAK,MAAM,OAAO,EAAE,MAAM;AAAA,UACxB;AAAA,UACA,mBAAmB;AAAA,UACnB,OAAO;AAAA,UACP,SAAS,KAAK;AAAA,UACd,OAAO,MAAM,KAAK,QAAQ,UAAU,MAAM;AAAA,QAC5C,CAAC,GACD,KAAK,IAAI,WAAW,UACpB,KAAK,IAAI,SAAS;AAAA,MACpB,GAAG,EAAE;AAAA,IACP;AAAA,IAEU,QAAQ,UAA2B,QAAyB;AACpE,YAAM,yBAAyB,WAAW,SAAS,MAAM;AAAA,IAC3D;AAAA,IAEU,UAAU,MAAW;AAC7B,UAAM,OAAO,KAAK,QAAQ,OAAO,KAAK,OAAO,KAAK,QAAQ;AAC1D,WAAK,KAAK,SAAS,KAAK,IAAI,SAAS,KAAK,IAAI,GAAG,GAAI;AAErD,eAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,QAAQ,KAAK;AAC5C,YAAM,OAAO,KAAK,QAAQ,CAAC,EAAE;AAC7B,aAAK,KAAK,OAAO,CAAC,IAAI,MACtB,KAAK,KAAK,OAAO,CAAC,EAAE,QAAQ,OAAO;AAAA,MACrC;AAEA,WAAK,MAAM,MACX,KAAK,aAAa,OAAO,EAAE,MAAM,GAAG,CAAC;AAAA,IACvC;AAAA,IAEA,WAAW,MAAc,IAAY;AACnC,eAAS,IAAI,MAAM,KAAK,IAAI;AAC1B,eAAO,KAAK,KAAK,CAAC;AAEpB,WAAK,WAAW,MAAM,EAAE;AAAA,IAC1B;AAAA,IAGA,QAAQ,QAAoB,KAAa;AACvC,WAAK,UAAU,QACf,KAAK,UAAU,KACf,KAAK,MAAM;AAAA,IACb;AAAA,IAEA,UAAU,KAAa;AACrB,WAAK,YAAY,KACjB,KAAK,MAAM;AAAA,IACb;AAAA,EACF;AAGA,EAAiB,OAAO,UACtB,OAAO,MAAM,OAAO,OAAO,MAAM,QAAQ,CAAC,GAC1C,OAAO,MAAM,KAAK,cAAc;",
"names": []
}
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["../../../src/plugins/slick.autotooltips.ts"],
"sourcesContent": ["import type { AutoTooltipOption, Column, SlickPlugin } from '../models/index.js';\r\nimport { type SlickEventData, Utils as Utils_ } from '../slick.core.js';\r\nimport type { SlickGrid } from '../slick.grid.js';\r\n\r\n// for (iife) load Slick methods from global Slick object, or use imports for (esm)\r\nconst Utils = IIFE_ONLY ? Slick.Utils : Utils_;\r\n\r\n/**\r\n * AutoTooltips plugin to show/hide tooltips when columns are too narrow to fit content.\r\n */\r\nexport class SlickAutoTooltips implements SlickPlugin {\r\n // --\r\n // public API\r\n pluginName = 'AutoTooltips' as const;\r\n\r\n // --\r\n // protected props\r\n protected _grid!: SlickGrid;\r\n protected _options?: AutoTooltipOption;\r\n protected _defaults: AutoTooltipOption = {\r\n enableForCells: true,\r\n enableForHeaderCells: false,\r\n maxToolTipLength: undefined,\r\n replaceExisting: true\r\n };\r\n\r\n /**\r\n * Constructor of the SlickGrid 3rd party plugin, it can optionally receive options\r\n * @param {boolean} [options.enableForCells=true] - Enable tooltip for grid cells\r\n * @param {boolean} [options.enableForHeaderCells=false] - Enable tooltip for header cells\r\n * @param {number} [options.maxToolTipLength=null] - The maximum length for a tooltip\r\n * @param {boolean} [options.replaceExisting=null] - Allow preventing custom tooltips from being overwritten by auto tooltips\r\n */\r\n constructor(options?: AutoTooltipOption) {\r\n this._options = Utils.extend(true, {}, this._defaults, options);\r\n }\r\n\r\n /**\r\n * Initialize plugin.\r\n */\r\n init(grid: SlickGrid) {\r\n this._grid = grid;\r\n if (this._options?.enableForCells) {\r\n this._grid.onMouseEnter.subscribe(this.handleMouseEnter.bind(this));\r\n }\r\n if (this._options?.enableForHeaderCells) {\r\n this._grid.onHeaderMouseEnter.subscribe(this.handleHeaderMouseEnter.bind(this));\r\n }\r\n }\r\n\r\n /**\r\n * Destroy plugin.\r\n */\r\n destroy() {\r\n if (this._options?.enableForCells) {\r\n this._grid.onMouseEnter.unsubscribe(this.handleMouseEnter.bind(this));\r\n }\r\n if (this._options?.enableForHeaderCells) {\r\n this._grid.onHeaderMouseEnter.unsubscribe(this.handleHeaderMouseEnter.bind(this));\r\n }\r\n }\r\n\r\n /**\r\n * Handle mouse entering grid cell to add/remove tooltip.\r\n * @param {SlickEventData} event - The event\r\n */\r\n protected handleMouseEnter(event: SlickEventData) {\r\n const cell = this._grid.getCellFromEvent(event);\r\n if (cell) {\r\n let node: HTMLElement | null = this._grid.getCellNode(cell.row, cell.cell);\r\n let text;\r\n if (this._options && node && (!node.title || this._options?.replaceExisting)) {\r\n if (node.clientWidth < node.scrollWidth) {\r\n text = node.textContent?.trim() ?? '';\r\n if (this._options?.maxToolTipLength && text.length > this._options?.maxToolTipLength) {\r\n text = text.substring(0, this._options.maxToolTipLength - 3) + '...';\r\n }\r\n } else {\r\n text = '';\r\n }\r\n node.title = text;\r\n }\r\n node = null;\r\n }\r\n }\r\n\r\n /**\r\n * Handle mouse entering header cell to add/remove tooltip.\r\n * @param {SlickEventData} event - The event\r\n * @param {object} args.column - The column definition\r\n */\r\n protected handleHeaderMouseEnter(event: SlickEventData, args: { column: Column; }) {\r\n const column = args.column;\r\n let node: HTMLDivElement | null;\r\n const targetElm = (event.target as HTMLDivElement);\r\n\r\n if (targetElm) {\r\n node = targetElm.closest<HTMLDivElement>('.slick-header-column');\r\n if (node && !(column?.toolTip)) {\r\n const titleVal = (targetElm.clientWidth < node.clientWidth) ? column?.name ?? '' : '';\r\n node.title = Utils.getHtmlStringOutput(titleVal, 'innerHTML');\r\n }\r\n }\r\n node = null;\r\n }\r\n}\r\n\r\n// extend Slick namespace on window object when building as iife\r\nif (IIFE_ONLY && window.Slick) {\r\n Utils.extend(true, window, {\r\n Slick: {\r\n AutoTooltips: SlickAutoTooltips\r\n }\r\n });\r\n}\r\n"],
"mappings": ";;;;;;;AAKA,MAAM,QAAoB,MAAM,OAKnB,oBAAN,MAA+C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAuBpD,YAAY,SAA6B;AApBzC;AAAA;AAAA,wCAAa;AAIb;AAAA;AAAA,0BAAU;AACV,0BAAU;AACV,0BAAU,aAA+B;AAAA,QACvC,gBAAgB;AAAA,QAChB,sBAAsB;AAAA,QACtB,kBAAkB;AAAA,QAClB,iBAAiB;AAAA,MACnB;AAUE,WAAK,WAAW,MAAM,OAAO,IAAM,CAAC,GAAG,KAAK,WAAW,OAAO;AAAA,IAChE;AAAA;AAAA;AAAA;AAAA,IAKA,KAAK,MAAiB;AAxCxB;AAyCI,WAAK,QAAQ,OACT,UAAK,aAAL,WAAe,kBACjB,KAAK,MAAM,aAAa,UAAU,KAAK,iBAAiB,KAAK,IAAI,CAAC,IAEhE,UAAK,aAAL,WAAe,wBACjB,KAAK,MAAM,mBAAmB,UAAU,KAAK,uBAAuB,KAAK,IAAI,CAAC;AAAA,IAElF;AAAA;AAAA;AAAA;AAAA,IAKA,UAAU;AArDZ;AAsDI,OAAI,UAAK,aAAL,WAAe,kBACjB,KAAK,MAAM,aAAa,YAAY,KAAK,iBAAiB,KAAK,IAAI,CAAC,IAElE,UAAK,aAAL,WAAe,wBACjB,KAAK,MAAM,mBAAmB,YAAY,KAAK,uBAAuB,KAAK,IAAI,CAAC;AAAA,IAEpF;AAAA;AAAA;AAAA;AAAA;AAAA,IAMU,iBAAiB,OAAuB;AAlEpD;AAmEI,UAAM,OAAO,KAAK,MAAM,iBAAiB,KAAK;AAC9C,UAAI,MAAM;AACR,YAAI,OAA2B,KAAK,MAAM,YAAY,KAAK,KAAK,KAAK,IAAI,GACrE;AACJ,QAAI,KAAK,YAAY,SAAS,CAAC,KAAK,UAAS,UAAK,aAAL,WAAe,qBACtD,KAAK,cAAc,KAAK,eAC1B,QAAO,gBAAK,gBAAL,mBAAkB,WAAlB,YAA4B,KAC/B,UAAK,aAAL,WAAe,oBAAoB,KAAK,WAAS,UAAK,aAAL,mBAAe,sBAClE,OAAO,KAAK,UAAU,GAAG,KAAK,SAAS,mBAAmB,CAAC,IAAI,UAGjE,OAAO,IAET,KAAK,QAAQ,OAEf,OAAO;AAAA,MACT;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOU,uBAAuB,OAAuB,MAA2B;AA3FrF;AA4FI,UAAM,SAAS,KAAK,QAChB,MACE,YAAa,MAAM;AAEzB,UAAI,cACF,OAAO,UAAU,QAAwB,sBAAsB,GAC3D,QAAQ,EAAE,yBAAQ,WAAU;AAC9B,YAAM,WAAY,UAAU,cAAc,KAAK,gBAAe,sCAAQ,SAAR,YAAqB;AACnF,aAAK,QAAQ,MAAM,oBAAoB,UAAU,WAAW;AAAA,MAC9D;AAEF,aAAO;AAAA,IACT;AAAA,EACF;AAGA,EAAiB,OAAO,SACtB,MAAM,OAAO,IAAM,QAAQ;AAAA,IACzB,OAAO;AAAA,MACL,cAAc;AAAA,IAChB;AAAA,EACF,CAAC;",
"names": []
}
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["../../../src/plugins/slick.cellcopymanager.ts"],
"sourcesContent": ["import type { CssStyleHash, SlickPlugin } from '../models/index.js';\r\nimport { keyCode as keyCode_, SlickEvent as SlickEvent_, type SlickEventData, Utils as Utils_, type SlickRange } from '../slick.core.js';\r\nimport type { SlickGrid } from '../slick.grid.js';\r\n\r\n// for (iife) load Slick methods from global Slick object, or use imports for (esm)\r\nconst keyCode = IIFE_ONLY ? Slick.keyCode : keyCode_;\r\nconst SlickEvent = IIFE_ONLY ? Slick.Event : SlickEvent_;\r\nconst Utils = IIFE_ONLY ? Slick.Utils : Utils_;\r\n\r\n/**\r\n * This manager enables users to copy/paste cell data\r\n */\r\nexport class SlickCellCopyManager implements SlickPlugin {\r\n // --\r\n // public API\r\n pluginName = 'CellCopyManager' as const;\r\n onCopyCells = new SlickEvent<{ ranges: SlickRange[] | null; }>('onCopyCells');\r\n onCopyCancelled = new SlickEvent<{ ranges: SlickRange[] | null; }>('onCopyCancelled');\r\n onPasteCells = new SlickEvent<{ from: SlickRange[] | undefined; to: SlickRange[] | undefined; }>('onPasteCells');\r\n\r\n // --\r\n // protected props\r\n protected _grid!: SlickGrid;\r\n protected _copiedRanges?: SlickRange[] | null = null;\r\n\r\n init(grid: SlickGrid) {\r\n this._grid = grid;\r\n Utils.addSlickEventPubSubWhenDefined(grid.getPubSubService(), this);\r\n this._grid.onKeyDown.subscribe(this.handleKeyDown.bind(this));\r\n }\r\n\r\n destroy() {\r\n this._grid.onKeyDown.unsubscribe(this.handleKeyDown.bind(this));\r\n }\r\n\r\n protected handleKeyDown(e: SlickEventData) {\r\n let ranges: SlickRange[] | undefined;\r\n if (!this._grid.getEditorLock().isActive()) {\r\n if (e.which === keyCode.ESCAPE) {\r\n if (this._copiedRanges) {\r\n e.preventDefault();\r\n this.clearCopySelection();\r\n this.onCopyCancelled.notify({ ranges: this._copiedRanges });\r\n this._copiedRanges = null;\r\n }\r\n }\r\n\r\n if (e.which === 67 && (e.ctrlKey || e.metaKey)) {\r\n ranges = this._grid.getSelectionModel()?.getSelectedRanges() ?? [];\r\n if (ranges.length !== 0) {\r\n e.preventDefault();\r\n this._copiedRanges = ranges;\r\n this.markCopySelection(ranges);\r\n this.onCopyCells.notify({ ranges });\r\n }\r\n }\r\n\r\n if (e.which === 86 && (e.ctrlKey || e.metaKey)) {\r\n if (this._copiedRanges) {\r\n e.preventDefault();\r\n ranges = this._grid.getSelectionModel()?.getSelectedRanges();\r\n this.onPasteCells.notify({ from: this._copiedRanges, to: ranges });\r\n if (!this._grid.getOptions().preserveCopiedSelectionOnPaste) {\r\n this.clearCopySelection();\r\n this._copiedRanges = null;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n protected markCopySelection(ranges: SlickRange[]) {\r\n const columns = this._grid.getColumns();\r\n const hash: CssStyleHash = {};\r\n for (let i = 0; i < ranges.length; i++) {\r\n for (let j = ranges[i].fromRow; j <= ranges[i].toRow; j++) {\r\n hash[j] = {};\r\n for (let k = ranges[i].fromCell; k <= ranges[i].toCell; k++) {\r\n hash[j][columns[k].id] = 'copied';\r\n }\r\n }\r\n }\r\n this._grid.setCellCssStyles('copy-manager', hash);\r\n }\r\n\r\n protected clearCopySelection() {\r\n this._grid.removeCellCssStyles('copy-manager');\r\n }\r\n}\r\n\r\n// extend Slick namespace on window object when building as iife\r\nif (IIFE_ONLY && window.Slick) {\r\n Utils.extend(true, window, {\r\n Slick: {\r\n CellCopyManager: SlickCellCopyManager\r\n }\r\n });\r\n}\r\n"],
"mappings": ";;;;;;;AAKA,MAAM,UAAsB,MAAM,SAC5B,aAAyB,MAAM,OAC/B,QAAoB,MAAM,OAKnB,uBAAN,MAAkD;AAAA,IAAlD;AAGL;AAAA;AAAA,wCAAa;AACb,yCAAc,IAAI,WAA6C,aAAa;AAC5E,6CAAkB,IAAI,WAA6C,iBAAiB;AACpF,0CAAe,IAAI,WAA8E,cAAc;AAI/G;AAAA;AAAA,0BAAU;AACV,0BAAU,iBAAsC;AAAA;AAAA,IAEhD,KAAK,MAAiB;AACpB,WAAK,QAAQ,MACb,MAAM,+BAA+B,KAAK,iBAAiB,GAAG,IAAI,GAClE,KAAK,MAAM,UAAU,UAAU,KAAK,cAAc,KAAK,IAAI,CAAC;AAAA,IAC9D;AAAA,IAEA,UAAU;AACR,WAAK,MAAM,UAAU,YAAY,KAAK,cAAc,KAAK,IAAI,CAAC;AAAA,IAChE;AAAA,IAEU,cAAc,GAAmB;AAnC7C;AAoCI,UAAI;AACJ,MAAK,KAAK,MAAM,cAAc,EAAE,SAAS,MACnC,EAAE,UAAU,QAAQ,UAClB,KAAK,kBACP,EAAE,eAAe,GACjB,KAAK,mBAAmB,GACxB,KAAK,gBAAgB,OAAO,EAAE,QAAQ,KAAK,cAAc,CAAC,GAC1D,KAAK,gBAAgB,OAIrB,EAAE,UAAU,OAAO,EAAE,WAAW,EAAE,aACpC,UAAS,gBAAK,MAAM,kBAAkB,MAA7B,mBAAgC,wBAAhC,YAAuD,CAAC,GAC7D,OAAO,WAAW,MACpB,EAAE,eAAe,GACjB,KAAK,gBAAgB,QACrB,KAAK,kBAAkB,MAAM,GAC7B,KAAK,YAAY,OAAO,EAAE,OAAO,CAAC,KAIlC,EAAE,UAAU,OAAO,EAAE,WAAW,EAAE,YAChC,KAAK,kBACP,EAAE,eAAe,GACjB,UAAS,UAAK,MAAM,kBAAkB,MAA7B,mBAAgC,qBACzC,KAAK,aAAa,OAAO,EAAE,MAAM,KAAK,eAAe,IAAI,OAAO,CAAC,GAC5D,KAAK,MAAM,WAAW,EAAE,mCAC3B,KAAK,mBAAmB,GACxB,KAAK,gBAAgB;AAAA,IAK/B;AAAA,IAEU,kBAAkB,QAAsB;AAChD,UAAM,UAAU,KAAK,MAAM,WAAW,GAChC,OAAqB,CAAC;AAC5B,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ;AACjC,iBAAS,IAAI,OAAO,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,EAAE,OAAO,KAAK;AACzD,eAAK,CAAC,IAAI,CAAC;AACX,mBAAS,IAAI,OAAO,CAAC,EAAE,UAAU,KAAK,OAAO,CAAC,EAAE,QAAQ;AACtD,iBAAK,CAAC,EAAE,QAAQ,CAAC,EAAE,EAAE,IAAI;AAAA,QAE7B;AAEF,WAAK,MAAM,iBAAiB,gBAAgB,IAAI;AAAA,IAClD;AAAA,IAEU,qBAAqB;AAC7B,WAAK,MAAM,oBAAoB,cAAc;AAAA,IAC/C;AAAA,EACF;AAGA,EAAiB,OAAO,SACtB,MAAM,OAAO,IAAM,QAAQ;AAAA,IACzB,OAAO;AAAA,MACL,iBAAiB;AAAA,IACnB;AAAA,EACF,CAAC;",
"names": []
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["../../../src/plugins/slick.cellrangedecorator.ts"],
"sourcesContent": ["import type { CSSStyleDeclarationWritable, CellRangeDecoratorOption, SlickPlugin } from '../models/index.js';\r\nimport { Utils as Utils_, type SlickRange } from '../slick.core.js';\r\nimport type { SlickGrid } from '../slick.grid.js';\r\n\r\n// for (iife) load Slick methods from global Slick object, or use imports for (esm)\r\nconst Utils = IIFE_ONLY ? Slick.Utils : Utils_;\r\n\r\n/***\r\n * Displays an overlay on top of a given cell range.\r\n *\r\n * TODO:\r\n * Currently, it blocks mouse events to DOM nodes behind it.\r\n * Use FF and WebKit-specific \"pointer-events\" CSS style, or some kind of event forwarding.\r\n * Could also construct the borders separately using 4 individual DIVs.\r\n *\r\n * @param {Grid} grid\r\n * @param {Object} options\r\n */\r\nexport class SlickCellRangeDecorator implements SlickPlugin {\r\n // --\r\n // public API\r\n pluginName = 'CellRangeDecorator' as const;\r\n\r\n // --\r\n // protected props\r\n protected _options: CellRangeDecoratorOption;\r\n protected _elem?: HTMLDivElement | null;\r\n protected _defaults = {\r\n selectionCssClass: 'slick-range-decorator',\r\n selectionCss: {\r\n zIndex: '9999',\r\n border: '2px dashed red'\r\n },\r\n offset: { top: -1, left: -1, height: -2, width: -2 }\r\n } as CellRangeDecoratorOption;\r\n\r\n constructor(protected readonly grid: SlickGrid, options?: Partial<CellRangeDecoratorOption>) {\r\n this._options = Utils.extend(true, {}, this._defaults, options);\r\n }\r\n\r\n destroy() {\r\n this.hide();\r\n }\r\n\r\n init() { }\r\n\r\n hide() {\r\n this._elem?.remove();\r\n this._elem = null;\r\n }\r\n\r\n show(range: SlickRange) {\r\n if (!this._elem) {\r\n this._elem = document.createElement('div');\r\n this._elem.className = this._options.selectionCssClass;\r\n Object.keys(this._options.selectionCss as CSSStyleDeclaration).forEach((cssStyleKey) => {\r\n this._elem!.style[cssStyleKey as CSSStyleDeclarationWritable] = this._options.selectionCss[cssStyleKey as CSSStyleDeclarationWritable];\r\n });\r\n this._elem.style.position = 'absolute';\r\n const canvasNode = this.grid.getActiveCanvasNode();\r\n if (canvasNode) {\r\n canvasNode.appendChild(this._elem);\r\n }\r\n }\r\n\r\n const from = this.grid.getCellNodeBox(range.fromRow, range.fromCell);\r\n const to = this.grid.getCellNodeBox(range.toRow, range.toCell);\r\n\r\n if (from && to && this._options?.offset) {\r\n this._elem.style.top = `${from.top + this._options.offset.top}px`;\r\n this._elem.style.left = `${from.left + this._options.offset.left}px`;\r\n this._elem.style.height = `${to.bottom - from.top + this._options.offset.height}px`;\r\n this._elem.style.width = `${to.right - from.left + this._options.offset.width}px`;\r\n }\r\n\r\n return this._elem;\r\n }\r\n}\r\n\r\n// extend Slick namespace on window object when building as iife\r\nif (IIFE_ONLY && window.Slick) {\r\n Utils.extend(true, window, {\r\n Slick: {\r\n CellRangeDecorator: SlickCellRangeDecorator\r\n }\r\n });\r\n}\r\n"],
"mappings": ";;;;;;;AAKA,MAAM,QAAoB,MAAM,OAanB,0BAAN,MAAqD;AAAA,IAkB1D,YAA+B,MAAiB,SAA6C;AAA9D;AAf/B;AAAA;AAAA,wCAAa;AAIb;AAAA;AAAA,0BAAU;AACV,0BAAU;AACV,0BAAU,aAAY;AAAA,QACpB,mBAAmB;AAAA,QACnB,cAAc;AAAA,UACZ,QAAQ;AAAA,UACR,QAAQ;AAAA,QACV;AAAA,QACA,QAAQ,EAAE,KAAK,IAAI,MAAM,IAAI,QAAQ,IAAI,OAAO,GAAG;AAAA,MACrD;AAGE,WAAK,WAAW,MAAM,OAAO,IAAM,CAAC,GAAG,KAAK,WAAW,OAAO;AAAA,IAChE;AAAA,IAEA,UAAU;AACR,WAAK,KAAK;AAAA,IACZ;AAAA,IAEA,OAAO;AAAA,IAAE;AAAA,IAET,OAAO;AA9CT;AA+CI,iBAAK,UAAL,WAAY,UACZ,KAAK,QAAQ;AAAA,IACf;AAAA,IAEA,KAAK,OAAmB;AAnD1B;AAoDI,UAAI,CAAC,KAAK,OAAO;AACf,aAAK,QAAQ,SAAS,cAAc,KAAK,GACzC,KAAK,MAAM,YAAY,KAAK,SAAS,mBACrC,OAAO,KAAK,KAAK,SAAS,YAAmC,EAAE,QAAQ,CAAC,gBAAgB;AACtF,eAAK,MAAO,MAAM,WAA0C,IAAI,KAAK,SAAS,aAAa,WAA0C;AAAA,QACvI,CAAC,GACD,KAAK,MAAM,MAAM,WAAW;AAC5B,YAAM,aAAa,KAAK,KAAK,oBAAoB;AACjD,QAAI,cACF,WAAW,YAAY,KAAK,KAAK;AAAA,MAErC;AAEA,UAAM,OAAO,KAAK,KAAK,eAAe,MAAM,SAAS,MAAM,QAAQ,GAC7D,KAAK,KAAK,KAAK,eAAe,MAAM,OAAO,MAAM,MAAM;AAE7D,aAAI,QAAQ,QAAM,UAAK,aAAL,WAAe,YAC/B,KAAK,MAAM,MAAM,MAAM,GAAG,KAAK,MAAM,KAAK,SAAS,OAAO,GAAG,MAC7D,KAAK,MAAM,MAAM,OAAO,GAAG,KAAK,OAAO,KAAK,SAAS,OAAO,IAAI,MAChE,KAAK,MAAM,MAAM,SAAS,GAAG,GAAG,SAAS,KAAK,MAAM,KAAK,SAAS,OAAO,MAAM,MAC/E,KAAK,MAAM,MAAM,QAAQ,GAAG,GAAG,QAAQ,KAAK,OAAO,KAAK,SAAS,OAAO,KAAK,OAGxE,KAAK;AAAA,IACd;AAAA,EACF;AAGA,EAAiB,OAAO,SACtB,MAAM,OAAO,IAAM,QAAQ;AAAA,IACzB,OAAO;AAAA,MACL,oBAAoB;AAAA,IACtB;AAAA,EACF,CAAC;",
"names": []
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,79 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
// src/plugins/slick.autotooltips.ts
var Utils = Slick.Utils, SlickAutoTooltips = class {
/**
* Constructor of the SlickGrid 3rd party plugin, it can optionally receive options
* @param {boolean} [options.enableForCells=true] - Enable tooltip for grid cells
* @param {boolean} [options.enableForHeaderCells=false] - Enable tooltip for header cells
* @param {number} [options.maxToolTipLength=null] - The maximum length for a tooltip
* @param {boolean} [options.replaceExisting=null] - Allow preventing custom tooltips from being overwritten by auto tooltips
*/
constructor(options) {
// --
// public API
__publicField(this, "pluginName", "AutoTooltips");
// --
// protected props
__publicField(this, "_grid");
__publicField(this, "_options");
__publicField(this, "_defaults", {
enableForCells: !0,
enableForHeaderCells: !1,
maxToolTipLength: void 0,
replaceExisting: !0
});
this._options = Utils.extend(!0, {}, this._defaults, options);
}
/**
* Initialize plugin.
*/
init(grid) {
var _a, _b;
this._grid = grid, (_a = this._options) != null && _a.enableForCells && this._grid.onMouseEnter.subscribe(this.handleMouseEnter.bind(this)), (_b = this._options) != null && _b.enableForHeaderCells && this._grid.onHeaderMouseEnter.subscribe(this.handleHeaderMouseEnter.bind(this));
}
/**
* Destroy plugin.
*/
destroy() {
var _a, _b;
(_a = this._options) != null && _a.enableForCells && this._grid.onMouseEnter.unsubscribe(this.handleMouseEnter.bind(this)), (_b = this._options) != null && _b.enableForHeaderCells && this._grid.onHeaderMouseEnter.unsubscribe(this.handleHeaderMouseEnter.bind(this));
}
/**
* Handle mouse entering grid cell to add/remove tooltip.
* @param {SlickEventData} event - The event
*/
handleMouseEnter(event) {
var _a, _b, _c, _d, _e;
let cell = this._grid.getCellFromEvent(event);
if (cell) {
let node = this._grid.getCellNode(cell.row, cell.cell), text;
this._options && node && (!node.title || (_a = this._options) != null && _a.replaceExisting) && (node.clientWidth < node.scrollWidth ? (text = (_c = (_b = node.textContent) == null ? void 0 : _b.trim()) != null ? _c : "", (_d = this._options) != null && _d.maxToolTipLength && text.length > ((_e = this._options) == null ? void 0 : _e.maxToolTipLength) && (text = text.substring(0, this._options.maxToolTipLength - 3) + "...")) : text = "", node.title = text), node = null;
}
}
/**
* Handle mouse entering header cell to add/remove tooltip.
* @param {SlickEventData} event - The event
* @param {object} args.column - The column definition
*/
handleHeaderMouseEnter(event, args) {
var _a;
let column = args.column, node, targetElm = event.target;
if (targetElm && (node = targetElm.closest(".slick-header-column"), node && !(column != null && column.toolTip))) {
let titleVal = targetElm.clientWidth < node.clientWidth && (_a = column == null ? void 0 : column.name) != null ? _a : "";
node.title = Utils.getHtmlStringOutput(titleVal, "innerHTML");
}
node = null;
}
};
window.Slick && Utils.extend(!0, window, {
Slick: {
AutoTooltips: SlickAutoTooltips
}
});
})();
//# sourceMappingURL=slick.autotooltips.js.map
@@ -0,0 +1,52 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
// src/plugins/slick.cellcopymanager.ts
var keyCode = Slick.keyCode, SlickEvent = Slick.Event, Utils = Slick.Utils, SlickCellCopyManager = class {
constructor() {
// --
// public API
__publicField(this, "pluginName", "CellCopyManager");
__publicField(this, "onCopyCells", new SlickEvent("onCopyCells"));
__publicField(this, "onCopyCancelled", new SlickEvent("onCopyCancelled"));
__publicField(this, "onPasteCells", new SlickEvent("onPasteCells"));
// --
// protected props
__publicField(this, "_grid");
__publicField(this, "_copiedRanges", null);
}
init(grid) {
this._grid = grid, Utils.addSlickEventPubSubWhenDefined(grid.getPubSubService(), this), this._grid.onKeyDown.subscribe(this.handleKeyDown.bind(this));
}
destroy() {
this._grid.onKeyDown.unsubscribe(this.handleKeyDown.bind(this));
}
handleKeyDown(e) {
var _a, _b, _c;
let ranges;
this._grid.getEditorLock().isActive() || (e.which === keyCode.ESCAPE && this._copiedRanges && (e.preventDefault(), this.clearCopySelection(), this.onCopyCancelled.notify({ ranges: this._copiedRanges }), this._copiedRanges = null), e.which === 67 && (e.ctrlKey || e.metaKey) && (ranges = (_b = (_a = this._grid.getSelectionModel()) == null ? void 0 : _a.getSelectedRanges()) != null ? _b : [], ranges.length !== 0 && (e.preventDefault(), this._copiedRanges = ranges, this.markCopySelection(ranges), this.onCopyCells.notify({ ranges }))), e.which === 86 && (e.ctrlKey || e.metaKey) && this._copiedRanges && (e.preventDefault(), ranges = (_c = this._grid.getSelectionModel()) == null ? void 0 : _c.getSelectedRanges(), this.onPasteCells.notify({ from: this._copiedRanges, to: ranges }), this._grid.getOptions().preserveCopiedSelectionOnPaste || (this.clearCopySelection(), this._copiedRanges = null)));
}
markCopySelection(ranges) {
let columns = this._grid.getColumns(), hash = {};
for (let i = 0; i < ranges.length; i++)
for (let j = ranges[i].fromRow; j <= ranges[i].toRow; j++) {
hash[j] = {};
for (let k = ranges[i].fromCell; k <= ranges[i].toCell; k++)
hash[j][columns[k].id] = "copied";
}
this._grid.setCellCssStyles("copy-manager", hash);
}
clearCopySelection() {
this._grid.removeCellCssStyles("copy-manager");
}
};
window.Slick && Utils.extend(!0, window, {
Slick: {
CellCopyManager: SlickCellCopyManager
}
});
})();
//# sourceMappingURL=slick.cellcopymanager.js.map
@@ -0,0 +1,282 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
// src/plugins/slick.cellexternalcopymanager.ts
var SlickEvent = Slick.Event, SlickRange = Slick.Range, Utils = Slick.Utils, CLEAR_COPY_SELECTION_DELAY = 2e3, CLIPBOARD_PASTE_DELAY = 100, SlickCellExternalCopyManager = class {
constructor(options) {
// --
// public API
__publicField(this, "pluginName", "CellExternalCopyManager");
__publicField(this, "onCopyCells", new SlickEvent("onCopyCells"));
__publicField(this, "onCopyCancelled", new SlickEvent("onCopyCancelled"));
__publicField(this, "onPasteCells", new SlickEvent("onPasteCells"));
// --
// protected props
__publicField(this, "_grid");
__publicField(this, "_bodyElement");
__publicField(this, "_copiedRanges", null);
__publicField(this, "_clearCopyTI");
__publicField(this, "_copiedCellStyle");
__publicField(this, "_copiedCellStyleLayerKey");
__publicField(this, "_onCopyInit");
__publicField(this, "_onCopySuccess");
__publicField(this, "_options");
__publicField(this, "keyCodes", {
C: 67,
V: 86,
ESC: 27,
INSERT: 45
});
this._options = options || {}, this._copiedCellStyleLayerKey = this._options.copiedCellStyleLayerKey || "copy-manager", this._copiedCellStyle = this._options.copiedCellStyle || "copied", this._bodyElement = this._options.bodyElement || document.body, this._onCopyInit = this._options.onCopyInit || void 0, this._onCopySuccess = this._options.onCopySuccess || void 0;
}
init(grid) {
this._grid = grid, Utils.addSlickEventPubSubWhenDefined(grid.getPubSubService(), this), this._grid.onKeyDown.subscribe(this.handleKeyDown.bind(this));
let cellSelectionModel = grid.getSelectionModel();
if (!cellSelectionModel)
throw new Error("Selection model is mandatory for this plugin. Please set a selection model on the grid before adding this plugin: grid.setSelectionModel(new Slick.CellSelectionModel())");
cellSelectionModel.onSelectedRangesChanged.subscribe(() => {
this._grid.getEditorLock().isActive() || this._grid.focus();
});
}
destroy() {
this._grid.onKeyDown.unsubscribe(this.handleKeyDown.bind(this));
}
getHeaderValueForColumn(columnDef) {
if (this._options.headerColumnValueExtractor) {
let val = Utils.getHtmlStringOutput(this._options.headerColumnValueExtractor(columnDef));
if (val)
return val;
}
return Utils.getHtmlStringOutput(columnDef.name || "");
}
getDataItemValueForColumn(item, columnDef, event) {
if (typeof this._options.dataItemColumnValueExtractor == "function") {
let val = this._options.dataItemColumnValueExtractor(item, columnDef);
if (val)
return val;
}
let retVal = "";
if (columnDef != null && columnDef.editor) {
let tmpP = document.createElement("p"), editor = new columnDef.editor({
container: tmpP,
// a dummy container
column: columnDef,
event,
position: { top: 0, left: 0 },
// a dummy position required by some editors
grid: this._grid
});
editor.loadValue(item), retVal = editor.serializeValue(), editor.destroy(), tmpP.remove();
} else
retVal = item[columnDef.field || ""];
return retVal;
}
setDataItemValueForColumn(item, columnDef, value) {
if (columnDef.denyPaste)
return null;
if (this._options.dataItemColumnValueSetter)
return this._options.dataItemColumnValueSetter(item, columnDef, value);
if (columnDef.editor) {
let tmpDiv = document.createElement("div"), editor = new columnDef.editor({
container: tmpDiv,
// a dummy container
column: columnDef,
position: { top: 0, left: 0 },
// a dummy position required by some editors
grid: this._grid
});
editor.loadValue(item), editor.applyValue(item, value), editor.destroy(), tmpDiv.remove();
} else
item[columnDef.field] = value;
}
_createTextBox(innerText) {
let scrollPos = document.documentElement.scrollTop || document.body.scrollTop, ta = document.createElement("textarea");
return ta.style.position = "absolute", ta.style.opacity = "0", ta.value = innerText, ta.style.top = `${scrollPos}px`, this._bodyElement.appendChild(ta), ta.select(), ta;
}
_decodeTabularData(grid, ta) {
var _a;
let columns = grid.getColumns(), clipRows = ta.value.split(/[\n\f\r]/);
clipRows[clipRows.length - 1] === "" && clipRows.pop();
let j = 0, clippedRange = [];
this._bodyElement.removeChild(ta);
for (let i = 0; i < clipRows.length; i++)
clipRows[i] !== "" ? clippedRange[j++] = clipRows[i].split(" ") : clippedRange[j++] = [""];
let selectedCell = grid.getActiveCell(), ranges = (_a = grid.getSelectionModel()) == null ? void 0 : _a.getSelectedRanges(), selectedRange = ranges && ranges.length ? ranges[0] : null, activeRow, activeCell;
if (selectedRange)
activeRow = selectedRange.fromRow, activeCell = selectedRange.fromCell;
else if (selectedCell)
activeRow = selectedCell.row, activeCell = selectedCell.cell;
else
return;
let oneCellToMultiple = !1, destH = clippedRange.length, destW = clippedRange.length ? clippedRange[0].length : 0;
clippedRange.length === 1 && clippedRange[0].length === 1 && selectedRange && (oneCellToMultiple = !0, destH = selectedRange.toRow - selectedRange.fromRow + 1, destW = selectedRange.toCell - selectedRange.fromCell + 1);
let availableRows = grid.getData().length - (activeRow || 0), addRows = 0;
if (availableRows < destH && typeof this._options.newRowCreator == "function") {
let d = grid.getData();
for (addRows = 1; addRows <= destH - availableRows; addRows++)
d.push({});
grid.setData(d), grid.render();
}
let overflowsBottomOfGrid = (activeRow || 0) + destH > grid.getDataLength();
if (this._options.newRowCreator && overflowsBottomOfGrid) {
let newRowsNeeded = (activeRow || 0) + destH - grid.getDataLength();
this._options.newRowCreator(newRowsNeeded);
}
let clipCommand = {
isClipboardCommand: !0,
clippedRange,
oldValues: [],
cellExternalCopyManager: this,
_options: this._options,
setDataItemValueForColumn: this.setDataItemValueForColumn.bind(this),
markCopySelection: this.markCopySelection.bind(this),
oneCellToMultiple,
activeRow,
activeCell,
destH,
destW,
maxDestY: grid.getDataLength(),
maxDestX: grid.getColumns().length,
h: 0,
w: 0,
execute: () => {
var _a2;
clipCommand.h = 0;
for (let y = 0; y < clipCommand.destH; y++) {
clipCommand.oldValues[y] = [], clipCommand.w = 0, clipCommand.h++;
let xOffset = 0;
for (let x = 0; x < clipCommand.destW; x++) {
let desty = activeRow + y, destx = activeCell + x, column = columns[destx];
if (column.hidden) {
clipCommand.destW++, xOffset++;
continue;
}
if (clipCommand.w++, desty < clipCommand.maxDestY && destx < clipCommand.maxDestX) {
let dt = grid.getDataItem(desty);
clipCommand.oldValues[y][x - xOffset] = dt[column.field], oneCellToMultiple ? clipCommand.setDataItemValueForColumn(dt, column, clippedRange[0][0]) : clipCommand.setDataItemValueForColumn(dt, column, clippedRange[y] ? clippedRange[y][x - xOffset] : ""), grid.updateCell(desty, destx), grid.onCellChange.notify({
row: desty,
cell: destx,
item: dt,
grid,
column: {}
});
}
}
}
let bRange = new SlickRange(
activeRow,
activeCell,
activeRow + clipCommand.h - 1,
activeCell + clipCommand.w - 1
);
this.markCopySelection([bRange]), (_a2 = grid.getSelectionModel()) == null || _a2.setSelectedRanges([bRange]), this.onPasteCells.notify({ ranges: [bRange] });
},
undo: () => {
var _a2;
for (let y = 0; y < clipCommand.destH; y++)
for (let x = 0; x < clipCommand.destW; x++) {
let desty = activeRow + y, destx = activeCell + x;
if (desty < clipCommand.maxDestY && destx < clipCommand.maxDestX) {
let dt = grid.getDataItem(desty);
oneCellToMultiple ? clipCommand.setDataItemValueForColumn(dt, columns[destx], clipCommand.oldValues[0][0]) : clipCommand.setDataItemValueForColumn(dt, columns[destx], clipCommand.oldValues[y][x]), grid.updateCell(desty, destx), grid.onCellChange.notify({
row: desty,
cell: destx,
item: dt,
grid,
column: {}
});
}
}
let bRange = new SlickRange(
activeRow,
activeCell,
activeRow + clipCommand.h - 1,
activeCell + clipCommand.w - 1
);
if (this.markCopySelection([bRange]), (_a2 = grid.getSelectionModel()) == null || _a2.setSelectedRanges([bRange]), typeof this._options.onPasteCells == "function" && this.onPasteCells.notify({ ranges: [bRange] }), addRows > 1) {
let d = grid.getData();
for (; addRows > 1; addRows--)
d.splice(d.length - 1, 1);
grid.setData(d), grid.render();
}
}
};
typeof this._options.clipboardCommandHandler == "function" ? this._options.clipboardCommandHandler(clipCommand) : clipCommand.execute();
}
handleKeyDown(e) {
var _a, _b, _c, _d, _e, _f;
let ranges;
if (!this._grid.getEditorLock().isActive() || this._grid.getOptions().autoEdit) {
if (e.which === this.keyCodes.ESC && this._copiedRanges && (e.preventDefault(), this.clearCopySelection(), this.onCopyCancelled.notify({ ranges: this._copiedRanges }), this._copiedRanges = null), (e.which === this.keyCodes.C || e.which === this.keyCodes.INSERT) && (e.ctrlKey || e.metaKey) && !e.shiftKey && (typeof this._onCopyInit == "function" && this._onCopyInit.call(this), ranges = (_b = (_a = this._grid.getSelectionModel()) == null ? void 0 : _a.getSelectedRanges()) != null ? _b : [], ranges.length !== 0)) {
this._copiedRanges = ranges, this.markCopySelection(ranges), this.onCopyCells.notify({ ranges });
let columns = this._grid.getColumns(), clipText = "";
for (let rg = 0; rg < ranges.length; rg++) {
let range = ranges[rg], clipTextRows = [];
for (let i = range.fromRow; i < range.toRow + 1; i++) {
let clipTextCells = [], dt = this._grid.getDataItem(i);
if (clipTextRows.length === 0 && this._options.includeHeaderWhenCopying) {
let clipTextHeaders = [];
for (let j = range.fromCell; j < range.toCell + 1; j++)
(columns[j].name instanceof HTMLElement ? columns[j].name.innerHTML : columns[j].name).length > 0 && !columns[j].hidden && clipTextHeaders.push(this.getHeaderValueForColumn(columns[j]) || "");
clipTextRows.push(clipTextHeaders.join(" "));
}
for (let j = range.fromCell; j < range.toCell + 1; j++)
(columns[j].name instanceof HTMLElement ? columns[j].name.innerHTML : columns[j].name).length > 0 && !columns[j].hidden && clipTextCells.push(this.getDataItemValueForColumn(dt, columns[j], e));
clipTextRows.push(clipTextCells.join(" "));
}
clipText += clipTextRows.join(`\r
`) + `\r
`;
}
if (window.clipboardData)
return window.clipboardData.setData("Text", clipText), !0;
{
let focusEl = document.activeElement, ta = this._createTextBox(clipText);
if (ta.focus(), window.setTimeout(() => {
this._bodyElement.removeChild(ta), focusEl ? focusEl.focus() : console.log("No element to restore focus to after copy?");
}, (_d = (_c = this._options) == null ? void 0 : _c.clipboardPasteDelay) != null ? _d : CLIPBOARD_PASTE_DELAY), typeof this._onCopySuccess == "function") {
let rowCount = 0;
ranges.length === 1 ? rowCount = ranges[0].toRow + 1 - ranges[0].fromRow : rowCount = ranges.length, this._onCopySuccess(rowCount);
}
return !1;
}
}
if (!this._options.readOnlyMode && (e.which === this.keyCodes.V && (e.ctrlKey || e.metaKey) && !e.shiftKey || e.which === this.keyCodes.INSERT && e.shiftKey && !e.ctrlKey)) {
let focusEl = document.activeElement, ta = this._createTextBox("");
return window.setTimeout(() => {
this._decodeTabularData(this._grid, ta), focusEl == null || focusEl.focus();
}, (_f = (_e = this._options) == null ? void 0 : _e.clipboardPasteDelay) != null ? _f : CLIPBOARD_PASTE_DELAY), !1;
}
}
}
markCopySelection(ranges) {
var _a;
this.clearCopySelection();
let columns = this._grid.getColumns(), hash = {};
for (let i = 0; i < ranges.length; i++)
for (let j = ranges[i].fromRow; j <= ranges[i].toRow; j++) {
hash[j] = {};
for (let k = ranges[i].fromCell; k <= ranges[i].toCell && k < columns.length; k++)
hash[j][columns[k].id] = this._copiedCellStyle;
}
this._grid.setCellCssStyles(this._copiedCellStyleLayerKey, hash), window.clearTimeout(this._clearCopyTI), this._clearCopyTI = window.setTimeout(() => {
this.clearCopySelection();
}, ((_a = this._options) == null ? void 0 : _a.clearCopySelectionDelay) || CLEAR_COPY_SELECTION_DELAY);
}
clearCopySelection() {
this._grid.removeCellCssStyles(this._copiedCellStyleLayerKey);
}
setIncludeHeaderWhenCopying(includeHeaderWhenCopying) {
this._options.includeHeaderWhenCopying = includeHeaderWhenCopying;
}
};
window.Slick && Utils.extend(!0, window, {
Slick: {
CellExternalCopyManager: SlickCellExternalCopyManager
}
});
})();
//# sourceMappingURL=slick.cellexternalcopymanager.js.map
@@ -0,0 +1,270 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
// src/plugins/slick.cellmenu.ts
var BindingEventService = Slick.BindingEventService, SlickEvent = Slick.Event, SlickEventData = Slick.EventData, EventHandler = Slick.EventHandler, Utils = Slick.Utils, SlickCellMenu = class {
constructor(optionProperties) {
// --
// public API
__publicField(this, "pluginName", "CellMenu");
__publicField(this, "onAfterMenuShow", new SlickEvent("onAfterMenuShow"));
__publicField(this, "onBeforeMenuShow", new SlickEvent("onBeforeMenuShow"));
__publicField(this, "onBeforeMenuClose", new SlickEvent("onBeforeMenuClose"));
__publicField(this, "onCommand", new SlickEvent("onCommand"));
__publicField(this, "onOptionSelected", new SlickEvent("onOptionSelected"));
// --
// protected props
__publicField(this, "_bindingEventService", new BindingEventService());
__publicField(this, "_cellMenuProperties");
__publicField(this, "_currentCell", -1);
__publicField(this, "_currentRow", -1);
__publicField(this, "_grid");
__publicField(this, "_gridOptions");
__publicField(this, "_gridUid", "");
__publicField(this, "_handler", new EventHandler());
__publicField(this, "_commandTitleElm");
__publicField(this, "_optionTitleElm");
__publicField(this, "_lastMenuTypeClicked", "");
__publicField(this, "_menuElm");
__publicField(this, "_subMenuParentId", "");
__publicField(this, "_defaults", {
autoAdjustDrop: !0,
// dropup/dropdown
autoAlignSide: !0,
// left/right
autoAdjustDropOffset: 0,
autoAlignSideOffset: 0,
hideMenuOnScroll: !0,
maxHeight: "none",
width: "auto",
subMenuOpenByEvent: "mouseover"
});
this._cellMenuProperties = Utils.extend({}, this._defaults, optionProperties);
}
init(grid) {
this._grid = grid, this._gridOptions = grid.getOptions(), Utils.addSlickEventPubSubWhenDefined(grid.getPubSubService(), this), this._gridUid = (grid == null ? void 0 : grid.getUID()) || "", this._handler.subscribe(this._grid.onClick, this.handleCellClick.bind(this)), this._cellMenuProperties.hideMenuOnScroll && this._handler.subscribe(this._grid.onScroll, this.closeMenu.bind(this));
}
setOptions(newOptions) {
this._cellMenuProperties = Utils.extend({}, this._cellMenuProperties, newOptions);
}
destroy() {
var _a;
this.onAfterMenuShow.unsubscribe(), this.onBeforeMenuShow.unsubscribe(), this.onBeforeMenuClose.unsubscribe(), this.onCommand.unsubscribe(), this.onOptionSelected.unsubscribe(), this._handler.unsubscribeAll(), this._bindingEventService.unbindAll(), (_a = this._menuElm) == null || _a.remove(), this._commandTitleElm = null, this._optionTitleElm = null, this._menuElm = null;
}
createParentMenu(e) {
var _a, _b;
let cell = this._grid.getCellFromEvent(e);
this._currentCell = (_a = cell == null ? void 0 : cell.cell) != null ? _a : 0, this._currentRow = (_b = cell == null ? void 0 : cell.row) != null ? _b : 0;
let columnDef = this._grid.getColumns()[this._currentCell], commandItems = this._cellMenuProperties.commandItems || [], optionItems = this._cellMenuProperties.optionItems || [];
if (!(!columnDef || !columnDef.cellMenu || !commandItems.length && !optionItems.length) && (this.closeMenu(), this.onBeforeMenuShow.notify({
cell: this._currentCell,
row: this._currentRow,
grid: this._grid
}, e, this).getReturnValue() !== !1 && (this._menuElm = this.createMenu(commandItems, optionItems), this._menuElm.style.top = `${e.pageY + 5}px`, this._menuElm.style.left = `${e.pageX}px`, this._menuElm.style.display = "block", document.body.appendChild(this._menuElm), this.onAfterMenuShow.notify({
cell: this._currentCell,
row: this._currentRow,
grid: this._grid
}, e, this).getReturnValue() !== !1)))
return this._menuElm;
}
/**
* Create parent menu or sub-menu(s), a parent menu will start at level 0 while sub-menu(s) will be incremented
* @param commandItems - array of optional commands or dividers
* @param optionItems - array of optional options or dividers
* @param level - menu level
* @param item - command, option or divider
* @returns menu DOM element
*/
createMenu(commandItems, optionItems, level = 0, item) {
var _a, _b;
let columnDef = this._grid.getColumns()[this._currentCell], dataContext = this._grid.getDataItem(this._currentRow), maxHeight = isNaN(this._cellMenuProperties.maxHeight) ? this._cellMenuProperties.maxHeight : `${(_a = this._cellMenuProperties.maxHeight) != null ? _a : 0}px`, width = isNaN(this._cellMenuProperties.width) ? this._cellMenuProperties.width : `${(_b = this._cellMenuProperties.maxWidth) != null ? _b : 0}px`, subMenuCommand = item == null ? void 0 : item.command, subMenuId = level === 1 && subMenuCommand ? subMenuCommand.replaceAll(" ", "") : "";
subMenuId && (this._subMenuParentId = subMenuId), level > 1 && (subMenuId = this._subMenuParentId);
let menuClasses = `slick-cell-menu slick-menu-level-${level} ${this._gridUid}`, bodyMenuElm = document.body.querySelector(`.slick-cell-menu.slick-menu-level-${level}${this.getGridUidSelector()}`);
if (bodyMenuElm) {
if (bodyMenuElm.dataset.subMenuParent === subMenuId)
return bodyMenuElm;
this.destroySubMenus();
}
let menuElm = document.createElement("div");
menuElm.className = menuClasses, level > 0 && (menuElm.classList.add("slick-submenu"), subMenuId && (menuElm.dataset.subMenuParent = subMenuId)), menuElm.ariaLabel = level > 1 ? "SubMenu" : "Cell Menu", menuElm.role = "menu", width && (menuElm.style.width = width), maxHeight && (menuElm.style.maxHeight = maxHeight), menuElm.style.display = "none";
let closeButtonElm = null;
if (level === 0) {
closeButtonElm = document.createElement("button"), closeButtonElm.type = "button", closeButtonElm.className = "close", closeButtonElm.dataset.dismiss = "slick-cell-menu", closeButtonElm.ariaLabel = "Close";
let spanCloseElm = document.createElement("span");
spanCloseElm.className = "close", spanCloseElm.ariaHidden = "true", spanCloseElm.textContent = "\xD7", closeButtonElm.appendChild(spanCloseElm);
}
if (!this._cellMenuProperties.hideOptionSection && optionItems.length > 0) {
let optionMenuElm = document.createElement("div");
optionMenuElm.className = "slick-cell-menu-option-list", optionMenuElm.role = "menu", item && level > 0 && this.addSubMenuTitleWhenExists(item, optionMenuElm), closeButtonElm && !this._cellMenuProperties.hideCloseButton && (this._bindingEventService.bind(closeButtonElm, "click", this.handleCloseButtonClicked.bind(this)), menuElm.appendChild(closeButtonElm)), menuElm.appendChild(optionMenuElm), this.populateCommandOrOptionItems(
"option",
this._cellMenuProperties,
optionMenuElm,
optionItems,
{ cell: this._currentCell, row: this._currentRow, column: columnDef, dataContext, grid: this._grid, level }
);
}
if (!this._cellMenuProperties.hideCommandSection && commandItems.length > 0) {
let commandMenuElm = document.createElement("div");
commandMenuElm.className = "slick-cell-menu-command-list", commandMenuElm.role = "menu", item && level > 0 && this.addSubMenuTitleWhenExists(item, commandMenuElm), closeButtonElm && !this._cellMenuProperties.hideCloseButton && (optionItems.length === 0 || this._cellMenuProperties.hideOptionSection) && (this._bindingEventService.bind(closeButtonElm, "click", this.handleCloseButtonClicked.bind(this)), menuElm.appendChild(closeButtonElm)), menuElm.appendChild(commandMenuElm), this.populateCommandOrOptionItems(
"command",
this._cellMenuProperties,
commandMenuElm,
commandItems,
{ cell: this._currentCell, row: this._currentRow, column: columnDef, dataContext, grid: this._grid, level }
);
}
return level++, menuElm;
}
addSubMenuTitleWhenExists(item, commandOrOptionMenu) {
if (item !== "divider" && (item != null && item.subMenuTitle)) {
let subMenuTitleElm = document.createElement("div");
subMenuTitleElm.className = "slick-menu-title", subMenuTitleElm.textContent = item.subMenuTitle;
let subMenuTitleClass = item.subMenuTitleCssClass;
subMenuTitleClass && subMenuTitleElm.classList.add(...Utils.classNameToList(subMenuTitleClass)), commandOrOptionMenu.appendChild(subMenuTitleElm);
}
}
handleCloseButtonClicked(e) {
e.defaultPrevented || this.closeMenu(e);
}
/** Close and destroy Cell Menu */
closeMenu(e, args) {
var _a, _b;
if (this._menuElm) {
if (this.onBeforeMenuClose.notify({
cell: (_a = args == null ? void 0 : args.cell) != null ? _a : 0,
row: (_b = args == null ? void 0 : args.row) != null ? _b : 0,
grid: this._grid
}, e, this).getReturnValue() === !1)
return;
this._menuElm.remove(), this._menuElm = null;
}
this.destroySubMenus();
}
/** Destroy all parent menus and any sub-menus */
destroyAllMenus() {
this.destroySubMenus(), this._bindingEventService.unbindAll("parent-menu"), document.querySelectorAll(`.slick-cell-menu${this.getGridUidSelector()}`).forEach((subElm) => subElm.remove());
}
/** Close and destroy all previously opened sub-menus */
destroySubMenus() {
this._bindingEventService.unbindAll("sub-menu"), document.querySelectorAll(`.slick-cell-menu.slick-submenu${this.getGridUidSelector()}`).forEach((subElm) => subElm.remove());
}
repositionSubMenu(item, type, level, e) {
(e.target.classList.contains("slick-cell") || this._lastMenuTypeClicked !== type) && this.destroySubMenus();
let subMenuElm = this.createMenu((item == null ? void 0 : item.commandItems) || [], (item == null ? void 0 : item.optionItems) || [], level + 1, item);
subMenuElm.style.display = "block", document.body.appendChild(subMenuElm), this.repositionMenu(e, subMenuElm);
}
/**
* Reposition the menu drop (up/down) and the side (left/right)
* @param {*} event
*/
repositionMenu(e, menuElm) {
var _a, _b, _c, _d, _e, _f, _g;
let isSubMenu = menuElm.classList.contains("slick-submenu"), parentElm = isSubMenu ? e.target.closest(".slick-cell-menu-item") : e.target.closest(".slick-cell");
if (menuElm && parentElm) {
let parentOffset = Utils.offset(parentElm), menuOffsetLeft = parentElm ? (_a = parentOffset == null ? void 0 : parentOffset.left) != null ? _a : 0 : (_b = e == null ? void 0 : e.pageX) != null ? _b : 0, menuOffsetTop = parentElm ? (_c = parentOffset == null ? void 0 : parentOffset.top) != null ? _c : 0 : (_d = e == null ? void 0 : e.pageY) != null ? _d : 0, parentCellWidth = (parentElm == null ? void 0 : parentElm.offsetWidth) || 0, menuHeight = (_e = menuElm == null ? void 0 : menuElm.offsetHeight) != null ? _e : 0, menuWidth = Number((_g = (_f = menuElm == null ? void 0 : menuElm.offsetWidth) != null ? _f : this._cellMenuProperties.width) != null ? _g : 0), rowHeight = this._gridOptions.rowHeight, dropOffset = Number(this._cellMenuProperties.autoAdjustDropOffset || 0), sideOffset = Number(this._cellMenuProperties.autoAlignSideOffset || 0);
if (this._cellMenuProperties.autoAdjustDrop) {
let spaceBottom = Utils.calculateAvailableSpace(parentElm).bottom, spaceTop = Utils.calculateAvailableSpace(parentElm).top, spaceBottomRemaining = spaceBottom + dropOffset - rowHeight, spaceTopRemaining = spaceTop - dropOffset + rowHeight;
(spaceBottomRemaining < menuHeight && spaceTopRemaining > spaceBottomRemaining ? "top" : "bottom") === "top" ? (menuElm.classList.remove("dropdown"), menuElm.classList.add("dropup"), isSubMenu ? menuOffsetTop -= menuHeight - dropOffset - parentElm.clientHeight : menuOffsetTop -= menuHeight - dropOffset) : (menuElm.classList.remove("dropup"), menuElm.classList.add("dropdown"), isSubMenu ? menuOffsetTop += dropOffset : menuOffsetTop += rowHeight + dropOffset);
}
if (this._cellMenuProperties.autoAlignSide) {
let gridPos = this._grid.getGridPosition(), subMenuPosCalc = menuOffsetLeft + Number(menuWidth);
isSubMenu && (subMenuPosCalc += parentElm.clientWidth);
let browserWidth = document.documentElement.clientWidth;
(subMenuPosCalc >= gridPos.width || subMenuPosCalc >= browserWidth ? "left" : "right") === "left" ? (menuElm.classList.remove("dropright"), menuElm.classList.add("dropleft"), isSubMenu ? menuOffsetLeft -= menuWidth - sideOffset : menuOffsetLeft -= menuWidth - parentCellWidth - sideOffset) : (menuElm.classList.remove("dropleft"), menuElm.classList.add("dropright"), isSubMenu ? menuOffsetLeft += sideOffset + parentElm.offsetWidth : menuOffsetLeft += sideOffset);
}
menuElm.style.top = `${menuOffsetTop}px`, menuElm.style.left = `${menuOffsetLeft}px`;
}
}
getGridUidSelector() {
let gridUid = this._grid.getUID() || "";
return gridUid ? `.${gridUid}` : "";
}
handleCellClick(evt, args) {
this.destroyAllMenus();
let e = evt instanceof SlickEventData ? evt.getNativeEvent() : evt, cell = this._grid.getCellFromEvent(e);
if (cell) {
let dataContext = this._grid.getDataItem(cell.row), columnDef = this._grid.getColumns()[cell.cell];
if (columnDef != null && columnDef.cellMenu && e.preventDefault(), this._cellMenuProperties = Utils.extend({}, this._cellMenuProperties, columnDef.cellMenu), args = args || {}, args.column = columnDef, args.dataContext = dataContext, args.grid = this._grid, !this.runOverrideFunctionWhenExists(this._cellMenuProperties.menuUsabilityOverride, args))
return;
this._menuElm = this.createParentMenu(e), this._menuElm && (this.repositionMenu(e, this._menuElm), this._menuElm.setAttribute("aria-expanded", "true"), this._menuElm.style.display = "block"), this._bindingEventService.bind(document.body, "mousedown", this.handleBodyMouseDown.bind(this));
}
}
/** When users click outside the Cell Menu, we will typically close the Cell Menu (and any sub-menus) */
handleBodyMouseDown(e) {
var _a;
let isMenuClicked = !1;
(_a = this._menuElm) != null && _a.contains(e.target) && (isMenuClicked = !0), isMenuClicked || document.querySelectorAll(`.slick-cell-menu.slick-submenu${this.getGridUidSelector()}`).forEach((subElm) => {
subElm.contains(e.target) && (isMenuClicked = !0);
}), this._menuElm !== e.target && !isMenuClicked && !e.defaultPrevented && this.closeMenu(e, { cell: this._currentCell, row: this._currentRow, grid: this._grid });
}
/** Build the Command Items section. */
populateCommandOrOptionItems(itemType, cellMenu, commandOrOptionMenuElm, commandOrOptionItems, args) {
if (!args || !commandOrOptionItems || !cellMenu)
return;
let level = (args == null ? void 0 : args.level) || 0, isSubMenu = level > 0;
cellMenu != null && cellMenu[`${itemType}Title`] && !isSubMenu && (this[`_${itemType}TitleElm`] = document.createElement("div"), this[`_${itemType}TitleElm`].className = "slick-menu-title", this[`_${itemType}TitleElm`].textContent = cellMenu[`${itemType}Title`], commandOrOptionMenuElm.appendChild(this[`_${itemType}TitleElm`]));
for (let i = 0, ln = commandOrOptionItems.length; i < ln; i++) {
let addClickListener = !0, item = commandOrOptionItems[i], isItemVisible = this.runOverrideFunctionWhenExists(item.itemVisibilityOverride, args), isItemUsable = this.runOverrideFunctionWhenExists(item.itemUsabilityOverride, args);
if (!isItemVisible)
continue;
Object.prototype.hasOwnProperty.call(item, "itemUsabilityOverride") && (item.disabled = !isItemUsable);
let liElm = document.createElement("div");
liElm.className = "slick-cell-menu-item", liElm.role = "menuitem", (item.divider || item === "divider") && (liElm.classList.add("slick-cell-menu-item-divider"), addClickListener = !1), (item.disabled || !isItemUsable) && liElm.classList.add("slick-cell-menu-item-disabled"), item.hidden && liElm.classList.add("slick-cell-menu-item-hidden"), item.cssClass && liElm.classList.add(...Utils.classNameToList(item.cssClass)), item.tooltip && (liElm.title = item.tooltip || "");
let iconElm = document.createElement("div");
iconElm.className = "slick-cell-menu-icon", liElm.appendChild(iconElm), item.iconCssClass && iconElm.classList.add(...Utils.classNameToList(item.iconCssClass)), item.iconImage && (iconElm.style.backgroundImage = `url(${item.iconImage})`);
let textElm = document.createElement("span");
if (textElm.className = "slick-cell-menu-content", textElm.textContent = item.title || "", liElm.appendChild(textElm), item.textCssClass && textElm.classList.add(...Utils.classNameToList(item.textCssClass)), commandOrOptionMenuElm.appendChild(liElm), addClickListener) {
let eventGroup = isSubMenu ? "sub-menu" : "parent-menu";
this._bindingEventService.bind(liElm, "click", this.handleMenuItemClick.bind(this, item, itemType, level), void 0, eventGroup);
}
if (this._cellMenuProperties.subMenuOpenByEvent === "mouseover" && this._bindingEventService.bind(liElm, "mouseover", (e) => {
item.commandItems || item.optionItems ? (this.repositionSubMenu(item, itemType, level, e), this._lastMenuTypeClicked = itemType) : isSubMenu || this.destroySubMenus();
}), item.commandItems || item.optionItems) {
let chevronElm = document.createElement("span");
chevronElm.className = "sub-item-chevron", this._cellMenuProperties.subItemChevronClass ? chevronElm.classList.add(...Utils.classNameToList(this._cellMenuProperties.subItemChevronClass)) : chevronElm.textContent = "\u2B9E", liElm.classList.add("slick-submenu-item"), liElm.appendChild(chevronElm);
continue;
}
}
}
handleMenuItemClick(item, type, level = 0, e) {
if ((item == null ? void 0 : item[type]) !== void 0 && item !== "divider" && !item.disabled && !item.divider && this._currentCell !== void 0 && this._currentRow !== void 0) {
if (type === "option" && !this._grid.getEditorLock().commitCurrentEdit())
return;
let optionOrCommand = item[type] !== void 0 ? item[type] : "", row = this._currentRow, cell = this._currentCell, columnDef = this._grid.getColumns()[cell], dataContext = this._grid.getDataItem(row);
if (optionOrCommand !== void 0 && !item[`${type}Items`]) {
let callbackArgs = {
cell,
row,
grid: this._grid,
[type]: optionOrCommand,
item,
column: columnDef,
dataContext
};
this[type === "command" ? "onCommand" : "onOptionSelected"].notify(callbackArgs, e, this), typeof item.action == "function" && item.action.call(this, e, callbackArgs), e.defaultPrevented || this.closeMenu(e, { cell, row, grid: this._grid });
} else item.commandItems || item.optionItems ? this.repositionSubMenu(item, type, level, e) : this.destroySubMenus();
this._lastMenuTypeClicked = type;
}
}
/**
* Method that user can pass to override the default behavior.
* In order word, user can choose or an item is (usable/visible/enable) by providing his own logic.
* @param overrideFn: override function callback
* @param args: multiple arguments provided to the override (cell, row, columnDef, dataContext, grid)
*/
runOverrideFunctionWhenExists(overrideFn, args) {
return typeof overrideFn == "function" ? overrideFn.call(this, args) : !0;
}
};
window.Slick && Utils.extend(!0, window, {
Slick: {
Plugins: {
CellMenu: SlickCellMenu
}
}
});
})();
//# sourceMappingURL=slick.cellmenu.js.map
@@ -0,0 +1,56 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
// src/plugins/slick.cellrangedecorator.ts
var Utils = Slick.Utils, SlickCellRangeDecorator = class {
constructor(grid, options) {
this.grid = grid;
// --
// public API
__publicField(this, "pluginName", "CellRangeDecorator");
// --
// protected props
__publicField(this, "_options");
__publicField(this, "_elem");
__publicField(this, "_defaults", {
selectionCssClass: "slick-range-decorator",
selectionCss: {
zIndex: "9999",
border: "2px dashed red"
},
offset: { top: -1, left: -1, height: -2, width: -2 }
});
this._options = Utils.extend(!0, {}, this._defaults, options);
}
destroy() {
this.hide();
}
init() {
}
hide() {
var _a;
(_a = this._elem) == null || _a.remove(), this._elem = null;
}
show(range) {
var _a;
if (!this._elem) {
this._elem = document.createElement("div"), this._elem.className = this._options.selectionCssClass, Object.keys(this._options.selectionCss).forEach((cssStyleKey) => {
this._elem.style[cssStyleKey] = this._options.selectionCss[cssStyleKey];
}), this._elem.style.position = "absolute";
let canvasNode = this.grid.getActiveCanvasNode();
canvasNode && canvasNode.appendChild(this._elem);
}
let from = this.grid.getCellNodeBox(range.fromRow, range.fromCell), to = this.grid.getCellNodeBox(range.toRow, range.toCell);
return from && to && ((_a = this._options) != null && _a.offset) && (this._elem.style.top = `${from.top + this._options.offset.top}px`, this._elem.style.left = `${from.left + this._options.offset.left}px`, this._elem.style.height = `${to.bottom - from.top + this._options.offset.height}px`, this._elem.style.width = `${to.right - from.left + this._options.offset.width}px`), this._elem;
}
};
window.Slick && Utils.extend(!0, window, {
Slick: {
CellRangeDecorator: SlickCellRangeDecorator
}
});
})();
//# sourceMappingURL=slick.cellrangedecorator.js.map
@@ -0,0 +1,199 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
// src/plugins/slick.cellrangeselector.ts
var SlickEvent = Slick.Event, SlickEventHandler = Slick.EventHandler, SlickRange = Slick.Range, Draggable = Slick.Draggable, SlickCellRangeDecorator = Slick.CellRangeDecorator, Utils = Slick.Utils, SlickCellRangeSelector = class {
constructor(options) {
// --
// public API
__publicField(this, "pluginName", "CellRangeSelector");
__publicField(this, "onBeforeCellRangeSelected", new SlickEvent("onBeforeCellRangeSelected"));
__publicField(this, "onCellRangeSelected", new SlickEvent("onCellRangeSelected"));
__publicField(this, "onCellRangeSelecting", new SlickEvent("onCellRangeSelecting"));
// --
// protected props
__publicField(this, "_grid");
__publicField(this, "_currentlySelectedRange", null);
__publicField(this, "_canvas", null);
__publicField(this, "_decorator");
__publicField(this, "_gridOptions");
__publicField(this, "_activeCanvas");
__publicField(this, "_dragging", !1);
__publicField(this, "_handler", new SlickEventHandler());
__publicField(this, "_options");
__publicField(this, "_defaults", {
autoScroll: !0,
minIntervalToShowNextCell: 30,
maxIntervalToShowNextCell: 600,
// better to a multiple of minIntervalToShowNextCell
accelerateInterval: 5,
// increase 5ms when cursor 1px outside the viewport.
selectionCss: {
border: "2px dashed blue"
}
});
// Frozen row & column variables
__publicField(this, "_rowOffset", 0);
__publicField(this, "_columnOffset", 0);
__publicField(this, "_isRightCanvas", !1);
__publicField(this, "_isBottomCanvas", !1);
// autoScroll related constiables
__publicField(this, "_activeViewport");
__publicField(this, "_autoScrollTimerId");
__publicField(this, "_draggingMouseOffset");
__publicField(this, "_moveDistanceForOneCell");
__publicField(this, "_xDelayForNextCell", 0);
__publicField(this, "_yDelayForNextCell", 0);
__publicField(this, "_viewportHeight", 0);
__publicField(this, "_viewportWidth", 0);
__publicField(this, "_isRowMoveRegistered", !1);
// Scrollings
__publicField(this, "_scrollLeft", 0);
__publicField(this, "_scrollTop", 0);
this._options = Utils.extend(!0, {}, this._defaults, options);
}
init(grid) {
if (Draggable === void 0)
throw new Error('Slick.Draggable is undefined, make sure to import "slick.interactions.js"');
this._decorator = this._options.cellDecorator || new SlickCellRangeDecorator(grid, this._options), this._grid = grid, Utils.addSlickEventPubSubWhenDefined(grid.getPubSubService(), this), this._canvas = this._grid.getCanvasNode(), this._gridOptions = this._grid.getOptions(), this._handler.subscribe(this._grid.onScroll, this.handleScroll.bind(this)).subscribe(this._grid.onDragInit, this.handleDragInit.bind(this)).subscribe(this._grid.onDragStart, this.handleDragStart.bind(this)).subscribe(this._grid.onDrag, this.handleDrag.bind(this)).subscribe(this._grid.onDragEnd, this.handleDragEnd.bind(this));
}
destroy() {
var _a;
this._handler.unsubscribeAll(), this._activeCanvas = null, this._activeViewport = null, this._canvas = null, (_a = this._decorator) == null || _a.destroy();
}
getCellDecorator() {
return this._decorator;
}
handleScroll(_e, args) {
this._scrollTop = args.scrollTop, this._scrollLeft = args.scrollLeft;
}
handleDragInit(e) {
this._activeCanvas = this._grid.getActiveCanvasNode(e), this._activeViewport = this._grid.getActiveViewportNode(e);
let scrollbarDimensions = this._grid.getDisplayedScrollbarDimensions();
if (this._viewportWidth = this._activeViewport.offsetWidth - scrollbarDimensions.width, this._viewportHeight = this._activeViewport.offsetHeight - scrollbarDimensions.height, this._moveDistanceForOneCell = {
x: this._grid.getAbsoluteColumnMinWidth() / 2,
y: this._grid.getOptions().rowHeight / 2
}, this._isRowMoveRegistered = this.hasRowMoveManager(), this._rowOffset = 0, this._columnOffset = 0, this._isBottomCanvas = this._activeCanvas.classList.contains("grid-canvas-bottom"), this._gridOptions.frozenRow > -1 && this._isBottomCanvas) {
let canvasSelector = `.${this._grid.getUID()} .grid-canvas-${this._gridOptions.frozenBottom ? "bottom" : "top"}`, canvasElm = document.querySelector(canvasSelector);
canvasElm && (this._rowOffset = canvasElm.clientHeight || 0);
}
if (this._isRightCanvas = this._activeCanvas.classList.contains("grid-canvas-right"), this._gridOptions.frozenColumn > -1 && this._isRightCanvas) {
let canvasLeftElm = document.querySelector(`.${this._grid.getUID()} .grid-canvas-left`);
canvasLeftElm && (this._columnOffset = canvasLeftElm.clientWidth || 0);
}
e.stopImmediatePropagation(), e.preventDefault();
}
handleDragStart(e, dd) {
var _a, _b;
let cell = this._grid.getCellFromEvent(e);
if (cell && this.onBeforeCellRangeSelected.notify(cell).getReturnValue() !== !1 && this._grid.canCellBeSelected(cell.row, cell.cell) && (this._dragging = !0, e.stopImmediatePropagation()), !this._dragging)
return;
this._grid.focus();
let canvasOffset = Utils.offset(this._canvas), startX = dd.startX - ((_a = canvasOffset == null ? void 0 : canvasOffset.left) != null ? _a : 0);
this._gridOptions.frozenColumn >= 0 && this._isRightCanvas && (startX += this._scrollLeft);
let startY = dd.startY - ((_b = canvasOffset == null ? void 0 : canvasOffset.top) != null ? _b : 0);
this._gridOptions.frozenRow >= 0 && this._isBottomCanvas && (startY += this._scrollTop);
let start = this._grid.getCellFromPoint(startX, startY);
return dd.range = { start, end: {} }, this._currentlySelectedRange = dd.range, this._decorator.show(new SlickRange(start.row, start.cell));
}
handleDrag(evt, dd) {
if (!this._dragging && !this._isRowMoveRegistered)
return;
this._isRowMoveRegistered || evt.stopImmediatePropagation();
let e = evt.getNativeEvent();
if (this._options.autoScroll && (this._draggingMouseOffset = this.getMouseOffsetViewport(e, dd), this._draggingMouseOffset.isOutsideViewport))
return this.handleDragOutsideViewport();
this.stopIntervalTimer(), this.handleDragTo(e, dd);
}
getMouseOffsetViewport(e, dd) {
var _a, _b, _c, _d;
let targetEvent = (_b = (_a = e == null ? void 0 : e.touches) == null ? void 0 : _a[0]) != null ? _b : e, viewportLeft = this._activeViewport.scrollLeft, viewportTop = this._activeViewport.scrollTop, viewportRight = viewportLeft + this._viewportWidth, viewportBottom = viewportTop + this._viewportHeight, viewportOffset = Utils.offset(this._activeViewport), viewportOffsetLeft = (_c = viewportOffset == null ? void 0 : viewportOffset.left) != null ? _c : 0, viewportOffsetTop = (_d = viewportOffset == null ? void 0 : viewportOffset.top) != null ? _d : 0, viewportOffsetRight = viewportOffsetLeft + this._viewportWidth, viewportOffsetBottom = viewportOffsetTop + this._viewportHeight, result = {
e,
dd,
viewport: {
left: viewportLeft,
top: viewportTop,
right: viewportRight,
bottom: viewportBottom,
offset: {
left: viewportOffsetLeft,
top: viewportOffsetTop,
right: viewportOffsetRight,
bottom: viewportOffsetBottom
}
},
// Consider the viewport as the origin, the `offset` is based on the coordinate system:
// the cursor is on the viewport's left/bottom when it is less than 0, and on the right/top when greater than 0.
offset: {
x: 0,
y: 0
},
isOutsideViewport: !1
};
return targetEvent.pageX < viewportOffsetLeft ? result.offset.x = targetEvent.pageX - viewportOffsetLeft : targetEvent.pageX > viewportOffsetRight && (result.offset.x = targetEvent.pageX - viewportOffsetRight), targetEvent.pageY < viewportOffsetTop ? result.offset.y = viewportOffsetTop - targetEvent.pageY : targetEvent.pageY > viewportOffsetBottom && (result.offset.y = viewportOffsetBottom - targetEvent.pageY), result.isOutsideViewport = !!result.offset.x || !!result.offset.y, result;
}
handleDragOutsideViewport() {
if (this._xDelayForNextCell = this._options.maxIntervalToShowNextCell - Math.abs(this._draggingMouseOffset.offset.x) * this._options.accelerateInterval, this._yDelayForNextCell = this._options.maxIntervalToShowNextCell - Math.abs(this._draggingMouseOffset.offset.y) * this._options.accelerateInterval, !this._autoScrollTimerId) {
let xTotalDelay = 0, yTotalDelay = 0;
this._autoScrollTimerId = window.setInterval(() => {
let xNeedUpdate = !1, yNeedUpdate = !1;
this._draggingMouseOffset.offset.x ? (xTotalDelay += this._options.minIntervalToShowNextCell, xNeedUpdate = xTotalDelay >= this._xDelayForNextCell) : xTotalDelay = 0, this._draggingMouseOffset.offset.y ? (yTotalDelay += this._options.minIntervalToShowNextCell, yNeedUpdate = yTotalDelay >= this._yDelayForNextCell) : yTotalDelay = 0, (xNeedUpdate || yNeedUpdate) && (xNeedUpdate && (xTotalDelay = 0), yNeedUpdate && (yTotalDelay = 0), this.handleDragToNewPosition(xNeedUpdate, yNeedUpdate));
}, this._options.minIntervalToShowNextCell);
}
}
handleDragToNewPosition(xNeedUpdate, yNeedUpdate) {
let pageX = this._draggingMouseOffset.e.pageX, pageY = this._draggingMouseOffset.e.pageY, mouseOffsetX = this._draggingMouseOffset.offset.x, mouseOffsetY = this._draggingMouseOffset.offset.y, viewportOffset = this._draggingMouseOffset.viewport.offset;
xNeedUpdate && mouseOffsetX && (mouseOffsetX > 0 ? pageX = viewportOffset.right + this._moveDistanceForOneCell.x : pageX = viewportOffset.left - this._moveDistanceForOneCell.x), yNeedUpdate && mouseOffsetY && (mouseOffsetY > 0 ? pageY = viewportOffset.top - this._moveDistanceForOneCell.y : pageY = viewportOffset.bottom + this._moveDistanceForOneCell.y), this.handleDragTo({ pageX, pageY }, this._draggingMouseOffset.dd);
}
stopIntervalTimer() {
this._autoScrollTimerId && (window.clearInterval(this._autoScrollTimerId), this._autoScrollTimerId = void 0);
}
handleDragTo(e, dd) {
var _a, _b, _c, _d, _e, _f;
let targetEvent = (_b = (_a = e == null ? void 0 : e.touches) == null ? void 0 : _a[0]) != null ? _b : e, canvasOffset = Utils.offset(this._activeCanvas), end = this._grid.getCellFromPoint(
targetEvent.pageX - ((_c = canvasOffset == null ? void 0 : canvasOffset.left) != null ? _c : 0) + this._columnOffset,
targetEvent.pageY - ((_d = canvasOffset == null ? void 0 : canvasOffset.top) != null ? _d : 0) + this._rowOffset
);
if (!(this._gridOptions.frozenColumn >= 0 && !this._isRightCanvas && end.cell > this._gridOptions.frozenColumn || this._isRightCanvas && end.cell <= this._gridOptions.frozenColumn) && !(this._gridOptions.frozenRow >= 0 && !this._isBottomCanvas && end.row >= this._gridOptions.frozenRow || this._isBottomCanvas && end.row < this._gridOptions.frozenRow)) {
if (this._options.autoScroll && this._draggingMouseOffset) {
let endCellBox = this._grid.getCellNodeBox(end.row, end.cell);
if (!endCellBox)
return;
let viewport = this._draggingMouseOffset.viewport;
(endCellBox.left < viewport.left || endCellBox.right > viewport.right || endCellBox.top < viewport.top || endCellBox.bottom > viewport.bottom) && this._grid.scrollCellIntoView(end.row, end.cell);
}
if (this._grid.canCellBeSelected(end.row, end.cell) && dd != null && dd.range) {
dd.range.end = end;
let range = new SlickRange((_e = dd.range.start.row) != null ? _e : 0, (_f = dd.range.start.cell) != null ? _f : 0, end.row, end.cell);
this._decorator.show(range), this.onCellRangeSelecting.notify({
range
});
}
}
}
hasRowMoveManager() {
return !!(this._grid.getPluginByName("RowMoveManager") || this._grid.getPluginByName("CrossGridRowMoveManager"));
}
handleDragEnd(e, dd) {
var _a, _b;
this._decorator.hide(), this._dragging && (this._dragging = !1, e.stopImmediatePropagation(), this.stopIntervalTimer(), this.onCellRangeSelected.notify({
range: new SlickRange(
(_a = dd.range.start.row) != null ? _a : 0,
(_b = dd.range.start.cell) != null ? _b : 0,
dd.range.end.row,
dd.range.end.cell
)
}));
}
getCurrentRange() {
return this._currentlySelectedRange;
}
};
window.Slick && Utils.extend(Slick, {
CellRangeSelector: SlickCellRangeSelector
});
})();
//# sourceMappingURL=slick.cellrangeselector.js.map
@@ -0,0 +1,114 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
// src/plugins/slick.cellselectionmodel.ts
var SlickEvent = Slick.Event, SlickEventData = Slick.EventData, SlickRange = Slick.Range, SlickCellRangeSelector = Slick.CellRangeSelector, Utils = Slick.Utils, SlickCellSelectionModel = class {
constructor(options) {
// --
// public API
__publicField(this, "pluginName", "CellSelectionModel");
__publicField(this, "onSelectedRangesChanged", new SlickEvent("onSelectedRangesChanged"));
// --
// protected props
__publicField(this, "_cachedPageRowCount", 0);
__publicField(this, "_dataView");
__publicField(this, "_grid");
__publicField(this, "_prevSelectedRow");
__publicField(this, "_prevKeyDown", "");
__publicField(this, "_ranges", []);
__publicField(this, "_selector");
__publicField(this, "_options");
__publicField(this, "_defaults", {
selectActiveCell: !0
});
options === void 0 || options.cellRangeSelector === void 0 ? this._selector = new Slick.CellRangeSelector({ selectionCss: { border: "2px solid black" } }) : this._selector = options.cellRangeSelector;
}
init(grid) {
this._options = Utils.extend(!0, {}, this._defaults, this._options), this._grid = grid, grid.hasDataView() && (this._dataView = grid.getData()), this._grid.onActiveCellChanged.subscribe(this.handleActiveCellChange.bind(this)), this._grid.onKeyDown.subscribe(this.handleKeyDown.bind(this)), grid.registerPlugin(this._selector), this._selector.onCellRangeSelected.subscribe(this.handleCellRangeSelected.bind(this)), this._selector.onBeforeCellRangeSelected.subscribe(this.handleBeforeCellRangeSelected.bind(this));
}
destroy() {
var _a;
this._grid.onActiveCellChanged.unsubscribe(this.handleActiveCellChange.bind(this)), this._grid.onKeyDown.unsubscribe(this.handleKeyDown.bind(this)), this._selector.onCellRangeSelected.unsubscribe(this.handleCellRangeSelected.bind(this)), this._selector.onBeforeCellRangeSelected.unsubscribe(this.handleBeforeCellRangeSelected.bind(this)), this._grid.unregisterPlugin(this._selector), (_a = this._selector) == null || _a.destroy();
}
removeInvalidRanges(ranges) {
let result = [];
for (let i = 0; i < ranges.length; i++) {
let r = ranges[i];
this._grid.canCellBeSelected(r.fromRow, r.fromCell) && this._grid.canCellBeSelected(r.toRow, r.toCell) && result.push(r);
}
return result;
}
rangesAreEqual(range1, range2) {
let areDifferent = range1.length !== range2.length;
if (!areDifferent) {
for (let i = 0; i < range1.length; i++)
if (range1[i].fromCell !== range2[i].fromCell || range1[i].fromRow !== range2[i].fromRow || range1[i].toCell !== range2[i].toCell || range1[i].toRow !== range2[i].toRow) {
areDifferent = !0;
break;
}
}
return !areDifferent;
}
/** Provide a way to force a recalculation of page row count (for example on grid resize) */
resetPageRowCount() {
this._cachedPageRowCount = 0;
}
setSelectedRanges(ranges, caller = "SlickCellSelectionModel.setSelectedRanges") {
if ((!this._ranges || this._ranges.length === 0) && (!ranges || ranges.length === 0))
return;
let rangeHasChanged = !this.rangesAreEqual(this._ranges, ranges);
if (this._ranges = this.removeInvalidRanges(ranges), rangeHasChanged) {
let eventData = new SlickEventData(new CustomEvent("click", { detail: { caller } }), this._ranges);
this.onSelectedRangesChanged.notify(this._ranges, eventData);
}
}
getSelectedRanges() {
return this._ranges;
}
refreshSelections() {
this.setSelectedRanges(this.getSelectedRanges());
}
handleBeforeCellRangeSelected(e) {
if (this._grid.getEditorLock().isActive())
return e.stopPropagation(), !1;
}
handleCellRangeSelected(_e, args) {
this._grid.setActiveCell(args.range.fromRow, args.range.fromCell, !1, !1, !0), this.setSelectedRanges([args.range]);
}
handleActiveCellChange(_e, args) {
var _a, _b;
this._prevSelectedRow = void 0;
let isCellDefined = Utils.isDefined(args.cell), isRowDefined = Utils.isDefined(args.row);
(_a = this._options) != null && _a.selectActiveCell && isRowDefined && isCellDefined ? this.setSelectedRanges([new SlickRange(args.row, args.cell)]) : (!((_b = this._options) != null && _b.selectActiveCell) || !isRowDefined && !isCellDefined) && this.setSelectedRanges([]);
}
isKeyAllowed(key) {
return ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "PageDown", "PageUp", "Home", "End"].some((k) => k === key);
}
handleKeyDown(e) {
var _a;
let ranges, last, colLn = this._grid.getColumns().length, active = this._grid.getActiveCell(), dataLn = 0;
if (this._dataView && "getPagingInfo" in this._dataView ? dataLn = ((_a = this._dataView) == null ? void 0 : _a.getPagingInfo().pageSize) || this._dataView.getLength() : dataLn = this._grid.getDataLength(), active && (e.shiftKey || e.ctrlKey) && !e.altKey && this.isKeyAllowed(e.key)) {
ranges = this.getSelectedRanges().slice(), ranges.length || ranges.push(new SlickRange(active.row, active.cell)), last = ranges.pop(), last.contains(active.row, active.cell) || (last = new SlickRange(active.row, active.cell));
let dRow = last.toRow - last.fromRow, dCell = last.toCell - last.fromCell, dirRow = active.row === last.fromRow ? 1 : -1, dirCell = active.cell === last.fromCell ? 1 : -1, isSingleKeyMove = e.key.startsWith("Arrow"), toCell, toRow = 0;
isSingleKeyMove && !e.ctrlKey ? (e.key === "ArrowLeft" ? dCell -= dirCell : e.key === "ArrowRight" ? dCell += dirCell : e.key === "ArrowUp" ? dRow -= dirRow : e.key === "ArrowDown" && (dRow += dirRow), toRow = active.row + dirRow * dRow) : (this._cachedPageRowCount < 1 && (this._cachedPageRowCount = this._grid.getViewportRowCount()), this._prevSelectedRow === void 0 && (this._prevSelectedRow = active.row), e.shiftKey && !e.ctrlKey && e.key === "Home" ? (toCell = 0, toRow = active.row) : e.shiftKey && !e.ctrlKey && e.key === "End" ? (toCell = colLn - 1, toRow = active.row) : e.ctrlKey && e.shiftKey && e.key === "Home" ? (toCell = 0, toRow = 0) : e.ctrlKey && e.shiftKey && e.key === "End" ? (toCell = colLn - 1, toRow = dataLn - 1) : e.key === "PageUp" ? (this._prevSelectedRow >= 0 && (toRow = this._prevSelectedRow - this._cachedPageRowCount), toRow < 0 && (toRow = 0)) : e.key === "PageDown" && (this._prevSelectedRow <= dataLn - 1 && (toRow = this._prevSelectedRow + this._cachedPageRowCount), toRow > dataLn - 1 && (toRow = dataLn - 1)), this._prevSelectedRow = toRow), toCell != null || (toCell = active.cell + dirCell * dCell);
let new_last = new SlickRange(active.row, active.cell, toRow, toCell);
if (this.removeInvalidRanges([new_last]).length) {
ranges.push(new_last);
let viewRow = dirRow > 0 ? new_last.toRow : new_last.fromRow, viewCell = dirCell > 0 ? new_last.toCell : new_last.fromCell;
isSingleKeyMove ? (this._grid.scrollRowIntoView(viewRow), this._grid.scrollCellIntoView(viewRow, viewCell)) : (this._grid.scrollRowIntoView(toRow), this._grid.scrollCellIntoView(toRow, viewCell));
} else
ranges.push(last);
this.setSelectedRanges(ranges), e.preventDefault(), e.stopPropagation(), this._prevKeyDown = e.key;
}
}
};
window.Slick && Utils.extend(!0, window, {
Slick: {
CellSelectionModel: SlickCellSelectionModel
}
});
})();
//# sourceMappingURL=slick.cellselectionmodel.js.map
@@ -0,0 +1,269 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
// src/plugins/slick.checkboxselectcolumn.ts
var BindingEventService = Slick.BindingEventService, SlickEventHandler = Slick.EventHandler, Utils = Slick.Utils, SlickCheckboxSelectColumn = class {
constructor(options) {
// --
// public API
__publicField(this, "pluginName", "CheckboxSelectColumn");
// --
// protected props
__publicField(this, "_dataView");
__publicField(this, "_grid");
__publicField(this, "_isUsingDataView", !1);
__publicField(this, "_selectableOverride", null);
__publicField(this, "_headerRowNode");
__publicField(this, "_selectAll_UID");
__publicField(this, "_handler", new SlickEventHandler());
__publicField(this, "_selectedRowsLookup", {});
__publicField(this, "_checkboxColumnCellIndex", null);
__publicField(this, "_options");
__publicField(this, "_defaults", {
columnId: "_checkbox_selector",
cssClass: void 0,
hideSelectAllCheckbox: !1,
name: "",
toolTip: "Select/Deselect All",
width: 30,
reorderable: !1,
applySelectOnAllPages: !1,
// defaults to false, when that is enabled the "Select All" will be applied to all pages (when using Pagination)
hideInColumnTitleRow: !1,
hideInFilterHeaderRow: !0
});
__publicField(this, "_isSelectAllChecked", !1);
__publicField(this, "_bindingEventService");
this._bindingEventService = new BindingEventService(), this._options = Utils.extend(!0, {}, this._defaults, options), this._selectAll_UID = this.createUID(), typeof this._options.selectableOverride == "function" && this.selectableOverride(this._options.selectableOverride);
}
init(grid) {
this._grid = grid, this._isUsingDataView = !Array.isArray(grid.getData()), this._isUsingDataView && (this._dataView = grid.getData()), this._handler.subscribe(this._grid.onSelectedRowsChanged, this.handleSelectedRowsChanged.bind(this)).subscribe(this._grid.onClick, this.handleClick.bind(this)).subscribe(this._grid.onKeyDown, this.handleKeyDown.bind(this)), this._isUsingDataView && this._dataView && this._options.applySelectOnAllPages && this._handler.subscribe(this._dataView.onSelectedRowIdsChanged, this.handleDataViewSelectedIdsChanged.bind(this)).subscribe(this._dataView.onPagingInfoChanged, this.handleDataViewSelectedIdsChanged.bind(this)), this._options.hideInFilterHeaderRow || this.addCheckboxToFilterHeaderRow(grid), this._options.hideInColumnTitleRow || this._handler.subscribe(this._grid.onHeaderClick, this.handleHeaderClick.bind(this));
}
destroy() {
this._handler.unsubscribeAll(), this._bindingEventService.unbindAll();
}
getOptions() {
return this._options;
}
setOptions(options) {
var _a;
if (this._options = Utils.extend(!0, {}, this._options, options), this._options.hideSelectAllCheckbox)
this.hideSelectAllFromColumnHeaderTitleRow(), this.hideSelectAllFromColumnHeaderFilterRow();
else if (this._options.hideInColumnTitleRow ? (this.hideSelectAllFromColumnHeaderTitleRow(), this._options.name && this._grid.updateColumnHeader(this._options.columnId || "", this._options.name, "")) : (this.renderSelectAllCheckbox(this._isSelectAllChecked), this._handler.subscribe(this._grid.onHeaderClick, this.handleHeaderClick.bind(this))), this._options.hideInFilterHeaderRow)
this.hideSelectAllFromColumnHeaderFilterRow();
else {
let selectAllContainerElm = (_a = this._headerRowNode) == null ? void 0 : _a.querySelector("#filter-checkbox-selectall-container");
if (selectAllContainerElm) {
selectAllContainerElm.style.display = "flex";
let selectAllInputElm = selectAllContainerElm.querySelector('input[type="checkbox"]');
selectAllInputElm && (selectAllInputElm.checked = this._isSelectAllChecked);
}
}
}
hideSelectAllFromColumnHeaderTitleRow() {
this._grid.updateColumnHeader(this._options.columnId || "", this._options.name || "", "");
}
hideSelectAllFromColumnHeaderFilterRow() {
var _a;
let selectAllContainerElm = (_a = this._headerRowNode) == null ? void 0 : _a.querySelector("#filter-checkbox-selectall-container");
selectAllContainerElm && (selectAllContainerElm.style.display = "none");
}
handleSelectedRowsChanged() {
var _a, _b;
let selectedRows = this._grid.getSelectedRows(), lookup = {}, row = 0, i = 0, k = 0, disabledCount = 0;
if (typeof this._selectableOverride == "function")
for (k = 0; k < this._grid.getDataLength(); k++) {
let dataItem = this._grid.getDataItem(k);
this.checkSelectableOverride(i, dataItem, this._grid) || disabledCount++;
}
let removeList = [];
for (i = 0; i < selectedRows.length; i++) {
row = selectedRows[i];
let rowItem = this._grid.getDataItem(row);
this.checkSelectableOverride(i, rowItem, this._grid) ? (lookup[row] = !0, lookup[row] !== this._selectedRowsLookup[row] && (this._grid.invalidateRow(row), delete this._selectedRowsLookup[row])) : removeList.push(row);
}
if (typeof this._selectedRowsLookup == "object" && Object.keys(this._selectedRowsLookup).forEach((selectedRow) => {
selectedRow !== void 0 && this._grid.invalidateRow(+selectedRow);
}), this._selectedRowsLookup = lookup, this._grid.render(), this._isSelectAllChecked = ((_a = selectedRows == null ? void 0 : selectedRows.length) != null ? _a : 0) + disabledCount >= this._grid.getDataLength(), (!this._isUsingDataView || !this._options.applySelectOnAllPages) && (!this._options.hideInColumnTitleRow && !this._options.hideSelectAllCheckbox && this.renderSelectAllCheckbox(this._isSelectAllChecked), !this._options.hideInFilterHeaderRow)) {
let selectAllElm = (_b = this._headerRowNode) == null ? void 0 : _b.querySelector(`#header-filter-selector${this._selectAll_UID}`);
selectAllElm && (selectAllElm.checked = this._isSelectAllChecked);
}
if (removeList.length > 0) {
for (i = 0; i < removeList.length; i++) {
let remIdx = selectedRows.indexOf(removeList[i]);
selectedRows.splice(remIdx, 1);
}
this._grid.setSelectedRows(selectedRows, "click.cleanup");
}
}
handleDataViewSelectedIdsChanged() {
var _a;
let selectedIds = this._dataView.getAllSelectedFilteredIds(), filteredItems = this._dataView.getFilteredItems(), disabledCount = 0;
if (typeof this._selectableOverride == "function" && selectedIds.length > 0)
for (let k = 0; k < this._dataView.getItemCount(); k++) {
let dataItem = this._dataView.getItemByIdx(k), idProperty = this._dataView.getIdPropertyName(), dataItemId = dataItem[idProperty];
filteredItems.findIndex(function(item) {
return item[idProperty] === dataItemId;
}) >= 0 && !this.checkSelectableOverride(k, dataItem, this._grid) && disabledCount++;
}
if (this._isSelectAllChecked = (selectedIds && selectedIds.length) + disabledCount >= filteredItems.length, !this._options.hideInColumnTitleRow && !this._options.hideSelectAllCheckbox && this.renderSelectAllCheckbox(this._isSelectAllChecked), !this._options.hideInFilterHeaderRow) {
let selectAllElm = (_a = this._headerRowNode) == null ? void 0 : _a.querySelector(`#header-filter-selector${this._selectAll_UID}`);
selectAllElm && (selectAllElm.checked = this._isSelectAllChecked);
}
}
handleKeyDown(e, args) {
e.which === 32 && this._grid.getColumns()[args.cell].id === this._options.columnId && ((!this._grid.getEditorLock().isActive() || this._grid.getEditorLock().commitCurrentEdit()) && this.toggleRowSelection(args.row), e.preventDefault(), e.stopImmediatePropagation());
}
handleClick(e, args) {
if (this._grid.getColumns()[args.cell].id === this._options.columnId && e.target.type === "checkbox") {
if (this._grid.getEditorLock().isActive() && !this._grid.getEditorLock().commitCurrentEdit()) {
e.preventDefault(), e.stopImmediatePropagation();
return;
}
this.toggleRowSelection(args.row), e.stopPropagation(), e.stopImmediatePropagation();
}
}
toggleRowSelection(row) {
let dataContext = this._grid.getDataItem(row);
if (this.checkSelectableOverride(row, dataContext, this._grid)) {
if (this._selectedRowsLookup[row]) {
let newSelectedRows = this._grid.getSelectedRows().filter((n) => n !== row);
this._grid.setSelectedRows(newSelectedRows, "click.toggle");
} else
this._grid.setSelectedRows(this._grid.getSelectedRows().concat(row), "click.toggle");
this._grid.setActiveCell(row, this.getCheckboxColumnCellIndex());
}
}
selectRows(rowArray) {
let addRows = [];
for (let i = 0, l = rowArray.length; i < l; i++)
this._selectedRowsLookup[rowArray[i]] || (addRows[addRows.length] = rowArray[i]);
this._grid.setSelectedRows(this._grid.getSelectedRows().concat(addRows), "SlickCheckboxSelectColumn.selectRows");
}
deSelectRows(rowArray) {
let removeRows = [];
for (let i = 0, l = rowArray.length; i < l; i++)
this._selectedRowsLookup[rowArray[i]] && (removeRows[removeRows.length] = rowArray[i]);
this._grid.setSelectedRows(this._grid.getSelectedRows().filter((n) => removeRows.indexOf(n) < 0), "SlickCheckboxSelectColumn.deSelectRows");
}
handleHeaderClick(e, args) {
if (args.column.id === this._options.columnId && e.target.type === "checkbox") {
if (this._grid.getEditorLock().isActive() && !this._grid.getEditorLock().commitCurrentEdit()) {
e.preventDefault(), e.stopImmediatePropagation();
return;
}
let isAllSelected = e.target.checked, caller = isAllSelected ? "click.selectAll" : "click.unselectAll", rows = [];
if (isAllSelected) {
for (let i = 0; i < this._grid.getDataLength(); i++) {
let rowItem = this._grid.getDataItem(i);
!rowItem.__group && !rowItem.__groupTotals && this.checkSelectableOverride(i, rowItem, this._grid) && rows.push(i);
}
isAllSelected = !0;
}
if (this._isUsingDataView && this._dataView && this._options.applySelectOnAllPages) {
let ids = [], filteredItems = this._dataView.getFilteredItems();
for (let j = 0; j < filteredItems.length; j++) {
let dataviewRowItem = filteredItems[j];
this.checkSelectableOverride(j, dataviewRowItem, this._grid) && ids.push(dataviewRowItem[this._dataView.getIdPropertyName()]);
}
this._dataView.setSelectedIds(ids, { isRowBeingAdded: isAllSelected });
}
this._grid.setSelectedRows(rows, caller), e.stopPropagation(), e.stopImmediatePropagation();
}
}
getCheckboxColumnCellIndex() {
if (this._checkboxColumnCellIndex === null) {
this._checkboxColumnCellIndex = 0;
let colArr = this._grid.getColumns();
for (let i = 0; i < colArr.length; i++)
colArr[i].id === this._options.columnId && (this._checkboxColumnCellIndex = i);
}
return this._checkboxColumnCellIndex;
}
/**
* use a DocumentFragment to return a fragment including an <input> then a <label> as siblings,
* the label is using `for` to link it to the input `id`
* @param {String} inputId - id to link the label
* @param {Boolean} [checked] - is the input checkbox checked? (defaults to false)
* @returns
*/
createCheckboxElement(inputId, checked = !1) {
let fragmentElm = new DocumentFragment();
return fragmentElm.appendChild(
Utils.createDomElement("input", { id: inputId, type: "checkbox", checked, ariaChecked: String(checked) })
), fragmentElm.appendChild(
Utils.createDomElement("label", { htmlFor: inputId })
), fragmentElm;
}
getColumnDefinition() {
var _a, _b, _c;
return {
id: this._options.columnId,
reorderable: this._options.reorderable,
name: this._options.hideSelectAllCheckbox || this._options.hideInColumnTitleRow ? this._options.name || "" : this.createCheckboxElement(`header-selector${this._selectAll_UID}`),
toolTip: this._options.hideSelectAllCheckbox || this._options.hideInColumnTitleRow ? "" : this._options.toolTip,
field: "sel",
width: this._options.width,
resizable: !1,
sortable: !1,
cssClass: this._options.cssClass,
hideSelectAllCheckbox: this._options.hideSelectAllCheckbox,
formatter: this.checkboxSelectionFormatter.bind(this),
// exclude from all menus, defaults to true unless the option is provided differently by the user
excludeFromColumnPicker: (_a = this._options.excludeFromColumnPicker) != null ? _a : !0,
excludeFromGridMenu: (_b = this._options.excludeFromGridMenu) != null ? _b : !0,
excludeFromHeaderMenu: (_c = this._options.excludeFromHeaderMenu) != null ? _c : !0
};
}
addCheckboxToFilterHeaderRow(grid) {
this._handler.subscribe(grid.onHeaderRowCellRendered, (_e, args) => {
if (args.column.field === "sel") {
Utils.emptyElement(args.node);
let spanElm = Utils.createDomElement("span", { id: "filter-checkbox-selectall-container", ariaChecked: "false" });
spanElm.appendChild(
Utils.createDomElement("input", { type: "checkbox", id: `header-filter-selector${this._selectAll_UID}` })
), spanElm.appendChild(
Utils.createDomElement("label", { htmlFor: `header-filter-selector${this._selectAll_UID}` })
), args.node.appendChild(spanElm), this._headerRowNode = args.node, this._bindingEventService.bind(spanElm, "click", (e) => this.handleHeaderClick(e, args));
}
});
}
createUID() {
return Math.round(1e7 * Math.random());
}
checkboxSelectionFormatter(row, _cell, _val, _columnDef, dataContext, grid) {
if (dataContext && this.checkSelectableOverride(row, dataContext, grid)) {
let UID = this.createUID() + row;
return this.createCheckboxElement(`selector${UID}`, !!this._selectedRowsLookup[row]);
}
return null;
}
checkSelectableOverride(row, dataContext, grid) {
return typeof this._selectableOverride == "function" ? this._selectableOverride(row, dataContext, grid) : !0;
}
renderSelectAllCheckbox(isSelectAllChecked) {
this._grid.updateColumnHeader(
this._options.columnId || "",
this.createCheckboxElement(`header-selector${this._selectAll_UID}`, !!isSelectAllChecked),
this._options.toolTip
);
}
/**
* Method that user can pass to override the default behavior or making every row a selectable row.
* In order word, user can choose which rows to be selectable or not by providing his own logic.
* @param overrideFn: override function callback
*/
selectableOverride(overrideFn) {
this._selectableOverride = overrideFn;
}
};
window.Slick && Utils.extend(!0, window, {
Slick: {
CheckboxSelectColumn: SlickCheckboxSelectColumn
}
});
})();
//# sourceMappingURL=slick.checkboxselectcolumn.js.map
@@ -0,0 +1,275 @@
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
// src/plugins/slick.contextmenu.ts
var BindingEventService = Slick.BindingEventService, SlickEvent = Slick.Event, SlickEventData = Slick.EventData, EventHandler = Slick.EventHandler, Utils = Slick.Utils, SlickContextMenu = class {
constructor(optionProperties) {
// --
// public API
__publicField(this, "pluginName", "ContextMenu");
__publicField(this, "onAfterMenuShow", new SlickEvent("onAfterMenuShow"));
__publicField(this, "onBeforeMenuShow", new SlickEvent("onBeforeMenuShow"));
__publicField(this, "onBeforeMenuClose", new SlickEvent("onBeforeMenuClose"));
__publicField(this, "onCommand", new SlickEvent("onCommand"));
__publicField(this, "onOptionSelected", new SlickEvent("onOptionSelected"));
// --
// protected props
__publicField(this, "_bindingEventService", new BindingEventService());
__publicField(this, "_contextMenuProperties");
__publicField(this, "_currentCell", -1);
__publicField(this, "_currentRow", -1);
__publicField(this, "_grid");
__publicField(this, "_gridOptions");
__publicField(this, "_gridUid", "");
__publicField(this, "_handler", new EventHandler());
__publicField(this, "_commandTitleElm");
__publicField(this, "_optionTitleElm");
__publicField(this, "_lastMenuTypeClicked", "");
__publicField(this, "_menuElm");
__publicField(this, "_subMenuParentId", "");
__publicField(this, "_defaults", {
autoAdjustDrop: !0,
// dropup/dropdown
autoAlignSide: !0,
// left/right
autoAdjustDropOffset: -4,
autoAlignSideOffset: 0,
hideMenuOnScroll: !1,
maxHeight: "none",
width: "auto",
optionShownOverColumnIds: [],
commandShownOverColumnIds: [],
subMenuOpenByEvent: "mouseover"
});
this._contextMenuProperties = Utils.extend({}, this._defaults, optionProperties);
}
init(grid) {
this._grid = grid, this._gridOptions = grid.getOptions(), this._gridUid = grid.getUID() || "", Utils.addSlickEventPubSubWhenDefined(grid.getPubSubService(), this), this._handler.subscribe(this._grid.onContextMenu, this.handleOnContextMenu.bind(this)), this._contextMenuProperties.hideMenuOnScroll && this._handler.subscribe(this._grid.onScroll, this.destroyMenu.bind(this));
}
setOptions(newOptions) {
this._contextMenuProperties = Utils.extend({}, this._contextMenuProperties, newOptions), newOptions.commandShownOverColumnIds && (this._contextMenuProperties.commandShownOverColumnIds = newOptions.commandShownOverColumnIds), newOptions.optionShownOverColumnIds && (this._contextMenuProperties.optionShownOverColumnIds = newOptions.optionShownOverColumnIds);
}
destroy() {
var _a;
this.onAfterMenuShow.unsubscribe(), this.onBeforeMenuShow.unsubscribe(), this.onBeforeMenuClose.unsubscribe(), this.onCommand.unsubscribe(), this.onOptionSelected.unsubscribe(), this._handler.unsubscribeAll(), this._bindingEventService.unbindAll(), (_a = this._menuElm) == null || _a.remove(), this._commandTitleElm = null, this._optionTitleElm = null, this._menuElm = null;
}
createParentMenu(evt) {
var _a, _b, _c, _d, _e, _f;
let e = evt instanceof SlickEventData ? evt.getNativeEvent() : evt, targetEvent = (_b = (_a = e.touches) == null ? void 0 : _a[0]) != null ? _b : e, cell = this._grid.getCellFromEvent(e);
this._currentCell = (_c = cell == null ? void 0 : cell.cell) != null ? _c : 0, this._currentRow = (_d = cell == null ? void 0 : cell.row) != null ? _d : 0;
let columnDef = this._grid.getColumns()[this._currentCell], isColumnOptionAllowed = this.checkIsColumnAllowed((_e = this._contextMenuProperties.optionShownOverColumnIds) != null ? _e : [], columnDef.id), isColumnCommandAllowed = this.checkIsColumnAllowed((_f = this._contextMenuProperties.commandShownOverColumnIds) != null ? _f : [], columnDef.id), commandItems = this._contextMenuProperties.commandItems || [], optionItems = this._contextMenuProperties.optionItems || [];
if (!(!columnDef || !isColumnCommandAllowed && !isColumnOptionAllowed || !commandItems.length && !optionItems.length) && (this.destroyMenu(e), this.onBeforeMenuShow.notify({
cell: this._currentCell,
row: this._currentRow,
grid: this._grid
}, e, this).getReturnValue() !== !1 && (this._menuElm = this.createMenu(commandItems, optionItems), this._menuElm.style.top = `${targetEvent.pageY}px`, this._menuElm.style.left = `${targetEvent.pageX}px`, this._menuElm.style.display = "block", document.body.appendChild(this._menuElm), this.onAfterMenuShow.notify({
cell: this._currentCell,
row: this._currentRow,
grid: this._grid
}, e, this).getReturnValue() !== !1)))
return this._menuElm;
}
createMenu(commandItems, optionItems, level = 0, item) {
var _a, _b, _c, _d;
let columnDef = this._grid.getColumns()[this._currentCell], dataContext = this._grid.getDataItem(this._currentRow), isColumnOptionAllowed = this.checkIsColumnAllowed((_a = this._contextMenuProperties.optionShownOverColumnIds) != null ? _a : [], columnDef.id), isColumnCommandAllowed = this.checkIsColumnAllowed((_b = this._contextMenuProperties.commandShownOverColumnIds) != null ? _b : [], columnDef.id), maxHeight = isNaN(this._contextMenuProperties.maxHeight) ? this._contextMenuProperties.maxHeight : `${(_c = this._contextMenuProperties.maxHeight) != null ? _c : 0}px`, width = isNaN(this._contextMenuProperties.width) ? this._contextMenuProperties.width : `${(_d = this._contextMenuProperties.maxWidth) != null ? _d : 0}px`, subMenuCommand = item == null ? void 0 : item.command, subMenuId = level === 1 && subMenuCommand ? subMenuCommand.replaceAll(" ", "") : "";
subMenuId && (this._subMenuParentId = subMenuId), level > 1 && (subMenuId = this._subMenuParentId);
let menuClasses = `slick-context-menu slick-menu-level-${level} ${this._gridUid}`, bodyMenuElm = document.body.querySelector(`.slick-context-menu.slick-menu-level-${level}${this.getGridUidSelector()}`);
if (bodyMenuElm) {
if (bodyMenuElm.dataset.subMenuParent === subMenuId)
return bodyMenuElm;
this.destroySubMenus();
}
let menuElm = document.createElement("div");
menuElm.className = menuClasses, level > 0 && (menuElm.classList.add("slick-submenu"), subMenuId && (menuElm.dataset.subMenuParent = subMenuId)), menuElm.ariaLabel = level > 1 ? "SubMenu" : "Context Menu", menuElm.role = "menu", width && (menuElm.style.width = width), maxHeight && (menuElm.style.maxHeight = maxHeight), menuElm.style.display = "none";
let closeButtonElm = null;
if (level === 0) {
closeButtonElm = document.createElement("button"), closeButtonElm.type = "button", closeButtonElm.className = "close", closeButtonElm.dataset.dismiss = "slick-context-menu", closeButtonElm.ariaLabel = "Close";
let spanCloseElm = document.createElement("span");
spanCloseElm.className = "close", spanCloseElm.ariaHidden = "true", spanCloseElm.textContent = "\xD7", closeButtonElm.appendChild(spanCloseElm);
}
if (!this._contextMenuProperties.hideOptionSection && isColumnOptionAllowed && optionItems.length > 0) {
let optionMenuElm = document.createElement("div");
optionMenuElm.className = "slick-context-menu-option-list", optionMenuElm.role = "menu", item && level > 0 && this.addSubMenuTitleWhenExists(item, optionMenuElm), closeButtonElm && !this._contextMenuProperties.hideCloseButton && (this._bindingEventService.bind(closeButtonElm, "click", this.handleCloseButtonClicked.bind(this)), menuElm.appendChild(closeButtonElm)), menuElm.appendChild(optionMenuElm), this.populateCommandOrOptionItems(
"option",
this._contextMenuProperties,
optionMenuElm,
optionItems,
{ cell: this._currentCell, row: this._currentRow, column: columnDef, dataContext, grid: this._grid, level }
);
}
if (!this._contextMenuProperties.hideCommandSection && isColumnCommandAllowed && commandItems.length > 0) {
let commandMenuElm = document.createElement("div");
commandMenuElm.className = "slick-context-menu-command-list", commandMenuElm.role = "menu", item && level > 0 && this.addSubMenuTitleWhenExists(item, commandMenuElm), closeButtonElm && !this._contextMenuProperties.hideCloseButton && (!isColumnOptionAllowed || optionItems.length === 0 || this._contextMenuProperties.hideOptionSection) && (this._bindingEventService.bind(closeButtonElm, "click", this.handleCloseButtonClicked.bind(this)), menuElm.appendChild(closeButtonElm)), menuElm.appendChild(commandMenuElm), this.populateCommandOrOptionItems(
"command",
this._contextMenuProperties,
commandMenuElm,
commandItems,
{ cell: this._currentCell, row: this._currentRow, column: columnDef, dataContext, grid: this._grid, level }
);
}
return level++, menuElm;
}
addSubMenuTitleWhenExists(item, commandOrOptionMenu) {
if (item !== "divider" && (item != null && item.subMenuTitle)) {
let subMenuTitleElm = document.createElement("div");
subMenuTitleElm.className = "slick-menu-title", subMenuTitleElm.textContent = item.subMenuTitle;
let subMenuTitleClass = item.subMenuTitleCssClass;
subMenuTitleClass && subMenuTitleElm.classList.add(...Utils.classNameToList(subMenuTitleClass)), commandOrOptionMenu.appendChild(subMenuTitleElm);
}
}
handleCloseButtonClicked(e) {
e.defaultPrevented || this.destroyMenu(e);
}
destroyMenu(e, args) {
var _a, _b, _c;
if (this._menuElm = this._menuElm || document.querySelector(`.slick-context-menu${this.getGridUidSelector()}`), (_a = this._menuElm) != null && _a.remove) {
if (this.onBeforeMenuClose.notify({
cell: (_b = args == null ? void 0 : args.cell) != null ? _b : 0,
row: (_c = args == null ? void 0 : args.row) != null ? _c : 0,
grid: this._grid
}, e, this).getReturnValue() === !1)
return;
this._menuElm.remove(), this._menuElm = null;
}
this.destroySubMenus();
}
/** Destroy all parent menus and any sub-menus */
destroyAllMenus() {
this.destroySubMenus(), this._bindingEventService.unbindAll("parent-menu"), document.querySelectorAll(`.slick-context-menu${this.getGridUidSelector()}`).forEach((subElm) => subElm.remove());
}
/** Close and destroy all previously opened sub-menus */
destroySubMenus() {
this._bindingEventService.unbindAll("sub-menu"), document.querySelectorAll(`.slick-context-menu.slick-submenu${this.getGridUidSelector()}`).forEach((subElm) => subElm.remove());
}
checkIsColumnAllowed(columnIds, columnId) {
let isAllowedColumn = !1;
if ((columnIds == null ? void 0 : columnIds.length) > 0)
for (let o = 0, ln = columnIds.length; o < ln; o++)
columnIds[o] === columnId && (isAllowedColumn = !0);
else
isAllowedColumn = !0;
return isAllowedColumn;
}
getGridUidSelector() {
let gridUid = this._grid.getUID() || "";
return gridUid ? `.${gridUid}` : "";
}
handleOnContextMenu(evt, args) {
this.destroyAllMenus();
let e = evt instanceof SlickEventData ? evt.getNativeEvent() : evt;
e.preventDefault();
let cell = this._grid.getCellFromEvent(e);
if (cell) {
let columnDef = this._grid.getColumns()[cell.cell], dataContext = this._grid.getDataItem(cell.row);
if (args = args || {}, args.cell = cell.cell, args.row = cell.row, args.column = columnDef, args.dataContext = dataContext, args.grid = this._grid, !this.runOverrideFunctionWhenExists(this._contextMenuProperties.menuUsabilityOverride, args))
return;
this._menuElm = this.createParentMenu(e), this._menuElm && (this.repositionMenu(e, this._menuElm), this._menuElm.style.display = "block"), this._bindingEventService.bind(document.body, "mousedown", this.handleBodyMouseDown.bind(this));
}
}
/** When users click outside the Cell Menu, we will typically close the Cell Menu (and any sub-menus) */
handleBodyMouseDown(e) {
var _a;
let isMenuClicked = !1;
(_a = this._menuElm) != null && _a.contains(e.target) && (isMenuClicked = !0), isMenuClicked || document.querySelectorAll(`.slick-context-menu.slick-submenu${this.getGridUidSelector()}`).forEach((subElm) => {
subElm.contains(e.target) && (isMenuClicked = !0);
}), this._menuElm !== e.target && !isMenuClicked && !e.defaultPrevented && this.destroyMenu(e, { cell: this._currentCell, row: this._currentRow });
}
/** Construct the Command Items section. */
populateCommandOrOptionItems(itemType, contextMenu, commandOrOptionMenuElm, commandOrOptionItems, args) {
if (!args || !commandOrOptionItems || !contextMenu)
return;
let level = (args == null ? void 0 : args.level) || 0, isSubMenu = level > 0;
contextMenu != null && contextMenu[`${itemType}Title`] && !isSubMenu && (this[`_${itemType}TitleElm`] = document.createElement("div"), this[`_${itemType}TitleElm`].className = "slick-menu-title", this[`_${itemType}TitleElm`].textContent = contextMenu[`${itemType}Title`], commandOrOptionMenuElm.appendChild(this[`_${itemType}TitleElm`]));
for (let i = 0, ln = commandOrOptionItems.length; i < ln; i++) {
let addClickListener = !0, item = commandOrOptionItems[i], isItemVisible = this.runOverrideFunctionWhenExists(item.itemVisibilityOverride, args), isItemUsable = this.runOverrideFunctionWhenExists(item.itemUsabilityOverride, args);
if (!isItemVisible)
continue;
Object.prototype.hasOwnProperty.call(item, "itemUsabilityOverride") && (item.disabled = !isItemUsable);
let liElm = document.createElement("div");
liElm.className = "slick-context-menu-item", liElm.role = "menuitem", (item.divider || item === "divider") && (liElm.classList.add("slick-context-menu-item-divider"), addClickListener = !1), (item.disabled || !isItemUsable) && liElm.classList.add("slick-context-menu-item-disabled"), item.hidden && liElm.classList.add("slick-context-menu-item-hidden"), item.cssClass && liElm.classList.add(...Utils.classNameToList(item.cssClass)), item.tooltip && (liElm.title = item.tooltip || "");
let iconElm = document.createElement("div");
iconElm.className = "slick-context-menu-icon", liElm.appendChild(iconElm), item.iconCssClass && iconElm.classList.add(...Utils.classNameToList(item.iconCssClass)), item.iconImage && (iconElm.style.backgroundImage = `url(${item.iconImage})`);
let textElm = document.createElement("span");
if (textElm.className = "slick-context-menu-content", textElm.textContent = item.title || "", liElm.appendChild(textElm), item.textCssClass && textElm.classList.add(...Utils.classNameToList(item.textCssClass)), commandOrOptionMenuElm.appendChild(liElm), addClickListener) {
let eventGroup = isSubMenu ? "sub-menu" : "parent-menu";
this._bindingEventService.bind(liElm, "click", this.handleMenuItemClick.bind(this, item, itemType, level), void 0, eventGroup);
}
if (this._contextMenuProperties.subMenuOpenByEvent === "mouseover" && this._bindingEventService.bind(liElm, "mouseover", (e) => {
item.commandItems || item.optionItems ? (this.repositionSubMenu(item, itemType, level, e), this._lastMenuTypeClicked = itemType) : isSubMenu || this.destroySubMenus();
}), item.commandItems || item.optionItems) {
let chevronElm = document.createElement("span");
chevronElm.className = "sub-item-chevron", this._contextMenuProperties.subItemChevronClass ? chevronElm.classList.add(...Utils.classNameToList(this._contextMenuProperties.subItemChevronClass)) : chevronElm.textContent = "\u2B9E", liElm.classList.add("slick-submenu-item"), liElm.appendChild(chevronElm);
continue;
}
}
}
handleMenuItemClick(item, type, level = 0, e) {
if ((item == null ? void 0 : item[type]) !== void 0 && item !== "divider" && !item.disabled && !item.divider && this._currentCell !== void 0 && this._currentRow !== void 0) {
if (type === "option" && !this._grid.getEditorLock().commitCurrentEdit())
return;
let optionOrCommand = item[type] !== void 0 ? item[type] : "", row = this._currentRow, cell = this._currentCell, columnDef = this._grid.getColumns()[cell], dataContext = this._grid.getDataItem(row), cellValue;
if (Object.prototype.hasOwnProperty.call(dataContext, columnDef == null ? void 0 : columnDef.field) && (cellValue = dataContext[columnDef.field]), optionOrCommand !== void 0 && !item[`${type}Items`]) {
let callbackArgs = {
cell,
row,
grid: this._grid,
[type]: optionOrCommand,
item,
column: columnDef,
dataContext,
value: cellValue
};
this[type === "command" ? "onCommand" : "onOptionSelected"].notify(callbackArgs, e, this), typeof item.action == "function" && item.action.call(this, e, callbackArgs), e.defaultPrevented || this.destroyMenu(e, { cell, row });
} else item.commandItems || item.optionItems ? this.repositionSubMenu(item, type, level, e) : this.destroySubMenus();
this._lastMenuTypeClicked = type;
}
}
repositionSubMenu(item, type, level, e) {
(e.target.classList.contains("slick-cell") || this._lastMenuTypeClicked !== type) && this.destroySubMenus();
let subMenuElm = this.createMenu((item == null ? void 0 : item.commandItems) || [], (item == null ? void 0 : item.optionItems) || [], level + 1, item);
subMenuElm.style.display = "block", document.body.appendChild(subMenuElm), this.repositionMenu(e, subMenuElm);
}
/**
* Reposition the menu drop (up/down) and the side (left/right)
* @param {*} event
*/
repositionMenu(e, menuElm) {
var _a, _b, _c, _d;
let isSubMenu = menuElm.classList.contains("slick-submenu"), targetEvent = (_b = (_a = e.touches) == null ? void 0 : _a[0]) != null ? _b : e, parentElm = isSubMenu ? e.target.closest(".slick-context-menu-item") : e.target.closest(".slick-cell");
if (menuElm && parentElm) {
let parentOffset = Utils.offset(parentElm), menuOffsetLeft = isSubMenu && parentElm ? (_c = parentOffset == null ? void 0 : parentOffset.left) != null ? _c : 0 : targetEvent.pageX, menuOffsetTop = parentElm ? (_d = parentOffset == null ? void 0 : parentOffset.top) != null ? _d : 0 : targetEvent.pageY, menuHeight = (menuElm == null ? void 0 : menuElm.offsetHeight) || 0, menuWidth = Number((menuElm == null ? void 0 : menuElm.offsetWidth) || this._contextMenuProperties.width || 0), rowHeight = this._gridOptions.rowHeight, dropOffset = Number(this._contextMenuProperties.autoAdjustDropOffset || 0), sideOffset = Number(this._contextMenuProperties.autoAlignSideOffset || 0);
if (this._contextMenuProperties.autoAdjustDrop) {
let spaceBottom = Utils.calculateAvailableSpace(parentElm).bottom, spaceTop = Utils.calculateAvailableSpace(parentElm).top, spaceBottomRemaining = spaceBottom + dropOffset - rowHeight, spaceTopRemaining = spaceTop - dropOffset + rowHeight;
(spaceBottomRemaining < menuHeight && spaceTopRemaining > spaceBottomRemaining ? "top" : "bottom") === "top" ? (menuElm.classList.remove("dropdown"), menuElm.classList.add("dropup"), isSubMenu ? menuOffsetTop -= menuHeight - dropOffset - parentElm.clientHeight : menuOffsetTop -= menuHeight - dropOffset) : (menuElm.classList.remove("dropup"), menuElm.classList.add("dropdown"), isSubMenu ? menuOffsetTop += dropOffset : menuOffsetTop += rowHeight + dropOffset);
}
if (this._contextMenuProperties.autoAlignSide) {
let gridPos = this._grid.getGridPosition(), subMenuPosCalc = menuOffsetLeft + Number(menuWidth);
isSubMenu && (subMenuPosCalc += parentElm.clientWidth);
let browserWidth = document.documentElement.clientWidth;
(subMenuPosCalc >= gridPos.width || subMenuPosCalc >= browserWidth ? "left" : "right") === "left" ? (menuElm.classList.remove("dropright"), menuElm.classList.add("dropleft"), menuOffsetLeft -= menuWidth - sideOffset) : (menuElm.classList.remove("dropleft"), menuElm.classList.add("dropright"), isSubMenu ? menuOffsetLeft += sideOffset + parentElm.offsetWidth : menuOffsetLeft += sideOffset);
}
menuElm.style.top = `${menuOffsetTop}px`, menuElm.style.left = `${menuOffsetLeft}px`;
}
}
/**
* Method that user can pass to override the default behavior.
* In order word, user can choose or an item is (usable/visible/enable) by providing his own logic.
* @param overrideFn: override function callback
* @param args: multiple arguments provided to the override (cell, row, columnDef, dataContext, grid)
*/
runOverrideFunctionWhenExists(overrideFn, args) {
return typeof overrideFn == "function" ? overrideFn.call(this, args) : !0;
}
};
window.Slick && Utils.extend(!0, window, {
Slick: {
Plugins: {
ContextMenu: SlickContextMenu
}
}
});
})();
//# sourceMappingURL=slick.contextmenu.js.map

Some files were not shown because too many files have changed in this diff Show More