@iamproperty/components 3.7.8--beta-2 → 3.7.9-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/assets/css/components/dialog.css +1 -1
  2. package/assets/css/components/dialog.css.map +1 -1
  3. package/assets/css/components/fileupload.css +1 -0
  4. package/assets/css/components/fileupload.css.map +1 -0
  5. package/assets/css/components/forms.css +1 -1
  6. package/assets/css/components/forms.css.map +1 -1
  7. package/assets/css/core.min.css +1 -1
  8. package/assets/css/core.min.css.map +1 -1
  9. package/assets/css/style.min.css +1 -1
  10. package/assets/css/style.min.css.map +1 -1
  11. package/assets/js/components/accordion/accordion.component.min.js +1 -1
  12. package/assets/js/components/applied-filters/applied-filters.component.min.js +1 -1
  13. package/assets/js/components/card/card.component.min.js +1 -1
  14. package/assets/js/components/fileupload/fileupload.component.js +44 -0
  15. package/assets/js/components/filterlist/filterlist.component.min.js +1 -1
  16. package/assets/js/components/header/header.component.min.js +1 -1
  17. package/assets/js/components/notification/notification.component.min.js +1 -1
  18. package/assets/js/components/pagination/pagination.component.min.js +1 -1
  19. package/assets/js/components/table/table.component.min.js +10 -10
  20. package/assets/js/components/table/table.component.min.js.map +1 -1
  21. package/assets/js/components/tabs/tabs.component.min.js +1 -1
  22. package/assets/js/dynamic.min.js +5 -5
  23. package/assets/js/dynamic.min.js.map +1 -1
  24. package/assets/js/modules/data-layer.js +32 -34
  25. package/assets/js/modules/dialogs.js +1 -1
  26. package/assets/js/modules/fileupload.js +70 -0
  27. package/assets/js/modules/inputs.js +10 -0
  28. package/assets/js/modules/table.js +49 -31
  29. package/assets/js/scripts.bundle.js +22 -22
  30. package/assets/js/scripts.bundle.js.map +1 -1
  31. package/assets/js/scripts.bundle.min.js +2 -2
  32. package/assets/js/scripts.bundle.min.js.map +1 -1
  33. package/assets/sass/_forms.scss +1 -1
  34. package/assets/sass/components/dialog.scss +3 -1
  35. package/assets/sass/components/fileupload.scss +156 -0
  36. package/assets/sass/components/forms.scss +98 -135
  37. package/assets/ts/components/accordion/README.md +15 -0
  38. package/assets/ts/components/applied-filters/README.md +15 -0
  39. package/assets/ts/components/card/README.md +15 -0
  40. package/assets/ts/components/fileupload/README.md +28 -0
  41. package/assets/ts/components/fileupload/fileupload.component.ts +55 -0
  42. package/assets/ts/components/filterlist/README.md +15 -0
  43. package/assets/ts/components/header/README.md +16 -3
  44. package/assets/ts/components/notification/README.md +15 -0
  45. package/assets/ts/components/pagination/README.md +15 -0
  46. package/assets/ts/components/table/README.md +15 -0
  47. package/assets/ts/components/tabs/README.md +15 -0
  48. package/assets/ts/modules/data-layer.md +72 -0
  49. package/assets/ts/modules/data-layer.ts +37 -41
  50. package/assets/ts/modules/dialogs.ts +1 -1
  51. package/assets/ts/modules/fileupload.ts +106 -0
  52. package/assets/ts/modules/inputs.ts +14 -0
  53. package/assets/ts/modules/table.ts +67 -44
  54. package/assets/ts/tests/data-layer.spec.js +69 -0
  55. package/dist/components.es.js +1122 -1148
  56. package/dist/components.umd.js +55 -40
  57. package/package.json +1 -1
  58. package/src/components/Card/Card.vue +8 -4
  59. package/src/components/FileUpload/FileUpload.vue +29 -0
  60. package/src/components/FileUpload/README.md +13 -0
  61. package/src/index.js +1 -1
  62. package/src/components/FileUploads/FileUploads.vue +0 -48
  63. package/src/components/FileUploads/README.md +0 -24
