PageSourceSearch

https://lk.nasledie.digital/wp-content/plugins/nasledie-billing/public/js/nd-billing-public.js

js nasledie.digital collected 2026-09-30 11:59:09 UTC 24,710 bytes, 865 lines download raw bytes

1(function ($) {
2	'use strict';
3
4	function createOrder(product_id = 0) {
5		return $.ajax({
6			type: "POST",
7			url: '/wp-admin/admin-ajax.php',
8			data: {
9				'action': 'create_order',
10				'product_id': product_id,
11			}
12		});
13	}
14
15	$(document).on('click', '.nd-product button', function () {
16		let item = $(this).closest('.nd-product');
17		let product_id = item.attr('data-product');
18		console.log( product_id );
19		createOrder(product_id)
20			.done(response => {
21				let resp = JSON.parse(response);
22				console.log(resp);
23
24
25				if (!resp.order_created) {
26
27					let redirect_url = document.location.origin + resp.pay_link
28					window.location = redirect_url
29
30				} else {
31					let userBalance = resp.user_balance;
32					let currentBalance = $('.woocommerce-Price-amount');
33
34					$('.woocommerce-Price-amount').html(`<bdi>${userBalance}&nbsp;<span class="woocommerce-Price-currencySymbol">Дин</span></bdi>`)
35
36					$(this).closest('.nd-tarif__footer').html(`<div class="nd-tarif--action">Активен</div>`)
37
38				}
39
40
41			})
42			.fail((jqXHR, exception) => {
43				var msg = '';
44				if (jqXHR.status === 0) {
45					msg = 'Not connect.\n Verify Network.';
46				} else if (jqXHR.status == 404) {
47					msg = 'Requested page not found. [404]';
48				} else if (jqXHR.status == 500) {
49					msg = 'Internal Server Error [500].';
50				} else if (exception === 'parsererror') {
51					msg = 'Requested JSON parse failed.';
52				} else if (exception === 'timeout') {
53					msg = 'Time out error.';
54				} else if (exception === 'abort') {
55					msg = 'Ajax request aborted.';
56				} else {
57					msg = 'Uncaught Error.\n' + jqXHR.responseText;
58				}
59				console.log(msg);
60			})
61	})
62
63
64	$(document).on('click', '.nd-addition__list  :checkbox', function (e) {
65
66		if ($(this).attr('name') == 'quota' && $(this).prop('checked') == true) {
67
68			$(`.addition-checkbox[name="quota"]`).each(function (index, item) {
69				$(item).prop('checked', false)
70			});
71
72			$(this).prop('checked', true)
73		}
74
75		if ($(this).attr('name') == 'quota' && $(this).prop('checked') == false) {
76			$(this).prop('checked', false)
77		}
78
79	})
80
81
82
83	$(document).on('click', '.add_addition_order', function () {
84
85		let choises = $('.nd-addition__list  :checked')
86		let choisesArr = [];
87		choises.each((i, c) => {
88			choisesArr.push($(c).val())
89		})
90		createOrder(choisesArr)
91			.done(res => {
92
93			})
94
95
96
97
98
99
100	})
101
102
103
104	$(document).on('click', '.nd-lk__add-balance', function(e) {
105
106		if ( window.nd_service && window.nd_service.user.anon ) {
107
108			openModalAddBalanceAnonUser()
109			e.preventDefault();
110
111		}
112
113
114
115
116	})
117
118
119
120
121
122
123
124
125
126
127	function fixamount() {
128
129
130
131
132	}
133
134
135
136
137
138
139
140	$(document).ready( function () {
141
142
143		$('.balance-form__fix-amount').on('click', function () {
144			let btn = $(this);
145			let fixDin = btn.attr('data-amount');
146			let rubs = $('.balance_amount_rub');
147			let submit = $('.balance-form__button .nd-button')
148			let input = $('#woo_wallet_balance_to_add');
149
150			if ( btn.hasClass('added') ) {
151				btn.removeClass('added')
152				input.val('')
153				rubs.text('')
154				submit.prop('disabled', true)
155				submit.val( 'Оплатить 0 ₽' )
156				return;
157			}
158
159			$('.balance-form__fix-amount').removeClass('added')
160
161			btn.addClass('added');
162			input.val(fixDin)
163			rubs.text(fixDin + ' ₽')
164
165
166			console.log( $('#balance-form_checbox:checked').val() );
167
168			if ( $('#balance-form_checbox:checked').val() == 'on' ) {
169				submit.prop('disabled', false)
170			}
171			submit.val( 'Оплатить ' + fixDin + ' ₽' )
172
173		})
174
175		$('#woo_wallet_balance_to_add').on('input', function () {
176			let inp = $(this)
177
178
179
180			inp.val( inp.val().replace(/\D/g, '') );
181			let rubs = $('.balance_amount_rub');
182			let submit = $('.balance-form__button .nd-button')
183
184			if ( !inp.val() ) {
185				submit.prop('disabled', true)
186			} else {
187				submit.prop('disabled', false)
188
189			}
190
191			inp.val(inp.val())
192			rubs.text(inp.val() + ' ₽')
193
194			submit.val( 'Оплатить ' + inp.val() + ' ₽' )
195
196		})
197
198
199		$('#balance-form_checbox').on('change', function () {
200			let submit = $('.balance-form__button .nd-button')
201
202			if ( this.checked ) {
203				submit.prop('disabled', false)
204			} else {
205				submit.prop('disabled', true)
206			}
207		})
208
209		console.log( sessionStorage.getItem('lk_capsule_href')  );
210		console.log( getCookie( 'lk_capsule_href' ) );
211	})
212	function getCookie(name) {
213		let matches = document.cookie.match(new RegExp(
214		  "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
215		));
216		return matches ? decodeURIComponent(matches[1]) : undefined;
217	  }
218
219
220
221
222	$(document).on('click', '.nd-lk-user__fio-edit', function () {
223
224		if( $('.nd-lk-user__fio--view').length ) {
225			$('.nd-lk-user__fio').removeClass('nd-lk-user__fio--view')
226			$('.nd-lk-user__fio').addClass('nd-lk-user__fio--edit')
227			$('.nd-lk-user__balance').addClass('nd-lk-user__balance--disabled')
228			$('.nd-lk-capsules__top a').addClass('disabled').prop('disabled', true)
229			$('.nd-lk-user__avatar').addClass('nd-lk-user__avatar--edit')
230		}
231
232	})
233
234
235	$(document).on('click', '.nd-lk-user__fio--cancel', function () {
236
237		if( $('.nd-lk-user__fio--edit').length ) {
238			$('.nd-lk-user__fio').removeClass('nd-lk-user__fio--edit')
239			$('.nd-lk-user__fio').addClass('nd-lk-user__fio--view')
240			$('.nd-lk-user__balance').removeClass('nd-lk-user__balance--disabled')
241			$('.nd-lk-capsules__top a').removeClass('disabled').prop('disabled', false)
242			$('.nd-lk-user__avatar').removeClass('nd-lk-user__avatar--edit')
243
244		}
245
246	})
247	$(document).on('click', '.nd-lk-user__fio--save', function () {
248
249		let fname, lname, mname, image;
250
251		fname = $(`[name="tp-fname"]`)
252		lname = $(`[name="tp-lname"]`)
253		mname = $(`[name="tp-mname"]`)
254
255		if ( $(`[data-cropped="afterCropImage"]`).length ) {
256			image = {
257				base: $(`[data-cropped="afterCropImage"]`).attr('src'),
258				original_file_id: $(`[name="original_file_id"]`).val()
259			}
260		}
261
262		$.ajax({
263			type: "POST",
264			url: '/wp-admin/admin-ajax.php',
265			data: {
266				'action': 'update_fio_user',
267				'fname': fname.val(),
268				'lname': lname.val(),
269				'mname': mname.val(),
270				'image': image
271			},
272			success: function (response) {
273				$('.nd-lk-user__fio').removeClass('nd-lk-user__fio--edit')
274				$('.nd-lk-user__fio').addClass('nd-lk-user__fio--view')
275				$('.nd-lk-user__balance').removeClass('nd-lk-user__balance--disabled')
276				$('.nd-lk-capsules__top a').removeClass('disabled').prop('disabled', false)
277				$('.nd-lk-user__avatar').removeClass('nd-lk-user__avatar--edit')
278
279
280				fname.next().text( fname.val() )
281				lname.next().text( lname.val() )
282				mname.next().text( mname.val() )
283
284
285			}
286		});
287
288
289	})
290
291
292
293
294	$(document).on('click','.nd-lk-user__avatar', function () {
295		if ( $('.nd-lk-user__fio--view').length ) return;
296
297		ND_Uploader({
298			enableStream: false,
299			enableCrop: true,
300			placeElement: '.nd-lk-user__avatar',
301		});
302	})
303
304	$(document).on('click','#crop_modal .ndmodal__close, #crop_modal .button-cancel', function () {
305		$('#crop_modal').remove()
306	})
307
308	$(document).on('click', '#crop_modal', function (e) {
309		if ( ! $(e.target).closest('.ndmodal__inner').length ) {
310			$('#crop_modal').remove()
311		}
312	})
313
314
315
316
317
318	// Табы списка капсул
319
320    window.openTabCapsule = (evt, tabId) => {
321		console.log( tabId );
322
323
324		const contents = document.querySelectorAll('.nd-tab-content');
325		contents.forEach(c => c.classList.remove('nd-tab-content--active'));
326
327		const buttons = document.querySelectorAll('.nd-tab-btn');
328		buttons.forEach(b => b.classList.remove('nd-tab-btn--active'));
329
330		document.getElementById(tabId).classList.add('nd-tab-content--active');
331		evt.currentTarget.classList.add('nd-tab-btn--active');
332	}
333
334	$(document).on('click', '.btn-cancel, .modal-close-x', function() {
335		$('#capsule-delete-modal-anon').remove()
336	})
337	$(document).on('click', '.ndui-modal-btn-open', function () {
338		const button = $(this);
339		let idCapusle = button.attr('id');
340		// const resultDiv = document.getElementById('my-api-result');
341		let item = button.parent()
342
343		let nameCaps = item.find('.capsule-item__name').text().trim();
344
345		let typeCapsule = button.attr('data-type');
346		let modal = typeCapsule == 'viral' ? htmlModalAnon(typeCapsule, nameCaps, idCapusle) : htmlModalPers(typeCapsule,nameCaps,idCapusle);
347
348		if ( $('.modal-delete-capsule').length ) $('.modal-delete-capsule').remove()
349
350
351		$('body').prepend(modal.html)
352
353
354	});
355
356
357	function htmlModalAnon(type = '', nameCaps = '', id = 0) {
358		let modal_id = 'capsule-delete-modal-anon';
359		let html = `<div id="${modal_id}" class="ndui-modal modal-delete-capsule">
360						<div class="ndui-modal__inner modal-inner">
361							<div class="modal-inner__top">
362								<p>Удаление капсулы</p>
363								<div class="modal-inner__close">
364									<i class="nd-icon nd-icon__close"></i>
365								</div>
366							</div>
367							<div class="modal-inner__content">
368								<div class="avatar-capsule avatar-capsule--lightning">
369									<img src="/wp-content/themes/nasledie/assets/ui-kit/img/person-no-gender.svg">
370								</div>
371								<p>Гостевая капсула <span class="modal-highlight">${nameCaps}</span> будет удалена безвозвратно.</p>
372								<div class="modal-delete-capsule__buttons">
373									<button class="nd-button btn-delete" id="capsule-delete" data-capsid="${id}">Удалить</button>
374				 					<button class="nd-button nd-button-empty btn-cancel" id="modal-cancel-btn">Отменить</button>
375				 				</div>
376							</div>
377
378						</div>
379					</div>`;
380
381		return {'html': html, 'id': modal_id };
382	}
383	function htmlModalPers(type = '', nameCaps = '', id = 0) {
384		let modal_id = 'capsule-delete-modal-pers';
385
386		let html = `<div id="${modal_id}" class="ndui-modal modal-delete-capsule">
387						<div class="ndui-modal__inner modal-inner">
388							<div class="modal-inner__top">
389								<p>Удаление капсулы</p>
390								<div class="modal-inner__close">
391									<i class="nd-icon nd-icon__close"></i>
392								</div>
393							</div>
394							<div class="modal-inner__content">
395								<div class="avatar-capsule avatar-capsule--lightning">
396									<img src="/wp-content/themes/nasledie/assets/ui-kit/img/person-no-gender.svg">
397								</div>
398								<h4>Доступ к капсуле будет прекращён</h4>
399								<p>Мы удалим ваши данные в срок до 30 дней, кроме данных, которые обязаны хранить по закону.</p>
400								<div class="modal-delete-capsule__buttons">
401									<button class="nd-button btn-delete" id="btn-cancel-otp" data-capsid="${id}">Удалить</button>
402				 					<button class="nd-button nd-button-empty btn-cancel" id="btn-cancel-btn">Отменить</button>
403				 				</div>
404							</div>
405
406						</div>
407					</div>`;
408
409		return {'html': html, 'id': modal_id };
410	}
411
412	let persContentModal = ''; //Для возврата
413
414	let intervalIdCode = '';
415	let buttonCodeLockTime = localStorage.getItem('buttonCodeLockTime');
416	let buttonCodeLockTimeDisabled = '';
417	// let intervalIdCode = '';
418
419	$(document).on('click', '#btn-cancel-otp', function () {
420		let id = $(this).attr('data-capsid');
421		let btn = $(this)
422		let _this = this;
423		persContentModal = $("#capsule-delete-modal-pers").find('.modal-inner__content');
424
425		$.ajax({
426			type: "GET",
427			url: `/wp-json/lk/v1/user/create_otp?email=${window?.nd_service?.user?.email}`,
428			headers: {
429				'X-WP-Nonce': window?.nd_service?.user?.nonce
430			},
431			beforeSend: function() {
432				btn.html(`<span class="nd-loading"><i class=""></i></span>`)
433			},
434			success: function (res) {
435
436				$("#capsule-delete-modal-pers").find('.modal-inner__content')
437					.html(`<p>Одноразовый код подтверждения отправлен на почту <span>${window.nd_service.user.email}</span></p>
438						<div class="nd-auth-inputs"></div>`)
439				$("#capsule-delete-modal-pers").find('.modal-inner__content')
440					.append(`<div class="modal-delete-capsule__buttons">
441								<button class="nd-button btn-delete" id="capsule-delete" disabled data-capsid="${id}">Подтвердить удаление</button>
442								<button class="nd-button nd-button-empty btn-cancel" id="modal-cancel-btn">Отменить</button>
443							</div>`)
444
445				const customEvent = new CustomEvent('otpDel.SendEmailCode', {
446					bubbles: true,
447					cancelable: true,
448					detail: {
449						request: res,
450						message: 'Код отправлен на почту',
451						params: {email:window?.nd_service?.user?.email},
452					}
453				});
454				$('.btn-delete')[0].dispatchEvent(customEvent);
455
456
457			},
458			error: function (jqXHR, exception) {
459				var msg = '';
460				if (jqXHR.status === 0) {
461					msg = 'Not connect.\n Verify Network.';
462				} else if (jqXHR.status == 404) {
463					msg = 'Requested page not found. [404]';
464				} else if (jqXHR.status == 500) {
465					msg = 'Internal Server Error [500].';
466				} else if (exception === 'parsererror') {
467					msg = 'Requested JSON parse failed.';
468				} else if (exception === 'timeout') {
469					msg = 'Time out error.';
470				} else if (exception === 'abort') {
471					msg = 'Ajax request aborted.';
472				} else {
473					msg = 'Uncaught Error.\n' + jqXHR.responseText;
474				}
475				btn.parent().before(`<p class='text-error-get-otp'>${msg}</p>`)
476				btn.html("Удалить")
477				console.log(`Ошибка: ${msg}`);
478			}
479		})
480	})
481
482	document.addEventListener("otpDel.SendEmailCode", (data) => {
483		let inputsCode = $(`#capsule-delete-modal-pers .verification-code-input`);
484
485		let otpCodeV = new CodeVerificationInput(
486			'#capsule-delete-modal-pers .nd-auth-inputs',
487			{
488			autoSend: true,
489			controls: false,
490			type: 'int',
491			length: 4,
492		});
493		if ( data.detail.request.error === true ) {
494																						// <i class="nd-icon nd-icon__black-info"></i>
495
496			if ( data.detail.request.code == 4 ) {
497				$('.modal-delete-capsule__buttons').before(`<div class="nd-auth-info-repeat-code">
498																	<span class="nd-info-iceon">
499																	 <i class="nd-icon nd-icon__black-info"></i>
500																	</span>
501
502																			<p>${data.detail.request.message}</p>
503																		</div>`);
504				$('.modal-delete-capsule__buttons').remove()
505			}
506			otpCodeV.clearInputrs()
507			otpCodeV.disable()
508			return;
509		}
510
511		let ct = Date.now() + 3000;
512		buttonCodeLockTime = ct
513		localStorage.setItem('buttonCodeLockTime', ct);
514		updateTimer()
515		intervalIdCode = setInterval(updateTimer, 1000)
516
517		otpCodeV.onComplete = function(code) {
518			let codeWidget = this
519			console.log("Код перехвачен через свойство класса:", code);
520
521			$.ajax({
522				type: "POST",
523				url: `/wp-json/lk/v1/user/check_otp`,
524				headers: {
525					'X-WP-Nonce': window?.nd_service?.user?.nonce
526				},
527				data: {
528					code: code,
529					email: window?.nd_service?.user?.email
530				},
531				beforeSend: function() {
532					codeWidget.clearError()
533					codeWidget.$container
534						.find('.verification-code-wrap')
535						.after(`<span class="nd-loading"><i class=""></i>Проверка кода</span>`)
536					codeWidget.disable()
537
538				},
539				success: function (res) {
540					codeWidget.enable()
541					codeWidget.$container.find('.nd-loading').remove()
542
543					if ( res.error === true ) {
544
545						if ( res.code == 4 ) {
546							$('.modal-delete-capsule__buttons').before(`<div class="nd-auth-info-repeat-code">
547								<span class="nd-info-iceon">
548																	 <i class="nd-icon nd-icon__black-info"></i>
549																	</span>
550																			<p>${res.message}</p>
551																		</div>`);
552							$('.modal-delete-capsule__buttons').remove()
553
554							otpCodeV.disable()
555							codeWidget.clearInputrs()
556							$('.nd-auth-button-repeat-code').remove()
557
558						}
559						// codeWidget.showError(`${res.message}`)
560
561						return;
562					}
563
564
565					$('.btn-delete').prop('disabled', false)
566
567
568				},
569				error: function (jqXHR, exception) {
570					var msg = '';
571					if (jqXHR.status === 0) {
572						msg = 'Not connect.\n Verify Network.';
573					} else if (jqXHR.status == 404) {
574						msg = 'Requested page not found. [404]';
575					} else if (jqXHR.status == 500) {
576						msg = 'Internal Server Error [500].';
577					} else if (exception === 'parsererror') {
578						msg = 'Requested JSON parse failed.';
579					} else if (exception === 'timeout') {
580						msg = 'Time out error.';
581					} else if (exception === 'abort') {
582						msg = 'Ajax request aborted.';
583					} else {
584						msg = 'Uncaught Error.\n' + jqXHR.responseText;
585					}
586					codeWidget.showError(`${msg}`)
587					console.log(`Ошибка: ${msg}`);
588				}
589			})
590
591		};
592
593
594
595	})
596	function updateTimer() {
597		const currentTime = Date.now();
598		if (buttonCodeLockTime && currentTime < buttonCodeLockTime) {
599			// Если время блокировки еще не истекло
600			const remainingTime = Math.ceil((buttonCodeLockTime - currentTime) / 1000);
601			const minutes = String(Math.floor(remainingTime / 60)).padStart(2, '0');
602			const seconds = String(remainingTime % 60).padStart(2, '0');
603
604			if ( $('.nd-auth-button-repeat-code').length === 0) {
605				$('.modal-delete-capsule__buttons').before('<div class="nd-auth-button-repeat-code"></div>')
606			}
607
608			if ($('.nd-auth-button-repeat-code').hasClass('active')) {
609				$('.nd-auth-button-repeat-code').removeClass('active');
610			}
611			$('.nd-auth-button-repeat-code').text(`Отправить новый код через ${minutes}:${seconds}`)
612			buttonCodeLockTimeDisabled = true
613
614		} else {
615			// Если время вышло
616			buttonCodeLockTime = ''
617			localStorage.removeItem('buttonCodeLockTime');
618			clearInterval(intervalIdCode);
619			$('.nd-auth-button-repeat-code')
620				.text(`Отправить новый код`)
621				.addClass('active')
622			buttonCodeLockTimeDisabled = false
623		}
624	}
625
626	$(document).on('click', '.nd-auth-button-repeat-code', function () {
627		console.log( $(this) );
628
629		if (!$(this).hasClass('active')) return;
630		getNewOTP()
631	})
632	function getNewOTP() {
633		$.ajax({
634			type: "GET",
635			url: `/wp-json/lk/v1/user/create_otp?email=${window?.nd_service?.user?.email}`,
636			headers: {
637				'X-WP-Nonce': window?.nd_service?.user?.nonce
638			},
639			beforeSend: function() {
640				$('.nd-auth-button-repeat-code.active').html(`<span class="nd-loading"><i class=""></i></span>`)
641			},
642			success: function (res) {
643				$('.nd-auth-button-repeat-code')
644					.removeClass('active').html('')
645
646				let ct = Date.now() + 3000;
647				buttonCodeLockTime = ct
648				localStorage.setItem('buttonCodeLockTime', ct);
649				updateTimer()
650				intervalIdCode = setInterval(updateTimer, 1000)
651			},
652			error: function (jqXHR, exception) {
653				var msg = '';
654				if (jqXHR.status === 0) {
655					msg = 'Not connect.\n Verify Network.';
656				} else if (jqXHR.status == 404) {
657					msg = 'Requested page not found. [404]';
658				} else if (jqXHR.status == 500) {
659					msg = 'Internal Server Error [500].';
660				} else if (exception === 'parsererror') {
661					msg = 'Requested JSON parse failed.';
662				} else if (exception === 'timeout') {
663					msg = 'Time out error.';
664				} else if (exception === 'abort') {
665					msg = 'Ajax request aborted.';
666				} else {
667					msg = 'Uncaught Error.\n' + jqXHR.responseText;
668				}
669				$('.nd-auth-button-repeat-code').before(`<p class='text-error-get-otp'>${msg}</p>`)
670				console.log(`Ошибка: ${msg}`);
671			}
672		})
673	}
674
675
676	$(document).on('click', '.btn-cancel', function(event) {
677		$('.ndui-modal').remove();
678	})
679
680
681
682
683	$(document).on('click', '#capsule-delete', function () {
684		let idCaps = $(this).attr('data-capsid');
685		const button = $(this);
686		console.log( idCaps );
687
688		button.prop('disabled',true);
689
690		const apiUrl = '/wp-json/lk/v1/capsule/delete';
691
692		closeModal()
693		fetch(apiUrl, {
694			method: 'POST',
695			headers: {
696				'Content-Type': 'application/json',
697				'X-WP-Nonce': window.nd_service.user.nonce
698			},
699			body: JSON.stringify({
700				id: idCaps
701			})
702		})
703		.then(response => {
704			if (!response.ok) {
705				throw new Error('Ошибка HTTP: ' + response.status);
706			}
707			return response.json();
708		})
709		.then(data => {
710
711			if ( $('.content-list-deleted .capsule-item').length == 0 ) {
712				$('.content-list-deleted').html('')
713			}
714
715			const formattedDate = new Intl.DateTimeFormat('ru', {
716				day: 'numeric',
717				month: 'long',
718				year: 'numeric'
719			}).format(new Date());
720
721
722			$(`.nd-lk-capsule__item[data-id="${idCaps}"]`)
723				.find('.capsule-item__btn-delete, .capsule-item__role').remove()
724				.end()
725				.prependTo('.content-list-deleted')
726				.find('.capsule-item__date-delete').text('удалена ' + formattedDate)
727
728
729			// $('.content-list-deleted').find('.date-delete--hidden').removeClass('date-delete--hidden')
730
731
732			if ( $('.content-list-viral').find('.capsule-item').length == 0 ) {
733				$('.content-list-viral').prev().remove();
734				$('.content-list-viral').remove()
735			}
736
737			if ( $('.content-list-pers').find('.capsule-item').length == 0 ) {
738				$('.content-list-pers').prev().remove();
739				$('.content-list-pers').remove()
740			}
741
742
743			if ( $('#capsule-delete-modal-pers').length ) $('#capsule-delete-modal-pers').remove()
744
745
746			let lng_items_tab1 = $('#nd-tab-1').find('.capsule-item').length
747			let lng_items_tab2 = $('#nd-tab-2').find('.capsule-item').length
748
749
750			$('.nd-tab-buttons').find('.nd-tab-1 p span').text(lng_items_tab1)
751			$('.nd-tab-buttons').find('.nd-tab-2 p span').text(lng_items_tab2)
752			console.log( data );
753
754		})
755		.catch(error => {
756		})
757		.finally(() => {
758			button.disabled = false;
759		});
760	})
761
762    function closeModal() {
763        $('#capsule-delete-modal-anon').remove();
764    }
765    $('click').on('click', '#modal-close-x, #modal-cancel-btn', function() {
766        closeModal();
767    });
768    $('#capsule-delete-modal-anon').on('click', function(e) {
769        if ($(e.target).is('#capsule-delete-modal-anon')) {
770            closeModal();
771        }
772    });
773
774	$(document).on('click', '.nd-sort-variant li', function(event) {
775		const direction = $(this).attr('data-value'); // 'asc' или 'desc'
776
777		// Функция для сортировки элементов внутри конкретного контейнера
778		const sortContainer = (containerSelector) => {
779			const container = document.querySelector(containerSelector);
780			if (!container) return;
781
782			const items = Array.from(container.querySelectorAll('.capsule-item'));
783			if (items.length === 0) return;
784
785			items.sort((a, b) => {
786				// ПРАВИЛО 1: Текущая капсула всегда первая
787				if (a.getAttribute('data-current') === 'true') return -1;
788				if (b.getAttribute('data-current') === 'true') return 1;
789
790				// ПРАВИЛО 2: Сортировка по ID (дате)
791				const idA = parseInt(a.getAttribute('data-id'), 10) || 0;
792				const idB = parseInt(b.getAttribute('data-id'), 10) || 0;
793
794				return direction === 'desc' ? idB - idA : idA - idB;
795			});
796
797			// Возвращаем отсортированные элементы в контейнер
798			items.forEach(item => container.appendChild(item));
799		};
800
801		// Сортируем списки внутри вкладок
802		// Вкладка 1: Активные (Личные и Гостевые)
803		// Личные капсулы
804		sortContainer('#nd-tab-1 .content-list-viral-pers');
805		// Гостевые капсулы
806		sortContainer('#nd-tab-1 .content-list-viral');
807
808		// Вкладка 2: Удаленные
809		sortContainer('#nd-tab-2 .content-list-deleted');
810	});
811
812
813})(jQuery);
814
815
816function openModalAddBalanceAnonUser() {
817	let email = window.nd_service.user.email;
818	let domen = email.split('@')[0];
819
820	let typeServer = window.nd_service.server.type.toLowerCase()
821	let test = typeServer == 'test' ? '.test' : '';
822
823	let url = `https://${domen}.${window.nd_service.server.domen_nasledie}?authorize-capsule`
824
825
826
827	let modal = `<div id="modal-balance" class="modal-balance">
828					<div class="modal-balance__body">
829						<div class="modal-balance__header">
830							<p class="modal-balance__title">Пополнение</p>
831							<div class="modal-balance__close">
832								<i class="nd-icon nd-icon__close"></i>
833							</div>
834						</div>
835						<div class="modal-balance__main">
836							<div class="modal-balance__text">Пополнение в неавторизованной капсуле невозможно, пожалуйста, авторизуйтесь.</div>
837							<a href="${url}" class="nd-button balance-info__btn" >
838								Авторизовать капсулу
839							</a>
840						</div>
841					</div>
842				</div>`
843
844	if ( $('#modal-balance').length ) { return; }
845	$('body').append(modal)
846
847
848	function closByEscape(e ) {
849		if (e.key != "Escape") return;
850		$('#modal-balance').remove();
851		$(document).off('click', closByEscape);
852	}
853	function closByClick(e) {
854		if (
855			e.target.className === 'modal-balance' ||
856			e.target.closest('.modal-balance__close')
857		) {
858			$('#modal-balance').remove();
859			$(document).off('click', closByClick);
860		}
861	}
862	$(document).on('keyup', closByEscape)
863	$('#modal-balance').on('click', closByClick)
864
865}

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.