PageSourceSearch

https://imc.ua/assets/components/fetchit/js/fetchit.js?v=1.1.2

js imc.ua collected 2026-09-30 14:31:36 UTC 8,018 bytes, 299 lines download raw bytes

1(function () {
2  'use strict';
3
4  class FetchIt {
5    static forms = [];
6    static instances = new Map();
7    static events = {
8      before: 'fetchit:before',
9      success: 'fetchit:success',
10      error: 'fetchit:error',
11      after: 'fetchit:after',
12      reset: 'fetchit:reset',
13    }
14
15    constructor (form, config) {
16      if (!(form instanceof HTMLFormElement)) {
17        throw new Error('Не форма');
18      }
19
20      this.form = form;
21      this.config = config;
22
23      this.request = new Request(this.config.actionUrl, {
24        method: 'post',
25        credentials: 'same-origin',
26        headers: {
27          'Accept': 'application/json',
28          'X-FetchIt-Action': this.config.action,
29        },
30      });
31
32      this.prepareEvents();
33
34      FetchIt.forms.push(this.form);
35      FetchIt.instances.set(this.form, this);
36    }
37
38    prepareEvents() {
39      this.form.addEventListener('submit', async e => {
40        e.preventDefault();
41
42        this.formData = new FormData(this.form);
43        this.formData.set('pageId', this.config.pageId);
44
45        this.clearErrors();
46
47        const beforeEvent = new CustomEvent(FetchIt.events.before, {
48          cancelable: true,
49          detail: {
50            form: this.form,
51            formData: this.formData,
52            fetchit: this,
53          },
54        });
55
56        FetchIt?.Message?.before?.();
57
58        if (!document.dispatchEvent(beforeEvent)) {
59          return;
60        }
61
62        this.disableFields();
63
64        try {
65          const query = await fetch(this.request, { body: this.formData });
66          const response = await query.json();
67
68          const afterEvent = new CustomEvent(FetchIt.events.after, {
69            cancelable: true,
70            detail: {
71              form: this.form,
72              formData: this.formData,
73              response,
74              fetchit: this,
75            },
76          });
77
78          FetchIt?.Message?.after?.(response.message);
79
80          if (!document.dispatchEvent(afterEvent)) {
81            return;
82          }
83
84          if (!response.success) {
85            FetchIt?.Message?.error?.(response.message);
86
87            const errorEvent = new CustomEvent(FetchIt.events.error, {
88              cancelable: true,
89              detail: {
90                form: this.form,
91                formData: this.formData,
92                response,
93                fetchit: this,
94              },
95            });
96
97            if (!document.dispatchEvent(errorEvent)) {
98              return;
99            }
100
101            for (const [ name, message ] of Object.entries(response.data)) {
102              this.setError(name, message);
103            }
104
105            return;
106          }
107
108          this.clearErrors();
109          FetchIt?.Message?.success?.(response.message);
110
111          const successEvent = new CustomEvent(FetchIt.events.success, {
112            detail: {
113              form: this.form,
114              formData: this.formData,
115              response,
116              fetchit: this,
117            },
118          });
119
120          if (!document.dispatchEvent(successEvent)) {
121            return;
122          }
123
124          if (typeof window.grecaptcha !== 'undefined') {
125            window.grecaptcha.reset();
126          }
127
128          if (this.config.clearFieldsOnSuccess) {
129            this.form.reset();
130          }
131        } catch (e) {
132          console.error(e);
133        } finally {
134          this.enableFields();
135        }
136      });
137
138      this.form.addEventListener('reset', () => {
139        const resetEvent = new CustomEvent(FetchIt.events.reset, {
140          detail: {
141            form: this.form,
142            fetchit: this,
143          },
144        });
145
146        document.dispatchEvent(resetEvent);
147        this.clearErrors();
148        FetchIt?.Message?.reset?.();
149      });
150
151      ['change', 'input'].forEach(eventName => {
152        this.form.addEventListener(eventName, ({ target }) => {
153          this.clearError(target.getAttribute('name'));
154        });
155      });
156    }
157
158    clearErrors () {
159      this.fields.forEach(field => this.clearError(field.getAttribute('name')));
160    }
161
162    clearError (name) {
163      const fields = this.getFields(name);
164      fields.forEach(field => {
165        if (this.inputInvalidClasses) {
166          field.classList.remove(...this.inputInvalidClasses);
167        }
168        field.removeAttribute('aria-invalid');
169        // field.setCustomValidity('');
170      });
171
172      const errors = this.getErrors(name);
173      errors.forEach(error => {
174        error.style.display = 'none';
175        error.innerHTML = '';
176      });
177
178      const customErrors = this.getCustomErrors(name);
179      if (this.customInvalidClasses) {
180        customErrors.forEach(({ classList }) => classList.remove(...this.customInvalidClasses));
181      }
182
183      return {
184        fields,
185        errors,
186        customErrors,
187      };
188    }
189
190    setError (name, message = '') {
191      this.getFields(name).forEach(field => {
192        if (this.inputInvalidClasses) {
193          field.classList.add(...this.inputInvalidClasses);
194        }
195        field.setAttribute('aria-invalid', true);
196        // if (!this.form.noValidate) {
197        //   field.setCustomValidity(FetchIt.sanitizeHTML(message));
198        //   field.reportValidity();
199        // }
200      });
201
202      if (this.customInvalidClasses) {
203        this.getCustomErrors(name).forEach(({ classList }) => classList.add(...this.customInvalidClasses));
204      }
205
206      this.getErrors(name).forEach(error => {
207        error.style.display = '';
208        error.innerHTML = message;
209      });
210    }
211
212    enableFields () {
213      this.elements.forEach(field => field.removeAttribute('disabled'));
214    }
215
216    disableFields () {
217      this.elements.forEach(field => field.setAttribute('disabled', ''));
218    }
219
220    getFields (name) {
221      if (!name) {
222        return [];
223      }
224
225      return Array.from(this.form.querySelectorAll(`[name="${name}"], [name="${name}[]"]`));
226    }
227
228    getErrors (name) {
229      if (!name) {
230        return [];
231      }
232
233      return Array.from(this.form.querySelectorAll(`[data-error="${name}"], [data-error="${name}[]"]`));
234    }
235
236    getCustomErrors (name) {
237      if (!name) {
238        return [];
239      }
240
241      return Array.from(this.form.querySelectorAll(`[data-custom="${name}"]`));
242    }
243
244    get elements () {
245      return Array.from(this.form.elements);
246    }
247
248    get fields () {
249      return this.elements.filter(({ tagName }) => ['select', 'input', 'textarea'].includes(tagName.toLowerCase()));
250    }
251
252    get inputInvalidClasses() {
253      return this.config.inputInvalidClass ? this.config.inputInvalidClass.split(' ') : [];
254    }
255
256    get customInvalidClasses() {
257      return this.config.customInvalidClass ? this.config.customInvalidClass.split(' ') : [];
258    }
259
260    static sanitizeHTML (str = '') {
261      return str.replace(/(<([^>]+)>)/gi, '');
262    }
263
264    static create(config) {
265      if (
266        config.defaultNotifier
267        && typeof window.Notyf === 'function'
268        && typeof FetchIt.Message === 'undefined'
269      ) {
270        const notyf = new Notyf();
271
272        FetchIt.Message = {
273          success(message) {
274            notyf.success(message);
275          },
276          error(message) {
277            notyf.error(message);
278          },
279        };
280      }
281
282      if (!config.action) {
283        throw new Error('Нет идентификатора формы FetchIt');
284      }
285
286      const forms = document.querySelectorAll(`form[data-fetchit="${config.action}"]`);
287      if (!forms) {
288        throw new Error(`В документе не найдено форм по селектору: form[data-fetchit="${config.action}"]`);
289      }
290
291      forms.forEach(form => {
292        new this(form, config);
293      });
294    }
295  }
296
297  window.FetchIt = FetchIt;
298
299})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.