@@ -0,0 +1,55 @@
1
+ // @ts-nocheck
2
+ import fileupload from "../../modules/fileupload";
3
+
4
+ // Data layer Web component created
5
+ window.dataLayer = window.dataLayer || [];
6
+ window.dataLayer.push({
7
+ "event": "customElementRegistered",
8
+ "element": "fileupload"
9
+ });
10
+
11
+ class iamFileupload extends HTMLElement {
12
+
13
+ constructor(){
14
+ super();
15
+ this.attachShadow({ mode: 'open'});
16
+
17
+ const assetLocation = document.body.hasAttribute('data-assets-location') ? document.body.getAttribute('data-assets-location') : '/assets'
18
+ const coreCSS = document.body.hasAttribute('data-core-css') ? document.body.getAttribute('data-core-css') : `${assetLocation}/css/core.min.css`;
19
+ const loadCSS = `@import "${assetLocation}/css/components/fileupload.css";`;
20
+
21
+ const template = document.createElement('template');
22
+ template.innerHTML = `
23
+ <style>
24
+ @import "${coreCSS}";
25
+ ${loadCSS}
26
+ ${this.hasAttribute('css') ? `@import "${this.getAttribute('css')}";` : ``}
27
+ </style>
28
+ <div class="file-upload">
29
+ <span class="file-upload__title">Upload file</span>
30
+ <p class="helper-text"></p>
31
+ <button class="btn btn-primary"><slot name="btn"></slot> Upload document</button>
32
+ <div class="drop-area"></div>
33
+ <hr/>
34
+ <slot></slot>
35
+ <div class="files"></div>
36
+ </div>
37
+ `;
38
+ this.shadowRoot.appendChild(template.content.cloneNode(true));
39
+ }
40
+
41
+ connectedCallback() {
42
+
43
+ this.innerHTML += '<i class="fa-regular fa-arrow-up-from-bracket me-2" aria-hidden="true" slot="btn"></i>';
44
+
45
+ const wrapper = this.shadowRoot.querySelector('.file-upload');
46
+ const input = this.querySelector('input');
47
+ const helperText = this.shadowRoot.querySelector('.helper-text');
48
+
49
+ helperText.innerHTML = `${this.hasAttribute('data-maxsize') ? `Max file size is ${this.getAttribute('data-maxsize')}kb. ` : '' }${ input.hasAttribute('accept') ? `Supported file types are ${input.getAttribute('accept')}` : '' }`;
50
+
51
+ fileupload(this,wrapper);
52
+ }
53
+ }
54
+
55
+ export default iamFileupload;
@@ -1,3 +1,18 @@
1
+ **Add the below to your initialise script**
2
+
3
+ ```
4
+ import('../node_modules/@iamproperty/components/assets/js/components/filterlist/filterlist.component.min').then(module => { // Might need to update the path
5
+
6
+ if (!window.customElements.get(`iam-filterlist`))
7
+ window.customElements.define(`iam-filterlist`, module.default);
8
+
9
+ }).catch((err) => {
10
+ console.log(err.message);
11
+ });
12
+ ```
13
+
14
+ **Add the below HTML code to where you want the component to live.**
15
+
1
16
  ```
2
17
  <iam-filterlist>
3
18
  <ul>
@@ -1,4 +1,17 @@
1
- ### Usage
1
+ **Add the below to your initialise script**
2
+
3
+ ```
4
+ import('../node_modules/@iamproperty/components/assets/js/components/filterlist/filterlist.component.min').then(module => { // Might need to update the path
5
+
6
+ if (!window.customElements.get(`iam-filterlist`))
7
+ window.customElements.define(`iam-filterlist`, module.default);
8
+
9
+ }).catch((err) => {
10
+ console.log(err.message);
11
+ });
12
+ ```
13
+
14
+ **Add the below HTML code to where you want the component to live.**
2
15
 
3
16
  ```
4
17
  <iam-header class="bg-secondary" image="/shutterstock_1229155495.webp">
@@ -11,14 +24,14 @@
11
24
  </iam-header>
12
25
  ```
13
26
 
14
- ### Properties
27
+ **Properties**
15
28
 
16
29
  | Option | Type | Default Value | Description |
17
30
  | ------ | ---- | ------------- | ----------- |
18
31
  | image | String | - | Optional image url to display in the background |
19
32
 
20
33
 
21
- ### Slots
34
+ **Slots**
22
35
 
23
36
  | Option | Default Value | Description |
24
37
  | ------ | ------------- | ----------- |
@@ -1,3 +1,18 @@
1
+ **Add the below to your initialise script**
2
+
3
+ ```
4
+ import('../node_modules/@iamproperty/components/assets/js/components/notification/notification.component.min').then(module => { // Might need to update the path
5
+
6
+ if (!window.customElements.get(`iam-notification`))
7
+ window.customElements.define(`iam-notification`, module.default);
8
+
9
+ }).catch((err) => {
10
+ console.log(err.message);
11
+ });
12
+ ```
13
+
14
+ **Add the below HTML code to where you want the component to live.**
15
+
1
16
  ```
