@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.
- package/assets/css/components/dialog.css +1 -1
- package/assets/css/components/dialog.css.map +1 -1
- package/assets/css/components/fileupload.css +1 -0
- package/assets/css/components/fileupload.css.map +1 -0
- package/assets/css/components/forms.css +1 -1
- package/assets/css/components/forms.css.map +1 -1
- package/assets/css/core.min.css +1 -1
- package/assets/css/core.min.css.map +1 -1
- package/assets/css/style.min.css +1 -1
- package/assets/css/style.min.css.map +1 -1
- package/assets/js/components/accordion/accordion.component.min.js +1 -1
- package/assets/js/components/applied-filters/applied-filters.component.min.js +1 -1
- package/assets/js/components/card/card.component.min.js +1 -1
- package/assets/js/components/fileupload/fileupload.component.js +44 -0
- package/assets/js/components/filterlist/filterlist.component.min.js +1 -1
- package/assets/js/components/header/header.component.min.js +1 -1
- package/assets/js/components/notification/notification.component.min.js +1 -1
- package/assets/js/components/pagination/pagination.component.min.js +1 -1
- package/assets/js/components/table/table.component.min.js +4 -4
- package/assets/js/components/table/table.component.min.js.map +1 -1
- package/assets/js/components/tabs/tabs.component.min.js +1 -1
- package/assets/js/dynamic.min.js +5 -5
- package/assets/js/dynamic.min.js.map +1 -1
- package/assets/js/modules/data-layer.js +32 -34
- package/assets/js/modules/dialogs.js +1 -1
- package/assets/js/modules/fileupload.js +70 -0
- package/assets/js/modules/inputs.js +10 -0
- package/assets/js/modules/table.js +0 -1
- package/assets/js/scripts.bundle.js +20 -20
- package/assets/js/scripts.bundle.js.map +1 -1
- package/assets/js/scripts.bundle.min.js +2 -2
- package/assets/js/scripts.bundle.min.js.map +1 -1
- package/assets/sass/_forms.scss +1 -1
- package/assets/sass/components/dialog.scss +3 -1
- package/assets/sass/components/fileupload.scss +156 -0
- package/assets/sass/components/forms.scss +98 -135
- package/assets/ts/components/fileupload/README.md +13 -0
- package/assets/ts/components/fileupload/fileupload.component.ts +55 -0
- package/assets/ts/modules/data-layer.md +72 -0
- package/assets/ts/modules/data-layer.ts +37 -41
- package/assets/ts/modules/dialogs.ts +1 -1
- package/assets/ts/modules/fileupload.ts +106 -0
- package/assets/ts/modules/inputs.ts +14 -0
- package/assets/ts/modules/table.ts +1 -1
- package/assets/ts/tests/data-layer.spec.js +69 -0
- package/dist/components.es.js +784 -748
- package/dist/components.umd.js +40 -25
- package/package.json +1 -1
- package/src/components/FileUpload/FileUpload.vue +29 -0
- package/src/components/FileUpload/README.md +13 -0
- package/src/index.js +1 -1
- package/src/components/FileUploads/FileUploads.vue +0 -48
- 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
|
-
|
|
12
|
-
|
|
10
|
+
event: "Pageview",
|
|
11
|
+
pageTitle: document.title,
|
|
13
12
|
});
|
|
14
|
-
|
|
15
|
-
// Global events to track
|
|
16
|
-
document.addEventListener('click', (event) => {
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
48
|
-
|
|
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
|
-
|
|
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
|
+
});
|