From 4e66c9d2a292720ce9b37405d8624b39869e58da Mon Sep 17 00:00:00 2001 From: Alex Olshansky Date: Fri, 17 Nov 2017 16:02:23 +0100 Subject: [PATCH 01/42] Fix typos in error message --- src/templater.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/templater.js b/src/templater.js index fb70ad33..ba37138f 100644 --- a/src/templater.js +++ b/src/templater.js @@ -132,7 +132,7 @@ var Templater = function(list) { return false; } if (itemSource === undefined) { - throw new Error("The list need to have at list one item on init otherwise you'll have to add a template."); + throw new Error("The list needs to have at least one item on init otherwise you'll have to add a template."); } /* If item source does not exists, use the first item in list as source for new items */ From dd5778092e4fe6decc14d7b67179b7e79a113150 Mon Sep 17 00:00:00 2001 From: Berkhan Berkdemir <24360355+BerkhanBerkdemir@users.noreply.github.com> Date: Fri, 5 Jan 2018 19:07:34 -0800 Subject: [PATCH 02/42] Update README.md Changed license date --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 72a3ab12..0abed50a 100644 --- a/README.md +++ b/README.md @@ -78,5 +78,5 @@ npm install list.js ## License (MIT) -Copyright (c) 2012-2017 Jonny Strömberg <[jonny.stromberg@gmail.com](mailto:jonny.stromberg@gmail.com)> +Copyright (c) 2011-2018 Jonny Strömberg <[jonny.stromberg@gmail.com](mailto:jonny.stromberg@gmail.com)> [http://javve.com](http://javve.com) From d17b28000eca1942c1fc5425b40f535b6806169d Mon Sep 17 00:00:00 2001 From: Berkhan Berkdemir <24360355+BerkhanBerkdemir@users.noreply.github.com> Date: Fri, 5 Jan 2018 19:08:39 -0800 Subject: [PATCH 03/42] Update LICENSE Now LICENSE is up to date. --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 20b618d1..42c01042 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2011-2014 Jonny Strömberg, jonnystromberg.com +Copyright (c) 2011-2018 Jonny Strömberg, jonnystromberg.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From ae1d45fa479e3d643836529067499bdcb9f1ab69 Mon Sep 17 00:00:00 2001 From: Jeremy Peters Date: Mon, 14 May 2018 13:58:21 +0200 Subject: [PATCH 04/42] Documentation correction --- docs/docs/fuzzysearch.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/fuzzysearch.html b/docs/docs/fuzzysearch.html index 31829c64..394305ec 100644 --- a/docs/docs/fuzzysearch.html +++ b/docs/docs/fuzzysearch.html @@ -77,10 +77,10 @@

Implementation

var listObj = new List('list-id', options); // Search manually -listObj.fuzzySearch.search('my search'); +listObj.fuzzySearch('my search'); // Search manually on specific columns -listObj.fuzzySearch.search('my search', [ 'name' ]); +listObj.fuzzySearch('my search', [ 'name' ]); </script> From 85066db9b1f160ca01ca5d22e3867912d5e23480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sun, 16 Dec 2018 20:50:16 +0100 Subject: [PATCH 05/42] Update jQuery --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 26341bbb..96ab6d12 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ }, "devDependencies": { "jest": "^18.1.0", - "jquery": "^1.12.0", + "jquery": "^1.12.4", "jshint": "^2.9.4", "jshint-loader": "^0.8.3", "webpack": "^2.2.0" From 60579c4d2b0e9c0eee375c25f8b46045245a6664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sun, 16 Dec 2018 22:17:37 +0100 Subject: [PATCH 06/42] Update Release instructions --- Release.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Release.md b/Release.md index d032027f..97e6bbfa 100644 --- a/Release.md +++ b/Release.md @@ -1,10 +1,10 @@ # RELEASE 1. Update version in package.json -2. `cp package.json docs/_data/pkg.json` -3. Commit "Version x.y.z" -4. Tag with `git tag -a v1.14.0 -m "Version 1.14.0` -5. Push with `git push` -6. Push tags with `git push --tags` -7. Update links in README.md +2. Update links in README.md +3. `cp package.json docs/_data/pkg.json` +4. Commit "Version x.y.z" +5. Tag with `git tag -a v1.14.0 -m "Version 1.14.0` +6. Push with `git push` +7. Push tags with `git push --tags` 8. `npm publish` From a12a7040c1fd6d8d15329c7d4ba1fe99930347a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sun, 16 Dec 2018 22:19:03 +0100 Subject: [PATCH 07/42] Update History.md with 1.5.1 updates --- History.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/History.md b/History.md index 855fab36..465eff8f 100644 --- a/History.md +++ b/History.md @@ -18,6 +18,14 @@ # Changelog +### 1.5.1 +- **[Website]** Use https instead of http for listjs.com +- **[Website]** Update Contribute guidelines [See commit →](https://github.com/javve/list.js/commit/6242496de2ac5c07903fb1590a5cb5129f0887a7) +- **[Website]** Update Jekyll & jQuery versions to remove security warnings. +- **[Misc]** Use one event listener per pagination and select page via data attributes + [See commit →](https://github.com/javve/list.js/commit/7610c59039f3b39f52175cd1a200e935664869e8) +- **[Bugfix]** Don't break pagination if page=0 + [See commit →](https://github.com/javve/list.js/commit/b3db0de731d436422e016b5e17f7ceab5941cd5d) ### 2017-01-29 v1.5.0 - **[Feature]** Bundle fuzzySearch and pagination plugins into List.js [See commit →](https://github.com/javve/list.js/commit/2f5322fd139ee6f30cef3bb5e15d382ff29f9489) From 56d4d99536d2ff031cea40259fcb0e01c8d07f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sun, 16 Dec 2018 23:02:31 +0100 Subject: [PATCH 08/42] Fix pagination test --- __test__/pagination.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/__test__/pagination.test.js b/__test__/pagination.test.js index 325deaf8..0c88831b 100644 --- a/__test__/pagination.test.js +++ b/__test__/pagination.test.js @@ -94,11 +94,11 @@ describe('Pagination', function() { }); it('should handle page = 0', function() { - expect(pagination.is(':visible')).toBe(true); + expect(list.listContainer.style.display).toBe(''); list.show(0, 0); - expect(pagination.is(':visible')).toBe(false); + expect(list.listContainer.style.display).toBe('none'); list.show(1, 1); - expect(pagination.is(':visible')).toBe(true); + expect(list.listContainer.style.display).toBe('block'); }); }); From 9c465e73f53de545f9a79ee520b3fe4608823a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sun, 16 Dec 2018 23:03:20 +0100 Subject: [PATCH 09/42] Add link to Stack overflow in readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 72a3ab12..19b6f16e 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,9 @@ npm install list.js - [Compressed list.js](https://raw.githubusercontent.com/javve/list.js/v1.5.0/dist/list.min.js) - [Uncompressed list.js](https://raw.githubusercontent.com/javve/list.js/v1.5.0/dist/list.js) +### Questions / How to? +https://stackoverflow.com/questions/tagged/list.js + ### Demo / Examples - [Existing list](http://listjs.com/examples/existing-list) - [Existing list + add](http://listjs.com/examples/existing-list-add) From ae3024caabe718d319b8fd35bb0e6a13858cfa50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sun, 16 Dec 2018 23:18:38 +0100 Subject: [PATCH 10/42] Update to circle ci 2 --- .circle/config.yml | 20 ++++++++++++++++++++ circle.yml | 9 --------- 2 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 .circle/config.yml delete mode 100644 circle.yml diff --git a/.circle/config.yml b/.circle/config.yml new file mode 100644 index 00000000..3b762417 --- /dev/null +++ b/.circle/config.yml @@ -0,0 +1,20 @@ +version: 2 +jobs: + build: + docker: + - image: circleci/node:6.11 +steps: + - checkout + - restore_cache: + keys: v1-dependencies-{{ checksum "package.json" }} + - run: npm install + - save_cache: + paths: + - node_modules + key: v1-dependencies-{{ checksum "package.json" }} + - run: + name: test + command: npm test + - run: + name: code-coverage + command: '<(curl -s https://codecov.io/bash)' diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 8eaa6240..00000000 --- a/circle.yml +++ /dev/null @@ -1,9 +0,0 @@ -machine: - node: - version: 6.9.1 - -test: - override: - - npm test - post: - - bash <(curl -s https://codecov.io/bash) From 4420c58564ae7ca1134a9338b82de9c9f34b5594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sun, 16 Dec 2018 23:34:46 +0100 Subject: [PATCH 11/42] Use node version 10 for circle ci --- .circle/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circle/config.yml b/.circle/config.yml index 3b762417..86a48c2b 100644 --- a/.circle/config.yml +++ b/.circle/config.yml @@ -2,7 +2,7 @@ version: 2 jobs: build: docker: - - image: circleci/node:6.11 + - image: circleci/node:10 steps: - checkout - restore_cache: From 785dc97130ddb6d095f36382039d00b7c8d1731c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Stro=CC=88mberg?= Date: Sun, 16 Dec 2018 23:40:47 +0100 Subject: [PATCH 12/42] Update node version in package.json and sync with circleci --- .circle/config.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circle/config.yml b/.circle/config.yml index 86a48c2b..da0e12e2 100644 --- a/.circle/config.yml +++ b/.circle/config.yml @@ -2,7 +2,7 @@ version: 2 jobs: build: docker: - - image: circleci/node:10 + - image: circleci/node:6.15 steps: - checkout - restore_cache: diff --git a/package.json b/package.json index 20f89db2..bcb37f8f 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ }, "main": "src/index", "engines": { - "node": ">= 0.10.21" + "node": "^6.15" }, "scripts": { "test": "jest" From 695494711652be7a153aeb8449e2283f151920b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sun, 16 Dec 2018 23:45:09 +0100 Subject: [PATCH 13/42] Correctly name circleconfig (lolz) --- {.circle => .circleci}/config.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {.circle => .circleci}/config.yml (100%) diff --git a/.circle/config.yml b/.circleci/config.yml similarity index 100% rename from .circle/config.yml rename to .circleci/config.yml From 8b8d2d92e7a08d132b960b2f519c8bd21141f075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sun, 16 Dec 2018 23:48:13 +0100 Subject: [PATCH 14/42] Validate and fix circleci config --- .circleci/config.yml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index da0e12e2..3fd24fa9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,18 +3,18 @@ jobs: build: docker: - image: circleci/node:6.15 -steps: - - checkout - - restore_cache: - keys: v1-dependencies-{{ checksum "package.json" }} - - run: npm install - - save_cache: - paths: - - node_modules - key: v1-dependencies-{{ checksum "package.json" }} - - run: - name: test - command: npm test - - run: - name: code-coverage - command: '<(curl -s https://codecov.io/bash)' + steps: + - checkout + - restore_cache: + keys: v1-dependencies-{{ checksum "package.json" }} + - run: npm install + - save_cache: + paths: + - node_modules + key: v1-dependencies-{{ checksum "package.json" }} + - run: + name: test + command: npm test + - run: + name: code-coverage + command: '<(curl -s https://codecov.io/bash)' From 5afc258fe4907400fbc7df4e1ee3270457b22e67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sun, 16 Dec 2018 23:50:10 +0100 Subject: [PATCH 15/42] Update codecov command --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3fd24fa9..79f633e0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,4 +17,4 @@ jobs: command: npm test - run: name: code-coverage - command: '<(curl -s https://codecov.io/bash)' + command: 'bash <(curl -s https://codecov.io/bash)' From b58b9fbc29c40c5e4ab69dc410f9afcfcec58ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sun, 16 Dec 2018 23:53:58 +0100 Subject: [PATCH 16/42] More circleci fixes --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 79f633e0..bdb870b7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,12 +6,12 @@ jobs: steps: - checkout - restore_cache: - keys: v1-dependencies-{{ checksum "package.json" }} + key: dependency-cache-{{ checksum "package.json" }} - run: npm install - save_cache: + key: dependency-cache-{{ checksum "package.json" }} paths: - node_modules - key: v1-dependencies-{{ checksum "package.json" }} - run: name: test command: npm test From 330c8e85dcc46e4a96252ce8c0dd047cbba6a66f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Tue, 18 Dec 2018 22:16:52 +0100 Subject: [PATCH 17/42] Fix typo --- docs/_includes/examples/annotated-example.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/_includes/examples/annotated-example.html b/docs/_includes/examples/annotated-example.html index ff1c687e..3c0b72e8 100644 --- a/docs/_includes/examples/annotated-example.html +++ b/docs/_includes/examples/annotated-example.html @@ -111,7 +111,7 @@

Apply List.js on existing HTML and then add items

} ]; -var userList = new List('example-list', options, values); +var userList = new List('users', options, values); // It's possible to add items after list been initiated userList.add({ @@ -159,7 +159,7 @@

