Compare commits

..

11 Commits

Author SHA1 Message Date
Faris Ansari
3d7ab754b0 Add docs for column and data options 2018-05-30 05:36:15 +05:30
Faris Ansari
85da21e54d Add gif for cell features 2018-05-30 05:35:53 +05:30
Faris Ansari
98f7a3bf71 Add gif for column features 2018-05-27 18:06:34 +05:30
Faris Ansari
2af5142f0a Fetch assets from unpkg 2018-05-23 13:14:44 +05:30
Faris Ansari
a1a87c9515 fix dest path 2018-05-23 13:01:18 +05:30
Faris Ansari
7895887a63 typo 2018-05-22 16:40:25 +05:30
Faris Ansari
f985b78bde Add styl and update script links with base 2018-05-22 16:38:03 +05:30
Faris Ansari
796196b81a Update docs config 2018-05-22 16:33:33 +05:30
Faris Ansari
a3785eff50 Init docs with vuepress 2018-05-22 14:09:57 +05:30
Faris Ansari
6636eca360 more docs 2018-05-16 02:19:33 +05:30
Faris Ansari
936dcca403 Documentation with docsify 💃 2018-05-10 17:58:26 +05:30
76 changed files with 18690 additions and 8404 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@ -7,8 +7,7 @@
"env": {
"browser": true,
"es6": true,
"node": true,
"mocha": true
"node": true
},
"globals": {
@ -22,9 +21,7 @@
"it": true,
"expect": true,
"sinon": true,
"Clusterize": true,
"cy": true,
"Cypress": true
"Clusterize": true
},
"plugins": [
@ -35,6 +32,7 @@
"block-scoped-var": 2,
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
"camelcase": [2, { "properties": "always" }],
"comma-dangle": [2, "never"],
"comma-spacing": [2, { "before": false, "after": true }],
"comma-style": [2, "last"],
"complexity": 0,

View File

@ -1,24 +0,0 @@
name: Test and Release
on:
push:
branches:
- master
jobs:
test-and-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Lint, build and test
uses: cypress-io/github-action@v2
with:
build: yarn lint-and-build
start: yarn cy:server
record: true
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Release
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: yarn semantic-release

View File

@ -1,16 +0,0 @@
name: Test Pull Request
on: pull_request
jobs:
test-pull-request:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Lint, build and test
uses: cypress-io/github-action@v2
with:
build: yarn lint-and-build
start: yarn cy:server
record: true
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

9
.gitignore vendored
View File

@ -34,12 +34,3 @@ node_modules
npm-debug.log.*
.DS_Store
# cypress
cypress/screenshots
cypress/videos
# dist
dist
.env

View File

@ -1,6 +1,6 @@
The MIT License
Copyright (c) 2018 Frappe Technologies Pvt. Ltd. <developers@frappe.io>
Copyright (c) 2018 Frappé Technologies Pvt. Ltd. <developers@frappe.io>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,75 +1,39 @@
<div align="center" markdown="1">
<img width="80" alt="datatable-logo" src="https://github.com/user-attachments/assets/8235f4b9-993a-4329-97de-9431dcf63aae" >
<h1>Frappe DataTable</h1>
**A modern datatable library for the web**
[![Test and Release](https://github.com/frappe/datatable/workflows/Test%20and%20Release/badge.svg)](https://github.com/frappe/datatable/actions?query=workflow%3A%22Test+and+Release%22)
[![npm version](https://badge.fury.io/js/frappe-datatable.svg)](https://badge.fury.io/js/frappe-datatable)
![npm bundle size (minified + gzip)](https://img.shields.io/bundlephobia/minzip/frappe-datatable.svg)
![datatable-demo-2](https://user-images.githubusercontent.com/9355208/40740030-5412aa40-6465-11e8-8542-b0247ab1daac.gif)
<div align="center">
<img src="https://github.com/frappe/design/blob/master/logos/data-table-logo.svg" height="128">
<h2>Frappe DataTables</h2>
<p align="center">
<p>
A modern datatable library for the web
</p>
</div>
## Frappe Datatable
Frappe DataTable is a simple, modern and interactive datatable library for displaying tabular data. Originally built for [ERPNext](https://github.com/frappe/erpnext), it can be used to render large amount of rows without sacrificing performance and has the basic data grid features like inline editing and keyboard navigation. It does not require jQuery, unlike most data grids out there.
### Motivation
I was trying to remove all legacy UI components from the [frappe](https://github.com/frappe/frappe) codebase. We were using [SlickGrid](https://github.com/mleibman/SlickGrid) for rendering tables. It was unmaintained and UI was dated. Other datatable solutions either didn't have the features we needed or were closed source. So we built our own.
### Key Features
- **Cell**: Enable editing within individual cells and features like custom formatters, inline editing, and mouse selection. Users can easily copy cell content, navigate through cells using the keyboard, and take advantage of a custom cell editor for advanced functionality.
- **Column**: Columns are highly flexible, allowing users to reorder, resize, and sort them with ease. Additional features include hiding/removing columns and adding custom actions.
- **Row**: Rows support advanced interactions, including row selection, tree-structured organization, and inline filters for precise control. They handle large datasets efficiently with dynamic row heights.
## Features
* Resizable columns
* Sorting
* Custom formatted data
* In place editing
* Efficient rendering of large data
## Usage
```bash
yarn add frappe-datatable
# or
npm install frappe-datatable
```
> Note: [`sortablejs`](https://github.com/RubaXa/Sortable) is required to be installed as well.
```js
const datatable = new DataTable('#datatable', {
columns: [ 'First Name', 'Last Name', 'Position' ],
data: [
[ 'Don', 'Joe', 'Designer' ],
[ 'Mary', 'Jane', 'Software Developer' ]
]
var grid = new DataTable(document.querySelector('#data-table'), {
data: {
columns: [ 'Sr No.', 'First Name', 'Last Name' ],
rows: [
[ '1', 'Don', 'Joe' ],
[ '2', 'Mary', 'Jane' ]
]
}
});
```
## Development Setup
## Contribute
* `yarn start` - Start dev server
* Open `index.html` located in the root folder, and start development.
* Run `yarn lint` before committing changes
* This project uses [commitizen](https://github.com/commitizen/cz-cli) for conventional commit messages, use `yarn commit` command instead of `git commit`
* `yarn start` - Start rollup watch
* `yarn build` - Build js/css bundles
## Links
## License
- [Making a new datatable for the web](https://medium.com/frapp%C3%A9-thoughts/things-i-learned-building-a-library-for-the-web-6846a588bf53)
<br>
<br>
<div align="center" style="padding-top: 0.75rem;">
<a href="https://frappe.io" target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://frappe.io/files/Frappe-white.png">
<img src="https://frappe.io/files/Frappe-black.png" alt="Frappe Technologies" height="28"/>
</picture>
</a>
</div>
MIT

View File

@ -1,4 +0,0 @@
{
"baseUrl": "http://localhost:8989",
"projectId": "2nsyux"
}

View File

@ -1,5 +0,0 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@ -1,84 +0,0 @@
describe('Cell', function () {
before(function () {
cy.visit('/');
});
it('focuses cell on click', function () {
cy.clickCell(2, 0)
.should('have.class', 'dt-cell--focus');
});
it('not focuses cell which are not focusable', function () {
cy.clickCell(1, 0)
.should('not.have.class', 'dt-cell--focus');
});
it('edit cell on enter press', function () {
cy.getCell(4, 0).type('{enter}')
.should('have.class', 'dt-cell--editing')
.type('{enter}')
.should('not.have.class', 'dt-cell--editing');
});
it('edit cell on double click', function () {
cy.getCell(4, 0)
.as('target')
.dblclick({ force: true })
.should('have.class', 'dt-cell--editing');
cy.clickCell(3, 0);
cy.get('@target').should('not.have.class', 'dt-cell--editing');
});
it('edit cell', function () {
cy.getCell(4, 1).dblclick({ force: true });
cy.getCell(4, 1).find('input').click();
cy.focused().type('{selectall}{del}Test{enter}');
cy.getCell(4, 1).contains('Test');
});
it('if editing is false: editing should not activate', function () {
cy.getCell(3, 0).dblclick({ force: true })
.should('not.have.class', 'dt-cell--editing');
});
it('navigation using arrow keys', function () {
cy.clickCell(2, 0)
.type('{rightarrow}');
cy.get('.dt-cell--focus')
.should('have.class', 'dt-cell--3-0')
.click({ force: true })
.type('{downarrow}');
cy.get('.dt-cell--focus')
.should('have.class', 'dt-cell--3-1');
// TODO: test navigation over hidden rows
});
it('navigation using ctrl + arrow keys', function () {
cy.clickCell(2, 0)
.type('{ctrl}{rightarrow}');
cy.get('.dt-cell--focus')
.should('have.class', 'dt-cell--11-0');
});
it('cell selection using shift + arrow keys', function () {
cy.getCell(2, 1)
.type('{shift}{rightarrow}{rightarrow}{downarrow}');
// 6 cells and 2 headers
cy.get('.dt-cell--highlight').should('have.length', 6 + 2);
cy.clickCell(2, 0);
});
it('mouse selection', function () {
// TODO:
// cy.getCell(2, 1)
// .trigger('mousedown', { which: 1, pageX: 331, pageY: 207, force: true })
// .trigger('mousemove', { which: 1, pageX: 489, pageY: 312 })
// .trigger('mouseup');
});
});

View File

@ -1,70 +0,0 @@
describe('Column', function () {
before(function () {
cy.visit('/');
});
it('header dropdown toggles on click', function () {
cy.getColumnCell(2)
.find('.dt-dropdown__toggle')
.as('toggle')
.click();
cy.get('.dt-dropdown__list')
.as('dropdown-list')
.should('be.visible');
cy.getColumnCell(2).click();
cy.get('@dropdown-list').should('not.be.visible');
});
it('sort ascending button should work', function () {
cy.clickDropdown(2);
cy.clickDropdownItem(2, 'Sort Ascending');
cy.window().then(win => win.datatable.getColumn(2))
.its('sortOrder')
.should('eq', 'asc');
cy.window().then(win => win.datatable.datamanager)
.its('currentSort.colIndex')
.should('eq', 2);
cy.get('.dt-scrollable .dt-row:first div:nth-of-type(3)')
.contains('Airi Satou');
cy.clickDropdownItem(2, 'Reset sorting');
});
it('removes column using dropdown action', function () {
cy.get('.dt-cell--header').should('have.length', 12);
cy.clickDropdown(5);
cy.clickDropdownItem(5, 'Remove column');
cy.get('.dt-cell--header').should('have.length', 11);
});
it('resize column with mouse drag', function () {
cy.get('.dt-cell--header-4 .dt-cell__resize-handle').as('resize-handle');
cy
.get('@resize-handle')
.trigger('mousedown')
.trigger('mousemove', { pageX: 700, pageY: 20, which: 1 })
.trigger('mouseup');
cy.getColumnCell(4).invoke('css', 'width').then((width) => {
cy.getColumnCell(4)
.should('have.css', 'width', width);
cy.getCell(4, 1)
.should('have.css', 'width', width);
});
});
it('resize column using double click', function () {
cy.get('.dt-cell--header-4 .dt-cell__resize-handle').trigger('dblclick');
cy.getColumnCell(4).should('have.css', 'width')
.and('match', /9\dpx/);
cy.getCell(4, 1).should('have.css', 'width')
.and('match', /9\dpx/);
});
});

View File

@ -1,89 +0,0 @@
describe('Inline Filters', function () {
before(function () {
cy.visit('/');
});
beforeEach(function () {
cy.get('.dt-filter[data-col-index=4]').as('filterInput4');
cy.get('.dt-filter[data-col-index=5]').as('filterInput5');
cy.get('.dt-filter[data-col-index=6]').as('filterInput6');
cy.get('.dt-row[data-row-index=0]').should('be.visible');
});
it('simple text filter', function () {
cy.getCell(4, 0).click().type('{ctrl}f');
cy.get('@filterInput4').type('edin');
cy.get('.dt-row-0').should('be.visible');
cy.get('.dt-row-1').should('not.exist');
cy.get('@filterInput4').clear();
});
it('simple number filter', function () {
cy.get('@filterInput5').type('2360');
cy.get('.dt-row[data-row-index=8]').should('be.visible');
cy.get('.dt-row[data-row-index=15]').should('not.exist');
cy.get('.dt-row[data-row-index=22]').should('not.exist');
cy.get('@filterInput5').clear();
});
it('greater than', function () {
cy.get('@filterInput5').type('> 6000');
cy.get('.dt-row[data-row-index=0]').should('not.exist');
cy.get('.dt-row[data-row-index=3]').should('be.visible');
cy.get('@filterInput5').clear();
});
it('less than', function () {
cy.get('@filterInput5').type('< 2000');
cy.get('.dt-row[data-row-index=0]').should('not.exist');
cy.get('.dt-row[data-row-index=51]').should('be.visible');
cy.get('@filterInput5').clear();
});
it('range', function () {
cy.get('@filterInput5').type(' 2000: 5000');
cy.get('.dt-row[data-row-index=4]').should('not.exist');
cy.get('.dt-row[data-row-index=5]').should('be.visible');
cy.get('@filterInput5').clear();
});
it('equals', function () {
cy.get('@filterInput5').type('=9608');
cy.get('.dt-row-6').should('be.visible');
cy.get('@filterInput5').clear();
});
it('multiple filters', function () {
cy.get('@filterInput4').type('to');
cy.get('@filterInput5').type('54');
cy.get('.dt-row[data-row-index=4]').should('be.visible');
cy.get('.dt-row[data-row-index=1]').should('not.exist');
cy.get('@filterInput4').clear();
cy.get('@filterInput5').clear();
});
it('greater than for string type filters', function () {
cy.get('@filterInput6').type('> 01/07/2011');
cy.get('.dt-row[data-row-index=0]').should('not.exist');
cy.get('.dt-row[data-row-index=1]').should('be.visible');
cy.get('.dt-row[data-row-index=3]').should('be.visible');
cy.get('.dt-row[data-row-index=5]').should('be.visible');
cy.get('@filterInput6').clear();
});
it('filters with sorting', function () {
cy.visit('/');
cy.clickDropdown(7);
cy.clickDropdownItem(7, 'Sort Descending');
cy.get('.dt-filter[data-col-index=5]').as('filterInput5');
cy.getCell(5, 24).click().type('{ctrl}f');
cy.get('@filterInput5').type('>3000', {delay: 100});
cy.get('.dt-scrollable .dt-row:first')
.should('contain', 'Angelica')
.should('have.class', 'dt-row-24');
cy.get('@filterInput5').clear();
});
});

View File

@ -1,20 +0,0 @@
describe('DataTable init', function () {
it('instance is created without any errors', () => {
cy.visit('/');
cy.window()
.its('DataTable')
.then(DataTable => {
// eslint-disable-next-line
new DataTable('#datatable2', {
columns: ['Name', 'Position'],
data: [
['Faris', 'Developer']
]
});
});
cy.get('#datatable2 .datatable')
.contains('Faris');
});
});

View File

@ -1,15 +0,0 @@
describe('Row', function () {
before(function () {
cy.visit('/');
});
it('check / uncheck row', function () {
cy.get('.dt-scrollable .dt-row:first')
.find('input[type="checkbox"]')
.click();
cy.get('[data-row-index="0"]').should('have.class', 'dt-row--highlight');
cy.get('.dt-toast').contains('1 row selected');
});
});

View File

@ -1,17 +0,0 @@
// ***********************************************************
// 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)
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
};

View File

@ -1,57 +0,0 @@
// ***********************************************
// 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 is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
Cypress.Commands.add('getCell', (col, row) => {
return cy.get(`.dt-cell--${col}-${row}`);
});
Cypress.Commands.add('clickCell', (col, row) => {
return cy.getCell(col, row).click({ force: true });
});
Cypress.Commands.add('getColumnCell', (col) => {
return cy.get(`.dt-cell--header-${col}`);
});
Cypress.Commands.add('clickDropdown', (col) => {
return cy.getColumnCell(col)
.find('.dt-dropdown__toggle')
.click();
});
Cypress.Commands.add('clickDropdownItem', (col, item) => {
return cy.get(`.dt-dropdown__list-item:contains("${item}")`)
.click({ force: true });
});
Cypress.Commands.add('typeTab', (shiftKey, ctrlKey) => {
cy.focused().trigger('keydown', {
keyCode: 9,
which: 9,
shiftKey: shiftKey,
ctrlKey: ctrlKey
});
});

View File

@ -1,20 +0,0 @@
// ***********************************************************
// 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')

View File

@ -1,12 +0,0 @@
{
"compilerOptions": {
"allowJs": true,
"baseUrl": "../node_modules",
"types": [
"cypress"
]
},
"include": [
"**/*.*"
]
}

282
dist/frappe-datatable.cjs.css vendored Normal file
View File

@ -0,0 +1,282 @@
/* This file is processed by postcss */
/* variables */
.data-table {
/* styling */
position: relative;
overflow: auto;
}
/* resets */
.data-table *, .data-table *::after, .data-table *::before {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.data-table button, .data-table input {
overflow: visible;
font-family: inherit;
font-size: inherit;
line-height: inherit;
margin: 0;
padding: 0;
}
.data-table .input-style {
outline: none;
width: 100%;
border: none;
}
.data-table *, .data-table *:focus {
outline: none;
border-radius: 0px;
-webkit-box-shadow: none;
box-shadow: none;
}
.data-table table {
border-collapse: collapse;
}
.data-table table td {
padding: 0;
border: 1px solid #d1d8dd;
}
.data-table thead td {
border-bottom-width: 1px;
}
.data-table .freeze-container {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-ms-flex-line-pack: center;
align-content: center;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: #f5f7fa;
opacity: 0.5;
font-size: 2em;
}
.data-table .freeze-container span {
position: absolute;
top: 50%;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
.data-table .hide {
display: none;
}
.data-table .toast-message {
position: absolute;
bottom: 16px;
bottom: 1rem;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
.data-table .toast-message span {
display: inline-block;
background-color: rgba(0, 0, 0, .8);
color: #dfe2e5;
border-radius: 3px;
padding: 8px 16px;
padding: 0.5rem 1rem;
}
.body-scrollable {
max-height: 500px;
overflow: auto;
border-bottom: 1px solid #d1d8dd;
}
.body-scrollable.row-highlight-all .data-table-row:not(.row-unhighlight) {
background-color: #f5f7fa;
}
.data-table-header {
position: absolute;
top: 0;
left: 0;
background-color: white;
font-weight: bold;
}
.data-table-header .content span:not(.column-resizer) {
cursor: pointer;
}
.data-table-header .column-resizer {
display: none;
position: absolute;
right: 0;
top: 0;
width: 4px;
width: 0.25rem;
height: 100%;
background-color: rgb(82, 146, 247);
cursor: col-resize;
}
.data-table-header .data-table-dropdown {
position: absolute;
right: 10px;
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
vertical-align: top;
text-align: left;
}
.data-table-header .data-table-dropdown.is-active .data-table-dropdown-list {
display: block;
}
.data-table-header .data-table-dropdown.is-active .data-table-dropdown-toggle {
display: block;
}
.data-table-header .data-table-dropdown-toggle {
display: none;
background-color: transparent;
border: none;
}
.data-table-header .data-table-dropdown-list {
display: none;
font-weight: normal;
position: absolute;
min-width: 128px;
min-width: 8rem;
top: 100%;
right: 0;
z-index: 1;
background-color: white;
border-radius: 3px;
-webkit-box-shadow: 0 2px 3px rgba(10, 10, 10, .1), 0 0 0 1px rgba(10, 10, 10, .1);
box-shadow: 0 2px 3px rgba(10, 10, 10, .1), 0 0 0 1px rgba(10, 10, 10, .1);
padding-bottom: 8px;
padding-bottom: 0.5rem;
padding-top: 8px;
padding-top: 0.5rem;
}
.data-table-header .data-table-dropdown-list> div {
padding: 8px 16px;
padding: 0.5rem 1rem;
}
.data-table-header .data-table-dropdown-list> div:hover {
background-color: #f5f7fa;
}
.data-table-header .data-table-cell.remove-column {
background-color: #FD8B8B;
-webkit-transition: 300ms background-color ease-in-out;
transition: 300ms background-color ease-in-out;
}
.data-table-header .data-table-cell.sortable-chosen {
background-color: #f5f7fa;
}
.data-table-cell {
position: relative;
}
.data-table-cell .content {
padding: 8px;
padding: 0.5rem;
border: 2px solid transparent;
}
.data-table-cell .content.ellipsis {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.data-table-cell .edit-cell {
display: none;
padding: 8px;
padding: 0.5rem;
background: #fff;
z-index: 1;
height: 100%;
}
.data-table-cell.selected .content {
border: 2px solid rgb(82, 146, 247);
}
.data-table-cell.editing .content {
display: none;
}
.data-table-cell.editing .edit-cell {
border: 2px solid rgb(82, 146, 247);
display: block;
}
.data-table-cell.highlight {
background-color: #f5f7fa;
}
.data-table-cell:hover .column-resizer {
display: inline-block;
}
.data-table-cell:hover .data-table-dropdown-toggle {
display: block;
}
.data-table-cell .tree-node {
display: inline-block;
position: relative;
}
.data-table-cell .toggle {
display: inline-block;
position: absolute;
padding: 0 4px;
cursor: pointer;
}
.data-table-cell .toggle:before {
content: '▼';
}
.data-table-cell.tree-close .toggle:before {
content: '►';
}
.data-table-row.row-highlight {
background-color: #f5f7fa;
}
.noselect {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
body.data-table-resize {
cursor: col-resize;
}

3691
dist/frappe-datatable.cjs.js vendored Normal file

File diff suppressed because it is too large Load Diff

257
dist/frappe-datatable.css vendored Normal file
View File

@ -0,0 +1,257 @@
.datatable *, .datatable *::after, .datatable *::before {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.datatable {
position: relative;
overflow: auto;
}
.dt-header {
border-collapse: collapse;
border-bottom: 1px solid #d1d8dd;
position: absolute;
top: 0;
left: 0;
background-color: #fff;
}
.dt-body {
border-collapse: collapse;
}
.dt-scrollable {
max-height: 40vw;
overflow: auto;
border-bottom: 1px solid #d1d8dd;
}
.dt-scrollable--highlight-all {
background-color: #fffce7;
}
.dt-scrollable__no-data {
text-align: center;
padding: 16px;
padding: 1rem;
border-left: 1px solid #d1d8dd;
border-right: 1px solid #d1d8dd;
}
.dt-row--highlight {
background-color: #fffce7;
}
.dt-row--unhighlight {
background-color: #fff;
}
.dt-row--hide {
display: none;
}
.dt-cell {
border: 1px solid #d1d8dd;
position: relative;
outline: none;
padding: 0;
}
.dt-cell__content {
padding: 8px;
padding: 0.5rem;
border: 2px solid transparent;
height: 100%;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.dt-cell__edit {
display: none;
padding: 8px;
padding: 0.5rem;
background-color: #fff;
border: 2px solid rgb(255, 160, 10);
z-index: 1;
height: 100%;
}
.dt-cell__resize-handle {
opacity: 0;
position: absolute;
right: -3px;
top: 0;
width: 5px;
height: 100%;
cursor: col-resize;
z-index: 1;
}
.dt-cell--editing .dt-cell__content {
display: none;
}
.dt-cell--editing .dt-cell__edit {
display: block;
}
.dt-cell--focus .dt-cell__content {
border-color: rgb(82, 146, 247);
}
.dt-cell--highlight {
background-color: #f5f7fa;
}
.dt-cell--dragging {
background-color: #f5f7fa;
}
.dt-cell--header .dt-cell__content {
padding-right: 16px;
padding-right: 1rem;
font-weight: bold;
}
.dt-cell--header:hover .dt-dropdown__toggle {
opacity: 1;
}
.dt-cell--tree-close .dt-tree-node__toggle:before {
content: '►';
}
.dt-dropdown {
position: absolute;
right: 10px;
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
vertical-align: top;
text-align: left;
font-weight: normal;
cursor: pointer;
}
.dt-dropdown__toggle {
opacity: 0;
}
.dt-dropdown__list {
display: none;
position: absolute;
min-width: 128px;
min-width: 8rem;
top: 100%;
right: 0;
z-index: 1;
background-color: #fff;
border-radius: 3px;
padding: 8px 0;
padding: 0.5rem 0;
-webkit-box-shadow: 0 2px 3px rgba(10, 10, 10, .1), 0 0 0 1px rgba(10, 10, 10, .1);
box-shadow: 0 2px 3px rgba(10, 10, 10, .1), 0 0 0 1px rgba(10, 10, 10, .1);
}
.dt-dropdown__list-item {
padding: 8px 16px;
padding: 0.5rem 1rem;
}
.dt-dropdown__list-item:hover {
background-color: #f5f7fa;
}
.dt-dropdown--active .dt-dropdown__list {
display: block;
}
.dt-tree-node {
display: inline-block;
position: relative;
}
.dt-tree-node__toggle {
display: inline-block;
position: absolute;
font-size: 10px;
padding: 0 4px;
cursor: pointer;
}
.dt-tree-node__toggle:before {
content: '▼';
}
.dt-toast {
position: absolute;
bottom: 16px;
bottom: 1rem;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
.dt-toast__message {
display: inline-block;
background-color: rgba(0, 0, 0, .8);
color: #dfe2e5;
border-radius: 3px;
padding: 8px 16px;
padding: 0.5rem 1rem;
}
.dt-input {
outline: none;
width: 100%;
border: none;
overflow: visible;
font-family: inherit;
font-size: inherit;
line-height: inherit;
margin: 0;
padding: 0;
}
.dt-freeze {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-ms-flex-line-pack: center;
align-content: center;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: #f5f7fa;
opacity: 0.5;
font-size: 2em;
}
.dt-freeze__message {
position: absolute;
top: 50%;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
.dt-paste-target {
position: fixed;
left: -999em;
}
body.dt-resize {
cursor: col-resize;
}

3692
dist/frappe-datatable.js vendored Normal file

File diff suppressed because it is too large Load Diff

1
dist/frappe-datatable.min.css vendored Normal file
View File

@ -0,0 +1 @@
.data-table{position:relative;overflow:auto}.data-table *,.data-table :after,.data-table :before{-webkit-box-sizing:border-box;box-sizing:border-box}.data-table button,.data-table input{overflow:visible;font-family:inherit;font-size:inherit;line-height:inherit;margin:0;padding:0}.data-table .input-style{outline:none;width:100%;border:none}.data-table *,.data-table :focus{outline:none;border-radius:0;-webkit-box-shadow:none;box-shadow:none}.data-table table{border-collapse:collapse}.data-table table td{padding:0;border:1px solid #d1d8dd}.data-table thead td{border-bottom-width:1px}.data-table .freeze-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-ms-flex-line-pack:center;align-content:center;position:absolute;left:0;right:0;top:0;bottom:0;background-color:#f5f7fa;opacity:.5;font-size:2em}.data-table .freeze-container span{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.data-table .hide{display:none}.data-table .toast-message{position:absolute;bottom:16px;bottom:1rem;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.data-table .toast-message span{display:inline-block;background-color:rgba(0,0,0,.8);color:#dfe2e5;border-radius:3px;padding:8px 16px;padding:.5rem 1rem}.body-scrollable{max-height:500px;overflow:auto;border-bottom:1px solid #d1d8dd}.body-scrollable.row-highlight-all .data-table-row:not(.row-unhighlight){background-color:#f5f7fa}.body-scrollable .no-data td{text-align:center;padding:8px;padding:.5rem}.data-table-header{position:absolute;top:0;left:0;background-color:#fff;font-weight:700}.data-table-header .content span:not(.column-resizer){cursor:pointer}.data-table-header .column-resizer{display:none;position:absolute;right:0;top:0;width:4px;width:.25rem;height:100%;background-color:#5292f7;cursor:col-resize}.data-table-header .data-table-dropdown{position:absolute;right:10px;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;vertical-align:top;text-align:left}.data-table-header .data-table-dropdown.is-active .data-table-dropdown-list,.data-table-header .data-table-dropdown.is-active .data-table-dropdown-toggle{display:block}.data-table-header .data-table-dropdown-toggle{display:none;background-color:transparent;border:none}.data-table-header .data-table-dropdown-list{display:none;font-weight:400;position:absolute;min-width:128px;min-width:8rem;top:100%;right:0;z-index:1;background-color:#fff;border-radius:3px;-webkit-box-shadow:0 2px 3px hsla(0,0%,4%,.1),0 0 0 1px hsla(0,0%,4%,.1);box-shadow:0 2px 3px hsla(0,0%,4%,.1),0 0 0 1px hsla(0,0%,4%,.1);padding-bottom:8px;padding-bottom:.5rem;padding-top:8px;padding-top:.5rem}.data-table-header .data-table-dropdown-list>div{padding:8px 16px;padding:.5rem 1rem}.data-table-header .data-table-dropdown-list>div:hover{background-color:#f5f7fa}.data-table-header .data-table-cell.remove-column{background-color:#fd8b8b;-webkit-transition:background-color .3s ease-in-out;transition:background-color .3s ease-in-out}.data-table-header .data-table-cell.sortable-chosen{background-color:#f5f7fa}.data-table-cell{position:relative}.data-table-cell .content{padding:8px;padding:.5rem;border:2px solid transparent;height:100%}.data-table-cell .content.ellipsis{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.data-table-cell .edit-cell{display:none;padding:8px;padding:.5rem;background-color:#fff;z-index:1;height:100%}.data-table-cell.selected .content{border:2px solid #5292f7}.data-table-cell.editing .content{display:none}.data-table-cell.editing .edit-cell{border:2px solid #ffa00a;border-style:dashed;display:block}.data-table-cell.highlight{background-color:#f5f7fa}.data-table-cell:hover .column-resizer{display:inline-block}.data-table-cell:hover .data-table-dropdown-toggle{display:block}.data-table-cell .tree-node{display:inline-block;position:relative}.data-table-cell .toggle{display:inline-block;position:absolute;padding:0 4px;cursor:pointer}.data-table-cell .toggle:before{content:"▼"}.data-table-cell.tree-close .toggle:before{content:"►"}.data-table-row.row-highlight{background-color:#f5f7fa}.noselect{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.data-table-resize{cursor:col-resize}

1
dist/frappe-datatable.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,289 @@
/* This file is processed by postcss */
/* variables */
.data-table {
/* styling */
position: relative;
overflow: auto;
}
/* resets */
.data-table *, .data-table *::after, .data-table *::before {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.data-table button, .data-table input {
overflow: visible;
font-family: inherit;
font-size: inherit;
line-height: inherit;
margin: 0;
padding: 0;
}
.data-table .input-style {
outline: none;
width: 100%;
border: none;
}
.data-table *, .data-table *:focus {
outline: none;
border-radius: 0px;
-webkit-box-shadow: none;
box-shadow: none;
}
.data-table table {
border-collapse: collapse;
}
.data-table table td {
padding: 0;
border: 1px solid #d1d8dd;
}
.data-table thead td {
border-bottom-width: 1px;
}
.data-table .freeze-container {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-ms-flex-line-pack: center;
align-content: center;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: #f5f7fa;
opacity: 0.5;
font-size: 2em;
}
.data-table .freeze-container span {
position: absolute;
top: 50%;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
.data-table .hide {
display: none;
}
.data-table .toast-message {
position: absolute;
bottom: 16px;
bottom: 1rem;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
.data-table .toast-message span {
display: inline-block;
background-color: rgba(0, 0, 0, .8);
color: #dfe2e5;
border-radius: 3px;
padding: 8px 16px;
padding: 0.5rem 1rem;
}
.body-scrollable {
max-height: 500px;
overflow: auto;
border-bottom: 1px solid #d1d8dd;
}
.body-scrollable.row-highlight-all .data-table-row:not(.row-unhighlight) {
background-color: #f5f7fa;
}
.body-scrollable .no-data td {
text-align: center;
padding: 8px;
padding: 0.5rem;
}
.data-table-header {
position: absolute;
top: 0;
left: 0;
background-color: white;
font-weight: bold;
}
.data-table-header .content span:not(.column-resizer) {
cursor: pointer;
}
.data-table-header .column-resizer {
display: none;
position: absolute;
right: 0;
top: 0;
width: 4px;
width: 0.25rem;
height: 100%;
background-color: rgb(82, 146, 247);
cursor: col-resize;
}
.data-table-header .data-table-dropdown {
position: absolute;
right: 10px;
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
vertical-align: top;
text-align: left;
}
.data-table-header .data-table-dropdown.is-active .data-table-dropdown-list {
display: block;
}
.data-table-header .data-table-dropdown.is-active .data-table-dropdown-toggle {
display: block;
}
.data-table-header .data-table-dropdown-toggle {
display: none;
background-color: transparent;
border: none;
}
.data-table-header .data-table-dropdown-list {
display: none;
font-weight: normal;
position: absolute;
min-width: 128px;
min-width: 8rem;
top: 100%;
right: 0;
z-index: 1;
background-color: white;
border-radius: 3px;
-webkit-box-shadow: 0 2px 3px rgba(10, 10, 10, .1), 0 0 0 1px rgba(10, 10, 10, .1);
box-shadow: 0 2px 3px rgba(10, 10, 10, .1), 0 0 0 1px rgba(10, 10, 10, .1);
padding-bottom: 8px;
padding-bottom: 0.5rem;
padding-top: 8px;
padding-top: 0.5rem;
}
.data-table-header .data-table-dropdown-list> div {
padding: 8px 16px;
padding: 0.5rem 1rem;
}
.data-table-header .data-table-dropdown-list> div:hover {
background-color: #f5f7fa;
}
.data-table-header .data-table-cell.remove-column {
background-color: #FD8B8B;
-webkit-transition: 300ms background-color ease-in-out;
transition: 300ms background-color ease-in-out;
}
.data-table-header .data-table-cell.sortable-chosen {
background-color: #f5f7fa;
}
.data-table-cell {
position: relative;
}
.data-table-cell .content {
padding: 8px;
padding: 0.5rem;
border: 2px solid transparent;
height: 100%;
}
.data-table-cell .content.ellipsis {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.data-table-cell .edit-cell {
display: none;
padding: 8px;
padding: 0.5rem;
background-color: #fff;
z-index: 1;
height: 100%;
}
.data-table-cell.selected .content {
border: 2px solid rgb(82, 146, 247);
}
.data-table-cell.editing .content {
display: none;
}
.data-table-cell.editing .edit-cell {
border: 2px solid rgb(255, 160, 10);
display: block;
}
.data-table-cell.highlight {
background-color: #f5f7fa;
}
.data-table-cell:hover .column-resizer {
display: inline-block;
}
.data-table-cell:hover .data-table-dropdown-toggle {
display: block;
}
.data-table-cell .tree-node {
display: inline-block;
position: relative;
}
.data-table-cell .toggle {
display: inline-block;
position: absolute;
padding: 0 4px;
cursor: pointer;
}
.data-table-cell .toggle:before {
content: '▼';
}
.data-table-cell.tree-close .toggle:before {
content: '►';
}
.data-table-row.row-highlight {
background-color: #f5f7fa;
}
.noselect {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
body.data-table-resize {
cursor: col-resize;
}

View File

@ -0,0 +1,99 @@
/*
Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #F0F0F0;
}
/* Base color: saturation 0; */
.hljs,
.hljs-subst {
color: #444;
}
.hljs-comment {
color: #888888;
}
.hljs-keyword,
.hljs-attribute,
.hljs-selector-tag,
.hljs-meta-keyword,
.hljs-doctag,
.hljs-name {
font-weight: bold;
}
/* User color: hue: 0 */
.hljs-type,
.hljs-string,
.hljs-number,
.hljs-selector-id,
.hljs-selector-class,
.hljs-quote,
.hljs-template-tag,
.hljs-deletion {
color: #880000;
}
.hljs-title,
.hljs-section {
color: #880000;
font-weight: bold;
}
.hljs-regexp,
.hljs-symbol,
.hljs-variable,
.hljs-template-variable,
.hljs-link,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #BC6060;
}
/* Language color: hue: 90; */
.hljs-literal {
color: #78A960;
}
.hljs-built_in,
.hljs-bullet,
.hljs-code,
.hljs-addition {
color: #397300;
}
/* Meta color: hue: 200 */
.hljs-meta {
color: #1f7199;
}
.hljs-meta-string {
color: #4d99bf;
}
/* Misc effects */
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

159
docs/assets/css/index.css Normal file
View File

@ -0,0 +1,159 @@
@import url('https://fonts.googleapis.com/css?family=Lato:400,700,900');
:root {
--border-color: #d1d8dd;
--border: 1px solid var(--border-color);
--text-color: #36414C;
--navbar-font-size: 1.25rem;
--light-bg: #f5f7fa;
--primary-color: #7575ff;
--primary-color-hover: #5b5be5;
}
*, *::after, *::before {
box-sizing: border-box;
padding: 0;
margin: 0;
}
html, body {
/* font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; */
font-family: Lato, sans-serif;
font-size: 12px;
color: var(--text-color);
}
body {
position: relative;
}
code {
font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
h1 {
font-size: 2.5rem;
margin: 2rem 0 4rem 0;
}
h3 {
font-size: 1.25rem;
}
p {
font-size: 1.25rem;
margin: 1rem 0;
}
.navbar {
position: sticky;
top: 0;
padding: 1.5rem;
background-color: white;
z-index: 1;
border-bottom: var(--border);
}
.navbar .container {
display: flex;
justify-content: space-between;
}
.navbar-links a {
color: var(--text-color);
text-decoration: none;
font-weight: bold;
font-size: var(--navbar-font-size);
}
.container {
max-width: 720px;
margin: 0 auto;
}
.logo {
max-width: 8rem;
}
.footer-logo {
max-width: 3rem;
max-height: 3rem;
padding: 0.5rem;
background-color: #fff;
transform: translateY(-50%);
}
.text-center {
text-align: center;
}
.padding-1 {
padding: 0.5rem;
}
.showcase {
display: flex;
flex-direction: column;
align-items: flex-start;
margin: 4rem 0;
}
.showcase.align-center {
align-items: center;
}
.features {
display: flex;
width: 100%;
font-size: 1.25rem;
margin-top: 1rem;
line-height: 2rem;
}
.features ul {
padding-left: 2rem;
flex: 1;
}
[class^="example-"] {
display: flex;
justify-content: center;
width: 100%;
}
.code {
text-align: left;
width: 100%;
margin: 1rem 0;
}
.hljs {
padding: 2rem;
border-left: 2px solid var(--border-color);
background-color: var(--light-bg);
}
footer {
border-top: 1px solid #d1d8dd;
}
.download-button {
color: #fff;
background-color: var(--primary-color);
border: 0px;
border-bottom: 3px solid rgba(0, 0, 0, 0.2);
font-size: 1.5rem;
padding: 1rem 2rem;
border-radius: 3px;
}
.download-button:hover {
cursor: pointer;
background-color: var(--primary-color-hover);
}
/* .data-table-header {
background: #f7fafc;
color: #8d99a6;
} */

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="340.42303" height="330.00024" viewBox="0 0 90.070259 87.312561" version="1.1" id="svg3970" inkscape:version="0.92.2 5c3e80d, 2017-08-06">
<defs id="defs3964"/>
<metadata id="metadata3967">
</metadata>
<g inkscape:label="Layer 1" id="layer1" transform="translate(-7.1255851,-173.21277)">
<rect transform="scale(-1,1)" ry="13.229167" rx="13.229167" y="173.21277" x="-94.438156" height="87.312546" width="87.312553" id="rect2004" style="opacity:1;fill:#edfdff;fill-opacity:1;stroke:none;stroke-width:1.74624979;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;"/>
<path style="opacity:1;fill:#c3f1ff;fill-opacity:1;stroke:none;stroke-width:6.59999943;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="M 0 96.25 L 0 151.25 L 77.5 151.25 C 80.27 151.25 82.5 149.02 82.5 146.25 L 82.5 101.25 C 82.5 98.48 80.27 96.25 77.5 96.25 L 0 96.25 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="rect2006"/>
<path style="opacity:1;fill:#c3f1ff;fill-opacity:1;stroke:none;stroke-width:6.5999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="M 50 0 C 22.299998 0 1.4210855e-14 22.299998 0 50 L 0 54.5 L 78 54.5 C 80.77 54.5 83 52.27 83 49.5 L 83 4.5 C 83 2.503655 81.832377 0.80274423 80.148438 0 L 50 0 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="rect2008"/>
<rect style="opacity:1;fill:#71caff;fill-opacity:1;stroke:none;stroke-width:1.74624979;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" id="rect2010" width="57.195782" height="14.552094" x="40.000061" y="198.74506" ry="1.3229167" rx="1.3229166"/>
<path style="opacity:1;fill:#c3f1ff;fill-opacity:1;stroke:none;stroke-width:6.59999943;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="M 0 193 L 0 248 L 77.5 248 C 80.27 248 82.5 245.77 82.5 243 L 82.5 198 C 82.5 195.23 80.27 193 77.5 193 L 0 193 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="rect2012"/>
<path style="fill:#87e34c;fill-opacity:1;stroke:none;stroke-width:1.00000012px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" clip-path="none" d="M 0 219.61328 L 0 284.29688 C 0 309.61626 27.643317 330 61.980469 330 L 268.01953 330 C 300.54576 330 327.04905 311.70603 329.75586 288.25586 L 330 248.5 C 256.7254 233.20714 83.19117 220.5514 0 219.61328 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="path2020"/>
<path style="opacity:1;fill:#c3f1ff;fill-opacity:1;stroke:none;stroke-width:6.59999943;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="M 129.25 193.5 C 126.48 193.5 124.25 195.73 124.25 198.5 L 124.25 243.5 C 124.25 246.27 126.48 248.5 129.25 248.5 L 330 248.5 L 330 193.5 L 129.25 193.5 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="rect2014"/>
<path style="opacity:1;fill:#c3f1ff;fill-opacity:1;stroke:none;stroke-width:6.5999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="M 127.10156 0 C 125.41762 0.80274423 124.25 2.503655 124.25 4.5 L 124.25 49.5 C 124.25 52.27 126.48 54.5 129.25 54.5 L 330 54.5 L 330 50 C 330 22.299998 307.7 0 280 0 L 127.10156 0 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="rect2016"/>
<path style="opacity:1;fill:#59b81c;fill-opacity:1;stroke:none;stroke-width:6.59999943;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="M 129.25 290.5 C 126.48 290.5 124.25 292.73 124.25 295.5 L 124.25 330 L 280 330 C 304.09518 330 324.09664 313.12363 328.89648 290.5 L 129.25 290.5 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="rect1135"/>
<path style="opacity:1;fill:#59b81c;fill-opacity:1;stroke:none;stroke-width:6.59999943;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="M 0.94921875 289.75 C 5.4614968 312.74994 25.639123 330 50 330 L 82.5 330 L 82.5 294.75 C 82.5 291.98 80.27 289.75 77.5 289.75 L 0.94921875 289.75 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="rect1139"/>
<path style="opacity:1;fill:#59b81c;fill-opacity:1;stroke:none;stroke-width:1.74624979;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="m 7.1257773,231.31877 v 7.51065 H 27.630987 c 0.732896,0 1.322917,-0.59002 1.322917,-1.32292 v -5.36505 C 20.620295,231.67818 13.007809,231.3851 7.1257773,231.31877 Z" id="path1264"/>
<path style="fill:#59b81c;fill-opacity:1;stroke:none;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" clip-path="none" d="m 40.000259,232.82824 v 4.81056 c 0,0.73289 0.59002,1.32291 1.322916,1.32291 h 53.115108 c -11.982795,-2.50088 -34.095004,-4.73297 -54.438024,-6.13347 z" id="path1163"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100%"
height="100%"
viewBox="0 0 260 260"
version="1.1"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"
id="svg16"
sodipodi:docname="frappe-bird-grey.svg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"><metadata
id="metadata22"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs20" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1029"
id="namedview18"
showgrid="false"
inkscape:snap-global="false"
inkscape:zoom="2.5673415"
inkscape:cx="125.36812"
inkscape:cy="132.66533"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="svg16" /><path
inkscape:connector-curvature="0"
id="path846"
d="m 39.426993,41.26578 c -0.08308,-0.002 -0.162537,0.01476 -0.244177,0.01847 -0.195406,-0.01104 -0.394663,-0.0078 -0.595581,0.02219 -0.671494,0.09826 -1.359798,0.439289 -1.985268,1.097637 L 36.166705,42.984362 3.911539,86.00785 c -1.4521873,1.95837 -0.089029,5.089411 2.840468,4.758942 l 35.051779,-4.999463 7.486826,52.499391 c 0.143332,1.06941 0.708175,1.87792 1.45651,2.37853 0.06099,0.57446 0.300326,1.15825 0.786491,1.67605 l 54.221237,55.16042 c 0.35241,0.34946 0.76163,0.57974 1.18925,0.71967 l 43.2449,43.9932 c 2.19797,2.06517 5.73881,0.59111 5.73827,-2.44537 l 0.72154,-88.30898 100.76861,-99.226182 c 2.03273,-1.933848 0.52846,-5.096585 -1.98911,-5.01476 L 146.21842,46.315471 c -1.15721,-0.0078 -1.82288,0.589677 -2.08644,0.84183 L 70.489255,119.67376 95.234723,86.666413 c 1.320352,-1.808803 0.561745,-3.846193 -0.6872,-4.787579 L 41.349464,41.92492 C 40.706305,41.485816 40.049657,41.2839 39.427179,41.266357 Z"
style="fill:#29344a;fill-opacity:1;stroke:none;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

2
docs/assets/js/Sortable.min.js vendored Normal file

File diff suppressed because one or more lines are too long

18
docs/assets/js/clusterize.min.js vendored Normal file
View File

@ -0,0 +1,18 @@
/*
Clusterize.js - v0.18.0 - 2017-11-04
http://NeXTs.github.com/Clusterize.js/
Copyright (c) 2015 Denis Lukov; Licensed GPLv3 */
;(function(q,n){"undefined"!=typeof module?module.exports=n():"function"==typeof define&&"object"==typeof define.amd?define(n):this[q]=n()})("Clusterize",function(){function q(b,a,c){return a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,c)}function n(b,a,c){return a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent("on"+b,c)}function r(b){return"[object Array]"===Object.prototype.toString.call(b)}function m(b,a){return window.getComputedStyle?window.getComputedStyle(a)[b]:
a.currentStyle[b]}var l=function(){for(var b=3,a=document.createElement("b"),c=a.all||[];a.innerHTML="\x3c!--[if gt IE "+ ++b+"]><i><![endif]--\x3e",c[0];);return 4<b?b:document.documentMode}(),x=navigator.platform.toLowerCase().indexOf("mac")+1,p=function(b){if(!(this instanceof p))return new p(b);var a=this,c={rows_in_block:50,blocks_in_cluster:4,tag:null,show_no_data_row:!0,no_data_class:"clusterize-no-data",no_data_text:"No data",keep_parity:!0,callbacks:{}};a.options={};for(var d="rows_in_block blocks_in_cluster show_no_data_row no_data_class no_data_text keep_parity tag callbacks".split(" "),
f=0,h;h=d[f];f++)a.options[h]="undefined"!=typeof b[h]&&null!=b[h]?b[h]:c[h];c=["scroll","content"];for(f=0;d=c[f];f++)if(a[d+"_elem"]=b[d+"Id"]?document.getElementById(b[d+"Id"]):b[d+"Elem"],!a[d+"_elem"])throw Error("Error! Could not find "+d+" element");a.content_elem.hasAttribute("tabindex")||a.content_elem.setAttribute("tabindex",0);var e=r(b.rows)?b.rows:a.fetchMarkup(),g={};b=a.scroll_elem.scrollTop;a.insertToDOM(e,g);a.scroll_elem.scrollTop=b;var k=!1,m=0,l=!1,t=function(){x&&(l||(a.content_elem.style.pointerEvents=
"none"),l=!0,clearTimeout(m),m=setTimeout(function(){a.content_elem.style.pointerEvents="auto";l=!1},50));k!=(k=a.getClusterNum())&&a.insertToDOM(e,g);a.options.callbacks.scrollingProgress&&a.options.callbacks.scrollingProgress(a.getScrollProgress())},u=0,v=function(){clearTimeout(u);u=setTimeout(a.refresh,100)};q("scroll",a.scroll_elem,t);q("resize",window,v);a.destroy=function(b){n("scroll",a.scroll_elem,t);n("resize",window,v);a.html((b?a.generateEmptyRow():e).join(""))};a.refresh=function(b){(a.getRowsHeight(e)||
b)&&a.update(e)};a.update=function(b){e=r(b)?b:[];b=a.scroll_elem.scrollTop;e.length*a.options.item_height<b&&(k=a.scroll_elem.scrollTop=0);a.insertToDOM(e,g);a.scroll_elem.scrollTop=b};a.clear=function(){a.update([])};a.getRowsAmount=function(){return e.length};a.getScrollProgress=function(){return this.options.scroll_top/(e.length*this.options.item_height)*100||0};var w=function(b,c){var d=r(c)?c:[];d.length&&(e="append"==b?e.concat(d):d.concat(e),a.insertToDOM(e,g))};a.append=function(a){w("append",
a)};a.prepend=function(a){w("prepend",a)}};p.prototype={constructor:p,fetchMarkup:function(){for(var b=[],a=this.getChildNodes(this.content_elem);a.length;)b.push(a.shift().outerHTML);return b},exploreEnvironment:function(b,a){var c=this.options;c.content_tag=this.content_elem.tagName.toLowerCase();b.length&&(l&&9>=l&&!c.tag&&(c.tag=b[0].match(/<([^>\s/]*)/)[1].toLowerCase()),1>=this.content_elem.children.length&&(a.data=this.html(b[0]+b[0]+b[0])),c.tag||(c.tag=this.content_elem.children[0].tagName.toLowerCase()),
this.getRowsHeight(b))},getRowsHeight:function(b){var a=this.options,c=a.item_height;a.cluster_height=0;if(b.length){b=this.content_elem.children;var d=b[Math.floor(b.length/2)];a.item_height=d.offsetHeight;"tr"==a.tag&&"collapse"!=m("borderCollapse",this.content_elem)&&(a.item_height+=parseInt(m("borderSpacing",this.content_elem),10)||0);"tr"!=a.tag&&(b=parseInt(m("marginTop",d),10)||0,d=parseInt(m("marginBottom",d),10)||0,a.item_height+=Math.max(b,d));a.block_height=a.item_height*a.rows_in_block;
a.rows_in_cluster=a.blocks_in_cluster*a.rows_in_block;a.cluster_height=a.blocks_in_cluster*a.block_height;return c!=a.item_height}},getClusterNum:function(){this.options.scroll_top=this.scroll_elem.scrollTop;return Math.floor(this.options.scroll_top/(this.options.cluster_height-this.options.block_height))||0},generateEmptyRow:function(){var b=this.options;if(!b.tag||!b.show_no_data_row)return[];var a=document.createElement(b.tag),c=document.createTextNode(b.no_data_text);a.className=b.no_data_class;
if("tr"==b.tag){var d=document.createElement("td");d.colSpan=100;d.appendChild(c)}a.appendChild(d||c);return[a.outerHTML]},generate:function(b,a){var c=this.options,d=b.length;if(d<c.rows_in_block)return{top_offset:0,bottom_offset:0,rows_above:0,rows:d?b:this.generateEmptyRow()};var f=Math.max((c.rows_in_cluster-c.rows_in_block)*a,0),h=f+c.rows_in_cluster,e=Math.max(f*c.item_height,0);c=Math.max((d-h)*c.item_height,0);d=[];var g=f;for(1>e&&g++;f<h;f++)b[f]&&d.push(b[f]);return{top_offset:e,bottom_offset:c,
rows_above:g,rows:d}},renderExtraTag:function(b,a){var c=document.createElement(this.options.tag);c.className=["clusterize-extra-row","clusterize-"+b].join(" ");a&&(c.style.height=a+"px");return c.outerHTML},insertToDOM:function(b,a){this.options.cluster_height||this.exploreEnvironment(b,a);var c=this.generate(b,this.getClusterNum()),d=c.rows.join(""),f=this.checkChanges("data",d,a),h=this.checkChanges("top",c.top_offset,a),e=this.checkChanges("bottom",c.bottom_offset,a),g=this.options.callbacks,
k=[];f||h?(c.top_offset&&(this.options.keep_parity&&k.push(this.renderExtraTag("keep-parity")),k.push(this.renderExtraTag("top-space",c.top_offset))),k.push(d),c.bottom_offset&&k.push(this.renderExtraTag("bottom-space",c.bottom_offset)),g.clusterWillChange&&g.clusterWillChange(),this.html(k.join("")),"ol"==this.options.content_tag&&this.content_elem.setAttribute("start",c.rows_above),this.content_elem.style["counter-increment"]="clusterize-counter "+(c.rows_above-1),g.clusterChanged&&g.clusterChanged()):
e&&(this.content_elem.lastChild.style.height=c.bottom_offset+"px")},html:function(b){var a=this.content_elem;if(l&&9>=l&&"tr"==this.options.tag){var c=document.createElement("div");for(c.innerHTML="<table><tbody>"+b+"</tbody></table>";b=a.lastChild;)a.removeChild(b);for(c=this.getChildNodes(c.firstChild.firstChild);c.length;)a.appendChild(c.shift())}else a.innerHTML=b},getChildNodes:function(b){b=b.children;for(var a=[],c=0,d=b.length;c<d;c++)a.push(b[c]);return a},checkChanges:function(b,a,c){var d=
a!=c[b];c[b]=a;return d}};return p});

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

722
docs/assets/js/index.js Normal file
View File

@ -0,0 +1,722 @@
/* global DataTable */
/* eslint-disable no-unused-vars */
const {
columns,
data
} = getSampleData();
// Hero
let datatable1 = new DataTable('.example-1', {
columns,
data,
checkboxColumn: true,
headerDropdown: [{
label: 'Add Column',
action: console.log
}]
});
// // Formatted Cells
// let datatable2 = new DataTable('.example-2', {
// columns: ['Name', 'Position', 'Office', 'Extn.', 'Start Date',
// { content: 'Salary', format: val => '$' + val, align: 'right' }],
// data
// });
// // Inline Filters
// let datatable3 = new DataTable('.example-3', {
// columns,
// data,
// enableInlineFilters: true
// });
// datatable3.showToastMessage('Click on a cell and press Ctrl/Cmd + F');
// // Keyboard
// let datatable4 = new DataTable('.example-4', {
// columns,
// data
// });
// datatable4.showToastMessage('Double click to edit');
// // Tree Structured Rows
// let datatable5 = new DataTable('.example-5', getTreeData());
// datatable5.showToastMessage('Expand/Collapse tree nodes');
function getSampleData(multiplier) {
let columns = ['Name', 'Position', 'Office', {name: 'Extn.', width: 120}, 'Start Date', 'Salary'];
let data = [
['Tiger Nixon', 'System Architect', 'Edinburgh', 5421, '2011/04/25', '320,800'],
['Garrett Winters', 'Accountant', 'Tokyo', 8422, '2011/07/25', '170,750'],
['Ashton Cox', 'Junior Technical Author', 'San Francisco', 1562, '2009/01/12', '86,000'],
['Cedric Kelly', 'Senior Javascript Developer', 'Edinburgh', 6224, '2012/03/29', '433,060'],
['Airi Satou', 'Accountant', 'Tokyo', 5407, '2008/11/28', '162,700'],
['Brielle Williamson', 'Integration Specialist', 'New York', 4804, '2012/12/02', '372,000'],
['Herrod Chandler', 'Sales Assistant', 'San Francisco', 9608, '2012/08/06', '137,500'],
['Rhona Davidson', 'Integration Specialist', 'Tokyo', 6200, '2010/10/14', '327,900'],
['Colleen Hurst', 'Javascript Developer', 'San Francisco', 2360, '2009/09/15', '205,500'],
['Sonya Frost', 'Software Engineer', 'Edinburgh', 1667, '2008/12/13', '103,600'],
['Jena Gaines', 'Office Manager', 'London', 3814, '2008/12/19', '90,560'],
['Quinn Flynn', 'Support Lead', 'Edinburgh', 9497, '2013/03/03', '342,000'],
['Charde Marshall', 'Regional Director', 'San Francisco', 6741, '2008/10/16', '470,600'],
['Haley Kennedy', 'Senior Marketing Designer', 'London', 3597, '2012/12/18', '313,500'],
['Tatyana Fitzpatrick', 'Regional Director', 'London', 1965, '2010/03/17', '385,750'],
['Michael Silva', 'Marketing Designer', 'London', 1581, '2012/11/27', '198,500'],
['Paul Byrd', 'Chief Financial Officer (CFO)', 'New York', 3059, '2010/06/09', '725,000'],
['Gloria Little', 'Systems Administrator', 'New York', 1721, '2009/04/10', '237,500'],
['Bradley Greer', 'Software Engineer', 'London', 2558, '2012/10/13', '132,000'],
['Dai Rios', 'Personnel Lead', 'Edinburgh', 2290, '2012/09/26', '217,500'],
['Jenette Caldwell', 'Development Lead', 'New York', 1937, '2011/09/03', '345,000'],
['Yuri Berry', 'Chief Marketing Officer (CMO)', 'New York', 6154, '2009/06/25', '675,000'],
['Caesar Vance', 'Pre-Sales Support', 'New York', 8330, '2011/12/12', '106,450'],
['Doris Wilder', 'Sales Assistant', 'Sidney', 3023, '2010/09/20', '85,600'],
['Angelica Ramos', 'Chief Executive Officer (CEO)', 'London', 5797, '2009/10/09', '1,200,000'],
['Gavin Joyce', 'Developer', 'Edinburgh', 8822, '2010/12/22', '92,575'],
['Jennifer Chang', 'Regional Director', 'Singapore', 9239, '2010/11/14', '357,650'],
['Brenden Wagner', 'Software Engineer', 'San Francisco', 1314, '2011/06/07', '206,850'],
['Fiona Green', 'Chief Operating Officer (COO)', 'San Francisco', 2947, '2010/03/11', '850,000'],
['Shou Itou', 'Regional Marketing', 'Tokyo', 8899, '2011/08/14', '163,000'],
['Michelle House', 'Integration Specialist', 'Sidney', 2769, '2011/06/02', '95,400'],
['Suki Burks', 'Developer', 'London', 6832, '2009/10/22', '114,500'],
['Prescott Bartlett', 'Technical Author', 'London', 3606, '2011/05/07', '145,000'],
['Gavin Cortez', 'Team Leader', 'San Francisco', 2860, '2008/10/26', '235,500'],
['Martena Mccray', 'Post-Sales support', 'Edinburgh', 8240, '2011/03/09', '324,050'],
['Unity Butler', 'Marketing Designer', 'San Francisco', 5384, '2009/12/09', '85,675'],
['Howard Hatfield', 'Office Manager', 'San Francisco', 7031, '2008/12/16', '164,500'],
['Hope Fuentes', 'Secretary', 'San Francisco', 6318, '2010/02/12', '109,850'],
['Vivian Harrell', 'Financial Controller', 'San Francisco', 9422, '2009/02/14', '452,500'],
['Timothy Mooney', 'Office Manager', 'London', 7580, '2008/12/11', '136,200'],
['Jackson Bradshaw', 'Director', 'New York', 1042, '2008/09/26', '645,750'],
['Olivia Liang', 'Support Engineer', 'Singapore', 2120, '2011/02/03', '234,500'],
['Bruno Nash', 'Software Engineer', 'London', 6222, '2011/05/03', '163,500'],
['Sakura Yamamoto', 'Support Engineer', 'Tokyo', 9383, '2009/08/19', '139,575'],
['Thor Walton', 'Developer', 'New York', 8327, '2013/08/11', '98,540'],
['Finn Camacho', 'Support Engineer', 'San Francisco', 2927, '2009/07/07', '87,500'],
['Serge Baldwin', 'Data Coordinator', 'Singapore', 8352, '2012/04/09', '138,575'],
['Zenaida Frank', 'Software Engineer', 'New York', 7439, '2010/01/04', '125,250'],
['Zorita Serrano', 'Software Engineer', 'San Francisco', 4389, '2012/06/01', '115,000'],
['Jennifer Acosta', 'Junior Javascript Developer', 'Edinburgh', 3431, '2013/02/01', '75,650'],
['Cara Stevens', 'Sales Assistant', 'New York', 3990, '2011/12/06', '145,600'],
['Hermione Butler', 'Regional Director', 'London', 1016, '2011/03/21', '356,250'],
['Lael Greer', 'Systems Administrator', 'London', 6733, '2009/02/27', '103,500'],
['Jonas Alexander', 'Developer', 'San Francisco', 8196, '2010/07/14', '86,500'],
['Shad Decker', 'Regional Director', 'Edinburgh', 6373, '2008/11/13', '183,000'],
['Michael Bruce', 'Javascript Developer', 'Singapore', 5384, '2011/06/27', '183,000'],
['Donna Snider', 'Customer Support', 'New York', 4226, '2011/01/25', '112,000']
];
if (multiplier) {
Array.from(new Array(multiplier - 1)).forEach(d => {
data = data.concat(data);
});
}
return {
columns,
data
};
}
function getTreeData() {
return {
columns: [{
'id': 'account',
'content': 'Account'
}, {
'id': 'opening_debit',
'content': 'Opening (Dr)'
}, {
'id': 'opening_credit',
'content': 'Opening (Cr)'
},
// {
// 'id': 'debit',
// 'content': 'Debit'
// },
// {
// 'id': 'credit',
// 'content': 'Credit'
// },
{
'id': 'closing_debit',
'content': 'Closing (Dr)'
}, {
'id': 'closing_credit',
'content': 'Closing (Cr)'
}, {
'id': 'currency',
'content': 'Currency',
'hidden': 1
}],
data: [{
'account_name': 'Application of Funds (Assets)',
'account': 'Application of Funds (Assets)',
'parent_account': null,
'indent': 0,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 12023729.54,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 12023729.54,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Current Assets',
'account': 'Current Assets',
'parent_account': 'Application of Funds (Assets)',
'indent': 1,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 13960649.54,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 13960649.54,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Accounts Receivable',
'account': 'Accounts Receivable',
'parent_account': 'Current Assets',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 742790.474,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 742790.474,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Debtors',
'account': 'Debtors',
'parent_account': 'Accounts Receivable',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 742790.474,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 742790.474,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Bank Accounts',
'account': 'Bank Accounts',
'parent_account': 'Current Assets',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 280676.822,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 280676.822,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Corporation Bank',
'account': 'Corporation Bank',
'parent_account': 'Bank Accounts',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 290676.822,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 290676.822,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'HDFC Bank',
'account': 'HDFC Bank',
'parent_account': 'Bank Accounts',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 10000.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 10000.0,
'has_value': true
}, {
'account_name': 'Cash In Hand',
'account': 'Cash In Hand',
'parent_account': 'Current Assets',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 229904.494,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 229904.494,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Cash',
'account': 'Cash',
'parent_account': 'Cash In Hand',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 229904.494,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 229904.494,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Stock Assets',
'account': 'Stock Assets',
'parent_account': 'Current Assets',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 12707277.75,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 12707277.75,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'All Warehouses',
'account': 'All Warehouses',
'parent_account': 'Stock Assets',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 12707277.75,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 12707277.75,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Finished Goods',
'account': 'Finished Goods',
'parent_account': 'All Warehouses',
'indent': 4,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 87320.3,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 87320.3,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Retail Stores',
'account': 'Retail Stores',
'parent_account': 'All Warehouses',
'indent': 4,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 4540590.0,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 4540590.0,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Bandra Store',
'account': 'Bandra Store',
'parent_account': 'Retail Stores',
'indent': 5,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 3246800.0,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 3246800.0,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Central Warehouse',
'account': 'Central Warehouse',
'parent_account': 'Retail Stores',
'indent': 5,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 1236790.0,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 1236790.0,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Lower Parel Store',
'account': 'Lower Parel Store',
'parent_account': 'Retail Stores',
'indent': 5,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 57000.0,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 57000.0,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Stores',
'account': 'Stores',
'parent_account': 'All Warehouses',
'indent': 4,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 8016525.27,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 8016525.27,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Work In Progress',
'account': 'Work In Progress',
'parent_account': 'All Warehouses',
'indent': 4,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 62842.18,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 62842.18,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Fixed Assets',
'account': 'Fixed Assets',
'parent_account': 'Application of Funds (Assets)',
'indent': 1,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 19920.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 19920.0,
'has_value': true
}, {
'account_name': 'Electronic Equipments',
'account': 'Electronic Equipments',
'parent_account': 'Fixed Assets',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 80.0,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 80.0,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Furnitures and Fixtures',
'account': 'Furnitures and Fixtures',
'parent_account': 'Fixed Assets',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 20000.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 20000.0,
'has_value': true
}, {
'account_name': 'Temporary Accounts',
'account': 'Temporary Accounts',
'parent_account': 'Application of Funds (Assets)',
'indent': 1,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 1917000.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 1917000.0,
'has_value': true
}, {
'account_name': 'Temporary Opening',
'account': 'Temporary Opening',
'parent_account': 'Temporary Accounts',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 1917000.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 1917000.0,
'has_value': true
}, {
'account_name': 'Source of Funds (Liabilities)',
'account': 'Source of Funds (Liabilities)',
'parent_account': null,
'indent': 0,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 2371628.002,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 2371628.002,
'has_value': true
}, {
'account_name': 'Current Liabilities',
'account': 'Current Liabilities',
'parent_account': 'Source of Funds (Liabilities)',
'indent': 1,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 2371628.002,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 2371628.002,
'has_value': true
}, {
'account_name': 'Accounts Payable',
'account': 'Accounts Payable',
'parent_account': 'Current Liabilities',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 368311.85,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 368311.85,
'has_value': true
}, {
'account_name': 'Creditors',
'account': 'Creditors',
'parent_account': 'Accounts Payable',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 194871.85,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 194871.85,
'has_value': true
}, {
'account_name': 'Salary Payable',
'account': 'Salary Payable',
'parent_account': 'Accounts Payable',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 173440.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 173440.0,
'has_value': true
}, {
'account_name': 'Duties and Taxes',
'account': 'Duties and Taxes',
'parent_account': 'Current Liabilities',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 150146.822,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 150146.822,
'has_value': true
}, {
'account_name': 'CGST',
'account': 'CGST',
'parent_account': 'Duties and Taxes',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 51479.591,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 51479.591,
'has_value': true
}, {
'account_name': 'IGST',
'account': 'IGST',
'parent_account': 'Duties and Taxes',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 1944.0,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 1944.0,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'SGST',
'account': 'SGST',
'parent_account': 'Duties and Taxes',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 97711.231,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 97711.231,
'has_value': true
}, {
'account_name': 'UGST',
'account': 'UGST',
'parent_account': 'Duties and Taxes',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 2900.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 2900.0,
'has_value': true
}, {
'account_name': 'Stock Liabilities',
'account': 'Stock Liabilities',
'parent_account': 'Current Liabilities',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 1853169.33,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 1853169.33,
'has_value': true
}, {
'account_name': 'Stock Received But Not Billed',
'account': 'Stock Received But Not Billed',
'parent_account': 'Stock Liabilities',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 1853169.33,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 1853169.33,
'has_value': true
}, {
'account_name': 'Equity',
'account': 'Equity',
'parent_account': null,
'indent': 0,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 10000.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 10000.0,
'has_value': true
}, {
'account_name': 'Capital Stock',
'account': 'Capital Stock',
'parent_account': 'Equity',
'indent': 1,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 10000.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 10000.0,
'has_value': true
}, {}, {
'account': 'Total',
'account_name': 'Total',
'warn_if_negative': true,
'opening_debit': 32260956.43,
'opening_credit': 22618854.891999997,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 32260956.43,
'closing_credit': 22618854.891999997,
'parent_account': null,
'indent': 0,
'has_value': true,
'currency': 'INR'
}]
};
}

172
docs/index.html Normal file
View File

@ -0,0 +1,172 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Frappe DataTable - A simple, modern datatable library for the web</title>
<link href="assets/css/frappe-datatable.css" rel="stylesheet">
<link href="assets/css/hljs-default.css" rel="stylesheet">
<link href="assets/css/index.css" rel="stylesheet">
</head>
<body>
<nav class="navbar">
<div class="container">
<h3>Frappe DataTable</h3>
<div class="navbar-links">
<a href="https://github.com/frappe/datatable">GitHub</a>
</div>
</div>
</nav>
<div class="container">
<section class="showcase align-center">
<img class="logo" src="assets/img/data-table-logo.svg" />
<h1 class="text-center">A simple, modern and interactive<br> datatable for the web</h1>
<div class="example-1"></div>
</section>
<section class="showcase installation">
<h3>Installation</h3>
<div class="code">
<pre><code class="shell"># Install using yarn
$ yarn add frappe-datatable
# or npm
$ npm install frappe-datatable</code></pre>
</section>
<section class="showcase installation">
<h3>Usage</h3>
<div class="code">
<pre><code>import DataTable from 'frappe-datatable';
// or add
// &lt;script src="frappe-datatable.js" &gt;&lt;/script&gt;
// in your html
let datatable = new DataTable({
columns: ['Name', 'Position', ...],
data: [
['Tiger Nixon', 'System Architect', ...],
['Garrett Winters', 'Accountant', ...],
...
]
});</code></pre>
</section>
<section class="showcase feature">
<h3>Cell Features</h3>
<div class="features">
<ul>
<li>Custom Formatters</li>
<li>Inline Editing</li>
<li>Mouse Selection</li>
</ul>
<ul>
<li>Copy Cells</li>
<li>Keyboard Navigation</li>
<li>Custom Cell Editor</li>
</ul>
</div>
</section>
<section class="showcase feature">
<h3>Column Features</h3>
<div class="features">
<ul>
<li>Reorder Columns</li>
<li>Sort by Column</li>
<li>Remove / Hide Column</li>
</ul>
<ul>
<li>Custom Actions</li>
<li>Resize Column</li>
<li>Flexible Layout</li>
</ul>
</div>
</section>
<section class="showcase feature">
<h3>Row Features</h3>
<div class="features">
<ul>
<li>Row Selection</li>
<li>Tree Structured Rows</li>
<li>Inline Filters</li>
</ul>
<ul>
<li>Large Number of Rows</li>
<li>Dynamic Row Height</li>
</ul>
</div>
</section>
<section class="showcase installation">
<h3>List of configurable options</h3>
<div class="code">
<pre><code>{
columns: [],
data: [],
dropdownButton: '▼',
headerDropdown: [
{
label: 'Custom Action',
action: console.log
}
],
events: {
onRemoveColumn(column) {
},
onSwitchColumn(column1, column2) {
},
onSortColumn(column) {
}
},
sortIndicator: {
asc: '↑',
desc: '↓',
none: ''
},
freezeMessage: '',
getEditor: () => {
},
addSerialNoColumn: true,
addCheckboxColumn: false,
enableClusterize: true,
enableLogs: false,
layout: 'fixed', // fixed, fluid
noDataMessage: 'No Data',
cellHeight: null,
enableInlineFilters: false
}</code></pre>
</div>
</section>
<section class="showcase align-center">
<p>
<button class="download-button">Download</button>
</p>
<p>
<a href="https://github.com/frappe/datatable">View on GitHub</a>
</p>
<p>
<span>MIT License</span>
</p>
</section>
</div>
<footer class="showcase align-center">
<img class="footer-logo" src="assets/img/frappe-bird-grey.svg" alt="Frappe Logo">
<section>Made with ❤️ by <a>Frappe</a></section>
</footer>
<script src="assets/js/clusterize.min.js"></script>
<script src="assets/js/Sortable.min.js"></script>
<script src="assets/js/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<script src="assets/js/frappe-datatable.js"></script>
<script src="assets/js/index.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -1,53 +1,35 @@
{
"name": "frappe-datatable",
"version": "0.0.0-development",
"version": "0.0.5",
"description": "A modern datatable library for the web",
"main": "dist/frappe-datatable.cjs.js",
"unpkg": "dist/frappe-datatable.min.js",
"jsdelivr": "dist/frappe-datatable.min.js",
"scripts": {
"start": "yarn run dev",
"build": "rollup -c && NODE_ENV=production rollup -c",
"build": "rollup -c",
"production": "rollup -c --production",
"build:docs": "rollup -c --docs",
"dev": "rollup -c -w",
"cy:server": "http-server -p 8989",
"cy:open": "cypress open",
"cy:run": "cypress run",
"test": "start-server-and-test cy:server http://localhost:8989 cy:run",
"test-local": "start-server-and-test cy:server http://localhost:8989 cy:open",
"travis-deploy-once": "travis-deploy-once",
"semantic-release": "semantic-release",
"lint": "eslint src",
"lint-and-build": "yarn lint && yarn build",
"commit": "npx git-cz"
"test": "mocha --compilers js:babel-core/register --colors ./test/*.spec.js",
"docs": "vuepress dev vuepress"
},
"files": [
"dist",
"src"
],
"devDependencies": {
"autoprefixer": "^9.0.0",
"chai": "3.5.0",
"cypress": "^9.2.0",
"cz-conventional-changelog": "^2.1.0",
"deepmerge": "^2.0.1",
"eslint": "^5.0.1",
"eslint-config-airbnb": "^16.1.0",
"eslint-config-airbnb-base": "^12.1.0",
"eslint-plugin-import": "^2.11.0",
"http-server": "^0.11.1",
"mocha": "3.3.0",
"postcss-custom-properties": "^7.0.0",
"postcss-cssnext": "^3.1.0",
"postcss-nested": "^3.0.0",
"rollup": "^0.59.4",
"rollup": "^0.59.1",
"rollup-plugin-commonjs": "^8.3.0",
"rollup-plugin-eslint": "^4.0.0",
"rollup-plugin-json": "^2.3.0",
"rollup-plugin-node-resolve": "^3.0.3",
"rollup-plugin-postcss": "^1.2.8",
"rollup-plugin-uglify-es": "^0.0.1",
"semantic-release": "^17.1.1",
"start-server-and-test": "^1.4.1",
"travis-deploy-once": "^5.0.1"
"script-loader": "^0.7.2",
"vuepress": "^0.8.4"
},
"repository": {
"type": "git",
@ -59,20 +41,15 @@
"grid",
"table"
],
"author": "Faris Ansari",
"author": "Frappe Technologies",
"license": "MIT",
"bugs": {
"url": "https://github.com/frappe/datatable/issues"
},
"homepage": "https://frappe.io/datatable",
"homepage": "https://frappe.github.io/datatable",
"dependencies": {
"hyperlist": "^1.0.0-beta",
"clusterize.js": "^0.18.0",
"lodash": "^4.17.5",
"sortablejs": "^1.7.0"
},
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
}
}
}

View File

@ -4,12 +4,11 @@ import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import postcss from 'rollup-plugin-postcss';
import nested from 'postcss-nested';
import customProperties from 'postcss-custom-properties';
import autoprefixer from 'autoprefixer';
import cssnext from 'postcss-cssnext';
import eslint from 'rollup-plugin-eslint';
import merge from 'deepmerge';
const production = process.env.NODE_ENV === 'production';
const production = process.argv[3] === '--production';
const baseJS = {
input: 'src/index.js',
@ -41,9 +40,8 @@ const baseCSS = {
extract: true,
minimize: production,
plugins: [
customProperties(),
nested(),
autoprefixer()
cssnext()
]
})
]
@ -87,8 +85,24 @@ const prodCSS = merge(devCSS, {
}
});
// docs
const docJS = merge(devIIFE, {
output: {
file: 'docs/assets/js/frappe-datatable.js'
}
});
const docCSS = merge(devCSS, {
output: {
file: 'docs/assets/css/frappe-datatable.css'
}
});
const developmentAssets = [devIIFE, devCjs, devCSS];
const documentationAssets = [docJS, docCSS];
const productionAssets = [prodIIFE, prodCSS];
const assets = production ? productionAssets : developmentAssets;
const docs = process.argv[3] === '--docs';
const assets = docs ? documentationAssets : production ? productionAssets : developmentAssets;
export default assets;

View File

@ -1,4 +1,6 @@
import HyperList from 'hyperlist';
import Clusterize from 'clusterize.js';
import $ from './dom';
import { nextTick } from './utils';
export default class BodyRenderer {
constructor(instance) {
@ -8,115 +10,60 @@ export default class BodyRenderer {
this.rowmanager = instance.rowmanager;
this.cellmanager = instance.cellmanager;
this.bodyScrollable = instance.bodyScrollable;
this.footer = this.instance.footer;
this.log = instance.log;
}
renderRows(rows) {
this.visibleRows = rows;
this.visibleRowIndices = rows.map(row => row.meta.rowIndex);
if (rows.length === 0) {
this.bodyScrollable.innerHTML = this.getNoDataHTML();
this.footer.innerHTML = '';
return;
}
// Create a temporary set for faster lookups.
// We can't change this.visibleRowIndices as it would be breaking for users.
let visibleRowIndicesSet = new Set(this.visibleRowIndices);
const rowViewOrder = this.datamanager.rowViewOrder.map(index => {
if (visibleRowIndicesSet.has(index)) {
return index;
}
return null;
}).filter(index => index !== null);
const computedStyle = getComputedStyle(this.bodyScrollable);
let config = {
width: computedStyle.width,
height: computedStyle.height,
itemHeight: this.options.cellHeight,
total: rows.length,
generate: (index) => {
const el = document.createElement('div');
const rowIndex = rowViewOrder[index];
const row = this.datamanager.getRow(rowIndex);
const rowHTML = this.rowmanager.getRowHTML(row, row.meta);
el.innerHTML = rowHTML;
return el.children[0];
},
afterRender: () => {
this.restoreState();
}
};
if (!this.hyperlist) {
this.hyperlist = new HyperList(this.bodyScrollable, config);
} else {
this.hyperlist.refresh(this.bodyScrollable, config);
}
this.renderFooter();
this.appendRemainingData = nextTick(this.appendRemainingData, this);
}
render() {
if (this.options.clusterize) {
this.renderBodyWithClusterize();
} else {
this.renderBodyHTML();
}
}
renderBodyHTML() {
const rows = this.datamanager.getRowsForView();
this.renderRows(rows);
// setDimensions requires atleast 1 row to exist in dom
this.bodyScrollable.innerHTML = this.getBodyHTML(rows);
this.instance.setDimensions();
this.restoreState();
}
renderFooter() {
if (!this.options.showTotalRow) return;
renderBodyWithClusterize() {
// first page
const rows = this.datamanager.getRowsForView(0, 20);
let initialData = this.getDataForClusterize(rows);
const totalRow = this.getTotalRow();
let html = this.rowmanager.getRowHTML(totalRow, { isTotalRow: 1, rowIndex: 'totalRow' });
if (initialData.length === 0) {
initialData = [this.getNoDataHTML()];
}
this.footer.innerHTML = html;
}
if (!this.clusterize) {
// empty body
this.bodyScrollable.innerHTML = this.getBodyHTML([]);
getTotalRow() {
const columns = this.datamanager.getColumns();
const totalRowTemplate = columns.map(col => {
let content = null;
if (['_rowIndex', '_checkbox'].includes(col.id)) {
content = '';
}
return {
content,
isTotalRow: 1,
colIndex: col.colIndex,
column: col
};
});
// first 20 rows will appended
// rest of them in nextTick
this.clusterize = new Clusterize({
rows: initialData,
scrollElem: this.bodyScrollable,
contentElem: $('tbody', this.bodyScrollable),
callbacks: {
clusterChanged: () => this.restoreState()
},
/* eslint-disable */
show_no_data_row: false,
/* eslint-enable */
});
const totalRow = totalRowTemplate.map((cell, i) => {
if (cell.content === '') return cell;
// setDimensions requires atleast 1 row to exist in dom
this.instance.setDimensions();
} else {
this.clusterize.update(initialData);
}
if (this.options.hooks.columnTotal) {
const columnValues = this.visibleRows.map(row => row[i].content);
const result = this.options.hooks.columnTotal.call(this.instance, columnValues, cell);
if (result != null) {
cell.content = result;
return cell;
}
}
cell.content = this.visibleRows.reduce((acc, prevRow) => {
const prevCell = prevRow[i];
if (typeof prevCell.content === 'number') {
if (acc == null) acc = 0;
return acc + prevCell.content;
}
return acc;
}, cell.content);
return cell;
});
return totalRow;
this.appendRemainingData();
}
restoreState() {
@ -125,6 +72,12 @@ export default class BodyRenderer {
this.cellmanager.focusCellOnClusterChanged();
}
appendRemainingData() {
const rows = this.datamanager.getRowsForView(20);
const data = this.getDataForClusterize(rows);
this.clusterize.append(data);
}
showToastMessage(message, hideAfter) {
this.instance.toastMessage.innerHTML = this.getToastMessageHTML(message);
@ -139,6 +92,20 @@ export default class BodyRenderer {
this.instance.toastMessage.innerHTML = '';
}
getDataForClusterize(rows) {
return rows.map(row => this.rowmanager.getRowHTML(row, row.meta));
}
getBodyHTML(rows) {
return `
<table class="dt-body">
<tbody>
${rows.map(row => this.rowmanager.getRowHTML(row, row.meta)).join('')}
</tbody>
</table>
`;
}
getNoDataHTML() {
return `<div class="dt-scrollable__no-data">${this.options.noDataMessage}</div>`;
}

View File

@ -2,11 +2,9 @@ import {
copyTextToClipboard,
makeDataAttributeString,
throttle,
linkProperties,
escapeHTML,
linkProperties
} from './utils';
import $ from './dom';
import icons from './icons';
export default class CellManager {
constructor(instance) {
@ -15,18 +13,14 @@ export default class CellManager {
'wrapper',
'options',
'style',
'header',
'bodyScrollable',
'columnmanager',
'rowmanager',
'datamanager',
'keyboard',
'footer'
'keyboard'
]);
this.bindEvents();
this.stickyRowWidth = 0;
this.stickyColWitdh = [];
}
bindEvents() {
@ -55,12 +49,34 @@ export default class CellManager {
this.activateEditing(this.$focusedCell);
} else if (this.$editingCell) {
// enter keypress on editing cell
this.submitEditing();
this.deactivateEditing();
}
});
}
bindKeyboardNav() {
const focusCell = (direction) => {
if (!this.$focusedCell || this.$editingCell) {
return false;
}
let $cell = this.$focusedCell;
if (direction === 'left' || direction === 'shift+tab') {
$cell = this.getLeftCell$($cell);
} else if (direction === 'right' || direction === 'tab') {
$cell = this.getRightCell$($cell);
} else if (direction === 'up') {
$cell = this.getAboveCell$($cell);
} else if (direction === 'down') {
$cell = this.getBelowCell$($cell);
}
this.focusCell($cell);
return true;
};
const focusLastCell = (direction) => {
if (!this.$focusedCell || this.$editingCell) {
return false;
@ -87,14 +103,13 @@ export default class CellManager {
};
['left', 'right', 'up', 'down', 'tab', 'shift+tab']
.map(direction => this.keyboard.on(direction, () => this.focusCellInDirection(direction)));
.map(direction => this.keyboard.on(direction, () => focusCell(direction)));
['left', 'right', 'up', 'down']
.map(direction => this.keyboard.on(`ctrl+${direction}`, () => focusLastCell(direction)));
this.keyboard.on('esc', () => {
this.deactivateEditing(false);
this.columnmanager.toggleFilter(false);
this.deactivateEditing();
});
if (this.options.inlineFilters) {
@ -105,10 +120,6 @@ export default class CellManager {
this.activateFilter(colIndex);
return true;
});
$.on(this.header, 'focusin', '.dt-filter', () => {
this.unfocusCell(this.$focusedCell);
});
}
}
@ -137,10 +148,7 @@ export default class CellManager {
bindCopyCellContents() {
this.keyboard.on('ctrl+c', () => {
const noOfCellsCopied = this.copyCellContents(this.$focusedCell, this.$selectionCursor);
const message = this.instance.translate('{count} cells copied', {
count: noOfCellsCopied
});
const message = `${noOfCellsCopied} cell${noOfCellsCopied > 1 ? 's' : ''} copied`;
if (noOfCellsCopied) {
this.instance.showToastMessage(message, 2);
}
@ -175,14 +183,6 @@ export default class CellManager {
mouseDown = false;
});
if (this.options.showTotalRow) {
$.on(this.footer, 'click', '.dt-cell', (e) => {
this.focusCell($(e.delegatedTarget));
});
}
const selectArea = (e) => {
if (!mouseDown) return;
this.selectArea($(e.delegatedTarget));
@ -205,9 +205,7 @@ export default class CellManager {
}
focusCell($cell, {
skipClearSelection = 0,
skipDOMFocus = 0,
skipScrollToCell = 0
skipClearSelection = 0
} = {}) {
if (!$cell) return;
@ -227,9 +225,7 @@ export default class CellManager {
return;
}
if (!skipScrollToCell) {
this.scrollToCell($cell);
}
this.scrollToCell($cell);
this.deactivateEditing();
if (!skipClearSelection) {
@ -243,27 +239,12 @@ export default class CellManager {
this.$focusedCell = $cell;
$cell.classList.add('dt-cell--focus');
if (!skipDOMFocus) {
// so that keyboard nav works
$cell.focus();
}
// so that keyboard nav works
$cell.focus();
this.highlightRowColumnHeader($cell);
}
unfocusCell($cell) {
if (!$cell) return;
// remove cell border
$cell.classList.remove('dt-cell--focus');
this.$focusedCell = null;
// reset header background
if (this.lastHeaders) {
this.lastHeaders.forEach(header => header && header.classList.remove('dt-cell--highlight'));
}
}
highlightRowColumnHeader($cell) {
const {
colIndex,
@ -275,14 +256,14 @@ export default class CellManager {
const rowHeaderSelector = `.dt-cell--${srNoColIndex}-${rowIndex}`;
if (this.lastHeaders) {
this.lastHeaders.forEach(header => header && header.classList.remove('dt-cell--highlight'));
this.lastHeaders.forEach(header => header.classList.remove('dt-cell--highlight'));
}
const colHeader = $(colHeaderSelector, this.wrapper);
const rowHeader = $(rowHeaderSelector, this.wrapper);
this.lastHeaders = [colHeader, rowHeader];
this.lastHeaders.forEach(header => header && header.classList.add('dt-cell--highlight'));
this.lastHeaders.forEach(header => header.classList.add('dt-cell--highlight'));
}
selectAreaOnClusterChanged() {
@ -312,15 +293,11 @@ export default class CellManager {
const $cell = this.getCell$(colIndex, rowIndex);
if (!$cell) return;
// this function is called after hyperlist renders the rows after scroll,
// this function is called after selectAreaOnClusterChanged,
// focusCell calls clearSelection which resets the area selection
// so a flag to skip it
// we also skip DOM focus and scroll to cell
// because it fights with the user scroll
this.focusCell($cell, {
skipClearSelection: 1,
skipDOMFocus: 1,
skipScrollToCell: 1
skipClearSelection: 1
});
}
@ -456,10 +433,7 @@ export default class CellManager {
}
}
deactivateEditing(submitValue = true) {
if (submitValue) {
this.submitEditing();
}
deactivateEditing() {
// keep focus on the cell so that keyboard navigation works
if (this.$focusedCell) this.$focusedCell.focus();
@ -510,9 +484,7 @@ export default class CellManager {
}
submitEditing() {
let promise = Promise.resolve();
if (!this.$editingCell) return promise;
if (!this.$editingCell) return;
const $cell = this.$editingCell;
const {
rowIndex,
@ -524,38 +496,25 @@ export default class CellManager {
const editor = this.currentCellEditor;
if (editor) {
let valuePromise = editor.getValue();
const value = editor.getValue();
const done = editor.setValue(value, rowIndex, col);
const oldValue = this.getCell(colIndex, rowIndex).content;
// convert to stubbed Promise
if (!valuePromise.then) {
valuePromise = Promise.resolve(valuePromise);
// update cell immediately
this.updateCell(colIndex, rowIndex, value);
$cell.focus();
if (done && done.then) {
// revert to oldValue if promise fails
done.catch((e) => {
console.log(e);
this.updateCell(colIndex, rowIndex, oldValue);
});
}
promise = valuePromise.then((value) => {
const oldValue = this.getCell(colIndex, rowIndex).content;
if (oldValue === value) return false;
const done = editor.setValue(value, rowIndex, col);
// update cell immediately
this.updateCell(colIndex, rowIndex, value, true);
$cell.focus();
if (done && done.then) {
// revert to oldValue if promise fails
done.catch((e) => {
console.log(e);
this.updateCell(colIndex, rowIndex, oldValue);
});
}
return done;
});
}
}
this.currentCellEditor = null;
return promise;
}
copyCellContents($cell1, $cell2) {
@ -563,18 +522,10 @@ export default class CellManager {
// copy only focusedCell
const {
colIndex,
rowIndex,
isTotalRow
rowIndex
} = $.data($cell1);
let copiedContent = '';
if (isTotalRow) {
let choosenFooterCell = this.$focusedCell;
copiedContent = choosenFooterCell.children[0].title;
} else {
const cell = this.getCell(colIndex, rowIndex);
copiedContent = cell.content;
}
copyTextToClipboard(copiedContent);
const cell = this.getCell(colIndex, rowIndex);
copyTextToClipboard(cell.content);
return 1;
}
const cells = this.getCellsInRange($cell1, $cell2);
@ -625,7 +576,7 @@ export default class CellManager {
let rowIndex = i + focusedCell.rowIndex;
row.forEach((cell, j) => {
let colIndex = j + focusedCell.colIndex;
this.updateCell(colIndex, rowIndex, cell, true);
this.updateCell(colIndex, rowIndex, cell);
});
});
}
@ -636,20 +587,20 @@ export default class CellManager {
if (!this.columnmanager.isFilterShown) {
// put focus back on cell
this.$focusedCell && this.$focusedCell.focus();
this.$focusedCell.focus();
}
}
updateCell(colIndex, rowIndex, value, refreshHtml = false) {
updateCell(colIndex, rowIndex, value) {
const cell = this.datamanager.updateCell(colIndex, rowIndex, {
content: value
});
this.refreshCell(cell, refreshHtml);
this.refreshCell(cell);
}
refreshCell(cell, refreshHtml = false) {
refreshCell(cell) {
const $cell = $(this.selector(cell.colIndex, cell.rowIndex), this.bodyScrollable);
$cell.innerHTML = this.getCellContent(cell, refreshHtml);
$cell.innerHTML = this.getCellContent(cell);
}
toggleTreeButton(rowIndex, flag) {
@ -665,49 +616,6 @@ export default class CellManager {
return colIndex < this.columnmanager.getFirstColumnIndex();
}
focusCellInDirection(direction) {
if (!this.$focusedCell || (this.$editingCell && ['left', 'right', 'up', 'down'].includes(direction))) {
return false;
} else if (this.$editingCell && ['tab', 'shift+tab'].includes(direction)) {
this.deactivateEditing();
}
let $cell = this.$focusedCell;
if (direction === 'left' || direction === 'shift+tab') {
$cell = this.getLeftCell$($cell);
} else if (direction === 'right' || direction === 'tab') {
$cell = this.getRightCell$($cell);
} else if (direction === 'up') {
$cell = this.getAboveCell$($cell);
} else if (direction === 'down') {
$cell = this.getBelowCell$($cell);
}
if (!$cell) {
return false;
}
const {
colIndex
} = $.data($cell);
const column = this.columnmanager.getColumn(colIndex);
if (!column.focusable) {
let $prevFocusedCell = this.$focusedCell;
this.unfocusCell($prevFocusedCell);
this.$focusedCell = $cell;
let ret = this.focusCellInDirection(direction);
if (!ret) {
this.focusCell($prevFocusedCell);
}
return ret;
}
this.focusCell($cell);
return true;
}
getCell$(colIndex, rowIndex) {
return $(this.selector(colIndex, rowIndex), this.bodyScrollable);
}
@ -773,7 +681,7 @@ export default class CellManager {
}
scrollToCell($cell) {
if ($.inViewport($cell, this.bodyScrollable) || $.inViewport($cell, this.footer)) return false;
if ($.inViewport($cell, this.bodyScrollable)) return false;
const {
rowIndex
@ -791,54 +699,16 @@ export default class CellManager {
rowIndex,
colIndex,
isHeader,
isFilter,
isTotalRow
isFilter
} = cell;
const dataAttr = makeDataAttributeString({
rowIndex,
colIndex,
isHeader,
isFilter,
isTotalRow
isFilter
});
let styles = '';
const row = this.datamanager.getRow(rowIndex);
const isBodyCell = !(isHeader || isFilter || isTotalRow);
const serialNoColIndex = !this.options.checkboxColumn && this.options.serialNoColumn ? 0 : 1;
let sticky = false;
let checkboxserialNoclass = '';
if (colIndex === 0 && this.options.checkboxColumn) {
if (cell.isHeader && !(cell.id in this.stickyColWitdh)) this.stickyRowWidth = 34;
checkboxserialNoclass = 'dt-cell-checkbox';
sticky = true;
} else if (colIndex === serialNoColIndex && this.options.serialNoColumn) {
if (cell.isHeader && !(cell.id in this.stickyColWitdh)) {
this.stickyColWitdh[cell.id] = this.stickyRowWidth;
this.stickyRowWidth += (cell.width || 37);
checkboxserialNoclass = 'dt-cell-serial-no';
}
styles = `left:${this.stickyColWitdh[isBodyCell ? cell.column.id : cell.id]}px;`;
sticky = true;
} else if (cell.sticky) {
if (cell.isHeader && !(cell.id in this.stickyColWitdh)) {
this.stickyColWitdh[cell.id] = this.stickyRowWidth;
this.stickyRowWidth += ((cell.width || 100) + 1);
}
styles = `left:${this.stickyColWitdh[cell.id]}px;`;
sticky = true;
} else if ((isBodyCell || isTotalRow) && cell.column.sticky) {
styles = `left:${this.stickyColWitdh[cell.column.id]}px;`;
sticky = true;
}
const isBodyCell = !(isHeader || isFilter);
const className = [
'dt-cell',
@ -847,20 +717,17 @@ export default class CellManager {
isBodyCell ? 'dt-cell--row-' + rowIndex : '',
isHeader ? 'dt-cell--header' : '',
isHeader ? `dt-cell--header-${colIndex}` : '',
isFilter ? 'dt-cell--filter' : '',
isBodyCell && (row && row.meta.isTreeNodeClose) ? 'dt-cell--tree-close' : '',
sticky ? 'dt-sticky-col' : '',
checkboxserialNoclass,
isFilter ? 'dt-cell--filter' : ''
].join(' ');
return `
<div class="${className}" ${dataAttr} tabindex="0" style="${styles}">
<td class="${className}" ${dataAttr} tabindex="0">
${this.getCellContent(cell)}
</div>
</td>
`;
}
getCellContent(cell, refreshHtml = false) {
getCellContent(cell) {
const {
isHeader,
isFilter,
@ -871,11 +738,7 @@ export default class CellManager {
const editCellHTML = editable ? this.getEditCellHTML(colIndex) : '';
const sortable = isHeader && cell.sortable !== false;
const sortIndicator = sortable ?
`<span class="sort-indicator">
${this.options.sortIndicator[cell.sortOrder]}
</span>` :
'';
const sortIndicator = sortable ? '<span class="sort-indicator"></span>' : '';
const resizable = isHeader && cell.resizable !== false;
const resizeColumn = resizable ? '<span class="dt-cell__resize-handle"></span>' : '';
@ -883,41 +746,29 @@ export default class CellManager {
const hasDropdown = isHeader && cell.dropdown !== false;
const dropdown = hasDropdown ? this.columnmanager.getDropdownHTML() : '';
let customFormatter = CellManager.getCustomCellFormatter(cell);
const customFormatter = cell.format || (cell.column && cell.column.format) || null;
let contentHTML;
if (isHeader || isFilter || !customFormatter) {
contentHTML = cell.content;
} else {
if (!cell.html || refreshHtml) {
const row = this.datamanager.getRow(cell.rowIndex);
const data = this.datamanager.getData(cell.rowIndex);
contentHTML = customFormatter(cell.content, row, cell.column, data);
} else {
contentHTML = cell.html;
}
const row = this.datamanager.getRow(cell.rowIndex);
const data = this.datamanager.getData(cell.rowIndex);
contentHTML = customFormatter(cell.content, row, cell.column, data);
}
cell.html = contentHTML;
if (this.options.treeView && !(isHeader || isFilter) && cell.indent !== undefined) {
const nextRow = this.datamanager.getRow(cell.rowIndex + 1);
const addToggle = nextRow && nextRow.meta.indent > cell.indent;
const leftPadding = 20;
const unit = 'px';
// Add toggle and indent in the first column
const firstColumnIndex = this.datamanager.getColumnIndexById('_rowIndex') + 1;
if (firstColumnIndex === cell.colIndex) {
const padding = ((cell.indent || 0)) * leftPadding;
const padding = ((cell.indent || 0) + 1) * 1.5;
const toggleHTML = addToggle ?
`<span class="dt-tree-node__toggle" style="left: ${padding - leftPadding}${unit}">
<span class="icon-open">${icons.chevronDown}</span>
<span class="icon-close">${icons.chevronRight}</span>
</span>` : '';
contentHTML = `<span class="dt-tree-node" style="padding-left: ${padding}${unit}">
${toggleHTML}
<span>${contentHTML}</span>
</span>`;
`<span class="dt-tree-node__toggle" style="left: ${padding - 1.5}rem"></span>` : '';
contentHTML = `<span class="dt-tree-node" style="padding-left: ${padding}rem">
${toggleHTML}${contentHTML}</span>`;
}
}
@ -926,7 +777,7 @@ export default class CellManager {
isHeader ? `dt-cell__content--header-${colIndex}` : `dt-cell__content--col-${colIndex}`
].join(' ');
let cellContentHTML = `
return `
<div class="${className}">
${contentHTML}
${sortIndicator}
@ -935,16 +786,6 @@ export default class CellManager {
</div>
${editCellHTML}
`;
let div = document.createElement('div');
div.innerHTML = contentHTML;
let textContent = div.textContent;
textContent = textContent.replace(/\s+/g, ' ').trim();
cellContentHTML = cellContentHTML.replace('>', ` title="${escapeHTML(textContent)}">`);
return cellContentHTML;
}
getEditCellHTML(colIndex) {
@ -954,8 +795,4 @@ export default class CellManager {
selector(colIndex, rowIndex) {
return `.dt-cell--${colIndex}-${rowIndex}`;
}
static getCustomCellFormatter(cell) {
return cell.format || (cell.column && cell.column.format) || null;
}
}

View File

@ -14,35 +14,57 @@ export default class ColumnManager {
'fireEvent',
'header',
'datamanager',
'cellmanager',
'style',
'wrapper',
'rowmanager',
'bodyScrollable',
'bodyRenderer'
'bodyScrollable'
]);
this.bindEvents();
}
renderHeader() {
this.header.innerHTML = '<div></div>';
this.header.innerHTML = '<thead></thead>';
this.refreshHeader();
}
refreshHeader() {
const columns = this.datamanager.getColumns();
const $cols = $.each('.dt-cell--header', this.header);
// refresh html
$('div', this.header).innerHTML = this.getHeaderHTML(columns);
const refreshHTML =
// first init
!$('.dt-cell', this.header) ||
// deleted column
columns.length < $cols.length;
this.$filterRow = $('.dt-row-filter', this.header);
if (this.$filterRow) {
$.style(this.$filterRow, { display: 'none' });
if (refreshHTML) {
// refresh html
$('thead', this.header).innerHTML = this.getHeaderHTML(columns);
this.$filterRow = $('.dt-row[data-is-filter]', this.header);
if (this.$filterRow) {
$.style(this.$filterRow, { display: 'none' });
}
} else {
// update data-attributes
$cols.map(($col, i) => {
const column = columns[i];
// column sorted or order changed
// update colIndex of each header cell
$.data($col, {
colIndex: column.colIndex
});
// refresh sort indicator
const sortIndicator = $('.sort-indicator', $col);
if (sortIndicator) {
sortIndicator.innerHTML = this.options.sortIndicator[column.sortOrder];
}
});
}
// reset columnMap
this.$columnMap = [];
this.bindMoveColumn();
}
getHeaderHTML(columns) {
@ -60,77 +82,51 @@ export default class ColumnManager {
bindEvents() {
this.bindDropdown();
this.bindResizeColumn();
this.bindPerfectColumnWidth();
this.bindMoveColumn();
this.bindFilter();
}
bindDropdown() {
let $activeDropdown;
let activeClass = 'dt-dropdown--active';
let toggleClass = '.dt-dropdown__toggle';
let dropdownClass = '.dt-dropdown__list';
// attach the dropdown list to container
this.instance.dropdownContainer.innerHTML = this.getDropdownListHTML();
this.$dropdownList = this.instance.dropdownContainer.firstElementChild;
$.on(this.header, 'click', toggleClass, (e, $button) => {
const $dropdown = $.closest('.dt-dropdown', $button);
$.on(this.header, 'click', toggleClass, e => {
this.openDropdown(e);
if (!$dropdown.classList.contains(activeClass)) {
deactivateDropdown();
$dropdown.classList.add(activeClass);
$activeDropdown = $dropdown;
} else {
deactivateDropdown();
}
});
const deactivateDropdownOnBodyClick = (e) => {
const selector = [
toggleClass, toggleClass + ' *',
dropdownClass, dropdownClass + ' *'
].join(',');
if (e.target.matches(selector)) return;
$.on(document.body, 'click', (e) => {
if (e.target.matches(toggleClass)) return;
deactivateDropdown();
};
$.on(document.body, 'click', deactivateDropdownOnBodyClick);
document.addEventListener('scroll', deactivateDropdown, true);
this.instance.on('onDestroy', () => {
$.off(document.body, 'click', deactivateDropdownOnBodyClick);
$.off(document, 'scroll', deactivateDropdown);
});
$.on(this.$dropdownList, 'click', '.dt-dropdown__list-item', (e, $item) => {
if (!this._dropdownActiveColIndex) return;
const dropdownItems = this.options.headerDropdown;
const { index } = $.data($item);
const colIndex = this._dropdownActiveColIndex;
const dropdownItems = this.options.headerDropdown;
$.on(this.header, 'click', '.dt-dropdown__list-item', (e, $item) => {
const $col = $.closest('.dt-cell', $item);
const {
index
} = $.data($item);
const {
colIndex
} = $.data($col);
let callback = dropdownItems[index].action;
callback && callback.call(this.instance, this.getColumn(colIndex));
this.hideDropdown();
});
const _this = this;
function deactivateDropdown(e) {
_this.hideDropdown();
$activeDropdown && $activeDropdown.classList.remove(activeClass);
$activeDropdown = null;
}
this.hideDropdown();
}
openDropdown(e) {
if (!this._dropdownWidth) {
$.style(this.$dropdownList, { display: '' });
this._dropdownWidth = $.style(this.$dropdownList, 'width');
}
$.style(this.$dropdownList, {
display: '',
left: (e.clientX - this._dropdownWidth + 4) + 'px',
top: (e.clientY + 4) + 'px'
});
const $cell = $.closest('.dt-cell', e.target);
const { colIndex } = $.data($cell);
this._dropdownActiveColIndex = colIndex;
}
hideDropdown() {
$.style(this.$dropdownList, {
display: 'none'
});
this._dropdownActiveColIndex = null;
}
bindResizeColumn() {
@ -155,7 +151,7 @@ export default class ColumnManager {
startX = e.pageX;
});
const onMouseup = (e) => {
$.on(document.body, 'mouseup', (e) => {
document.body.classList.remove('dt-resize');
if (!$resizingCell) return;
isDragging = false;
@ -166,95 +162,61 @@ export default class ColumnManager {
this.setColumnWidth(colIndex);
this.style.setBodyStyle();
$resizingCell = null;
};
$.on(document.body, 'mouseup', onMouseup);
this.instance.on('onDestroy', () => {
$.off(document.body, 'mouseup', onMouseup);
});
const onMouseMove = (e) => {
$.on(document.body, 'mousemove', (e) => {
if (!isDragging) return;
let delta = e.pageX - startX;
if (this.options.direction === 'rtl') {
delta = -1 * delta;
}
const finalWidth = startWidth + delta;
const finalWidth = startWidth + (e.pageX - startX);
const {
colIndex
} = $.data($resizingCell);
let columnMinWidth = this.options.minimumColumnWidth;
if (columnMinWidth > finalWidth) {
// don't resize past 30 pixels
if (this.getColumnMinWidth(colIndex) > finalWidth) {
// don't resize past minWidth
return;
}
this.datamanager.updateColumn(colIndex, {
width: finalWidth
});
this.setColumnHeaderWidth(colIndex);
};
$.on(document.body, 'mousemove', onMouseMove);
this.instance.on('onDestroy', () => {
$.off(document.body, 'mousemove', onMouseMove);
});
}
bindPerfectColumnWidth() {
$.on(this.header, 'dblclick', '.dt-cell .dt-cell__resize-handle', (e, $handle) => {
const $cell = $handle.parentNode.parentNode;
const { colIndex } = $.data($cell);
let longestCell = this.bodyRenderer.visibleRows
.map(d => d[colIndex])
.reduce((acc, curr) => acc.content.length > curr.content.length ? acc : curr);
let $longestCellHTML = this.cellmanager.getCellHTML(longestCell);
let $div = document.createElement('div');
$div.innerHTML = $longestCellHTML;
let cellText = $div.querySelector('.dt-cell__content').textContent;
let {
borderLeftWidth,
borderRightWidth,
paddingLeft,
paddingRight
} = $.getStyle(this.bodyScrollable.querySelector('.dt-cell__content'));
let padding = [borderLeftWidth, borderRightWidth, paddingLeft, paddingRight]
.map(parseFloat)
.reduce((sum, val) => sum + val);
let width = $.measureTextWidth(cellText) + padding;
this.datamanager.updateColumn(colIndex, { width });
this.setColumnHeaderWidth(colIndex);
this.setColumnWidth(colIndex);
});
}
bindMoveColumn() {
if (this.options.disableReorderColumn) return;
let initialized;
const $parent = $('.dt-row', this.header);
const initialize = () => {
if (initialized) {
$.off(document.body, 'mousemove', initialize);
return;
}
const ready = $('.dt-cell', this.header);
if (!ready) return;
this.sortable = Sortable.create($parent, {
onEnd: (e) => {
const {
oldIndex,
newIndex
} = e;
const $draggedCell = e.item;
const {
colIndex
} = $.data($draggedCell);
if (+colIndex === newIndex) return;
const $parent = $('.dt-row', this.header);
this.switchColumn(oldIndex, newIndex);
},
preventOnFilter: false,
filter: '.dt-cell__resize-handle, .dt-dropdown',
chosenClass: 'dt-cell--dragging',
animation: 150
});
this.sortable = Sortable.create($parent, {
onEnd: (e) => {
const {
oldIndex,
newIndex
} = e;
const $draggedCell = e.item;
const {
colIndex
} = $.data($draggedCell);
if (+colIndex === newIndex) return;
this.switchColumn(oldIndex, newIndex);
},
preventOnFilter: false,
filter: '.dt-cell__resize-handle, .dt-dropdown',
chosenClass: 'dt-cell--dragging',
animation: 150
});
};
$.on(document.body, 'mousemove', initialize);
}
sortColumn(colIndex, nextSortOrder) {
@ -304,8 +266,6 @@ export default class ColumnManager {
}
toggleFilter(flag) {
if (!this.options.inlineFilters) return;
let showFilter;
if (flag === undefined) {
showFilter = !this.isFilterShown;
@ -326,48 +286,31 @@ export default class ColumnManager {
focusFilter(colIndex) {
if (!this.isFilterShown) return;
const $filterInput = $(`.dt-cell--col-${colIndex} .dt-filter`, this.$filterRow);
const $filterInput = $(`[data-col-index="${colIndex}"] .dt-filter`, this.$filterRow);
$filterInput.focus();
}
bindFilter() {
if (!this.options.inlineFilters) return;
const handler = e => {
this.applyFilter(this.getAppliedFilters());
const $filterCell = $.closest('.dt-cell', e.target);
const {
colIndex
} = $.data($filterCell);
const keyword = e.target.value;
this.datamanager.filterRows(keyword, colIndex)
.then(({
rowsToHide,
rowsToShow
}) => {
this.rowmanager.hideRows(rowsToHide);
this.rowmanager.showRows(rowsToShow);
});
};
$.on(this.header, 'keydown', '.dt-filter', debounce(handler, 300));
}
applyFilter(filters) {
this.datamanager.filterRows(filters)
.then(({
rowsToShow
}) => {
this.rowmanager.showRows(rowsToShow);
});
}
getAppliedFilters() {
const filters = {};
$.each('.dt-filter', this.header).map((input) => {
const value = input.value;
if (value) {
filters[input.dataset.colIndex] = value;
}
});
return filters;
}
applyDefaultSortOrder() {
// sort rows if any 1 column has a default sortOrder set
const columnsToSort = this.getColumns().filter(col => col.sortOrder !== 'none');
if (columnsToSort.length === 1) {
const column = columnsToSort[0];
this.sortColumn(column.colIndex, column.sortOrder);
}
}
sortRows(colIndex, sortOrder) {
return this.datamanager.sortRows(colIndex, sortOrder);
}
@ -382,9 +325,11 @@ export default class ColumnManager {
setColumnWidth(colIndex, width) {
colIndex = +colIndex;
this._columnWidthMap = this._columnWidthMap || [];
let columnWidth = width || this.getColumn(colIndex).width;
let index = this._columnWidthMap[colIndex];
const selector = [
`.dt-cell__content--col-${colIndex}`,
`.dt-cell__edit--col-${colIndex}`
@ -394,7 +339,11 @@ export default class ColumnManager {
width: columnWidth + 'px'
};
this.style.setStyle(selector, styles);
index = this.style.setStyle(selector, styles, index);
if (index !== undefined) {
this._columnWidthMap[colIndex] = index;
}
}
setColumnHeaderWidth(colIndex) {
@ -432,24 +381,17 @@ export default class ColumnManager {
}
getDropdownHTML() {
const { dropdownButton } = this.options;
const { dropdownButton, headerDropdown: dropdownItems } = this.options;
return `
<div class="dt-dropdown">
<div class="dt-dropdown__toggle">${dropdownButton}</div>
<div class="dt-dropdown__list">
${dropdownItems.map((d, i) => `
<div class="dt-dropdown__list-item" data-index="${i}">${d.label}</div>
`).join('')}
</div>
</div>
`;
}
getDropdownListHTML() {
const { headerDropdown: dropdownItems } = this.options;
return `
<div class="dt-dropdown__list">
${dropdownItems.map((d, i) => `
<div class="dt-dropdown__list-item" data-index="${i}">${d.label}</div>
`).join('')}
</div>
`;
}
}

View File

@ -1,11 +0,0 @@
.datatable {
--dt-border-color: #424242;
--dt-light-bg: #2e3538;
--dt-text-color: #dfe2e5;
--dt-text-light: #dfe2e5;
--dt-cell-bg: #1c1f20;
--dt-focus-border-width: 1px;
--dt-selection-highlight-color: var(--dt-light-bg);
--dt-toast-message-border: 1px solid var(--dt-border-color);
--dt-header-cell-bg: #262c2e;
}

View File

@ -11,7 +11,7 @@ export default class DataManager {
this.sortRows = nextTick(this.sortRows, this);
this.switchColumn = nextTick(this.switchColumn, this);
this.removeColumn = nextTick(this.removeColumn, this);
this.options.filterRows = nextTick(this.options.filterRows, this);
this.filterRows = nextTick(this.filterRows, this);
}
init(data, columns) {
@ -29,10 +29,10 @@ export default class DataManager {
this.rows = [];
this.prepareColumns();
this.validateData(this.data);
this.rows = this.prepareRows(this.data);
this.prepareRows();
this.prepareTreeRows();
this.prepareRowView();
this.prepareNumericColumns();
}
@ -134,7 +134,7 @@ export default class DataManager {
this.columns = this.columns.map((column, i) => {
const cellValue = row0[i].content;
if (!column.align && isNumeric(cellValue)) {
if (!column.align && cellValue && isNumeric(cellValue)) {
column.align = 'right';
}
@ -142,8 +142,10 @@ export default class DataManager {
});
}
prepareRows(data) {
return data.map((d, i) => {
prepareRows() {
this.validateData(this.data);
this.rows = this.data.map((d, i) => {
const index = this._getNextRowCount();
let row = [];
@ -192,7 +194,6 @@ export default class DataManager {
row.meta.isLeaf = !nextRow ||
notSet(nextRow.meta.indent) ||
nextRow.meta.indent <= row.meta.indent;
row.meta.isTreeNodeClose = false;
}
});
}
@ -242,9 +243,8 @@ export default class DataManager {
appendRows(rows) {
this.validateData(rows);
this.rows = this.rows.concat(this.prepareRows(rows));
this.prepareTreeRows();
this.prepareRowView();
this.rows.push(...this.prepareRows(rows));
}
sortRows(colIndex, sortOrder = 'none') {
@ -280,11 +280,8 @@ export default class DataManager {
this.rowViewOrder.sort((a, b) => {
const aIndex = a;
const bIndex = b;
let aContent = this.getCell(colIndex, a).content;
let bContent = this.getCell(colIndex, b).content;
aContent = aContent == null ? '' : aContent;
bContent = bContent == null ? '' : bContent;
const aContent = this.getCell(colIndex, a).content;
const bContent = this.getCell(colIndex, b).content;
if (sortOrder === 'none') {
return aIndex - bIndex;
@ -426,37 +423,32 @@ export default class DataManager {
return column;
}
filterRows(filters) {
return this.options.filterRows(this.rows, filters, this)
.then(result => {
if (!result) {
result = this.getAllRowIndices();
}
filterRows(keyword, colIndex) {
let rowsToHide = [];
let rowsToShow = [];
const cells = this.rows.map(row => row[colIndex]);
if (!result.then) {
result = Promise.resolve(result);
}
cells.forEach(cell => {
const hay = String(cell.content || '').toLowerCase();
const needle = (keyword || '').toLowerCase();
return result.then(rowsToShow => {
this._filteredRows = rowsToShow;
if (!needle || hay.includes(needle)) {
rowsToShow.push(cell.rowIndex);
} else {
rowsToHide.push(cell.rowIndex);
}
});
const rowsToHide = this.getAllRowIndices()
.filter(index => !rowsToShow.includes(index));
this._filteredRows = rowsToShow;
return {
rowsToHide,
rowsToShow
};
});
});
return {
rowsToHide,
rowsToShow
};
}
getFilteredRowIndices() {
return this._filteredRows || this.getAllRowIndices();
}
getAllRowIndices() {
return this.rows.map(row => row.meta.rowIndex);
return this._filteredRows || this.rows.map(row => row.meta.rowIndex);
}
getRowCount() {

View File

@ -6,18 +6,7 @@ import RowManager from './rowmanager';
import BodyRenderer from './body-renderer';
import Style from './style';
import Keyboard from './keyboard';
import TranslationManager from './translationmanager';
import getDefaultOptions from './defaults';
let defaultComponents = {
DataManager,
CellManager,
ColumnManager,
RowManager,
BodyRenderer,
Style,
Keyboard
};
import DEFAULT_OPTIONS from './defaults';
class DataTable {
constructor(wrapper, options) {
@ -32,48 +21,36 @@ class DataTable {
throw new Error('Invalid argument given for `wrapper`');
}
this.initializeTranslations(options);
this.setDefaultOptions();
this.buildOptions(options);
this.prepare();
this.initializeComponents();
this.style = new Style(this);
this.keyboard = new Keyboard(this.wrapper);
this.datamanager = new DataManager(this.options);
this.rowmanager = new RowManager(this);
this.columnmanager = new ColumnManager(this);
this.cellmanager = new CellManager(this);
this.bodyRenderer = new BodyRenderer(this);
if (this.options.data) {
this.refresh();
this.columnmanager.applyDefaultSortOrder();
}
}
initializeTranslations(options) {
this.language = options.language || 'en';
this.translationManager = new TranslationManager(this.language);
if (options.translations) {
this.translationManager.addTranslations(options.translations);
}
}
setDefaultOptions() {
this.DEFAULT_OPTIONS = getDefaultOptions(this);
}
buildOptions(options) {
this.options = this.options || {};
this.options = Object.assign(
{}, this.DEFAULT_OPTIONS,
{}, DEFAULT_OPTIONS,
this.options || {}, options
);
options.headerDropdown = options.headerDropdown || [];
this.options.headerDropdown = [
...this.DEFAULT_OPTIONS.headerDropdown,
...options.headerDropdown
];
this.options.headerDropdown
.push(...(options.headerDropdown || []));
// custom user events
this.events = Object.assign(
{}, this.DEFAULT_OPTIONS.events,
{}, DEFAULT_OPTIONS.events,
this.options.events || {},
options.events || {}
);
@ -85,34 +62,12 @@ class DataTable {
this.unfreeze();
}
initializeComponents() {
let components = Object.assign({}, defaultComponents, this.options.overrideComponents);
let {
Style,
Keyboard,
DataManager,
RowManager,
ColumnManager,
CellManager,
BodyRenderer
} = components;
this.style = new Style(this);
this.keyboard = new Keyboard(this.wrapper);
this.datamanager = new DataManager(this.options);
this.rowmanager = new RowManager(this);
this.columnmanager = new ColumnManager(this);
this.cellmanager = new CellManager(this);
this.bodyRenderer = new BodyRenderer(this);
}
prepareDom() {
this.wrapper.innerHTML = `
<div class="datatable" dir="${this.options.direction}">
<div class="datatable-content">
<div class="dt-header"></div>
<div class="dt-scrollable"></div>
<div class="dt-footer"></div>
<div class="datatable">
<table class="dt-header">
</table>
<div class="dt-scrollable">
</div>
<div class="dt-freeze">
<span class="dt-freeze__message">
@ -120,19 +75,16 @@ class DataTable {
</span>
</div>
<div class="dt-toast"></div>
<div class="dt-dropdown-container"></div>
<textarea class="dt-paste-target"></textarea>
</div>
`;
this.datatableWrapper = $('.datatable', this.wrapper);
this.header = $('.dt-header', this.wrapper);
this.footer = $('.dt-footer', this.wrapper);
this.bodyScrollable = $('.dt-scrollable', this.wrapper);
this.freezeContainer = $('.dt-freeze', this.wrapper);
this.toastMessage = $('.dt-toast', this.wrapper);
this.pasteTarget = $('.dt-paste-target', this.wrapper);
this.dropdownContainer = $('.dt-dropdown-container', this.wrapper);
}
refresh(data, columns) {
@ -144,7 +96,6 @@ class DataTable {
destroy() {
this.wrapper.innerHTML = '';
this.style.destroy();
this.fireEvent('onDestroy');
}
appendRows(rows) {
@ -238,22 +189,7 @@ class DataTable {
}
fireEvent(eventName, ...args) {
// fire internalEventHandlers if any
// and then user events
const handlers = [
...(this._internalEventHandlers[eventName] || []),
this.events[eventName]
].filter(Boolean);
for (let handler of handlers) {
handler.apply(this, args);
}
}
on(event, handler) {
this._internalEventHandlers = this._internalEventHandlers || {};
this._internalEventHandlers[event] = this._internalEventHandlers[event] || [];
this._internalEventHandlers[event].push(handler);
this.events[eventName].apply(this, args);
}
log() {
@ -261,10 +197,6 @@ class DataTable {
console.log.apply(console, arguments);
}
}
translate(str, args) {
return this.translationManager.translate(str, args);
}
}
DataTable.instances = 0;

View File

@ -1,73 +1,56 @@
import filterRows from './filterRows';
import icons from './icons';
export default function getDefaultOptions(instance) {
return {
columns: [],
data: [],
dropdownButton: icons.chevronDown,
headerDropdown: [
{
label: instance.translate('Sort Ascending'),
action: function (column) {
this.sortColumn(column.colIndex, 'asc');
}
},
{
label: instance.translate('Sort Descending'),
action: function (column) {
this.sortColumn(column.colIndex, 'desc');
}
},
{
label: instance.translate('Reset sorting'),
action: function (column) {
this.sortColumn(column.colIndex, 'none');
}
},
{
label: instance.translate('Remove column'),
action: function (column) {
this.removeColumn(column.colIndex);
}
export default {
columns: [],
data: [],
dropdownButton: '▼',
headerDropdown: [
{
label: 'Sort Ascending',
action: function (column) {
this.sortColumn(column.colIndex, 'asc');
}
],
events: {
onRemoveColumn(column) {},
onSwitchColumn(column1, column2) {},
onSortColumn(column) {},
onCheckRow(row) {},
onDestroy() {}
},
hooks: {
columnTotal: null
{
label: 'Sort Descending',
action: function (column) {
this.sortColumn(column.colIndex, 'desc');
}
},
sortIndicator: {
asc: '↑',
desc: '↓',
none: ''
{
label: 'Reset sorting',
action: function (column) {
this.sortColumn(column.colIndex, 'none');
}
},
overrideComponents: {
// ColumnManager: CustomColumnManager
},
filterRows: filterRows,
freezeMessage: '',
getEditor: null,
serialNoColumn: true,
checkboxColumn: false,
clusterize: true,
logs: false,
layout: 'fixed', // fixed, fluid, ratio
noDataMessage: instance.translate('No Data'),
cellHeight: 40,
minimumColumnWidth: 30,
inlineFilters: false,
treeView: false,
checkedRowStatus: true,
dynamicRowHeight: false,
pasteFromClipboard: false,
showTotalRow: false,
direction: 'ltr',
disableReorderColumn: false
};
{
label: 'Remove column',
action: function (column) {
this.removeColumn(column.colIndex);
}
}
],
events: {
onRemoveColumn(column) {},
onSwitchColumn(column1, column2) {},
onSortColumn(column) {},
onCheckRow(row) {}
},
sortIndicator: {
asc: '↑',
desc: '↓',
none: ''
},
freezeMessage: '',
getEditor: null,
serialNoColumn: true,
checkboxColumn: false,
clusterize: true,
logs: false,
layout: 'fixed', // fixed, fluid, ratio
noDataMessage: 'No Data',
cellHeight: null,
dynamicRowHeight: false,
inlineFilters: false,
treeView: false,
checkedRowStatus: true,
pasteFromClipboard: false
};

View File

@ -138,10 +138,6 @@ $.removeStyle = (elements, styleProps) => {
};
$.getStyle = (element, prop) => {
if (!prop) {
return getComputedStyle(element);
}
let val = getComputedStyle(element)[prop];
if (['width', 'height'].includes(prop)) {
@ -184,16 +180,7 @@ $.scrollTop = function scrollTop(element, pixels) {
});
};
$.scrollbarSize = function scrollbarSize() {
if (!$.scrollBarSizeValue) {
$.scrollBarSizeValue = getScrollBarSize();
}
return $.scrollBarSizeValue;
};
function getScrollBarSize() {
// assume scrollbar width and height would be the same
$.scrollbarWidth = function scrollbarWidth() {
// Create the measurement node
const scrollDiv = document.createElement('div');
$.style(scrollDiv, {
@ -212,24 +199,4 @@ function getScrollBarSize() {
document.body.removeChild(scrollDiv);
return scrollbarWidth;
}
$.hasVerticalOverflow = function (element) {
return element.scrollHeight > element.offsetHeight + 10;
};
$.hasHorizontalOverflow = function (element) {
return element.scrollWidth > element.offsetWidth + 10;
};
$.measureTextWidth = function (text) {
const div = document.createElement('div');
div.style.position = 'absolute';
div.style.visibility = 'hidden';
div.style.height = 'auto';
div.style.width = 'auto';
div.style.whiteSpace = 'nowrap';
div.innerText = text;
document.body.appendChild(div);
return div.clientWidth + 1;
};

View File

@ -1,209 +0,0 @@
import { isNumber, stripHTML } from './utils';
import CellManager from './cellmanager';
export default function filterRows(rows, filters, data) {
let filteredRowIndices = [];
if (Object.keys(filters).length === 0) {
return rows.map(row => row.meta.rowIndex);
}
for (let colIndex in filters) {
const keyword = filters[colIndex];
const filteredRows = filteredRowIndices.length ?
filteredRowIndices.map(i => rows[i]) :
rows;
const cells = filteredRows.map(row => row[colIndex]);
let filter = guessFilter(keyword);
let filterMethod = getFilterMethod(rows, data, filter);
if (filterMethod) {
filteredRowIndices = filterMethod(filter.text, cells);
} else {
filteredRowIndices = cells.map(cell => cell.rowIndex);
}
}
return filteredRowIndices;
};
function getFilterMethod(rows, allData, filter) {
const getFormattedValue = cell => {
let formatter = CellManager.getCustomCellFormatter(cell);
let rowData = rows[cell.rowIndex];
if (allData && allData.data && allData.data.length) {
rowData = allData.data[cell.rowIndex];
}
if (formatter && cell.content) {
cell.html = formatter(cell.content, rows[cell.rowIndex], cell.column, rowData, filter);
return stripHTML(cell.html);
}
return cell.content || '';
};
const stringCompareValue = cell =>
String(stripHTML(cell.html || '') || getFormattedValue(cell)).toLowerCase();
const numberCompareValue = cell => parseFloat(cell.content);
const getCompareValues = (cell, keyword) => {
if (cell.column.compareValue) {
const compareValues = cell.column.compareValue(cell, keyword);
if (compareValues && Array.isArray(compareValues)) return compareValues;
}
// check if it can be converted to number
const float = numberCompareValue(cell);
if (!isNaN(float)) {
return [float, keyword];
}
return [stringCompareValue(cell), keyword];
};
let filterMethodMap = {
contains(keyword, cells) {
return cells
.filter(cell => {
const needle = (keyword || '').toLowerCase();
return !needle ||
(cell.content || '').toLowerCase().includes(needle) ||
stringCompareValue(cell).includes(needle);
})
.map(cell => cell.rowIndex);
},
greaterThan(keyword, cells) {
return cells
.filter(cell => {
const [compareValue, keywordValue] = getCompareValues(cell, keyword);
return compareValue > keywordValue;
})
.map(cell => cell.rowIndex);
},
lessThan(keyword, cells) {
return cells
.filter(cell => {
const [compareValue, keywordValue] = getCompareValues(cell, keyword);
return compareValue < keywordValue;
})
.map(cell => cell.rowIndex);
},
equals(keyword, cells) {
return cells
.filter(cell => {
const value = parseFloat(cell.content);
return value === keyword;
})
.map(cell => cell.rowIndex);
},
notEquals(keyword, cells) {
return cells
.filter(cell => {
const value = parseFloat(cell.content);
return value !== keyword;
})
.map(cell => cell.rowIndex);
},
range(rangeValues, cells) {
return cells
.filter(cell => {
const values1 = getCompareValues(cell, rangeValues[0]);
const values2 = getCompareValues(cell, rangeValues[1]);
const value = values1[0];
return value >= values1[1] && value <= values2[1];
})
.map(cell => cell.rowIndex);
},
containsNumber(keyword, cells) {
return cells
.filter(cell => {
let number = parseFloat(keyword, 10);
let string = keyword;
let hayNumber = numberCompareValue(cell);
let hayString = stringCompareValue(cell);
return number === hayNumber || hayString.includes(string);
})
.map(cell => cell.rowIndex);
}
};
return filterMethodMap[filter.type];
}
function guessFilter(keyword = '') {
if (keyword.length === 0) return {};
let compareString = keyword;
if (['>', '<', '='].includes(compareString[0])) {
compareString = keyword.slice(1);
} else if (compareString.startsWith('!=')) {
compareString = keyword.slice(2);
}
if (keyword.startsWith('>')) {
if (compareString) {
return {
type: 'greaterThan',
text: compareString.trim()
};
}
}
if (keyword.startsWith('<')) {
if (compareString) {
return {
type: 'lessThan',
text: compareString.trim()
};
}
}
if (keyword.startsWith('=')) {
if (isNumber(compareString)) {
return {
type: 'equals',
text: Number(keyword.slice(1).trim())
};
}
}
if (isNumber(compareString)) {
return {
type: 'containsNumber',
text: compareString
};
}
if (keyword.startsWith('!=')) {
if (isNumber(compareString)) {
return {
type: 'notEquals',
text: Number(keyword.slice(2).trim())
};
}
}
if (keyword.split(':').length === 2 && keyword.split(':').every(v => isNumber(v.trim()))) {
compareString = keyword.split(':');
return {
type: 'range',
text: compareString.map(v => v.trim())
};
}
return {
type: 'contains',
text: compareString.toLowerCase()
};
}

View File

@ -1,10 +0,0 @@
/* eslint-disable max-len */
// Icons from https://feathericons.com/
let icons = {
chevronDown: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-down"><polyline points="6 9 12 15 18 9"></polyline></svg>',
chevronRight: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"><polyline points="9 18 15 12 9 6"></polyline></svg>'
};
export default icons;

View File

@ -3,9 +3,7 @@ import {
makeDataAttributeString,
nextTick,
ensureArray,
linkProperties,
uniq,
numberSortAsc
linkProperties
} from './utils';
export default class RowManager {
@ -16,8 +14,7 @@ export default class RowManager {
'fireEvent',
'wrapper',
'bodyScrollable',
'bodyRenderer',
'style'
'bodyRenderer'
]);
this.bindEvents();
@ -42,7 +39,7 @@ export default class RowManager {
// map of checked rows
this.checkMap = [];
$.on(this.wrapper, 'click', '.dt-cell--col-0 [type="checkbox"]', (e, $checkbox) => {
$.on(this.wrapper, 'click', '.dt-cell[data-col-index="0"] [type="checkbox"]', (e, $checkbox) => {
const $cell = $checkbox.closest('.dt-cell');
const {
rowIndex,
@ -67,7 +64,7 @@ export default class RowManager {
const _row = this.datamanager.updateRow(row, rowIndex);
_row.forEach(cell => {
this.cellmanager.refreshCell(cell, true);
this.cellmanager.refreshCell(cell);
});
}
@ -94,7 +91,8 @@ export default class RowManager {
checkRow(rowIndex, toggle) {
const value = toggle ? 1 : 0;
const selector = rowIndex => `.dt-cell--0-${rowIndex} [type="checkbox"]`;
const selector = rowIndex =>
`.dt-cell[data-row-index="${rowIndex}"][data-col-index="0"] [type="checkbox"]`;
// update internal map
this.checkMap[rowIndex] = value;
// set checkbox value explicitly
@ -113,25 +111,18 @@ export default class RowManager {
// update internal map
if (toggle) {
if (this.datamanager._filteredRows) {
this.datamanager._filteredRows.forEach(f => {
this.checkRow(f, toggle);
});
} else {
this.checkMap = Array.from(Array(this.getTotalRows())).map(c => value);
}
this.checkMap = Array.from(Array(this.getTotalRows())).map(c => value);
} else {
this.checkMap = [];
}
// set checkbox value
$.each('.dt-cell--col-0 [type="checkbox"]', this.bodyScrollable)
$.each('.dt-cell[data-col-index="0"] [type="checkbox"]', this.bodyScrollable)
.map(input => {
input.checked = toggle;
});
// highlight all
this.highlightAll(toggle);
this.showCheckStatus();
this.fireEvent('onCheckRow');
}
showCheckStatus() {
@ -139,10 +130,7 @@ export default class RowManager {
const checkedRows = this.getCheckedRows();
const count = checkedRows.length;
if (count > 0) {
let message = this.instance.translate('{count} rows selected', {
count: count
});
this.bodyRenderer.showToastMessage(message);
this.bodyRenderer.showToastMessage(`${count} row${count > 1 ? 's' : ''} selected`);
} else {
this.bodyRenderer.clearToastMessage();
}
@ -185,104 +173,42 @@ export default class RowManager {
}
}
hideRows(rowIndices) {
rowIndices = ensureArray(rowIndices);
rowIndices.map(rowIndex => {
const $tr = this.getRow$(rowIndex);
$tr.classList.add('dt-row--hide');
});
}
showRows(rowIndices) {
rowIndices = ensureArray(rowIndices);
const rows = rowIndices.map(rowIndex => this.datamanager.getRow(rowIndex));
this.bodyRenderer.renderRows(rows);
}
showAllRows() {
const rowIndices = this.datamanager.getAllRowIndices();
this.showRows(rowIndices);
}
getChildrenToShowForNode(rowIndex) {
const row = this.datamanager.getRow(rowIndex);
row.meta.isTreeNodeClose = false;
return this.datamanager.getImmediateChildren(rowIndex);
rowIndices.map(rowIndex => {
const $tr = this.getRow$(rowIndex);
$tr.classList.remove('dt-row--hide');
});
}
openSingleNode(rowIndex) {
const childrenToShow = this.getChildrenToShowForNode(rowIndex);
const visibleRowIndices = this.bodyRenderer.visibleRowIndices;
const rowsToShow = uniq([...childrenToShow, ...visibleRowIndices]).sort(numberSortAsc);
const rowsToShow = this.datamanager.getImmediateChildren(rowIndex);
this.showRows(rowsToShow);
}
getChildrenToHideForNode(rowIndex) {
const row = this.datamanager.getRow(rowIndex);
row.meta.isTreeNodeClose = true;
const rowsToHide = this.datamanager.getChildren(rowIndex);
rowsToHide.forEach(rowIndex => {
const row = this.datamanager.getRow(rowIndex);
if (!row.meta.isLeaf) {
row.meta.isTreeNodeClose = true;
}
});
return rowsToHide;
this.cellmanager.toggleTreeButton(rowIndex, true);
}
closeSingleNode(rowIndex) {
const rowsToHide = this.getChildrenToHideForNode(rowIndex);
const visibleRows = this.bodyRenderer.visibleRowIndices;
const rowsToShow = visibleRows
.filter(rowIndex => !rowsToHide.includes(rowIndex))
.sort(numberSortAsc);
this.showRows(rowsToShow);
}
expandAllNodes() {
let rows = this.datamanager.getRows();
let rootNodes = rows.filter(row => !row.meta.isLeaf);
const childrenToShow = rootNodes.map(row => this.getChildrenToShowForNode(row.meta.rowIndex)).flat();
const visibleRowIndices = this.bodyRenderer.visibleRowIndices;
const rowsToShow = uniq([...childrenToShow, ...visibleRowIndices]).sort(numberSortAsc);
this.showRows(rowsToShow);
}
collapseAllNodes() {
let rows = this.datamanager.getRows();
let rootNodes = rows.filter(row => row.meta.indent === 0);
const rowsToHide = rootNodes.map(row => this.getChildrenToHideForNode(row.meta.rowIndex)).flat();
const visibleRows = this.bodyRenderer.visibleRowIndices;
const rowsToShow = visibleRows
.filter(rowIndex => !rowsToHide.includes(rowIndex))
.sort(numberSortAsc);
this.showRows(rowsToShow);
}
setTreeDepth(depth) {
let rows = this.datamanager.getRows();
const rowsToOpen = rows.filter(row => row.meta.indent < depth);
const rowsToClose = rows.filter(row => row.meta.indent >= depth);
const rowsToHide = rowsToClose.filter(row => row.meta.indent > depth);
rowsToClose.forEach(row => {
if (!row.meta.isLeaf) {
row.meta.isTreeNodeClose = true;
const children = this.datamanager.getImmediateChildren(rowIndex);
children.forEach(childIndex => {
const row = this.datamanager.getRow(childIndex);
if (row.meta.isLeaf) {
// close
this.hideRows(childIndex);
this.cellmanager.toggleTreeButton(childIndex, false);
} else {
this.closeSingleNode(childIndex);
this.hideRows(childIndex);
}
});
rowsToOpen.forEach(row => {
if (!row.meta.isLeaf) {
row.meta.isTreeNodeClose = false;
}
});
const rowsToShow = rows
.filter(row => !rowsToHide.includes(row))
.map(row => row.meta.rowIndex)
.sort(numberSortAsc);
this.showRows(rowsToShow);
this.cellmanager.toggleTreeButton(rowIndex, false);
}
getRow$(rowIndex) {
@ -329,41 +255,31 @@ export default class RowManager {
getRowHTML(row, props) {
const dataAttr = makeDataAttributeString(props);
let rowIdentifier = props.rowIndex;
if (props.isFilter) {
row = row.map(cell => (Object.assign({}, cell, {
content: this.getFilterInput({
colIndex: cell.colIndex,
name: cell.name
colIndex: cell.colIndex
}),
isFilter: 1,
isHeader: undefined,
editable: false
})));
rowIdentifier = 'filter';
}
if (props.isHeader) {
rowIdentifier = 'header';
}
return `
<div class="dt-row dt-row-${rowIdentifier}" ${dataAttr}>
<tr class="dt-row" ${dataAttr}>
${row.map(cell => this.cellmanager.getCellHTML(cell)).join('')}
</div>
</tr>
`;
}
getFilterInput(props) {
let title = `title="Filter based on ${props.name || 'Index'}"`;
const dataAttr = makeDataAttributeString(props);
return `<input class="dt-filter dt-input" type="text" ${dataAttr} tabindex="1"
${props.colIndex === 0 ? 'disabled' : title} />`;
return `<input class="dt-filter dt-input" type="text" ${dataAttr} />`;
}
selector(rowIndex) {
return `.dt-row-${rowIndex}`;
return `.dt-row[data-row-index="${rowIndex}"]`;
}
}

View File

@ -1,308 +1,259 @@
:root {
--dt-border-color: #d1d8dd;
--dt-primary-color: rgb(82, 146, 247);
--dt-light-bg: #f5f7fa;
--dt-light-red: #FD8B8B;
--dt-light-yellow: #fffce7;
--dt-orange: rgb(255, 160, 10);
--dt-text-color: #000000;
--dt-text-light: #dfe2e5;
--dt-spacer-1: 0.25rem;
--dt-spacer-2: 0.5rem;
--dt-spacer-3: 1rem;
--dt-border-radius: 3px;
--dt-cell-bg: #fff;
--dt-focus-border-width: 2px;
--dt-selection-highlight-color: var(--dt-light-yellow);
--dt-toast-message-border: none;
--dt-header-cell-bg: var(--dt-cell-bg);
--border-color: #d1d8dd;
--primary-color: rgb(82, 146, 247);
--light-bg: #f5f7fa;
--light-red: #FD8B8B;
--light-yellow: #fffce7;
--orange: rgb(255, 160, 10);
--text-color: #000000;
--text-light: #dfe2e5;
--spacer-1: 0.25rem;
--spacer-2: 0.5rem;
--spacer-3: 1rem;
--border-radius: 3px;
--cell-bg: #fff;
}
.datatable {
*, *::after, *::before {
box-sizing: border-box;
}
box-sizing: border-box;
}
}
.datatable {
position: relative;
overflow: hidden;
.dt-cell--col-0{
border-left: 1px solid var(--dt-border-color);
}
position: relative;
overflow: auto;
}
.dt-header{
border-bottom: 2px solid var(--dt-border-color);
.dt-header {
border-collapse: collapse;
border-bottom: 1px solid var(--border-color);
position: absolute;
top: 0;
left: 0;
background-color: var(--cell-bg);
}
.datatable-content{
.dt-header{
display: flex;
}
.dt-body {
border-collapse: collapse;
}
.dt-scrollable {
height: 40vw;
max-height: 40vw;
overflow: auto;
border-bottom: 1px solid var(--border-color);
&--highlight-all {
background-color: var(--dt-selection-highlight-color);
}
&--highlight-all {
background-color: var(--light-yellow);
}
&__no-data {
text-align: center;
padding: var(--dt-spacer-3);
border-left: 1px solid var(--dt-border-color);
border-right: 1px solid var(--dt-border-color);
}
&__no-data {
text-align: center;
padding: var(--spacer-3);
border-left: 1px solid var(--border-color);
border-right: 1px solid var(--border-color);
}
}
.dt-row {
display: flex;
&--highlight {
background-color: var(--light-yellow);
}
&--highlight .dt-cell {
background-color: var(--dt-selection-highlight-color);
}
&--unhighlight {
background-color: var(--cell-bg);
}
&--unhighlight .dt-cell {
background-color: var(--dt-cell-bg);
}
&--hide {
display: none;
}
&:last-child:not(.dt-row-filter) {
border-bottom: 1px solid var(--dt-border-color);
}
&--hide {
display: none;
}
}
.dt-cell {
border: 1px solid var(--dt-border-color);
border-bottom: none;
border-left: none;
position: relative;
outline: none;
padding: 0;
background-color: var(--dt-cell-bg);
color: var(--dt-text-color);
/*
Fix for firefox and Edge
https://stackoverflow.com/a/16337203
firefox paints td background over border
*/
background-clip: padding-box;
user-select: none;
border: 1px solid var(--border-color);
position: relative;
outline: none;
padding: 0;
&__content {
padding: var(--dt-spacer-2);
border: var(--dt-focus-border-width) solid transparent;
height: 100%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
&__content {
padding: var(--spacer-2);
border: 2px solid transparent;
height: 100%;
user-select: none;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
&__edit {
display: none;
padding: var(--dt-spacer-2);
background-color: var(--dt-cell-bg);
border: var(--dt-focus-border-width) solid var(--dt-orange);
z-index: 1;
height: 100%;
}
&__edit {
display: none;
padding: var(--spacer-2);
background-color: var(--cell-bg);
border: 2px solid var(--orange);
z-index: 1;
height: 100%;
}
&__resize-handle {
opacity: 0;
position: absolute;
right: -3px;
top: 0;
width: 5px;
height: 100%;
cursor: col-resize;
z-index: 1;
}
&__resize-handle {
opacity: 0;
position: absolute;
right: -3px;
top: 0;
width: 5px;
height: 100%;
cursor: col-resize;
z-index: 1;
}
&--editing &__content {
display: none;
}
&--editing &__content {
display: none;
}
&--editing &__edit {
display: block;
}
&--editing &__edit {
display: block;
}
&--focus &__content {
border-color: var(--dt-primary-color);
}
&--focus &__content {
border-color: var(--primary-color);
}
&--highlight {
background-color: var(--dt-light-bg);
}
&--highlight {
background-color: var(--light-bg);
}
&--dragging {
background-color: var(--dt-light-bg);
}
&--dragging {
background-color: var(--light-bg);
}
&--header {
background-color: var(--dt-header-cell-bg);
}
&--header &__content {
padding-right: var(--spacer-3);
font-weight: bold;
}
&--header:last-child {
border-right: 1px solid var(--dt-border-color);
}
&--header:hover .dt-dropdown__toggle {
opacity: 1;
}
&--header &__content {
padding-right: var(--dt-spacer-3);
font-weight: bold;
}
&--header:hover .dt-dropdown__toggle {
opacity: 1;
}
&--tree-close {
.icon-open {
display: none;
}
.icon-close {
display: flex;
}
}
&:last-child {
border-right: 1px solid var(--dt-border-color);
}
}
.datatable[dir=rtl] .dt-cell__resize-handle {
right: unset;
left: -3px;
}
.icon-open, .icon-close {
width: 16px;
height: 16px;
}
.icon-open {
display: flex;
}
.icon-close {
display: none;
&--tree-close {
.dt-tree-node__toggle:before {
content: '►';
}
}
}
.dt-dropdown {
position: absolute;
right: 10px;
display: inline-flex;
vertical-align: top;
text-align: left;
font-weight: normal;
cursor: pointer;
position: absolute;
right: 10px;
display: inline-flex;
vertical-align: top;
text-align: left;
font-weight: normal;
cursor: pointer;
&__toggle {
opacity: 0;
background-color: var(--dt-header-cell-bg);
}
&__toggle {
opacity: 0;
}
&__list {
position: fixed;
min-width: 8rem;
z-index: 1;
cursor: pointer;
background-color: var(--dt-cell-bg);
border-radius: var(--dt-border-radius);
padding: var(--dt-spacer-2) 0;
box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1);
}
&__list {
display: none;
&__list-item {
padding: var(--dt-spacer-2) var(--dt-spacer-3);
position: absolute;
min-width: 8rem;
top: 100%;
right: 0;
z-index: 1;
background-color: var(--cell-bg);
border-radius: var(--border-radius);
padding: var(--spacer-2) 0;
box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1);
}
&:hover {
background-color: var(--dt-light-bg);
}
}
&__list-item {
padding: var(--spacer-2) var(--spacer-3);
&--active &__list {
display: block;
}
&:hover {
background-color: var(--light-bg);
}
}
&--active &__list {
display: block;
}
}
.dt-tree-node {
display: flex;
align-items: center;
position: relative;
display: inline-block;
position: relative;
&__toggle {
display: inline-block;
cursor: pointer;
margin-right: 0.2rem;
}
&__toggle {
display: inline-block;
position: absolute;
font-size: 10px;
padding: 0 4px;
cursor: pointer;
}
&__toggle:before {
content: '▼';
}
}
.dt-toast {
position: absolute;
bottom: var(--dt-spacer-3);
left: 50%;
transform: translateX(-50%);
position: absolute;
bottom: var(--spacer-3);
left: 50%;
transform: translateX(-50%);
&__message {
display: inline-block;
background-color: rgba(0, 0, 0, 0.8);
color: var(--dt-text-light);
border-radius: var(--dt-border-radius);
padding: var(--dt-spacer-2) var(--dt-spacer-3);
border: var(--dt-toast-message-border);
}
&__message {
display: inline-block;
background-color: rgba(0, 0, 0, 0.8);
color: var(--text-light);
border-radius: var(--border-radius);
padding: var(--spacer-2) var(--spacer-3);
}
}
.dt-input {
outline: none;
width: 100%;
border: none;
overflow: visible;
font-family: inherit;
font-size: inherit;
line-height: inherit;
background-color: inherit;
color: inherit;
margin: 0;
padding: 0;
outline: none;
width: 100%;
border: none;
overflow: visible;
font-family: inherit;
font-size: inherit;
line-height: inherit;
margin: 0;
padding: 0;
}
.dt-freeze {
display: flex;
justify-content: center;
align-content: center;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: var(--dt-light-bg);
opacity: 0.5;
font-size: 2em;
display: flex;
justify-content: center;
align-content: center;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: var(--light-bg);
opacity: 0.5;
font-size: 2em;
&__message {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
&__message {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
}
.dt-paste-target {
position: fixed;
left: -999em;
position: fixed;
left: -999em;
}
body.dt-resize {
cursor: col-resize;
cursor: col-resize;
}
.dt-sticky-col {
position: sticky;
z-index: 1;
left: 0;
}

View File

@ -11,8 +11,8 @@ export default class Style {
linkProperties(this, this.instance, [
'options', 'datamanager', 'columnmanager',
'header', 'footer', 'bodyScrollable', 'datatableWrapper',
'getColumn', 'bodyRenderer'
'header', 'bodyScrollable', 'datatableWrapper',
'getColumn'
]);
this.scopeClass = 'dt-instance-' + instance.constructor.instances;
@ -23,7 +23,6 @@ export default class Style {
this.styleEl = styleEl;
this.bindResizeWindow();
this.bindScrollHeader();
}
get stylesheet() {
@ -31,165 +30,78 @@ export default class Style {
}
bindResizeWindow() {
this.onWindowResize = this.onWindowResize.bind(this);
this.onWindowResize = throttle(this.onWindowResize, 300);
if (this.options.layout === 'fluid') {
$.on(window, 'resize', this.onWindowResize);
$.on(window, 'resize', throttle(() => {
this.distributeRemainingWidth();
this.refreshColumnWidth();
this.compensateScrollbarWidth();
this.setBodyStyle();
}, 300));
}
}
bindScrollHeader() {
this._settingHeaderPosition = false;
$.on(this.bodyScrollable, 'scroll', (e) => {
if (this._settingHeaderPosition) return;
this._settingHeaderPosition = true;
requestAnimationFrame(() => {
const scrollLeft = e.target.scrollLeft;
// Move non-sticky header and footer cells normally
const nonStickyHeaderCells = this.header.querySelectorAll('.dt-cell:not(.dt-sticky-col)');
const nonStickyFooterCells = this.footer.querySelectorAll('.dt-cell:not(.dt-sticky-col)');
nonStickyHeaderCells.forEach(cell => {
$.style(cell, { transform: `translateX(${-scrollLeft}px)` });
});
nonStickyFooterCells.forEach(cell => {
$.style(cell, { transform: `translateX(${-scrollLeft}px)` });
});
const stickyHeaderCells = this.header.querySelectorAll(
'.dt-cell.dt-sticky-col:not(.dt-cell-serial-no):not(.dt-cell-checkbox)'
);
stickyHeaderCells.forEach((headerCell) => {
const colIndex = headerCell.getAttribute('data-col-index');
const bodyCell = this.bodyScrollable.querySelector(`.dt-cell[data-col-index="${colIndex}"]`);
const colLeft = parseFloat(headerCell.style.left) || 0; // get left position of the column
// Find corresponding footer cell
const footerCell = this.footer.querySelector(`.dt-cell[data-col-index="${colIndex}"]`);
if (~~(bodyCell.offsetLeft - scrollLeft) > colLeft) {
headerCell.style.transform = `translateX(${-scrollLeft - 1}px)`;
if (footerCell) {
footerCell.style.transform = `translateX(${scrollLeft ? -scrollLeft - 1 : 0}px)`;
}
} else {
headerCell.style.transform = `translateX(${colLeft - headerCell.offsetLeft}px)`;
if (footerCell) footerCell.style.transform = `translateX(${colLeft - footerCell.offsetLeft}px)`;
}
});
this._settingHeaderPosition = false;
});
});
}
onWindowResize() {
this.distributeRemainingWidth();
this.refreshColumnWidth();
this.setBodyStyle();
}
destroy() {
this.styleEl.remove();
$.off(window, 'resize', this.onWindowResize);
}
setStyle(selector, styleObject) {
if (selector.includes(',')) {
selector.split(',')
.map(s => s.trim())
.forEach(selector => {
this.setStyle(selector, styleObject);
});
return;
}
selector = selector.trim();
if (!selector) return;
this._styleRulesMap = this._styleRulesMap || {};
const prefixedSelector = this._getPrefixedSelector(selector);
if (this._styleRulesMap[prefixedSelector]) {
this.removeStyle(selector);
// merge with old styleobject
styleObject = Object.assign({}, this._styleRulesMap[prefixedSelector], styleObject);
}
const styleString = this._getRuleString(styleObject);
const ruleString = `${prefixedSelector} { ${styleString} }`;
this._styleRulesMap[prefixedSelector] = styleObject;
this.stylesheet.insertRule(ruleString);
}
removeStyle(selector) {
if (selector.includes(',')) {
selector.split(',')
.map(s => s.trim())
.forEach(selector => {
this.removeStyle(selector);
});
return;
}
selector = selector.trim();
if (!selector) return;
// find and remove
const prefixedSelector = this._getPrefixedSelector(selector);
const index = Array.from(this.stylesheet.cssRules)
.findIndex(rule => rule.selectorText === prefixedSelector);
if (index === -1) return;
this.stylesheet.deleteRule(index);
}
_getPrefixedSelector(selector) {
return `.${this.scopeClass} ${selector}`;
}
_getRuleString(styleObject) {
return Object.keys(styleObject)
setStyle(selector, styleMap, index = -1) {
const styles = Object.keys(styleMap)
.map(prop => {
let dashed = prop;
if (!prop.includes('-')) {
dashed = camelCaseToDash(prop);
prop = camelCaseToDash(prop);
}
return `${dashed}:${styleObject[prop]};`;
return `${prop}:${styleMap[prop]};`;
})
.join('');
let prefixedSelector = selector
.split(',')
.map(r => `.${this.scopeClass} ${r}`)
.join(',');
let ruleString = `${prefixedSelector} { ${styles} }`;
if (!this.stylesheet) return;
let _index = this.stylesheet.cssRules.length;
if (index !== -1) {
this.stylesheet.deleteRule(index);
_index = index;
}
this.stylesheet.insertRule(ruleString, _index);
return _index; // eslint-disable-line
}
setDimensions() {
this.setCellHeight();
this.setHeaderStyle();
this.setupMinWidth();
this.setupNaturalColumnWidth();
this.setupColumnWidth();
this.distributeRemainingWidth();
this.setColumnStyle();
this.compensateScrollbarWidth();
this.setDefaultCellHeight();
this.setBodyStyle();
}
setCellHeight() {
this.setStyle('.dt-cell', {
height: this.options.cellHeight + 'px'
setHeaderStyle() {
if (this.options.layout === 'fluid') {
// setting width as 0 will ensure that the
// header doesn't take the available space
$.style(this.header, {
width: 0
});
}
$.style(this.header, {
margin: 0
});
}
setupMinWidth() {
$.each('.dt-cell--header', this.header).map(col => {
$.each('.dt-cell[data-is-header]', this.header).map(col => {
const { colIndex } = $.data(col);
const column = this.getColumn(colIndex);
@ -204,19 +116,8 @@ export default class Style {
setupNaturalColumnWidth() {
if (!$('.dt-row')) return;
$.each('.dt-row-header .dt-cell', this.header).map($headerCell => {
const { colIndex } = $.data($headerCell);
const column = this.datamanager.getColumn(colIndex);
let width = $.style($('.dt-cell__content', $headerCell), 'width');
if (typeof width === 'number' && width >= this.options.minimumColumnWidth) {
column.naturalWidth = width;
} else {
column.naturalWidth = this.options.minimumColumnWidth;
}
});
// set initial width as naturally calculated by table's first row
$.each('.dt-row-0 .dt-cell', this.bodyScrollable).map($cell => {
$.each('.dt-row[data-row-index="0"] .dt-cell', this.bodyScrollable).map($cell => {
const {
colIndex
} = $.data($cell);
@ -224,11 +125,12 @@ export default class Style {
let naturalWidth = $.style($('.dt-cell__content', $cell), 'width');
if (typeof naturalWidth === 'number' && naturalWidth >= column.naturalWidth) {
column.naturalWidth = naturalWidth;
} else {
column.naturalWidth = column.naturalWidth;
if (column.id === '_rowIndex') {
naturalWidth = this.getRowIndexColumnWidth(naturalWidth);
column.width = naturalWidth;
}
column.naturalWidth = naturalWidth;
});
}
@ -272,32 +174,29 @@ export default class Style {
if (!column.width) {
column.width = column.naturalWidth;
}
if (column.id === '_rowIndex') {
column.width = this.getRowIndexColumnWidth();
}
if (column.width < this.options.minimumColumnWidth) {
column.width = this.options.minimumColumnWidth;
if (column.width < column.minWidth) {
column.width = column.minWidth;
}
});
}
}
compensateScrollbarWidth() {
requestAnimationFrame(() => {
const scrollbarWidth = $.scrollbarWidth();
const lastCol = this.datamanager.getColumn(-1);
const width = lastCol.width - scrollbarWidth;
this.columnmanager.setColumnWidth(lastCol.colIndex, width);
});
}
distributeRemainingWidth() {
if (this.options.layout !== 'fluid') return;
const wrapperWidth = $.style(this.instance.datatableWrapper, 'width');
let firstRow = $('.dt-row', this.bodyScrollable);
let firstRowWidth = wrapperWidth;
if (!firstRow) {
let headerRow = $('.dt-row', this.instance.header);
let cellWidths = Array.from(headerRow.children)
.map(cell => cell.offsetWidth);
firstRowWidth = cellWidths.reduce((sum, a) => sum + a, 0);
} else {
firstRowWidth = $.style(firstRow, 'width');
}
const headerWidth = $.style(this.header, 'width');
const resizableColumns = this.datamanager.getColumns().filter(col => col.resizable);
const deltaWidth = (wrapperWidth - firstRowWidth) / resizableColumns.length;
const deltaWidth = (wrapperWidth - headerWidth) / resizableColumns.length;
resizableColumns.map(col => {
const width = $.style(this.getColumnHeaderElement(col.colIndex), 'width');
@ -309,25 +208,40 @@ export default class Style {
});
}
setDefaultCellHeight() {
if (this.options.dynamicRowHeight) return;
if (this.__cellHeightSet) return;
const $firstCell = $('.dt-cell[data-is-header]', this.instance.header);
if (!$firstCell) return;
const height = this.options.cellHeight || $.style($firstCell, 'height');
if (height) {
this.setCellHeight(height);
this.__cellHeightSet = true;
}
}
setCellHeight(height) {
this.setStyle('.dt-cell__content, .dt-cell__edit', {
height: height + 'px'
});
}
setColumnStyle() {
// align columns
this.datamanager.getColumns()
.map(column => {
// alignment
if (!column.align) {
column.align = 'left';
if (['left', 'center', 'right'].includes(column.align)) {
this.setStyle(`.dt-cell--col-${column.colIndex}`, {
'text-align': column.align
});
}
if (!['left', 'center', 'right'].includes(column.align)) {
column.align = 'left';
}
this.setStyle(`.dt-cell--col-${column.colIndex}`, {
'text-align': column.align
});
// width
this.columnmanager.setColumnHeaderWidth(column.colIndex);
this.columnmanager.setColumnWidth(column.colIndex);
});
this.setBodyStyle();
}
refreshColumnWidth() {
@ -339,67 +253,48 @@ export default class Style {
}
setBodyStyle() {
const bodyWidth = $.style(this.datatableWrapper, 'width');
const firstRow = $('.dt-row', this.bodyScrollable);
if (!firstRow) return;
const rowWidth = $.style(firstRow, 'width');
requestAnimationFrame(() => {
const width = $.style(this.header, 'width');
let width = bodyWidth > rowWidth ? rowWidth + 10 : bodyWidth;
$.style(this.bodyScrollable, {
width: width + 'px'
});
$.style(this.bodyScrollable, {
width: width + 'px'
});
// remove the body height, so that it resets to it's original
$.removeStyle(this.bodyScrollable, 'height');
const $body = $('.dt-body', this.bodyScrollable);
// when there are less rows than the container
// adapt the container height
let bodyHeight = $.getStyle(this.bodyScrollable, 'height');
const scrollHeight = (this.bodyRenderer.hyperlist || {})._scrollHeight || Infinity;
const hasHorizontalOverflow = $.hasHorizontalOverflow(this.bodyScrollable);
let height;
if (scrollHeight < bodyHeight) {
height = scrollHeight;
// account for scrollbar size when
// there is horizontal overflow
if (hasHorizontalOverflow) {
height += $.scrollbarSize();
if ($body) {
$.style($body, {
height: '0px'
});
}
$.style(this.bodyScrollable, {
height: height + 'px'
marginTop: $.style(this.header, 'height') + 'px'
});
}
const verticalOverflow = this.bodyScrollable.scrollHeight - this.bodyScrollable.offsetHeight;
if (verticalOverflow < $.scrollbarSize()) {
// if verticalOverflow is less than scrollbar size
// then most likely scrollbar is causing the scroll
// which is not needed
$.style(this.bodyScrollable, {
overflowY: 'hidden'
$.style($('table', this.bodyScrollable), {
margin: 0,
width: '100%'
});
}
if (this.options.layout === 'fluid') {
$.style(this.bodyScrollable, {
overflowX: 'hidden'
});
}
});
}
getColumnHeaderElement(colIndex) {
colIndex = +colIndex;
if (colIndex < 0) return null;
return $(`.dt-cell--col-${colIndex}`, this.header);
return $(`.dt-cell[data-col-index="${colIndex}"]`, this.header);
}
getRowIndexColumnWidth() {
getRowIndexColumnWidth(baseWidth) {
this._rowIndexColumnWidthMap = this._rowIndexColumnWidthMap || {};
const rowCount = this.datamanager.getRowCount();
const padding = 22;
return $.measureTextWidth(rowCount + '') + padding;
const digits = (rowCount + '').length;
if (!this._rowIndexColumnWidthMap[digits]) {
// add 8px for each unit
this._rowIndexColumnWidthMap[digits] = baseWidth + ((digits - 1) * 8);
}
return this._rowIndexColumnWidthMap[digits];
}
}

View File

@ -1,30 +0,0 @@
import { format } from './utils';
import getTranslations from './translations';
export default class TranslationManager {
constructor(language) {
this.language = language;
this.translations = getTranslations();
}
addTranslations(translations) {
this.translations = Object.assign(this.translations, translations);
}
translate(sourceText, args) {
let translation = (this.translations[this.language] &&
this.translations[this.language][sourceText]) || sourceText;
if (typeof translation === 'object') {
translation = args && args.count ?
this.getPluralizedTranslation(translation, args.count) :
sourceText;
}
return format(translation, args || {});
}
getPluralizedTranslation(translations, count) {
return translations[count] || translations['default'];
}
};

View File

@ -1,15 +0,0 @@
{
"Sort Ascending": "Aufsteigend sortieren",
"Sort Descending": "Absteigend sortieren",
"Reset sorting": "Sortierung zurücksetzen",
"Remove column": "Spalte entfernen",
"No Data": "Keine Daten",
"{count} cells copied": {
"1": "{count} Zelle kopiert",
"default": "{count} Zellen kopiert"
},
"{count} rows selected": {
"1": "{count} Zeile ausgewählt",
"default": "{count} Zeilen ausgewählt"
}
}

View File

@ -1,15 +0,0 @@
{
"Sort Ascending": "Sort Ascending",
"Sort Descending": "Sort Descending",
"Reset sorting": "Reset sorting",
"Remove column": "Remove column",
"No Data": "No Data",
"{count} cells copied": {
"1": "{count} cell copied",
"default": "{count} cells copied"
},
"{count} rows selected": {
"1": "{count} row selected",
"default": "{count} rows selected"
}
}

View File

@ -1,15 +0,0 @@
{
"Sort Ascending": "Trier par ordre croissant",
"Sort Descending": "Trier par ordre décroissant",
"Reset sorting": "Réinitialiser le tri",
"Remove column": "Supprimer colonne",
"No Data": "Pas de données",
"{count} cells copied": {
"1": "{count} cellule copiée",
"default": "{count} cellules copiées"
},
"{count} rows selected": {
"1": "{count} ligne sélectionnée",
"default": "{count} lignes sélectionnées"
}
}

View File

@ -1,13 +0,0 @@
import en from './en.json';
import de from './de.json';
import fr from './fr.json';
import it from './it.json';
export default function getTranslations() {
return {
en,
de,
fr,
it,
};
};

View File

@ -1,15 +0,0 @@
{
"Sort Ascending": "Ordinamento ascendente",
"Sort Descending": "Ordinamento decrescente",
"Reset sorting": "Azzeramento ordinamento",
"Remove column": "Rimuovi colonna",
"No Data": "Nessun dato",
"{count} cells copied": {
"1": "Copiato {count} cella",
"default": "{count} celle copiate"
},
"{count} rows selected": {
"1": "{count} linea selezionata",
"default": "{count} linee selezionate"
}
}

View File

@ -1,6 +1,5 @@
import _throttle from 'lodash/throttle';
import _debounce from 'lodash/debounce';
import _uniq from 'lodash/uniq';
export function camelCaseToDash(str) {
return str.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`);
@ -126,42 +125,3 @@ export function ensureArray(val) {
}
return val;
}
export function uniq(arr) {
return _uniq(arr);
}
export function numberSortAsc(a, b) {
return a - b;
};
export function stripHTML(html) {
return html.replace(/<[^>]*>/g, '');
};
export function format(str, args) {
if (!str) return str;
Object.keys(args).forEach(arg => {
let regex = new RegExp(`{(${arg})}`, 'g');
str = str.replace(regex, args[arg]);
});
return str;
};
export function escapeHTML(txt) {
if (!txt) return '';
let escapeHtmlMapping = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;',
'`': '&#x60;',
'=': '&#x3D;',
};
return String(txt).replace(/[&<>"'`=/]/g, (char) => escapeHtmlMapping[char] || char);
};

View File

@ -0,0 +1,27 @@
<template>
<datatable-example v-on:scriptsLoaded="initDatatable">
<div id="example-basic"></div>
</datatable-example>
</template>
<script>
import DatatableExample from "./datatable-example";
import { getSampleData } from "./datatableData";
export default {
name: "DatatableBasic",
components: {
DatatableExample
},
methods: {
initDatatable() {
const { data } = getSampleData();
let columns = ['Name', {name: 'Position', width: 195}, 'Office', 'Extn.', 'Start Date', 'Salary'];
const datatable = new DataTable("#example-basic", {
columns,
data,
inlineFilters: true
});
}
}
};
</script>

View File

@ -0,0 +1,34 @@
<template>
<datatable-example v-on:scriptsLoaded="initDatatable">
<div id="example-cell"></div>
</datatable-example>
</template>
<script>
import DatatableExample from "./datatable-example";
import { getSampleData } from "./datatableData";
export default {
name: "DatatableCell",
components: {
DatatableExample
},
methods: {
initDatatable() {
const { data } = getSampleData();
let columns = [
"Name",
{ name: "Position", width: 185 },
{ name: "Office" },
"Extn.",
"Start Date",
{ name: "Salary", format: value => "$" + value }
];
const datatable = new DataTable("#example-cell", {
columns,
data
});
}
}
};
</script>

View File

@ -0,0 +1,56 @@
<template>
<div>
<slot></slot>
</div>
</template>
<script>
import { getSampleData } from "./datatableData";
export default {
name: "DatatableExample",
props: ["type"],
mounted() {
this.loadScriptsAndStyle().then(() => {
this.$emit('scriptsLoaded');
});
},
methods: {
initDatatable() {
const { columns, data } = getSampleData();
const datatable = new DataTable("#example-" + this.type, {
columns,
data
});
},
loadScriptsAndStyle() {
if (!window.scriptsLoadedPromise) {
window.scriptsLoadedPromise = Promise.all([
this.loadScript("//unpkg.com/sortablejs@1.7.0/Sortable.min.js"),
this.loadScript("//unpkg.com/clusterize.js@0.18.1/clusterize.min.js"),
this.loadScript("//unpkg.com/frappe-datatable@0.0.8/dist/frappe-datatable.min.js"),
this.loadStyle("//unpkg.com/frappe-datatable@0.0.8/dist/frappe-datatable.min.css")
]);
}
return window.scriptsLoadedPromise;
},
loadScript(src) {
return new Promise(resolve => {
const script = document.createElement("script");
script.src = src;
script.async = false;
script.type = 'text/javascript';
script.onload = resolve;
document.body.appendChild(script);
});
},
loadStyle(src) {
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = src;
document.head.appendChild(link);
}
}
};
</script>

View File

@ -0,0 +1,683 @@
function getSampleData(multiplier) {
let columns = ['Name', {name: 'Position', width: 195}, 'Office', 'Extn.', 'Start Date', 'Salary'];
let data = [
['Tiger Nixon', 'System Architect', 'Edinburgh', 5421, '2011/04/25', '320,800'],
['Garrett Winters', 'Accountant', 'Tokyo', 8422, '2011/07/25', '170,750'],
['Ashton Cox', 'Junior Technical Author', 'San Francisco', 1562, '2009/01/12', '86,000'],
['Cedric Kelly', 'Senior Javascript Developer', 'Edinburgh', 6224, '2012/03/29', '433,060'],
['Airi Satou', 'Accountant', 'Tokyo', 5407, '2008/11/28', '162,700'],
['Brielle Williamson', 'Integration Specialist', 'New York', 4804, '2012/12/02', '372,000'],
['Herrod Chandler', 'Sales Assistant', 'San Francisco', 9608, '2012/08/06', '137,500'],
['Rhona Davidson', 'Integration Specialist', 'Tokyo', 6200, '2010/10/14', '327,900'],
['Colleen Hurst', 'Javascript Developer', 'San Francisco', 2360, '2009/09/15', '205,500'],
['Sonya Frost', 'Software Engineer', 'Edinburgh', 1667, '2008/12/13', '103,600'],
['Jena Gaines', 'Office Manager', 'London', 3814, '2008/12/19', '90,560'],
['Quinn Flynn', 'Support Lead', 'Edinburgh', 9497, '2013/03/03', '342,000'],
['Charde Marshall', 'Regional Director', 'San Francisco', 6741, '2008/10/16', '470,600'],
['Haley Kennedy', 'Senior Marketing Designer', 'London', 3597, '2012/12/18', '313,500'],
['Tatyana Fitzpatrick', 'Regional Director', 'London', 1965, '2010/03/17', '385,750'],
['Michael Silva', 'Marketing Designer', 'London', 1581, '2012/11/27', '198,500'],
['Paul Byrd', 'Chief Financial Officer (CFO)', 'New York', 3059, '2010/06/09', '725,000'],
['Gloria Little', 'Systems Administrator', 'New York', 1721, '2009/04/10', '237,500'],
['Bradley Greer', 'Software Engineer', 'London', 2558, '2012/10/13', '132,000'],
['Dai Rios', 'Personnel Lead', 'Edinburgh', 2290, '2012/09/26', '217,500'],
['Jenette Caldwell', 'Development Lead', 'New York', 1937, '2011/09/03', '345,000'],
['Yuri Berry', 'Chief Marketing Officer (CMO)', 'New York', 6154, '2009/06/25', '675,000'],
['Caesar Vance', 'Pre-Sales Support', 'New York', 8330, '2011/12/12', '106,450'],
['Doris Wilder', 'Sales Assistant', 'Sidney', 3023, '2010/09/20', '85,600'],
['Angelica Ramos', 'Chief Executive Officer (CEO)', 'London', 5797, '2009/10/09', '1,200,000'],
['Gavin Joyce', 'Developer', 'Edinburgh', 8822, '2010/12/22', '92,575'],
['Jennifer Chang', 'Regional Director', 'Singapore', 9239, '2010/11/14', '357,650'],
['Brenden Wagner', 'Software Engineer', 'San Francisco', 1314, '2011/06/07', '206,850'],
['Fiona Green', 'Chief Operating Officer (COO)', 'San Francisco', 2947, '2010/03/11', '850,000'],
['Shou Itou', 'Regional Marketing', 'Tokyo', 8899, '2011/08/14', '163,000'],
['Michelle House', 'Integration Specialist', 'Sidney', 2769, '2011/06/02', '95,400'],
['Suki Burks', 'Developer', 'London', 6832, '2009/10/22', '114,500'],
['Prescott Bartlett', 'Technical Author', 'London', 3606, '2011/05/07', '145,000'],
['Gavin Cortez', 'Team Leader', 'San Francisco', 2860, '2008/10/26', '235,500'],
['Martena Mccray', 'Post-Sales support', 'Edinburgh', 8240, '2011/03/09', '324,050'],
['Unity Butler', 'Marketing Designer', 'San Francisco', 5384, '2009/12/09', '85,675'],
['Howard Hatfield', 'Office Manager', 'San Francisco', 7031, '2008/12/16', '164,500'],
['Hope Fuentes', 'Secretary', 'San Francisco', 6318, '2010/02/12', '109,850'],
['Vivian Harrell', 'Financial Controller', 'San Francisco', 9422, '2009/02/14', '452,500'],
['Timothy Mooney', 'Office Manager', 'London', 7580, '2008/12/11', '136,200'],
['Jackson Bradshaw', 'Director', 'New York', 1042, '2008/09/26', '645,750'],
['Olivia Liang', 'Support Engineer', 'Singapore', 2120, '2011/02/03', '234,500'],
['Bruno Nash', 'Software Engineer', 'London', 6222, '2011/05/03', '163,500'],
['Sakura Yamamoto', 'Support Engineer', 'Tokyo', 9383, '2009/08/19', '139,575'],
['Thor Walton', 'Developer', 'New York', 8327, '2013/08/11', '98,540'],
['Finn Camacho', 'Support Engineer', 'San Francisco', 2927, '2009/07/07', '87,500'],
['Serge Baldwin', 'Data Coordinator', 'Singapore', 8352, '2012/04/09', '138,575'],
['Zenaida Frank', 'Software Engineer', 'New York', 7439, '2010/01/04', '125,250'],
['Zorita Serrano', 'Software Engineer', 'San Francisco', 4389, '2012/06/01', '115,000'],
['Jennifer Acosta', 'Junior Javascript Developer', 'Edinburgh', 3431, '2013/02/01', '75,650'],
['Cara Stevens', 'Sales Assistant', 'New York', 3990, '2011/12/06', '145,600'],
['Hermione Butler', 'Regional Director', 'London', 1016, '2011/03/21', '356,250'],
['Lael Greer', 'Systems Administrator', 'London', 6733, '2009/02/27', '103,500'],
['Jonas Alexander', 'Developer', 'San Francisco', 8196, '2010/07/14', '86,500'],
['Shad Decker', 'Regional Director', 'Edinburgh', 6373, '2008/11/13', '183,000'],
['Michael Bruce', 'Javascript Developer', 'Singapore', 5384, '2011/06/27', '183,000'],
['Donna Snider', 'Customer Support', 'New York', 4226, '2011/01/25', '112,000']
];
if (multiplier) {
Array.from(new Array(multiplier - 1)).forEach(d => {
data = data.concat(data);
});
}
return {
columns,
data
};
}
function getTreeData() {
return {
columns: [{
'id': 'account',
'content': 'Account'
}, {
'id': 'opening_debit',
'content': 'Opening (Dr)'
}, {
'id': 'opening_credit',
'content': 'Opening (Cr)'
},
// {
// 'id': 'debit',
// 'content': 'Debit'
// },
// {
// 'id': 'credit',
// 'content': 'Credit'
// },
{
'id': 'closing_debit',
'content': 'Closing (Dr)'
}, {
'id': 'closing_credit',
'content': 'Closing (Cr)'
}, {
'id': 'currency',
'content': 'Currency',
'hidden': 1
}],
data: [{
'account_name': 'Application of Funds (Assets)',
'account': 'Application of Funds (Assets)',
'parent_account': null,
'indent': 0,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 12023729.54,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 12023729.54,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Current Assets',
'account': 'Current Assets',
'parent_account': 'Application of Funds (Assets)',
'indent': 1,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 13960649.54,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 13960649.54,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Accounts Receivable',
'account': 'Accounts Receivable',
'parent_account': 'Current Assets',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 742790.474,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 742790.474,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Debtors',
'account': 'Debtors',
'parent_account': 'Accounts Receivable',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 742790.474,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 742790.474,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Bank Accounts',
'account': 'Bank Accounts',
'parent_account': 'Current Assets',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 280676.822,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 280676.822,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Corporation Bank',
'account': 'Corporation Bank',
'parent_account': 'Bank Accounts',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 290676.822,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 290676.822,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'HDFC Bank',
'account': 'HDFC Bank',
'parent_account': 'Bank Accounts',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 10000.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 10000.0,
'has_value': true
}, {
'account_name': 'Cash In Hand',
'account': 'Cash In Hand',
'parent_account': 'Current Assets',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 229904.494,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 229904.494,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Cash',
'account': 'Cash',
'parent_account': 'Cash In Hand',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 229904.494,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 229904.494,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Stock Assets',
'account': 'Stock Assets',
'parent_account': 'Current Assets',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 12707277.75,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 12707277.75,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'All Warehouses',
'account': 'All Warehouses',
'parent_account': 'Stock Assets',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 12707277.75,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 12707277.75,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Finished Goods',
'account': 'Finished Goods',
'parent_account': 'All Warehouses',
'indent': 4,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 87320.3,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 87320.3,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Retail Stores',
'account': 'Retail Stores',
'parent_account': 'All Warehouses',
'indent': 4,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 4540590.0,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 4540590.0,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Bandra Store',
'account': 'Bandra Store',
'parent_account': 'Retail Stores',
'indent': 5,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 3246800.0,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 3246800.0,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Central Warehouse',
'account': 'Central Warehouse',
'parent_account': 'Retail Stores',
'indent': 5,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 1236790.0,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 1236790.0,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Lower Parel Store',
'account': 'Lower Parel Store',
'parent_account': 'Retail Stores',
'indent': 5,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 57000.0,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 57000.0,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Stores',
'account': 'Stores',
'parent_account': 'All Warehouses',
'indent': 4,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 8016525.27,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 8016525.27,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Work In Progress',
'account': 'Work In Progress',
'parent_account': 'All Warehouses',
'indent': 4,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 62842.18,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 62842.18,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Fixed Assets',
'account': 'Fixed Assets',
'parent_account': 'Application of Funds (Assets)',
'indent': 1,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 19920.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 19920.0,
'has_value': true
}, {
'account_name': 'Electronic Equipments',
'account': 'Electronic Equipments',
'parent_account': 'Fixed Assets',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 80.0,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 80.0,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'Furnitures and Fixtures',
'account': 'Furnitures and Fixtures',
'parent_account': 'Fixed Assets',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 20000.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 20000.0,
'has_value': true
}, {
'account_name': 'Temporary Accounts',
'account': 'Temporary Accounts',
'parent_account': 'Application of Funds (Assets)',
'indent': 1,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 1917000.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 1917000.0,
'has_value': true
}, {
'account_name': 'Temporary Opening',
'account': 'Temporary Opening',
'parent_account': 'Temporary Accounts',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 1917000.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 1917000.0,
'has_value': true
}, {
'account_name': 'Source of Funds (Liabilities)',
'account': 'Source of Funds (Liabilities)',
'parent_account': null,
'indent': 0,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 2371628.002,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 2371628.002,
'has_value': true
}, {
'account_name': 'Current Liabilities',
'account': 'Current Liabilities',
'parent_account': 'Source of Funds (Liabilities)',
'indent': 1,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 2371628.002,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 2371628.002,
'has_value': true
}, {
'account_name': 'Accounts Payable',
'account': 'Accounts Payable',
'parent_account': 'Current Liabilities',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 368311.85,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 368311.85,
'has_value': true
}, {
'account_name': 'Creditors',
'account': 'Creditors',
'parent_account': 'Accounts Payable',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 194871.85,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 194871.85,
'has_value': true
}, {
'account_name': 'Salary Payable',
'account': 'Salary Payable',
'parent_account': 'Accounts Payable',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 173440.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 173440.0,
'has_value': true
}, {
'account_name': 'Duties and Taxes',
'account': 'Duties and Taxes',
'parent_account': 'Current Liabilities',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 150146.822,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 150146.822,
'has_value': true
}, {
'account_name': 'CGST',
'account': 'CGST',
'parent_account': 'Duties and Taxes',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 51479.591,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 51479.591,
'has_value': true
}, {
'account_name': 'IGST',
'account': 'IGST',
'parent_account': 'Duties and Taxes',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 1944.0,
'opening_credit': 0.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 1944.0,
'closing_credit': 0.0,
'has_value': true
}, {
'account_name': 'SGST',
'account': 'SGST',
'parent_account': 'Duties and Taxes',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 97711.231,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 97711.231,
'has_value': true
}, {
'account_name': 'UGST',
'account': 'UGST',
'parent_account': 'Duties and Taxes',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 2900.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 2900.0,
'has_value': true
}, {
'account_name': 'Stock Liabilities',
'account': 'Stock Liabilities',
'parent_account': 'Current Liabilities',
'indent': 2,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 1853169.33,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 1853169.33,
'has_value': true
}, {
'account_name': 'Stock Received But Not Billed',
'account': 'Stock Received But Not Billed',
'parent_account': 'Stock Liabilities',
'indent': 3,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 1853169.33,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 1853169.33,
'has_value': true
}, {
'account_name': 'Equity',
'account': 'Equity',
'parent_account': null,
'indent': 0,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 10000.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 10000.0,
'has_value': true
}, {
'account_name': 'Capital Stock',
'account': 'Capital Stock',
'parent_account': 'Equity',
'indent': 1,
'from_date': '2018-04-01',
'to_date': '2019-03-31',
'currency': 'INR',
'opening_debit': 0.0,
'opening_credit': 10000.0,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 0.0,
'closing_credit': 10000.0,
'has_value': true
}, {}, {
'account': 'Total',
'account_name': 'Total',
'warn_if_negative': true,
'opening_debit': 32260956.43,
'opening_credit': 22618854.891999997,
'debit': 0.0,
'credit': 0.0,
'closing_debit': 32260956.43,
'closing_credit': 22618854.891999997,
'parent_account': null,
'indent': 0,
'has_value': true,
'currency': 'INR'
}]
};
}
export {
getSampleData,
getTreeData
}

View File

@ -0,0 +1,18 @@
module.exports = {
title: 'Frappe DataTable',
description: 'A simple, modern and interactive datatable for the web',
dest: './static/docs/datatable',
base: '/docs/datatable/',
themeConfig: {
sidebar: [
'/getting-started',
'/download',
'/configuration',
'/events'
],
nav: [
{ text: 'Documentation', link: '/getting-started'},
{ text: 'GitHub', link: 'https://github.com/frappe/datatable'},
]
}
}

View File

@ -0,0 +1 @@
// @import "../../docs.styl"

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="340.42303" height="330.00024" viewBox="0 0 90.070259 87.312561" version="1.1" id="svg3970" inkscape:version="0.92.2 5c3e80d, 2017-08-06">
<defs id="defs3964"/>
<metadata id="metadata3967">
</metadata>
<g inkscape:label="Layer 1" id="layer1" transform="translate(-7.1255851,-173.21277)">
<rect transform="scale(-1,1)" ry="13.229167" rx="13.229167" y="173.21277" x="-94.438156" height="87.312546" width="87.312553" id="rect2004" style="opacity:1;fill:#edfdff;fill-opacity:1;stroke:none;stroke-width:1.74624979;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;"/>
<path style="opacity:1;fill:#c3f1ff;fill-opacity:1;stroke:none;stroke-width:6.59999943;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="M 0 96.25 L 0 151.25 L 77.5 151.25 C 80.27 151.25 82.5 149.02 82.5 146.25 L 82.5 101.25 C 82.5 98.48 80.27 96.25 77.5 96.25 L 0 96.25 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="rect2006"/>
<path style="opacity:1;fill:#c3f1ff;fill-opacity:1;stroke:none;stroke-width:6.5999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="M 50 0 C 22.299998 0 1.4210855e-14 22.299998 0 50 L 0 54.5 L 78 54.5 C 80.77 54.5 83 52.27 83 49.5 L 83 4.5 C 83 2.503655 81.832377 0.80274423 80.148438 0 L 50 0 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="rect2008"/>
<rect style="opacity:1;fill:#71caff;fill-opacity:1;stroke:none;stroke-width:1.74624979;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" id="rect2010" width="57.195782" height="14.552094" x="40.000061" y="198.74506" ry="1.3229167" rx="1.3229166"/>
<path style="opacity:1;fill:#c3f1ff;fill-opacity:1;stroke:none;stroke-width:6.59999943;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="M 0 193 L 0 248 L 77.5 248 C 80.27 248 82.5 245.77 82.5 243 L 82.5 198 C 82.5 195.23 80.27 193 77.5 193 L 0 193 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="rect2012"/>
<path style="fill:#87e34c;fill-opacity:1;stroke:none;stroke-width:1.00000012px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" clip-path="none" d="M 0 219.61328 L 0 284.29688 C 0 309.61626 27.643317 330 61.980469 330 L 268.01953 330 C 300.54576 330 327.04905 311.70603 329.75586 288.25586 L 330 248.5 C 256.7254 233.20714 83.19117 220.5514 0 219.61328 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="path2020"/>
<path style="opacity:1;fill:#c3f1ff;fill-opacity:1;stroke:none;stroke-width:6.59999943;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="M 129.25 193.5 C 126.48 193.5 124.25 195.73 124.25 198.5 L 124.25 243.5 C 124.25 246.27 126.48 248.5 129.25 248.5 L 330 248.5 L 330 193.5 L 129.25 193.5 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="rect2014"/>
<path style="opacity:1;fill:#c3f1ff;fill-opacity:1;stroke:none;stroke-width:6.5999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="M 127.10156 0 C 125.41762 0.80274423 124.25 2.503655 124.25 4.5 L 124.25 49.5 C 124.25 52.27 126.48 54.5 129.25 54.5 L 330 54.5 L 330 50 C 330 22.299998 307.7 0 280 0 L 127.10156 0 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="rect2016"/>
<path style="opacity:1;fill:#59b81c;fill-opacity:1;stroke:none;stroke-width:6.59999943;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="M 129.25 290.5 C 126.48 290.5 124.25 292.73 124.25 295.5 L 124.25 330 L 280 330 C 304.09518 330 324.09664 313.12363 328.89648 290.5 L 129.25 290.5 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="rect1135"/>
<path style="opacity:1;fill:#59b81c;fill-opacity:1;stroke:none;stroke-width:6.59999943;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="M 0.94921875 289.75 C 5.4614968 312.74994 25.639123 330 50 330 L 82.5 330 L 82.5 294.75 C 82.5 291.98 80.27 289.75 77.5 289.75 L 0.94921875 289.75 z " transform="matrix(0.26458332,0,0,0.26458332,7.1255851,173.21277)" id="rect1139"/>
<path style="opacity:1;fill:#59b81c;fill-opacity:1;stroke:none;stroke-width:1.74624979;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;" clip-path="none" d="m 7.1257773,231.31877 v 7.51065 H 27.630987 c 0.732896,0 1.322917,-0.59002 1.322917,-1.32292 v -5.36505 C 20.620295,231.67818 13.007809,231.3851 7.1257773,231.31877 Z" id="path1264"/>
<path style="fill:#59b81c;fill-opacity:1;stroke:none;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" clip-path="none" d="m 40.000259,232.82824 v 4.81056 c 0,0.73289 0.59002,1.32291 1.322916,1.32291 h 53.115108 c -11.982795,-2.50088 -34.095004,-4.73297 -54.438024,-6.13347 z" id="path1163"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100%"
height="100%"
viewBox="0 0 260 260"
version="1.1"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"
id="svg16"
sodipodi:docname="frappe-bird-grey.svg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"><metadata
id="metadata22"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs20" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1029"
id="namedview18"
showgrid="false"
inkscape:snap-global="false"
inkscape:zoom="2.5673415"
inkscape:cx="125.36812"
inkscape:cy="132.66533"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="svg16" /><path
inkscape:connector-curvature="0"
id="path846"
d="m 39.426993,41.26578 c -0.08308,-0.002 -0.162537,0.01476 -0.244177,0.01847 -0.195406,-0.01104 -0.394663,-0.0078 -0.595581,0.02219 -0.671494,0.09826 -1.359798,0.439289 -1.985268,1.097637 L 36.166705,42.984362 3.911539,86.00785 c -1.4521873,1.95837 -0.089029,5.089411 2.840468,4.758942 l 35.051779,-4.999463 7.486826,52.499391 c 0.143332,1.06941 0.708175,1.87792 1.45651,2.37853 0.06099,0.57446 0.300326,1.15825 0.786491,1.67605 l 54.221237,55.16042 c 0.35241,0.34946 0.76163,0.57974 1.18925,0.71967 l 43.2449,43.9932 c 2.19797,2.06517 5.73881,0.59111 5.73827,-2.44537 l 0.72154,-88.30898 100.76861,-99.226182 c 2.03273,-1.933848 0.52846,-5.096585 -1.98911,-5.01476 L 146.21842,46.315471 c -1.15721,-0.0078 -1.82288,0.589677 -2.08644,0.84183 L 70.489255,119.67376 95.234723,86.666413 c 1.320352,-1.808803 0.561745,-3.846193 -0.6872,-4.787579 L 41.349464,41.92492 C 40.706305,41.485816 40.049657,41.2839 39.427179,41.266357 Z"
style="fill:#29344a;fill-opacity:1;stroke:none;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,22 @@
## DataManager
All the methods listed here are available on the `datatable.datamanager` property.
Example
```javascript
const datatable = new DataTable(container, options);
datatable.datamanager.getRows();
```
#### sortRows
Sorts rows according the values in the column identified by `colIndex` and order `sortOrder`.
```javascript
sortRows(colIndex: Number, sortOrder: 'asc | desc | none'): void
// Usage
datatable.datamanager.sortRows(data, columns);
```
---

125
vuepress/api/datatable.md Normal file
View File

@ -0,0 +1,125 @@
## Datatable
All the methods listed here are available on the `datatable` instance created using the `DataTable` constructor.
Example
```javascript
const datatable = new DataTable(container, options);
datatable.refresh(data);
```
#### refresh
Refreshes the datatable with new `data` and `column`
```javascript
refresh(data: Array, columns: Array): void
// Usage
datatable.refresh(data, columns);
```
---
#### setDimensions
Refreshes the datatable layout.
```javascript
setDimensions(): void
// Usage
datatable.setDimensions();
```
---
#### appendRows
Append new rows to the datatable
```javascript
appendRows(rows: Array): void
// Usage
datatable.appendRows(rows);
```
---
#### showToastMessage
Show a toast message at the bottom center of the datatable. You can hide the message by providing `hideAfter` value which is in seconds.
```javascript
showToastMessage(message: String, hideAfter: Number): void
// Usage
datatable.showToastMessage('Hey', 2);
```
---
#### clearToastMessage
Clear any toast message in the datatable.
```javascript
clearToastMessage(): void
// Usage
datatable.clearToastMessage();
```
---
#### getColumns
Get all the columns
```javascript
getColumns(): Array
// Usage
datatable.getColumns();
```
---
#### getRows
Get all the rows
```javascript
getRows(): Array
// Usage
datatable.getRows();
```
---
#### freeze
Show an overlay on the datatable which displays the `freezeMessage` value provided in `options`. You cannot interact with the datatable when it is frozen.
```javascript
freeze(): void
// Usage
datatable.freeze();
```
---
#### unfreeze
Remove the freeze overlay.
```javascript
unfreeze(): void
// Usage
datatable.unfreeze();
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1014 KiB

357
vuepress/configuration.md Normal file
View File

@ -0,0 +1,357 @@
---
sidebarDepth: 2
---
# Configuration
Frappe DataTable has a lot of customizable features, this section is dedicated to enabling / disabling existing functionality.
## Container
The first parameter required by the `DataTable` constructor is the container element. You can pass in a CSS Selector or a DOM Object.
```javascript
const datatable = new DataTable('#datatable', options);
// or
const container = document.querySelector('#datatable');
const datatable = new DataTable(container, options);
```
## Options
The second parameter required by the `DataTable` constructor is the options object. The minimum required configuration is to pass `column` and `data` values.
```javascript
const options = {
columns: ['Name', 'Position', 'Salary'],
data: [
['John Doe', 'DevOps Engineer', '$12300'],
['Mary Jane', 'UX Design', '$14000'],
]
}
const datatable = new DataTable(container, options);
```
The following options are configurable:
### columns
- Type: `Array`
- Default: `[]`
- Required
The minimum required value is to pass a list of column header names
```js
const options = {
columns: ['Name', 'Position', 'Country']
}
```
You can also pass an Array of Object Descriptors for each column header
```js
const options = {
columns: [
{
name: 'Name',
id: 'name',
editable: false,
resizable: false,
sortable: false,
focusable: false,
dropdown: false,
width: 32,
format: (value) => {
return value.bold();
}
},
...
]
}
```
#### column / name
- Type: `String`
- Required
#### column / id
- Type: `String`
- Default: Slugified version of `name`
#### column / editable
- Type: `Boolean`
- Default: `true`
If this is set to false, the entire column will be read-only
#### column / resizable
- Type: `Boolean`
- Default: `true`
If this is set to false, the column width will be fixed and is not resizable using mouse drag
#### column / sortable
- Type: `Boolean`
- Default: `true`
If this is set to false, the column is not sortable using column actions
#### column / focusable
- Type: `Boolean`
- Default: `true`
If this is set to false, the cells in the column is not focusable on click
#### column / dropdown
- Type: `Boolean`
- Default: `true`
Show / Hide the dropdown action button on column header
#### column / width
- Type: `Number`
If the `layout` option is set to
- `fluid`, then this value doesn't have any effect
- `fixed`, then this value is set in pixels
- `ratio`, then this value works similar to `flex` property in CSS. So, if column A has `width: 1` and column B has `width: 2`, then column B will occupy twice as much width as column A
#### column / format
- Type: `Function`
- Default: `null`
Custom Formatter function that is passed the value of the cell. You can process the value and return any valid HTML to customize how the cell is rendered.
---
### data
- Type: `Array`
- Default: `[]`
- Required
The minimum required value is to pass an array of array of cell values. The order of cell values should match with the order of columns passed
```js
const options = {
columns: ['Name', 'Position', 'Country'],
data: [
['Faris', 'Software Developer', 'India'],
['Kenneth', 'Marketing Engineer', 'India']
]
}
```
You can also pass an Object Descriptor for each cell value
```js
const options = {
columns: ['Name', 'Position', 'Country'],
data: [
[
{
content: 'Faris',
// disable editing just for this cell
editable: false,
// format function takes precedence over
// the format function defined in column header
format: (value) => {
return value.fontcolor('blue');
}
},
...
],
...
]
}
```
### getEditor
- Type: `Function`
- Default: `null`
Customize the editor behaviour.
---
### serialNoColumn
- Type: `Boolean`
- Default: `true`
Whether to show serial number as the first column in datatable.
---
### checkboxColumn
- Type: `Boolean`
- Default: `false`
Whether to show checkbox column in the datatable.
---
### clusterize
- Type: `Boolean`
- Default: `true`
Whether to use clusterize to render the data.
> If you don't want to show large number of rows. Then you can turn this off. In that case you don't need to load the `clusterize.js` lib
---
### layout
- Type: `String`
- Default: `fixed`
- Options: `fixed | fluid | ratio`
This option controls how width of each `column` is calculated in the DataTable.
#### fixed
The column width is calculated based on the content of the first row of the table. This layout can result in horizontal scroll.
#### fluid
The column width is adjusted based on the width of container. So the columns will be resized if the window is resized. This layout won't result in horizontal scroll. You will always see all the columns.
#### ratio
This layout works similar to the `flex` property in CSS. When column A has `width` set as `1` and column B as `2`, then column B's width will be twice as much as column A.
---
### noDataMessage
- Type: `String`
- Default: `No Data`
The message shown when there are no rows to show in the DataTable.
---
### dynamicRowHeight
- Type: `Boolean`
- Default: `false`
The height of the row will be set according to the content of the cell with the maximum height in that row.
---
### cellHeight
- Type: `Number`
- Default: `null`
Set the height of each cell explicitly.
> If this value is set, `dynamicRowHeight` won't have any effect.
---
### inlineFilters
- Type: `Boolean`
- Default: `false`
Whether to enable the inline filter feature. If the value is `true`, then you can activate the filter row by pressing `Ctrl/Cmd + F` after clicking on any cell in the DataTable.
---
### treeView
- Type: `Boolean`
- Default: `false`
Whether to render rows in a tree structure. For this to work, you must pass the `indent` value for each row.
Example
```javascript
const data = [
{
'Department': 'IT Department',
'No of People': '10',
'indent': 0,
},
{
'Department': 'Javascript Team',
'No of People': '5',
'indent': 1,
},
{
'Department': 'Vue.js Team',
'No of People': '3',
'indent': 2,
},
{
'Department': 'React Team',
'No of People': '2',
'indent': 2,
},
{
'Department': 'Design Team',
'No of People': '5',
'indent': 1,
},
]
const datatable = new DataTable('#datatable', {
columns: ['Department', 'No of People'],
data: data
});
```
---
### checkedRowStatus
- Type: `Boolean`
- Default: `true`
Whether to show the number of rows checked in a toast message.
---
### pasteFromClipboard
- _Experimental_
- Type: `Boolean`
- Default: `false`
Whether to allow the user to paste copied content into selected cell(s).
---
### dropdownButton
- Type: `String`
- Default: `▼`
String to render as the dropdown button. You can pass a span with an icon class.
Example
```javascript
{
dropdownButton: '<span class="fa fa-chevron-down"></span>'
}
```
### headerDropdown
- Type: `Array`
When you hover over any column, you see the dropdown button which is used to perform certain actions for that column.
This option allows you to pass an array of custom buttons custom actions defined by you.
```javascript
options = {
headerDropdown: [
{
label: 'Copy column contents',
action: function (column) {
// code to copy the column contents
}
},
}
```
### events
- Type: `Object`
The events options is described in detailed in the [next section](events.md).

29
vuepress/download.md Normal file
View File

@ -0,0 +1,29 @@
# Download
Frappe DataTable can be consumed in several different forms.
## CDN
Load it directly from the unpkg CDN.
```html
<script src="https://unpkg.com/frappe-datatable@0.0.5/dist/frappe-datatable.min.js"></script>
```
## Package managers
Include it directly in your build workflow. You can find the compiled JS/CSS files in the `dist/` directory.
```bash
yarn add frappe-datatable
# or
npm install frappe-datatable
```
## Source
The complete source code is always available on Github.
```bash
git clone https://github.com/frappe/datatable
```

46
vuepress/events.md Normal file
View File

@ -0,0 +1,46 @@
# Events
Hook custom actions on certain events occurred during the lifecycle of DataTable. You can define a function to be called on these events using the `events` key in `options`.
Example
```javascript
const options = {
events: {
onRemoveColumn(column) {
// your code
}
}
}
```
## onRemoveColumn
- params: `column`
Called when a column is removed using the dropdown option or API.
---
## onSwitchColumn
- params: `column1`, `column2`
Called when a column position is switched using the drag behaviour.
---
## onSortColumn
- params: `column`
Called when a column's sorting is changed using the dropdown or API.
---
## onCheckRow
- params: `row`
Called when a row is checked using the checkbox or API.

View File

@ -0,0 +1,34 @@
---
sidebarDepth: 0
---
# Getting Started
The easiest way to get started with Frappe DataTable is using this [JSFiddle Demo](https://jsfiddle.net/f4qe6phc/7/). Or you can copy the following template into a new index.html file.
## Example
```html
<!-- include styles -->
<link href="https://unpkg.com/frappe-datatable@0.0.5/dist/frappe-datatable.min.css">
<!-- create the container element -->
<div id="datatable"></div>
<!-- include the dependencies -->
<script src="https://unpkg.com/sortablejs@1.7.0/Sortable.min.js"></script>
<script src="https://unpkg.com/clusterize.js@0.18.0/clusterize.min.js"></script>
<!-- include the lib -->
<script src="https://unpkg.com/frappe-datatable@0.0.5/dist/frappe-datatable.min.js"></script>
<!-- initialize DataTable -->
<script>
const datatable = new DataTable('#datatable', {
columns: ['Name', 'Position', 'Salary'],
data: [
['Faris', 'Software Developer', '$1200'],
['Manas', 'Software Engineer', '$1400'],
]
});
</script>
```

89
vuepress/readme.md Normal file
View File

@ -0,0 +1,89 @@
---
home: true
---
<datatable-basic />
## Installation
```bash
# Install using yarn
$ yarn add frappe-datatable
# or NPM
$ npm install frappe-datatable
```
## Usage
```javascript
import DataTable from 'frappe-datatable';
// or add
// <script src="frappe-datatable.js" ></script>
// in your html
let datatable = new DataTable({
columns: ['Name', 'Position', ...],
data: [
['Tiger Nixon', 'System Architect', ...],
['Garrett Winters', 'Accountant', ...],
...
]
});
```
## Cell Features
* Custom Formatters
* Inline Editing
* Mouse Selection
* Copy Cells
* Keyboard Navigation
* Custom Cell Editor
<img src="./assets/datatable-cell-demo.gif" />
## Column Features
* Reorder Columns
* Sort by Column
* Remove / Hide Column
* Custom Actions
* Resize Column
* Flexible Layout
<img src="./assets/datatable-column-demo.gif" />
## Row Features
* Row Selection
* Tree Structured Rows
* Inline Filters
* Large Number of Rows
* Dynamic Row Height
<div class="footer">
Made with ❤️ by Frappe
</div>
<style>
.theme-container.no-sidebar .home {
max-width: 740px;
}
.datatable {
font-size: 14px;
}
tr:nth-child(2n) {
background-color: transparent;
}
.content.custom > div {
/* height: 2000px; */
}
.home .hero .description {
max-width: 30rem;
font-size: 2rem;
margin-bottom: 4rem;
}
</style>

9058
yarn.lock

File diff suppressed because it is too large Load Diff