diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index 691efdf..447c1dd 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -1,46 +1,46 @@
name: CI
-
on:
push:
- branches:
- - main
- paths:
- - 'src/sortable.ts'
- - '.github/workflows/CI.yml'
+ branches: [main]
+ paths-ignore:
+ - '**.md'
+ - 'docs/**'
pull_request:
- branches:
- - main
- paths:
- - 'src/sortable.ts'
- - '.github/workflows/CI.yml'
+ branches: [main]
+ paths-ignore:
+ - '**.md'
+ - 'docs/**'
jobs:
- run-linters-and-tests:
- name: Run linters
+ test:
+ name: Playwright Tests
+ timeout-minutes: 30
runs-on: ubuntu-latest
- strategy:
- matrix:
- node-version: [20]
steps:
- - uses: actions/checkout@v3
- - uses: pnpm/action-setup@v2
- with:
- version: latest
- - name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v3
+ - uses: actions/checkout@v4
+
+ - uses: pnpm/action-setup@v4
+
+ - uses: actions/setup-node@v4
with:
- node-version: ${{ matrix.node-version }}
+ node-version: 22
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- - name: Run linters
- run: npm run lint
+ - name: Install Playwright Browsers
+ run: pnpm exec playwright install chromium --with-deps
- - name: Run tests
- run: npm run test
+ - name: Run Playwright tests
+ run: pnpm run test
- - name: Run tests with minified code
- run: npm run test:min
+ - uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: playwright-report
+ path: |
+ playwright-report/
+ test-results/
+ retention-days: 30
diff --git a/.gitignore b/.gitignore
index 7ec9f92..567566d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,26 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
node_modules
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
.DS_Store
-._*
\ No newline at end of file
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+test-results
+playwright-report
\ No newline at end of file
diff --git a/.prettierrc.js b/.prettierrc.cjs
similarity index 76%
rename from .prettierrc.js
rename to .prettierrc.cjs
index 24df7e8..6142589 100644
--- a/.prettierrc.js
+++ b/.prettierrc.cjs
@@ -1,7 +1,7 @@
module.exports = {
singleQuote: true,
semi: false,
- trailingComma: 'all',
+ trailingComma: "all",
tabWidth: 2,
printWidth: 120,
-}
+};
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c1de75d..46bfd47 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,22 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [4.0.0] - 2024-11-15
+
+### Breaking Changes
+
+- Built files are now located in the `/dist` directory
+- Update your references from:
+ - `sortable.min.js` to `dist/sortable.min.js`
+ - `sortable.a11y.min.js` to `dist/sortable.a11y.min.js`
+ - etc.
+
+### Added
+
+- `setTimeout` lets double-click "re-sort" the table only once
+- `sort-start` and `sort-end` events
+- `dist/standalone` folder where all files are inlined, in case you want the functions to be available in the global scope
+
## [3.2.3] - 2024-05-08
### Changed
@@ -138,10 +154,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- First release
-## Acknowledgments
-
-This CHANGELOG.md was generated with the assistance of [ChatGPT by OpenAI](https://www.openai.com/research/chatgpt).
-
+[4.0.0]: https://github.com/tofsjonas/sortable/releases/tag/4.0.0
[3.2.3]: https://github.com/tofsjonas/sortable/releases/tag/3.2.3
[3.2.2]: https://github.com/tofsjonas/sortable/releases/tag/3.2.2
[3.2.1]: https://github.com/tofsjonas/sortable/releases/tag/3.2.1
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
deleted file mode 100755
index b2e87d7..0000000
--- a/CODE_OF_CONDUCT.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# Contributor Covenant Code of Conduct
-
-## Our Pledge
-
-In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
-
-## Our Standards
-
-Examples of behavior that contributes to creating a positive environment include:
-
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery and unwelcome sexual attention or advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
-* Public or private harassment
-* Publishing others' private information, such as a physical or electronic address, without explicit permission
-* Other conduct which could reasonably be considered inappropriate in a professional setting
-
-## Our Responsibilities
-
-Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
-
-Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
-
-## Scope
-
-This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
-
-## Enforcement
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at jonas@earendel.se. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
-
-Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
-
-## Attribution
-
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
-
-[homepage]: http://contributor-covenant.org
-[version]: http://contributor-covenant.org/version/1/4/
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 89ad019..7714ba0 100755
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,5 +1,5 @@
+
# Contributing
-I am grateful for any and all contributions.
+I am grateful for any and all contributions. 😀
-If it's a minor thing I guess it's easier to open an issue, but if you prefer creating a fork, go ahead! :)
diff --git a/README.md b/README.md
index 885f17e..a419b18 100755
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
sortable
- a tiny, vanilla/plain JavaScript table sorter
-![GitHub Issues or Pull Requests](https://img.shields.io/github/issues/tofsjonas/sortable) ![NPM Version](https://img.shields.io/npm/v/sortable-tablesort) ![NPM Downloads](https://img.shields.io/npm/dw/sortable-tablesort) ![GitHub Repo stars](https://img.shields.io/github/stars/tofsjonas/sortable) [![jsdelivr](https://data.jsdelivr.com/v1/package/gh/tofsjonas/sortable/badge)](https://www.jsdelivr.com/package/gh/tofsjonas/sortable)
+[![GitHub Issues or Pull Requests](https://img.shields.io/github/issues/tofsjonas/sortable)](https://github.com/tofsjonas/sortable) [![NPM Version](https://img.shields.io/npm/v/sortable-tablesort)](https://www.npmjs.com/package/sortable-tablesort) [![NPM Downloads](https://img.shields.io/npm/dw/sortable-tablesort)](https://www.npmjs.com/package/sortable-tablesort) [![GitHub Repo stars](https://img.shields.io/github/stars/tofsjonas/sortable)](https://github.com/tofsjonas/sortable) [![jsdelivr](https://data.jsdelivr.com/v1/package/gh/tofsjonas/sortable/badge)](https://www.jsdelivr.com/package/gh/tofsjonas/sortable)
Makes any table with **class="sortable"**, er, sortable. The user can click on a table header and change the sorting of the table rows.
@@ -27,6 +27,7 @@ You can find a simple demo on
- [...using `td` instead of `th`](#using-td-instead-of-th)
- [Indicators/arrows on the left side](#indicatorsarrows-on-the-left-side)
- [NOTE ABOUT CSS/SCSS](#note-about-cssscss)
+ - [Sticky headers](#sticky-headers)
- [Sorting sizes, dates and such](#sorting-sizes-dates-and-such)
- [Alternative sorting](#alternative-sorting)
- [Colspans/Sort on specific column](#colspanssort-on-specific-column)
@@ -35,12 +36,13 @@ You can find a simple demo on
- [Tiebreaker / secondary sort](#tiebreaker--secondary-sort)
- [Empty/null rows always last](#emptynull-rows-always-last)
- [Accessibility](#accessibility)
+- [Sort Events](#sort-events)
- [Sort on load](#sort-on-load)
- [Thank you...](#thank-you)
## Factoids
-- **1148 bytes** minified. (619 bytes gzipped)
+- **1.52KB** minified. (795 bytes gzipped)
- Works with **JavaScript generated tables**. (since we are using an eventListener)
@@ -60,12 +62,6 @@ You can find a simple demo on
There are three ways to use sortable, all of which have their pros and cons. [S Anand](https://github.com/sanand0) and [dkhgh](https://github.com/dkhgh) had some [interesting thoughts](https://github.com/tofsjonas/sortable/issues/28) about it.
-1. Include a link to [jsDelivr](https://www.jsdelivr.com/package/gh/tofsjonas/sortable). (easiest)
-
-2. Copy the file from [jsDelivr](https://www.jsdelivr.com/package/gh/tofsjonas/sortable) or [Github](https://github.com/tofsjonas/sortable) and put it in your assets folder. (in between)
-
-3. Install the [npm package](https://www.npmjs.com/package/sortable-tablesort). (most reliable)
-
### 1. link to jsDelivr
```html
@@ -82,13 +78,13 @@ There are three ways to use sortable, all of which have their pros and cons. [S
-
-
+
+
```
The `span` on line four is just there to prove that you can have elements inside `th`!
@@ -97,7 +93,7 @@ The `span` on line four is just there to prove that you can have elements inside
### 2. copy file to assets folder
-Same as above, but link to your own files
+Same as above, but link to your own files from the `dist` directory
```html
...
@@ -116,16 +112,16 @@ npm install sortable-tablesort
# pnpm install sortable-tablesort
```
-Now you can
+Now you can:
#### a) use links in the html
-Same as above, with links to files
+Same as above, with links to files from the `dist` directory
```html
...
-
-
+
+
...
```
@@ -135,8 +131,8 @@ or
```javascript
// main.js
-import 'sortable-tablesort/sortable.min.css'
-import 'sortable-tablesort/sortable.min.js'
+import 'sortable-tablesort/dist/sortable.min.css'
+import 'sortable-tablesort/dist/sortable.min.js'
```
## Non-sortable field
@@ -222,6 +218,28 @@ That said, if you're feeling lazy, here are two stylesheets you can use:
```
+### Sticky headers
+
+I'm not sure if it's a good idea to have it in the main css, BUT if you are using the above `sortable(.min).css` file (not the -base files) and want sticky headers, you can simply add the class `sticky` to the table.
+
+Blame [razorkyle](https://github.com/razorkyle), it was his idea! 😜
+
+```html
+
+ ...
+
+```
+
+If you are not using the css file, you can use the following css:
+
+```css
+.sortable thead th {
+ position: sticky;
+ top: 0;
+ z-index: 1;
+}
+```
+
## Sorting sizes, dates and such
Using the `data-sort` attribute in `tbody` > `td` you can have one visible value and one sortable value. This is useful in case you have for instance sizes like kb, Mb, GB, or really weird date formats. 😉
@@ -410,9 +428,9 @@ Sortable is not very accessible in its raw form. It does not support screen read
...
-
-
-
+
+
+
```
By including the file the global function `enhanceSortableAccessibility` will automatically run through all existing `.sortable` tables, but you can also run it manually, like so:
@@ -423,13 +441,38 @@ enhanceSortableAccessibility([table1, table2,...etc.])
The function adds an `aria-label` to each th, as well as `tabindex="0"` to each th in the thead of each table, making it possible to tab through the headers. It updates the `aria-label` depending on the direction.
-if you want to import it instead this _should_ work: (I haven't tested it)
+If you want to import it instead:
```ts
-import { enhanceSortableAccessibility } from 'sortable-tablesort/enhanceSortableAccessibility'
+import { enhanceSortableAccessibility } from 'sortable-tablesort/dist/esm/enhanceSortableAccessibility'
enhanceSortableAccessibility([table1, table2,...etc.])
```
+## Sort Events
+
+The table element dispatches two custom events that bubble up the DOM tree:
+
+- `sort-start`: Fired when sorting begins
+- `sort-end`: Fired when sorting is complete
+
+You can listen for these events on any parent element, including the document itself:
+
+```js
+// Listen for events from any sortable table
+document.addEventListener('sort-start', function (e) {
+ console.log('Sorting started on:', e.target) // logs the table element
+})
+
+document.addEventListener('sort-end', function (e) {
+ console.log('Sorting complete on:', e.target) // logs the table element
+})
+
+// Or listen to a specific table
+const table = document.querySelector('.sortable')
+table.addEventListener('sort-start', () => console.log('Sorting started'))
+table.addEventListener('sort-end', () => console.log('Sorting complete'))
+```
+
## Sort on load
If you wish to sort a table on load, I would recommend doing something like this:
@@ -494,3 +537,5 @@ Combine this with `
` to reverse the sort order. Or d
- ...[Jojo-IO](https://github.com/Jojo-IO) for the finding the "`parseFloat` messes up time values" bug!
- ...[Steve Wirt](https://github.com/swirtSJW) for lifting the Accessibility issue! 🦾️
+
+- ...[GazHay](https://github.com/gazhay) for the [sort events](#sort-events) idea!
diff --git a/babel.config.js b/babel.config.js
deleted file mode 100644
index 8fb20b9..0000000
--- a/babel.config.js
+++ /dev/null
@@ -1,10 +0,0 @@
-module.exports = {
- presets: [
- [
- '@babel/preset-env',
- {
- targets: '> 0.25%, not dead',
- },
- ],
- ],
-}
diff --git a/src/sortable.test.html b/demo/index.html
similarity index 82%
rename from src/sortable.test.html
rename to demo/index.html
index 2b34106..96a7514 100644
--- a/src/sortable.test.html
+++ b/demo/index.html
@@ -5,12 +5,13 @@
sortable test
-
-
+
+
+
-