@iamproperty/components 5.5.1-beta-2 → 5.5.1-beta-5
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/actionbar.css +1 -1
- package/assets/css/components/actionbar.css.map +1 -1
- package/assets/css/components/actionbar.global.css +1 -1
- package/assets/css/components/actionbar.global.css.map +1 -1
- package/assets/css/components/inline-edit.css +1 -0
- package/assets/css/components/inline-edit.css.map +1 -0
- package/assets/css/components/inline-edit.preload.css +1 -0
- package/assets/css/components/inline-edit.preload.css.map +1 -0
- package/assets/css/components/multiselect.css +1 -0
- package/assets/css/components/multiselect.css.map +1 -0
- package/assets/css/components/multiselect.preload.css +1 -0
- package/assets/css/components/multiselect.preload.css.map +1 -0
- package/assets/css/components/nav.global.css +1 -1
- package/assets/css/components/nav.global.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/actionbar/actionbar.component.js +2 -0
- package/assets/js/components/actionbar/actionbar.component.min.js +5 -3
- package/assets/js/components/actionbar/actionbar.component.min.js.map +1 -1
- package/assets/js/components/address-lookup/address-lookup.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/collapsible-side/collapsible-side.component.min.js +1 -1
- package/assets/js/components/fileupload/fileupload.component.min.js +1 -1
- 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/inline-edit/inline-edit.component.js +148 -0
- package/assets/js/components/inline-edit/inline-edit.component.min.js +22 -0
- package/assets/js/components/inline-edit/inline-edit.component.min.js.map +1 -0
- package/assets/js/components/multiselect/multiselect.component.js +221 -0
- package/assets/js/components/multiselect/multiselect.component.min.js +25 -0
- package/assets/js/components/multiselect/multiselect.component.min.js.map +1 -0
- package/assets/js/components/nav/nav.component.min.js +2 -2
- 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/search/search.component.min.js +1 -1
- package/assets/js/components/search/search.component.min.js.map +1 -1
- package/assets/js/components/table/table.component.js +26 -14
- 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/helpers.js +4 -0
- package/assets/js/modules/inputs.js +6 -2
- package/assets/js/modules/table.js +36 -18
- package/assets/js/scripts.bundle.js +4 -4
- 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/_components.scss +5 -0
- package/assets/sass/components/actionbar.global.scss +10 -0
- package/assets/sass/components/actionbar.scss +20 -3
- package/assets/sass/components/inline-edit.preload.scss +98 -0
- package/assets/sass/components/inline-edit.scss +32 -0
- package/assets/sass/components/multiselect.preload.scss +37 -0
- package/assets/sass/components/multiselect.scss +186 -0
- package/assets/sass/components/nav.global.scss +2 -0
- package/assets/sass/elements/admin-panel.scss +0 -3
- package/assets/sass/elements/badge-tag.scss +15 -5
- package/assets/sass/elements/forms.scss +16 -3
- package/assets/ts/components/actionbar/actionbar.component.ts +2 -0
- package/assets/ts/components/inline-edit/README.md +30 -0
- package/assets/ts/components/inline-edit/inline-edit.component.ts +211 -0
- package/assets/ts/components/multiselect/README.md +35 -0
- package/assets/ts/components/multiselect/multiselect.component.ts +304 -0
- package/assets/ts/components/search/README.md +36 -0
- package/assets/ts/components/table/table.component.ts +28 -21
- package/assets/ts/modules/helpers.ts +6 -0
- package/assets/ts/modules/inputs.ts +8 -2
- package/assets/ts/modules/table.ts +40 -19
- package/dist/components.es.js +66 -65
- package/dist/components.umd.js +61 -64
- package/package.json +1 -1
- package/src/components/InlineEdit/InlineEdit.vue +45 -0
- package/src/components/InlineEdit/README.md +7 -0
- package/src/components/Multiselect/Multiselect.vue +24 -0
- package/src/components/Multiselect/README.md +12 -0
- package/src/components/Search/README.md +11 -0
- package/src/components/Search/Search.vue +1 -1
- package/src/components/Table/Table.vue +2 -1
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
|
|
3
|
+
// Data layer Web component created
|
|
4
|
+
window.dataLayer = window.dataLayer || [];
|
|
5
|
+
window.dataLayer.push({
|
|
6
|
+
"event": "customElementRegistered",
|
|
7
|
+
"element": "inline edit"
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
class iamInlineEdit extends HTMLElement {
|
|
11
|
+
|
|
12
|
+
constructor(){
|
|
13
|
+
super();
|
|
14
|
+
const shadowRoot = this.attachShadow({ mode: 'open'});
|
|
15
|
+
|
|
16
|
+
const assetLocation = document.body.hasAttribute('data-assets-location') ? document.body.getAttribute('data-assets-location') : '/assets';
|
|
17
|
+
const coreCSS = document.body.hasAttribute('data-core-css') ? document.body.getAttribute('data-core-css') : `${assetLocation}/css/core.min.css`;
|
|
18
|
+
const loadCSS = `@import "${assetLocation}/css/components/inline-edit.css";`;
|
|
19
|
+
|
|
20
|
+
const template = document.createElement('template');
|
|
21
|
+
template.innerHTML = `
|
|
22
|
+
<style class="styles">
|
|
23
|
+
@import "${coreCSS}";
|
|
24
|
+
${loadCSS}
|
|
25
|
+
</style>
|
|
26
|
+
<link rel="stylesheet" href="https://kit.fontawesome.com/26fdbf0179.css" crossorigin="anonymous">
|
|
27
|
+
|
|
28
|
+
<slot></slot>
|
|
29
|
+
<div class="btns">
|
|
30
|
+
<button class="btn btn-action" id="save"><i class="fa-regular fa-save m-0"></i> Save</button><button class="btn btn-action" id="cancel">Cancel</button>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="status pe-none">
|
|
33
|
+
<span class="btn btn-action border-0 bg-transparent prevent-invert d-none" id="saving"><i class="fa-regular fa-spinner fa-spin me-1"></i> Saving...</span>
|
|
34
|
+
<span class="btn btn-action border-0 bg-transparent prevent-invert d-none" id="saved"><i class="fa-regular fa-check me-1"></i> Saved</span>
|
|
35
|
+
<span class="btn btn-action border-0 bg-transparent prevent-invert d-none" id="notsaved"><i class="fa-regular fa-circle-info me-1"></i> Not Saved</span>
|
|
36
|
+
</div>
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
shadowRoot.appendChild(template.content.cloneNode(true));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
connectedCallback() {
|
|
43
|
+
|
|
44
|
+
let inlineEdit = this;
|
|
45
|
+
let saveButton = this.shadowRoot.querySelector('#save');
|
|
46
|
+
let cancelButton = this.shadowRoot.querySelector('#cancel');
|
|
47
|
+
|
|
48
|
+
let label = this.querySelector('label');
|
|
49
|
+
let input = this.querySelector('input, textarea, select');
|
|
50
|
+
|
|
51
|
+
let statusSaving = this.shadowRoot.querySelector('#saving');
|
|
52
|
+
let statusSaved = this.shadowRoot.querySelector('#saved');
|
|
53
|
+
let statusNotSaved = this.shadowRoot.querySelector('#notsaved');
|
|
54
|
+
|
|
55
|
+
// Save the original value for later
|
|
56
|
+
let originalValue = input.value;
|
|
57
|
+
|
|
58
|
+
// cancel
|
|
59
|
+
cancelButton.addEventListener('click', (event) => {
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
console.log(originalValue)
|
|
63
|
+
|
|
64
|
+
input.value = originalValue;
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
input.blur();
|
|
68
|
+
inlineEdit.blur();
|
|
69
|
+
|
|
70
|
+
inlineEdit.classList.remove('was-validated');
|
|
71
|
+
statusNotSaved.classList.add('d-none');
|
|
72
|
+
|
|
73
|
+
const cancelEvent = new CustomEvent("inline-edit-cancel", { detail: { name: input.getAttribute('name')} });
|
|
74
|
+
inlineEdit.dispatchEvent(cancelEvent);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Save
|
|
78
|
+
saveButton.addEventListener('click', (event) => {
|
|
79
|
+
|
|
80
|
+
if(inlineEdit.querySelector(':invalid')){
|
|
81
|
+
|
|
82
|
+
inlineEdit.classList.add('was-validated');
|
|
83
|
+
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
originalValue = input.value;
|
|
88
|
+
|
|
89
|
+
// dispatch save event
|
|
90
|
+
const saveEvent = new CustomEvent("inline-edit-save", { detail: { name: input.getAttribute('name'), value: input.value } });
|
|
91
|
+
inlineEdit.dispatchEvent(saveEvent);
|
|
92
|
+
|
|
93
|
+
//inlineEdit.setAttribute('data-saving','true');
|
|
94
|
+
input.disabled = true;
|
|
95
|
+
|
|
96
|
+
input.blur();
|
|
97
|
+
inlineEdit.blur();
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
statusSaving.classList.remove('d-none');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Save
|
|
104
|
+
if(input.tagName === 'input'){
|
|
105
|
+
input.addEventListener('keydown', (event) => {
|
|
106
|
+
|
|
107
|
+
switch (event.key) { // change to event.key to key to use the above variable
|
|
108
|
+
case "Enter":
|
|
109
|
+
|
|
110
|
+
event.stopPropagation();
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
|
|
113
|
+
saveButton.click();
|
|
114
|
+
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Saved
|
|
121
|
+
inlineEdit.addEventListener('inline-edit-saved', (event) => {
|
|
122
|
+
|
|
123
|
+
setTimeout(() => {
|
|
124
|
+
|
|
125
|
+
statusSaving.classList.add('d-none');
|
|
126
|
+
statusSaved.classList.remove('d-none');
|
|
127
|
+
|
|
128
|
+
const confirmEvent = new CustomEvent("inline-edit-confirmed", { detail: { name: input.getAttribute('name') } });
|
|
129
|
+
inlineEdit.dispatchEvent(confirmEvent);
|
|
130
|
+
}, 100);
|
|
131
|
+
|
|
132
|
+
// Reset to normal
|
|
133
|
+
setTimeout(() => {
|
|
134
|
+
|
|
135
|
+
input.disabled = false;
|
|
136
|
+
inlineEdit.removeAttribute('data-saving');
|
|
137
|
+
|
|
138
|
+
statusSaving.classList.add('d-none');
|
|
139
|
+
statusSaved.classList.add('d-none');
|
|
140
|
+
statusNotSaved.classList.add('d-none');
|
|
141
|
+
}, 1000);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// enter key saves
|
|
145
|
+
if(input.tagName === 'SELECT'){
|
|
146
|
+
|
|
147
|
+
input.addEventListener('change',(event) => {
|
|
148
|
+
|
|
149
|
+
originalValue = input.value;
|
|
150
|
+
|
|
151
|
+
const saveEvent = new CustomEvent("inline-edit-save", { detail: { name: input.getAttribute('name'), value: input.value } });
|
|
152
|
+
inlineEdit.dispatchEvent(saveEvent);
|
|
153
|
+
|
|
154
|
+
inlineEdit.setAttribute('data-saving','true');
|
|
155
|
+
input.disabled = true;
|
|
156
|
+
|
|
157
|
+
input.blur();
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if(input.tagName != 'SELECT'){
|
|
162
|
+
input.addEventListener('focus',(event) => {
|
|
163
|
+
|
|
164
|
+
input.select();
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
//blur it should autosave
|
|
169
|
+
inlineEdit.addEventListener('blur',(event) => {
|
|
170
|
+
|
|
171
|
+
if(input.value != originalValue){
|
|
172
|
+
|
|
173
|
+
let feedbackText = '(Unsaved)';
|
|
174
|
+
|
|
175
|
+
if(inlineEdit.hasAttribute('data-autosave')) {
|
|
176
|
+
|
|
177
|
+
originalValue = input.value;
|
|
178
|
+
|
|
179
|
+
const saveEvent = new CustomEvent("inline-edit-autosave", { detail: { name: input.getAttribute('name'), value: input.value } });
|
|
180
|
+
inlineEdit.dispatchEvent(saveEvent);
|
|
181
|
+
|
|
182
|
+
statusSaving.classList.remove('d-none');
|
|
183
|
+
}
|
|
184
|
+
else if(!inlineEdit.querySelector('.inline-feedback')){
|
|
185
|
+
statusNotSaved.classList.remove('d-none');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// checkboxes
|
|
191
|
+
inlineEdit.addEventListener('change', (event) => {
|
|
192
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('input[type="checkbox"]')){
|
|
193
|
+
|
|
194
|
+
let saveValue = "";
|
|
195
|
+
|
|
196
|
+
Array.from(inlineEdit.querySelectorAll(`label input[type="checkbox"]:checked`)).forEach((checkbox, index) => {
|
|
197
|
+
|
|
198
|
+
if(index != 0)
|
|
199
|
+
saveValue += ", ";
|
|
200
|
+
|
|
201
|
+
saveValue += checkbox.value;
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const saveEvent = new CustomEvent("inline-edit-save", { detail: { name: event.target.closest('input[type="checkbox"]').getAttribute('name'), value: saveValue } });
|
|
205
|
+
inlineEdit.dispatchEvent(saveEvent);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export default iamInlineEdit;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
**Add the below to your initialise script**
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
import('../node_modules/@iamproperty/components/assets/js/components/fileupload/fileupload.component.min').then(module => { // Might need to update the path
|
|
5
|
+
|
|
6
|
+
if (!window.customElements.get(`iam-fileupload`))
|
|
7
|
+
window.customElements.define(`iam-fileupload`, 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
|
+
|
|
16
|
+
```
|
|
17
|
+
<iam-multiselect>
|
|
18
|
+
<span class="label" slot="label">Users</span>
|
|
19
|
+
<label class="tag"><input type="checkbox" name="tags" value="IT James Lambert" />James Lambert</label>
|
|
20
|
+
<label class="tag"><input type="checkbox" name="tags" value="IT Amanda Knight"/>Amanda Knight</label>
|
|
21
|
+
<label class="tag"><input type="checkbox" name="tags" value="IT Brian Lord"/>Brian Lord</label>
|
|
22
|
+
<label class="tag"><input type="checkbox" name="tags" value="Claire Lane"/>Claire Lane</label>
|
|
23
|
+
<label class="tag"><input type="checkbox" name="tags" value="John Smith"/>John Smith</label>
|
|
24
|
+
<label class="tag"><input type="checkbox" name="tags" value="James Brown"/>James Brown</label>
|
|
25
|
+
<label class="tag"><input type="checkbox" name="tags" value="Sarah Brown"/>Sarah Brown</label>
|
|
26
|
+
</iam-multiselect>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Properties**
|
|
30
|
+
|
|
31
|
+
| Option | Type | Default Value | Description |
|
|
32
|
+
| ------ | ---- | ------------- | ----------- |
|
|
33
|
+
| data-min | Int | - | Set's the minimum amout of tags needed for the input field to validate |
|
|
34
|
+
| data-min | Int | - | Set's the maximum amout of tags allowed to be added |
|
|
35
|
+
| data-is-required | flag | - | Makes it so at least one tag must be added for the it to be valid and allow the outer form to be sumitted |
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
|
|
3
|
+
// Data layer Web component created
|
|
4
|
+
window.dataLayer = window.dataLayer || [];
|
|
5
|
+
window.dataLayer.push({
|
|
6
|
+
"event": "customElementRegistered",
|
|
7
|
+
"element": "mutliselect"
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
class iamMultiselect extends HTMLElement {
|
|
11
|
+
|
|
12
|
+
constructor(){
|
|
13
|
+
super();
|
|
14
|
+
this.attachShadow({ mode: 'open'});
|
|
15
|
+
|
|
16
|
+
const assetLocation = document.body.hasAttribute('data-assets-location') ? document.body.getAttribute('data-assets-location') : '/assets'
|
|
17
|
+
const coreCSS = document.body.hasAttribute('data-core-css') ? document.body.getAttribute('data-core-css') : `${assetLocation}/css/core.min.css`;
|
|
18
|
+
const loadCSS = `@import "${assetLocation}/css/components/multiselect.css";`;
|
|
19
|
+
|
|
20
|
+
const template = document.createElement('template');
|
|
21
|
+
template.innerHTML = `
|
|
22
|
+
<style>
|
|
23
|
+
@import "${coreCSS}";
|
|
24
|
+
${loadCSS}
|
|
25
|
+
${this.hasAttribute('css') ? `@import "${this.getAttribute('css')}";` : ``}
|
|
26
|
+
</style>
|
|
27
|
+
<label for="search"> <slot name="feedback"></slot></label>
|
|
28
|
+
<div class="outer">
|
|
29
|
+
<div class="wrapper">
|
|
30
|
+
|
|
31
|
+
<slot name="checked"></slot>
|
|
32
|
+
<input name="search" id="search" autocomplete="off" required />
|
|
33
|
+
<span class="admin-panel feedback">This field is required</span>
|
|
34
|
+
<div class="admin-panel dropdown">
|
|
35
|
+
<slot></slot>
|
|
36
|
+
</div>
|
|
37
|
+
<button id="clear"><span class="visually-hidden">Clear</span></button>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
`;
|
|
41
|
+
this.shadowRoot.appendChild(template.content.cloneNode(true));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
connectedCallback() {
|
|
45
|
+
|
|
46
|
+
let multiselect = this;
|
|
47
|
+
let form = this.closest('form');
|
|
48
|
+
let wrapper = this.shadowRoot.querySelector('.wrapper');
|
|
49
|
+
let search = multiselect.shadowRoot.querySelector('#search');
|
|
50
|
+
let button = multiselect.shadowRoot.querySelector('#clear');
|
|
51
|
+
let order = 0;
|
|
52
|
+
let label = multiselect.shadowRoot.querySelector('label');
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
label.innerHTML = multiselect.getAttribute('data-label');
|
|
56
|
+
|
|
57
|
+
if(multiselect.hasAttribute('placeholder')){
|
|
58
|
+
|
|
59
|
+
search.setAttribute('placeholder', multiselect.getAttribute('placeholder'));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
multiselect.setAttribute('data-error','true');
|
|
63
|
+
|
|
64
|
+
// If in form and is required lets watch for the form being submitted
|
|
65
|
+
if(form && multiselect.hasAttribute('data-is-required')){
|
|
66
|
+
|
|
67
|
+
let observer = new MutationObserver(function(mutations) {
|
|
68
|
+
mutations.forEach(function(mutationRecord) {
|
|
69
|
+
const targetElement = mutationRecord.target as HTMLElement;
|
|
70
|
+
|
|
71
|
+
console.log(targetElement);
|
|
72
|
+
|
|
73
|
+
if (targetElement.classList.contains("was-validated")) {
|
|
74
|
+
wrapper.classList.add('was-validated');
|
|
75
|
+
} else {
|
|
76
|
+
wrapper.classList.remove('was-validated');
|
|
77
|
+
};
|
|
78
|
+
})
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
if (form.classList.contains("was-validated")) {
|
|
82
|
+
wrapper.classList.add('was-validated');
|
|
83
|
+
} else {
|
|
84
|
+
wrapper.classList.remove('was-validated');
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
observer.observe(form, {
|
|
88
|
+
attributes : true,
|
|
89
|
+
attributeFilter : ['style', 'class']
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Set the correct attributes
|
|
94
|
+
function setItem(inputToSet){
|
|
95
|
+
|
|
96
|
+
if(inputToSet.checked == false){
|
|
97
|
+
|
|
98
|
+
inputToSet.closest('label').removeAttribute('slot');
|
|
99
|
+
inputToSet.closest('label').removeAttribute('style');
|
|
100
|
+
inputToSet.closest('label').removeAttribute('data-order');
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
|
|
104
|
+
order++;
|
|
105
|
+
|
|
106
|
+
inputToSet.closest('label').setAttribute('slot','checked');
|
|
107
|
+
inputToSet.closest('label').setAttribute('style',`--order:${order};`);
|
|
108
|
+
inputToSet.closest('label').setAttribute('data-order',order);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// check for errors
|
|
112
|
+
if(multiselect.querySelector('label[slot="checked"]')){
|
|
113
|
+
wrapper.classList.add('filled');
|
|
114
|
+
multiselect.removeAttribute('data-error');
|
|
115
|
+
|
|
116
|
+
search.removeAttribute('placeholder');
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
wrapper.classList.remove('filled');
|
|
120
|
+
multiselect.setAttribute('data-error','true');
|
|
121
|
+
|
|
122
|
+
if(multiselect.hasAttribute('placeholder')){
|
|
123
|
+
|
|
124
|
+
search.setAttribute('placeholder', multiselect.getAttribute('placeholder'));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Set on load
|
|
132
|
+
Array.from(multiselect.querySelectorAll(`label input[type="checkbox"]:checked`)).forEach((checkbox, index) => {
|
|
133
|
+
|
|
134
|
+
setItem(checkbox);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
// Filter list
|
|
139
|
+
search.addEventListener('input', (event) => {
|
|
140
|
+
|
|
141
|
+
Array.from(multiselect.querySelectorAll(`label:not([slot="checked"])`)).forEach((label, index) => {
|
|
142
|
+
|
|
143
|
+
let checkbox = label.querySelector('input');
|
|
144
|
+
let searchValue = checkbox.value;
|
|
145
|
+
|
|
146
|
+
if(searchValue.toLowerCase().includes(search.value.toLowerCase())){
|
|
147
|
+
label.removeAttribute('slot')
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
label.setAttribute('slot','notmatched');
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Set items
|
|
156
|
+
multiselect.addEventListener('change', (event) => {
|
|
157
|
+
|
|
158
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('input[type="checkbox"]')){
|
|
159
|
+
let checkbox = event.target.closest('input[type="checkbox"]');
|
|
160
|
+
|
|
161
|
+
setItem(checkbox);
|
|
162
|
+
|
|
163
|
+
search.focus();
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Clear all
|
|
168
|
+
button.addEventListener("click", function(event) {
|
|
169
|
+
|
|
170
|
+
Array.from(multiselect.querySelectorAll(`label input[type="checkbox"]`)).forEach((checkbox, index) => {
|
|
171
|
+
|
|
172
|
+
checkbox.checked = false;
|
|
173
|
+
|
|
174
|
+
setItem(checkbox);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
search.focus();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Add some keyboard features to keep it accessible
|
|
181
|
+
multiselect.addEventListener("keydown", function(event) {
|
|
182
|
+
|
|
183
|
+
const activeElement = document.activeElement;
|
|
184
|
+
|
|
185
|
+
switch (event.key) { // change to event.key to key to use the above variable
|
|
186
|
+
case "ArrowUp":
|
|
187
|
+
// Up pressed
|
|
188
|
+
event.preventDefault();
|
|
189
|
+
|
|
190
|
+
if(activeElement.hasAttribute('type') && activeElement.getAttribute('type') == "checkbox"){
|
|
191
|
+
|
|
192
|
+
let arrCheckboxes = multiselect.querySelectorAll(`label:not([slot="checked"]):not([slot="checked"])`);
|
|
193
|
+
|
|
194
|
+
let activeIndex = Array.from(arrCheckboxes).indexOf(activeElement.closest('label'));
|
|
195
|
+
let prevCheckbox = Array.from(arrCheckboxes)[activeIndex-1];
|
|
196
|
+
|
|
197
|
+
if(prevCheckbox)
|
|
198
|
+
prevCheckbox.focus();
|
|
199
|
+
else
|
|
200
|
+
search.focus();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
break;
|
|
204
|
+
case "ArrowDown":
|
|
205
|
+
// Down pressed
|
|
206
|
+
event.preventDefault();
|
|
207
|
+
|
|
208
|
+
if(activeElement == multiselect){
|
|
209
|
+
|
|
210
|
+
multiselect.querySelector('label:not([slot="checked"]):not([slot="checked"])').focus();
|
|
211
|
+
}
|
|
212
|
+
else if(activeElement.hasAttribute('type') && activeElement.getAttribute('type') == "checkbox"){
|
|
213
|
+
|
|
214
|
+
let activeValue = activeElement.value;
|
|
215
|
+
|
|
216
|
+
let nextCheckbox = multiselect.querySelector(`label:has(input[value="${activeValue}"]) ~ label:not([slot="checked"]):not([slot="checked"])`);
|
|
217
|
+
|
|
218
|
+
if(nextCheckbox)
|
|
219
|
+
nextCheckbox.focus();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
break;
|
|
223
|
+
case "Enter":
|
|
224
|
+
|
|
225
|
+
event.stopPropagation();
|
|
226
|
+
event.preventDefault();
|
|
227
|
+
|
|
228
|
+
if(activeElement.hasAttribute('type') && activeElement.getAttribute('type') == "checkbox"){
|
|
229
|
+
|
|
230
|
+
if(activeElement.checked == false)
|
|
231
|
+
activeElement.checked = true;
|
|
232
|
+
else
|
|
233
|
+
activeElement.checked = false;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
setItem(activeElement);
|
|
237
|
+
search.focus();
|
|
238
|
+
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
function checkLastTag(){
|
|
244
|
+
|
|
245
|
+
if(order == 0)
|
|
246
|
+
return false;
|
|
247
|
+
|
|
248
|
+
let lastTag = multiselect.querySelector(`label[data-order="${order}"]`);
|
|
249
|
+
|
|
250
|
+
if(!lastTag){
|
|
251
|
+
lastTag = checkLastTag(order--);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return lastTag;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
search.addEventListener("keydown", function(event) {
|
|
258
|
+
|
|
259
|
+
switch (event.key) { // change to event.key to key to use the above variable
|
|
260
|
+
case "Enter":
|
|
261
|
+
|
|
262
|
+
let match = multiselect.querySelector(`input[value="${search.value}"]:not(:checked)`);
|
|
263
|
+
|
|
264
|
+
if(!match)
|
|
265
|
+
search.value = "";
|
|
266
|
+
|
|
267
|
+
search.focus();
|
|
268
|
+
|
|
269
|
+
break;
|
|
270
|
+
case "Backspace":
|
|
271
|
+
|
|
272
|
+
if(!search.value){
|
|
273
|
+
|
|
274
|
+
let lastTag = checkLastTag(order);
|
|
275
|
+
|
|
276
|
+
if(lastTag){
|
|
277
|
+
|
|
278
|
+
let lastTagInput = lastTag.querySelector('input');
|
|
279
|
+
lastTagInput.checked = false;
|
|
280
|
+
setItem(lastTagInput);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
search.focus();
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
// Fix for the inline edit multiselect
|
|
292
|
+
multiselect.addEventListener("mousedown", (event) => {
|
|
293
|
+
|
|
294
|
+
wrapper.setAttribute('data-mousedown','true');
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
multiselect.addEventListener("mouseup", (event) => {
|
|
298
|
+
|
|
299
|
+
wrapper.removeAttribute('data-mousedown');
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export default iamMultiselect;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
**Add the below to your initialise script**
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
import('../node_modules/@iamproperty/components/assets/js/components/fileupload/fileupload.component.min').then(module => { // Might need to update the path
|
|
5
|
+
|
|
6
|
+
if (!window.customElements.get(`iam-fileupload`))
|
|
7
|
+
window.customElements.define(`iam-fileupload`, 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
|
+
|
|
16
|
+
```
|
|
17
|
+
<iam-search>
|
|
18
|
+
<label>Search existing transactions
|
|
19
|
+
<span>
|
|
20
|
+
<input type="text" name="client" autocomplete="off" aria-autocomplete="none" required />
|
|
21
|
+
<span class="suffix fa-regular fa-search"></span>
|
|
22
|
+
</span>
|
|
23
|
+
</label>
|
|
24
|
+
<datalist id="properties"></datalist>
|
|
25
|
+
</iam-search>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Properties**
|
|
29
|
+
|
|
30
|
+
| Option | Type | Default Value | Description |
|
|
31
|
+
| ------ | ---- | ------------- | ----------- |
|
|
32
|
+
| data-url | String | - | Optional value that populates the datalist with extra results from an API |
|
|
33
|
+
| data-schema | String | - | Tells the JavaScript where to look for the array of values in the API JSON |
|
|
34
|
+
| data-value-schema | String | - | Tells the JavaScript where to look for the value within the API JSON |
|
|
35
|
+
| data-display-schema | String | - | Tells the JavaScript where to look for the title within the API JSON |
|
|
36
|
+
|
|
@@ -39,8 +39,9 @@ class iamTable extends HTMLElement {
|
|
|
39
39
|
this.shadowRoot.appendChild(template.content.cloneNode(true));
|
|
40
40
|
|
|
41
41
|
// insert extra CSS
|
|
42
|
-
if(!document.getElementById('tableExtras'))
|
|
42
|
+
if(!document.getElementById('tableExtras')){
|
|
43
43
|
document.head.insertAdjacentHTML('beforeend',`<style id="tableExtras">${loadExtraCSS}</style>`);
|
|
44
|
+
}
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
connectedCallback() {
|
|
@@ -48,17 +49,22 @@ class iamTable extends HTMLElement {
|
|
|
48
49
|
const params = new URLSearchParams(window.location.search)
|
|
49
50
|
|
|
50
51
|
// Set default attributes
|
|
51
|
-
if(!this.hasAttribute('data-total'))
|
|
52
|
+
if(!this.hasAttribute('data-total')){
|
|
52
53
|
this.setAttribute('data-total', this.querySelectorAll('table tbody tr').length);
|
|
54
|
+
}
|
|
53
55
|
|
|
54
|
-
if(!this.hasAttribute('data-page'))
|
|
56
|
+
if(!this.hasAttribute('data-page')){
|
|
55
57
|
this.setAttribute('data-page', (params.has('page') ? params.get('page') : 1));
|
|
58
|
+
}
|
|
56
59
|
|
|
57
|
-
if(!this.hasAttribute('data-show'))
|
|
60
|
+
if(!this.hasAttribute('data-show')){
|
|
58
61
|
this.setAttribute('data-show', (params.has('show') ? params.get('show') : 15));
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if(!this.hasAttribute('data-increment')){
|
|
61
65
|
this.setAttribute('data-increment', this.getAttribute('data-show'));
|
|
66
|
+
}
|
|
67
|
+
|
|
62
68
|
|
|
63
69
|
// Update table__wrapper class
|
|
64
70
|
let classList = this.classList.toString();
|
|
@@ -69,8 +75,9 @@ class iamTable extends HTMLElement {
|
|
|
69
75
|
this.shadowRoot.querySelector('.table__wrapper').className += ` ${classList}`;
|
|
70
76
|
|
|
71
77
|
// set actionbar class if needed
|
|
72
|
-
if(this.querySelector('.actionbar__sticky'))
|
|
78
|
+
if(this.querySelector('.actionbar__sticky')){
|
|
73
79
|
this.shadowRoot.querySelector('.table__wrapper').classList.add('has-actionbar');
|
|
80
|
+
}
|
|
74
81
|
|
|
75
82
|
this.table = this.querySelector('table');
|
|
76
83
|
this.savedTableBody = this.table.querySelector('tbody').cloneNode(true);
|
|
@@ -81,21 +88,21 @@ class iamTable extends HTMLElement {
|
|
|
81
88
|
this.pagination.setAttribute('data-show', this.getAttribute('data-show'));
|
|
82
89
|
this.pagination.setAttribute('data-increment', this.getAttribute('data-show'));
|
|
83
90
|
|
|
84
|
-
if(this.hasAttribute('data-page-jump'))
|
|
91
|
+
if(this.hasAttribute('data-page-jump')){
|
|
85
92
|
this.pagination.setAttribute('data-page-jump', 'true');
|
|
86
|
-
|
|
87
|
-
if(this.hasAttribute('data-per-page'))
|
|
93
|
+
}
|
|
94
|
+
if(this.hasAttribute('data-per-page')){
|
|
88
95
|
this.pagination.setAttribute('data-per-page', 'true');
|
|
89
|
-
|
|
90
|
-
if(this.hasAttribute('data-item-count'))
|
|
96
|
+
}
|
|
97
|
+
if(this.hasAttribute('data-item-count')){
|
|
91
98
|
this.pagination.setAttribute('data-item-count', 'true');
|
|
92
|
-
|
|
93
|
-
if(this.hasAttribute('data-loading'))
|
|
99
|
+
}
|
|
100
|
+
if(this.hasAttribute('data-loading')){
|
|
94
101
|
this.pagination.setAttribute('data-loading', 'true');
|
|
95
|
-
|
|
96
|
-
if(this.classList.contains('table--fullwidth'))
|
|
102
|
+
}
|
|
103
|
+
if(this.classList.contains('table--fullwidth')){
|
|
97
104
|
this.pagination.setAttribute('data-minimal', 'true');
|
|
98
|
-
|
|
105
|
+
}
|
|
99
106
|
|
|
100
107
|
// Remove table CTA
|
|
101
108
|
const isCTA = this.classList.contains('table--cta');
|
|
@@ -115,9 +122,9 @@ class iamTable extends HTMLElement {
|
|
|
115
122
|
}
|
|
116
123
|
|
|
117
124
|
// Set ajax class
|
|
118
|
-
if(this.form.hasAttribute('data-ajax'))
|
|
125
|
+
if(this.form.hasAttribute('data-ajax')){
|
|
119
126
|
this.table.classList.add('table--ajax');
|
|
120
|
-
|
|
127
|
+
}
|
|
121
128
|
// Create a data list if a search input is present
|
|
122
129
|
tableModule.createSearchDataList(this.table, this.form);
|
|
123
130
|
|
|
@@ -150,9 +157,9 @@ class iamTable extends HTMLElement {
|
|
|
150
157
|
|
|
151
158
|
// Add in the checkboxes
|
|
152
159
|
|
|
153
|
-
if(this.querySelector('iam-actionbar[data-selectall]')){
|
|
160
|
+
if(this.querySelector('iam-actionbar[data-selectall]') || document.querySelector(`iam-actionbar[data-for='${this.getAttribute('id')}']`)){
|
|
154
161
|
|
|
155
|
-
const actionbar = this.querySelector('iam-actionbar[data-selectall]');
|
|
162
|
+
const actionbar = this.querySelector('iam-actionbar[data-selectall]') ? this.querySelector('iam-actionbar[data-selectall]') : document.querySelector(`iam-actionbar[data-for='${this.getAttribute('id')}']`);
|
|
156
163
|
|
|
157
164
|
Array.from(this.table.querySelectorAll('thead tr')).forEach((row,index) => {
|
|
158
165
|
|