2
17
  <!-- Inline -->
3
18
  <iam-notification data-status="danger" data-dismiss="">
@@ -1,3 +1,18 @@
1
+ **Add the below to your initialise script**
2
+
3
+ ```
4
+ import('../node_modules/@iamproperty/components/assets/js/components/pagination/pagination.component.min').then(module => { // Might need to update the path
5
+
6
+ if (!window.customElements.get(`iam-pagination`))
7
+ window.customElements.define(`iam-pagination`, module.default);
8
+
9
+ }).catch((err) => {
10
+ console.log(err.message);
11
+ });
12
+ ```
13
+
14
+ **Add the below HTML code to where you want the component to live.**
15
+
1
16
  ```
2
17
  <iam-pagination data-total="12"></iam-pagination>
3
18
  ```
@@ -1,3 +1,18 @@
1
+ **Add the below to your initialise script**
2
+
3
+ ```
4
+ import('../node_modules/@iamproperty/components/assets/js/components/table/table.component.min').then(module => { // Might need to update the path
5
+
6
+ if (!window.customElements.get(`iam-table`))
7
+ window.customElements.define(`iam-table`, module.default);
8
+
9
+ }).catch((err) => {
10
+ console.log(err.message);
11
+ });
12
+ ```
13
+
14
+ **Add the below HTML code to where you want the component to live.**
15
+
1
16
  ```
2
17
  <iam-table class="container">
3
18
  <table>
@@ -1,3 +1,18 @@
1
+ **Add the below to your initialise script**
2
+
3
+ ```
4
+ import('../node_modules/@iamproperty/components/assets/js/components/tabs/tabs.component.min').then(module => { // Might need to update the path
5
+
6
+ if (!window.customElements.get(`iam-tabs`))
7
+ window.customElements.define(`iam-tabs`, module.default);
8
+
9
+ }).catch((err) => {
10
+ console.log(err.message);
11
+ });
12
+ ```
13
+
14
+ **Add the below HTML code to where you want the component to live.**
15
+
1
16
  ```
2
17
  <iam-tabs class="container">
3
18
  <details>
