PageSourceSearch

https://jinnvl.ru/bitrix/templates/aspro-allcorp3digital/js/custom.js

js jinnvl.ru collected 2026-10-07 23:50:08 UTC 5,861 bytes, 149 lines download raw bytes

1/* ФУНКЦИЯ КАЛЬКУЛЯТОРА НАЧАЛО*/
2/**
3 * Логика тумблеров: Включает или ВЫКЛЮЧАЕТ услуги.
4 * Если тумблер выключается, он снимает галку только если ни один ДРУГОЙ активный тумблер её не держит.
5 */
6function applyPreset(el, presetName) {
7    const container = el.closest('.it-calc-wrapper');
8    const allCheckboxes = container.querySelectorAll('.it-calc-item input[type="checkbox"]');
9    const allPresets = container.querySelectorAll('.it-preset-control input[type="checkbox"]');
10
11    allCheckboxes.forEach(cb => {
12        const cbPresets = cb.getAttribute('data-preset');
13        if (!cbPresets) return;
14        
15        const belongsToCurrent = cbPresets.split(' ').includes(presetName);
16        if (!belongsToCurrent) return;
17
18        if (el.checked) {
19            // Если тумблер включили — просто включаем галку
20            cb.checked = true;
21        } else {
22            // Если тумблер выключили — проверяем, нет ли других ВКЛЮЧЕННЫХ тумблеров для этой галки
23            let keepChecked = false;
24            allPresets.forEach(otherPreset => {
25                const otherName = otherPreset.getAttribute('data-preset-target');
26                if (otherPreset.checked && cbPresets.split(' ').includes(otherName)) {
27                    keepChecked = true;
28                }
29            });
30            if (!keepChecked) cb.checked = false;
31        }
32    });
33}
34
35/**
36 * Синхронизация: если пользователь вручную снял галку из пакета — тумблер гаснет.
37 */
38function syncPresets(cb) {
39    const container = cb.closest('.it-calc-wrapper');
40    const presetsStr = cb.getAttribute('data-preset');
41    if (!presetsStr) return;
42
43    presetsStr.split(' ').forEach(name => {
44        const toggle = container.querySelector(`.it-switch input[data-preset-target="${name}"]`);
45        if (toggle) {
46            if (!cb.checked) {
47                toggle.checked = false;
48            } else {
49                // Проверяем, не собрался ли пакет целиком вручную
50                const presetCbs = container.querySelectorAll(`.it-calc-item input[data-preset]`);
51                let isFull = true;
52                presetCbs.forEach(item => {
53                    if (item.getAttribute('data-preset').split(' ').includes(name) && !item.checked) isFull = false;
54                });
55                if (isFull) toggle.checked = true;
56            }
57        }
58    });
59}
60
61/**
62 * Расчет
63 */
64function calculateServerPrice(calcId) {
65    const root = document.getElementById(calcId);
66    const selected = root.querySelectorAll('.it-calc-item input[type="checkbox"]:checked');
67    const area = root.querySelector('#it-results-area');
68    const content = root.querySelector('.it-res-content');
69    const totalDisp = root.querySelector('.it-res-total');
70
71    if (selected.length === 0) {
72        alert("Пожалуйста, выберите услуги.");
73        area.style.display = 'none';
74        return;
75    }
76
77    let total = 0;
78    let html = '<table class="it-res-table">';
79    selected.forEach(input => {
80        const p = parseInt(input.getAttribute('data-price'));
81        const n = input.getAttribute('data-name');
82        total += p;
83        html += `<tr><td>${n}</td><td style="text-align:right; font-weight:bold;">от ${p.toLocaleString()} ₽</td></tr>`;
84    });
85    html += '</table>';
86
87    content.innerHTML = html;
88    totalDisp.innerHTML = `Итого: от ${total.toLocaleString()} ₽`;
89    area.style.display = 'block';
90    area.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
91}
92/* ФУНКЦИЯ КАЛЬКУЛЯТОРА КОНЕЦ*/
93/* */
94/* */
95/* */
96/* */
97/* */
98/* */
99/* ФУНКЦИЯ ДЛЯ ВЫЗОВА КАРТОЧЕК 4 В РЯД НАЧАЛО*/
100function renderCustomCards(containerId, data) {
101    const container = document.getElementById(containerId);
102    if (!container || !data) return;
103
104    container.classList.add('custom-cards-section');
105
106    let html = '<div class="custom-grid-flex">'; // Убрали класс row
107
108    data.forEach(item => {
109        const hasLink = item.LINK && item.LINK.trim() !== '';
110        const tagName = hasLink ? 'a' : 'div';
111        const linkAttrs = hasLink ? `href="${item.LINK}" target="_blank"` : '';
112        const noLinkClass = !hasLink ? 'no-link' : '';
113
114        let iconHtml = '';
115        if (item.ICON && item.ICON.trim() !== '') {
116            const content = item.IS_SVG 
117                ? `<svg width="55" height="55"><use xlink:href="${item.ICON}"></use></svg>`
118                : `<img src="${item.ICON}" style="width:55px; height:55px; object-fit:contain;">`;
119            iconHtml = `<i class="svg inline svg-inline-more_icon" style="display:block; margin-bottom:15px;">${content}</i>`;
120        }
121
122        let listHtml = '';
123        if (item.LIST && Array.isArray(item.LIST)) {
124            listHtml = '<ul class="card-features">' + 
125                       item.LIST.map(line =>
125 `<li>${line}</li>`).join('') + 
126                       '</ul>';
127        }
128
129        html += `
130            <div class="item-column">
131                <${tagName} ${linkAttrs} class="custom-card-link ${noLinkClass}">
132                    <div class="card-head">
133                        ${iconHtml}
134                        <div class="title">${item.TITLE || ''}</div>
135                    </div>
136                    ${listHtml}
137                </${tagName}>
138            </div>`;
139    });
140
141    html += '</div>';
142    container.innerHTML = html;
143}
144/* ФУНКЦИЯ ДЛЯ ВЫЗОВА КАРТОЧЕК 4 В РЯД КОНЕЦ*/
145/* */
146/* */
147/* */
148/* */
149/* */

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.