@iamproperty/components 3.7.8--beta → 3.7.8

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 (53) 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 +4 -4
  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 +0 -1
  29. package/assets/js/scripts.bundle.js +20 -20
  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/fileupload/README.md +13 -0
  38. package/assets/ts/components/fileupload/fileupload.component.ts +55 -0
  39. package/assets/ts/modules/data-layer.md +72 -0
  40. package/assets/ts/modules/data-layer.ts +37 -41
  41. package/assets/ts/modules/dialogs.ts +1 -1
  42. package/assets/ts/modules/fileupload.ts +106 -0
  43. package/assets/ts/modules/inputs.ts +14 -0
  44. package/assets/ts/modules/table.ts +1 -1
  45. package/assets/ts/tests/data-layer.spec.js +69 -0
  46. package/dist/components.es.js +784 -748
  47. package/dist/components.umd.js +40 -25
  48. package/package.json +1 -1
  49. package/src/components/FileUpload/FileUpload.vue +29 -0
  50. package/src/components/FileUpload/README.md +13 -0
  51. package/src/index.js +1 -1
  52. package/src/components/FileUploads/FileUploads.vue +0 -48
  53. package/src/components/FileUploads/README.md +0 -24
@@ -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) => {
@@ -923,7 +923,7 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper){
923
923
  wrapper.setAttribute('data-page', parseInt(currentPage));
924
924
  wrapper.setAttribute('data-pages', Math.ceil(wrapper.getAttribute('data-total') / wrapper.getAttribute('data-show')));
925
925
 
926
- filterTable(table, form, wrapper);
926
+
927
927
  makeTableFunctional(table, form, pagination, wrapper);
928
928
  createPaginationButttons(wrapper, pagination);
929
929
 
@@ -0,0 +1,69 @@
1
+ // @ts-nocheck
2
+ import '@testing-library/jest-dom'
3
+ import createDataLayer from "../modules/data-layer";
4
+
5
+ describe('createDataLayer', () => {
6
+ // Mocking the window object for testing
7
+ let mockDataLayer = [];
8
+ beforeEach(() => {
9
+ window.dataLayer = mockDataLayer;
10
+ document.title = 'Mock Page Title';
11
+ });
12
+
13
+ it('should push a "Pageview" event to dataLayer on function call', () => {
14
+ createDataLayer();
15
+ expect(window.dataLayer).toEqual([
16
+ {
17
+ event: 'Pageview',
18
+ pageTitle: 'Mock Page Title',
19
+ },
20
+ ]);
21
+ });
22
+
23
+ it('should push a "closeDetails" event when the document click target has "open" attribute and is summary element', () => {
24
+ // Create a mock DOM structure with a summary element having the 'open' attribute
25
+ document.body.innerHTML = `
26
+ <details>
27
+ <summary open>Summary Text</summary>
28
+ </details>
29
+ `;
30
+ const summaryElement = document.querySelector('summary');
31
+
32
+ // Simulate the click event on the summary element
33
+ const clickEvent = new MouseEvent('click', {
34
+ bubbles: true,
35
+ cancelable: true,
36
+ });
37
+ summaryElement.dispatchEvent(clickEvent);
38
+
39
+ expect(window.dataLayer).toEqual([
40
+ {
41
+ event: 'Pageview',
42
+ pageTitle: 'Mock Page Title',
43
+ },
44
+ {
45
+ event: 'openDetails',
46
+ detailsTitle: 'Summary Text',
47
+ },
48
+ ]);
49
+
50
+ summaryElement.dispatchEvent(clickEvent);
51
+ expect(window.dataLayer).toEqual([
52
+ {
53
+ event: 'Pageview',
54
+ pageTitle: 'Mock Page Title',
55
+ },
56
+ {
57
+ event: 'openDetails',
58
+ detailsTitle: 'Summary Text',
59
+ },
60
+ {
61
+ event: 'closeDetails',
62
+ detailsTitle: 'Summary Text',
63
+ },
64
+ ]);
65
+
66
+ });
67
+
68
+ // More test cases for other scenarios can be added here...
69
+ });