@gudhub/ssg-web-components-library 1.0.102 → 1.0.104
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/package.json
CHANGED
|
@@ -26,6 +26,8 @@ class BreadcrumbsComponent extends GHComponent {
|
|
|
26
26
|
|
|
27
27
|
this.items === null ? console.error(`Didn't find current route in config, current URL: ${currentUrl}`) : null;
|
|
28
28
|
|
|
29
|
+
console.log("this.items:", this.items);
|
|
30
|
+
|
|
29
31
|
if (this.items) {
|
|
30
32
|
super.render(html);
|
|
31
33
|
}
|
|
@@ -26,6 +26,7 @@ class GetInTouchBlock extends GHComponent {
|
|
|
26
26
|
this.subtitleName = this.hasAttribute('data-form-subtitle') ? this.getAttribute('data-form-subtitle') : null;
|
|
27
27
|
this.placement = this.hasAttribute('data-form-placement') ? this.getAttribute('data-form-placement') : "main";
|
|
28
28
|
this.buttonText = this.hasAttribute('data-form-button-text') ? this.getAttribute('data-form-button-text') : null;
|
|
29
|
+
this.recaptchaSiteKey = this.hasAttribute('data-recaptcha-site-key') ? this.getAttribute('data-recaptcha-site-key') : null;
|
|
29
30
|
|
|
30
31
|
const attributes = [{
|
|
31
32
|
'data-form-id': this.formId,
|
|
@@ -33,6 +34,7 @@ class GetInTouchBlock extends GHComponent {
|
|
|
33
34
|
'data-form-subtitle': this.subtitleName,
|
|
34
35
|
'data-form-placement': this.placement,
|
|
35
36
|
'data-form-button-text': this.buttonText,
|
|
37
|
+
'data-recaptcha-site-key': this.recaptchaSiteKey,
|
|
36
38
|
}];
|
|
37
39
|
|
|
38
40
|
const attributesString = attributes.reduce((acc, obj) => {
|
|
@@ -47,4 +49,5 @@ class GetInTouchBlock extends GHComponent {
|
|
|
47
49
|
return attributesString;
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
|
-
|
|
52
|
+
|
|
53
|
+
window.customElements.define('get-in-touch-block', GetInTouchBlock);
|
|
@@ -1,12 +1,39 @@
|
|
|
1
1
|
import html from './get-in-touch-form.html';
|
|
2
2
|
import './get-in-touch-form.scss';
|
|
3
|
+
|
|
3
4
|
import defaultConfigs from './get-in-touch-form-data.json';
|
|
4
5
|
import { checkInputsValidations } from './inputsValidation.js';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
let recaptchaPromise = null;
|
|
8
|
+
|
|
9
|
+
function loadRecaptcha(siteKey) {
|
|
10
|
+
if (window.grecaptcha) return Promise.resolve(window.grecaptcha);
|
|
11
|
+
|
|
12
|
+
if (recaptchaPromise) return recaptchaPromise;
|
|
13
|
+
|
|
14
|
+
recaptchaPromise = new Promise((resolve, reject) => {
|
|
15
|
+
const script = document.createElement('script');
|
|
16
|
+
script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
|
|
17
|
+
script.async = true;
|
|
18
|
+
script.defer = true;
|
|
19
|
+
|
|
20
|
+
script.onload = () => {
|
|
21
|
+
if (window.grecaptcha) resolve(window.grecaptcha);
|
|
22
|
+
else reject('grecaptcha not available');
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
script.onerror = reject;
|
|
26
|
+
|
|
27
|
+
document.head.appendChild(script);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return recaptchaPromise;
|
|
31
|
+
}
|
|
7
32
|
|
|
33
|
+
class GetInTouchForm extends GHComponent {
|
|
8
34
|
constructor() {
|
|
9
35
|
super();
|
|
36
|
+
|
|
10
37
|
this.formId = this.getAttribute("data-form-id");
|
|
11
38
|
this.defaultConfigs = defaultConfigs;
|
|
12
39
|
|
|
@@ -15,12 +42,14 @@ class GetInTouchForm extends GHComponent {
|
|
|
15
42
|
|
|
16
43
|
this.placement = 'main';
|
|
17
44
|
this.config = window.getConfig()?.componentsConfigs?.formConfig || window.getConfig()?.formConfig;
|
|
45
|
+
|
|
46
|
+
this.recaptcha_site_key = this.hasAttribute('data-recaptcha-site-key')
|
|
47
|
+
? this.getAttribute('data-recaptcha-site-key')
|
|
48
|
+
: null;
|
|
18
49
|
}
|
|
19
50
|
|
|
20
51
|
onServerRender() {
|
|
21
|
-
if (this.hasAttribute('data-in-popup'))
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
52
|
+
if (this.hasAttribute('data-in-popup')) return;
|
|
24
53
|
|
|
25
54
|
this.initConfig(this.config);
|
|
26
55
|
super.render(html);
|
|
@@ -30,6 +59,8 @@ class GetInTouchForm extends GHComponent {
|
|
|
30
59
|
if (!this.hasAttribute('data-in-popup')) {
|
|
31
60
|
this.initConfig(this.config);
|
|
32
61
|
this.attachEventListeners();
|
|
62
|
+
|
|
63
|
+
loadRecaptcha(this.recaptcha_site_key).catch(console.error);
|
|
33
64
|
}
|
|
34
65
|
}
|
|
35
66
|
|
|
@@ -40,8 +71,11 @@ class GetInTouchForm extends GHComponent {
|
|
|
40
71
|
}
|
|
41
72
|
|
|
42
73
|
attachEventListeners() {
|
|
43
|
-
this.getElementsByTagName('form')[0]
|
|
44
|
-
|
|
74
|
+
this.getElementsByTagName('form')[0]
|
|
75
|
+
.addEventListener('submit', (e) => this.handleSubmit(e));
|
|
76
|
+
|
|
77
|
+
this.getElementsByClassName('restart_button')[0]
|
|
78
|
+
.addEventListener('click', () => this.hideFail());
|
|
45
79
|
}
|
|
46
80
|
|
|
47
81
|
onParentPopupClose() {
|
|
@@ -56,53 +90,70 @@ class GetInTouchForm extends GHComponent {
|
|
|
56
90
|
initConfig(formConfigs) {
|
|
57
91
|
try {
|
|
58
92
|
this.config = formConfigs.find(({ id }) => id === this.formId);
|
|
59
|
-
if (!this.config)
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
} catch (error) {
|
|
93
|
+
if (!this.config) throw new Error("Config not found");
|
|
94
|
+
} catch {
|
|
63
95
|
const defaultId = this.isInPopup ? 'default popup' : 'default';
|
|
64
96
|
this.config = defaultConfigs.find(({ id }) => id === defaultId);
|
|
65
97
|
}
|
|
66
98
|
|
|
67
|
-
this.titleName = this.
|
|
68
|
-
this.subtitleName = this.
|
|
69
|
-
this.placement = this.
|
|
70
|
-
this.buttonText = this.
|
|
71
|
-
}
|
|
99
|
+
this.titleName = this.getAttribute('data-form-title') || this.config.title;
|
|
100
|
+
this.subtitleName = this.getAttribute('data-form-subtitle') || this.config.subtitle;
|
|
101
|
+
this.placement = this.getAttribute('data-form-placement') || "main";
|
|
102
|
+
this.buttonText = this.getAttribute('data-form-button-text') || this.config.button_text;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async getRecaptchaToken(action = 'submit') {
|
|
106
|
+
const grecaptcha = await loadRecaptcha(this.recaptcha_site_key);
|
|
107
|
+
|
|
108
|
+
return new Promise((resolve, reject) => {
|
|
109
|
+
grecaptcha.ready(() => {
|
|
110
|
+
grecaptcha.execute(this.recaptcha_site_key, { action })
|
|
111
|
+
.then(resolve)
|
|
112
|
+
.catch(reject);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
}
|
|
72
116
|
|
|
73
117
|
async handleSubmit(event) {
|
|
74
118
|
event.preventDefault();
|
|
75
119
|
const form = event.target;
|
|
76
|
-
|
|
77
|
-
const validationResults = await this.inputsValidation(form);
|
|
120
|
+
|
|
121
|
+
const validationResults = await this.inputsValidation(form);
|
|
78
122
|
|
|
79
123
|
if (validationResults.every(({ isValid }) => isValid)) {
|
|
80
124
|
this.addLoader();
|
|
125
|
+
|
|
81
126
|
try {
|
|
82
|
-
await this.
|
|
127
|
+
const token = await this.getRecaptchaToken();
|
|
128
|
+
|
|
129
|
+
await this.fetchExample(token);
|
|
130
|
+
|
|
131
|
+
this.handleSuccessFormValidation(form, token);
|
|
83
132
|
|
|
84
|
-
this.handleSuccessFormValidation(form);
|
|
85
133
|
} catch (error) {
|
|
86
134
|
console.error(error);
|
|
87
135
|
this.showFail();
|
|
88
136
|
}
|
|
89
137
|
|
|
90
|
-
this.removeLoader(
|
|
138
|
+
this.removeLoader();
|
|
91
139
|
|
|
92
140
|
} else {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
141
|
+
validationResults
|
|
142
|
+
.filter(item => typeof item === 'object')
|
|
143
|
+
.forEach(({ input, isValid }) => this.toggleError(input, isValid));
|
|
96
144
|
}
|
|
97
145
|
}
|
|
98
146
|
|
|
99
|
-
handleSuccessFormValidation = (form) => {
|
|
147
|
+
handleSuccessFormValidation = (form, token) => {
|
|
100
148
|
const emailInput = form.querySelector('[name="email"]');
|
|
101
149
|
const phoneInput = form.querySelector('[name="phone"]');
|
|
102
150
|
|
|
103
|
-
this.showSuccess({
|
|
151
|
+
this.showSuccess({
|
|
152
|
+
email: emailInput?.value || '',
|
|
153
|
+
phone: phoneInput?.value || ''
|
|
154
|
+
});
|
|
104
155
|
|
|
105
|
-
const formDataObj = this.createDataObject(form, this.placement)
|
|
156
|
+
const formDataObj = this.createDataObject(form, this.placement, token);
|
|
106
157
|
|
|
107
158
|
window.dispatchEvent(new CustomEvent('submitForm', { detail: { formDataObj } }));
|
|
108
159
|
|
|
@@ -112,38 +163,31 @@ class GetInTouchForm extends GHComponent {
|
|
|
112
163
|
|
|
113
164
|
inputsValidation = async (form) => {
|
|
114
165
|
const inputs = Array.from(form.querySelectorAll('input'));
|
|
115
|
-
|
|
116
|
-
const validationResults = checkInputsValidations(inputs);
|
|
117
|
-
|
|
118
|
-
return validationResults;
|
|
166
|
+
return checkInputsValidations(inputs);
|
|
119
167
|
}
|
|
120
168
|
|
|
121
|
-
fetchExample = () => {
|
|
169
|
+
fetchExample = (recaptchaToken) => {
|
|
122
170
|
const isSuccess = true;
|
|
123
171
|
|
|
124
172
|
return new Promise((resolve, reject) => {
|
|
125
|
-
|
|
173
|
+
console.log('reCAPTCHA token:', recaptchaToken);
|
|
126
174
|
|
|
127
175
|
setTimeout(() => {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
} else {
|
|
131
|
-
reject();
|
|
132
|
-
}
|
|
133
|
-
}, TIMEOUT_DURATION);
|
|
176
|
+
isSuccess ? resolve() : reject();
|
|
177
|
+
}, 2000);
|
|
134
178
|
});
|
|
135
179
|
}
|
|
136
|
-
|
|
137
|
-
createDataObject(form, placement) {
|
|
180
|
+
|
|
181
|
+
createDataObject(form, placement, recaptchaToken) {
|
|
138
182
|
const inputs = {};
|
|
139
183
|
|
|
140
|
-
for (const [name, value] of
|
|
184
|
+
for (const [name, value] of new FormData(form).entries()) {
|
|
141
185
|
inputs[name] = value;
|
|
142
186
|
}
|
|
143
187
|
|
|
144
188
|
const { id, mailConfig } = this.config;
|
|
145
189
|
|
|
146
|
-
|
|
190
|
+
return {
|
|
147
191
|
inputs,
|
|
148
192
|
mailConfig,
|
|
149
193
|
website: window.location.hostname,
|
|
@@ -151,9 +195,8 @@ class GetInTouchForm extends GHComponent {
|
|
|
151
195
|
formId: id,
|
|
152
196
|
formPlacement: placement,
|
|
153
197
|
referrer: localStorage.getItem('referrer'),
|
|
198
|
+
recaptchaToken
|
|
154
199
|
};
|
|
155
|
-
|
|
156
|
-
return formDataObj;
|
|
157
200
|
}
|
|
158
201
|
|
|
159
202
|
toggleError(input, isValid) {
|
|
@@ -161,49 +204,49 @@ class GetInTouchForm extends GHComponent {
|
|
|
161
204
|
input.parentElement.classList[isValid ? 'remove' : 'add']('error-input');
|
|
162
205
|
}
|
|
163
206
|
|
|
164
|
-
|
|
207
|
+
addLoader() {
|
|
165
208
|
this.classList.add('loading');
|
|
166
209
|
this.querySelector('button[type="submit"]').disabled = true;
|
|
167
210
|
}
|
|
168
211
|
|
|
169
|
-
|
|
212
|
+
removeLoader() {
|
|
170
213
|
this.classList.remove('loading');
|
|
171
|
-
const
|
|
172
|
-
setTimeout(() =>
|
|
173
|
-
submitButton.disabled = false;
|
|
174
|
-
}, 500);
|
|
214
|
+
const btn = this.querySelector('button[type="submit"]');
|
|
215
|
+
setTimeout(() => btn.disabled = false, 500);
|
|
175
216
|
}
|
|
176
217
|
|
|
177
|
-
|
|
218
|
+
showSuccess({email, phone}) {
|
|
178
219
|
if (email) {
|
|
179
220
|
this.querySelector('.check_entity').classList.add('provided');
|
|
180
221
|
this.getElementsByClassName('email')[0].innerText = email;
|
|
181
222
|
}
|
|
182
|
-
|
|
223
|
+
|
|
183
224
|
if (phone) {
|
|
184
|
-
this.querySelector('.
|
|
225
|
+
this.querySelector('.phone_entity').classList.add('provided');
|
|
185
226
|
this.getElementsByClassName('phone')[0].innerText = phone;
|
|
186
227
|
}
|
|
228
|
+
|
|
187
229
|
this.classList.add('success');
|
|
188
230
|
}
|
|
189
231
|
|
|
190
|
-
|
|
232
|
+
showFail() {
|
|
191
233
|
this.classList.add('fail');
|
|
192
234
|
}
|
|
193
235
|
|
|
194
|
-
|
|
236
|
+
hideSuccess() {
|
|
195
237
|
this.getElementsByClassName('email')[0].innerText = '';
|
|
196
238
|
this.getElementsByClassName('phone')[0].innerText = '';
|
|
197
|
-
this.querySelector('.
|
|
239
|
+
this.querySelector('.phone_entity').classList.remove('provided');
|
|
198
240
|
this.classList.remove('success');
|
|
199
241
|
}
|
|
200
242
|
|
|
201
|
-
|
|
202
|
-
const
|
|
203
|
-
|
|
243
|
+
hideFail() {
|
|
244
|
+
const el = this.querySelector('.overflow.fail');
|
|
245
|
+
el.style.opacity = 0;
|
|
246
|
+
|
|
204
247
|
setTimeout(() => {
|
|
205
248
|
this.classList.remove('fail');
|
|
206
|
-
|
|
249
|
+
el.style.opacity = '';
|
|
207
250
|
}, 500);
|
|
208
251
|
}
|
|
209
252
|
|
|
@@ -218,10 +261,15 @@ class GetInTouchForm extends GHComponent {
|
|
|
218
261
|
|
|
219
262
|
const tag = input.type === 'textarea' ? 'textarea' : 'input';
|
|
220
263
|
const maxLength = tag === 'textarea' ? maxSymbols.long : maxSymbols[input.type];
|
|
264
|
+
|
|
221
265
|
return acc + `
|
|
222
266
|
<div class="input-wrap col-${input.width}">
|
|
223
267
|
${input.title ? `<label for="${input.name}">${input.title}</label>` : ''}
|
|
224
|
-
<${tag}
|
|
268
|
+
<${tag} name="${input.name}"
|
|
269
|
+
${input.placeholder ? `placeholder="${input.placeholder}"` : ''}
|
|
270
|
+
${JSON.parse(input.required) ? 'required' : ''}
|
|
271
|
+
${maxLength ? `maxlength="${maxLength}"` : ''}>
|
|
272
|
+
</${tag}>
|
|
225
273
|
${input.type === 'email' || input.type === 'phone' ? `<span class="${input.type}-error">${input.errorText}</span>` : ''}
|
|
226
274
|
</div>
|
|
227
275
|
`;
|
|
@@ -231,4 +279,4 @@ class GetInTouchForm extends GHComponent {
|
|
|
231
279
|
|
|
232
280
|
if (!customElements.get('get-in-touch-form')) {
|
|
233
281
|
customElements.define('get-in-touch-form', GetInTouchForm);
|
|
234
|
-
}
|
|
282
|
+
}
|
|
@@ -99,18 +99,16 @@ class MetaTag extends GHComponent {
|
|
|
99
99
|
// fieldId = fieldId.field_id;
|
|
100
100
|
// value = item.fields.find(findedField => findedField.field_id == fieldId).field_value;
|
|
101
101
|
|
|
102
|
-
|
|
103
102
|
let titleValue = item.fields.find(findedField => findedField.field_id == titleId).field_value;
|
|
104
103
|
let descriptionValue = item.fields.find(findedField => findedField.field_id == descriptionId).field_value;
|
|
105
104
|
let slugValue = item.fields.find(findedField => findedField.field_id == slugId).field_value;
|
|
106
|
-
let imageValue = !slugValue.includes('/blog/') ? item.fields.find(findedField => findedField.field_id == imageUrl).field_value : false;
|
|
105
|
+
let imageValue = (!slugValue.includes('/blog/') && !slugValue.includes('/service-areas/')) ? item.fields.find(findedField => findedField.field_id == imageUrl).field_value : false;
|
|
107
106
|
|
|
108
107
|
// value = isNaN(value) ? value : await this.getContent(`https://gudhub.com/userdata/${window.getConfig().chapters[chapter].app_id}/${value}.html`);
|
|
109
108
|
titleValue = isNaN(titleValue) ? titleValue : await this.getContent(`https://app.gudhub.com/userdata/${window.getConfig().chapters[chapter].app_id}/${titleValue}.html`);
|
|
110
109
|
descriptionValue = isNaN(descriptionValue) ? descriptionValue : await this.getContent(`https://app.gudhub.com/userdata/${window.getConfig().chapters[chapter].app_id}/${descriptionValue}.html`);
|
|
111
110
|
slugValue = isNaN(slugValue) ? slugValue : await this.getContent(`https://app.gudhub.com/userdata/${window.getConfig().chapters[chapter].app_id}/${slugValue}.html`);
|
|
112
|
-
imageValue = !slugValue.includes('/blog/') ? isNaN(imageValue) ? imageValue : await this.getContent(`https://app.gudhub.com/userdata/${window.getConfig() .chapters[chapter].app_id}/${imageValue}.html`) : false;
|
|
113
|
-
|
|
111
|
+
imageValue = (!slugValue.includes('/blog/') && !slugValue.includes('/service-areas/')) ? isNaN(imageValue) ? imageValue : await this.getContent(`https://app.gudhub.com/userdata/${window.getConfig() .chapters[chapter].app_id}/${imageValue}.html`) : false;
|
|
114
112
|
|
|
115
113
|
//TITLE
|
|
116
114
|
if ( !document.querySelector('title') ) {
|
|
@@ -142,7 +140,7 @@ class MetaTag extends GHComponent {
|
|
|
142
140
|
}
|
|
143
141
|
|
|
144
142
|
|
|
145
|
-
if (!slugValue.includes('/blog/')) {
|
|
143
|
+
if ((!slugValue.includes('/blog/') && !slugValue.includes('/service-areas/'))) {
|
|
146
144
|
if ( !document.querySelector('[name="twitter:image"]') ) {
|
|
147
145
|
const twitterMetaSiteImage = document.createElement('meta');
|
|
148
146
|
twitterMetaSiteImage.setAttribute('name', 'twitter:image');
|