PageSourceSearch

https://www.n-ergie-immobilien.de/public/remotemedien/media/_tech/nkp/webforms/javascript/jquery-webforms.js

js n-ergie-immobilien.de collected 2026-10-08 08:26:11 UTC 61,086 bytes, 1,684 lines download raw bytes

1/*!
2 *  Monday Webforms for FirstSpirit v1.8.12.FS5, (c) 2018 Monday Consulting GmbH
3 *
4 *  @see https://monday-webforms.com/
5 */
6
7;(function(factory) {
8    "use strict";
9    if (typeof define === 'function' && define.amd) {
10        // AMD. Register as an anonymous module.
11        define(['jquery'], factory);
12    } else if (typeof exports === 'object' && typeof require === 'function') {
13        // Node/CommonJS
14        factory(require('jquery'));
15    } else {
16        // Browser globals
17        factory(jQuery);
18    }
19}(function($) {
20    "use strict";
21
22    // polyfill for customevent for IE10
23    (function() {
24        if (typeof window.CustomEvent === "function") {
25            return false;
26        }
27        function CustomEvent(event, params) {
28            params = params || {bubbles: false, cancelable: false, detail: undefined};
29            var evt = document.createEvent('CustomEvent');
30            evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
31            return evt;
32        }
33
34        CustomEvent.prototype = window.Event.prototype;
35
36        window.CustomEvent = CustomEvent;
37    })();
38
39    var EVENTS = {
40            AJAX_FINISHED: "mwf-ajax-finished",
41            AJAX_ERROR: "mwf-ajax-error",
42            FILL_DROPDOWN: "mwf-fill-dropdown",
43            FILL_SELECTION: "mwf-fill-selection",
44            FILL_HIDDEN: "mwf-fill-hidden",
45            SUGGESTION_SELECTED: "mwf-suggestion-selected",
46            VALUE_CHANGED: "mwf-value-changed"
47        },
48
49        globalSettings = {},
50        initialXhrRequest;
51
52    function triggerEvent(el, eventName, options) {
53        var event;
54        if (window.CustomEvent) {
55            event = new CustomEvent(eventName, options);
56        } else {
57            event = document.createEvent('CustomEvent');
58            event.initCustomEvent(eventName, true, true, options);
59        }
60        el.dispatchEvent(event);
61    }
62
63    function globalSettingsWithVariant(variant) {
64        return variant === undefined ?
65            globalSettings.def : $.extend(true, {}, globalSettings.def, globalSettings[variant]);
66    }
67
68    /**
69     * Monday Webforms jQuery-Plugin
70     * @constructor
71     */
72    function Webforms(elem, settings) {
73        var
74            plugin = this,
75            $elem = $(elem),
76            operators = {},
77            filenames = {},
78
79            uiState = {
80                visible: {},
81                hidden: {},
82                writable: {},
83                readonly: {},
84                optional: {},
85                mandatory: {},
86                disabled: {},
87                enabled: {}
88            },
89
90            stateMapping = {
91                visible: 'hidden',
92                hidden: 'visible',
93                writable: 'readonly',
94                readonly: 'writable',
95                optional: 'mandatory',
96                mandatory: 'optional',
97                disabled: 'enabled',
98                enabled: 'disabled'
99            },
100
101            $form = $elem.is('form') ? $elem : $elem.find("form"),
102            formId = $form.dataWithDefault('mwf-id', $form.data('mwf-form')),
103            targetUrl = $form.dataWithDefault('mwf-target', settings.url),
104            statisticsUrl = settings.statisticsUrl,
105            formdata = settings.formdata !== undefined ? settings.formdata : {},
106            trimSpaces = settings.trimSpaces !== undefined ? settings.trimSpaces : true;
107
108        if (!statisticsUrl || 0 === statisticsUrl.length) {
109            statisticsUrl = null;
110        }
111
112        plugin.settings = settings;
113
114        /* internal utility functions
115         -----------------------------------------------------------------------------------------------------------  */
116
117        function updateUI(fields, conditionId, cond) {
118            var s, i, inverseState, isTrue, isFalse, state, input,
119
120                conditionalFieldsState = {
121                    'visible': [], 'hidden': [],
122                    'writable': [], 'readonly': [],
123                    'optional': [], 'mandatory': [],
124                    'enabled': [], 'disabled': []
125                };
126
127            // clear UI state of this condition
128            for (s in uiState) {
129                if (uiState.hasOwnProperty(s)) {
130                    delete uiState[s][conditionId];
131                }
132            }
133
134            for (i = 0; i < fields.length; i++) {
135                input = fields[i].input;
136                state = fields[i].state;
137
138                if (cond) {
139                    conditionalFieldsState[state].push(input);
140                }
141
142                uiState[state][conditionId] = conditionalFieldsState[state];
143
144                inverseState = stateMapping[state];
145
146                isTrue = containsState(state, input);
147                isFalse = containsState(inverseState, input);
148
149                if (isTrue) {
150                    plugin.settings.operations[state]($form, fields[i]);
151                    if (plugin.settings.onConditionTrue !== undefined) {
152                        plugin.settings.onConditionTrue($form, fields[i], state);
153                    }
154                } else if (isFalse || !isTrue) {
155                    plugin.settings.operations[inverseState]($form, fields[i]);
156                    if (plugin.settings.onConditionFalse !== undefined) {
157                        plugin.settings.onConditionFalse($form, fields[i], inverseState);
158                    }
159                }
160            }
161        }
162
163        function containsState(type, input) {
164            var state = uiState[type], cond;
165            for (cond in state) {
166                if (state.hasOwnProperty(cond) && $.inArray(input, state[cond]) > -1) {
167                    return true;
168                }
169            }
170            return false;
171        }
172
173        function valueChanged($elem) {
174            if (!$elem.is(':file')) {
175                formdata = serializeForm($form);
176                $form.trigger("mwf-valuechange", $elem);
177            }
178        }
179
180        function startsWith(formValue, value) {
181            if (formValue == null || value == null) {
182                return false;
183            }
184
185            return RegExp("^" + value).test(formValue);
186        }
187
188        function serializeForm($form) {
189            var o = {}, a = $form.serializeArray(), form = $form.get(0);
190
191            $.each(a, function() {
192                var input = form.querySelector('[name="' + this.name + '"]'),
193                    value = this.value || '',
194                    type = input.getAttribute('type'),
195                    key;
196
197                if (type === 'radio' || type === 'checkbox' || input.nodeName.toLowerCase() === 'select') {
198
199                    if (!o.hasOwnProperty(this.name)) {
200                        o[this.name] = [];
201                    }
202
203                    if (startsWith(value, '{')) {
204                        try {
205                            key = JSON.parse(value).k;
206                        } catch (ex) {
207                            // do nothing
208                        }
209                    } else if (value === 'EMPTY_VALUE') {
210                        value = '';
211                    }
212
213                    o[this.name].push((key !== undefined) ? key : value);
214
215                } else if (type === 'hidden') {
216
217                    if (startsWith(value, '{')) {
218                        try {
219                            key = JSON.parse(value).v;
220                        } catch (ex) {
221                            // do nothing
222                        }
223                    }
224
225                    o[this.name] = (key !== undefined) ? key : value;
226                } else {
227                    o[this.name] = trimSpaces ? value.trim() : value;
228                }
229            });
230
231            $.each(form.querySelectorAll('input[type="checkbox"]:not(:checked),input[type="radio"]:not(:checked)'), function() {
232                var name = this.getAttribute('name');
233                if (!o.hasOwnProperty(name)) {
234                    o[name] = '';
235                }
236            });
237
238            return o;
239        }
240
241        function valueLabel(name, v) {
242            var l = [];
243
244            $.each($form.find('[name="' + name + '"]'), function() {
245                var $input = $(this);
246
247                if ($input.is(':radio') || $input.is(':checkbox')) {
248                    if ($.inArray($input.attr('data-mwf-value'), v) !== -1) {
249                        l.push($input.attr('data-mwf-label'));
250                    }
251                } else if ($input.is('select')) {
252                    $.each($input.find('option'), function() {
253                        var $option = $(this);
254
255                        if ($.inArray($option.attr('data-mwf-value'), v) !== -1) {
256                            l.push($option.attr('data-mwf-label'));
257                        }
258                    });
259                } else if ($input.is(':file')) {
260                    $.merge(l, filenames[name]);
261                } else {
262                    l.push(v);
263                }
264            });
265
266            return l;
267        }
268
269        /* API functions
270         -----------------------------------------------------------------------------------------------------------  */
271
272        function maxSelected(array, max) {
273            var m = Number(max), l = (array !== null) ? array.length : 0;
274            return (l < m);
275        }
276
277        function minSelected(array, min) {
278            var m = Number(min), l = (array !== null) ? array.length : 0;
279            return (l > m);
280        }
281
282        function isSelected(array, s) {
283            return array != null && $.inArray(s, array) > -1;
284        }
285
286        function parseAge(format, str) {
287            if (str == null) {
288                return null;
289            }
290            var date = parseDate(format, str), today = new Date();
291            return Math.floor((today - date) / (365.25 * 24 * 60 * 60 * 1000));
292        }
293
294        function parseDate(format, date) {
295            if (date == null) {
296                return null;
297            }
298            return $.format.date(date, format);
299        }
300
301        function isEmptyList(array) {
302            var i, s;
303            if (array != null) {
304                for (i = 0; i < array.length; i++) {
305                    s = String(array[i]);
306                    if (s != null && s !== '' && s !== 'EMPTY_VALUE') {
307                        return false;
308                    }
309                }
310            }
311            return true;
312        }
313
314        function ajaxFillSelection($elem, attr) {
315            var data = $.extend(formdata, attr.data);
316
317            if ((attr.createEntry === undefined)) {
318                attr.createEntry = (attr.type === 'checkbox') ? plugin.settings.createCheckBox : plugin.settings.createRadio;
319            }
320
321            if ((attr.onFillSelection === undefined)) {
322                attr.onFillSelection = plugin.settings.onFillSelection;
323            }
324
325            $.ajax({
326                    url: attr.url,
327                    type: 'POST',
328                    data: data,
329                    traditional: true,
330                    cache: false,
331                    xhrFields: {
332                        withCredentials: true
333                    }
334                })
335                .done(function(json) {
336                    var pre = attr.preselected.split(','), i, entry;
337
338                    $elem.find('[data-mwf-mutable]').remove();
339
340                    for (i in json) {
341                        if (json.hasOwnProperty(i)) {
342                            entry = json[i];
343                            $elem.append(attr.createEntry($form, attr.name, entry, $.inArray(entry.k, pre) !== -1));
344                        }
345                    }
346
347                    attr.onFillSelection($form, $elem);
348                    triggerEvent(document, EVENTS.FILL_SELECTION, {detail: {$form: $form, $elem: $elem}});
349                })
350                .fail(function(jqXHR, textStatus, errorThrown) {
351                    plugin.settings.onAjaxError(jqXHR, textStatus, errorThrown);
352                });
353        }
354
355        function ajaxFillHidden($elem, attr) {
356            var data = $.extend(formdata, attr.data);
357
358            $.ajax({
359                    url: attr.url,
360                    type: 'POST',
361                    data: data,
362                    traditional: true,
363                    cache: false,
364                    xhrFields: {
365                        withCredentials: true
366                    }
367                })
368                .done(function(json) {
369                    $elem.val(JSON.stringify(json));
370                    $elem.attr('data-mwf-value', json.v);
371                    $elem.trigger('change');
372
373                    triggerEvent(document, EVENTS.FILL_HIDDEN, {detail: {$form: $form, $elem: $elem}});
374                })
375                .fail(function(jqXHR, textStatus, errorThrown) {
376                    plugin.settings.onAjaxError(jqXHR, textStatus, errorThrown);
377                });
378        }
379
380        function ajaxFillDropdown($elem, attr) {
381            var data = $.extend(formdata, attr.data);
382
383            if ((attr.createOption === undefined)) {
384                attr.createOption = plugin.settings.createOption;
385            }
386
387            if ((attr.onFillDropdown === undefined)) {
388                attr.onFillDropdown = plugin.settings.onFillDropdown;
389            }
390
391            $.ajax({
392                    url: attr.url,
393                    type: 'POST',
394                    data: data,
395                    traditional: true,
396                    cache: false,
397                    xhrFields: {
398                        withCredentials: true
399                    }
400                })
401                .done(function(json) {
402                    var $option, i, entry, pre = attr.preselected.split(',');
403
404                    $elem.find('[data-mwf-mutable]').remove();
405
406                    for (i in json) {
407                        if (json.hasOwnProperty(i)) {
408                            entry = json[i];
409                            $option = attr.createOption($form, entry, $.inArray(entry.k, pre) !== -1);
410                            $elem.append($option);
411                        }
412                    }
413
414                    attr.onFillDropdown($form, $elem);
415
416                    triggerEvent(document, EVENTS.FILL_DROPDOWN, {detail: {$form: $form, $elem: $elem}});
417                })
418                .fail(function(jqXHR, textStatus, errorThrown) {
419                    plugin.settings.onAjaxError(jqXHR, textStatus, errorThrown);
420                });
421        }
422
423        function ajaxAutocomplete($elem, attr) {
424            var chars = 1;
425
426            if (attr.params.chars !== undefined) {
427                chars = attr.params.chars;
428            }
429
430            var onSelect = function(selection) {
431                valueChanged($elem);
432                triggerEvent(document, EVENTS.SUGGESTION_SELECTED, {
433                    detail: {
434                        $form: $form,
435                        $elem: $elem,
436                        id: formId,
437                        selection: selection,
438                        params: attr.params
439                    }
440                });
441                if ($.isFunction(attr.onSelect)) {
442                    attr.onSelect(arguments);
443                }
444            };
445
446            $elem.autocomplete({
447                paramName: 'query',
448                params: attr.data,
449                serviceUrl: attr.url,
450                maxHeight: 150,
451                noCache: true,
452                minChars: chars,
453                type: 'POST',
454                onSelect: onSelect,
455                autoSelectFirst: true,
456                sendFormData: true,
457
458                transformResult: function(response) {
459                    response = JSON.parse(response);
460                    return {
461                        suggestions: $.map(response, function(entry, key) {
462                            return {value: entry.v, data: entry.k};
463                        })
464                    };
465                }
466            });
467        }
468
469        function ajaxSubmit(opt) {
470            var $buttons = $form.find(':button').filter(':not(:disabled)'),
471                data = {_parentUrl: window.location.href, _timezone: $.timezone()};
472
473            if (plugin.settings.appendUrlVars) {
474                $.extend(data, $.getUrlVars(window.location.search));
475            }
476
477            $.extend(data, $.getUrlVars(opt.query), opt.data, $form.serializeObject());
478
479            if (opt.onSubmit !== undefined) {
480                if (!opt.onSubmit($form, opt.url, opt.query)) {
481                    return;
482                }
483            }
484
485            $buttons.prop('disabled', true);
486
487            $.ajax({
488                    url: opt.url,
489                    type: 'POST',
490                    data: data,
491                    traditional: true,
492                    cache: false,
493                    xhrFields: {
494                        withCredentials: true
495                    }
496                })
497                .done(function(data, textStatus, jqXHR) {
498
499                    if (jqXHR && jqXHR.getResponseHeader("X-Redirect-Location")) {
500                        if (opt.onRedirect !== undefined) {
501                            opt.onRedirect($form, data, textStatus, jqXHR);
502                        }
503                        var timeout = (jqXHR.getResponseHeader('X-Redirect-Delay') || 0) * 1000;
504                        setTimeout(function() {
505                            location.assign(jqXHR.getResponseHeader('X-Redirect-Location'));
506                        }, timeout);
507
508                        if (!timeout) {
509                            return;
510                        }
511                    }
512
513                    $elem = $elem.replaceWithPush(data);
514                    $form = $elem.is('form') ? $elem : $elem.find("form");
515
516                    if (opt.onSuccess !== undefined) {
517                        opt.onSuccess($form, data, textStatus, jqXHR);
518                    }
519
520                    triggerEvent(document, EVENTS.AJAX_FINISHED, {detail: {$dest: $elem}});
521                })
522                .fail(function(jqXHR, textStatus, errorThrown) {
523                    if (opt.onError !== undefined) {
524                        opt.onError($form, jqXHR, textStatus, errorThrown);
525                    }
526
527                    $buttons.prop('disabled', false);
528                    triggerEvent(document, EVENTS.AJAX_ERROR, {
529                        detail: {
530                            $dest: $elem,
531                            jqXHR: jqXHR,
532                            textStatus: textStatus,
533                            errorThrown: errorThrown
534                        }
535                    })
536                });
537        }
538
539        function createCondition(conditionId, conjunction, conditions, fields) {
540            var checkCondition = function() {
541                var all = true, any = false, condTrue, i, formValue, cond;
542
543                for (i = 0; i < conditions.length; i++) {
544                    cond = conditions[i];
545
546                    if (!cond) {
547                        continue;
548                    }
549
550                    formValue = formdata[cond[1]];
551
552                    if (formValue === undefined) {
553                        formValue = cond[4];
554                    }
555                    condTrue = operators[cond[2]](formValue, cond[3]);
556
557                    if (condTrue) {
558                        any = true;
559                    } else {
560                        all = false;
561                    }
562
563                    if (!conjunction && any) {
564                        break;
565                    }
566                }
567
568                updateUI(fields, conditionId, (all || (!conjunction && any)));
569            };
570
571            // register event listener
572            $form.on('mwf-valuechange', function(e, input) {
573                var cond, i;
574
575                for (i = 0; i < conditions.length; i++) {
576                    cond = conditions[i];
577
578                    if (!cond) {
579                        continue;
580                    }
581
582                    if ($(input).attr("name") === conditions[i][1]) {
583                        checkCondition();
584                    }
585                }
586            });
587
588            // check conditions initially
589            checkCondition();
590
591            if (plugin.settings.onConditionCreated !== undefined) {
592                plugin.settings.onConditionCreated($form, conditionId, conjunction, conditions, fields);
593            }
594        }
595
596        function createCalculatedValue(calcValueId, js, fields, formVariables, updateV
596alue) {
597            updateValue = (updateValue === undefined) ? plugin.settings.updateCalculatedValue : updateValue;
598
599            var name,
600                id = calcValueId,
601                vars = formVariables,
602                fct,
603                calculate = function() {
604                    var state = $.extend({}, fields, formdata, vars),
605                        result = fct(state),
606                        $field = $form.find('[data-mwf-id="' + id + '"]');
607
608                    updateValue($form, id, result);
609                    $field.val(result).trigger('change');
610                };
611
612            try {
613                eval('fct = function(s) {' + js + '}');
614            } catch (ex) {
615                $.logError(ex.message);
616            }
617
618            // register event listener
619            $form.on('mwf-valuechange', function(e, input) {
620                for (name in fields) {
621                    if (fields.hasOwnProperty(name) && $(input).attr('name') === name) {
622                        calculate();
623                        break;
624                    }
625                }
626            });
627        }
628
629        /* condition operators
630         -----------------------------------------------------------------------------------------------------------  */
631
632        operators.contains = function(formValue, value) {
633            if (formValue == null || value == null) {
634                return false;
635            }
636            return formValue.indexOf(value) !== -1;
637        };
638
639        operators.containsnot = function(formValue, value) {
640            if (formValue == null || value == null) {
641                return false;
642            }
643            return formValue.indexOf(value) === -1;
644        };
645
646        operators.startswith = function(formValue, value) {
647            return startsWith(formValue, value);
648        };
649
650        operators.endswith = function(formValue, value) {
651            if (formValue == null || value == null) {
652                return false;
653            }
654            return RegExp(value + "$").test(formValue);
655        };
656
657        operators.equal = function(formValue, value) {
658            if (formValue == null || value == null) {
659                return formValue === value;
660            }
661            var f1 = parseFloat(formValue.replace(',', '.')),
662                f2 = parseFloat(value.replace(',', '.'));
663
664            return (!isNaN(f1) && !isNaN(f2) && f1 === f2) || (formValue === value);
665        };
666
667        operators.notequal = function(formValue, value) {
668            if (formValue == null || value == null) {
669                return formValue !== value;
670            }
671            var f1 = parseFloat(formValue.replace(',', '.')),
672                f2 = parseFloat(value.replace(',', '.'));
673
674            return (!isNaN(f1) && !isNaN(f2) && f1 !== f2) || (formValue !== value);
675        };
676
677        operators.empty = function(formValue, value) {
678            return formValue == null || formValue === '';
679        };
680
681        operators.notempty = function(formValue, value) {
682            return formValue != null && formValue !== '';
683        };
684
685        operators.emptylist = function(formValue, value) {
686            return isEmptyList(formValue);
687        };
688
689        operators.notemptylist = function(formValue, value) {
690            return !isEmptyList(formValue);
691        };
692
693        operators.selected = function(formValue, value) {
694            if (formValue == null || value == null) {
695                return false;
696            }
697            return $.inArray(value, formValue) !== -1;
698        };
699
700        operators.notselected = function(formValue, value) {
701            if (formValue == null || value == null) {
702                return false;
703            }
704            return $.inArray(value, formValue) === -1;
705        };
706
707        operators.minselected = function(formValue, value) {
708            var l = (formValue == null) ? 0 : formValue.length;
709            return l > Number(value);
710        };
711
712        operators.maxselected = function(formValue, value) {
713            var l = (formValue == null) ? 0 : formValue.length;
714            return l < Number(value);
715        };
716
717        operators.lessthan = function(formValue, value) {
718            if (formValue == null || value == null) {
719                return false;
720            }
721            var f1 = parseFloat(formValue.replace(',', '.')),
722                f2 = parseFloat(value.replace(',', '.'));
723
724            return (!isNaN(f1) && !isNaN(f2) && f1 < f2);
725        };
726
727        operators.greaterthan = function(formValue, value) {
728            if (formValue == null || value == null) {
729                return false;
730            }
731            var f1 = parseFloat(formValue.replace(',', '.')),
732                f2 = parseFloat(value.replace(',', '.'));
733
734            return (!isNaN(f1) && !isNaN(f2) && f1 > f2);
735        };
736
737        /* public methods
738         -----------------------------------------------------------------------------------------------------------  */
739
740        plugin.formSubmit = function(opt) {
741            ajaxSubmit({
742                url: targetUrl,
743                id: formId,
744                query: (opt.query !== undefined) ? opt.query : '',
745                onSubmit: (opt.submit !== undefined) ? opt.submit : plugin.settings.onSubmit,
746                onSuccess: (opt.success !== undefined) ? opt.success : plugin.settings.onSuccess,
747                onError: (opt.error !== undefined) ? opt.error : plugin.settings.onAjaxError,
748                onRedirect: (opt.redirect !== undefined) ? opt.redirect : plugin.settings.onRedirect
749            });
750        };
751
752        plugin.gotoPage = function(opt) {
753            ajaxSubmit({
754                url: targetUrl,
755                id: formId,
756                query: opt.query.concat('&_target', opt.page, '=', opt.page),
757                onSubmit: (opt.submit !== undefined) ? opt.submit : plugin.settings.onSubmit,
758                onSuccess: (opt.success !== undefined) ? opt.success : plugin.settings.onSuccess,
759                onError: (opt.error !== undefined) ? opt.error : plugin.settings.onAjaxError,
760                onRedirect: (opt.redirect !== undefined) ? opt.redirect : plugin.settings.onRedirect
761            });
762        };
763
764        plugin.init = function() {
765            $form.find('input').keydown(function(e) {
766                if (e.keyCode === 13) {
767                    e.preventDefault();
768                    return false;
769                }
770            });
771
772            $form.on('change', function(event) {
773                valueChanged($(event.target));
774
775                if (statisticsUrl !== null) {
776                    $.ajax({
777                        url: statisticsUrl,
778                        xhrFields: {
779                            withCredentials: true
780                        }
781                    });
782                    statisticsUrl = null;
783                }
784            });
785
786            if (targetUrl === undefined) {
787                $.logError('No target URL specified.')
788            }
789
790            $.each($form.find('[data-mwf-submit]'), function() {
791                var attr = $(this).data('mwf-submit'),
792                    query = (attr.query !== undefined) ? attr.query : '',
793                    onSuccess = (attr.success !== undefined) ? attr.success : plugin.settings.onSuccess,
794                    onRedirect = (attr.redirect !== undefined) ? attr.redirect : plugin.settings.onRedirect,
795                    onError = (attr.error !== undefined) ? attr.error : plugin.settings.onAjaxError,
796                    onSubmit = (attr.submit !== undefined) ? attr.submit : plugin.settings.onSubmit;
797
798                switch (attr.type) {
799                    case 'next':
800                    case 'back':
801                    case 'goto':
802                        query = query.concat('&_target', attr.page, '=', attr.page);
803                        break;
804
805                    case 'cancel':
806                    case 'exit':
807                    case 'finish':
808                        query = query.concat('&_', attr.type, '=1');
809                        break;
810                }
811
812                $(this).on('click', function() {
813                    ajaxSubmit({
814                        url: targetUrl,
815                        id: formId,
816                        query: query,
817                        onSubmit: onSubmit,
818                        onSuccess: onSuccess,
819                        onError: onError,
820                        onRedirect: onRedirect
821                    });
822                });
823            });
824
825            $.each($form.find('[data-mwf-bind]'), function() {
826                var name = $(this).data('mwf-bind'),
827                    $elem = $(this);
828
829                $form.on('mwf-valuechange', function(e, input) {
830                    var v, l;
831
832                    if ($(input).attr('name') === name) {
833                        v = formdata[name];
834                        l = valueLabel(name, v);
835
836                        plugin.settings.updateFormValue($form, $elem, name, l);
837                        triggerEvent(document, EVENTS.VALUE_CHANGED, {
838                            detail: {
839                                $form: $form,
840                                $elem: $elem,
841                                name: name,
842                                value: l
843                            }
844                        });
845                        return false;
846                    }
847                });
848            });
849
850            $.each($form.find('[data-mwf-fileupload]'), function() {
851                var $upload = $(this),
852                    attr = $(this).data('mwf-fileupload'),
853                    $dropzone = $upload.find('[data-mwf-dropzone]'),
854                    $files = $upload.find('[data-mwf-files]'),
855                    $fileInput = $upload.find('input:file'),
856                    multiple = $fileInput.attr('multiple') !== undefined,
857                    useXhr = (!multiple && $.support.xhrFileUpload) || $.support.xhrFormDataFileUpload,
858                    count = 0,
859                    pendingList = [],
860                    errorRows = [],
861                    enabled = true,
862                    $buttons = null;
863
864                $upload.find('[data-mwf-file-upload-all]').on('click', function() {
865                    pendingList.forEach(function(data) {
866                        data.submit();
867                    });
868                    pendingList = [];
869                });
870
871                $upload.find('[data-mwf-file-delete-all]').on('click', function() {
872                    $files.find('[data-mwf-file-delete]').trigger('click');
873                    pendingList = [];
874                });
875
876                $upload.on('disable', function() {
877                    enabled = false;
878                    $upload.fileupload('disable');
879                    $upload.addClass('mwf-upload-disabled');
880                    $upload.find(':button').prop('disabled', true);
881                    $fileInput.prop('disabled', true);
882                });
883
884                $upload.on('enable', function() {
885                    enabled = true;
886                    $upload.fileupload('enable');
887                    $upload.removeClass('mwf-upload-disabled');
888                    $upload.find(':button').prop('disabled', false);
889                    $fileInput.prop('disabled', false);
890                });
891
892                $dropzone.on('dragover', function() {
893                    if (enabled) {
894                        $(this).addClass('mwf-upload-dragover');
895                    }
896                });
897
898                $dropzone.on('dragleave drop', function() {
899                    $(this).removeClass('mwf-upload-dragover');
900                });
901
902                $upload.fileupload({
903                    url: attr.url,
904                    paramName: attr.name,
905                    dataType: 'json',
906                    dropZone: $dropzone,
907                    fileInput: $fileInput,
908                    previewMaxWidth: attr.previewMaxWidth,
909                    previewMaxHeight: attr.previewMaxHeight,
910                    previewCrop: true,
911                    maxNumberOfFiles: 1,
912                    formData: {xhr: useXhr},
913                    xhrFields: {
914                        withCredentials: true
915                    },
916
917                    add: function(e, data) {
918                        var $this = $upload;
919
920                        if (!enabled) {
921                            return false;
922                        }
923
924                        $.each(errorRows, function(index, $row) {
925                            $row.remove();
926                        });
927
928                        if (multiple || count === 0) {
929                            count++;
930                        } else {
931                            return false;
932                        }
933
934                        pendingList.push(data);
935
936                        data.process(function() {
937                            return $this.fileupload('process', data);
938                        }).always(function() {
939                            $.each(data.files, function(index, file) {
940                                var $row = plugin.settings.createUploadFileRow($form, attr, file);
941                                data.context = $row;
942
943                                $row.find('[data-mwf-file-upload]').data(data).on('click', function() {
944                                    pendingList.splice($.inArray(data, pendingList), 1);
945                                    data.submit();
946                                });
947
948                                $row.find('[data-mwf-file-delete]').data(data).on('click', function() {
949                                    $row.remove();
950                                    pendingList.splice($.inArray(data, pendingList), 1);
951                                    count--;
952                                });
953
954                                $row.find('[data-mwf-file-preview]').append(file.preview);
955
956                                $files.append($row);
957                            });
958
959                            if (attr.autoUpload === true) {
960                                data.submit();
961                            }
962                        });
963                    },
964
965                    submit: function(e, data) {
966                        if ($buttons === null) {
967                            $buttons = $form.find(':button').filter(':not(:disabled)');
968                            $buttons.prop('disabled', true);
969                        }
970                    },
971
972                    progress: function(e, data) {
973                        var progress = parseInt(data.loaded / data.total * 100, 10);
974                        if (data.context) {
975                            data.context.each(function() {
976                                data.context.find('[data-mwf-file-progress]').attr('aria-valuenow', progress).css('display', 'block').children().first().css('width', progress + '%').text(progress + '%');
977                            });
978                        }
979                    },
980
981                    done: function(e, data) {
982                        var files = (typeof data.result === 'string') ? JSON.parse(data.result).files : data.result.files;
983
984                        $.each(files, function(index, file) {
985                            var $row = plugin.settings.createDownloadFileRow($form, attr, file);
986
987                            if (data.context !== undefined) {
988                                data.context.replaceWith($row)
989                            } else {
990                                $files.append($row);
991                            }
992
993                            if (file.error === undefined) {
994                                $row.find('[data-mwf-file-delete]').on('click', function() {
995                                    if (file.delete_url) {
996                                        $.ajax({
997                                            url: file.delete_url,
998                                            xhrFields: {
999                                                withCredentials: true
1000                                            }
1001                                        });
1002                                    }
1003                                    $row.remove();
1004                                    pendingList.splice($.inArray(data, pendingList), 1);
1005
1006                                    // update filenames
1007                                    if (filenames.hasOwnProperty(attr.name)) {
1008                                        filenames[attr.name].splice($.inArray(file.name, filenames[attr.name]), 1
1008);
1009                                        $form.trigger("mwf-valuechange", data.fileInput);
1010                                    }
1011
1012                                    count--;
1013                                });
1014
1015                                // update filenames
1016                                if (!filenames.hasOwnProperty(attr.name)) {
1017                                    filenames[attr.name] = [];
1018                                }
1019
1020                                filenames[attr.name].push(file.name);
1021                                $form.trigger("mwf-valuechange", data.fileInput);
1022
1023                            } else {
1024                                $row.find('[data-mwf-file-delete]').on('click', function() {
1025                                    $row.remove();
1026                                    pendingList.splice($.inArray(data, pendingList), 1);
1027                                });
1028
1029                                errorRows.push($row);
1030                                count--;
1031                            }
1032                        });
1033                    },
1034
1035                    fail: function(e, data) {
1036                        $.each(data.files, function(index, file) {
1037                            var $row = plugin.settings.createDownloadFileRow($form, attr, {
1038                                name: file.name,
1039                                size: file.size,
1040                                error: attr.labels.error
1041                            });
1042
1043                            $row.find('[data-mwf-file-delete]').data(data).on('click', function() {
1044                                $row.remove();
1045                                pendingList.splice($.inArray(data, pendingList), 1);
1046                            });
1047
1048                            errorRows.push($row);
1049                            count--;
1050
1051                            if (data.context !== undefined) {
1052                                data.context.replaceWith($row)
1053                            } else {
1054                                $files.append($row);
1055                            }
1056                        });
1057                    },
1058
1059                    always: function(e, data) {
1060                        if ($buttons !== null && $upload.fileupload('active') === 1) {
1061                            $buttons.prop('disabled', false);
1062                            $buttons = null;
1063                        }
1064                    }
1065                });
1066
1067                // preload existing files
1068                $.ajax({
1069                    url: attr.url,
1070                    dataType: "json",
1071                    data: {_name: attr.name, _do: 'files'},
1072                    xhrFields: {
1073                        withCredentials: true
1074                    }
1075                }).done(function(result) {
1076                    $upload.fileupload('option', 'done').call($upload, $.Event('done'), {result: result});
1077                    count = result.files.length;
1078                });
1079            });
1080
1081            $.each($form.find('[data-mwf-datasource]'), function() {
1082                var def = {
1083                        params: {},
1084                        data: {}
1085                    },
1086                    attr = $.extend(true, {}, def, $(this).data('mwf-datasource')),
1087                    $elem = $(this);
1088
1089                switch (attr.type) {
1090                    case 'checkbox':
1091                    case 'radio':
1092                        ajaxFillSelection($elem, attr);
1093
1094                        $form.on('mwf-valuechange', function(e, input) {
1095                            if ($.trim(attr.params.dependsOn)) {
1096                                $.each(attr.params.dependsOn.split(','), function(i, v) {
1097                                    if ($(input).attr('name') === v) {
1098                                        ajaxFillSelection($elem, attr);
1099                                        return false;
1100                                    }
1101                                });
1102                            }
1103                        });
1104                        break;
1105                    case 'selection':
1106                        ajaxFillDropdown($elem, attr);
1107
1108                        $form.on('mwf-valuechange', function(e, input) {
1109                            if ($.trim(attr.params.dependsOn)) {
1110                                $.each(attr.params.dependsOn.split(','), function(i, v) {
1111                                    if ($(input).attr('name') === v) {
1112                                        ajaxFillDropdown($elem, attr);
1113                                        return false;
1114                                    }
1115                                });
1116                            }
1117                        });
1118                        break;
1119                    case 'suggestion':
1120                        ajaxAutocomplete($elem, attr);
1121                        break;
1122                    case 'hidden':
1123                        ajaxFillHidden($elem, attr);
1124
1125                        $form.on('mwf-valuechange', function(e, input) {
1126                            if ($.trim(attr.params.dependsOn)) {
1127                                $.each(attr.params.dependsOn.split(','), function(i, v) {
1128                                    if ($(input).attr('name') === v) {
1129                                        ajaxFillHidden($elem, attr);
1130                                        return false;
1131                                    }
1132                                });
1133                            }
1134                        });
1135                        break;
1136                    default:
1137                        $.logError(attr.type === undefined ?
1138                            'Please specifiy the datasource type (checkbox, radio, selection or suggestion).' :
1139                            'Unknown datasource type "'.concat(attr.type, '".'));
1140                }
1141            });
1142
1143            $.each(plugin.settings.conditions, function() {
1144                createCondition($(this).attr('id'), $(this).attr('conjunction'), $(this).attr('conditions'), $(this).attr('fields'));
1145            });
1146
1147            $.each(plugin.settings.calculatedValues, function() {
1148                createCalculatedValue($(this).attr('id'), $(this).attr('js'), $(this).attr('fields'), $(this).attr('vars'));
1149            });
1150
1151            plugin.settings.onInit($form);
1152        };
1153
1154        plugin.init();
1155    }
1156
1157    /* default plugin settings
1158     -----------------------------------------------------------------------------------------------------------  */
1159
1160    globalSettings.def = {
1161        appendUrlVars: false,
1162        operations: {},
1163        conditions: [],
1164        calculatedValues: [],
1165        fileuploadOptions: {},
1166        onConditionTrue: undefined,
1167        onConditionFalse: undefined,
1168        statisticsUrl: null
1169    };
1170
1171    globalSettings.def.operations['visible'] = function($form, field) {
1172        var $field = $form.find('[data-mwf-container="' + field.input + '"]');
1173        $field.removeAttr('disabled');
1174        $field.removeClass('mwf-hidden');
1175    };
1176
1177    globalSettings.def.operations['hidden'] = function($form, field) {
1178        var $field = $form.find('[data-mwf-container="' + field.input + '"]');
1179        $field.attr("disabled", "true");
1180        $field.addClass('mwf-hidden');
1181    };
1182
1183    globalSettings.def.operations['writable'] = function($form, field) {
1184        var $field = $form.find('[data-mwf-id="' + field.input + '"]');
1185        $field.removeAttr('readonly');
1186    };
1187
1188    globalSettings.def.operations['readonly'] = function($form, field) {
1189        var $field = $form.find('[data-mwf-id="' + field.input + '"]');
1190        $field.val(field.value);
1191        $field.attr("readonly", "true");
1192    };
1193
1194    globalSettings.def.operations['enabled'] = function($form, field) {
1195        var $field = $form.find('[data-mwf-id="' + field.input + '"]');
1196        $field.removeAttr('disabled');
1197        $field.trigger('enable');
1198    };
1199
1200    globalSettings.def.operations['disabled'] = function($form, field) {
1201        var $field = $form.find('[data-mwf-id="' + field.input + '"]');
1202        $field.attr("disabled", "true");
1203        $field.trigger('disable');
1204    };
1205
1206    globalSettings.def.operations['optional'] = function($form, field) {
1207        var $label = $form.find('label[for="' + field.input + '"]');
1208        $label.children('span.mwf-required').remove();
1209    };
1210
1211    globalSettings.def.operations['mandatory'] = function($form, field) {
1212        var $label = $form.find('label[for="' + field.input + '"]'),
1213            $span = $('<span></span>').attr('class', 'mwf-required').text('*');
1214        $label.children('span.mwf-required').remove();
1215        $label.append($span);
1216    };
1217
1218    globalSettings.def.createOption = function($form, entry, selected) {
1219        var $option = $('<option></option>')
1220            .attr('data-mwf-value', entry.k)
1221            .attr('data-mwf-label', entry.v)
1222            .attr('data-mwf-mutable', '')
1223            .attr('value', JSON.stringify(entry))
1224            .append(entry.v);
1225
1226        if (selected) {
1227            $option.attr('selected', true);
1228        }
1229        return $option;
1230    };
1231
1232    globalSettings.def.createRadio = function($form, name, entry, checked) {
1233        var $span, $input, $label;
1234
1235        $span = $('<span></span>')
1236            .attr('class', 'mwf-option')
1237            .attr('data-mwf-mutable', '');
1238
1239        $input = $('<input/>')
1240            .attr('type', 'radio')
1241            .attr('id', entry.i)
1242            .attr('data-mwf-id', entry.i)
1243            .attr('data-mwf-value', entry.k)
1244            .attr('data-mwf-label', entry.v)
1245            .attr('value', JSON.stringify(entry))
1246            .attr('name', name)
1247            .attr('class', 'mwf-radio');
1248
1249        if (checked) {
1250            $input.attr('checked', 'checked');
1251        }
1252
1253        $label = $('<label></label>')
1254            .attr('for', entry.i).append(entry.v);
1255
1256        $span.append($input);
1257        $span.append(' ');
1258        $span.append($label);
1259
1260        return $span;
1261    };
1262
1263    globalSettings.def.createCheckBox = function($form, name, entry, checked) {
1264        var $span, $input, $label;
1265
1266        $span = $('<span></span>')
1267            .attr('class', 'mwf-option')
1268            .attr('data-mwf-mutable', '');
1269
1270        $input = $('<input/>')
1271            .attr('type', 'checkbox')
1272            .attr('id', entry.i)
1273            .attr('data-mwf-id', entry.i)
1274            .attr('data-mwf-value', entry.k)
1275            .attr('data-mwf-label', entry.v)
1276            .attr('value', JSON.stringify(entry))
1277            .attr('name', name)
1278            .attr('class', 'mwf-checkbox');
1279
1280        if (checked) {
1281            $input.attr('checked', 'checked');
1282        }
1283
1284        $label = $('<label></label>')
1285            .attr('for', entry.i).append(entry.v);
1286
1287        $span.append($input);
1288        $span.append(' ');
1289        $span.append($label);
1290
1291        return $span;
1292    };
1293
1294    globalSettings.def.updateFormValue = function($form, $elem, name, v) {
1295        $elem.html($.isArray(v) ? v.join(', ') : v);
1296    };
1297
1298    globalSettings.def.createUploadFileRow = function($form, attr, file) {
1299
1300        var $row, $fileinfo, $meta, $preview, $ul, $name, $size, $buttons, $upload, $delete, $span, $progress, $error;
1301
1302        $row = $('<div/>').attr('data-mwf-file', '').attr('class', 'mwf-upload-row');
1303
1304        $fileinfo = $('<div/>').attr('class', 'mwf-upload-fileinfo');
1305
1306        $preview = $('<div/>').attr('data-mwf-file-preview', '').attr('class', 'mwf-upload-preview');
1307
1308        $meta = $('<div/>').attr('class', 'mwf-upload-metadata');
1309
1310        $ul = $('<ul/>');
1311
1312        $name = $('<li>').text(attr.labels.name + ': ' + file.name);
1313
1314        $size = $('<li>').text(attr.labels.size + ': ' + $.formatSize(file.size));
1315
1316        $buttons = $('<div/>').attr('class', ' mwf-upload-actions');
1317
1318        $upload = $('<button>').attr('data-mwf-file-upload', '').attr('class', 'mwf-upload-upload').text(attr.labels.upload);
1319
1320        $delete = $('<button>').attr('data-mwf-file-delete', '').attr('class', 'mwf-upload-delete').text(attr.labels.del);
1321
1322        $span = $('<span>').css('width', '0%');
1323
1324        $progress = $('<div/>').attr('data-mwf-file-progress', '').attr('class', 'mwf-upload-progressbar');
1325
1326        $error = $('<div/>').attr('data-mwf-file-error', '').attr('class', 'mwf-upload-error');
1327
1328        $buttons.append($delete);
1329
1330        if (attr.autoUpload === false) {
1331            $buttons.append($upload);
1332        }
1333
1334        $ul.append($name);
1335        $ul.append($size);
1336        $meta.append($ul);
1337        $fileinfo.append($preview);
1338        $fileinfo.append($meta);
1339        $progress.append($span);
1340        $row.append($fileinfo);
1341        $row.append($buttons);
1342        $row.append($error);
1343        $row.append($progress);
1344
1345        return $row;
1346    };
1347
1348    globalSettings.def.createDownloadFileRow = function($form, attr, file) {
1349
1350        var $row, $fileinfo, $meta, $preview, $image, $ul, $name, $size, $buttons, $delete, $span, $error;
1351
1352        $row = $('<div/>').attr('data-mwf-file', '').attr('class', 'mwf-upload-row');
1353
1354        $fileinfo = $('<div/>').attr('class', 'mwf-upload-fileinfo');
1355
1356        $preview = $('<div/>').attr('data-mwf-preview', '').attr('class', 'mwf-upload-preview');
1357
1358        $meta = $('<div/>').attr('class', 'mwf-upload-metadata');
1359
1360        $ul = $('<ul/>');
1361
1362        $name = $('<li>').text(attr.labels.name + ': ' + file.name);
1363
1364        $size = $('<li>').text(attr.labels.size + ': ' + $.formatSize(file.size));
1365
1366        $buttons = $('<div/>').attr('class', ' mwf-upload-actions');
1367
1368        $delete = $('<button>').attr('data-mwf-file-delete', '').attr('class', 'mwf-upload-delete').text(attr.labels.del);
1369
1370        $buttons.append($delete);
1371        $ul.append($name);
1372        $ul.append($size);
1373        $meta.append($ul);
1374
1375        if (file.thumbnail_url) {
1376            $image = $('<img/>').attr('src', file.thumbnail_url);
1377            $preview.append($image);
1378        }
1379
1380        $fileinfo.append($preview);
1381        $fileinfo.append($meta);
1382        $row.append($fileinfo);
1383        $row.append($buttons);
1384
1385        if (file.error) {
1386            $error = $('<div/>').attr('data-mwf-file-error', '').attr('class', 'mwf-upload-error');
1387            $span = $('<span>').text(file.error);
1388            $error.append($span);
1389            $row.append($error);
1390        }
1391
1392        return $row;
1393    };
1394
1395    globalSettings.def.updateCalculatedValue = function($form, id, value) {
1396        $form.find('[data-mwf-value="' + id + '"]').text(value).html();
1397    };
1398
1399    globalSettings.def.onAjaxError = function(jqXHR, status, error) {
1400        $.logError(jqXHR.responseText);
1401    };
1402
1403    globalSettings.def.onSubmit = function($form, url, query) {
1404        return true;
1405    };
1406
1407    globalSettings.def.onConditionCreated = function($form, conditionId, conjunction, conditions, fields) {
1408        // do nothing
1409    };
1410
1411    globalSettings.def.onFillDropdown = function($form, $elem) {
1412        // do nothing
1413    };
1414
1415    globalSettings.def.onFillSelection = function($form, $elem) {
1416        // do nothing
1417    };
1418
1419    globalSettings.def.onInit = function($form) {
1420        // do nothing
1421    };
1422
1423
1424    /* plugin related jQuery functions
1425     ---------------------------------------------------------------------------------------------------------------  */
1426
1427    $.fn.webforms = function(opt) {
1428        var dataKey = 'webforms', $this = $(this), s;
1429
1430        s = {
1431            id: $this.data('mwf-id'),
1432            type: 'GET',
1433            appendUrlVars: false
1434        };
1435
1436        $.extend(true, s, globalSettingsWithVariant(opt.variant), opt);
1437
1438        if ($this.is('form') || $this.find('form').length > 0) {
1439            return $this.each(function() {
1440                var instance = $this.data(dataKey);
1441
1442                if (instance && instance.dispose) {
1443                    instance.dispose();
1444                }
1445
1446                instance = new Webforms($this, s);
1447                $this.data(dataKey, instance);
1448            });
1449        } else {
1450            s.selector = $this;
1451            $.mwfAjaxReplace(s);
1452        }
1453    };
1454
1455    $.fn.webforms.settings = function(variant) {
1456        if (variant === undefined) {
1457            return globalSettings.def;
1458        } else {
1459            if (globalSettings[variant] === undefined) {
1460                globalSettings[variant] = {};
1461            }
1462            return globalSettings[variant];
1463        }
1464    };
1465
1466    /* deprecated: Use $.fn.webforms.settings instead. */
1467    $.fn.webforms.defaults = $.fn.webforms.settings;
1468
1469    /* general jQuery utility functions
1470     ---------------------------------------------------------------------------------------------------------------  */
1471
1472    $.fn.replaceWithPush = function(elem) {
1473        var $elem = $(elem);
1474        this.replaceWith($elem);
1475        return $elem;
1476    };
1477
1478    $.fn.dataWithDefault = function(key, def) {
1479        var value = this.data(key);
1480        return (value !== undefined) ? value : def;
1481    };
1482
1483    if (typeof $.fn.serializeObject === 'undefined') {
1484        $.fn.serializeObject = function() {
1485            var o = {}, a = this.serializeArray();
1486            $.each(a, function() {
1487                if (o[this.name] !== undefined) {
1488                    if (!o[this.name].push) {
1489                        o[this.name] = [o[this.name]];
1490                    }
1491                    o[this.name].push(this.value || '');
1492                } else {
1493                    o[this.name] = this.value || '';
1494                }
1495            });
1496            return o;
1497        };
1498    }
1499
1500    if (typeof $.logError === 'undefined') {
1501        $.extend({
1502            logError: function(msg) {
1503                try {
1504                    if (msg !== undefined && typeof window.console !== 'undefined') {
1505                        console.error(msg);
1506                    }
1507                } catch (ex) {
1508                }
1509            }
1510        });
1511    }
1512
1513    $.extend({
1514        mwfAjaxReplace: function(opt) {
1515            var $dest = $(opt.selector), optinId, s, performAjaxRequest,
1516                data = {_parentUrl: window.location.href, _timezone: $.timezone()};
1517
1518            if ($dest.length > 0) {
1519                optinId = $.getOptinIdFromHash(opt.uid);
1520
1521                if (optinId !== null) {
1522                    data._optinId = optinId;
1523
1524                    if (typeof history.replaceState !== 'undefined') {
1525                        history.replaceState({}, document.title, window.location.pathname);
1526                    } else {
1527                        window.location.hash = '';
1528                    }
1529
1530                    $('html, body').animate({
1531                        scrollTop: $dest.offset().top
1532                    });
1533                }
1534
1535                s = {
1536                    url: null,
1537                    type: 'POST',
1538                    appendUrlVars: false
1539                };
1540
1541                // Create the final settings object
1542                $.extend(s, opt);
1543
1544                if (s.appendUrlVars) {
1545                    $.extend(data, $.getUrlVars(window.location.search));
1546                }
1547
1548                $.extend(data, $.getUrlVars(s.query), opt.data);
1549
1550                performAjaxRequest = function() {
1551                    return $.ajax({
1552                        url: s.url,
1553                        type: s.type,
1554                        data: data,
1555                        traditional: true,
1556                        cache: false,
1557                        xhrFields: {
1558                            withCredentials: true
1559                        }
1560                    })
1561                        .done(function(innerData, textStatus, jqXHR) {
1562                            if (jqXHR && jqXHR.getResponseHeader("X-Redirect-Location")) {
1563                                location.assign(jqXHR.getResponseHeader("X-Redirect-Location"));
1564                                return;
1565                            }
1566
1567                            $dest = $dest.replaceWithPush(innerData);
1568                            if (s.onSuccess !== undefined) {
1569                                s.onSuccess(innerData, textStatus, jqXHR);
1570                            }
1571                            triggerEvent(document, EVENTS.AJAX_FINISHED, {detail: {$dest: $dest}});
1572                        })
1573                        .fail(function(jqXHR, textStatus, errorThrown) {
1574                            if (s.onError !== undefined) {
1575                                s.onError(jqXHR, textStatus, errorThrown);
1576                            } else {
1577                                $.logError(jqXHR.responseText);
1578                            }
1579
1580                            triggerEvent(document, EVENTS.AJAX_ERROR, {
1581                                detail: {
1582                                    $dest: $dest,
1583                                    jqXHR: jqXHR,
1584                                    textStatus: textStatus,
1585                                    errorThrown: errorThrown
1586                                }
1587                            });
1588                        })
1589                };
1590
1591                if (initialXhrRequest === undefined) {
1592                    // The first request may be performed instantaneously
1593                    initialXhrRequest = performAjaxRequest();
1594                } else {
1595                    // Following requests have to wait for the termination of the first request.
1596                    // This prevents the creation of multiple sessions on pages with more than one form.
1597                    $.when(initialXhrRequest).always(performAjaxRequest);
1598                }
1599            }
1600        },
1601
1602        getUrlVars: function(url) {
1603            var params = {}, i, param, pos, key, value, length;
1604
1605            if (typeof url === "string" && url.length > 0) {
1606                if (url[0] === '?') {
1607                    url = url.substring(1);
1608                }
1609
1610                url = url.split('&');
1611
1612                for (i = 0, length = url.length; i < length; i++) {
1613                    if (!url[i] || 0 === url[i].length) {
1614                        continue;
1615                    }
1616
1617                    param = url[i];
1618                    pos = param.indexOf('=');
1619
1620                    if (pos >= 0) {
1621                        key = param.substr(0, pos);
1622                        value = param.substr(pos + 1);
1623                    } else {
1624                        key = param;
1625                        value = '';
1626                    }
1627
1628                    value = decodeURIComponent(value);
1629
1630                    if (params[key] === undefined) {
1631                        params[key] = value;
1632                    } else if (params[key] instanceof Array) {
1633                        params[key].push(value);
1634                    } else {
1635                        params[key] = [params[key], value];
1636                    }
1637                }
1638            }
1639
1640            return params;
1641        },
1642
1643        getUrlVar: function(url, name) {
1644            return $.getUrlVars(url)[name];
1645        },
1646
1647        getOptinIdFromHash: function(id) {
1648            // legacy hash = mwf:uuid
1649            // new hash = mwf:formId:uuid
1650            var hash = location.hash.replace('#', ''),
1651                idx = hash.indexOf("mwf:");
1652
1653            if (idx !== -1) {
1654                var elements = hash.split(":");
1655                if (elements.length === 2 || elements[1] === String(id)) {
1656                    return hash.substring(idx + 4, hash.length);
1657                }
1658            }
1659            return null;
1660        },
1661
1662        formatSize: function(bytes) {
1663            if (typeof bytes !== 'number') {
1664                return '';
1665            }
1666            if (bytes >= 1000000000) {
1667                return (bytes / 1000000000).toFixed(2) + ' GB';
1668            }
1669            if (bytes >= 1000000) {
1670                return (bytes / 1000000).toFixed(2) + ' MB';
1671            }
1672            return (bytes / 1000).toFixed(2) + ' KB';
1673        },
1674
1675        timezone: function() {
1676            try {
1677                return Intl.DateTimeFormat().resolvedOptions().timeZone;
1678            } catch (ex) {
1679                return "UTC";
1680            }
1681        }
1682    });
1683
1684}));

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.