Make List.js create a list from scratch

} ]; -var userList = new List('example-list', options, values); +var userList = new List('users', options, values); userList.add({ name: 'Gustaf Lindqvist', From 166b73c2d20d0b0941fe007c3f0545cb883f72cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Tue, 18 Dec 2018 22:49:30 +0100 Subject: [PATCH 18/42] Added a WISHLIST.md to be able to clean up in issues. --- History.md | 23 ++++------------------- WISHLIST.md | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 19 deletions(-) create mode 100644 WISHLIST.md diff --git a/History.md b/History.md index 465eff8f..ce3e3bce 100644 --- a/History.md +++ b/History.md @@ -1,31 +1,16 @@ -# TODO - -- Add tests for custom event handlers. 27e2d6fdeee7090eb1342a108013db898fc29b96 -- Regex in search https://github.com/javve/list.js/issues/371 -- Keep original order? -- Automatically add item in the right place if sort is active -- How to handle arrays? -- Implement debouncing in search? -- Better search https://github.com/javve/list.js/pull/312/files ? -- Investigate sort button defaults: - - https://github.com/javve/list.js/issues/316 - - https://github.com/javve/list.js/pull/301 -- Improve testability by decoupling things and make it possible to use require('') in tests -- Add .remove() method to remove all listeners etc. -- Example of more advanced filtering -- Fix test suite -- Example with multiple lists - # Changelog ### 1.5.1 +- **[Misc]** Added WISHLIST.md for feature requests to allow cleanup of issue list. +- **[Misc]** Update CircleCI from 1.0 to 2.0 - **[Website]** Use https instead of http for listjs.com - **[Website]** Update Contribute guidelines [See commit →](https://github.com/javve/list.js/commit/6242496de2ac5c07903fb1590a5cb5129f0887a7) - **[Website]** Update Jekyll & jQuery versions to remove security warnings. -- **[Misc]** Use one event listener per pagination and select page via data attributes +- **[Bugfix]** Use one event listener per pagination and select page via data attributes [See commit →](https://github.com/javve/list.js/commit/7610c59039f3b39f52175cd1a200e935664869e8) - **[Bugfix]** Don't break pagination if page=0 [See commit →](https://github.com/javve/list.js/commit/b3db0de731d436422e016b5e17f7ceab5941cd5d) + [See commit →](https://github.com/javve/list.js/commit/725bc188d7ba72c7d234bda1e09fc50b40661310) ### 2017-01-29 v1.5.0 - **[Feature]** Bundle fuzzySearch and pagination plugins into List.js [See commit →](https://github.com/javve/list.js/commit/2f5322fd139ee6f30cef3bb5e15d382ff29f9489) diff --git a/WISHLIST.md b/WISHLIST.md new file mode 100644 index 00000000..95ddbfd3 --- /dev/null +++ b/WISHLIST.md @@ -0,0 +1,21 @@ +# Wishlist +- Add tests for custom event handlers. 27e2d6fdeee7090eb1342a108013db898fc29b96 +- Regex in search https://github.com/javve/list.js/issues/371 +- Keep original order? + know +- Automatically add item in the right place if sort is active +- How to handle arrays? +- Implement debouncing in search? +- Better search https://github.com/javve/list.js/pull/312/files ? +- Investigate sort button defaults: + - https://github.com/javve/list.js/issues/316 + - https://github.com/javve/list.js/pull/301 +- Improve testability by decoupling things and make it possible to use require('') in tests +- Add .remove() method to remove all listeners etc. +- Example of more advanced filtering +- Example with multiple lists +- Multiple filter functionality +- Activ search term, sort order, filter, etc +- [Updated ] https://github.com/javve/list.js/issues/599 + +# Known bugs +Pagination does not respect .show(i, page) From dc6ab59c6fb21242c4bb53fa928c6901936a489c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Tue, 18 Dec 2018 23:21:35 +0100 Subject: [PATCH 19/42] Update wishlist --- WISHLIST.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WISHLIST.md b/WISHLIST.md index 95ddbfd3..afb04475 100644 --- a/WISHLIST.md +++ b/WISHLIST.md @@ -4,7 +4,7 @@ - Keep original order? + know - Automatically add item in the right place if sort is active - How to handle arrays? -- Implement debouncing in search? +- [Implement debouncing in search?](https://github.com/javve/list.js/issues/621) - Better search https://github.com/javve/list.js/pull/312/files ? - Investigate sort button defaults: - https://github.com/javve/list.js/issues/316 @@ -15,7 +15,7 @@ - Example with multiple lists - Multiple filter functionality - Activ search term, sort order, filter, etc -- [Updated ] https://github.com/javve/list.js/issues/599 +- [Smarter pagination window](https://github.com/javve/list.js/issues/599) # Known bugs Pagination does not respect .show(i, page) From 41764c772ac188167deac26483b70def51795a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Mon, 23 Dec 2019 10:00:15 +0100 Subject: [PATCH 20/42] Added OkayAnalytics.com to the web site --- docs/_layouts/default.html | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index f8b37593..d3b7eb0a 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -49,6 +49,7 @@ })(); + From 88ac583a627cad1ea3f3489903ddbdab44db1262 Mon Sep 17 00:00:00 2001 From: sheffieldnick Date: Thu, 2 Apr 2020 08:34:55 +0000 Subject: [PATCH 21/42] Add options.searchColumns to List API docs #648 --- docs/api.html | 2 ++ 1 file changed, 2 insertions(+) mode change 100644 => 100755 docs/api.html diff --git a/docs/api.html b/docs/api.html old mode 100644 new mode 100755 index 7b876afb..c3dc1d7e --- a/docs/api.html +++ b/docs/api.html @@ -121,6 +121,8 @@

What is the class of the list-container?

  • searchClass String, default: "search"
    What is the class of the search field?

  • +
  • searchColumns Array of strings, default: null
    +Restrict searching to just these column names? Default is to search all columns.

  • sortClass String, default: "sort"
    What is the class of the sort buttons?

  • indexAsync Boolean, default: false
    From 85f18b1a1dd182b1bfd1147fd7d3df7de779bb21 Mon Sep 17 00:00:00 2001 From: sheffieldnick Date: Thu, 2 Apr 2020 08:50:08 +0000 Subject: [PATCH 22/42] Fixed searchColumns default --- docs/api.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.html b/docs/api.html index c3dc1d7e..3784794d 100755 --- a/docs/api.html +++ b/docs/api.html @@ -121,7 +121,7 @@

    What is the class of the list-container?

  • searchClass String, default: "search"
    What is the class of the search field?

  • -
  • searchColumns Array of strings, default: null
    +

  • searchColumns Array of strings, default: undefined
    Restrict searching to just these column names? Default is to search all columns.

  • sortClass String, default: "sort"
    What is the class of the sort buttons?

  • From 109adc11a95e22f54994e6ee91cd9850ffc78d3e Mon Sep 17 00:00:00 2001 From: sheffieldnick Date: Thu, 2 Apr 2020 09:06:14 +0000 Subject: [PATCH 23/42] Minor fixes to doc --- docs/api.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api.html b/docs/api.html index 3784794d..2171d75a 100755 --- a/docs/api.html +++ b/docs/api.html @@ -62,11 +62,11 @@

    • - id or element *required + id or element *required
      Id the element in which the list area should be initialized. OR the actual element itself.
    • -

      options +

      options Object, default: undefined
      Some of the option parameters are required at some times

        @@ -138,7 +138,7 @@

        Read more here.

    • -
    • values Array of objects) (*optional +

    • values Array of objects, default: undefined
      Values to add to the list on initialization.

    From a22771ae4d09b037e01b6b7a4da0f15a8831a885 Mon Sep 17 00:00:00 2001 From: sheffieldnick Date: Thu, 2 Apr 2020 09:52:19 +0000 Subject: [PATCH 24/42] More minor fixes to API docs --- docs/api.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/api.html b/docs/api.html index 2171d75a..bf3fd5bf 100755 --- a/docs/api.html +++ b/docs/api.html @@ -20,6 +20,7 @@

    Options

  • page
  • pagination
  • searchClass
  • +
  • searchColumns
  • sortClass
  • valueNames
  • @@ -44,7 +45,7 @@

    Methods

  • fuzzySearch
  • get
  • on
  • -
  • reindex
  • +
  • reIndex
  • remove
  • search
  • size
  • @@ -134,7 +135,7 @@

    performance.

  • i Int, default: 1
    Which item should be shown as the first one.

  • -
  • pagination Boolean, default: false
    +

  • pagination Boolean, default: undefined
    Read more here.

  • @@ -347,7 +348,7 @@

    Methods

    Read more here

  • -

    on(event, callback)
    +

    on(event, callback)
    Execute callback when list have been updated (triggered by update(), which is used by a lot of methods). Use updated as the event.

    Avaliable events

      From e12d13744745beea1564b52202d9d890b17c10bf Mon Sep 17 00:00:00 2001 From: sheffieldnick Date: Thu, 2 Apr 2020 10:18:15 +0000 Subject: [PATCH 25/42] Added custom search function to List API doc - closes #678 --- docs/api.html | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/api.html b/docs/api.html index bf3fd5bf..cae012cf 100755 --- a/docs/api.html +++ b/docs/api.html @@ -272,7 +272,7 @@

      Methods

    • -

      search(searchString, columns)
      +

      search(searchString, columns, searchFunction)
      Searches the list

      itemsInList = [
      @@ -285,7 +285,20 @@ 

      Methods

      listObj.search(); // Show all items in list -listObj.search('Jonny', ['name']); // Only search in the 'name' column
      +listObj.search('Jonny', ['name']); // Only search in the 'name' column + +listObj.search('Jonny', searchFunction); // Custom search for Jonny + +listObj.search('Jonny', ['name'], searchFunction); // Custom search in the 'name' column +

      The optional searchFunction should be of the form:

      + +
      function searchFunction(searchString, columns) {
      +  for (var k = 0, kl = listObj.items.length; k < kl; k++) {
      +     listObj.items[k].found = false;
      +     // Insert your custom search logic here, set found = true
      +
      +  }
      +};
    • From 389b9dcb944836152f2d8827f661c99d37c9f347 Mon Sep 17 00:00:00 2001 From: sheffieldnick Date: Thu, 2 Apr 2020 13:39:08 +0000 Subject: [PATCH 26/42] Multiple word searching with List.search - closes #680 --- src/search.js | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) mode change 100644 => 100755 src/search.js diff --git a/src/search.js b/src/search.js old mode 100644 new mode 100755 index f7b0b6db..52e585d8 --- a/src/search.js +++ b/src/search.js @@ -45,28 +45,40 @@ module.exports = function(list) { }; var search = { list: function() { + // Extract quoted phrases "word1 word2" from original searchString + // searchString is converted to lowercase by List.js + var words = [], phrase, ss = searchString; + while ((phrase = ss.match(/"([^"]+)"/)) !== null) { + words.push(phrase[1]); + ss = ss.substring(0,phrase.index) + ss.substring(phrase.index+phrase[0].length); + }; + // Get remaining space-separated words (if any) + ss = ss.trim(); + if (ss.length) words = words.concat(ss.split(/\s+/)); for (var k = 0, kl = list.items.length; k < kl; k++) { - search.item(list.items[k]); - } - }, - item: function(item) { - item.found = false; - for (var j = 0, jl = columns.length; j < jl; j++) { - if (search.values(item.values(), columns[j])) { - item.found = true; - return; - } - } - }, - values: function(values, column) { - if (values.hasOwnProperty(column)) { - text = list.utils.toString(values[column]).toLowerCase(); - if ((searchString !== "") && (text.search(searchString) > -1)) { - return true; + var item = list.items[k]; + item.found = false; + if (!words.length) continue; + for (var i = 0, il = words.length; i < il; i++) { + var word_found = false; + for (var j = 0, jl = columns.length; j < jl; j++) { + var values = item.values(), column = columns[j]; + if (values.hasOwnProperty(column) && values[column] !== undefined && values[column] !== null) { + var text = (typeof values[column] !== 'string') ? values[column].toString() : values[column]; + if (text.toLowerCase().indexOf(words[i]) !== -1) { + // word found, so no need to check it against any other columns + word_found = true; + break; + } + } + } + // this word not found? no need to check any other words, the item cannot match + if (!word_found) break; } + item.found = word_found; } - return false; }, + // Removed search.item() and search.values() reset: function() { list.reset.search(); list.searched = false; From 5a8c19beb5ea6f80bd5cc959128c53c90ee80130 Mon Sep 17 00:00:00 2001 From: sheffieldnick Date: Thu, 2 Apr 2020 14:29:54 +0000 Subject: [PATCH 27/42] Multiple word searching documented in List API --- docs/api.html | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/api.html b/docs/api.html index cae012cf..b7210ceb 100755 --- a/docs/api.html +++ b/docs/api.html @@ -276,23 +276,32 @@

      Methods

      Searches the list

      itemsInList = [
      -{ id: 1, name: "Jonny" }
      -, { id: 2, name "Gustaf" }
      -, { id: 3, name "Jonas" }
      +{ id: 1, name: "Jonny Stromberg", born: 1986 }
      +, { id: 2, name "Jonas Arnklint", born: 1985 }
      +, { id: 3, name "Martina Elm", born: 1986 }
      +, { id: 4, name "Gustaf Lindqvist", born: 1983 }
      +, { id: 5, name "Jonny Strandberg", born: 1990 }
       ];
       
      -listObj.search('Jonny'); // Only item with name Jonny is shown (also returns this item)
      +listObj.search('Jonny'); // Only items with name Jonny are shown (also returns these items)
       
       listObj.search(); // Show all items in list
       
      -listObj.search('Jonny', ['name']); // Only search in the 'name' column
      +listObj.search('Jonny', ['name']); // Only search in the 'name' column
      + +

      Space-separated words match in any order using logical AND. Surround a phrase in quotes for exact matches:

      + +
      listObj.search('Jon 198'); // Items that match Jon AND 198
      +
      +listObj.search('"Jonny S" 1990'); // Items that match "Jonny S" AND 1990
      + +

      Optionally your own search function can be used:

      -listObj.search('Jonny', searchFunction); // Custom search for Jonny +
      listObj.search('Jonny', searchFunction); // Custom search for Jonny
       
      -listObj.search('Jonny', ['name'], searchFunction); // Custom search in the 'name' column
      -

      The optional searchFunction should be of the form:

      +listObj.search('Jonny', ['name'], searchFunction); // Custom search in the 'name' column -
      function searchFunction(searchString, columns) {
      +function searchFunction(searchString, columns) {
         for (var k = 0, kl = listObj.items.length; k < kl; k++) {
            listObj.items[k].found = false;
            // Insert your custom search logic here, set found = true
      
      From ec685e7b4f55928592573a859be57faeede960ca Mon Sep 17 00:00:00 2001
      From: sheffieldnick 
      Date: Thu, 2 Apr 2020 15:22:37 +0000
      Subject: [PATCH 28/42] Added test units for multi-word and quoted phrase
       searches
      
      ---
       __test__/search.test.js | 48 ++++++++++++++++++++++++++++++++++++++---
       1 file changed, 45 insertions(+), 3 deletions(-)
       mode change 100644 => 100755 __test__/search.test.js
      
      diff --git a/__test__/search.test.js b/__test__/search.test.js
      old mode 100644
      new mode 100755
      index 6139b49a..8c62684e
      --- a/__test__/search.test.js
      +++ b/__test__/search.test.js
      @@ -109,7 +109,7 @@ describe('Search', function() {
         });
       
       
      -  describe('Specfic columns', function() {
      +  describe('Specific columns', function() {
           it('should find match in column', function() {
             var result = list.search('jonny', [ 'name' ]);
             expect(result.length).toEqual(1);
      @@ -128,11 +128,11 @@ describe('Search', function() {
             var result = list.search('jonny', [ 'born' ]);
             expect(result.length).toEqual(0);
           });
      -    it('should work with columns that does not exist', function() {
      +    it('should work with columns that do not exist', function() {
             var result = list.search('jonny', [ 'pet' ]);
             expect(result.length).toEqual(0);
           });
      -    it('should remove columnm option', function() {
      +    it('should remove column option', function() {
             var result = list.search('jonny', [ 'born' ]);
             expect(result.length).toEqual(0);
             result = list.search('jonny');
      @@ -157,6 +157,48 @@ describe('Search', function() {
             expect(result.length).toEqual(4);
           });
         });
      +
      +  describe('Multiple word search', function() {
      +    it('should find jonny, hasse', function() {
      +      var result = list.search('berg str');
      +      expect(result.length).toEqual(2);
      +      expect(jonny.matching()).toBe(true);
      +      expect(martina.matching()).toBe(false);
      +      expect(angelica.matching()).toBe(false);
      +      expect(sebastian.matching()).toBe(false);
      +      expect(imma.matching()).toBe(false);
      +      expect(hasse.matching()).toBe(true);
      +    });
      +    it('should find martina, angelica, sebastian, hasse', function() {
      +      var result = list.search('a e');
      +      expect(result.length).toEqual(4);
      +      expect(jonny.matching()).toBe(false);
      +      expect(martina.matching()).toBe(true);
      +      expect(angelica.matching()).toBe(true);
      +      expect(sebastian.matching()).toBe(true);
      +      expect(imma.matching()).toBe(false);
      +      expect(hasse.matching()).toBe(true);
      +    });
      +    it('stripping whitespace should find martina', function() {
      +      var result = list.search('martina  elm ');
      +      expect(result.length).toEqual(1);
      +      expect(result[0]).toEqual(martina);
      +    });
      +  });
      +
      +  describe('Quoted phrase searches', function() {
      +    it('should find martina', function() {
      +      var result = list.search('"a e"');
      +      expect(result.length).toEqual(1);
      +      expect(result[0]).toEqual(martina);
      +    });
      +    it('quoted phrase and multiple words should find jonny', function() {
      +      var result = list.search('" str" 1986');
      +      expect(result.length).toEqual(1);
      +      expect(result[0]).toEqual(jonny);
      +    });
      +  });
      +
         //
         // describe('Special characters', function() {
         //   it('should escape and handle special characters', function() {
      
      From 4a8c40f050ecd087189dd7a39556ba891c32f302 Mon Sep 17 00:00:00 2001
      From: sheffieldnick 
      Date: Thu, 2 Apr 2020 18:02:10 +0000
      Subject: [PATCH 29/42] Generic debounce wrapper added to utils/events.js
      
      ---
       src/utils/events.js | 27 +++++++++++++++++++++++++++
       1 file changed, 27 insertions(+)
       mode change 100644 => 100755 src/utils/events.js
      
      diff --git a/src/utils/events.js b/src/utils/events.js
      old mode 100644
      new mode 100755
      index 21695985..63a14e92
      --- a/src/utils/events.js
      +++ b/src/utils/events.js
      @@ -36,3 +36,30 @@ exports.unbind = function(el, type, fn, capture){
           el[i][unbind](prefix + type, fn, capture || false);
         }
       };
      +
      +/**
      + * Returns a function, that, as long as it continues to be invoked, will not
      + * be triggered. The function will be called after it stops being called for
      + * `wait` milliseconds. If `immediate` is true, trigger the function on the
      + * leading edge, instead of the trailing.
      + *
      + * @param {Function} fn
      + * @param {Integer} wait
      + * @param {Boolean} immediate
      + * @api public
      + */
      +
      +exports.debounce = function(fn, wait, immediate){
      +  var timeout;
      +	return function() {
      +		var context = this, args = arguments;
      +		var later = function() {
      +			timeout = null;
      +			if (!immediate) fn.apply(context, args);
      +		};
      +		var callNow = immediate && !timeout;
      +		clearTimeout(timeout);
      +		timeout = setTimeout(later, wait);
      +		if (callNow) fn.apply(context, args);
      +	};  
      +};
      
      From bc88b0bcbc0d5501aecaac5c423de2f317487954 Mon Sep 17 00:00:00 2001
      From: sheffieldnick 
      Date: Thu, 2 Apr 2020 20:43:39 +0000
      Subject: [PATCH 30/42] Debounce keyup handler for search and fuzzySearch. Wait
       for 750ms inactivity makes searching far more usable with very large lists
       and/or slow devices
      
      ---
       src/fuzzy-search.js | 4 ++--
       src/search.js       | 4 ++--
       2 files changed, 4 insertions(+), 4 deletions(-)
       mode change 100644 => 100755 src/fuzzy-search.js
      
      diff --git a/src/fuzzy-search.js b/src/fuzzy-search.js
      old mode 100644
      new mode 100755
      index ac49dfa1..1852526a
      --- a/src/fuzzy-search.js
      +++ b/src/fuzzy-search.js
      @@ -56,10 +56,10 @@ module.exports = function(list, options) {
         };
       
       
      -  events.bind(getByClass(list.listContainer, options.searchClass), 'keyup', function(e) {
      +  events.bind(getByClass(list.listContainer, options.searchClass), 'keyup', list.utils.events.debounce(function(e) {
           var target = e.target || e.srcElement; // IE have srcElement
           list.search(target.value, fuzzySearch.search);
      -  });
      +  }, 750));
       
         return function(str, columns) {
           list.search(str, columns, fuzzySearch.search);
      diff --git a/src/search.js b/src/search.js
      index 52e585d8..f4c355da 100755
      --- a/src/search.js
      +++ b/src/search.js
      @@ -112,13 +112,13 @@ module.exports = function(list) {
         list.handlers.searchStart = list.handlers.searchStart || [];
         list.handlers.searchComplete = list.handlers.searchComplete || [];
       
      -  list.utils.events.bind(list.utils.getByClass(list.listContainer, list.searchClass), 'keyup', function(e) {
      +  list.utils.events.bind(list.utils.getByClass(list.listContainer, list.searchClass), 'keyup', list.utils.events.debounce(function(e) {
           var target = e.target || e.srcElement, // IE have srcElement
             alreadyCleared = (target.value === "" && !list.searched);
           if (!alreadyCleared) { // If oninput already have resetted the list, do nothing
             searchMethod(target.value);
           }
      -  });
      +  }, 750));
       
         // Used to detect click on HTML5 clear button
         list.utils.events.bind(list.utils.getByClass(list.listContainer, list.searchClass), 'input', function(e) {
      
      From 071b1a72582fbeaeb1037a9d0e63a11c96851417 Mon Sep 17 00:00:00 2001
      From: sheffieldnick 
      Date: Fri, 3 Apr 2020 09:17:30 +0000
      Subject: [PATCH 31/42] New List option searchDelay to control debounce in
       search keypress, default 0. Updated API doc
      
      ---
       docs/api.html       | 3 +++
       src/fuzzy-search.js | 2 +-
       src/index.js        | 1 +
       src/search.js       | 2 +-
       src/utils/events.js | 4 ++--
       5 files changed, 8 insertions(+), 4 deletions(-)
       mode change 100644 => 100755 src/index.js
      
      diff --git a/docs/api.html b/docs/api.html
      index b7210ceb..9c71aec3 100755
      --- a/docs/api.html
      +++ b/docs/api.html
      @@ -21,6 +21,7 @@ 

      Options

    • pagination
    • searchClass
    • searchColumns
    • +
    • searchDelay
    • sortClass
    • valueNames
    @@ -124,6 +125,8 @@

    What is the class of the search field?

  • searchColumns Array of strings, default: undefined
    Restrict searching to just these column names? Default is to search all columns.

  • +
  • searchDelay Int default: 0
    +Delay in milliseconds after last keypress in search field before search starts. 250→750 is good for very large lists.

  • sortClass String, default: "sort"
    What is the class of the sort buttons?

  • indexAsync Boolean, default: false
    diff --git a/src/fuzzy-search.js b/src/fuzzy-search.js index 1852526a..77f9f4f4 100755 --- a/src/fuzzy-search.js +++ b/src/fuzzy-search.js @@ -59,7 +59,7 @@ module.exports = function(list, options) { events.bind(getByClass(list.listContainer, options.searchClass), 'keyup', list.utils.events.debounce(function(e) { var target = e.target || e.srcElement; // IE have srcElement list.search(target.value, fuzzySearch.search); - }, 750)); + }, list.searchDelay)); return function(str, columns) { list.search(str, columns, fuzzySearch.search); diff --git a/src/index.js b/src/index.js old mode 100644 new mode 100755 index 887019ff..5004e912 --- a/src/index.js +++ b/src/index.js @@ -29,6 +29,7 @@ module.exports = function(id, options, values) { self.searched = false; self.filtered = false; self.searchColumns = undefined; + self.searchDelay = 0; self.handlers = { 'updated': [] }; self.valueNames = []; self.utils = { diff --git a/src/search.js b/src/search.js index f4c355da..f3d98250 100755 --- a/src/search.js +++ b/src/search.js @@ -118,7 +118,7 @@ module.exports = function(list) { if (!alreadyCleared) { // If oninput already have resetted the list, do nothing searchMethod(target.value); } - }, 750)); + }, list.searchDelay)); // Used to detect click on HTML5 clear button list.utils.events.bind(list.utils.getByClass(list.listContainer, list.searchClass), 'input', function(e) { diff --git a/src/utils/events.js b/src/utils/events.js index 63a14e92..85903198 100755 --- a/src/utils/events.js +++ b/src/utils/events.js @@ -51,7 +51,7 @@ exports.unbind = function(el, type, fn, capture){ exports.debounce = function(fn, wait, immediate){ var timeout; - return function() { + return wait ? function() { var context = this, args = arguments; var later = function() { timeout = null; @@ -61,5 +61,5 @@ exports.debounce = function(fn, wait, immediate){ clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) fn.apply(context, args); - }; + } : fn; }; From 0c90d04d454281f4407cbf1e6c00ac35620cb3d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sun, 22 Nov 2020 14:15:26 +0100 Subject: [PATCH 32/42] Move all existing tests to /integration --- __test__/create.test.js | 303 ----------------- .../{ => integration}/add-get-remove.test.js | 0 __test__/{ => integration}/buttons.test.js | 2 +- __test__/integration/create.test.js | 315 ++++++++++++++++++ __test__/{ => integration}/defaults.test.js | 0 __test__/{ => integration}/filter.test.js | 0 .../{ => integration}/fixtures-fuzzysearch.js | 0 .../{ => integration}/fixtures-pagination.js | 0 __test__/{ => integration}/fixtures.js | 2 +- .../{ => integration}/fuzzysearch.test.js | 2 +- __test__/{ => integration}/item.test.js | 0 __test__/{ => integration}/off.test.js | 0 __test__/{ => integration}/on.test.js | 0 __test__/{ => integration}/pagination.test.js | 2 +- __test__/{ => integration}/parse.test.js | 2 +- __test__/{ => integration}/re-index.test.js | 0 .../{ => integration}/search-filter.test.js | 0 __test__/{ => integration}/search.test.js | 0 __test__/{ => integration}/show.test.js | 0 __test__/{ => integration}/sort.test.js | 0 __test__/{ => integration}/trigger.test.js | 0 .../{ => integration}/utils.classes.test.js | 2 +- .../utils.get-by-class.test.js | 2 +- 23 files changed, 322 insertions(+), 310 deletions(-) delete mode 100644 __test__/create.test.js rename __test__/{ => integration}/add-get-remove.test.js (100%) rename __test__/{ => integration}/buttons.test.js (99%) create mode 100644 __test__/integration/create.test.js rename __test__/{ => integration}/defaults.test.js (100%) rename __test__/{ => integration}/filter.test.js (100%) rename __test__/{ => integration}/fixtures-fuzzysearch.js (100%) rename __test__/{ => integration}/fixtures-pagination.js (100%) rename __test__/{ => integration}/fixtures.js (96%) rename __test__/{ => integration}/fuzzysearch.test.js (98%) rename __test__/{ => integration}/item.test.js (100%) rename __test__/{ => integration}/off.test.js (100%) rename __test__/{ => integration}/on.test.js (100%) rename __test__/{ => integration}/pagination.test.js (99%) rename __test__/{ => integration}/parse.test.js (99%) rename __test__/{ => integration}/re-index.test.js (100%) rename __test__/{ => integration}/search-filter.test.js (100%) rename __test__/{ => integration}/search.test.js (100%) rename __test__/{ => integration}/show.test.js (100%) rename __test__/{ => integration}/sort.test.js (100%) rename __test__/{ => integration}/trigger.test.js (100%) rename __test__/{ => integration}/utils.classes.test.js (96%) rename __test__/{ => integration}/utils.get-by-class.test.js (92%) diff --git a/__test__/create.test.js b/__test__/create.test.js deleted file mode 100644 index bae4c927..00000000 --- a/__test__/create.test.js +++ /dev/null @@ -1,303 +0,0 @@ -const $ = require('jquery'), - List = require('../src/index') - -describe('Create', function () { - describe('With HTML items', function () { - var listEl = $( - '

    \ -
      \ -
    • Jonny
    • \ -
    \ -
    ' - ) - - $(document.body).append(listEl) - - var list = new List('list', { valueNames: ['name'] }) - - it('should contain one item', function () { - expect(list.items.length).toEqual(1) - expect(listEl.find('li').length).toEqual(1) - }) - - it('should contain two items', function () { - list.add({ name: 'Jonas' }) - expect(list.items.length).toEqual(2) - expect(listEl.find('li').length).toEqual(2) - }) - - listEl.remove() - }) - - describe('With and element instead of id', function () { - var listEl = $( - '
    \ -
      \ -
    • Jonny
    • \ -
    \ -
    ' - ) - - $(document.body).append(listEl) - var el = document.getElementById('list') - - var list = new List(el, { valueNames: ['name'] }) - - it('should contain one item', function () { - expect(list.items.length).toEqual(1) - expect(listEl.find('li').length).toEqual(1) - }) - - listEl.remove() - }) - - describe('Without items and with string template', function () { - var listEl = $('
    \ -
      \ -
      ') - - $(document.body).append(listEl) - - var list = new List( - 'list', - { - valueNames: ['name'], - item: '
    • ', - }, - [{ name: 'Jonny' }] - ) - - it('should contain one item', function () { - expect(list.items.length).toEqual(1) - expect(listEl.find('li').length).toEqual(1) - }) - - it('should contain two items', function () { - list.add({ name: 'Jonas' }) - expect(list.items.length).toEqual(2) - expect(listEl.find('li').length).toEqual(2) - }) - - listEl.remove() - }) - - describe('Without items and with string template for table', function () { - var listEl = $('
      \ -
      \ -
      ') - - $(document.body).append(listEl) - - var list = new List( - 'list', - { - valueNames: ['name'], - item: '', - }, - [{ name: 'Jonny' }] - ) - - it('should contain one item', function () { - expect(list.items.length).toEqual(1) - expect(listEl.find('tr').length).toEqual(1) - }) - - it('should contain two items', function () { - list.add({ name: 'Jonas' }) - expect(list.items.length).toEqual(2) - expect(listEl.find('tr').length).toEqual(2) - }) - - listEl.remove() - }) - - describe('Without items and with template function', function () { - var listEl = $('
      \ -
        \ -
        ') - - $(document.body).append(listEl) - - var list = new List( - 'list', - { - valueNames: ['name'], - item: function (values) { - return `
      • ` - }, - }, - [{ name: 'Jonny' }] - ) - - it('should contain one item', function () { - expect(list.items.length).toEqual(1) - expect(listEl.find('li').length).toEqual(1) - }) - - it('should contain two items', function () { - list.add({ name: 'Jonas' }) - expect(list.items.length).toEqual(2) - expect(listEl.find('li').length).toEqual(2) - }) - - it('should get values from items', function () { - list.add({ name: 'Egon' }) - expect(listEl.find('li[data-template-fn-egon]').length).toEqual(1) - }) - - listEl.remove() - }) - - describe('without items and or template', function () { - it('should throw error on init', function () { - var listEl = $('
        \ -
          \ -
          ') - $(document.body).append(listEl) - - expect(function () { - var list = new List('list', { - valueNames: ['name'], - }) - }).toThrow() - listEl.remove() - }) - }) - - describe('Without items and with HTML template', function () { - var listEl = $('
          \ -
            \ -
            ') - - var templateEl = $('
          • ') - - $(document.body).append(listEl) - $(document.body).append(templateEl) - - var list = new List( - 'list', - { - valueNames: ['name'], - item: 'template-item', - }, - [{ name: 'Jonny' }] - ) - - it('should contain one item', function () { - expect(list.items.length).toEqual(1) - expect(listEl.find('li').length).toEqual(1) - }) - - it('should contain two items', function () { - list.add({ name: 'Jonas' }) - expect(list.items.length).toEqual(2) - expect(listEl.find('li').length).toEqual(2) - }) - - listEl.remove() - templateEl.remove() - }) - - describe('Asyn index with existing list', function () { - var listEl = $( - '
            \ -
              \ -
            • Jonny
            • Sven
            • \ -
            • Anna
            • Lisa
            • \ -
            • Egon
            • Frida
            • \ -
            • Maj-britt
            • Fredrik
            • \ -
            • Torbjorn
            • Lolzor
            • \ -
            • Sandra
            • Gottfrid
            • \ -
            • Tobias
            • Martina
            • \ -
            • Johannes
            • Ted
            • \ -
            • Malin
            • Filippa
            • \ -
            • Imma
            • Hasse
            • \ -
            • Robert
            • Mona
            • \ -
            • Anna
            • Lisa
            • \ -
            • Egon
            • Frida
            • \ -
            • Maj-britt
            • Fredrik
            • \ -
            • Torbjorn
            • Lolzor
            • \ -
            • Sandra
            • Gottfrid
            • \ -
            • Tobias
            • Martina
            • \ -
            • Johannes
            • Ted
            • \ -
            • Malin
            • Filippa
            • \ -
            • Imma
            • Hasse
            • \ -
            • Robert
            • Mona
            • \ -
            • Anna
            • Lisa
            • \ -
            • Egon
            • Frida
            • \ -
            • Maj-britt
            • Fredrik
            • \ -
            • Torbjorn
            • Lolzor
            • \ -
            • Sandra
            • Gottfrid
            • \ -
            • Tobias
            • Martina
            • \ -
            • Johannes
            • Ted
            • \ -
            • Malin
            • Filippa
            • \ -
            • Imma
            • Hasse
            • \ -
            • Robert
            • Mona
            • \ -
            • Anna
            • Lisa
            • \ -
            • Egon
            • Frida
            • \ -
            • Maj-britt
            • Fredrik
            • \ -
            • Torbjorn
            • Lolzor
            • \ -
            • Sandra
            • Gottfrid
            • \ -
            • Tobias
            • Martina
            • \ -
            • Johannes
            • Ted
            • \ -
            • Malin
            • Filippa
            • \ -
            • Imma
            • Hasse
            • \ -
            • Robert
            • Mona
            • \ -
            • Anna
            • Lisa
            • \ -
            • Egon
            • Frida
            • \ -
            • Maj-britt
            • Fredrik
            • \ -
            • Torbjorn
            • Lolzor
            • \ -
            • Sandra
            • Gottfrid
            • \ -
            • Tobias
            • Martina
            • \ -
            • Johannes
            • Ted
            • \ -
            • Malin
            • Filippa
            • \ -
            • Imma
            • Hasse
            • \ -
            • Robert
            • Mona
            • \ -
            • Anna
            • Lisa
            • \ -
            • Egon
            • Frida
            • \ -
            • Maj-britt
            • Fredrik
            • \ -
            • Torbjorn
            • Lolzor
            • \ -
            • Sandra
            • Gottfrid
            • \ -
            • Tobias
            • Martina
            • \ -
            • Johannes
            • Ted
            • \ -
            • Malin
            • Filippa
            • \ -
            • Imma
            • Hasse
            • \ -
            • Robert
            • Mona
            • \ -
            • Anna
            • Lisa
            • \ -
            • Egon
            • Frida
            • \ -
            • Maj-britt
            • Fredrik
            • \ -
            • Torbjorn
            • Lolzor
            • \ -
            • Sandra
            • Gottfrid
            • \ -
            • Tobias
            • Martina
            • \ -
            • Johannes
            • Ted
            • \ -
            • Malin
            • Filippa
            • \ -
            • Imma
            • Hasse
            • \ -
            • Robert
            • Mona
            • \ -
            • Anna
            • Lisa
            • \ -
            • Egon
            • Frida
            • \ -
            • Maj-britt
            • Fredrik
            • \ -
            • Torbjorn
            • Lolzor
            • \ -
            • Sandra
            • Gottfrid
            • \ -
            • Tobias
            • Martina
            • \ -
            • Johannes
            • Ted
            • \ -
            • Malin
            • Filippa
            • \ -
            • Imma
            • Hasse
            • \ -
            • Robert
            • Mona
            • \ -
            \ -
            ' - ) - - it('should contain one item', function (done) { - $(document.body).append(listEl) - var list = new List('list', { - valueNames: ['name'], - indexAsync: true, - parseComplete: function (list) { - expect(listEl.find('li').length).toEqual(162) - listEl.remove() - done() - }, - }) - }) - }) -}) diff --git a/__test__/add-get-remove.test.js b/__test__/integration/add-get-remove.test.js similarity index 100% rename from __test__/add-get-remove.test.js rename to __test__/integration/add-get-remove.test.js diff --git a/__test__/buttons.test.js b/__test__/integration/buttons.test.js similarity index 99% rename from __test__/buttons.test.js rename to __test__/integration/buttons.test.js index 2165579e..ca6103fa 100644 --- a/__test__/buttons.test.js +++ b/__test__/integration/buttons.test.js @@ -1,5 +1,5 @@ const $ = require('jquery'), - List = require('../src/index') + List = require('../../src/index') function fireKeyup(el) { if (document.createEvent) { diff --git a/__test__/integration/create.test.js b/__test__/integration/create.test.js new file mode 100644 index 00000000..8a353fbb --- /dev/null +++ b/__test__/integration/create.test.js @@ -0,0 +1,315 @@ +const $ = require('jquery') +const List = require('../../src/index') + +describe('Create', () => { + describe('With HTML items', () => { + let list, listEl + beforeEach(function () { + listEl = $(` +
            +
              +
            • Jonny
            • +
            +
            + `) + $(document.body).append(listEl) + list = new List('list', { valueNames: ['name'] }) + }) + afterEach(() => { + listEl.remove() + }) + + it('should contain one item', () => { + expect(list.items.length).toEqual(1) + expect(listEl.find('li').length).toEqual(1) + }) + + it('should contain two items', () => { + list.add({ name: 'Jonas' }) + expect(list.items.length).toEqual(2) + expect(listEl.find('li').length).toEqual(2) + }) + }) + + describe('With and element instead of id', () => { + var listEl, list + beforeEach(() => { + listEl = $(` +
            +
              +
            • Jonny
            • +
            +
            + `) + $(document.body).append(listEl) + var el = document.getElementById('list') + list = new List(el, { valueNames: ['name'] }) + }) + afterEach(() => { + listEl.remove() + }) + + it('should contain one item', () => { + expect(list.items.length).toEqual(1) + expect(listEl.find('li').length).toEqual(1) + }) + }) + + describe('Without items and with string template', () => { + var listEl, list + beforeEach(() => { + listEl = $('
            \ +
              \ +
              ') + $(document.body).append(listEl) + list = new List( + 'list', + { + valueNames: ['name'], + item: '
            • ', + }, + [{ name: 'Jonny' }] + ) + }) + afterEach(() => { + listEl.remove() + }) + + it('should contain one item', () => { + expect(list.items.length).toEqual(1) + expect(listEl.find('li').length).toEqual(1) + }) + + it('should contain two items', () => { + list.add({ name: 'Jonas' }) + expect(list.items.length).toEqual(2) + expect(listEl.find('li').length).toEqual(2) + }) + }) + + describe('Without items and with string template for table', () => { + var listEl, list + + beforeEach(() => { + listEl = $(` +
              +
              +
              + `) + $(document.body).append(listEl) + list = new List( + 'list', + { + valueNames: ['name'], + item: '', + }, + [{ name: 'Jonny' }] + ) + }) + + afterEach(() => { + listEl.remove() + }) + + it('should contain one item', () => { + expect(list.items.length).toEqual(1) + expect(listEl.find('tr').length).toEqual(1) + }) + + it('should contain two items', () => { + list.add({ name: 'Jonas' }) + expect(list.items.length).toEqual(2) + expect(listEl.find('tr').length).toEqual(2) + }) + }) + + describe('Without items and with template function', () => { + var listEl, list + beforeEach(() => { + listEl = $('
                ') + $(document.body).append(listEl) + list = new List( + 'list', + { + valueNames: ['name'], + item: function (values) { + return `
              • ` + }, + }, + [{ name: 'Jonny' }] + ) + }) + afterEach(() => { + listEl.remove() + }) + + it('should contain one item', () => { + expect(list.items.length).toEqual(1) + expect(listEl.find('li').length).toEqual(1) + }) + + it('should contain two items', () => { + list.add({ name: 'Jonas' }) + expect(list.items.length).toEqual(2) + expect(listEl.find('li').length).toEqual(2) + }) + + it('should get values from items', () => { + list.add({ name: 'Egon' }) + expect(listEl.find('li[data-template-fn-egon]').length).toEqual(1) + }) + }) + + describe('without items and or template', () => { + it('should throw error on init', () => { + var listEl = $('
                  ') + $(document.body).append(listEl) + + expect(() => { + var list = new List('list', { + valueNames: ['name'], + }) + }).toThrow() + + listEl.remove() + }) + }) + + describe('Without items and with HTML template', () => { + var listEl, list, templateEl + beforeEach(() => { + listEl = $('
                    ') + + templateEl = $('
                  • ') + + $(document.body).append(listEl) + $(document.body).append(templateEl) + + list = new List( + 'list', + { + valueNames: ['name'], + item: 'template-item', + }, + [{ name: 'Jonny' }] + ) + }) + afterEach(() => { + listEl.remove() + templateEl.remove() + }) + + it('should contain one item', () => { + expect(list.items.length).toEqual(1) + expect(listEl.find('li').length).toEqual(1) + }) + + it('should contain two items', () => { + list.add({ name: 'Jonas' }) + expect(list.items.length).toEqual(2) + expect(listEl.find('li').length).toEqual(2) + }) + }) + + describe('Asyn index with existing list', () => { + it('should contain 162 items', (done) => { + var listEl = $(` +
                    +
                      +
                    • Jonny
                    • Sven
                    • +
                    • Anna
                    • Lisa
                    • +
                    • Egon
                    • Frida
                    • +
                    • Maj-britt
                    • Fredrik
                    • +
                    • Torbjorn
                    • Lolzor
                    • +
                    • Sandra
                    • Gottfrid
                    • +
                    • Tobias
                    • Martina
                    • +
                    • Johannes
                    • Ted
                    • +
                    • Malin
                    • Filippa
                    • +
                    • Imma
                    • Hasse
                    • +
                    • Robert
                    • Mona
                    • +
                    • Anna
                    • Lisa
                    • +
                    • Egon
                    • Frida
                    • +
                    • Maj-britt
                    • Fredrik
                    • +
                    • Torbjorn
                    • Lolzor
                    • +
                    • Sandra
                    • Gottfrid
                    • +
                    • Tobias
                    • Martina
                    • +
                    • Johannes
                    • Ted
                    • +
                    • Malin
                    • Filippa
                    • +
                    • Imma
                    • Hasse
                    • +
                    • Robert
                    • Mona
                    • +
                    • Anna
                    • Lisa
                    • +
                    • Egon
                    • Frida
                    • +
                    • Maj-britt
                    • Fredrik
                    • +
                    • Torbjorn
                    • Lolzor
                    • +
                    • Sandra
                    • Gottfrid
                    • +
                    • Tobias
                    • Martina
                    • +
                    • Johannes
                    • Ted
                    • +
                    • Malin
                    • Filippa
                    • +
                    • Imma
                    • Hasse
                    • +
                    • Robert
                    • Mona
                    • +
                    • Anna
                    • Lisa
                    • +
                    • Egon
                    • Frida
                    • +
                    • Maj-britt
                    • Fredrik
                    • +
                    • Torbjorn
                    • Lolzor
                    • +
                    • Sandra
                    • Gottfrid
                    • +
                    • Tobias
                    • Martina
                    • +
                    • Johannes
                    • Ted
                    • +
                    • Malin
                    • Filippa
                    • +
                    • Imma
                    • Hasse
                    • +
                    • Robert
                    • Mona
                    • +
                    • Anna
                    • Lisa
                    • +
                    • Egon
                    • Frida
                    • +
                    • Maj-britt
                    • Fredrik
                    • +
                    • Torbjorn
                    • Lolzor
                    • +
                    • Sandra
                    • Gottfrid
                    • +
                    • Tobias
                    • Martina
                    • +
                    • Johannes
                    • Ted
                    • +
                    • Malin
                    • Filippa
                    • +
                    • Imma
                    • Hasse
                    • +
                    • Robert
                    • Mona
                    • +
                    • Anna
                    • Lisa
                    • +
                    • Egon
                    • Frida
                    • +
                    • Maj-britt
                    • Fredrik
                    • +
                    • Torbjorn
                    • Lolzor
                    • +
                    • Sandra
                    • Gottfrid
                    • +
                    • Tobias
                    • Martina
                    • +
                    • Johannes
                    • Ted
                    • +
                    • Malin
                    • Filippa
                    • +
                    • Imma
                    • Hasse
                    • +
                    • Robert
                    • Mona
                    • +
                    • Anna
                    • Lisa
                    • +
                    • Egon
                    • Frida
                    • +
                    • Maj-britt
                    • Fredrik
                    • +
                    • Torbjorn
                    • Lolzor
                    • +
                    • Sandra
                    • Gottfrid
                    • +
                    • Tobias
                    • Martina
                    • +
                    • Johannes
                    • Ted
                    • +
                    • Malin
                    • Filippa
                    • +
                    • Imma
                    • Hasse
                    • +
                    • Robert
                    • Mona
                    • +
                    • Anna
                    • Lisa
                    • +
                    • Egon
                    • Frida
                    • +
                    • Maj-britt
                    • Fredrik
                    • +
                    • Torbjorn
                    • Lolzor
                    • +
                    • Sandra
                    • Gottfrid
                    • +
                    • Tobias
                    • Martina
                    • +
                    • Johannes
                    • Ted
                    • +
                    • Malin
                    • Filippa
                    • +
                    • Imma
                    • Hasse
                    • +
                    • Robert
                    • Mona
                    • +
                    +
                    + `) + $(document.body).append(listEl) + var list = new List('list', { + valueNames: ['name'], + indexAsync: true, + parseComplete: function (list) { + expect(listEl.find('li').length).toEqual(162) + listEl.remove() + done() + }, + }) + }) + }) +}) diff --git a/__test__/defaults.test.js b/__test__/integration/defaults.test.js similarity index 100% rename from __test__/defaults.test.js rename to __test__/integration/defaults.test.js diff --git a/__test__/filter.test.js b/__test__/integration/filter.test.js similarity index 100% rename from __test__/filter.test.js rename to __test__/integration/filter.test.js diff --git a/__test__/fixtures-fuzzysearch.js b/__test__/integration/fixtures-fuzzysearch.js similarity index 100% rename from __test__/fixtures-fuzzysearch.js rename to __test__/integration/fixtures-fuzzysearch.js diff --git a/__test__/fixtures-pagination.js b/__test__/integration/fixtures-pagination.js similarity index 100% rename from __test__/fixtures-pagination.js rename to __test__/integration/fixtures-pagination.js diff --git a/__test__/fixtures.js b/__test__/integration/fixtures.js similarity index 96% rename from __test__/fixtures.js rename to __test__/integration/fixtures.js index 083dae56..32245c99 100644 --- a/__test__/fixtures.js +++ b/__test__/integration/fixtures.js @@ -1,5 +1,5 @@ const $ = require('jquery'), - List = require('../src/index') + List = require('../../src/index') var fixture = { list: function (valueNames, items) { diff --git a/__test__/fuzzysearch.test.js b/__test__/integration/fuzzysearch.test.js similarity index 98% rename from __test__/fuzzysearch.test.js rename to __test__/integration/fuzzysearch.test.js index eea89f5d..f0ba9afc 100644 --- a/__test__/fuzzysearch.test.js +++ b/__test__/integration/fuzzysearch.test.js @@ -1,6 +1,6 @@ const $ = require('jquery'), fixtureFuzzysearch = require('./fixtures-fuzzysearch'), - List = require('../src/index') + List = require('../../src/index') function fireKeyup(el) { if (document.createEvent) { diff --git a/__test__/item.test.js b/__test__/integration/item.test.js similarity index 100% rename from __test__/item.test.js rename to __test__/integration/item.test.js diff --git a/__test__/off.test.js b/__test__/integration/off.test.js similarity index 100% rename from __test__/off.test.js rename to __test__/integration/off.test.js diff --git a/__test__/on.test.js b/__test__/integration/on.test.js similarity index 100% rename from __test__/on.test.js rename to __test__/integration/on.test.js diff --git a/__test__/pagination.test.js b/__test__/integration/pagination.test.js similarity index 99% rename from __test__/pagination.test.js rename to __test__/integration/pagination.test.js index 0e113b1e..3dc1ff3e 100644 --- a/__test__/pagination.test.js +++ b/__test__/integration/pagination.test.js @@ -1,6 +1,6 @@ const $ = require('jquery'), fixturePagination = require('./fixtures-pagination'), - List = require('../src/index') + List = require('../../src/index') describe('Pagination', function () { describe('Default settings, innerWindow: 2, outerWindow: 0, left: 0, right: 0', function () { diff --git a/__test__/parse.test.js b/__test__/integration/parse.test.js similarity index 99% rename from __test__/parse.test.js rename to __test__/integration/parse.test.js index 4055050f..64c7e290 100644 --- a/__test__/parse.test.js +++ b/__test__/integration/parse.test.js @@ -1,5 +1,5 @@ const $ = require('jquery'), - List = require('../src/index') + List = require('../../src/index') describe('Parse', function () { describe('Parse class', function () { diff --git a/__test__/re-index.test.js b/__test__/integration/re-index.test.js similarity index 100% rename from __test__/re-index.test.js rename to __test__/integration/re-index.test.js diff --git a/__test__/search-filter.test.js b/__test__/integration/search-filter.test.js similarity index 100% rename from __test__/search-filter.test.js rename to __test__/integration/search-filter.test.js diff --git a/__test__/search.test.js b/__test__/integration/search.test.js similarity index 100% rename from __test__/search.test.js rename to __test__/integration/search.test.js diff --git a/__test__/show.test.js b/__test__/integration/show.test.js similarity index 100% rename from __test__/show.test.js rename to __test__/integration/show.test.js diff --git a/__test__/sort.test.js b/__test__/integration/sort.test.js similarity index 100% rename from __test__/sort.test.js rename to __test__/integration/sort.test.js diff --git a/__test__/trigger.test.js b/__test__/integration/trigger.test.js similarity index 100% rename from __test__/trigger.test.js rename to __test__/integration/trigger.test.js diff --git a/__test__/utils.classes.test.js b/__test__/integration/utils.classes.test.js similarity index 96% rename from __test__/utils.classes.test.js rename to __test__/integration/utils.classes.test.js index e2ad006f..71038e7d 100644 --- a/__test__/utils.classes.test.js +++ b/__test__/integration/utils.classes.test.js @@ -1,4 +1,4 @@ -const classes = require('../src/utils/classes') +const classes = require('../../src/utils/classes') describe('Classes', function () { var el diff --git a/__test__/utils.get-by-class.test.js b/__test__/integration/utils.get-by-class.test.js similarity index 92% rename from __test__/utils.get-by-class.test.js rename to __test__/integration/utils.get-by-class.test.js index b524b544..b3f08d95 100644 --- a/__test__/utils.get-by-class.test.js +++ b/__test__/integration/utils.get-by-class.test.js @@ -1,4 +1,4 @@ -const getByClass = require('../src/utils/get-by-class') +const getByClass = require('../../src/utils/get-by-class') describe('GetByClass', function () { var el From fa8173dc1ad2f11f2ba8e95baa273b3c6d388c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Mon, 23 Nov 2020 11:53:54 +0100 Subject: [PATCH 33/42] Add unit tests for templates and star decouple Templater api from Item --- __test__/unit/templater.test.js | 165 ++++++++++++++++++++++++++++++++ src/index.js | 2 +- src/item.js | 13 ++- src/templater.js | 66 ++++++------- 4 files changed, 203 insertions(+), 43 deletions(-) create mode 100644 __test__/unit/templater.test.js diff --git a/__test__/unit/templater.test.js b/__test__/unit/templater.test.js new file mode 100644 index 00000000..e19ac7d3 --- /dev/null +++ b/__test__/unit/templater.test.js @@ -0,0 +1,165 @@ +const $ = require('jquery') +const Templater = require('../../src/templater') + +describe('Templater', () => { + describe('init', () => { + it('should init with item string of a div', () => { + const item = `
                    Foo
                    ` + const valueNames = ['name'] + const templater = Templater({ item, valueNames }) + const itemEl = templater.createItem() + expect(itemEl.outerHTML).toEqual('
                    ') + }) + it('should init with item string of a tr', () => { + const item = `Foo` + const valueNames = ['name'] + const templater = Templater({ item, valueNames }) + const itemEl = templater.createItem() + expect(itemEl.outerHTML).toEqual('') + }) + it('should init with item function', () => { + const item = () => { + return `
                    ` + } + const valueNames = ['name'] + const templater = Templater({ item, valueNames }) + const itemEl = templater.createItem() + expect(itemEl.outerHTML).toEqual('
                    ') + }) + it('should init without item', () => { + const listEl = $(` +
                      +
                    • Jonny
                    • +
                    + `) + $(document.body).append(listEl) + const valueNames = ['name'] + const templater = Templater({ valueNames, list: document.querySelector('.list') }) + const itemEl = templater.createItem() + expect(itemEl.outerHTML).toEqual('
                  • ') + }) + }) + describe('create', () => { + it('should create item with values', () => { + const item = + '
                    ' + + 'Jonny' + + '1986' + + '' + + '' + + '
                    ' + + const valueNames = [ + 'name', + 'born', + { data: ['id'] }, + { attr: 'src', name: 'image' }, + { attr: 'href', name: 'link' }, + { attr: 'value', name: 'foo' }, + { attr: 'data-timestamp', name: 'timestamp' }, + ] + const templater = Templater({ item, valueNames }) + const itemEl = templater.create({ + name: 'Sven', + born: 1950, + id: 4, + image: 'usage/rey.jpeg', + link: 'localhost', + timestamp: '1337', + foo: 'hej', + }) + expect(itemEl.outerHTML).toEqual( + '
                    ' + + 'Sven' + + '1950' + + '' + + '' + + '
                    ' + ) + }) + }) + describe('remove', () => { + it('should remove element from list', () => { + const listEl = $(` +
                    +
                    Foo
                    +
                    + `)[0] + document.body.appendChild(listEl) + const item = listEl.querySelector('div') + const valueNames = ['name'] + const templater = Templater({ list: listEl, valueNames }) + expect(listEl.querySelector('div')).not.toEqual(null) + templater.remove(item) + expect(listEl.querySelector('div')).toEqual(null) + }) + }) + describe('show', () => { + it('should add element to list', () => { + const listEl = $(`
                    `)[0] + document.body.appendChild(listEl) + const item = $('
                    Foo
                    ')[0] + const valueNames = ['name'] + const templater = Templater({ list: listEl, valueNames, item: '
                    ' }) + expect(listEl.querySelector('div')).toEqual(null) + templater.show(item) + expect(listEl.querySelector('div')).not.toEqual(null) + }) + }) + describe('clear', () => { + it('should clear the entire list of children', () => { + const listEl = $(` +
                    +
                    Foo
                    +
                    Foo
                    +
                    + `)[0] + document.body.appendChild(listEl) + const valueNames = ['name'] + const templater = Templater({ list: listEl, valueNames }) + expect(listEl.querySelectorAll('div').length).toEqual(2) + templater.clear() + expect(listEl.querySelectorAll('div').length).toEqual(0) + }) + }) + describe('set', () => { + it('should set values to element', () => { + const itemEl = $( + '
                    ' + + 'Jonny' + + '1986' + + '' + + '' + + '
                    ' + )[0] + const valueNames = [ + 'name', + 'born', + { data: ['id'] }, + { attr: 'src', name: 'image' }, + { attr: 'href', name: 'link' }, + { attr: 'value', name: 'foo' }, + { attr: 'data-timestamp', name: 'timestamp' }, + ] + const templater = Templater({ item: '
                    ', valueNames }) + templater.set(itemEl, { + name: 'Sven', + born: 1950, + id: 4, + image: 'usage/rey.jpeg', + link: 'localhost', + timestamp: '1337', + foo: 'hej', + }) + expect(itemEl.outerHTML).toEqual( + '
                    ' + + 'Sven' + + '1950' + + '' + + '' + + '
                    ' + ) + }) + }) + describe('get', () => {}) +}) diff --git a/src/index.js b/src/index.js index 39ffcbac..ca6bb6d0 100644 --- a/src/index.js +++ b/src/index.js @@ -153,7 +153,7 @@ module.exports = function (id, options, values) { var found = 0 for (var i = 0, il = self.items.length; i < il; i++) { if (self.items[i].values()[valueName] == value) { - self.templater.remove(self.items[i], options) + self.templater.remove(self.items[i].elm) self.items.splice(i, 1) il-- i-- diff --git a/src/item.js b/src/item.js index 41410625..942d7768 100644 --- a/src/item.js +++ b/src/item.js @@ -27,7 +27,11 @@ module.exports = function (list) { item._values[name] = newValues[name] } if (notCreate !== true) { - list.templater.set(item, item.values()) + if (item.elm) { + list.templater.set(item.elm, item.values()) + } else { + list.templater.create(item.values()) + } } } else { return item._values @@ -35,11 +39,14 @@ module.exports = function (list) { } this.show = function () { - list.templater.show(item) + if (!item.elm) { + item.elm = list.templater.create(item.values()) + } + list.templater.show(item.elm) } this.hide = function () { - list.templater.hide(item) + list.templater.remove(item.elm) } this.matching = function () { diff --git a/src/templater.js b/src/templater.js index 5d09973d..ebe2e654 100644 --- a/src/templater.js +++ b/src/templater.js @@ -1,4 +1,6 @@ -var Templater = function (list) { +var getByClass = require('./utils/get-by-class') + +module.exports = function (list) { var createItem, templater = this @@ -6,7 +8,7 @@ var Templater = function (list) { var itemSource if (typeof list.item === 'function') { - createItem = function (values) { + templater.createItem = function (values) { var item = list.item(values) return getItemSource(item) } @@ -31,7 +33,7 @@ var Templater = function (list) { itemSource = createCleanTemplateItem(itemSource, list.valueNames) - createItem = function () { + templater.createItem = function () { return itemSource.cloneNode(true) } } @@ -48,12 +50,12 @@ var Templater = function (list) { el.setAttribute('data-' + valueName.data[j], '') } } else if (valueName.attr && valueName.name) { - elm = list.utils.getByClass(el, valueName.name, true) + elm = getByClass(el, valueName.name, true) if (elm) { elm.setAttribute(valueName.attr, '') } } else { - elm = list.utils.getByClass(el, valueName, true) + elm = getByClass(el, valueName, true) if (elm) { elm.innerHTML = '' } @@ -106,19 +108,19 @@ var Templater = function (list) { } } - var setValue = function (item, name, value) { + var setValue = function (el, name, value) { var elm = undefined, valueName = getValueName(name) if (!valueName) return if (valueName.data) { - item.elm.setAttribute('data-' + valueName.data, value) + el.setAttribute('data-' + valueName.data, value) } else if (valueName.attr && valueName.name) { - elm = list.utils.getByClass(item.elm, valueName.name, true) + elm = getByClass(el, valueName.name, true) if (elm) { elm.setAttribute(valueName.attr, value) } } else { - elm = list.utils.getByClass(item.elm, valueName, true) + elm = getByClass(el, valueName, true) if (elm) { elm.innerHTML = value } @@ -136,47 +138,36 @@ var Templater = function (list) { values[valueName.data[j]] = list.utils.getAttribute(item.elm, 'data-' + valueName.data[j]) } } else if (valueName.attr && valueName.name) { - elm = list.utils.getByClass(item.elm, valueName.name, true) + elm = getByClass(item.elm, valueName.name, true) values[valueName.name] = elm ? list.utils.getAttribute(elm, valueName.attr) : '' } else { - elm = list.utils.getByClass(item.elm, valueName, true) + elm = getByClass(item.elm, valueName, true) values[valueName] = elm ? elm.innerHTML : '' } } return values } - this.set = function (item, values) { - if (!templater.create(item)) { - for (var v in values) { - if (values.hasOwnProperty(v)) { - setValue(item, v, values[v]) - } + this.set = function (el, values) { + for (var v in values) { + if (values.hasOwnProperty(v)) { + setValue(el, v, values[v]) } } } - this.create = function (item) { - if (item.elm !== undefined) { - return false - } - item.elm = createItem(item.values()) - templater.set(item, item.values()) - return true + this.create = function (values) { + var elm = templater.createItem(values) + templater.set(elm, values) + return elm } - this.remove = function (item) { - if (item.elm.parentNode === list.list) { - list.list.removeChild(item.elm) + this.remove = function (el) { + if (el !== undefined && el.parentNode === list.list) { + list.list.removeChild(el) } } - this.show = function (item) { - templater.create(item) - list.list.appendChild(item.elm) - } - this.hide = function (item) { - if (item.elm !== undefined && item.elm.parentNode === list.list) { - list.list.removeChild(item.elm) - } + this.show = function (el) { + list.list.appendChild(el) } this.clear = function () { /* .innerHTML = ''; fucks up IE */ @@ -188,8 +179,5 @@ var Templater = function (list) { } init() -} - -module.exports = function (list) { - return new Templater(list) + return templater } From 3b2792d808bccb3a502b1f93e2f9bb43113d1c52 Mon Sep 17 00:00:00 2001 From: sheffieldnick Date: Sat, 4 Apr 2020 20:23:29 +0000 Subject: [PATCH 34/42] Added new documentation page "Automagical Searching + Sorting" with links from left sidebar and "Getting started" page --- docs/_includes/menu.html | 1 + docs/docs/index.html | 5 +-- docs/docs/search-sort.html | 91 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 3 deletions(-) mode change 100644 => 100755 docs/_includes/menu.html mode change 100644 => 100755 docs/docs/index.html create mode 100755 docs/docs/search-sort.html diff --git a/docs/_includes/menu.html b/docs/_includes/menu.html old mode 100644 new mode 100755 index f09173ac..79a81266 --- a/docs/_includes/menu.html +++ b/docs/_includes/menu.html @@ -14,6 +14,7 @@

                    Documentation

                  • Getting started
                  • List API
                  • Item API
                  • +
                  • Searching + Sorting
                  • FAQ
                  • diff --git a/docs/docs/index.html b/docs/docs/index.html old mode 100644 new mode 100755 index b2f8d1ec..45632742 --- a/docs/docs/index.html +++ b/docs/docs/index.html @@ -4,7 +4,7 @@ ---

                    Really simple examples

                    -

                    You can use List.js on either exising HTML or create new with super simple templating.

                    +

                    You can use List.js on either existing HTML or create new with super simple templating.

                    Example 1: Using existing list

                    @@ -127,8 +127,7 @@
                    JavaScript (nothing special)
                    var hackerList = new List('hacker-list', options);
                    - - +

                    Read more here



                    Example 6: Using data attributes and other custom attributes (introduced in v1.2.0)

                    diff --git a/docs/docs/search-sort.html b/docs/docs/search-sort.html new file mode 100755 index 00000000..7dbac087 --- /dev/null +++ b/docs/docs/search-sort.html @@ -0,0 +1,91 @@ +--- +layout: default +title: Automagical Searching + Sorting +--- + +

                    +Automagical Searching + Sorting

                    + +

                    It is easy to add search input and sort buttons with just a few classes and attributes in your HTML. ‘Automagical’ because List.js registers the event handlers, searches/sorts and updates the list for you:

                    + +

                    +Searching

                    + +
                      +
                    • +

                      + class String. *required
                      + The default class search is how List.js finds your writable search field. If you change it also set options.searchClass.

                      +

                      + Alternatively, using fuzzy-search here will switch to the Fuzzy Search function. +

                      +
                    • +
                    • +

                      + type String. *required
                      + The default input type search is similar to using text, but web browsers may render it slightly differently: see https://developer.mozilla.org/.../input/search. Either type will work with List.js. +

                      +
                    • +
                    + +
                    
                    +<input type="search" class="search" placeholder="normal search"> or
                    +<input type="search" class="fuzzy-search" placeholder="fuzzy search!">
                    +
                    + +

                    Sorting

                    + +
                      +
                    • +

                      class String. *required
                      + The default class sort is how List.js finds clickable sort buttons. If you change it also set options.sortClass. +

                      +
                    • +
                    • +

                      + data-sort String. *required
                      + This attribute on a clickable sort button should match the column name passed to List.js in options.valueNames. +

                      +
                    • +
                    • +

                      + data-order String
                      + Set to asc or desc to enforce that sorting order for a column. The user won't be able to change the order, and any data-default-order attribute is ignored. +

                      +
                    • +
                    • +

                      + data-default-order String, default: "asc"
                      + Set to desc to change the initial sorting order for a column. Subsequent clicks will toggle the sorting order between ascending/descending, as usual. +

                      +
                    • +
                    • +

                      + data-insensitive Boolean, default: true
                      + Set to false for case-sensitive sorting of that column. +

                      +
                    • +
                    + +
                    
                    +Sort by: 
                    +<span class='sort' data-sort='name'>Name</span> or 
                    +<span class='sort' data-sort='born' data-default-order='desc'>Born in Year</span> or 
                    +<span class='sort' data-sort='city'>City</span>
                    +
                    + +

                    The CSS classes asc and desc are added when a sort button is clicked on, so List.js can show which column is currently sorted. For example, using this CSS sets a yellow background with ⬆ or ⬇ added after the button text:

                    + +
                    
                    +.sort.asc, .sort.desc {
                    +  background-color: yellow;
                    +  }
                    +.sort.asc::after {
                    +  content: "\002B06";
                    +  padding-left: 3px;
                    +  }
                    +.sort.desc::after {
                    +  content: "\002B07";
                    +  padding-left: 3px
                    +  }
                    +
                    From 7e3539f408dcb1ccca7ebd13a37c34c11dc0b30f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Mon, 23 Nov 2020 12:47:23 +0100 Subject: [PATCH 35/42] Update changelog --- CHANGELOG.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41dd9649..07fd2eee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +### 2.2.0 + +- **[Feature]** #682 Multiple word search +- **[Feature]** #683 Debounced keyup handler in search +- **[Website]** #684 Add more documentation for automagical search and sort elements + ### 2.1.0 - 2020-11-21 - **[Feature]** #634 Add item template function @@ -12,8 +18,6 @@ ### 2.0.0 - 2020-11-21 - Winter cleanup 🧹 - **[Breaking]** Drop support for IE6-8 -- **[Website]** Update Jekyll to remove security warnings -- **[Website]** Fix all examples (sorry that they we're broken) - **[Misc]** Update dev dependencies to latest version: Webpack 3.12.0 -> 5.6.0, jest 23.3 -> 26.6.3, jquery 3.3.1 -> 3.5.1, Removed: jshint jshint-loader - **[Misc]** Replace uglify-js with terser - **[Misc]** Update Node for dev from 6.15 to 14.15.1 @@ -22,14 +26,12 @@ - **[Misc]** Rename History.md to CHANGELOG.md - **[Misc]** Use `babal-loader` with `@babel/preset-env` for supporting IE9-11 - **[Misc]** Add source-maps to `/dist` - -### 1.5.1 - - **[Misc]** Added WISHLIST.md for feature requests to allow cleanup of issue list. - **[Misc]** Update CircleCI from 1.0 to 2.0 +- **[Website]** Update Jekyll to remove security warnings +- **[Website]** Fix all examples (sorry that they we're broken) - **[Website]** Use https instead of http for listjs.com - **[Website]** Update Contribute guidelines [See commit →](https://github.com/javve/list.js/commit/6242496de2ac5c07903fb1590a5cb5129f0887a7) -- **[Website]** Update Jekyll & jQuery versions to remove security warnings. - **[Bugfix]** Use one event listener per pagination and select page via data attributes [See commit →](https://github.com/javve/list.js/commit/7610c59039f3b39f52175cd1a200e935664869e8) - **[Bugfix]** Don't break pagination if page=0 From 5d522e727bb58f58cd0b43410350575895ff45bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Wed, 25 Nov 2020 22:06:28 +0100 Subject: [PATCH 36/42] Refactor templater.get and add unit test --- __test__/unit/templater.test.js | 33 ++++++++++++++++++++++++++++++++- src/item.js | 2 +- src/templater.js | 16 ++++++++-------- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/__test__/unit/templater.test.js b/__test__/unit/templater.test.js index e19ac7d3..3047e9bb 100644 --- a/__test__/unit/templater.test.js +++ b/__test__/unit/templater.test.js @@ -161,5 +161,36 @@ describe('Templater', () => { ) }) }) - describe('get', () => {}) + describe('get', () => { + it('should get all values from element', () => { + const itemEl = $( + '
                    ' + + 'Jonny' + + '1986' + + '' + + '' + + '
                    ' + )[0] + const valueNames = [ + 'name', + 'born', + { data: ['id'] }, + { attr: 'src', name: 'image' }, + { attr: 'href', name: 'link' }, + { attr: 'value', name: 'foo' }, + { attr: 'data-timestamp', name: 'timestamp' }, + ] + const templater = Templater({ item: '
                    ', valueNames }) + const values = templater.get(itemEl) + expect(values).toEqual({ + name: 'Jonny', + born: '1986', + id: '1', + image: 'usage/boba.jpeg', + link: 'http://lol.com', + foo: 'Bar', + timestamp: '54321', + }) + }) + }) }) diff --git a/src/item.js b/src/item.js index 942d7768..c62a3d06 100644 --- a/src/item.js +++ b/src/item.js @@ -16,7 +16,7 @@ module.exports = function (list) { } } else { item.elm = element - var values = list.templater.get(item, initValues) + var values = list.templater.get(item.elm) item.values(values) } } diff --git a/src/templater.js b/src/templater.js index ebe2e654..b5856e9f 100644 --- a/src/templater.js +++ b/src/templater.js @@ -1,4 +1,5 @@ var getByClass = require('./utils/get-by-class') +var getAttribute = require('./utils/get-attribute') module.exports = function (list) { var createItem, @@ -127,21 +128,20 @@ module.exports = function (list) { } } - this.get = function (item, valueNames) { - templater.create(item) + this.get = function (el) { + var valueNames = list.valueNames var values = {} for (var i = 0, il = valueNames.length; i < il; i++) { - var elm = undefined, - valueName = valueNames[i] + var valueName = valueNames[i] if (valueName.data) { for (var j = 0, jl = valueName.data.length; j < jl; j++) { - values[valueName.data[j]] = list.utils.getAttribute(item.elm, 'data-' + valueName.data[j]) + values[valueName.data[j]] = getAttribute(el, 'data-' + valueName.data[j]) } } else if (valueName.attr && valueName.name) { - elm = getByClass(item.elm, valueName.name, true) - values[valueName.name] = elm ? list.utils.getAttribute(elm, valueName.attr) : '' + var elm = getByClass(el, valueName.name, true) + values[valueName.name] = elm ? getAttribute(elm, valueName.attr) : '' } else { - elm = getByClass(item.elm, valueName, true) + var elm = getByClass(el, valueName, true) values[valueName] = elm ? elm.innerHTML : '' } } From b27b1f63355f656c5bfd114d9233b994c13818f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sat, 28 Nov 2020 20:18:16 +0100 Subject: [PATCH 37/42] Complete decoupling of templater from list --- __test__/unit/templater.test.js | 83 ++++---- __test__/unit/utils.value-names.test.js | 65 +++++++ src/index.js | 17 +- src/item.js | 17 +- src/parse.js | 3 +- src/search.js | 2 +- src/templater.js | 239 +++++++++--------------- src/utils/value-names.js | 39 ++++ 8 files changed, 258 insertions(+), 207 deletions(-) create mode 100644 __test__/unit/utils.value-names.test.js create mode 100644 src/utils/value-names.js diff --git a/__test__/unit/templater.test.js b/__test__/unit/templater.test.js index 3047e9bb..d56fd4db 100644 --- a/__test__/unit/templater.test.js +++ b/__test__/unit/templater.test.js @@ -1,20 +1,20 @@ const $ = require('jquery') -const Templater = require('../../src/templater') +const templater = require('../../src/templater') describe('Templater', () => { - describe('init', () => { - it('should init with item string of a div', () => { + describe('getTemplate function', () => { + it('should get from string with div', () => { const item = `
                    Foo
                    ` const valueNames = ['name'] - const templater = Templater({ item, valueNames }) - const itemEl = templater.createItem() + const template = templater.getTemplate({ template: item, valueNames }) + const itemEl = template() expect(itemEl.outerHTML).toEqual('
                    ') }) it('should init with item string of a tr', () => { const item = `Foo` const valueNames = ['name'] - const templater = Templater({ item, valueNames }) - const itemEl = templater.createItem() + const template = templater.getTemplate({ template: item, valueNames }) + const itemEl = template() expect(itemEl.outerHTML).toEqual('') }) it('should init with item function', () => { @@ -22,8 +22,8 @@ describe('Templater', () => { return `
                    ` } const valueNames = ['name'] - const templater = Templater({ item, valueNames }) - const itemEl = templater.createItem() + const template = templater.getTemplate({ template: item, valueNames }) + const itemEl = template() expect(itemEl.outerHTML).toEqual('
                    ') }) it('should init without item', () => { @@ -34,8 +34,8 @@ describe('Templater', () => { `) $(document.body).append(listEl) const valueNames = ['name'] - const templater = Templater({ valueNames, list: document.querySelector('.list') }) - const itemEl = templater.createItem() + const template = templater.getTemplate({ parentEl: document.querySelector('.list'), valueNames }) + const itemEl = template() expect(itemEl.outerHTML).toEqual('
                  • ') }) }) @@ -58,16 +58,20 @@ describe('Templater', () => { { attr: 'value', name: 'foo' }, { attr: 'data-timestamp', name: 'timestamp' }, ] - const templater = Templater({ item, valueNames }) - const itemEl = templater.create({ - name: 'Sven', - born: 1950, - id: 4, - image: 'usage/rey.jpeg', - link: 'localhost', - timestamp: '1337', - foo: 'hej', - }) + const template = templater.getTemplate({ template: item, valueNames }) + const itemEl = templater.create( + { + name: 'Sven', + born: 1950, + id: 4, + image: 'usage/rey.jpeg', + link: 'localhost', + timestamp: '1337', + foo: 'hej', + }, + valueNames, + template + ) expect(itemEl.outerHTML).toEqual( '
                    ' + 'Sven' + @@ -88,9 +92,8 @@ describe('Templater', () => { document.body.appendChild(listEl) const item = listEl.querySelector('div') const valueNames = ['name'] - const templater = Templater({ list: listEl, valueNames }) expect(listEl.querySelector('div')).not.toEqual(null) - templater.remove(item) + templater.remove(item, listEl) expect(listEl.querySelector('div')).toEqual(null) }) }) @@ -99,10 +102,8 @@ describe('Templater', () => { const listEl = $(`
                    `)[0] document.body.appendChild(listEl) const item = $('
                    Foo
                    ')[0] - const valueNames = ['name'] - const templater = Templater({ list: listEl, valueNames, item: '
                    ' }) expect(listEl.querySelector('div')).toEqual(null) - templater.show(item) + templater.show(item, listEl) expect(listEl.querySelector('div')).not.toEqual(null) }) }) @@ -115,10 +116,8 @@ describe('Templater', () => {
                    `)[0] document.body.appendChild(listEl) - const valueNames = ['name'] - const templater = Templater({ list: listEl, valueNames }) expect(listEl.querySelectorAll('div').length).toEqual(2) - templater.clear() + templater.clear(listEl) expect(listEl.querySelectorAll('div').length).toEqual(0) }) }) @@ -141,16 +140,19 @@ describe('Templater', () => { { attr: 'value', name: 'foo' }, { attr: 'data-timestamp', name: 'timestamp' }, ] - const templater = Templater({ item: '
                    ', valueNames }) - templater.set(itemEl, { - name: 'Sven', - born: 1950, - id: 4, - image: 'usage/rey.jpeg', - link: 'localhost', - timestamp: '1337', - foo: 'hej', - }) + templater.set( + itemEl, + { + name: 'Sven', + born: 1950, + id: 4, + image: 'usage/rey.jpeg', + link: 'localhost', + timestamp: '1337', + foo: 'hej', + }, + valueNames + ) expect(itemEl.outerHTML).toEqual( '
                    ' + 'Sven' + @@ -180,8 +182,7 @@ describe('Templater', () => { { attr: 'value', name: 'foo' }, { attr: 'data-timestamp', name: 'timestamp' }, ] - const templater = Templater({ item: '
                    ', valueNames }) - const values = templater.get(itemEl) + const values = templater.get(itemEl, valueNames) expect(values).toEqual({ name: 'Jonny', born: '1986', diff --git a/__test__/unit/utils.value-names.test.js b/__test__/unit/utils.value-names.test.js new file mode 100644 index 00000000..b48c2b65 --- /dev/null +++ b/__test__/unit/utils.value-names.test.js @@ -0,0 +1,65 @@ +const $ = require('jquery') +const valueNamesUtils = require('../../src/utils/value-names') + +describe('Utils / Value Names', () => { + let valueNames, itemEl + + beforeEach(() => { + valueNames = [ + 'name', + 'born', + { data: ['id'] }, + { attr: 'src', name: 'image' }, + { attr: 'href', name: 'link' }, + { attr: 'value', name: 'foo' }, + { attr: 'data-timestamp', name: 'timestamp' }, + ] + itemEl = $( + '
                    ' + + 'Jonny' + + '1986' + + '' + + '' + + '
                    ' + )[0] + }) + describe('getDefinitionFromName', () => { + it('should get regular class name', () => { + expect(valueNamesUtils.getDefinitionFromName('born', valueNames)).toEqual('born') + }) + it('should get root data attribute', () => { + expect(valueNamesUtils.getDefinitionFromName('id', valueNames)).toEqual({ data: 'id' }) + }) + it('should get attribute', () => { + expect(valueNamesUtils.getDefinitionFromName('link', valueNames)).toEqual({ attr: 'href', name: 'link' }) + }) + it('should get data attribute', () => { + expect(valueNamesUtils.getDefinitionFromName('timestamp', valueNames)).toEqual({ + attr: 'data-timestamp', + name: 'timestamp', + }) + }) + }) + describe('set', () => { + it('should set class', () => { + valueNamesUtils.set(itemEl, 'born', '1337', valueNames) + const born = itemEl.querySelector('.born').innerHTML + expect(born).toEqual('1337') + }) + it('should set root data attribute', () => { + valueNamesUtils.set(itemEl, 'id', '555', valueNames) + const id = itemEl.getAttribute('data-id') + expect(id).toEqual('555') + }) + it('should set attribute', () => { + valueNamesUtils.set(itemEl, 'link', 'http://foo.se/', valueNames) + const link = itemEl.querySelector('a').href + expect(link).toEqual('http://foo.se/') + }) + it('should set data attribut', () => { + valueNamesUtils.set(itemEl, 'timestamp', 'bar-bar', valueNames) + const timestamp = itemEl.querySelector('span').getAttribute('data-timestamp') + expect(timestamp).toEqual('bar-bar') + }) + }) +}) diff --git a/src/index.js b/src/index.js index 9171c458..78754210 100755 --- a/src/index.js +++ b/src/index.js @@ -52,7 +52,12 @@ module.exports = function (id, options, values) { self.list = getByClass(self.listContainer, self.listClass, true) self.parse = require('./parse')(self) - self.templater = require('./templater')(self) + self.templater = require('./templater') + self.template = self.templater.getTemplate({ + parentEl: self.list, + valueNames: self.valueNames, + template: self.item, + }) self.search = require('./search')(self) self.filter = require('./filter')(self) self.sort = require('./sort')(self) @@ -129,9 +134,7 @@ module.exports = function (id, options, values) { values = [values] } for (var i = 0, il = values.length; i < il; i++) { - var item = null - notCreate = self.items.length > self.page ? true : false - item = new Item(values[i], undefined, notCreate) + var item = new Item(values[i], undefined, notCreate) self.items.push(item) added.push(item) } @@ -154,7 +157,7 @@ module.exports = function (id, options, values) { var found = 0 for (var i = 0, il = self.items.length; i < il; i++) { if (self.items[i].values()[valueName] == value) { - self.templater.remove(self.items[i].elm) + self.templater.remove(self.items[i].elm, self.list) self.items.splice(i, 1) il-- i-- @@ -190,7 +193,7 @@ module.exports = function (id, options, values) { * Removes all items from the list */ this.clear = function () { - self.templater.clear() + self.templater.clear(self.list) self.items = [] return self } @@ -242,7 +245,7 @@ module.exports = function (id, options, values) { self.visibleItems = [] self.matchingItems = [] - self.templater.clear() + self.templater.clear(self.list) for (var i = 0; i < il; i++) { if (is[i].matching() && self.matchingItems.length + 1 >= self.i && self.visibleItems.length < self.page) { is[i].show() diff --git a/src/item.js b/src/item.js index c62a3d06..0d5a264d 100644 --- a/src/item.js +++ b/src/item.js @@ -16,8 +16,7 @@ module.exports = function (list) { } } else { item.elm = element - var values = list.templater.get(item.elm) - item.values(values) + item.values(initValues) } } @@ -26,12 +25,8 @@ module.exports = function (list) { for (var name in newValues) { item._values[name] = newValues[name] } - if (notCreate !== true) { - if (item.elm) { - list.templater.set(item.elm, item.values()) - } else { - list.templater.create(item.values()) - } + if (item.elm) { + list.templater.set(item.elm, item.values(), list.valueNames) } } else { return item._values @@ -40,13 +35,13 @@ module.exports = function (list) { this.show = function () { if (!item.elm) { - item.elm = list.templater.create(item.values()) + item.elm = list.templater.create(item.values(), list.valueNames, list.template) } - list.templater.show(item.elm) + list.templater.show(item.elm, list.list) } this.hide = function () { - list.templater.remove(item.elm) + list.templater.remove(item.elm, list.list) } this.matching = function () { diff --git a/src/parse.js b/src/parse.js index 0abe5900..7d7fe561 100644 --- a/src/parse.js +++ b/src/parse.js @@ -15,7 +15,8 @@ module.exports = function (list) { var parse = function (itemElements, valueNames) { for (var i = 0, il = itemElements.length; i < il; i++) { - list.items.push(new Item(valueNames, itemElements[i])) + var values = list.templater.get(itemElements[i], list.valueNames) + list.items.push(new Item(values, itemElements[i])) } } var parseAsync = function (itemElements, valueNames) { diff --git a/src/search.js b/src/search.js index 06c2d4b1..f64ae4cc 100755 --- a/src/search.js +++ b/src/search.js @@ -4,7 +4,7 @@ module.exports = function (list) { var prepare = { resetList: function () { list.i = 1 - list.templater.clear() + list.templater.clear(list.list) customSearch = undefined }, setOptions: function (args) { diff --git a/src/templater.js b/src/templater.js index b5856e9f..19af827d 100644 --- a/src/templater.js +++ b/src/templater.js @@ -1,183 +1,130 @@ var getByClass = require('./utils/get-by-class') var getAttribute = require('./utils/get-attribute') +var valueNamesUtils = require('./utils/value-names') -module.exports = function (list) { - var createItem, - templater = this - - var init = function () { - var itemSource - - if (typeof list.item === 'function') { - templater.createItem = function (values) { - var item = list.item(values) - return getItemSource(item) +var createCleanTemplateItem = function (templateNode, valueNames) { + var el = templateNode.cloneNode(true) + el.removeAttribute('id') + for (var i = 0, il = valueNames.length; i < il; i++) { + var elm = undefined, + valueName = valueNames[i] + if (valueName.data) { + for (var j = 0, jl = valueName.data.length; j < jl; j++) { + el.setAttribute('data-' + valueName.data[j], '') } - return - } - - if (typeof list.item === 'string') { - if (list.item.indexOf('<') === -1) { - itemSource = document.getElementById(list.item) - } else { - itemSource = getItemSource(list.item) + } else if (valueName.attr && valueName.name) { + elm = getByClass(el, valueName.name, true) + if (elm) { + elm.setAttribute(valueName.attr, '') } } else { - /* If item source does not exists, use the first item in list as - source for new items */ - itemSource = getFirstListItem() - } - - if (!itemSource) { - throw new Error("The list needs to have at least one item on init otherwise you'll have to add a template.") + elm = getByClass(el, valueName, true) + if (elm) { + elm.innerHTML = '' + } } + } + return el +} - itemSource = createCleanTemplateItem(itemSource, list.valueNames) - - templater.createItem = function () { - return itemSource.cloneNode(true) - } +var stringToDOMElement = function (itemHTML) { + if (typeof itemHTML !== 'string') return undefined + if (/]/g.exec(itemHTML)) { + var tbody = document.createElement('tbody') + tbody.innerHTML = itemHTML + return tbody.firstElementChild + } else if (itemHTML.indexOf('<') !== -1) { + var div = document.createElement('div') + div.innerHTML = itemHTML + return div.firstElementChild } + return undefined +} - var createCleanTemplateItem = function (templateNode, valueNames) { - var el = templateNode.cloneNode(true) - el.removeAttribute('id') +var templater = {} - for (var i = 0, il = valueNames.length; i < il; i++) { - var elm = undefined, - valueName = valueNames[i] - if (valueName.data) { - for (var j = 0, jl = valueName.data.length; j < jl; j++) { - el.setAttribute('data-' + valueName.data[j], '') - } - } else if (valueName.attr && valueName.name) { - elm = getByClass(el, valueName.name, true) - if (elm) { - elm.setAttribute(valueName.attr, '') - } - } else { - elm = getByClass(el, valueName, true) - if (elm) { - elm.innerHTML = '' - } - } +templater.getTemplate = function ({ valueNames, parentEl, template }) { + if (typeof template === 'function') { + return function (values) { + var item = template(values) + return stringToDOMElement(item) } - return el } - var getFirstListItem = function () { - var nodes = list.list.childNodes - + var itemSource + if (typeof template === 'string') { + if (template.indexOf('<') === -1) { + itemSource = document.getElementById(template) + } else { + itemSource = stringToDOMElement(template) + } + } else { + var nodes = parentEl.childNodes for (var i = 0, il = nodes.length; i < il; i++) { // Only textnodes have a data attribute if (nodes[i].data === undefined) { - return nodes[i].cloneNode(true) + itemSource = nodes[i].cloneNode(true) + break } } - return undefined } + if (!itemSource) + throw new Error("The list needs to have at least one item on init otherwise you'll have to add a template.") - var getItemSource = function (itemHTML) { - if (typeof itemHTML !== 'string') return undefined - if (/]/g.exec(itemHTML)) { - var tbody = document.createElement('tbody') - tbody.innerHTML = itemHTML - return tbody.firstElementChild - } else if (itemHTML.indexOf('<') !== -1) { - var div = document.createElement('div') - div.innerHTML = itemHTML - return div.firstElementChild - } - return undefined - } + itemSource = createCleanTemplateItem(itemSource, valueNames) - var getValueName = function (name) { - for (var i = 0, il = list.valueNames.length; i < il; i++) { - var valueName = list.valueNames[i] - if (valueName.data) { - var data = valueName.data - for (var j = 0, jl = data.length; j < jl; j++) { - if (data[j] === name) { - return { data: name } - } - } - } else if (valueName.attr && valueName.name && valueName.name == name) { - return valueName - } else if (valueName === name) { - return name - } - } + return function () { + return itemSource.cloneNode(true) } +} - var setValue = function (el, name, value) { - var elm = undefined, - valueName = getValueName(name) - if (!valueName) return +templater.get = function (el, valueNames) { + var values = {} + for (var i = 0, il = valueNames.length; i < il; i++) { + var valueName = valueNames[i] if (valueName.data) { - el.setAttribute('data-' + valueName.data, value) - } else if (valueName.attr && valueName.name) { - elm = getByClass(el, valueName.name, true) - if (elm) { - elm.setAttribute(valueName.attr, value) + for (var j = 0, jl = valueName.data.length; j < jl; j++) { + values[valueName.data[j]] = getAttribute(el, 'data-' + valueName.data[j]) } + } else if (valueName.attr && valueName.name) { + var elm = getByClass(el, valueName.name, true) + values[valueName.name] = elm ? getAttribute(elm, valueName.attr) : '' } else { - elm = getByClass(el, valueName, true) - if (elm) { - elm.innerHTML = value - } - } - } - - this.get = function (el) { - var valueNames = list.valueNames - var values = {} - for (var i = 0, il = valueNames.length; i < il; i++) { - var valueName = valueNames[i] - if (valueName.data) { - for (var j = 0, jl = valueName.data.length; j < jl; j++) { - values[valueName.data[j]] = getAttribute(el, 'data-' + valueName.data[j]) - } - } else if (valueName.attr && valueName.name) { - var elm = getByClass(el, valueName.name, true) - values[valueName.name] = elm ? getAttribute(elm, valueName.attr) : '' - } else { - var elm = getByClass(el, valueName, true) - values[valueName] = elm ? elm.innerHTML : '' - } + var elm = getByClass(el, valueName, true) + values[valueName] = elm ? elm.innerHTML : '' } - return values } + return values +} - this.set = function (el, values) { - for (var v in values) { - if (values.hasOwnProperty(v)) { - setValue(el, v, values[v]) - } +templater.set = function (el, values, valueNames) { + for (var v in values) { + if (values.hasOwnProperty(v)) { + valueNamesUtils.set(el, v, values[v], valueNames) } } +} - this.create = function (values) { - var elm = templater.createItem(values) - templater.set(elm, values) - return elm - } - this.remove = function (el) { - if (el !== undefined && el.parentNode === list.list) { - list.list.removeChild(el) - } - } - this.show = function (el) { - list.list.appendChild(el) +templater.create = function (values, valueNames, template) { + var elm = template(values) + templater.set(elm, values, valueNames) + return elm +} +templater.remove = function (el, parentEl) { + if (el !== undefined && el.parentNode === parentEl) { + parentEl.removeChild(el) } - this.clear = function () { - /* .innerHTML = ''; fucks up IE */ - if (list.list.hasChildNodes()) { - while (list.list.childNodes.length >= 1) { - list.list.removeChild(list.list.firstChild) - } +} +templater.show = function (el, parentEl) { + parentEl.appendChild(el) +} +templater.clear = function (parentEl) { + /* .innerHTML = ''; fucks up IE */ + if (parentEl.hasChildNodes()) { + while (parentEl.childNodes.length >= 1) { + parentEl.removeChild(parentEl.firstChild) } } - - init() - return templater } + +module.exports = templater diff --git a/src/utils/value-names.js b/src/utils/value-names.js new file mode 100644 index 00000000..158d8595 --- /dev/null +++ b/src/utils/value-names.js @@ -0,0 +1,39 @@ +var getByClass = require('./get-by-class') + +const getDefinitionFromName = (name, valueNames) => { + for (var i = 0, il = valueNames.length; i < il; i++) { + var valueName = valueNames[i] + if (valueName.data) { + var data = valueName.data + for (var j = 0, jl = data.length; j < jl; j++) { + if (data[j] === name) { + return { data: name } + } + } + } else if (valueName.attr && valueName.name && valueName.name == name) { + return valueName + } else if (valueName === name) { + return name + } + } +} +const set = (el, name, value, valueNames) => { + var elm = undefined, + valueName = getDefinitionFromName(name, valueNames) + if (!valueName) return + if (valueName.data) { + el.setAttribute('data-' + valueName.data, value) + } else if (valueName.attr && valueName.name) { + elm = getByClass(el, valueName.name, true) + if (elm) { + elm.setAttribute(valueName.attr, value) + } + } else { + elm = getByClass(el, valueName, true) + if (elm) { + elm.innerHTML = value + } + } +} + +module.exports = { getDefinitionFromName, set } From 6d7c59088a81a39e25ac54f54d065e4fda94e965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sun, 29 Nov 2020 12:15:33 +0100 Subject: [PATCH 38/42] Begin decouple item from list and remove item.visible/hide/show and change .matching --- __test__/integration/filter.test.js | 25 ++-- __test__/integration/item.test.js | 46 ++---- __test__/integration/search-filter.test.js | 36 ++--- __test__/integration/search.test.js | 48 +++---- __test__/integration/show.test.js | 157 +++++++++++---------- __test__/unit/templater.test.js | 9 +- __test__/utils/is-visible.js | 4 + src/index.js | 23 +-- src/item.js | 33 ++--- src/templater.js | 25 ++-- 10 files changed, 195 insertions(+), 211 deletions(-) create mode 100644 __test__/utils/is-visible.js diff --git a/__test__/integration/filter.test.js b/__test__/integration/filter.test.js index 37760e20..78711dc0 100644 --- a/__test__/integration/filter.test.js +++ b/__test__/integration/filter.test.js @@ -1,4 +1,5 @@ const fixture = require('./fixtures') +const isVisible = require('../utils/is-visible') describe('Filter', function () { var list, jonny, martina, angelica, sebastian, imma, hasse @@ -68,34 +69,34 @@ describe('Filter', function () { }) }) it('should match jonny', function () { - expect(jonny.matching()).toBe(true) + expect(jonny.matching(list)).toBe(true) expect(jonny.filtered).toBe(true) - expect(jonny.visible()).toBe(true) + expect(isVisible(jonny.elm, list.list)).toBe(true) }) it('should match martina', function () { - expect(martina.matching()).toBe(true) + expect(martina.matching(list)).toBe(true) expect(martina.filtered).toBe(true) - expect(martina.visible()).toBe(true) + expect(isVisible(martina.elm, list.list)).toBe(true) }) it('should match but not show angelica', function () { - expect(angelica.matching()).toBe(true) + expect(angelica.matching(list)).toBe(true) expect(angelica.filtered).toBe(true) - expect(angelica.visible()).toBe(false) + expect(isVisible(angelica.elm, list.list)).toBe(false) }) it('should match but not show sebastian', function () { - expect(sebastian.matching()).toBe(true) + expect(sebastian.matching(list)).toBe(true) expect(sebastian.filtered).toBe(true) - expect(sebastian.visible()).toBe(false) + expect(isVisible(sebastian.elm, list.list)).toBe(false) }) it('should not match imma', function () { - expect(imma.matching()).toBe(false) + expect(imma.matching(list)).toBe(false) expect(imma.filtered).toBe(false) - expect(imma.visible()).toBe(false) + expect(isVisible(imma.elm, list.list)).toBe(false) }) it('should not match hasse', function () { - expect(hasse.matching()).toBe(false) + expect(hasse.matching(list)).toBe(false) expect(hasse.filtered).toBe(false) - expect(hasse.visible()).toBe(false) + expect(isVisible(hasse.elm, list.list)).toBe(false) }) }) }) diff --git a/__test__/integration/item.test.js b/__test__/integration/item.test.js index e1e6c464..07131c51 100644 --- a/__test__/integration/item.test.js +++ b/__test__/integration/item.test.js @@ -1,5 +1,6 @@ const $ = require('jquery'), - fixture = require('./fixtures') + fixture = require('./fixtures'), + isVisible = require('../utils/is-visible') describe('Item', function () { var list, item @@ -39,11 +40,8 @@ describe('Item', function () { }) it('should have all default methods', function () { - expect(item.hide).toBeInstanceOf(Function) - expect(item.show).toBeInstanceOf(Function) expect(item.values).toBeInstanceOf(Function) expect(item.matching).toBeInstanceOf(Function) - expect(item.visible).toBeInstanceOf(Function) }) }) @@ -79,44 +77,28 @@ describe('Item', function () { }) }) - describe('Hide, show, visible', function () { - it('should be hidden', function () { - expect($('#list li').length).toEqual(1) - item.hide() - expect(item.visible()).toBe(false) - expect($('#list li').length).toEqual(0) - }) - it('should be visible', function () { - item.hide() - expect($('#list li').length).toEqual(0) - item.show() - expect(item.visible()).toBe(true) - expect($('#list li').length).toEqual(1) - }) - }) - describe('Matching, found, filtered', function () { describe('Searching', function () { it('should not be visible, match, found or filtered', function () { list.search('Fredrik') - expect(item.matching()).toBe(false) + expect(item.matching(list)).toBe(false) expect(item.found).toBe(false) expect(item.filtered).toBe(false) - expect(item.visible()).toBe(false) + expect(isVisible(item.elm, list.list)).toBe(false) }) it('should be visble, match and found but not filterd', function () { var result = list.search('Sven') - expect(item.matching()).toBe(true) + expect(item.matching(list)).toBe(true) expect(item.found).toBe(true) expect(item.filtered).toBe(false) - expect(item.visible()).toBe(true) + expect(isVisible(item.elm, list.list)).toBe(true) }) it('reset: should be visible and matching but not found or filtered', function () { list.search() - expect(item.matching()).toBe(true) + expect(item.matching(list)).toBe(true) expect(item.found).toBe(false) expect(item.filtered).toBe(false) - expect(item.visible()).toBe(true) + expect(isVisible(item.elm, list.list)).toBe(true) }) }) describe('Filtering', function () { @@ -124,26 +106,26 @@ describe('Item', function () { list.filter(function (item) { return item.values().name == 'Fredrik' }) - expect(item.matching()).toBe(false) + expect(item.matching(list)).toBe(false) expect(item.found).toBe(false) expect(item.filtered).toBe(false) - expect(item.visible()).toBe(false) + expect(isVisible(item.elm, list.list)).toBe(false) }) it('should be visble, match and filtered but not found', function () { list.filter(function (item) { return item.values().name == 'Sven' }) - expect(item.matching()).toBe(true) + expect(item.matching(list)).toBe(true) expect(item.found).toBe(false) expect(item.filtered).toBe(true) - expect(item.visible()).toBe(true) + expect(isVisible(item.elm, list.list)).toBe(true) }) it('reset: should be visble and match but not filtered or found', function () { list.filter() - expect(item.matching()).toBe(true) + expect(item.matching(list)).toBe(true) expect(item.found).toBe(false) expect(item.filtered).toBe(false) - expect(item.visible()).toBe(true) + expect(isVisible(item.elm, list.list)).toBe(true) }) }) }) diff --git a/__test__/integration/search-filter.test.js b/__test__/integration/search-filter.test.js index 73e7264f..e7f69b60 100644 --- a/__test__/integration/search-filter.test.js +++ b/__test__/integration/search-filter.test.js @@ -29,12 +29,12 @@ describe('Search and filter', function () { return item.values().born == '1986' }) expect(list.matchingItems.length).toEqual(3) - expect(jonny.matching()).toBe(true) - expect(martina.matching()).toBe(true) - expect(angelica.matching()).toBe(true) - expect(sebastian.matching()).toBe(false) - expect(imma.matching()).toBe(false) - expect(hasse.matching()).toBe(false) + expect(jonny.matching(list)).toBe(true) + expect(martina.matching(list)).toBe(true) + expect(angelica.matching(list)).toBe(true) + expect(sebastian.matching(list)).toBe(false) + expect(imma.matching(list)).toBe(false) + expect(hasse.matching(list)).toBe(false) }) it('should find everyone born 1986 and containes "ö"', function () { list.filter(function (item) { @@ -42,12 +42,12 @@ describe('Search and filter', function () { }) list.search('ö') expect(list.matchingItems.length).toEqual(1) - expect(jonny.matching()).toBe(true) - expect(martina.matching()).toBe(false) - expect(angelica.matching()).toBe(false) - expect(sebastian.matching()).toBe(false) - expect(imma.matching()).toBe(false) - expect(hasse.matching()).toBe(false) + expect(jonny.matching(list)).toBe(true) + expect(martina.matching(list)).toBe(false) + expect(angelica.matching(list)).toBe(false) + expect(sebastian.matching(list)).toBe(false) + expect(imma.matching(list)).toBe(false) + expect(hasse.matching(list)).toBe(false) }) it('should find everyone with a "ö"', function () { list.filter(function (item) { @@ -56,12 +56,12 @@ describe('Search and filter', function () { list.search('ö') list.filter() expect(list.matchingItems.length).toEqual(4) - expect(jonny.matching()).toBe(true) - expect(martina.matching()).toBe(false) - expect(angelica.matching()).toBe(false) - expect(sebastian.matching()).toBe(true) - expect(imma.matching()).toBe(true) - expect(hasse.matching()).toBe(true) + expect(jonny.matching(list)).toBe(true) + expect(martina.matching(list)).toBe(false) + expect(angelica.matching(list)).toBe(false) + expect(sebastian.matching(list)).toBe(true) + expect(imma.matching(list)).toBe(true) + expect(hasse.matching(list)).toBe(true) }) }) }) diff --git a/__test__/integration/search.test.js b/__test__/integration/search.test.js index ec2abc7e..b2af0e62 100755 --- a/__test__/integration/search.test.js +++ b/__test__/integration/search.test.js @@ -30,22 +30,22 @@ describe('Search', function () { it('should find jonny, martina, angelice', function () { var result = list.search('1986') expect(result.length).toEqual(3) // 3!! - expect(jonny.matching()).toBe(true) - expect(martina.matching()).toBe(true) - expect(angelica.matching()).toBe(true) - expect(sebastian.matching()).toBe(false) - expect(imma.matching()).toBe(false) - expect(hasse.matching()).toBe(false) + expect(jonny.matching(list)).toBe(true) + expect(martina.matching(list)).toBe(true) + expect(angelica.matching(list)).toBe(true) + expect(sebastian.matching(list)).toBe(false) + expect(imma.matching(list)).toBe(false) + expect(hasse.matching(list)).toBe(false) }) it('should find all with utf-8 char ö', function () { var result = list.search('ö') expect(result.length).toEqual(4) // 4!! - expect(jonny.matching()).toBe(true) - expect(martina.matching()).toBe(false) - expect(angelica.matching()).toBe(false) - expect(sebastian.matching()).toBe(true) - expect(imma.matching()).toBe(true) - expect(hasse.matching()).toBe(true) + expect(jonny.matching(list)).toBe(true) + expect(martina.matching(list)).toBe(false) + expect(angelica.matching(list)).toBe(false) + expect(sebastian.matching(list)).toBe(true) + expect(imma.matching(list)).toBe(true) + expect(hasse.matching(list)).toBe(true) }) it('should not break with weird searches', function () { expect(function () { @@ -159,22 +159,22 @@ describe('Search', function () { it('should find jonny, hasse', function () { var result = list.search('berg str') expect(result.length).toEqual(2) - expect(jonny.matching()).toBe(true) - expect(martina.matching()).toBe(false) - expect(angelica.matching()).toBe(false) - expect(sebastian.matching()).toBe(false) - expect(imma.matching()).toBe(false) - expect(hasse.matching()).toBe(true) + expect(jonny.matching(list)).toBe(true) + expect(martina.matching(list)).toBe(false) + expect(angelica.matching(list)).toBe(false) + expect(sebastian.matching(list)).toBe(false) + expect(imma.matching(list)).toBe(false) + expect(hasse.matching(list)).toBe(true) }) it('should find martina, angelica, sebastian, hasse', function () { var result = list.search('a e') expect(result.length).toEqual(4) - expect(jonny.matching()).toBe(false) - expect(martina.matching()).toBe(true) - expect(angelica.matching()).toBe(true) - expect(sebastian.matching()).toBe(true) - expect(imma.matching()).toBe(false) - expect(hasse.matching()).toBe(true) + expect(jonny.matching(list)).toBe(false) + expect(martina.matching(list)).toBe(true) + expect(angelica.matching(list)).toBe(true) + expect(sebastian.matching(list)).toBe(true) + expect(imma.matching(list)).toBe(false) + expect(hasse.matching(list)).toBe(true) }) it('stripping whitespace should find martina', function () { var result = list.search('martina elm ') diff --git a/__test__/integration/show.test.js b/__test__/integration/show.test.js index 60fa41cb..d32dcf46 100644 --- a/__test__/integration/show.test.js +++ b/__test__/integration/show.test.js @@ -1,4 +1,5 @@ const fixture = require('./fixtures') +const isVisible = require('../utils/is-visible') describe('Show', function () { var list, a, b, c, d, e, f @@ -36,52 +37,52 @@ describe('Show', function () { it('should be 1, 2', function () { list.show(1, 2) expect(list.visibleItems.length).toEqual(2) - expect(a.visible()).toBe(true) - expect(b.visible()).toBe(true) - expect(c.visible()).toBe(false) - expect(d.visible()).toBe(false) - expect(e.visible()).toBe(false) - expect(f.visible()).toBe(false) + expect(isVisible(a.elm, list.list)).toBe(true) + expect(isVisible(b.elm, list.list)).toBe(true) + expect(isVisible(c.elm, list.list)).toBe(false) + expect(isVisible(d.elm, list.list)).toBe(false) + expect(isVisible(e.elm, list.list)).toBe(false) + expect(isVisible(f.elm, list.list)).toBe(false) }) it('should show item 6', function () { list.show(6, 2) expect(list.visibleItems.length).toEqual(1) - expect(a.visible()).toBe(false) - expect(b.visible()).toBe(false) - expect(c.visible()).toBe(false) - expect(d.visible()).toBe(false) - expect(e.visible()).toBe(false) - expect(f.visible()).toBe(true) + expect(isVisible(a.elm, list.list)).toBe(false) + expect(isVisible(b.elm, list.list)).toBe(false) + expect(isVisible(c.elm, list.list)).toBe(false) + expect(isVisible(d.elm, list.list)).toBe(false) + expect(isVisible(e.elm, list.list)).toBe(false) + expect(isVisible(f.elm, list.list)).toBe(true) }) it('should show item 1, 2, 3, 4, 5, 6', function () { list.show(1, 200) expect(list.visibleItems.length).toEqual(6) - expect(a.visible()).toBe(true) - expect(b.visible()).toBe(true) - expect(c.visible()).toBe(true) - expect(d.visible()).toBe(true) - expect(e.visible()).toBe(true) - expect(f.visible()).toBe(true) + expect(isVisible(a.elm, list.list)).toBe(true) + expect(isVisible(b.elm, list.list)).toBe(true) + expect(isVisible(c.elm, list.list)).toBe(true) + expect(isVisible(d.elm, list.list)).toBe(true) + expect(isVisible(e.elm, list.list)).toBe(true) + expect(isVisible(f.elm, list.list)).toBe(true) }) it('should show item 3, 4, 5', function () { list.show(3, 3) expect(list.visibleItems.length).toEqual(3) - expect(a.visible()).toBe(false) - expect(b.visible()).toBe(false) - expect(c.visible()).toBe(true) - expect(d.visible()).toBe(true) - expect(e.visible()).toBe(true) - expect(f.visible()).toBe(false) + expect(isVisible(a.elm, list.list)).toBe(false) + expect(isVisible(b.elm, list.list)).toBe(false) + expect(isVisible(c.elm, list.list)).toBe(true) + expect(isVisible(d.elm, list.list)).toBe(true) + expect(isVisible(e.elm, list.list)).toBe(true) + expect(isVisible(f.elm, list.list)).toBe(false) }) it('should show item 5, 6', function () { list.show(5, 3) expect(list.visibleItems.length).toEqual(2) - expect(a.visible()).toBe(false) - expect(b.visible()).toBe(false) - expect(c.visible()).toBe(false) - expect(d.visible()).toBe(false) - expect(e.visible()).toBe(true) - expect(f.visible()).toBe(true) + expect(isVisible(a.elm, list.list)).toBe(false) + expect(isVisible(b.elm, list.list)).toBe(false) + expect(isVisible(c.elm, list.list)).toBe(false) + expect(isVisible(d.elm, list.list)).toBe(false) + expect(isVisible(e.elm, list.list)).toBe(true) + expect(isVisible(f.elm, list.list)).toBe(true) }) }) @@ -93,35 +94,35 @@ describe('Show', function () { list.search('b') list.show(1, 2) expect(list.visibleItems.length).toEqual(2) - expect(a.visible()).toBe(false) - expect(b.visible()).toBe(false) - expect(c.visible()).toBe(true) - expect(d.visible()).toBe(true) - expect(e.visible()).toBe(false) - expect(f.visible()).toBe(false) + expect(isVisible(a.elm, list.list)).toBe(false) + expect(isVisible(b.elm, list.list)).toBe(false) + expect(isVisible(c.elm, list.list)).toBe(true) + expect(isVisible(d.elm, list.list)).toBe(true) + expect(isVisible(e.elm, list.list)).toBe(false) + expect(isVisible(f.elm, list.list)).toBe(false) }) it('should show item 3,4,5,6', function () { list.search('b') list.show(1, 4) expect(list.visibleItems.length).toEqual(4) - expect(a.visible()).toBe(false) - expect(b.visible()).toBe(false) - expect(c.visible()).toBe(true) - expect(d.visible()).toBe(true) - expect(e.visible()).toBe(true) - expect(f.visible()).toBe(true) + expect(isVisible(a.elm, list.list)).toBe(false) + expect(isVisible(b.elm, list.list)).toBe(false) + expect(isVisible(c.elm, list.list)).toBe(true) + expect(isVisible(d.elm, list.list)).toBe(true) + expect(isVisible(e.elm, list.list)).toBe(true) + expect(isVisible(f.elm, list.list)).toBe(true) }) it('should not show any items but match two', function () { list.search('a') list.show(3, 2) expect(list.visibleItems.length).toEqual(0) expect(list.matchingItems.length).toEqual(2) - expect(a.visible()).toBe(false) - expect(b.visible()).toBe(false) - expect(c.visible()).toBe(false) - expect(d.visible()).toBe(false) - expect(e.visible()).toBe(false) - expect(f.visible()).toBe(false) + expect(isVisible(a.elm, list.list)).toBe(false) + expect(isVisible(b.elm, list.list)).toBe(false) + expect(isVisible(c.elm, list.list)).toBe(false) + expect(isVisible(d.elm, list.list)).toBe(false) + expect(isVisible(e.elm, list.list)).toBe(false) + expect(isVisible(f.elm, list.list)).toBe(false) }) }) @@ -136,12 +137,12 @@ describe('Show', function () { list.show(1, 2) expect(list.visibleItems.length).toEqual(2) expect(list.matchingItems.length).toEqual(2) - expect(a.visible()).toBe(false) - expect(b.visible()).toBe(false) - expect(c.visible()).toBe(true) - expect(d.visible()).toBe(true) - expect(e.visible()).toBe(false) - expect(f.visible()).toBe(false) + expect(isVisible(a.elm, list.list)).toBe(false) + expect(isVisible(b.elm, list.list)).toBe(false) + expect(isVisible(c.elm, list.list)).toBe(true) + expect(isVisible(d.elm, list.list)).toBe(true) + expect(isVisible(e.elm, list.list)).toBe(false) + expect(isVisible(f.elm, list.list)).toBe(false) }) it('should show item 3,4,5,6', function () { list.filter(function (item) { @@ -150,12 +151,12 @@ describe('Show', function () { list.show(1, 4) expect(list.visibleItems.length).toEqual(2) expect(list.matchingItems.length).toEqual(2) - expect(a.visible()).toBe(false) - expect(b.visible()).toBe(false) - expect(c.visible()).toBe(false) - expect(d.visible()).toBe(false) - expect(e.visible()).toBe(true) - expect(f.visible()).toBe(true) + expect(isVisible(a.elm, list.list)).toBe(false) + expect(isVisible(b.elm, list.list)).toBe(false) + expect(isVisible(c.elm, list.list)).toBe(false) + expect(isVisible(d.elm, list.list)).toBe(false) + expect(isVisible(e.elm, list.list)).toBe(true) + expect(isVisible(f.elm, list.list)).toBe(true) }) it('should not show any items but match two', function () { list.filter(function (item) { @@ -164,12 +165,12 @@ describe('Show', function () { list.show(3, 2) expect(list.visibleItems.length).toEqual(0) expect(list.matchingItems.length).toEqual(2) - expect(a.visible()).toBe(false) - expect(b.visible()).toBe(false) - expect(c.visible()).toBe(false) - expect(d.visible()).toBe(false) - expect(e.visible()).toBe(false) - expect(f.visible()).toBe(false) + expect(isVisible(a.elm, list.list)).toBe(false) + expect(isVisible(b.elm, list.list)).toBe(false) + expect(isVisible(c.elm, list.list)).toBe(false) + expect(isVisible(d.elm, list.list)).toBe(false) + expect(isVisible(e.elm, list.list)).toBe(false) + expect(isVisible(f.elm, list.list)).toBe(false) }) }) @@ -185,12 +186,12 @@ describe('Show', function () { list.search('b') expect(list.visibleItems.length).toEqual(2) expect(list.matchingItems.length).toEqual(3) - expect(a.visible()).toBe(false) - expect(b.visible()).toBe(false) - expect(c.visible()).toBe(false) - expect(d.visible()).toBe(true) - expect(e.visible()).toBe(true) - expect(f.visible()).toBe(false) + expect(isVisible(a.elm, list.list)).toBe(false) + expect(isVisible(b.elm, list.list)).toBe(false) + expect(isVisible(c.elm, list.list)).toBe(false) + expect(isVisible(d.elm, list.list)).toBe(true) + expect(isVisible(e.elm, list.list)).toBe(true) + expect(isVisible(f.elm, list.list)).toBe(false) }) it('should show 5, 6', function () { list.show(1, 2) @@ -201,12 +202,12 @@ describe('Show', function () { list.show(2, 2) expect(list.visibleItems.length).toEqual(2) expect(list.matchingItems.length).toEqual(3) - expect(a.visible()).toBe(false) - expect(b.visible()).toBe(false) - expect(c.visible()).toBe(false) - expect(d.visible()).toBe(false) - expect(e.visible()).toBe(true) - expect(f.visible()).toBe(true) + expect(isVisible(a.elm, list.list)).toBe(false) + expect(isVisible(b.elm, list.list)).toBe(false) + expect(isVisible(c.elm, list.list)).toBe(false) + expect(isVisible(d.elm, list.list)).toBe(false) + expect(isVisible(e.elm, list.list)).toBe(true) + expect(isVisible(f.elm, list.list)).toBe(true) }) }) }) diff --git a/__test__/unit/templater.test.js b/__test__/unit/templater.test.js index d56fd4db..f717f95c 100644 --- a/__test__/unit/templater.test.js +++ b/__test__/unit/templater.test.js @@ -7,14 +7,14 @@ describe('Templater', () => { const item = `
                    Foo
                    ` const valueNames = ['name'] const template = templater.getTemplate({ template: item, valueNames }) - const itemEl = template() + const itemEl = template.render() expect(itemEl.outerHTML).toEqual('
                    ') }) it('should init with item string of a tr', () => { const item = `Foo` const valueNames = ['name'] const template = templater.getTemplate({ template: item, valueNames }) - const itemEl = template() + const itemEl = template.render() expect(itemEl.outerHTML).toEqual('') }) it('should init with item function', () => { @@ -23,7 +23,7 @@ describe('Templater', () => { } const valueNames = ['name'] const template = templater.getTemplate({ template: item, valueNames }) - const itemEl = template() + const itemEl = template.render() expect(itemEl.outerHTML).toEqual('
                    ') }) it('should init without item', () => { @@ -35,7 +35,7 @@ describe('Templater', () => { $(document.body).append(listEl) const valueNames = ['name'] const template = templater.getTemplate({ parentEl: document.querySelector('.list'), valueNames }) - const itemEl = template() + const itemEl = template.render() expect(itemEl.outerHTML).toEqual('
                  • ') }) }) @@ -69,7 +69,6 @@ describe('Templater', () => { timestamp: '1337', foo: 'hej', }, - valueNames, template ) expect(itemEl.outerHTML).toEqual( diff --git a/__test__/utils/is-visible.js b/__test__/utils/is-visible.js new file mode 100644 index 00000000..dd00b255 --- /dev/null +++ b/__test__/utils/is-visible.js @@ -0,0 +1,4 @@ +module.exports = function (el, parent) { + if (!el) return false + return el && el.parentNode == parent +} diff --git a/src/index.js b/src/index.js index 78754210..b037d610 100755 --- a/src/index.js +++ b/src/index.js @@ -6,7 +6,8 @@ var naturalSort = require('string-natural-compare'), toString = require('./utils/to-string'), classes = require('./utils/classes'), getAttribute = require('./utils/get-attribute'), - toArray = require('./utils/to-array') + toArray = require('./utils/to-array'), + templater = require('./templater') module.exports = function (id, options, values) { var self = this, @@ -52,7 +53,7 @@ module.exports = function (id, options, values) { self.list = getByClass(self.listContainer, self.listClass, true) self.parse = require('./parse')(self) - self.templater = require('./templater') + self.templater = templater self.template = self.templater.getTemplate({ parentEl: self.list, valueNames: self.valueNames, @@ -128,13 +129,12 @@ module.exports = function (id, options, values) { addAsync(values.slice(0), callback) return } - var added = [], - notCreate = false + var added = [] if (values[0] === undefined) { values = [values] } for (var i = 0, il = values.length; i < il; i++) { - var item = new Item(values[i], undefined, notCreate) + var item = new Item(values[i]) self.items.push(item) added.push(item) } @@ -247,15 +247,18 @@ module.exports = function (id, options, values) { self.matchingItems = [] self.templater.clear(self.list) for (var i = 0; i < il; i++) { - if (is[i].matching() && self.matchingItems.length + 1 >= self.i && self.visibleItems.length < self.page) { - is[i].show() + if (is[i].matching(self) && self.matchingItems.length + 1 >= self.i && self.visibleItems.length < self.page) { + if (!is[i].elm) { + is[i].elm = templater.create(is[i].values(), self.template) + } + templater.show(is[i].elm, self.list) self.visibleItems.push(is[i]) self.matchingItems.push(is[i]) - } else if (is[i].matching()) { + } else if (is[i].matching(self)) { self.matchingItems.push(is[i]) - is[i].hide() + templater.remove(is[i].elm, self.list) } else { - is[i].hide() + templater.remove(is[i].elm, self.list) } } self.trigger('updated') diff --git a/src/item.js b/src/item.js index 0d5a264d..2158ce9a 100644 --- a/src/item.js +++ b/src/item.js @@ -1,11 +1,13 @@ +const templater = require('./templater') + module.exports = function (list) { return function (initValues, element, notCreate) { var item = this this._values = {} - this.found = false // Show if list.searched == true and this.found == true - this.filtered = false // Show if list.filtered == true and this.filtered == true + this.found = false + this.filtered = false var init = function (initValues, element, notCreate) { if (element === undefined) { @@ -26,37 +28,22 @@ module.exports = function (list) { item._values[name] = newValues[name] } if (item.elm) { - list.templater.set(item.elm, item.values(), list.valueNames) + templater.set(item.elm, item.values(), list.valueNames) } } else { return item._values } } - this.show = function () { - if (!item.elm) { - item.elm = list.templater.create(item.values(), list.valueNames, list.template) - } - list.templater.show(item.elm, list.list) - } - - this.hide = function () { - list.templater.remove(item.elm, list.list) - } - - this.matching = function () { + this.matching = function ({ searched, filtered }) { return ( - (list.filtered && list.searched && item.found && item.filtered) || - (list.filtered && !list.searched && item.filtered) || - (!list.filtered && list.searched && item.found) || - (!list.filtered && !list.searched) + (filtered && searched && item.found && item.filtered) || + (filtered && !searched && item.filtered) || + (!filtered && searched && item.found) || + (!filtered && !searched) ) } - this.visible = function () { - return item.elm && item.elm.parentNode == list.list ? true : false - } - init(initValues, element, notCreate) } } diff --git a/src/templater.js b/src/templater.js index 19af827d..a0e40bed 100644 --- a/src/templater.js +++ b/src/templater.js @@ -45,9 +45,13 @@ var templater = {} templater.getTemplate = function ({ valueNames, parentEl, template }) { if (typeof template === 'function') { - return function (values) { - var item = template(values) - return stringToDOMElement(item) + return { + valueNames, + type: 'dynamic', + render: function (values) { + var item = template(values) + return stringToDOMElement(item) + }, } } @@ -73,8 +77,13 @@ templater.getTemplate = function ({ valueNames, parentEl, template }) { itemSource = createCleanTemplateItem(itemSource, valueNames) - return function () { - return itemSource.cloneNode(true) + return { + valueNames, + render: function (values) { + var el = itemSource.cloneNode(true) + templater.set(el, values, valueNames) + return el + }, } } @@ -105,10 +114,8 @@ templater.set = function (el, values, valueNames) { } } -templater.create = function (values, valueNames, template) { - var elm = template(values) - templater.set(elm, values, valueNames) - return elm +templater.create = function (values, template) { + return template.render(values) } templater.remove = function (el, parentEl) { if (el !== undefined && el.parentNode === parentEl) { From 5500a5c9204c8cbd80dbb6e55e67e8232fc9d626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Sun, 29 Nov 2020 16:47:49 +0100 Subject: [PATCH 39/42] Complete decoupling of list from item --- src/index.js | 6 ++--- src/item.js | 68 +++++++++++++++++++++++----------------------------- src/parse.js | 6 ++--- 3 files changed, 36 insertions(+), 44 deletions(-) diff --git a/src/index.js b/src/index.js index b037d610..ee43dd0c 100755 --- a/src/index.js +++ b/src/index.js @@ -7,12 +7,12 @@ var naturalSort = require('string-natural-compare'), classes = require('./utils/classes'), getAttribute = require('./utils/get-attribute'), toArray = require('./utils/to-array'), - templater = require('./templater') + templater = require('./templater'), + Item = require('./item') module.exports = function (id, options, values) { var self = this, init, - Item = require('./item')(self), addAsync = require('./add-async')(self), initPagination = require('./pagination')(self) @@ -134,7 +134,7 @@ module.exports = function (id, options, values) { values = [values] } for (var i = 0, il = values.length; i < il; i++) { - var item = new Item(values[i]) + var item = new Item(values[i], { template: self.template }) self.items.push(item) added.push(item) } diff --git a/src/item.js b/src/item.js index 2158ce9a..2e29847e 100644 --- a/src/item.js +++ b/src/item.js @@ -1,49 +1,41 @@ const templater = require('./templater') -module.exports = function (list) { - return function (initValues, element, notCreate) { - var item = this +module.exports = function (initValues, { element, template } = {}) { + var item = this - this._values = {} + this._values = {} - this.found = false - this.filtered = false + this.found = false + this.filtered = false - var init = function (initValues, element, notCreate) { - if (element === undefined) { - if (notCreate) { - item.values(initValues, notCreate) - } else { - item.values(initValues) - } - } else { - item.elm = element - item.values(initValues) - } - } + var init = function (values, { element, template } = {}) { + if (element) item.elm = element + if (!template) throw new Error('no tempalte!') + item.template = template + item.values(values) + } - this.values = function (newValues, notCreate) { - if (newValues !== undefined) { - for (var name in newValues) { - item._values[name] = newValues[name] - } - if (item.elm) { - templater.set(item.elm, item.values(), list.valueNames) - } - } else { - return item._values + this.values = function (newValues) { + if (newValues !== undefined) { + for (var name in newValues) { + item._values[name] = newValues[name] } + if (item.elm) { + templater.set(item.elm, item.values(), item.template.valueNames) + } + } else { + return item._values } + } - this.matching = function ({ searched, filtered }) { - return ( - (filtered && searched && item.found && item.filtered) || - (filtered && !searched && item.filtered) || - (!filtered && searched && item.found) || - (!filtered && !searched) - ) - } - - init(initValues, element, notCreate) + this.matching = function ({ searched, filtered }) { + return ( + (filtered && searched && item.found && item.filtered) || + (filtered && !searched && item.filtered) || + (!filtered && searched && item.found) || + (!filtered && !searched) + ) } + + init(initValues, { element, template }) } diff --git a/src/parse.js b/src/parse.js index 7d7fe561..ab666589 100644 --- a/src/parse.js +++ b/src/parse.js @@ -1,6 +1,6 @@ -module.exports = function (list) { - var Item = require('./item')(list) +var Item = require('./item') +module.exports = function (list) { var getChildren = function (parent) { var nodes = parent.childNodes, items = [] @@ -16,7 +16,7 @@ module.exports = function (list) { var parse = function (itemElements, valueNames) { for (var i = 0, il = itemElements.length; i < il; i++) { var values = list.templater.get(itemElements[i], list.valueNames) - list.items.push(new Item(values, itemElements[i])) + list.items.push(new Item(values, { element: itemElements[i], template: list.template })) } } var parseAsync = function (itemElements, valueNames) { From 238b9001a3e19935ca36295bf184bc9ee23c01f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Mon, 30 Nov 2020 18:13:09 +0100 Subject: [PATCH 40/42] Add unit tests for Item --- __test__/unit/item.test.js | 102 +++++++++++++++++++++++++++++++++++++ src/item.js | 2 +- 2 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 __test__/unit/item.test.js diff --git a/__test__/unit/item.test.js b/__test__/unit/item.test.js new file mode 100644 index 00000000..e4f1ce15 --- /dev/null +++ b/__test__/unit/item.test.js @@ -0,0 +1,102 @@ +const $ = require('jquery') + +const Item = require('../../src/item') +const templater = require('../../src/templater') + +describe('item', function () { + beforeAll(() => { + this.templateParams = { + template: '
                    ', + valueNames: ['name'], + } + }) + describe('init', () => { + it('should throw error if missing template', () => { + expect(() => { + new Item({ name: 'Jonny' }) + }).toThrowError('missing_item_template') + }) + }) + describe('create', () => { + it('should create item with only values', () => { + const template = templater.getTemplate(this.templateParams) + const item = new Item({ name: 'Jonny' }, { template }) + expect(item._values).toEqual({ name: 'Jonny' }) + expect(item.elm).toBeUndefined() + }) + it('should create item with values and element', () => { + const template = templater.getTemplate(this.templateParams) + const element = document.createElement('div') + const item = new Item({ name: 'Jonny' }, { element, template }) + expect(item._values).toEqual({ name: 'Jonny' }) + expect(item.elm).not.toBeUndefined() + expect(item.elm).toBe(element) + }) + }) + describe('get', () => { + it('should get values', () => { + const template = templater.getTemplate(this.templateParams) + const item = new Item({ name: 'Jonny' }, { template }) + expect(item.values()).toEqual({ name: 'Jonny' }) + }) + }) + describe('set', () => { + it('should set values on item without element', () => { + const template = templater.getTemplate(this.templateParams) + const item = new Item({ name: 'Jonny' }, { template }) + item.values({ name: 'Anna' }) + expect(item.elm).toBeUndefined() + expect(item._values.name).toEqual('Anna') + }) + it('should set values on item with element', () => { + const template = templater.getTemplate(this.templateParams) + const element = $('
                    Jonny
                    ')[0] + const item = new Item({ name: 'Jonny' }, { element, template }) + expect(item.elm.querySelector('span').innerHTML).toEqual('Jonny') + item.values({ name: 'Anna' }) + expect(item._values.name).toEqual('Anna') + expect(item.elm.querySelector('span').innerHTML).toEqual('Anna') + }) + }) + describe('matching', () => { + beforeAll(() => { + const template = templater.getTemplate(this.templateParams) + this.item = new Item({ name: 'Jonny' }, { template }) + }) + it('should handle not found or filtered', () => { + const item = this.item + item.found = false + item.filtered = false + expect(item.matching({ searched: false, filtered: false })).toEqual(true) + expect(item.matching({ searched: true, filtered: false })).toEqual(false) + expect(item.matching({ searched: true, filtered: false })).toEqual(false) + }) + it('should handle found and not filtered', () => { + const item = this.item + item.found = true + item.filtered = false + expect(item.matching({ searched: false, filtered: false })).toEqual(true) + expect(item.matching({ searched: true, filtered: false })).toEqual(true) + expect(item.matching({ searched: true, filtered: true })).toEqual(false) + expect(item.matching({ searched: false, filtered: true })).toEqual(false) + }) + it('should handle not found but filtered', () => { + const item = this.item + item.found = false + item.filtered = true + expect(item.matching({ searched: false, filtered: false })).toEqual(true) + expect(item.matching({ searched: true, filtered: false })).toEqual(false) + expect(item.matching({ searched: true, filtered: true })).toEqual(false) + expect(item.matching({ searched: false, filtered: true })).toEqual(true) + }) + it('should handle both found and filtered', () => { + const item = this.item + item.found = true + item.filtered = true + expect(item.matching({ searched: false, filtered: false })).toEqual(true) + expect(item.matching({ searched: true, filtered: false })).toEqual(true) + expect(item.matching({ searched: true, filtered: true })).toEqual(true) + expect(item.matching({ searched: false, filtered: true })).toEqual(true) + }) + }) +}) diff --git a/src/item.js b/src/item.js index 2e29847e..9d7628af 100644 --- a/src/item.js +++ b/src/item.js @@ -10,7 +10,7 @@ module.exports = function (initValues, { element, template } = {}) { var init = function (values, { element, template } = {}) { if (element) item.elm = element - if (!template) throw new Error('no tempalte!') + if (!template) throw new Error('missing_item_template') item.template = template item.values(values) } From d538d091cc187725f921dc81f48e747381ec4977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Thu, 17 Dec 2020 00:29:22 +0100 Subject: [PATCH 41/42] Update string-natural-compare from 2.0.2 to 3.0.1 --- __test__/integration/sort.test.js | 10 +++------- package-lock.json | 6 +++--- package.json | 2 +- src/sort.js | 16 +++++++++++----- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/__test__/integration/sort.test.js b/__test__/integration/sort.test.js index c30503f8..bcbcdd1c 100644 --- a/__test__/integration/sort.test.js +++ b/__test__/integration/sort.test.js @@ -286,24 +286,20 @@ describe('Sort', function () { expect(list.items[11].values().val).toBe('z') }) - it('should handle not longer (since 1.4.0) space and zero the same for desc and asc', function () { + it('should handle space and zero the same for desc and asc (worked 1.4.0 - 2.3.0 then string-natural-compare was updated)', function () { list.clear() list.add({ val: '' }) list.add({ val: '0' }) - list.add({ val: 0 }) list.sort('val', { order: 'asc' }) expect(list.items[0].values().val).toBe('') expect(list.items[1].values().val).toBe('0') - expect(list.items[2].values().val).toBe(0) list.sort('val', { order: 'desc' }) - expect(list.items[0].values().val).toBe('0') - expect(list.items[1].values().val).toBe(0) - expect(list.items[2].values().val).toBe('') + expect(list.items[0].values().val).toBe('') + expect(list.items[1].values().val).toBe('0') list.sort('val', { order: 'asc' }) expect(list.items[0].values().val).toBe('') expect(list.items[1].values().val).toBe('0') - expect(list.items[2].values().val).toBe(0) }) }) diff --git a/package-lock.json b/package-lock.json index fe1950dc..75cda77e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6529,9 +6529,9 @@ } }, "string-natural-compare": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-2.0.3.tgz", - "integrity": "sha512-4Kcl12rNjc+6EKhY8QyDVuQTAlMWwRiNbsxnVwBUKFr7dYPQuXVrtNU4sEkjF9LHY0AY6uVbB3ktbkIH4LC+BQ==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==" }, "strip-bom": { "version": "4.0.0", diff --git a/package.json b/package.json index ddf8dadb..29edf624 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "url": "https://github.com/javve/list.js/issues" }, "dependencies": { - "string-natural-compare": "^2.0.2" + "string-natural-compare": "^3.0.1" }, "devDependencies": { "@babel/core": "^7.12.7", diff --git a/src/sort.js b/src/sort.js index 4e4b415f..1020d0c7 100644 --- a/src/sort.js +++ b/src/sort.js @@ -77,12 +77,18 @@ module.exports = function (list) { } } else { sortFunction = function (itemA, itemB) { - var sort = list.utils.naturalSort - sort.alphabet = list.alphabet || options.alphabet || undefined - if (!sort.alphabet && options.insensitive) { - sort = list.utils.naturalSort.caseInsensitive + var naturalSortOptions = {} + naturalSortOptions.alphabet = list.alphabet || options.alphabet || undefined + if (!naturalSortOptions.alphabet && options.insensitive) { + naturalSortOptions.caseInsensitive = true } - return sort(itemA.values()[options.valueName], itemB.values()[options.valueName]) * multi + return ( + list.utils.naturalSort( + '' + itemA.values()[options.valueName], + '' + itemB.values()[options.valueName], + naturalSortOptions + ) * multi + ) } } From ae7e92962e3378f6ad9dbd25948190cbd1685942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonny=20Str=C3=B6mberg?= Date: Thu, 17 Dec 2020 00:32:47 +0100 Subject: [PATCH 42/42] Refactor sort and sort listeners + add unit tests --- __test__/unit/sort-buttons.test.js | 210 ++++++++++++++++++++++++++ __test__/unit/sort.test.js | 230 +++++++++++++++++++++++++++++ src/index.js | 43 +++++- src/sort-buttons.js | 75 ++++++++++ src/sort.js | 131 ++++------------ 5 files changed, 581 insertions(+), 108 deletions(-) create mode 100644 __test__/unit/sort-buttons.test.js create mode 100644 __test__/unit/sort.test.js create mode 100644 src/sort-buttons.js diff --git a/__test__/unit/sort-buttons.test.js b/__test__/unit/sort-buttons.test.js new file mode 100644 index 00000000..5666f293 --- /dev/null +++ b/__test__/unit/sort-buttons.test.js @@ -0,0 +1,210 @@ +const naturalSort = require('string-natural-compare') +const $ = require('jquery') + +const Item = require('../../src/item') +const templater = require('../../src/templater') +const { + addSortListeners, + getInSensitive, + getNextSortOrder, + setSortOrder, + clearSortOrder, +} = require('../../src/sort-buttons') + +describe('sort listeners', function () { + describe('getInSensitive', () => { + it('should be false if data-insensitive is false', () => { + const button = $(`