summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2023-02-02 15:19:36 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2023-02-02 15:56:52 +0000
commitd77b7d0d97a4d698f801b92ce3b7ae5135908fdf (patch)
treee732e690b836a2d69290e83ac1e3d1823e72171c
parentInitial commit. (diff)
downloadsortable-d77b7d0d97a4d698f801b92ce3b7ae5135908fdf.tar.xz
sortable-d77b7d0d97a4d698f801b92ce3b7ae5135908fdf.zip
Adding upstream version 1.6.0+20221231.upstream/1.6.0+20221231upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--.gitignore1
-rw-r--r--.prettierrc.js7
-rwxr-xr-xCODE_OF_CONDUCT.md46
-rwxr-xr-xCONTRIBUTING.md5
-rwxr-xr-xLICENSE24
-rwxr-xr-xPULL_REQUEST_TEMPLATE.md13
-rwxr-xr-xREADME.md304
-rw-r--r--example.css124
-rw-r--r--example.css.map1
-rw-r--r--example.min.css1
-rw-r--r--example.min.css.map1
-rw-r--r--example.scss42
-rwxr-xr-xindex.html343
-rw-r--r--sortable-base.css45
-rw-r--r--sortable-base.css.map1
-rw-r--r--sortable-base.min.css1
-rw-r--r--sortable-base.min.css.map1
-rw-r--r--sortable-base.scss68
-rw-r--r--sortable.css82
-rw-r--r--sortable.css.map1
-rwxr-xr-xsortable.js125
-rw-r--r--sortable.min.css1
-rw-r--r--sortable.min.css.map1
-rwxr-xr-xsortable.min.js2
-rwxr-xr-xsortable.scss44
25 files changed, 1284 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c6f9a44
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.vscode/settings.json
diff --git a/.prettierrc.js b/.prettierrc.js
new file mode 100644
index 0000000..24df7e8
--- /dev/null
+++ b/.prettierrc.js
@@ -0,0 +1,7 @@
+module.exports = {
+ singleQuote: true,
+ semi: false,
+ trailingComma: 'all',
+ tabWidth: 2,
+ printWidth: 120,
+}
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100755
index 0000000..b2e87d7
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,46 @@
+# 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
new file mode 100755
index 0000000..89ad019
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,5 @@
+# Contributing
+
+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/LICENSE b/LICENSE
new file mode 100755
index 0000000..cf1ab25
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org>
diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md
new file mode 100755
index 0000000..0674d91
--- /dev/null
+++ b/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,13 @@
+# Pull request template
+
+## Purpose
+
+_Describe the problem or feature in addition to a link to the issues._
+
+## Approach
+
+_How does this change address the problem?_
+
+## Fixes
+
+_List of resolved issues._
diff --git a/README.md b/README.md
new file mode 100755
index 0000000..80ebc0b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,304 @@
+# sortable - a tiny, vanilla JS table sorter
+
+Makes any table with **class="sortable"**, er, sortable. That is the user can click on a table header and change the sorting of the table rows.
+
+Just include the JavaScript and it will work. No function calls needed, all is done with an **eventListener**.
+(the CSS is not strictly needed, but makes it ~pretty and user friendly)
+
+- [sortable - a tiny, vanilla JS table sorter](#sortable---a-tiny-vanilla-js-table-sorter)
+ - [Factoids](#factoids)
+ - [...with a little help from my friends](#with-a-little-help-from-my-friends)
+ - [Demo](#demo)
+ - [A basic example](#a-basic-example)
+ - [Non-sortable field](#non-sortable-field)
+ - [...using `class` and `css`](#using-class-and-css)
+ - [...using `css` only](#using-css-only)
+ - [Indicators/arrows on the left side](#indicatorsarrows-on-the-left-side)
+ - [Note about css/scss](#note-about-cssscss)
+ - [Sort on value other than the one shown](#sort-on-value-other-than-the-one-shown)
+ - [Alternative sorting](#alternative-sorting)
+ - [Specify which column should be sorted](#specify-which-column-should-be-sorted)
+ - [Ascending sort](#ascending-sort)
+ - [Sort on load](#sort-on-load)
+
+## Factoids
+
+- **954 bytes** minified. (545 bytes gzipped) Still under 1k! 🥳
+
+- Works with **JavaScript generated tables**. (since we are using an eventListener)
+
+- **Lightning fast**. _Huge_ tables will make it slow and may freeze the browser, especially for mobiles, so you know...
+
+- Requires **thead** and **tbody**.
+
+- **cross browser**, ie9+ (I think, there have been a _whole_ bunch of changes since I last tested it on ie9 🤷)
+
+- ~~eventListeners attached to the rows _WILL_ be removed~~
+
+- eventListeners are no longer removed! 😊
+
+- NOT tested with React, Angular, Vue, etc.
+
+- Works with [Svelte](https://svelte.dev/)!
+
+### ...with a little help from my friends
+
+- `<table class="sortable asc">` let's you [sort ascending](#ascending-sort) by default. Thanks [
+ Nikita Dunajevs](https://github.com/dunajevs)!
+
+- `data-sort-alt` in `tbody` > `td` allows for [alternative sorting](#alternative-sorting) while holding `shift` or `alt`. Thanks [wodny](https://github.com/wodny)!
+
+- `data-sort-col` in `thead` > `th` allows you to [specify which column should be sorted](#specify-which-column-should-be-sorted), in case you are using `colspan`, for instance. Thanks [Nick Kocharhook](https://github.com/nk9)!
+
+- **Nested elements** inside `th` now works. Thanks [mxve](https://github.com/mxve)!
+
+- [Sort on load](#sort-on-load) example. Thanks [Christian Petersson](https://github.com/Issen007) and [Abit Salihu](https://github.com/abitsalihu)!
+
+- Thanks to [chatcoda](https://github.com/chatcoda) for the `<td></td>` / `<td>0</td>` sorting bug fix!
+
+- If you have more than one `<tbody />`, they will all be sorted. (Multiple `<thead />`s are not "allowed".) Thanks [GazHay](https://github.com/gazhay)!
+
+## Demo
+
+You can find a simple demo on <https://tofsjonas.github.io/sortable/>
+
+## A basic example
+
+```html
+<table class="sortable">
+ <thead>
+ <tr>
+ <th><span>Role</span></th>
+ <th>Name</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Genius</td>
+ <td>Rick</td>
+ </tr>
+ <tr>
+ <td><a href="javascript:alert('Inline javascript works!');">Sidekick</a></td>
+ <td>Morty</td>
+ </tr>
+ </tbody>
+</table>
+<link href="https://cdn.jsdelivr.net/gh/tofsjonas/sortable/sortable.min.css" rel="stylesheet" />
+<script src="https://cdn.jsdelivr.net/gh/tofsjonas/sortable/sortable.min.js"></script>
+```
+
+_(The `span` is just there to prove that elements inside `th` works)_
+
+## Non-sortable field
+
+### ...using `class` and `css`
+
+If you wish to disable sorting for a specific field, the easiest way is to add a class to it, like so:
+
+```html
+<tr>
+ <th class="no-sort">Role</th>
+ <th>Name</th>
+</tr>
+```
+
+and then use css to block clicks. like so:
+
+```css
+.sortable th.no-sort {
+ pointer-events: none;
+}
+```
+
+### ...using `css` only
+
+This is a bit trickier, but it doesn't require any changes to the html, so I guess it could be worth it in some cases.
+
+```css
+/* the first column in every sortable table should not be sortable*/
+.sortable th:nth-child(1) {
+ pointer-events: none;
+}
+
+/* the seventh column in the second .sortable table should not be sortable*/
+.sortable:nth-of-type(2) th:nth-child(7) {
+ pointer-events: none;
+}
+```
+
+## Indicators/arrows on the left side
+
+If you have text that is aligned on the right side, you may want to have the arrows on the left side.
+
+This is solved by adding a class to the css and using `::before` instead of `::after`.
+
+(You can of course use a pure css solution, without class names - just like with the [non-sortable field](#non-sortable-field) - but _that_ I will leave for you to figure out.)
+
+```css
+.sortable th.indicator-left::after {
+ content: '';
+}
+.sortable th.indicator-left::before {
+ margin-right: 3px;
+ content: '▸';
+}
+/* etc. */
+```
+
+> _Full example: [CSS](https://github.com/tofsjonas/sortable/blob/main/sortable-base.css), [SCSS](https://github.com/tofsjonas/sortable/blob/main/sortable-base.scss)_
+
+## Note about css/scss
+
+The `css/scss` in this repo was only ever meant as an example. It was never intended to be actually _used_.
+
+That said, if you're feeling lazy, here are two stylesheets you can use:
+
+```html
+<!-- This will add arrows only -->
+<link href="https://cdn.jsdelivr.net/gh/tofsjonas/sortable/sortable-base.min.css" rel="stylesheet" />
+
+<!-- This will make it look like the tables in the example, with arrows, striped rows etc. -->
+<link href="https://cdn.jsdelivr.net/gh/tofsjonas/sortable/sortable.min.css" rel="stylesheet" />
+```
+
+## Sort on value other than the one shown
+
+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, etc.
+
+```html
+<table class="sortable">
+ <thead>
+ <tr>
+ <th>Movie Name</th>
+ <th>Size</th>
+ <th>Release date</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Zack Snyder's Justice League</td>
+ <td data-sort="943718400">900MB</td>
+ <td data-sort="20210318">03/18/2021</td>
+ </tr>
+ <tr>
+ <td>The Sound of Music</td>
+ <td data-sort="1610612736">1.5GB</td>
+ <td data-sort="19651209">12/09/1965</td>
+ </tr>
+ </tbody>
+</table>
+```
+
+## Alternative sorting
+
+If you click on a table header while holding **shift** or **alt** an alternative
+`data-sort-alt` attribute will override `data-sort`.
+
+```html
+<table class="sortable">
+ <thead>
+ <tr>
+ <th>Movie Name</th>
+ <th>Size</th>
+ <th>Release date</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Something</td>
+ <td data-sort-alt="c" data-sort="a">A</td>
+ <td data-sort-alt="b" data-sort="c">B</td>
+ <td data-sort-alt="a" data-sort="b">C</td>
+ </tr>
+ <tr>
+ <td>Something else</td>
+ <td data-sort-alt="e" data-sort="f">D</td>
+ <td data-sort-alt="f" data-sort="e">E</td>
+ <td data-sort-alt="d" data-sort="d">F</td>
+ </tr>
+ </tbody>
+</table>
+```
+
+## Specify which column should be sorted
+
+Using the `data-sort-col` attribute in `thead` > `th`, you can sort on a different column than the one that was clicked. For instance if you want to have colspans. Like so:
+
+```html
+<thead>
+ <tr>
+ <th></th>
+ <th>Category</th>
+ <th class="show_name">Show</th>
+ <th colspan="2">Overall</th>
+ <th colspan="2" data-sort-col="5">On Our Dates</th>
+ <th data-sort-col="7">First Sold Out</th>
+ </tr>
+</thead>
+<tbody>
+ <tr>
+ <td class="tags">&nbsp;</td>
+ <td class="category">Comedy</td>
+ <td class="show_name">Show 1</td>
+ <td class="ratio all" data-sort="72">18/25</td>
+ <td class="pct all">72%</td>
+ <td class="ratio ours" data-sort="75">3/4</td>
+ <td class="pct ours">75%</td>
+ <td>2022-07-30</td>
+ </tr>
+ ...
+</tbody>
+```
+
+## Ascending sort
+
+By adding `asc` to `table`, the default sorting direction will be **ascending** instead of descending
+
+```html
+<table class="sortable asc">
+ <thead>
+ ...
+ </thead>
+ <tbody>
+ ...
+ </tbody>
+</table>
+```
+
+## Sort on load
+
+If you wish to sort a table on load, I would recommend doing something like this:
+
+```html
+<table class="sortable">
+ <thead>
+ <tr>
+ <th>Movie Name</th>
+ <th id="movie-size">Size</th>
+ <th>Release date</th>
+ </tr>
+ </thead>
+ <tbody>
+ ...
+ </tbody>
+</table>
+
+<script>
+ window.addEventListener('load', function () {
+ const el = document.getElementById('movie-size')
+ // without id:
+ // const el = document.querySelector('.sortable th:first-child')
+ // const el = document.querySelector('.sortable th:nth-child(2)')
+ // const el = document.querySelectorAll('.sortable')[3].querySelector('th:nth-child(7)')
+ // etc.
+ if (el) {
+ el.click()
+ }
+ })
+</script>
+```
+
+Combine this with `<table class="sortable asc">` to reverse the sort order. Or do `el.click()` twice!
+
+[![jsdelivr](https://data.jsdelivr.com/v1/package/gh/tofsjonas/sortable/badge)](https://www.jsdelivr.com/package/gh/tofsjonas/sortable)
diff --git a/example.css b/example.css
new file mode 100644
index 0000000..113a7bf
--- /dev/null
+++ b/example.css
@@ -0,0 +1,124 @@
+@charset "UTF-8";
+.sortable th {
+ cursor: pointer;
+}
+.sortable th.no-sort {
+ pointer-events: none;
+}
+.sortable th::after, .sortable th::before {
+ transition: color 0.1s ease-in-out;
+ font-size: 1.2em;
+ color: transparent;
+}
+.sortable th::after {
+ margin-left: 3px;
+ content: "▸";
+}
+.sortable th:hover::after {
+ color: inherit;
+}
+.sortable th.dir-d::after {
+ color: inherit;
+ content: "▾";
+}
+.sortable th.dir-u::after {
+ color: inherit;
+ content: "▴";
+}
+.sortable th.indicator-left::after {
+ content: "";
+}
+.sortable th.indicator-left::before {
+ margin-right: 3px;
+ content: "▸";
+}
+.sortable th.indicator-left:hover::before {
+ color: inherit;
+}
+.sortable th.indicator-left.dir-d::before {
+ color: inherit;
+ content: "▾";
+}
+.sortable th.indicator-left.dir-u::before {
+ color: inherit;
+ content: "▴";
+}
+
+.sortable {
+ --stripe-color: #e4e4e4;
+ --th-color: #fff;
+ --th-bg: #808080;
+ --td-color: #000;
+ --td-on-stripe-color: #000;
+ border-spacing: 0;
+}
+.sortable tbody tr:nth-child(odd) {
+ background-color: var(--stripe-color);
+ color: var(--td-on-stripe-color);
+}
+.sortable th {
+ background: var(--th-bg);
+ color: var(--th-color);
+ font-weight: normal;
+ text-align: left;
+ text-transform: capitalize;
+ vertical-align: baseline;
+ white-space: nowrap;
+}
+.sortable td {
+ color: var(--td-color);
+}
+.sortable td,
+.sortable th {
+ padding: 10px;
+}
+.sortable td:first-child,
+.sortable th:first-child {
+ border-top-left-radius: 4px;
+}
+.sortable td:last-child,
+.sortable th:last-child {
+ border-top-right-radius: 4px;
+}
+
+body {
+ font-size: 14px;
+}
+
+p {
+ line-height: 1.7em;
+}
+
+code {
+ font-family: monospace;
+ background: #eee;
+ padding: 5px;
+ border-radius: 2px;
+}
+
+* {
+ box-sizing: border-box;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.sortable:nth-of-type(4) th:nth-child(7),
+th.no-sort {
+ background: pink;
+ color: red;
+ pointer-events: none;
+}
+
+.sortable:nth-of-type(4) th:nth-child(7)::after {
+ color: red;
+ content: "(also not sortable)";
+ font-size: 0.9em;
+ display: block;
+}
+
+.lefty td:nth-child(2),
+.lefty th:nth-child(2) {
+ width: 80px;
+ text-align: right;
+}/*# sourceMappingURL=example.css.map */ \ No newline at end of file
diff --git a/example.css.map b/example.css.map
new file mode 100644
index 0000000..e5d7a9c
--- /dev/null
+++ b/example.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["example.css","sortable-base.scss","sortable.scss","example.scss"],"names":[],"mappings":"AAAA,gBAAgB;ACCd;EACE,eAAA;ADCJ;ACCI;EACE,oBAAA;ADCN;ACCI;EAEE,kCAAA;EACA,gBAAA;EACA,kBAAA;ADAN;ACGI;EACE,gBAAA;EACA,YAAA;ADDN;ACIM;EACE,cAAA;ADFR;ACOM;EACE,cAAA;EACA,YAAA;ADLR;ACUM;EACE,cAAA;EACA,YAAA;ADRR;ACYM;EACE,WAAA;ADVR;ACYM;EACE,iBAAA;EACA,YAAA;ADVR;ACcQ;EACE,cAAA;ADZV;ACiBQ;EACE,cAAA;EACA,YAAA;ADfV;ACoBQ;EACE,cAAA;EACA,YAAA;ADlBV;;AE1CA;EACE,uBAAA;EACA,gBAAA;EACA,gBAAA;EACA,gBAAA;EACA,0BAAA;EAEA,iBAAA;AF4CF;AExCM;EACE,qCAAA;EACA,gCAAA;AF0CR;AEtCE;EACE,wBAAA;EACA,sBAAA;EACA,mBAAA;EACA,gBAAA;EACA,0BAAA;EACA,wBAAA;EACA,mBAAA;AFwCJ;AEtCE;EACE,sBAAA;AFwCJ;AEtCE;;EAEE,aAAA;AFwCJ;AEtCI;;EACE,2BAAA;AFyCN;AEtCI;;EACE,4BAAA;AFyCN;;AGhFA;EACE,eAAA;AHmFF;;AGhFA;EACE,kBAAA;AHmFF;;AGhFA;EACE,sBAAA;EACA,gBAAA;EACA,YAAA;EACA,kBAAA;AHmFF;;AGhFA;EACE,sBAAA;EACA,8JAAA;EAEA,mCAAA;EACA,kCAAA;AHkFF;;AGhFA;;EAEE,gBAAA;EACA,UAAA;EACA,oBAAA;AHmFF;;AGjFA;EACE,UAAA;EACA,8BAAA;EACA,gBAAA;EACA,cAAA;AHoFF;;AGjFE;;EAEE,WAAA;EACA,iBAAA;AHoFJ","file":"example.css"} \ No newline at end of file
diff --git a/example.min.css b/example.min.css
new file mode 100644
index 0000000..86aa6c1
--- /dev/null
+++ b/example.min.css
@@ -0,0 +1 @@
+.sortable th{cursor:pointer}.sortable th.no-sort{pointer-events:none}.sortable th::after,.sortable th::before{transition:color .1s ease-in-out;font-size:1.2em;color:rgba(0,0,0,0)}.sortable th::after{margin-left:3px;content:"▸"}.sortable th:hover::after{color:inherit}.sortable th.dir-d::after{color:inherit;content:"▾"}.sortable th.dir-u::after{color:inherit;content:"▴"}.sortable th.indicator-left::after{content:""}.sortable th.indicator-left::before{margin-right:3px;content:"▸"}.sortable th.indicator-left:hover::before{color:inherit}.sortable th.indicator-left.dir-d::before{color:inherit;content:"▾"}.sortable th.indicator-left.dir-u::before{color:inherit;content:"▴"}.sortable{--stripe-color: #e4e4e4;--th-color: #fff;--th-bg: #808080;--td-color: #000;--td-on-stripe-color: #000;border-spacing:0}.sortable tbody tr:nth-child(odd){background-color:var(--stripe-color);color:var(--td-on-stripe-color)}.sortable th{background:var(--th-bg);color:var(--th-color);font-weight:normal;text-align:left;text-transform:capitalize;vertical-align:baseline;white-space:nowrap}.sortable td{color:var(--td-color)}.sortable td,.sortable th{padding:10px}.sortable td:first-child,.sortable th:first-child{border-top-left-radius:4px}.sortable td:last-child,.sortable th:last-child{border-top-right-radius:4px}body{font-size:14px}p{line-height:1.7em}code{font-family:monospace;background:#eee;padding:5px;border-radius:2px}*{box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.sortable:nth-of-type(4) th:nth-child(7),th.no-sort{background:pink;color:red;pointer-events:none}.sortable:nth-of-type(4) th:nth-child(7)::after{color:red;content:"(also not sortable)";font-size:.9em;display:block}.lefty td:nth-child(2),.lefty th:nth-child(2){width:80px;text-align:right}/*# sourceMappingURL=example.min.css.map */ \ No newline at end of file
diff --git a/example.min.css.map b/example.min.css.map
new file mode 100644
index 0000000..c748cb8
--- /dev/null
+++ b/example.min.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["example.min.css","sortable-base.scss","sortable.scss","example.scss"],"names":[],"mappings":"AAAA,aCCE,cACE,CAAA,qBAEA,mBACE,CAAA,yCAEF,gCAEE,CAAA,eACA,CAAA,mBACA,CAAA,oBAGF,eACE,CAAA,WACA,CAAA,0BAGA,aACE,CAAA,0BAKF,aACE,CAAA,WACA,CAAA,0BAKF,aACE,CAAA,WACA,CAAA,mCAIF,UACE,CAAA,oCAEF,gBACE,CAAA,WACA,CAAA,0CAIA,aACE,CAAA,0CAKF,aACE,CAAA,WACA,CAAA,0CAKF,aACE,CAAA,WACA,CAAA,UC5DV,uBACE,CAAA,gBACA,CAAA,gBACA,CAAA,gBACA,CAAA,0BACA,CAAA,gBAEA,CAAA,kCAII,oCACE,CAAA,+BACA,CAAA,aAIN,uBACE,CAAA,qBACA,CAAA,kBACA,CAAA,eACA,CAAA,yBACA,CAAA,uBACA,CAAA,kBACA,CAAA,aAEF,qBACE,CAAA,0BAEF,YAEE,CAAA,kDAEA,0BACE,CAAA,gDAGF,2BACE,CAAA,KCvCN,cACE,CAAA,EAGF,iBACE,CAAA,KAGF,qBACE,CAAA,eACA,CAAA,WACA,CAAA,iBACA,CAAA,EAGF,qBACE,CAAA,mJACA,CAAA,kCAEA,CAAA,iCACA,CAAA,oDAEF,eAEE,CAAA,SACA,CAAA,mBACA,CAAA,gDAEF,SACE,CAAA,6BACA,CAAA,cACA,CAAA,aACA,CAAA,8CAGA,UAEE,CAAA,gBACA","file":"example.min.css"} \ No newline at end of file
diff --git a/example.scss b/example.scss
new file mode 100644
index 0000000..2dfb47e
--- /dev/null
+++ b/example.scss
@@ -0,0 +1,42 @@
+@import 'sortable.scss';
+body {
+ font-size: 14px;
+}
+
+p {
+ line-height: 1.7em;
+}
+
+code {
+ font-family: monospace;
+ background: #eee;
+ padding: 5px;
+ border-radius: 2px;
+}
+
+* {
+ box-sizing: border-box;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans',
+ 'Droid Sans', 'Helvetica Neue', sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+.sortable:nth-of-type(4) th:nth-child(7),
+th.no-sort {
+ background: pink;
+ color: red;
+ pointer-events: none;
+}
+.sortable:nth-of-type(4) th:nth-child(7)::after {
+ color: red;
+ content: '(also not sortable)';
+ font-size: 0.9em;
+ display: block;
+}
+.lefty {
+ td:nth-child(2),
+ th:nth-child(2) {
+ width: 80px;
+ text-align: right;
+ }
+}
diff --git a/index.html b/index.html
new file mode 100755
index 0000000..80e38b8
--- /dev/null
+++ b/index.html
@@ -0,0 +1,343 @@
+<!DOCTYPE html>
+
+<html lang="en">
+ <head>
+ <meta name="charset" content="UTF-8" />
+ <meta name="author" content="Jonas Earendel" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <meta name="description" content="Just testing some table sorting." />
+ <title>sortable - the example page</title>
+ <!-- <link rel="stylesheet" type="text/css" href="sortable-base.css" />
+ <link rel="stylesheet" type="text/css" href="sortable.css" /> -->
+ <link rel="stylesheet" type="text/css" href="example.css" />
+ </head>
+ <style></style>
+
+ <body>
+ <h1>Demos</h1>
+ Here are some basic demos for the tiny table sorter found on
+ <a href="https://github.com/tofsjonas/sortable">https://github.com/tofsjonas/sortable</a>
+ <h2>Table with three &lt;tbody/&gt;, sorted separately:</h2>
+ <table class="sortable" style="--sortable-th-bg: pink">
+ <thead>
+ <tr>
+ <th><span>Role</span></th>
+ <th>Name</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Genius</td>
+ <td>Rick</td>
+ </tr>
+ <tr>
+ <td><a href="javascript:alert('Inline javascript works!');">Sidekick</a></td>
+ <td><a id="morty" href="#">Morty</a></td>
+ </tr>
+ </tbody>
+ <tbody style="font-style: italic">
+ <tr>
+ <td>Genius</td>
+ <td>Rick</td>
+ </tr>
+ <tr>
+ <td><a href="javascript:alert('Inline javascript works!');">Sidekick</a></td>
+ <td><a id="morty" href="#">Morty</a></td>
+ </tr>
+ </tbody>
+ <tbody style="font-weight: bold">
+ <tr>
+ <td>Genius</td>
+ <td>Rick</td>
+ </tr>
+ <tr>
+ <td><a href="javascript:alert('Inline javascript works!');">Sidekick</a></td>
+ <td><a id="morty" href="#">Morty</a></td>
+ </tr>
+ </tbody>
+ </table>
+
+ <h2>An example with arrows on the left side:</h2>
+
+ <table class="sortable lefty">
+ <thead>
+ <tr>
+ <th><span>Text</span></th>
+ <th class="indicator-left">Number</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>jkl</td>
+ <td>0.4</td>
+ </tr>
+ <tr>
+ <td>abc</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td>def</td>
+ <td>0.2</td>
+ </tr>
+ <tr>
+ <td>ghi</td>
+ <td></td>
+ </tr>
+ </tbody>
+ </table>
+
+ <script>
+ document.getElementById('morty').addEventListener('click', function (e) {
+ e.preventDefault()
+ alert('event listeners also work!')
+ })
+ </script>
+
+ <h2>Using the data-sort attribute</h2>
+
+ <p>Here 1.5GB has <code>data-sort="1610612736"</code> and 900MB has <code>data-sort="943718400"</code></p>
+ <p>
+ The same with the dates. 03/18/2021 is turned into <code>data-sort="20210318"</code> and 12/09/1965 into
+ <code>data-sort="19651209"</code>
+ </p>
+ <p>Otherwise the sorting would be wrong.</p>
+ <table class="sortable advanced-table">
+ <thead>
+ <tr>
+ <th>Movie Name</th>
+ <th>Size</th>
+ <th>Release date</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>The Sound of Music</td>
+ <td>1.5GB</td>
+ <td>12/09/1965</td>
+ </tr>
+ <tr>
+ <td>Zack Snyder's Justice League</td>
+ <td>900MB</td>
+ <td>03/18/2021</td>
+ </tr>
+ </tbody>
+ </table>
+
+ <h2>Slightly larger</h2>
+
+ <p>"Ram" has class="no-sort", which has the css property "pointer-events: none;"</p>
+ <p>"Screen width" has the "css only" way of disabling sorting.</p>
+
+ <table class="sortable">
+ <thead>
+ <tr>
+ <td colspan="3">personal</td>
+ <td colspan="5">hardware</td>
+ <td colspan="4">software</td>
+ </tr>
+ <tr>
+ <th>job title</th>
+ <th>name</th>
+ <th>company</th>
+ <th>processor</th>
+ <th class="no-sort">ram(not sortable)</th>
+ <th>graphics card</th>
+ <th>screen width</th>
+ <th>screen height</th>
+ <th>platform</th>
+ <th>browser</th>
+ <th>browser version</th>
+ <th>language</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Boss</td>
+ <td>Stan the Man</td>
+ <td>Monsters Inc</td>
+ <td>AMD</td>
+ <td>2</td>
+ <td>Nvidia</td>
+ <td>1510</td>
+ <td>981</td>
+ <td>Win32</td>
+ <td>IE</td>
+ <td>11</td>
+ <td>en-us</td>
+ </tr>
+ <tr>
+ <td>Stevedore</td>
+ <td>Bridget Jones</td>
+ <td>The Hand</td>
+ <td>i7</td>
+ <td>8gb</td>
+ <td>-</td>
+ <td>1530</td>
+ <td>1080</td>
+ <td>Linux x86_64</td>
+ <td>Firefox</td>
+ <td>54</td>
+ <td>sv-se</td>
+ </tr>
+ <tr>
+ <td>HR</td>
+ <td>Bruce Wayne</td>
+ <td>League of Shadows</td>
+ <td>i5</td>
+ <td>-</td>
+ <td>GeForce</td>
+ <td>1520</td>
+ <td>1080</td>
+ <td>Linux x86_64</td>
+ <td>Opera</td>
+ <td>46</td>
+ <td>dk</td>
+ </tr>
+ <tr>
+ <td>Programmer</td>
+ <td>Bilbo Baggins</td>
+ <td>Brotherhood of Evil Mutants</td>
+ <td>i3</td>
+ <td>4 gigabyte</td>
+ <td>-</td>
+ <td>130</td>
+ <td>1080</td>
+ <td>Linux x86_64</td>
+ <td>Opera</td>
+ <td>46</td>
+ <td>en</td>
+ </tr>
+ </tbody>
+ <tfoot></tfoot>
+ </table>
+
+ <h2>Even larger table (with ascending sort)</h2>
+
+ <table class="sortable asc massive">
+ <thead>
+ <tr>
+ <td colspan="3">personal</td>
+ <td colspan="5">hardware</td>
+ <td colspan="4">software</td>
+ </tr>
+ <tr>
+ <th>job title</th>
+ <th>name</th>
+ <th>company</th>
+ <th>processor</th>
+ <th>ram</th>
+ <th>graphics card</th>
+ <th>screen width</th>
+ <th>screen height</th>
+ <th>platform</th>
+ <th>browser</th>
+ <th>browser version</th>
+ <th>language</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Boss</td>
+ <td>Stan the Man</td>
+ <td>Monsters Inc</td>
+ <td>AMD</td>
+ <td>2</td>
+ <td>Nvidia</td>
+ <td>1510</td>
+ <td>981</td>
+ <td>Win32</td>
+ <td>IE</td>
+ <td>11</td>
+ <td>en-us</td>
+ </tr>
+ <tr>
+ <td>Slave</td>
+ <td>Bridget Jones</td>
+ <td>The Hand</td>
+ <td>i7</td>
+ <td>8gb</td>
+ <td>-</td>
+ <td>1530</td>
+ <td>1080</td>
+ <td>Linux x86_64</td>
+ <td>Firefox</td>
+ <td>54</td>
+ <td>sv-se</td>
+ </tr>
+ <tr>
+ <td>HR</td>
+ <td>Bruce Wayne</td>
+ <td>League of Shadows</td>
+ <td>i5</td>
+ <td>-</td>
+ <td>GeForce</td>
+ <td>1520</td>
+ <td>1080</td>
+ <td>Linux x86_64</td>
+ <td>Opera</td>
+ <td>46</td>
+ <td>dk</td>
+ </tr>
+ <tr>
+ <td>Programmer</td>
+ <td>Bilbo Baggins</td>
+ <td>Brotherhood of Evil Mutants</td>
+ <td>i3</td>
+ <td>4 gigabyte</td>
+ <td>-</td>
+ <td>130</td>
+ <td>1080</td>
+ <td>Linux x86_64</td>
+ <td>Opera</td>
+ <td>46</td>
+ <td>en</td>
+ </tr>
+ </tbody>
+ <tfoot></tfoot>
+ </table>
+ <script>
+ var table = document.querySelector('.massive')
+ var tbody = table.tBodies[0]
+ var rows = [].slice.call(tbody.rows, 0)
+ var fragment = document.createDocumentFragment()
+
+ for (var k = 0; k < 50; k++) {
+ for (var i = 0; i < rows.length; i++) {
+ fragment.appendChild(rows[i].cloneNode(true))
+ }
+ }
+ tbody.innerHTML = ''
+ tbody.appendChild(fragment)
+ </script>
+ <!-- <script type="text/javascript" src="sortable.js"></script> -->
+ <script src="sortable.js"></script>
+ <script>
+ function prepareAdvancedTable() {
+ function convertSizeToBytes(str) {
+ var matches = str.match(/^([0-9.]+)(\w+)$/)
+ if (matches) {
+ var vals = {
+ kB: 1, // 1024 B
+ KiB: 1, // 1024 B
+ MB: 2, // 1024 * 1024 B
+ GB: 3, // 1024 * 1024 * 1024 B
+ TB: 4, // 1024 * 1024 * 1024 *1024 B
+ }
+ return (matches[1] || 0) * Math.pow(1024, vals[matches[2]])
+ }
+ return str
+ }
+
+ var size_table = document.querySelector('.advanced-table')
+ var rows = size_table.tBodies[0].rows
+ for (let i = 0; i < rows.length; i++) {
+ const date_element = rows[i].cells[2]
+ const size_element = rows[i].cells[1]
+ date_element.setAttribute('data-sort', date_element.innerText.replace(/(\d+)\/(\d+)\/(\d+)/, '$3$1$2'))
+ size_element.setAttribute('data-sort', convertSizeToBytes(size_element.innerText))
+ }
+ }
+ prepareAdvancedTable()
+ </script>
+ </body>
+</html>
diff --git a/sortable-base.css b/sortable-base.css
new file mode 100644
index 0000000..39d5078
--- /dev/null
+++ b/sortable-base.css
@@ -0,0 +1,45 @@
+@charset "UTF-8";
+.sortable th {
+ cursor: pointer;
+}
+.sortable th.no-sort {
+ pointer-events: none;
+}
+.sortable th::after, .sortable th::before {
+ transition: color 0.1s ease-in-out;
+ font-size: 1.2em;
+ color: transparent;
+}
+.sortable th::after {
+ margin-left: 3px;
+ content: "▸";
+}
+.sortable th:hover::after {
+ color: inherit;
+}
+.sortable th.dir-d::after {
+ color: inherit;
+ content: "▾";
+}
+.sortable th.dir-u::after {
+ color: inherit;
+ content: "▴";
+}
+.sortable th.indicator-left::after {
+ content: "";
+}
+.sortable th.indicator-left::before {
+ margin-right: 3px;
+ content: "▸";
+}
+.sortable th.indicator-left:hover::before {
+ color: inherit;
+}
+.sortable th.indicator-left.dir-d::before {
+ color: inherit;
+ content: "▾";
+}
+.sortable th.indicator-left.dir-u::before {
+ color: inherit;
+ content: "▴";
+}/*# sourceMappingURL=sortable-base.css.map */ \ No newline at end of file
diff --git a/sortable-base.css.map b/sortable-base.css.map
new file mode 100644
index 0000000..d6b8cdc
--- /dev/null
+++ b/sortable-base.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["sortable-base.css","sortable-base.scss"],"names":[],"mappings":"AAAA,gBAAgB;ACCd;EACE,eAAA;ADCJ;ACCI;EACE,oBAAA;ADCN;ACCI;EAEE,kCAAA;EACA,gBAAA;EACA,kBAAA;ADAN;ACGI;EACE,gBAAA;EACA,YAAA;ADDN;ACIM;EACE,cAAA;ADFR;ACOM;EACE,cAAA;EACA,YAAA;ADLR;ACUM;EACE,cAAA;EACA,YAAA;ADRR;ACYM;EACE,WAAA;ADVR;ACYM;EACE,iBAAA;EACA,YAAA;ADVR;ACcQ;EACE,cAAA;ADZV;ACiBQ;EACE,cAAA;EACA,YAAA;ADfV;ACoBQ;EACE,cAAA;EACA,YAAA;ADlBV","file":"sortable-base.css"} \ No newline at end of file
diff --git a/sortable-base.min.css b/sortable-base.min.css
new file mode 100644
index 0000000..3a2dde2
--- /dev/null
+++ b/sortable-base.min.css
@@ -0,0 +1 @@
+.sortable th{cursor:pointer}.sortable th.no-sort{pointer-events:none}.sortable th::after,.sortable th::before{transition:color .1s ease-in-out;font-size:1.2em;color:rgba(0,0,0,0)}.sortable th::after{margin-left:3px;content:"▸"}.sortable th:hover::after{color:inherit}.sortable th.dir-d::after{color:inherit;content:"▾"}.sortable th.dir-u::after{color:inherit;content:"▴"}.sortable th.indicator-left::after{content:""}.sortable th.indicator-left::before{margin-right:3px;content:"▸"}.sortable th.indicator-left:hover::before{color:inherit}.sortable th.indicator-left.dir-d::before{color:inherit;content:"▾"}.sortable th.indicator-left.dir-u::before{color:inherit;content:"▴"}/*# sourceMappingURL=sortable-base.min.css.map */ \ No newline at end of file
diff --git a/sortable-base.min.css.map b/sortable-base.min.css.map
new file mode 100644
index 0000000..df0a5ba
--- /dev/null
+++ b/sortable-base.min.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["sortable-base.min.css","sortable-base.scss"],"names":[],"mappings":"AAAA,aCCE,cACE,CAAA,qBAEA,mBACE,CAAA,yCAEF,gCAEE,CAAA,eACA,CAAA,mBACA,CAAA,oBAGF,eACE,CAAA,WACA,CAAA,0BAGA,aACE,CAAA,0BAKF,aACE,CAAA,WACA,CAAA,0BAKF,aACE,CAAA,WACA,CAAA,mCAIF,UACE,CAAA,oCAEF,gBACE,CAAA,WACA,CAAA,0CAIA,aACE,CAAA,0CAKF,aACE,CAAA,WACA,CAAA,0CAKF,aACE,CAAA,WACA","file":"sortable-base.min.css"} \ No newline at end of file
diff --git a/sortable-base.scss b/sortable-base.scss
new file mode 100644
index 0000000..ee059b5
--- /dev/null
+++ b/sortable-base.scss
@@ -0,0 +1,68 @@
+.sortable {
+ th {
+ cursor: pointer;
+
+ &.no-sort {
+ pointer-events: none;
+ }
+ &::after,
+ &::before {
+ transition: color 0.1s ease-in-out;
+ font-size: 1.2em;
+ color: transparent;
+ }
+
+ &::after {
+ margin-left: 3px;
+ content: '\025B8';
+ }
+ &:hover {
+ &::after {
+ color: inherit;
+ }
+ }
+
+ &.dir-d {
+ &::after {
+ color: inherit;
+ content: '\025BE';
+ }
+ }
+
+ &.dir-u {
+ &::after {
+ color: inherit;
+ content: '\025B4';
+ }
+ }
+ &.indicator-left {
+ &::after {
+ content: '';
+ }
+ &::before {
+ margin-right: 3px;
+ content: '\025B8';
+ }
+
+ &:hover {
+ &::before {
+ color: inherit;
+ }
+ }
+
+ &.dir-d {
+ &::before {
+ color: inherit;
+ content: '\025BE';
+ }
+ }
+
+ &.dir-u {
+ &::before {
+ color: inherit;
+ content: '\025B4';
+ }
+ }
+ }
+ }
+}
diff --git a/sortable.css b/sortable.css
new file mode 100644
index 0000000..e6d321a
--- /dev/null
+++ b/sortable.css
@@ -0,0 +1,82 @@
+@charset "UTF-8";
+.sortable th {
+ cursor: pointer;
+}
+.sortable th.no-sort {
+ pointer-events: none;
+}
+.sortable th::after, .sortable th::before {
+ transition: color 0.1s ease-in-out;
+ font-size: 1.2em;
+ color: transparent;
+}
+.sortable th::after {
+ margin-left: 3px;
+ content: "▸";
+}
+.sortable th:hover::after {
+ color: inherit;
+}
+.sortable th.dir-d::after {
+ color: inherit;
+ content: "▾";
+}
+.sortable th.dir-u::after {
+ color: inherit;
+ content: "▴";
+}
+.sortable th.indicator-left::after {
+ content: "";
+}
+.sortable th.indicator-left::before {
+ margin-right: 3px;
+ content: "▸";
+}
+.sortable th.indicator-left:hover::before {
+ color: inherit;
+}
+.sortable th.indicator-left.dir-d::before {
+ color: inherit;
+ content: "▾";
+}
+.sortable th.indicator-left.dir-u::before {
+ color: inherit;
+ content: "▴";
+}
+
+.sortable {
+ --stripe-color: #e4e4e4;
+ --th-color: #fff;
+ --th-bg: #808080;
+ --td-color: #000;
+ --td-on-stripe-color: #000;
+ border-spacing: 0;
+}
+.sortable tbody tr:nth-child(odd) {
+ background-color: var(--stripe-color);
+ color: var(--td-on-stripe-color);
+}
+.sortable th {
+ background: var(--th-bg);
+ color: var(--th-color);
+ font-weight: normal;
+ text-align: left;
+ text-transform: capitalize;
+ vertical-align: baseline;
+ white-space: nowrap;
+}
+.sortable td {
+ color: var(--td-color);
+}
+.sortable td,
+.sortable th {
+ padding: 10px;
+}
+.sortable td:first-child,
+.sortable th:first-child {
+ border-top-left-radius: 4px;
+}
+.sortable td:last-child,
+.sortable th:last-child {
+ border-top-right-radius: 4px;
+}/*# sourceMappingURL=sortable.css.map */ \ No newline at end of file
diff --git a/sortable.css.map b/sortable.css.map
new file mode 100644
index 0000000..4e0279f
--- /dev/null
+++ b/sortable.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["sortable.css","sortable-base.scss","sortable.scss"],"names":[],"mappings":"AAAA,gBAAgB;ACCd;EACE,eAAA;ADCJ;ACCI;EACE,oBAAA;ADCN;ACCI;EAEE,kCAAA;EACA,gBAAA;EACA,kBAAA;ADAN;ACGI;EACE,gBAAA;EACA,YAAA;ADDN;ACIM;EACE,cAAA;ADFR;ACOM;EACE,cAAA;EACA,YAAA;ADLR;ACUM;EACE,cAAA;EACA,YAAA;ADRR;ACYM;EACE,WAAA;ADVR;ACYM;EACE,iBAAA;EACA,YAAA;ADVR;ACcQ;EACE,cAAA;ADZV;ACiBQ;EACE,cAAA;EACA,YAAA;ADfV;ACoBQ;EACE,cAAA;EACA,YAAA;ADlBV;;AE1CA;EACE,uBAAA;EACA,gBAAA;EACA,gBAAA;EACA,gBAAA;EACA,0BAAA;EAEA,iBAAA;AF4CF;AExCM;EACE,qCAAA;EACA,gCAAA;AF0CR;AEtCE;EACE,wBAAA;EACA,sBAAA;EACA,mBAAA;EACA,gBAAA;EACA,0BAAA;EACA,wBAAA;EACA,mBAAA;AFwCJ;AEtCE;EACE,sBAAA;AFwCJ;AEtCE;;EAEE,aAAA;AFwCJ;AEtCI;;EACE,2BAAA;AFyCN;AEtCI;;EACE,4BAAA;AFyCN","file":"sortable.css"} \ No newline at end of file
diff --git a/sortable.js b/sortable.js
new file mode 100755
index 0000000..62d9090
--- /dev/null
+++ b/sortable.js
@@ -0,0 +1,125 @@
+/**
+ * sortable 1.6.0 (or something, I always forget to update this)
+ *
+ * Makes html tables sortable, ie9+
+ *
+ * Styling is done in css.
+ *
+ * Copyleft 2017 Jonas Earendel
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ *
+ */
+
+document.addEventListener('click', function (e) {
+ try {
+ // allows for elements inside TH
+ function findElementRecursive(element, tag) {
+ return element.nodeName === tag ? element : findElementRecursive(element.parentNode, tag)
+ }
+
+ var descending_th_class = ' dir-d '
+ var ascending_th_class = ' dir-u '
+ var ascending_table_sort_class = 'asc'
+ var regex_dir = / dir-(u|d) /
+ var regex_table = /\bsortable\b/
+ var alt_sort = e.shiftKey || e.altKey
+ var element = findElementRecursive(e.target, 'TH')
+ var tr = findElementRecursive(element, 'TR')
+ var table = findElementRecursive(tr, 'TABLE')
+
+ function reClassify(element, dir) {
+ element.className = element.className.replace(regex_dir, '') + dir
+ }
+
+ function getValue(element) {
+ // If you aren't using data-sort and want to make it just the tiniest bit smaller/faster
+ // comment this line and uncomment the next one
+ var value =
+ (alt_sort && element.getAttribute('data-sort-alt')) || element.getAttribute('data-sort') || element.innerText
+ return value
+ // return element.innerText
+ }
+ if (regex_table.test(table.className)) {
+ var column_index
+ var nodes = tr.cells
+
+ // Reset thead cells and get column index
+ for (var i = 0; i < nodes.length; i++) {
+ if (nodes[i] === element) {
+ column_index = element.getAttribute('data-sort-col') || i
+ } else {
+ reClassify(nodes[i], '')
+ }
+ }
+
+ var dir = descending_th_class
+
+ // Check if we're sorting ascending or descending
+ if (
+ element.className.indexOf(descending_th_class) !== -1 ||
+ (table.className.indexOf(ascending_table_sort_class) !== -1 &&
+ element.className.indexOf(ascending_th_class) == -1)
+ ) {
+ dir = ascending_th_class
+ }
+
+ // Update the `th` class accordingly
+ reClassify(element, dir)
+
+ // loop through all tbodies and sort them
+ for (var i = 0; i < table.tBodies.length; i++) {
+ const org_tbody = table.tBodies[i]
+
+ // Get the array rows in an array, so we can sort them...
+ var rows = [].slice.call(org_tbody.rows, 0)
+
+ var reverse = dir === ascending_th_class
+
+ // Sort them using Array.prototype.sort()
+ rows.sort(function (a, b) {
+ var x = getValue((reverse ? a : b).cells[column_index])
+ var y = getValue((reverse ? b : a).cells[column_index])
+ var bool = x.length && y.length && !isNaN(x - y) ? x - y : x.localeCompare(y)
+ return bool
+ })
+
+ // Make a clone without content
+ var clone_tbody = org_tbody.cloneNode()
+
+ // Fill it with the sorted values
+ while (rows.length) {
+ clone_tbody.appendChild(rows.splice(0, 1)[0])
+ }
+
+ // And finally replace the unsorted table with the sorted one
+ table.replaceChild(clone_tbody, org_tbody)
+ }
+ }
+ } catch (error) {
+ // console.log(error)
+ }
+})
diff --git a/sortable.min.css b/sortable.min.css
new file mode 100644
index 0000000..59abc45
--- /dev/null
+++ b/sortable.min.css
@@ -0,0 +1 @@
+.sortable th{cursor:pointer}.sortable th.no-sort{pointer-events:none}.sortable th::after,.sortable th::before{transition:color .1s ease-in-out;font-size:1.2em;color:rgba(0,0,0,0)}.sortable th::after{margin-left:3px;content:"▸"}.sortable th:hover::after{color:inherit}.sortable th.dir-d::after{color:inherit;content:"▾"}.sortable th.dir-u::after{color:inherit;content:"▴"}.sortable th.indicator-left::after{content:""}.sortable th.indicator-left::before{margin-right:3px;content:"▸"}.sortable th.indicator-left:hover::before{color:inherit}.sortable th.indicator-left.dir-d::before{color:inherit;content:"▾"}.sortable th.indicator-left.dir-u::before{color:inherit;content:"▴"}.sortable{--stripe-color: #e4e4e4;--th-color: #fff;--th-bg: #808080;--td-color: #000;--td-on-stripe-color: #000;border-spacing:0}.sortable tbody tr:nth-child(odd){background-color:var(--stripe-color);color:var(--td-on-stripe-color)}.sortable th{background:var(--th-bg);color:var(--th-color);font-weight:normal;text-align:left;text-transform:capitalize;vertical-align:baseline;white-space:nowrap}.sortable td{color:var(--td-color)}.sortable td,.sortable th{padding:10px}.sortable td:first-child,.sortable th:first-child{border-top-left-radius:4px}.sortable td:last-child,.sortable th:last-child{border-top-right-radius:4px}/*# sourceMappingURL=sortable.min.css.map */ \ No newline at end of file
diff --git a/sortable.min.css.map b/sortable.min.css.map
new file mode 100644
index 0000000..ec7420b
--- /dev/null
+++ b/sortable.min.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["sortable.min.css","sortable-base.scss","sortable.scss"],"names":[],"mappings":"AAAA,aCCE,cACE,CAAA,qBAEA,mBACE,CAAA,yCAEF,gCAEE,CAAA,eACA,CAAA,mBACA,CAAA,oBAGF,eACE,CAAA,WACA,CAAA,0BAGA,aACE,CAAA,0BAKF,aACE,CAAA,WACA,CAAA,0BAKF,aACE,CAAA,WACA,CAAA,mCAIF,UACE,CAAA,oCAEF,gBACE,CAAA,WACA,CAAA,0CAIA,aACE,CAAA,0CAKF,aACE,CAAA,WACA,CAAA,0CAKF,aACE,CAAA,WACA,CAAA,UC5DV,uBACE,CAAA,gBACA,CAAA,gBACA,CAAA,gBACA,CAAA,0BACA,CAAA,gBAEA,CAAA,kCAII,oCACE,CAAA,+BACA,CAAA,aAIN,uBACE,CAAA,qBACA,CAAA,kBACA,CAAA,eACA,CAAA,yBACA,CAAA,uBACA,CAAA,kBACA,CAAA,aAEF,qBACE,CAAA,0BAEF,YAEE,CAAA,kDAEA,0BACE,CAAA,gDAGF,2BACE","file":"sortable.min.css"} \ No newline at end of file
diff --git a/sortable.min.js b/sortable.min.js
new file mode 100755
index 0000000..e48fe33
--- /dev/null
+++ b/sortable.min.js
@@ -0,0 +1,2 @@
+document.addEventListener("click",function(b){try{var p=function(a){return v&&a.getAttribute("data-sort-alt")||a.getAttribute("data-sort")||a.innerText},q=function(a,c){a.className=a.className.replace(w,"")+c},g=function(a,c){return a.nodeName===c?a:g(a.parentNode,c)},w=/ dir-(u|d) /,v=b.shiftKey||b.altKey,e=g(b.target,"TH"),r=g(e,"TR"),f=g(r,"TABLE");if(/\bsortable\b/.test(f.className)){var l,d=r.cells;for(b=0;b<d.length;b++)d[b]===e?l=e.getAttribute("data-sort-col")||b:q(d[b],"");d=" dir-d ";if(-1!==
+e.className.indexOf(" dir-d ")||-1!==f.className.indexOf("asc")&&-1==e.className.indexOf(" dir-u "))d=" dir-u ";q(e,d);for(b=0;b<f.tBodies.length;b++){var m=f.tBodies[b],n=[].slice.call(m.rows,0),t=" dir-u "===d;n.sort(function(a,c){var h=p((t?a:c).cells[l]),k=p((t?c:a).cells[l]);return h.length&&k.length&&!isNaN(h-k)?h-k:h.localeCompare(k)});for(var u=m.cloneNode();n.length;)u.appendChild(n.splice(0,1)[0]);f.replaceChild(u,m)}}}catch(a){}}); \ No newline at end of file
diff --git a/sortable.scss b/sortable.scss
new file mode 100755
index 0000000..6996535
--- /dev/null
+++ b/sortable.scss
@@ -0,0 +1,44 @@
+@import 'sortable-base.scss';
+
+.sortable {
+ --stripe-color: #e4e4e4;
+ --th-color: #fff;
+ --th-bg: #808080;
+ --td-color: #000;
+ --td-on-stripe-color: #000;
+
+ border-spacing: 0;
+
+ tbody {
+ tr {
+ &:nth-child(odd) {
+ background-color: var(--stripe-color);
+ color: var(--td-on-stripe-color);
+ }
+ }
+ }
+ th {
+ background: var(--th-bg);
+ color: var(--th-color);
+ font-weight: normal;
+ text-align: left;
+ text-transform: capitalize;
+ vertical-align: baseline;
+ white-space: nowrap;
+ }
+ td {
+ color: var(--td-color);
+ }
+ td,
+ th {
+ padding: 10px;
+
+ &:first-child {
+ border-top-left-radius: 4px;
+ }
+
+ &:last-child {
+ border-top-right-radius: 4px;
+ }
+ }
+}