PageSourceSearch

https://universus.club/nassets/b9c49911/js/main.js?v=1791191309

js universus.club collected 2026-10-06 06:54:55 UTC 37,235 bytes, 1,235 lines download raw bytes

1var ajaxCallAutoCsrfRoutes = [
2	'/teach/control/stream/saveChanges',
3	'/teach/control/stream',
4];
5
6function ajaxCall(url, data, options, successCallback, completeCallback, errorCallback) {
7    if ( ! options ) {
8        options = {};
9    }
10    if (options.useQueue) {
11        ajaxCallQueue.request(url, data, options, successCallback, completeCallback);
12        return;
13    }
14
15    var suppressErrors = undefined === options.suppressErrors ? false :options.suppressErrors;
16	var enableSimpleSign = undefined === options.enableSimpleSign ? false :options.enableSimpleSign;
17	const suppressNotify = options.suppressNotify || false;
18
19    if ( options.btn ) {
20        options.btn.attr( 'disabled', 'disabled' );
21    }
22    var method = "post";
23    if ( options.method ) {
24        method = options.method;
25    }
26
27	var enableCsrf = options.enableCsrf === undefined ? false : options.enableCsrf;
28	if (typeof options.enableCsrf === 'undefined' && String(method).toLowerCase() !== 'get') {
29		var csrfPath = String(url).split('#')[0].split('?')[0];
30		var csrfOriginMatch = csrfPath.match(/^https?:\/\/[^\/]+(\/.*)$/);
31		if (csrfOriginMatch) {
32			csrfPath = csrfOriginMatch[1];
33		}
34		for (var csrfRouteIndex = 0; csrfRouteIndex < ajaxCallAutoCsrfRoutes.length; csrfRouteIndex++) {
35			var csrfRoute = ajaxCallAutoCsrfRoutes[csrfRouteIndex];
36			if (csrfPath === csrfRoute || csrfPath.indexOf(csrfRoute + '/') === 0) {
37				enableCsrf = true;
38				break;
39			}
40		}
41	}
42
43    if (enableCsrf && window.csrfToken !== undefined) {
44		if (typeof data === 'object') {
45			data['_csrf'] = window.csrfToken;
46		}
47		else if (typeof data === 'string') {
48			data += '&_csrf='+window.csrfToken;
49        }
50    }
51	if (enableSimpleSign && window.requestTime !== undefined && window.requestSimpleSign !== undefined) {
52		if (typeof data === 'object') {
53			data['requestTime'] = window.requestTime;
54			data['requestSimpleSign'] = window.requestSimpleSign;
55		}
56		else if (typeof data === 'string') {
57			data += '&requestTime='+window.requestTime;
58			data += '&requestSimpleSign='+window.requestSimpleSign;
59		}
60	}
61	if ( typeof(Storage) !== 'undefined' ) {
62		try {
63			var session = localStorage.getItem('session');
64			var visit = localStorage.getItem('visit');
65			var visitor = localStorage.getItem('visitor');
66			var hash = localStorage.getItem('hash');
67			if (session && hash) {
68				if (typeof data === 'object') {
69					data['gcSession'] = session;
70					data['gcVisit'] = visit;
71					data['gcVisitor'] = visitor;
72					data['gcSessionHash'] = hash;
73				} else if (typeof data === 'string') {
74					data += '&gcSession=' + session;
75					data += '&gcVisit=' + visit;
76					data += '&gcVisitor=' + visitor;
77					data += '&gcSessionHash=' + hash;
78				}
79			}
80		} catch (e) {
81			// В режиме блокирования кук (как минимум хром) бросает ошибку при доступе к
82			// localStorage, хотя объект определен
83		}
84	}
85
86    var async = true;
87    if (options.async === false) {
88        async = false;
89    }
90
91    var params = {
92        url: url,
93        type: method,
94        data: data,
95        async: async,
96        complete: function ( jqResponse, status ) {
97
98            error_text_value = 'Ошибка';
99            if (typeof Yii != 'undefined') {
100                error_text_value = Yii.t( "common", "Error" );
101            }
102
103            if ( options.btn ) {
104                options.btn.removeAttr( 'disabled' );
105            }
106
107            try {
108                response = $.parseJSON(jqResponse.responseText);
109            } catch (exception) {
110                response = jqResponse;
111                response.success = false;
112                response.message = "Неизвестная ошибка";
113            }
114
115			if (status === 'success') {
116                if ( response.success ) {
117					if (!suppressNotify && response.message && response.message.length > 0) {
118                        var message = response.message;
119                        var messageOptions = { type: "success" };
120                        if (window.isPageRedesigned) {
121                            showRedesignAlert('success', message)
122                        } else {
123                            if ( $.toast ) {
124                                $.toast.config.width = Math.min(500, $(window).width() * 0.95);
125                                $.toast(message, messageOptions);
126                            }
127                            else {
128                                console.log(message);
129                            }
130                        }
131                    }
132                    if ( successCallback ) {
133                        successCallback( response );
134                    }
135                }
136                else {
137                    if ( !suppressErrors ) {
138                        if (window.isPageRedesigned && typeof showRedesignAlert === 'function') {
139                            showRedesignAlert('danger', response.message)
140                        } else {
141                            if ( $.toast ) {
142                                $.toast.config.width = Math.min(500, $(window).width() * 0.95);
143                                if (response.only_last_error) {
144                                    $('.toast .danger').remove();
145                                }
146                                $.toast(error_text_value + ": " + response.message, {
147                                    type: "danger",
148                                    sticky: response.toast_sticky === true,
149                                });
150                            } else {
151                                alert(response.message);
152                            }
153                        }
154
155                    }
156                    if (errorCallback) {
157                        errorCallback(response);
158                    }
159                }
160            }
161            else {
162                if ( jqResponse.readyState == 0 ) {
163                    return;
164                }
165                if ( !suppressErrors ) {
166                    if ($.toast) {
167                        $.toast.config.width = Math.min(500, $(window).width() * 0.95);
168                        $.toast(  error_text_value + ": " + jqResponse.statusText, {type: "danger"});
169                    } else {
170						alert(response.message);
171                    }
172                }
173				console.error('error', jqResponse.statusText);
174				console.error(jqResponse.responseText);
175                if (errorCallback) {
176                    errorCallback(response);
177                }
178            }
179            if (completeCallback) {
180                completeCallback(response);
181            }
182        }
183    };
184
185    if (options.crossDomain) {
186        params.crossDomain = true;
187    }
188
189    $.ajax(params);
190}
191
192var ajaxCallQueue = new (function () {
193    /** @private */
194    let self = this;
195
196    this.limit = 4;
197    /** @private */
198    this.active = 0;
199    /** @private */
200    this.queue = [];
201
202    this.request = function (url, data, options, successCallback, completeCallback) {
203        this.queue.push({
204            url: url,
205            data: data,
206            options: options,
207            successCallback: successCallback,
208            completeCallback: completeCallback
209        });
210        this.processQueue();
211    }
212
213    /**
214     * @private
215     */
216    this.processQueue = function () {
217        if (this.queue.length === 0) {
218            return;
219        }
220
221        if (this.active >= this.limit) {
222            return;
223        }
224
225        this.active++;
226        let request = this.queue.shift();
227        request.options.useQueue = false;
228
229        ajaxCall(
230            request.url,
231            request.data,
232            request.options,
233            function (response) {
234                try {
235                    request.successCallback(response);
236                } catch ($e) {
237                    console.error($e);
238                }
239            },
240            function () {
241                if (request.completeCallback) {
242                    try {
243                        request.completeCallback();
244                    } catch ($e) {
245                        console.error($e);
246                    }
247                }
248                self.active--;
249                self.processQueue();
250            },
251        );
252    }
253})();
254
255function bodyScrollTo( $el, padding ) {
256    if (  padding  == null ) {
257        padding = 400;
258    }
259    $( "body,html" ).animate({
260        scrollTop: Math.round( $el.offset().top ) - padding
261    }, 200 );
262}
263
264
265
266function initUploadify( $fileElem, options ) {
267
268    var defaultButtonText = Yii.t('common', 'Добавить файлы');
269    if ( $fileElem.attr( 'title') ) {
270        defaultButtonText = $fileElem.attr( 'title');
271    }
272    var url = options.url ? options.url : (
273        '/fileservice/widget/upload?deprecated=17'
274            + '&secure=' + window.isEnabledSecureUpload
275            + '&host=' + window.fileserviceUploadHost
276    );
277    var finalOptions = {
278        auto: true,
279        buttonText: options.buttonText ? options.buttonText : defaultButtonText,
280        width: options.width ? options.width : 200,
281        itemTemplate: options.itemTemplate ? options.itemTemplate : false,
282        fileSizeLimit: options.fileSizeLimit ? options.fileSizeLimit : '2GB',
283        formData: {
284            userId: options.userId
285        },
286        uploadScript: url,
287        onUploadError: function (file, errorCode, errorMsg) {
288            alert("ERROR");
289        },
290        onUploadComplete: options.onUploadComplete ? options.onUploadComplete : function (e, res) {
291            $hiddenInputEl = $(options.valueElemSelector);
292            oldVal = $hiddenInputEl.val();
293            newVal = oldVal;
294            if (newVal && newVal.length > 0) {
295                newVal += ",";
296            }
297            newVal += res;
298
299            $hiddenInputEl.val(newVal);
300            //location.href = location.href;
301        },
302        multi: options.hasOwnProperty('multi') ? options.multi : true
303    };
304    if (options.onQueueComplete) {
305        finalOptions.onQueueComplete = options.onQueueComplete;
306    }
307    if (options.onUpload) {
308        finalOptions.onUpload = options.onUpload;
309    } else if (window.isEnabledSecureUpload && window.fileserviceUploadHost) {
310        finalOptions.onUpload = getUploadifySecretLink;
311    }
312
313    if (options.other) {
314        $.each(options.other, function(key, callback) {
315            finalOptions[key] = callback;
316        });
317    }
318    $fileElem.uploadifive(finalOptions);
319
320    if ( options.fileSizeLimit ) {
321        var fileSizeLimitWarning = options.fileSizeLimitWarning ? options.fileSizeLimitWarning : Yii.t('common', 'Макс. размер 2 ГБ');
322        var warning = $("<p class='text-muted'>" + fileSizeLimitWarning + "</p>");
323        $fileElem.parent().after(warning);
324    }
325}
326
327window.errCount = 0;
328
329function sendError(message) {
330    window.errCount++;
331    if (window.errCount <= 10) {
332        $.ajax({
333            url: '/pl/gc/log',
334            method: 'POST',
335            data: {data:  message}
336        });
337    }
338}
339
340function sendCreateLinkError(http, message, exc) {
341    var postMessage = '';
342    var toastMessage = '';
343    if (http.responseJSON) {
344        postMessage += (http.responseJSON ? ('json: ' + JSON.stringify(http.responseJSON)) : '');
345    }
346
347    toastMessage += 'status: ' + http.status + '; ';
348    toastMessage += (http.statusText ? ('statusText: ' +  http.statusText + '; ') : '');
349    postMessage += toastMessage;
350
351    postMessage += (message ? ('message: ' + message + ' /// ') : '');
352
353    postMessage += (exc ? ('exc: ' + exc + ' /// ') : '');
354
355    if ($.isFunction($.fn.toast)) {
356        $.toast(toastMessage, {type: "danger"});
357    }
358    console.log(postMessage);
359    sendError(postMessage);
360}
361
362function getUploadifySecretLink(filesToUpload, settings) {
363    var secureDirectUploadUri = '/fileservice/widget/secure-direct-upload';
364    try {
365        var session = localStorage.getItem('session');
366        var requestParams = {"fs_ref": window.location.href};
367
368        if (session !== undefined && session != null){
369            var objSession = jQuery.parseJSON(session);
370
371            if (objSession.hasOwnProperty('user_id') && objSession.user_id != null) {
372                requestParams.fs_u = objSession.user_id;
373            } else {
374                requestParams.fs_u = -1;
375            }
376        }
377
378        secureDirectUploadUri += '?' + jQuery.param(requestParams);
379    } catch (err) {
380    }
381
382    if (typeof settings !== 'undefined' && settings !== null) {
383        delete settings.uploadScript;
384    }
385
386    $.ajax({
387        url: '/fileservice/widget/create-secret-link',
388        method: 'GET',
389        data: {
390            host: window.fileserviceUploadHost,
391            uri: secureDirectUploadUri,
392            expires: 600
393        },
394        success: function (data) {
395            if (data.link) {
396                if (typeof settings !== 'undefined' && settings !== null) {
397                    settings.uploadScript = data.link;
398                }
399            } else {
400                ajaxCall('/fileservice/widget/log-error', {m:  'No link'}, {});
401            }
402        },
403        error: function (http, message, exc) {
404            sendCreateLinkError(http, message, exc);
405        },
406        async: false
407    });
408}
409
410function panelPutTaskAside( task_id ) {
411    $('.aside-loading').css('opacity', 1);
412    $('.aside-link').css('opacity', 0).css('cursor', 'default');
413    $.ajax({
414        url: '/tasks/control/task/setNew',
415        method: 'post',
416        data: {'id': task_id },
417        success: function(data) {
418            panelLoad();
419        }
420    });
421}
422function panelFinishTask( task_id, result ) {
423    $('.aside-loading').css('opacity', 1);
424    $.ajax({
425        url: '/tasks/control/task/setCompleted',
426        method: 'post',
427        data: {'id': task_id, result: result },
428        success: function(data) {
429            panelLoad();
430        }
431    });
432
433    return false;
434}
435
436function panelLoad() {
437    $.ajax({
438        url: '/tasks/control/task/getPanel',
439    success: function(data) {
440        $('#task-panel-placeholder').html( data );
441        }
442    });
443}
444
445function setElLoading( el ) {
446    $(el).html('<div class="text-center padding-10"><img src="/public/img/loading.gif"></div>');
447}
448
449
450$( function() {
451    $('.editable .edit-link').click( function() {
452        $(this).parents('.editable').toggleClass('edit');
453        $(this).parents('.editable').find( 'input').focus();
454    });
455})
456
457$( function() {
458	$( '.action-link').click( function() {
459		if ( $(this).data('gc-confirm' ) ) {
460			if ( ! confirm( $(this).data('gc-confirm' ) ) ) {
461				return false;
462			}
463		}
464		$( '.page-main-form' ).find( 'input[name=action]').val( $(this).data('action' ) );
465		$( '.page-main-form' ).submit();
466	});
467})
468
469
470function extend(Child, Parent) {
471    var F = function() { }
472    F.prototype = Parent.prototype
473    Child.prototype = new F()
474    Child.prototype.constructor = Child
475    Child.superclass = Parent.prototype
476}
477
478function mixin(cls, mixin) {
479	for (var key in mixin) {
480		if (cls.prototype[key]) {
481			// console.log("Class " + cls + " already has a method named " + key + "!");
482		}
483		else {
484			cls.prototype[key] = mixin[key];
485		}
486	}
487}
488
489
490$( function() {
491	if ( $('.date-input').datetimepicker ) {
492		$('.date-input').datetimepicker({
493			timepicker: false, closeOnDateSelect: true, format:'d.m.Y',
494			step: 20, lang:'ru', dayOfWeekStart: 1, todayButton: false, validateOnBlur: true, allowBlank: true, yearStart: '2013', yearEnd: '2020', lazyInit: false
495		});
496
497		$('.date-time-input').datetimepicker({
498			timepicker: true, closeOnDateSelect: false, format:'d.m.Y H:i',
499			step: 20, lang:'ru', dayOfWeekStart: 1, todayButton: false, validateOnBlur: true, allowBlank: true, yearStart: '2013', yearEnd: '2020', lazyInit: false
500		});
501	}
502});
503
504
505$.fn.scrollTo = function( target, options, callback ){
506    if(typeof options == 'function' && arguments.length == 2){ callback = options; options = target; }
507    var settings = $.extend({
508        scrollTarget  : target,
509        offsetTop     : 50,
510        duration      : 500,
511        easing        : 'swing'
512    }, options);
513    return this.each(function(){
514        var scrollPane = $(this);
515        var scrollTarget = (typeof settings.scrollTarget == "number") ? settings.scrollTarget : $(settings.scrollTarget);
516        var scrollY = (typeof scrollTarget == "number") ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop);
517        scrollPane.animate({scrollTop : scrollY }, parseInt(settings.duration), settings.easing, function(){
518            if (typeof callback == 'function') { callback.call(this); }
519        });
520    });
521};
522
523function getThumbnailUrl( hash, width, height ) {
524    var result = "/fileservice/file/thumbnail/h/" +  hash + "/s/" + width + "x" + height;
525    if (window.accountId) {
526        result += '/a/'+window.accountId;
527    }
528    if ( window.fileserviceThumbnailHost ) {
529        result = "//" + window.fileserviceThumbnailHost + result;
530    }
531    return result;
532}
533function getBorderedThumbnailUrl( hash, width, height, borderName) {
534
535    if ( borderName == "" ) {
536        return getThumbnailUrl(hash, width, height);
537    }
538
539    var result = "/fileservice/file/bordered/h/" +  hash + "/s/" + width + "x" + height + "/b/" + borderName;
540    if (window.accountId) {
541        result += '/a/'+window.accountId;
542    }
543    if ( window.fileserviceThumbnailHost ) {
544        result = "//" + window.fileserviceThumbnailHost + result;
545    }
546    return result;
547}
548function getDownloadUrl( hash ) {
549	var result = "/pl/fileservice/user/file/download?h=" + hash;
550
551    return result;
552}
553
554function isImage(hash) {
555    let hashParts = hash.split(".");
556	if (hashParts.length === 2) {
557		let imgExts = ['jpeg', 'jpg', 'gif', 'png', 'heic'];
558		return imgExts.includes(hashParts[1]);
559	} else {
560		return false;
561	}
562}
563
564function isVideo(hash) {
565    var hashParts = hash.toLowerCase().split(".");
566    if (hashParts.length === 2) {
567        var imgExts = ['mp4', 'mov'];
568        return imgExts.includes(hashParts[1]);
569    } else {
570        return false;
571    }
572}
573
574/**
575 * Когда нужно обновить картинку в обход кэша браузера
576 */
577function updateThumbnailVersion(hash, version) {
578    if (!window.thumbnailVersions) {
579        window.thumbnailVersions = {};
580    }
581    window.thumbnailVersions[hash] = version;
582}
583
584function getVideoThumbnailUrl( hash, width, height ) {
585    var url = "/pl/fileservice/video/preview-redirect/?file-hash=" + hash;
586    if (window.thumbnailVersions && hash in window.thumbnailVersions) {
587        url += '&v=' + window.thumbnailVersions[hash];
588    }
589    return url;
590}
591
592function gcGetFileObj( row ) {
593    var title = row.title;
594    if ( ! title ) title = row.filename;
595    if ( ! title ) title = row.hash;
596
597    var result = {
598        hash: row.hash,
599        title: title,
600        description: row.description,
601        getThumbnailUrl: function( width, height ) {
602            return "/fileservice/file/thumbnail/h/" + this.hash + "/s/" + width + "x" + height;
603        },
604        getDownloadUrl: function() {
605            return "/pl/fileservice/user/file/download?h=" + this.hash;
606        }
607    };
608    return result;
609}
610
611var getProp = function(o, name, defaultValue) {
612    return undefined === o[name] ? defaultValue : o[name];
613};
614
615$(function () {
616    if ($('#blueimp-gallery').length == 0) {
617        var $el = $('<div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls"><div class="slides next-click"></div><h3 class="title"></h3><a class="prev">‹</a><a class="next next-click">›</a><a class="play-pause"></a><ol class="indicator"></ol></div>')
618        $el.hide();
619        $el.appendTo($(document.body));
620    }
621});
622
623$(function () {
624    function handleAction(href, target) {
625        var accountDomains = window.accountDomains || [];
626        var pathsToWrap = window.pathsToWrap || [];
627        var authingUrl = window.authingUrl || '';
628        var openInExternalApp = target === '_blank';
629        var mainDomain = window.mainDomain || '';
630        if (!href.startsWith('https://') && !href.startsWith('http://')) {
631            const locationHref = new URL(location.href);
632            href = locationHref.origin + href;
633            openInExternalApp = false;
634        }
635        if (accountDomains.includes((new URL(href)).host)) {
636            openInExternalApp = false;
637        }
638
639        var url = new URL(href);
640        for (var path of pathsToWrap) {
641            if (url.pathname.startsWith(path)) {
642                openInExternalApp = true;
643                href = authingUrl !== '' && mainDomain === url.host
644                    ? authingUrl + '&redirectUrl=' + encodeURIComponent(url.href)
645                    : url.href;
646                break;
647            }
648        }
649
650        window.appHandleAction({
651            type: "navigate",
652            url: href,
653            openInExternalApp: openInExternalApp
654        });
655    }
656    $(".lt-block-wrapper a:visible, .xdget-block.xdget-html a:visible, .xdget-block.xdget-lessonContent a:visible, .lite-page a:visible")
657        .on('click', function (event) {
658            const elem = event.currentTarget;
659
660            if (
661                !elem ||
662                !elem.href
663            ) {
664                return;
665            }
666
667            if (
668                elem &&
669                elem.href &&
670                typeof elem.href === 'string' &&
671                elem.href.indexOf('#') >= 0
672            ) {
673                const cleanThisHref = document.location.href.replace(/\#.*$/, '');
674                const cleanAnchorHref = elem.href.replace(/\#.*$/, '');
675                if (cleanThisHref === cleanAnchorHref) {
676                    return;
677                }
678            }
679
680            if (!elem.href.startsWith('#') && !elem.href.startsWith('javascript:') && window.appHandleAction) {
681                event.preventDefault();
682                handleAction(elem.href, elem.target);
683                return false;
684            }
685        });
686});
687
688$( function() {
689    $('.editable-link').each( function( index, el ) {
690        $el = $(el)
691        $wrapper = $el.parents('.editable-link-wrapper')
692
693        if ( $wrapper.length == 0 ) {
694            $wrapper = $('<span class="editable-link-wrapper"/>')
695            $el.replaceWith( $wrapper )
696            $el.appendTo( $wrapper )
697        }
698
699        $link = $('<a class="link"/>')
700        if ( $el.data('header')) {
701            $header = $('<h1/>')
702            $link.appendTo( $header )
703            $header.appendTo( $wrapper )
704        }
705        else {
706            $link.appendTo( $wrapper )
707        }
708
709        var value = null;
710
711        if ( $el.val() != "" ) {
712            value = $el.val();
713        } else if ( $el.attr("placeholder") && $el.attr("placeholder") != "" ) {
714            if(!window.isPageRedesigned) {
715                value = $el.attr("placeholder");
716            } else {
717                value = Yii.t( "common", "change" );
718                $link.addClass('rd-fake-link rd-first-letter-up');
719            }
720        } else {
721            value = 'изменить';
722
723            if (typeof Yii != 'undefined') {
724                value = Yii.t( "common", "change" );
725            }
726            $wrapper.addClass( 'no-value' );
727            if(window.isPageRedesigned) {
728                $link.addClass('rd-fake-link rd-first-letter-up');
729            }
730        }
731
732        if (window.isPageRedesigned && typeof Yii != 'undefined') {
733            if (value === 'male') {
734                value = Yii.t("user", "Male");
735            }
736            if (value === 'female') {
737                value = Yii.t("user", "Female");
738            }
739        }
740
741        $link.html(value);
742
743        $link.click( function() {
744            $(this).parents('.editable-link-wrapper').addClass('edit-mode')
745        })
746
747    })
748})
749
750window.runOneTimeOnElement = function($el, key, callback) {
751    if ($el.data(key)) {
752        return;
753    }
754    $el.data(key, callback($el));
755};
756window.eachAndRunOneTimeOnElement = function($each, key, callback) {
757    $each.each(function(index, el) {
758        runOneTimeOnElement($(el), key, callback);
759    });
760}
761
762function objectToQueryString (a) {
763    var prefix, s, add, name, r20, output;
764    s = [];
765    r20 = /%20/g;
766    add = function (key, value) {
767        // If value is a function, invoke it and return its value
768        value = ( typeof value == 'function' ) ? value() : ( value == null ? "" : value );
769        s[ s.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value);
770    };
771    if (a instanceof Array) {
772        for (name in a) {
773            add(name, a[name]);
774        }
775    } else {
776        for (prefix in a) {
777            buildParams(prefix, a[ prefix ], add);
778        }
779    }
780    output = s.join("&").replace(r20, "+");
781    return output;
782};
783function buildParams(prefix, obj, add) {
784    var name, i, l, rbracket;
785    rbracket = /\[\]$/;
786    if (obj instanceof Array) {
787        for (i = 0, l = obj.length; i < l; i++) {
788            if (rbracket.test(prefix)) {
789                add(prefix, obj[i]);
790            } else {
791                buildParams(prefix + "[" + ( typeof obj[i] === "object" ? i : "" ) + "]", obj[i], add);
792            }
793        }
794    } else if (typeof obj == "object") {
795        // Serialize object item.
796        for (name in obj) {
797            buildParams(prefix + "[" + name + "]", obj[ name ], add);
798        }
799    } else {
800        // Serialize scalar item.
801        add(prefix, obj);
802    }
803}
804
805$.fn.serializeObject = function()
806{
807    var o = {};
808    var a = this.serializeArray();
809    $.each(a, function() {
810        if (o[this.name] !== undefined) {
811            if (!o[this.name].push) {
812                o[this.name] = [o[this.name]];
813            }
814            o[this.name].push(this.value || '');
815        } else {
816            o[this.name] = this.value || '';
817        }
818    });
819    return o;
820};
821
822window.gcIsHiddenTab = function(){
823    var hidden, state;
824
825    if (typeof document.hidden !== "undefined") {
826        state = "visibilityState";
827    } else if (typeof document.mozHidden !== "undefined") {
828        state = "mozVisibilityState";
829    } else if (typeof document.msHidden !== "undefined") {
830        state = "msVisibilityState";
831    } else if (typeof document.webkitHidden !== "undefined") {
832        state = "webkitVisibilityState";
833    }
834
835    return document[state] == "hidden";
836};
837window.gcIsActiveTab = !window.gcIsHiddenTab();
838$(window).focus(function() {
839    window.gcIsActiveTab = true;
840});
841
842$(window).blur(function() {
843    window.gcIsActiveTab = false;
844});
845
846window.gcGetCookie = function(name) {
847    var matches = document.cookie.match(new RegExp(
848        "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
849    ));
850    return matches ? decodeURIComponent(matches[1]) : undefined;
851};
852
853window.gcSetCookie = function gcSetCookie(name, value, options) {
854    options = options || {};
855
856    var expires = options.expires;
857
858    if (typeof expires == "number" && expires) {
859        var d = new Date();
860        d.setTime(d.getTime() + expires * 1000);
861        expires = options.expires = d;
862    }
863    if (expires && expires.toUTCString) {
864        options.expires = expires.toUTCString();
865    }
866
867    value = encodeURIComponent(value);
868
869    var updatedCookie = name + "=" + value;
870
871    for (var propName in options) {
872        updatedCookie += "; " + propName;
873        var propValue = options[propName];
874        if (propValue !== true) {
875            updatedCookie += "=" + propValue;
876        }
877    }
878
879    document.cookie = updatedCookie;
880};
881
882
883function addParamToLocation( key, value)
884{
885    key = encodeURI(key); value = encodeURI(value);
886
887    var kvp = document.location.search.substr(1).split('&');
888
889    var i=kvp.length; var x; while(i--)
890    {
891        x = kvp[i].split('=');
892
893        if (x[0]==key)
894        {
895            x[1] = value;
896            kvp[i] = x.join('=');
897            break;
898        }
899    }
900
901    if(i<0) {kvp[kvp.length] = [key,value].join('=');}
902
903    //this will reload the page, it's likely better to store this until finished
904    document.location.search = kvp.join('&');
905}
906
907function removeParamFromLocation( key )
908{
909    key = encodeURI(key);
910
911    var kvp = document.location.search.substr(1).split('&');
912
913    var i=kvp.length; var x; while(i--)
914    {
915        x = kvp[i].split('=');
916
917
918        if (x[0]==key)
919        {
920            kvp[i] = null
921            break;
922        }
923    }
924    var search = kvp.join("&") != "&" ? kvp.join('&') : "";
925//alert(kvp.length > 0 kvp.join('&') : "")
926    //this will reload the page, it's likely better to store this until finished
927    document.location.search = search;
928}
929
930
931function escapeDoubleQuotes(str) {
932	return str.replace(/\\([\s\S])|(")/g,"\\$1$2");
933}
934
935function setVisibilityRelation( checkboxSelector, paramsSelector ) {
936    var $checkboxSelector = $(checkboxSelector)
937    var $paramsSelector = $(paramsSelector)
938    var changed = function() {
939        var checked = $checkboxSelector.prop('checked');
940        if ( checked ) $paramsSelector.show(); else $paramsSelector.hide();
941    }
942    $checkboxSelector.click( changed )
943    changed();
944}
945
946function getParamFromLocation( key )
947{
948    key = encodeURI(key);
949
950    var kvp = document.location.search.substr(1).split('&');
951
952    var i=kvp.length; var x; while(i--)
953    {
954        x = kvp[i].split('=');
955
956
957        if (x[0]==key)
958        {
959            return x[1];
960        }
961    }
962    return null;
963}
964
965function getParamFromHash( key )
966{
967    key = encodeURI(key);
968
969    var kvp = document.location.hash.substr(1).split('&');
970
971    var i=kvp.length; var x; while(i--)
972{
973    x = kvp[i].split('=');
974
975
976    if (x[0]==key)
977    {
978		var res = x[1];
979		return res;
980    }
981}
982    return null;
983}
984
985var gcParseUrl = function(url) {
986    var urlEl = document.createElement('a');
987    urlEl.href = url;
988    return urlEl;
989};
990
991var gcAddResourceElement = function(tag, attr, createElementCallback) {
992    var resources = {};
993
994    return function(resourceUrl) {
995        if (!resources.hasOwnProperty(resourceUrl)) {
996            var list = document.getElementsByTagName(tag);
997            var i = list.length, exists = false;
998            while (i--) {
999                var url = gcParseUrl(list[i][attr]);
1000                if (url.pathname+url.search == resourceUrl) {
1001                    exists = true;
1002                    break;
1003                }
1004            }
1005            if (!exists) {
1006                resources[resourceUrl] = createElementCallback(resourceUrl);
1007                console.log('loaded '+resourceUrl);
1008            }
1009        }
1010    };
1011};
1012
1013var gcAddScriptElement = (function() {
1014    return gcAddResourceElement('script', 'src', function (resourceUrl) {
1015        var script = document.createElement("script");
1016        script.type = "text/javascript";
1017        script.src = resourceUrl;
1018        document.getElementsByTagName('head')[0].appendChild(script);
1019        return script;
1020    });
1021})();
1022
1023var gcAddLinkElement = (function() {
1024    return gcAddResourceElement('link', 'href', function (resourceUrl) {
1025        var link = document.createElement("link");
1026        link.rel = "stylesheet";
1027        link.src = resourceUrl;
1028        document.getElementsByTagName('head')[0].appendChild(link);
1029        return link;
1030    });
1031})();
1032
1033
1034
1035function replaceAll(str, find, replace) {
1036    return str.replace(new RegExp(find, 'g'), replace);
1037}
1038
1039serializeObj = function(obj, prefix) {
1040    var str = [], p;
1041    for(p in obj) {
1042        if (obj.hasOwnProperty(p)) {
1043            var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
1044            if ( typeof v === "undefined" ) {
1045                continue;
1046            }
1047            if ( v == null ) {
1048                continue;
1049            }
1050            str.push((v !== null && typeof v === "object") ?
1051                serializeObj(v, k) :
1052            encodeURIComponent(k) + "=" + encodeURIComponent(v));
1053        }
1054    }
1055    return str.join("&");
1056};
1057
1058function initListSearch( element, selector ) {
1059
1060    var filter = function( value ) {
1061        value = value.toLowerCase();
1062        var found = false;
1063        element.find(selector).each(function () {
1064            var text = $(this).html().toLowerCase();
1065            if (value == "") {
1066                $(this).show();
1067                found = true;
1068            }
1069            else {
1070                if (text.indexOf(value) > -1) {
1071                    $(this).show();
1072                    found = true;
1073                }
1074                else {
1075                    $(this).hide();
1076                }
1077            }
1078
1079        })
1080        return found;
1081    };
1082
1083    var placeholderValue = window.isPageRedesigned ? 'Поиск' : 'поиск';
1084    var notFound = 'ничего не найдено';
1085    if (typeof Yii != 'undefined') {
1086        placeholderValue = window.isPageRedesigned ? Yii.t("common", "Поиск") : Yii.t("common", "search");
1087        notFound = Yii.t("common", "ничего не найдено");
1088    }
1089
1090    var liStyle = window.isPageRedesigned ? 'margin: 0; list-style: none; padding: 8px 12px;' : 'margin: 0; list-style: none; padding: 5px 3px;';
1091
1092    var $searchRuleBlock = $("<li style='" + liStyle + "'><input class='search-input' placeholder='" + placeholderValue + "' type='text'/><div class='nothing-found-label' style='padding-top: 10px; background: lightyellow; display:none'>" + notFound + "</div></li>")
1093    if(window.isPageRedesigned) {
1094        if(element.find('li:not(.hidden):not(:has(input))').length >= 5) {
1095            $searchRuleBlock.prependTo ( element )
1096        }
1097    } else {
1098        $searchRuleBlock.prependTo ( element )
1099    }
1100    var searchRuleInput = $searchRuleBlock.find('input')
1101    searchRuleInput.keyup( function() {
1102        if ( filter( $(this).val() ) ) {
1103            $searchRuleBlock.find('.nothing-found-label').hide()
1104        }
1105        else {
1106            $searchRuleBlock.find('.nothing-found-label').show()
1107        }
1108    });
1109}
1110
1111function initDropdownSearch( $dropdownMenu ) {
1112
1113    $dropdownMenu = $dropdownMenu.find('.dropdown-menu')
1114
1115    initListSearch( $dropdownMenu, 'a' );
1116
1117    $dropdownMenu.parent().on( 'show.bs.dropdown', function() {
1118        setTimeout( function() {
1119            $dropdownMenu.find('.search-input').focus();
1120        })
1121    })
1122
1123
1124
1125
1126}
1127
1128
1129function number_format( number, decimals, dec_point, thousands_sep ) {	// Format a number with grouped thousands
1130    //
1131    // +   original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
1132    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
1133    // +	 bugfix by: Michael White (http://crestidg.com)
1134
1135    var i, j, kw, kd, km;
1136
1137    // input sanitation & defaults
1138    if( isNaN(decimals = Math.abs(decimals)) ){
1139        decimals = 2;
1140    }
1141    if( dec_point == undefined ){
1142        dec_point = ",";
1143    }
1144    if( thousands_sep == undefined ){
1145        thousands_sep = ".";
1146    }
1147
1148    i = parseInt(number = (+number || 0).toFixed(decimals)) + "";
1149
1150    if( (j = i.length) > 3 ){
1151        j = j % 3;
1152    } else{
1153        j = 0;
1154    }
1155
1156    km = (j ? i.substr(0, j) + thousands_sep : "");
1157    kw = i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands_sep);
1158    //kd = (decimals ? dec_point + Math.abs(number - i).toFixed(decimals).slice(2) : "");
1159    kd = (decimals ? dec_point + Math.abs(number - i).toFixed(decimals).replace(/-/, 0).slice(2) : "");
1160
1161
1162    return km + kw + kd;
1163}
1164
1165
1166function onTelegramAuth(user) {
1167    ajaxCall( "/pl/user/profile/login-with-telegram", { user: user }, {method: 'get'}, function( response ) {
1168        if ( window.afterTelegramAuthCallback ) {
1169            window.afterTelegramAuthCallback();
1170        }
1171        //alert( response )
1172    });
1173}
1174
1175window.phoneChecked = false;
1176window.checkFormPhone = function(form) {
1177    var phoneInput = $(form).find('input.phone-input')
1178    if ( phoneInput.length > 0 && ! window.phoneChecked ) {
1179        ajaxCall( "/pl/user/profile/set-phone", { phone: phoneInput.val() }, {}, function( response ) {
1180            if ( response.data.success) {
1181                window.phoneChecked = true;
1182                $(form).submit()
1183            }
1184            else {
1185                alert( response.data.error )
1186            }
1187        } );
1188        return false;
1189    }
1190    else {
1191        return true;
1192    }
1193
1194};
1195window.tt = function(category, text, params) {
1196    return (typeof Yii != 'undefined') ? Yii.t(category,  text, params) : text;
1197};
1198
1199
1200window.renderIcon = function( icon, $parentEl ) {
1201
1202    let $el = $parentEl.find('.chatium-icon');
1203    if ( $el.length == 0 ) {
1204        $el = $('<div class="chatium-icon"/>').appendTo( $parentEl );
1205    }
1206
1207    let url = icon.url;
1208    if ( ! url && icon.image ) {
1209        url = icon.image;
1210    }
1211    if ( icon.hash ) {
1212        url = getThumbnailUrl(icon.hash, 100, 100);
1213    }
1214    if ( url ) {
1215        $el.empty();
1216        $('<img/>').attr( 'src', url ).appendTo( $el );
1217    }
1218    else if ( icon.iconCssClass ) {
1219        $el.html("<div class='chatium-icon-text'><span class='" + icon.iconCssClass + "'></span></div>")
1220        $el.addClass('icon-type-icon' );
1221    }
1222    else {
1223        $el.html( "<div class='chatium-icon-text'>" + ( icon.text ? icon.text : "" ) + "</div>" );
1224        if ( icon.type ) {
1225            $el.addClass('icon-type-' + icon.type );
1226        }
1227
1228    }
1229    if ( icon.color ) {
1230        $el.css('color', icon.color)
1231    }
1232    if ( icon.bgColor && !url) {
1233        $el.css('background-color', icon.bgColor)
1234    }
1235};

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.