PluginProbe
seQura / 3.0.0
seQura v3.0.0
4.3.4 4.3.3 4.3.2 4.3.1 trunk 2.0.0 2.0.10 2.0.11 2.0.12 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 3.0.0 3.0.2 3.0.5 3.0.6 3.0.7 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 4.0.0 All 30 releases
sequra / assets / js / src / core / Repeater.js

Repeater.js in seQura 3.0.0, at assets/js/src/core/Repeater.js

130 lines 4.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * @typedef RepeaterAdapter
3 * @property {string} containerSelector
4 * @property {array} data
5 * @property {function} getHeaders
6 * @property {function} getRowContent
7 * @property {function} getRowHeader
8 * @property {function|null} handleChange
9 * @property {string} addRowText
10 */
11
12 /**
13 * Repeater component.
14 */
15 export class Repeater {
16
17 /**
18 *
19 * @param {RepeaterAdapter} adapter
20 */
21 constructor(adapter) {
22 this.adapter = adapter;
23 this.elem = document.querySelector(this.adapter.containerSelector);
24 if (!this.elem) return;
25
26 this.#renderTable();
27
28 this.checkAllCheckbox = this.elem.querySelector('.sq-check-all');
29
30 this.body = this.elem.querySelector('.sq-table__body');
31 this.template = this.body.querySelector('template');
32
33 const addBtn = this.elem.querySelector('.sq-add');
34 if (addBtn) {
35 addBtn.addEventListener('click', this.#addRow);
36 }
37
38 this.adapter.data.forEach((row) => this.#addRow(null, row));
39 }
40
41 #addRow = (e, data = null) => {
42 if ('undefined' !== typeof e?.preventDefault) {
43 e?.preventDefault();
44 }
45 const clone = this.template.cloneNode(true);
46 const row = clone.content.querySelector('.sq-table__row');
47 row.querySelector('.sq-table__row-header').innerHTML = this.adapter.getRowHeader(data);
48 row.querySelector('.sq-table__row-content').innerHTML = this.adapter.getRowContent(data);
49
50
51 const rmBtn = row.querySelector('.sq-remove');
52 if (rmBtn) {
53 rmBtn.addEventListener('click', this.#deleteRow);
54 }
55
56 this.body.appendChild(row);
57
58 // row.querySelector('.sq-table__row-content').querySelectorAll('input,textarea,select').forEach(elem => {
59 row.querySelectorAll('input,textarea,select').forEach(elem => {
60 elem.addEventListener('change', () => {
61 if (this.adapter.handleChange) {
62 this.adapter.handleChange(this.elem.querySelector('.sq-table'))
63 }
64 });
65 });
66
67 this.#updateVisibility();
68 };
69
70 #deleteRow = e => {
71 if ('undefined' !== typeof e?.preventDefault) {
72 e?.preventDefault();
73 }
74 e.target.closest('.sq-table__row').remove();
75 this.#updateVisibility();
76 }
77
78 #updateVisibility = () => {
79 const rows = this.elem.querySelectorAll('.sq-table__body >.sq-table__row');
80 if (rows.length === 0) {
81 this.elem.querySelector('.sq-table__body').classList.add('sqs--hidden');
82 } else {
83 this.elem.querySelector('.sq-table__body').classList.remove('sqs--hidden');
84 }
85
86 if (this.adapter.handleChange) {
87 this.adapter.handleChange(this.elem.querySelector('.sq-table'));
88 }
89 }
90
91 #renderTable = () => {
92 const repeater = document.createElement('div');
93 repeater.classList.add('sq-table');
94
95 let canAdd = true;
96 if ('undefined' !== typeof this.adapter.canAdd) {
97 canAdd = this.adapter.canAdd;
98 }
99
100 let canRemove = true;
101 if ('undefined' !== typeof this.adapter.canRemove) {
102 canRemove = this.adapter.canRemove;
103 }
104
105 let nameAttr = '';
106 if ('undefined' !== typeof this.adapter.name) {
107 nameAttr = `name="${this.adapter.name}"`;
108 }
109
110 const addBtn = !canAdd ? '' : `<button class="sq-button sq-add sqm--small" type="button">${SequraFE.translationService.translate(this.adapter.addRowText)}</button>`;
111 const rmBtn = !canRemove ? '' : `<button class="sq-button sq-remove sqm--small" type="button">${SequraFE.translationService.translate(this.adapter.removeRowText)}</button>`;
112 repeater.innerHTML = `
113 <header class="sq-table__header">
114 ${this.adapter.getHeaders().map(header => `<div class="sq-table__header-item"><h3 class="sqp-field-title">${header.title}</h3><span class="sqp-field-subtitle">${header.description}</span></div>`).join('')}
115 ${addBtn}
116 </header>
117 <div class="sq-table__body sqs--hidden">
118 <template>
119 <details class="sq-table__row" ${nameAttr}>
120 <summary class="sq-table__row-header"></summary>
121 <div class="sq-table__row-content"></div>
122 ${rmBtn}
123 </details>
124 </template>
125 </div>
126 `.trim();
127
128 this.elem.appendChild(repeater);
129 }
130 }