Skip to content

Commit da5b17e

Browse files
authored
Feature/voucher form (#4)
* Voucher Form with Gift Card component
1 parent 303d7e3 commit da5b17e

22 files changed

+2488
-475
lines changed

blocks/form/form-fields.js

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
import { toClassName } from '../../scripts/aem.js';
2+
3+
function createFieldWrapper(fd) {
4+
const fieldWrapper = document.createElement('div');
5+
if (fd.Style) fieldWrapper.className = fd.Style;
6+
fieldWrapper.classList.add('field-wrapper', `${fd.Type}-wrapper`);
7+
8+
fieldWrapper.dataset.fieldset = fd.Fieldset;
9+
10+
return fieldWrapper;
11+
}
12+
13+
const ids = [];
14+
function generateFieldId(fd, suffix = '') {
15+
const slug = toClassName(`form-${fd.Name}${suffix}`);
16+
ids[slug] = ids[slug] || 0;
17+
const idSuffix = ids[slug] ? `-${ids[slug]}` : '';
18+
ids[slug] += 1;
19+
return `${slug}${idSuffix}`;
20+
}
21+
22+
function createLabel(fd) {
23+
const label = document.createElement('label');
24+
label.id = generateFieldId(fd, '-label');
25+
label.textContent = fd.Label;
26+
label.setAttribute('for', fd.Id);
27+
if (fd.Mandatory.toLowerCase() === 'true' || fd.Mandatory.toLowerCase() === 'x') {
28+
label.dataset.required = true;
29+
}
30+
return label;
31+
}
32+
33+
function setCommonAttributes(field, fd) {
34+
field.id = fd.Id;
35+
field.name = fd.Name;
36+
field.required = fd.Mandatory && (fd.Mandatory.toLowerCase() === 'true' || fd.Mandatory.toLowerCase() === 'x');
37+
field.placeholder = fd.Placeholder;
38+
field.value = fd.Value;
39+
40+
if (fd.SearchParam) {
41+
const searchParams = new URLSearchParams(window.location.search);
42+
const val = searchParams.get(fd.SearchParam);
43+
if (val) {
44+
field.value = val;
45+
}
46+
}
47+
}
48+
49+
const createHeading = (fd) => {
50+
const fieldWrapper = createFieldWrapper(fd);
51+
52+
const level = fd.Style && fd.Style.includes('sub-heading') ? 3 : 2;
53+
const heading = document.createElement(`h${level}`);
54+
heading.textContent = fd.Value || fd.Label;
55+
heading.id = fd.Id;
56+
57+
fieldWrapper.append(heading);
58+
59+
return { field: heading, fieldWrapper };
60+
};
61+
62+
const createPlaintext = (fd) => {
63+
const fieldWrapper = createFieldWrapper(fd);
64+
65+
const text = document.createElement('p');
66+
text.textContent = fd.Value || fd.Label;
67+
text.id = fd.Id;
68+
69+
fieldWrapper.append(text);
70+
71+
return { field: text, fieldWrapper };
72+
};
73+
74+
const createSelect = async (fd) => {
75+
const select = document.createElement('select');
76+
setCommonAttributes(select, fd);
77+
const addOption = ({ text, value }) => {
78+
const option = document.createElement('option');
79+
option.text = text.trim();
80+
option.value = value.trim();
81+
if (option.value === select.value) {
82+
option.setAttribute('selected', '');
83+
}
84+
select.add(option);
85+
return option;
86+
};
87+
88+
if (fd.Placeholder) {
89+
const ph = addOption({ text: fd.Placeholder, value: '' });
90+
ph.setAttribute('disabled', '');
91+
}
92+
93+
if (fd.Options) {
94+
let options = [];
95+
if (fd.Options.startsWith('https://')) {
96+
const optionsUrl = new URL(fd.Options);
97+
const resp = await fetch(`${optionsUrl.pathname}${optionsUrl.search}`);
98+
const json = await resp.json();
99+
json.data.forEach((opt) => {
100+
options.push({
101+
text: opt.Option,
102+
value: opt.Value || opt.Option,
103+
});
104+
});
105+
} else {
106+
options = fd.Options.split(',').map((opt) => ({
107+
text: opt.trim(),
108+
value: opt.trim().toLowerCase(),
109+
}));
110+
}
111+
112+
options.forEach((opt) => addOption(opt));
113+
}
114+
115+
const fieldWrapper = createFieldWrapper(fd);
116+
fieldWrapper.append(select);
117+
fieldWrapper.prepend(createLabel(fd));
118+
119+
return { field: select, fieldWrapper };
120+
};
121+
122+
const createConfirmation = (fd, form) => {
123+
form.dataset.confirmation = new URL(fd.Value).pathname;
124+
125+
return {};
126+
};
127+
128+
const createSubmit = (fd) => {
129+
const button = document.createElement('button');
130+
button.textContent = fd.Label || fd.Name;
131+
button.classList.add('button');
132+
button.type = 'submit';
133+
134+
const fieldWrapper = createFieldWrapper(fd);
135+
fieldWrapper.append(button);
136+
return { field: button, fieldWrapper };
137+
};
138+
139+
const createTextArea = (fd) => {
140+
const field = document.createElement('textarea');
141+
setCommonAttributes(field, fd);
142+
143+
const fieldWrapper = createFieldWrapper(fd);
144+
const label = createLabel(fd);
145+
field.setAttribute('aria-labelledby', label.id);
146+
field.setAttribute('rows', fd.Rows || 2);
147+
fieldWrapper.append(field);
148+
fieldWrapper.prepend(label);
149+
150+
return { field, fieldWrapper };
151+
};
152+
153+
const createInput = (fd) => {
154+
const field = document.createElement('input');
155+
field.type = fd.Type;
156+
setCommonAttributes(field, fd);
157+
158+
const fieldWrapper = createFieldWrapper(fd);
159+
const label = createLabel(fd);
160+
field.setAttribute('aria-labelledby', label.id);
161+
fieldWrapper.append(field);
162+
if (fd.Type === 'radio' || fd.Type === 'checkbox') {
163+
fieldWrapper.append(label);
164+
} else {
165+
fieldWrapper.prepend(label);
166+
}
167+
168+
return { field, fieldWrapper };
169+
};
170+
171+
const createFieldset = (fd) => {
172+
const field = document.createElement('fieldset');
173+
setCommonAttributes(field, fd);
174+
175+
if (fd.Label) {
176+
const legend = document.createElement('legend');
177+
legend.textContent = fd.Label;
178+
field.append(legend);
179+
}
180+
181+
const fieldWrapper = createFieldWrapper(fd);
182+
fieldWrapper.append(field);
183+
184+
return { field, fieldWrapper };
185+
};
186+
187+
const createToggle = (fd) => {
188+
const { field, fieldWrapper } = createInput(fd);
189+
field.type = 'checkbox';
190+
if (!field.value) field.value = 'on';
191+
field.classList.add('toggle');
192+
fieldWrapper.classList.add('selection-wrapper');
193+
194+
const toggleSwitch = document.createElement('div');
195+
toggleSwitch.classList.add('switch');
196+
toggleSwitch.append(field);
197+
fieldWrapper.append(toggleSwitch);
198+
199+
const slider = document.createElement('span');
200+
slider.classList.add('slider');
201+
toggleSwitch.append(slider);
202+
slider.addEventListener('click', () => {
203+
field.checked = !field.checked;
204+
});
205+
206+
return { field, fieldWrapper };
207+
};
208+
209+
const createCheckbox = (fd) => {
210+
const { field, fieldWrapper } = createInput(fd);
211+
if (!field.value) field.value = 'checked';
212+
fieldWrapper.classList.add('selection-wrapper');
213+
214+
return { field, fieldWrapper };
215+
};
216+
217+
const createRadio = (fd) => {
218+
const { field, fieldWrapper } = createInput(fd);
219+
if (!field.value) field.value = fd.Label || 'on';
220+
fieldWrapper.classList.add('selection-wrapper');
221+
222+
return { field, fieldWrapper };
223+
};
224+
225+
const FIELD_CREATOR_FUNCTIONS = {
226+
select: createSelect,
227+
heading: createHeading,
228+
plaintext: createPlaintext,
229+
'text-area': createTextArea,
230+
toggle: createToggle,
231+
submit: createSubmit,
232+
confirmation: createConfirmation,
233+
fieldset: createFieldset,
234+
checkbox: createCheckbox,
235+
radio: createRadio,
236+
};
237+
238+
export default async function createField(fd, form) {
239+
fd.Id = fd.Id || generateFieldId(fd);
240+
const type = fd.Type.toLowerCase();
241+
const createFieldFunc = FIELD_CREATOR_FUNCTIONS[type] || createInput;
242+
const fieldElements = await createFieldFunc(fd, form);
243+
244+
return fieldElements.fieldWrapper;
245+
}

0 commit comments

Comments
 (0)