@@ -0,0 +1,72 @@
1
+ # Function `createDataLayer()`
2
+
3
+ The `createDataLayer()` function sets up a dataLayer for tracking events and interactions on a web page. It initializes the `window.dataLayer` array if it doesn't exist, and then pushes a "Pageview" event with the current document title. It also attaches a click event listener to the document, which tracks additional events related to clicks on elements like `summary`, `a` (anchor), and `button` elements.
4
+
5
+ ## Usage
6
+
7
+ The `createDataLayer()` function should be called in the JavaScript code of the web page, typically during its initialization phase. This allows the dataLayer to be available for tracking various events and interactions.
8
+
9
+ ## Function Signature
10
+
11
+ `function createDataLayer(): void`
12
+
13
+ ## Events Tracked
14
+
15
+ 1. **"Pageview" Event**
16
+
17
+ - Description: This event is automatically pushed to the `window.dataLayer` array during the function's execution, representing the initial pageview with the current document title.
18
+ - Event Data:
19
+ - `event`: "Pageview"
20
+ - `pageTitle`: The title of the current document.
21
+ 2. **"closeDetails" Event**
22
+
23
+ - Description: This event is triggered when a click occurs on an element with the attribute `[open] summary`, indicating that a summary element with the `[open]` attribute is being closed.
24
+ - Event Data:
25
+ - `event`: "closeDetails"
26
+ - `detailsTitle`: The text content of the `summary` element associated with the clicked element. If the `summary` element doesn't have any text content, an empty string is used.
27
+ 3. **"openDetails" Event**
28
+
29
+ - Description: This event is triggered when a click occurs on a `summary` element (not associated with `[open]` attribute), indicating that a summary element is being opened.
30
+ - Event Data:
31
+ - `event`: "openDetails"
32
+ - `detailsTitle`: The text content of the clicked `summary` element. If the `summary` element doesn't have any text content, an empty string is used.
33
+ 4. **"linkClicked" Event**
34
+
35
+ - Description: This event is triggered when a click occurs on an `a` (anchor) element.
36
+ - Event Data:
37
+ - `event`: "linkClicked"
38
+ - `linkText`: The text content of the clicked `a` element. If the `a` element has a `title` attribute, its value is used as `linkText`; otherwise, the text content of the `a` element is used. If the `a` element doesn't have any text content, an empty string is used.
39
+ - `class`: The `class` attribute value of the `a` element. If the `a` element doesn't have a `class` attribute, an empty string is used.
40
+ - `href`: The value of the `href` attribute of the `a` element. If the `a` element doesn't have an `href` attribute, an empty string is used.
41
+ 5. **"buttonClicked" Event**
42
+
43
+ - Description: This event is triggered when a click occurs on a `button` element.
44
+ - Event Data:
45
+ - `event`: "buttonClicked"
46
+ - `buttonText`: The text content of the clicked `button` element. If the `button` element doesn't have any text content, an empty string is used.
47
+ - `class`: The `class` attribute value of the `button` element. If the `button` element doesn't have a `class` attribute, an empty string is used.
48
+
49
+ ## Notes
50
+
51
+ - The function relies on the `window.dataLayer` array to store the events, so it should be executed after the page has loaded and the `window` object is available.
52
+ - This implementation assumes that the JavaScript code is placed at the end of the HTML document, ensuring that the DOM elements are accessible at the time the function is executed.
53
+
54
+ ### Example Usage
55
+
56
+ ```
57
+ <!DOCTYPE html>
58
+ <html>
59
+ <head>
60
+ <title>My Web Page</title>
61
+ </head>
62
+ <body>
63
+ <!-- Your web page content here -->
64
+
65
+ <script> // Call the createDataLayer function to initialize event tracking
66
+ createDataLayer();
67
+ </script>
68
+ </body>
69
+ </html>
70
+ ```
71
+
72
+ In this example, the `createDataLayer()` function is called in a script block within the HTML document, allowing it to set up the dataLayer for event tracking on the page.
@@ -4,54 +4,50 @@ type WindowWithDataLayer = Window & {
4
4
 
5
5
  declare const window: WindowWithDataLayer;
6
6
 
7
- function createDataLayer () {
8
-
7
+ function createDataLayer(): void {
9
8
  window.dataLayer = window.dataLayer || [];
10
9
  window.dataLayer.push({
11
- "event": "Pageview",
12
- "pageTitle": document.title
10
+ event: "Pageview",
11
+ pageTitle: document.title,
13
12
  });
14
-
15
- // Global events to track
16
- document.addEventListener('click', (event) => {
17
13
 
18
- if (event && event.target instanceof HTMLElement && event.target.closest('[open] summary')){
19
- window.dataLayer.push({
20
- "event": "closeDetails",
21
- // @ts-ignore: Object is possibly 'null'.
22
- "detailsTitle": event.target.closest('summary').textContent
23
- });
24
- }
25
- else if (event && event.target instanceof HTMLElement && event.target.closest('summary')){
26
-
27
- window.dataLayer.push({
28
- "event": "openDetails",
29
- // @ts-ignore: Object is possibly 'null'.
30
- "detailsTitle": event.target.closest('summary').textContent
31
- });
32
- }
33
-
34
- if (event && event.target instanceof HTMLElement && event.target.closest('a')){
35
- window.dataLayer.push({
36
- "event": "linkClicked",
37
- // @ts-ignore: Object is possibly 'null'.
38
- "linkText": event.target.closest('a').hasAttribute('title') ? event.target.closest('a').getAttribute('title') : event.target.closest('a').textContent,
39
- // @ts-ignore: Object is possibly 'null'.
40
- "class": (event.target.closest('a').hasAttribute('class') ? event.target.closest('a').getAttribute('class') : ''),
41
- // @ts-ignore: Object is possibly 'null'.
42
- "href": event.target.closest('a').getAttribute('href')
43
- });
44
- }
45
- if (event && event.target instanceof HTMLElement && event.target.closest('button')){
14
+ document.addEventListener("click", (event: MouseEvent) => {
15
+ const target = (event.target as HTMLElement).closest<HTMLElement>("[open] summary");
16
+
17
+ if (target) {
46
18
  window.dataLayer.push({
47
- "event": "buttonClicked",
48
- // @ts-ignore: Object is possibly 'null'.
49
- "buttonText": event.target.closest('button').textContent,
50
- // @ts-ignore: Object is possibly 'null'.
51
- "class": (event.target.closest('button').hasAttribute('class') ? event.target.closest('button').getAttribute('class') : '')
19
+ event: "closeDetails",
20
+ detailsTitle: target.textContent || "",
52
21
  });
53
- }
22
+ } else {
23
+ const summary = (event.target as HTMLElement).closest<HTMLElement>("summary");
24
+ const link = (event.target as HTMLElement).closest<HTMLAnchorElement>("a");
25
+ const button = (event.target as HTMLElement).closest<HTMLButtonElement>("button");
54
26
 
27
+ if (summary) {
28
+ window.dataLayer.push({
29
+ event: "openDetails",
30
+ detailsTitle: summary.textContent || "",
31
+ });
32
+ }
33
+
34
+ if (link) {
35
+ window.dataLayer.push({
36
+ event: "linkClicked",
37
+ linkText: link.hasAttribute("title") ? link.getAttribute("title") || "" : link.textContent || "",
38
+ class: link.hasAttribute("class") ? link.getAttribute("class") || "" : "",
39
+ href: link.getAttribute("href") || "",
40
+ });
41
+ }
42
+
43
+ if (button) {
44
+ window.dataLayer.push({
45
+ event: "buttonClicked",
46
+ buttonText: button.textContent || "",
47
+ class: button.hasAttribute("class") ? button.getAttribute("class") || "" : "",
48
+ });
49
+ }
50
+ }
55
51
  });
56
52
  }
57
53
 
@@ -151,7 +151,7 @@ const extendDialogs = (body) => {
151
151
  let windowPos = window.innerHeight - window.scrollY;
152
152
  if(popoverBottom > windowPos){
153
153
 
154
- let currentStyle = popover.getAttribute('style');
154
+ let currentStyle = popover.hasAttribute('style') ? popover.getAttribute('style')+' ' : '';
155
155
 
156
156
  popover.setAttribute('style',currentStyle+`transform: translate(0, calc(-100% - 4rem))`);
157
157
  }
@@ -0,0 +1,106 @@
1
+ // @ts-nocheck
2
+ function fileupload(fileupload: Element, wrapper: Element) {
3
+
4
+ const filesWrapper = wrapper.querySelector('.files');
5
+ const dropArea = wrapper.querySelector('.drop-area');
6
+ const input = fileupload.querySelector('input');
7
+ const maxSize = fileupload.hasAttribute('data-maxsize') ? fileupload.getAttribute('data-maxsize') : 0;
8
+
9
+ // We clone the input field to work as a buffer input field, this allows us to add new files without losing the old ones
10
+ const cloneInput = input.cloneNode();
11
+ dropArea.append(cloneInput);
12
+
13
+ wrapper.addEventListener('click', (event) => {
14
+
15
+ if (event && event.target instanceof HTMLElement && event.target.closest('.btn-primary')){
16
+
17
+ const button = event.target.closest('.btn-primary');
18
+
19
+ // If the input allows multiples then use the buffer clone input
20
+ const inputTrigger = input.hasAttribute('multiple') ? cloneInput : input;
21
+
22
+ inputTrigger.click();
23
+ }
24
+ });
25
+
26
+ wrapper.addEventListener('click', (event) => {
27
+
28
+ if (event && event.target instanceof HTMLElement && event.target.closest('.files button')){
29
+
30
+ const dt = new DataTransfer();
31
+ const { files } = input;
32
+ const button = event.target.closest('.files button');
33
+
34
+ for (let i = 0; i < files.length; i++) {
35
+ const file = files[i]
36
+
37
+ if(file.name != button.getAttribute('data-file'))
38
+ dt.items.add(file) // here you exclude the file. thus removing it.
39
+ }
40
+
41
+ input.files = dt.files // Assign the updates list
42
+
43
+ const changeEvent = new Event('change');
44
+ input.dispatchEvent(changeEvent);
45
+ }
46
+ });
47
+
48
+ // Buffer input change event
49
+ cloneInput.addEventListener('change', (event) => {
50
+
51
+ if(input.hasAttribute('multiple')){
52
+ const filesArray = [...input.files, ...cloneInput.files];
53
+
54
+ let fileNames = [];
55
+
56
+ const dt = new DataTransfer();
57
+
58
+ for (let i = 0; i < filesArray.length; i++) {
59
+ const file = filesArray[i]
60
+
61
+ const size = file.size/1000;
62
+
63
+ if(!fileNames.includes(file.name) && (maxSize == 0 || size < maxSize))
64
+ dt.items.add(file) // here you exclude the file. thus removing it.
65
+
66
+ fileNames.push(file.name);
67
+ }
68
+
69
+ input.files = dt.files;
70
+ }
71
+ else {
72
+
73
+ input.files = cloneInput.files;
74
+ }
75
+
76
+ const changeEvent = new Event('change');
77
+ input.dispatchEvent(changeEvent);
78
+ });
79
+
80
+
81
+ cloneInput.addEventListener('dragenter', (event) => {
82
+
83
+ cloneInput.classList.add('focus');
84
+ });
85
+
86
+ cloneInput.addEventListener('dragleave', (event) => {
87
+
88
+ cloneInput.classList.remove('focus');
89
+ });
90
+
91
+ cloneInput.addEventListener('drop', (event) => {
92
+
93
+ cloneInput.classList.remove('focus');
94
+ });
95
+
96
+ input.addEventListener('change', (event) => {
97
+
98
+ // Reset
99
+ filesWrapper.innerHTML = '';
100
+
101
+ for (const file of input.files)
102
+ filesWrapper.innerHTML += `<span class="file">${file.name} <button data-file="${file.name}">Remove</button></span>`;
103
+ });
104
+ }
105
+
106
+ export default fileupload;
@@ -40,6 +40,20 @@ const extendInputs = (body) => {
40
40
  changeType(input,newType);
41
41
  }
42
42
  }
43
+
44
+ if (event && event.target instanceof HTMLElement && event.target.closest('dialog [type="radio"]')){
45
+
46
+ const dialog = event.target.closest('dialog');
47
+ const radio = event.target.closest('dialog [type="radio"]');
48
+
49
+ Array.from(dialog.querySelectorAll('[type="radio"][autofocus]')).forEach((input,index) => {
50
+ input.removeAttribute('autofocus');
51
+ });
52
+
53
+ Array.from(dialog.querySelectorAll('[type="radio"]:checked')).forEach((input,index) => {
54
+ input.setAttribute('autofocus',true);
55
+ });
56
+ }
43
57
  });
44
58
 
45
59
  body.addEventListener('click', (event) => {
@@ -160,6 +160,16 @@ export const addFilterEventListeners = (table, form, pagination, wrapper, savedT
160
160
  createPaginationButttons(wrapper,pagination);
161
161
  populateDataQueries(table,form);
162
162
  }
163
+
164
+ // Pass post data back to the page
165
+ if(form.hasAttribute('data-ajax-post')){
166
+
167
+ let formData = new FormData(form);
168
+ let queryString = new URLSearchParams(formData).toString();
169
+ const http = new XMLHttpRequest()
170
+ http.open('GET', `${window.location.href}?ajax=true&${queryString}`);
171
+ http.send();
172
+ }
163
173
  }
164
174
 
165
175
  form.addEventListener('keyup', (event) => {
@@ -417,7 +427,7 @@ export const filterTable = (table, form, wrapper) => {
417
427
 
418
428
  table.classList.remove('table--filtered');
419
429
 
420
- let filters = [];
430
+ let filters = filterFilters(form);
421
431
  let searches = [];
422
432
  let matched = 0;
423
433
  let page = form.querySelector('[data-pagination]') ? parseInt(form.querySelector('[data-pagination]').value) : 1;
@@ -432,40 +442,6 @@ export const filterTable = (table, form, wrapper) => {
432
442
  row.removeAttribute('data-filtered-by');
433
443
  });
434
444
 
435
- // Filter
436
- let filterInputs = Array.from(form.querySelectorAll('[data-filter]'));
437
-
438
- filterInputs.forEach((filterInput, index) => {
439
-
440
- // Ignore uncked radio inputs
441
- if(filterInput.type == 'radio' && !filterInput.checked){
442
- return;
443
- }
444
-
445
- if(filterInput.type == 'checkbox' && !filterInput.checked){
446
- return;
447
- }
448
-
449
-
450
- if(filterInput.getAttribute('data-filter') == "multi"){
451
-
452
- for (const [key, value] of Object.entries(JSON.parse(filterInput.value))) {
453
- filters[filterInput.getAttribute('data-filter')].push(value);
454
- }
455
- }
456
- else if (filterInput && filterInput.value) {
457
-
458
- let dataFilter = filterInput.getAttribute('data-filter');
459
-
460
- if(!filters[dataFilter])
461
- filters[dataFilter] = new Array();
462
-
463
- filters[dataFilter].push(filterInput.value);
464
- }
465
-
466
- });
467
-
468
-
469
445
  // Add search columns too
470
446
  if(form.querySelector('[data-search]')){
471
447
  let searchInput = form.querySelector('[data-search]');
@@ -482,10 +458,10 @@ export const filterTable = (table, form, wrapper) => {
482
458
  element.innerHTML = '';
483
459
  });
484
460
 
485
- if(filters.length) {
461
+ if(Object.keys(filters).length) {
486
462
 
487
463
  Array.from(form.querySelectorAll('[data-filter-count]')).forEach((element, index) => {
488
- element.innerHTML += `(${filters.length})`;
464
+ element.innerHTML += `(${Object.keys(filters).length})`;
489
465
  });
490
466
  }
491
467
 
@@ -804,7 +780,37 @@ export const makeTableFunctional = function(table, form, pagination, wrapper){
804
780
  }
805
781
  }
806
782
 
783
+ const filterFilters = function(form){
784
+
785
+ let filters = new Object();
807
786
 
787
+ // Filter
788
+ let filterInputs = Array.from(form.querySelectorAll('[data-filter]'));
789
+
790
+ filterInputs.forEach((filterInput, index) => {
791
+
792
+ // Ignore uncked radio inputs
793
+ if(filterInput.type == 'radio' && !filterInput.checked){
794
+ return;
795
+ }
796
+
797
+ if(filterInput.type == 'checkbox' && !filterInput.checked){
798
+ return;
799
+ }
800
+
801
+ if (filterInput && filterInput.value) {
802
+
803
+ let dataFilter = filterInput.getAttribute('data-filter');
804
+
805
+ if(!filters[dataFilter])
806
+ filters[dataFilter] = new Array();
807
+
808
+ filters[dataFilter].push(filterInput.value);
809
+ }
810
+ });
811
+
812
+ return filters;
813
+ }
808
814
 
809
815
  export const loadAjaxTable = async function (table, form, pagination, wrapper){
810
816
 
@@ -818,6 +824,20 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper){
818
824
 
819
825
  wrapper.classList.add('table--loading');
820
826
 
827
+ // Display the filter count
828
+ let filters = filterFilters(form);
829
+
830
+ Array.from(form.querySelectorAll('[data-filter-count]')).forEach((element, index) => {
831
+ element.innerHTML = '';
832
+ });
833
+
834
+ if(Object.keys(filters).length) {
835
+
836
+ Array.from(form.querySelectorAll('[data-filter-count]')).forEach((element, index) => {
837
+ element.innerHTML += `(${Object.keys(filters).length})`;
838
+ });
839
+ }
840
+
821
841
  // Setup controller vars if not already set
822
842
  if(!window.controller)
823
843
  window.controller = [];
@@ -927,6 +947,16 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper){
927
947
  makeTableFunctional(table, form, pagination, wrapper);
928
948
  createPaginationButttons(wrapper, pagination);
929
949
 
950
+ Array.from(form.querySelectorAll('[data-ajax-query]')).forEach((queryElement, index) => {
951
+
952
+ let totalNumber = resolvePath(response, queryElement.getAttribute('data-ajax-query'), '');
953
+
954
+ if(queryElement.hasAttribute('data-total'))
955
+ queryElement.setAttribute('data-total', totalNumber);
956
+ else
957
+ queryElement.innerHTML = totalNumber;
958
+ });
959
+
930
960
  if(parseInt(totalNumber) == 0){
931
961
  tbody.innerHTML = `<tr><td colspan="100%"><span>${emptyMsg}</span></td></tr>`;
932
962
  }
@@ -943,13 +973,6 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper){
943
973
  else {
944
974
  tbody.innerHTML = '<tr><td colspan="100%"><span>Error loading table</span></td></tr>';
945
975
  }
946
-
947
- // Pass post data back to the page
948
- if(form.hasAttribute('data-ajax-post')){
949
- const http = new XMLHttpRequest()
950
- http.open('GET', `${window.location.href}?ajax=true&${queryString}`);
951
- http.send();
952
- }
953
976
  });
954
977
  } catch (error) {
955
978
  console.log(error);