Карточка: обновление в DOM на месте (без перезагрузки) — страница не дёргается; бейджи не переносятся
Вместо location.reload при смене подписи карточка теперь обновляется рекурсивным морфингом
<main>: догружаем ту же страницу и сливаем только изменившиеся узлы, одинаковые поддеревья не
трогаем. Прокрутка окна и боковых блоков («Путь заявки» .claim-tl / .in-tl) не сбивается,
выделение в неизменном тексте сохраняется, нет прыжков и мигания. Морфинг пропускается, если
правится форма (dirty) или идёт выделение. Копи-кнопки переинициализируются (bjInitCopyBars).
Плюс .badge { white-space:nowrap } — в журнале стрелка «↗ Исходящий» больше не переносится над словом.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -161,7 +161,7 @@ th { color:var(--muted); font-weight:600; font-size:11px; text-transform:upperca
|
||||
tbody tr:hover td { background:var(--accent-weak); }
|
||||
|
||||
/* ---- Бейджи статусов ---- */
|
||||
.badge { display:inline-block; padding:3px 9px; border-radius:20px; font-size:11px; font-weight:600; }
|
||||
.badge { display:inline-block; padding:3px 9px; border-radius:20px; font-size:11px; font-weight:600; white-space:nowrap; }
|
||||
.live { font-size:11.5px; margin-top:4px; color:var(--muted); display:flex; align-items:center; gap:6px; line-height:1.3 }
|
||||
.live::before { content:''; width:7px; height:7px; border-radius:50%; background:var(--muted); flex:none }
|
||||
.live-wait::before { background:var(--accent); animation:pulse 2.4s var(--ease) infinite }
|
||||
@@ -798,7 +798,8 @@ button.dq-link, .dq-link { background:none !important; border:0 !important; padd
|
||||
return Promise.resolve(fallback());
|
||||
};
|
||||
// Кнопка «Скопировать» над каждым блоком скрипта/кода (pre.copyable): копирует текст целиком.
|
||||
(function(){
|
||||
// Вынесено в window.bjInitCopyBars, чтобы вызывать повторно после обновления карточки в DOM.
|
||||
window.bjInitCopyBars = function(){
|
||||
document.querySelectorAll('pre.copyable').forEach(function(pre){
|
||||
if (pre.previousElementSibling && pre.previousElementSibling.classList.contains('copy-bar')) return;
|
||||
var bar=document.createElement('div'); bar.className='copy-bar';
|
||||
@@ -812,7 +813,8 @@ button.dq-link, .dq-link { background:none !important; border:0 !important; padd
|
||||
});
|
||||
bar.appendChild(b); pre.parentNode.insertBefore(bar, pre);
|
||||
});
|
||||
})();
|
||||
};
|
||||
bjInitCopyBars();
|
||||
// Цепочка связи с НРД в шапке: обновляется каждые 30 с, чтобы открытая страница не показывала старое.
|
||||
(function(){
|
||||
var el = document.getElementById('nsd-chain');
|
||||
@@ -856,6 +858,48 @@ button.dq-link, .dq-link { background:none !important; border:0 !important; padd
|
||||
} catch(e){}
|
||||
location.reload();
|
||||
}
|
||||
// Обновление карточки заявки БЕЗ перезагрузки: догружаем ту же страницу и аккуратно
|
||||
// сливаем изменения в DOM (рекурсивный морфинг <main>). Одинаковые поддеревья не трогаем —
|
||||
// страница не дёргается, прокрутка окна и боковых блоков («Путь заявки») не сбивается,
|
||||
// выделение в неизменном тексте сохраняется. Скролл прокручиваемых блоков восстанавливается.
|
||||
function bjMorphKids(oldP, newP){
|
||||
if (!oldP || !newP) return;
|
||||
var top = oldP.scrollTop, left = oldP.scrollLeft;
|
||||
var olds = [].slice.call(oldP.childNodes), news = [].slice.call(newP.childNodes);
|
||||
var common = Math.min(olds.length, news.length), i;
|
||||
for (i = 0; i < common; i++) bjMorphNode(oldP, olds[i], news[i]);
|
||||
for (i = olds.length - 1; i >= common; i--) oldP.removeChild(olds[i]);
|
||||
for (i = common; i < news.length; i++) oldP.appendChild(news[i].cloneNode(true));
|
||||
oldP.scrollTop = top; oldP.scrollLeft = left;
|
||||
}
|
||||
function bjMorphNode(parent, o, n){
|
||||
if (o.nodeType === 3 || o.nodeType === 8) { // текст/комментарий
|
||||
if (n.nodeType === o.nodeType) { if (o.nodeValue !== n.nodeValue) o.nodeValue = n.nodeValue; }
|
||||
else parent.replaceChild(n.cloneNode(true), o);
|
||||
return;
|
||||
}
|
||||
if (o.nodeType !== 1 || n.nodeType !== 1 || o.nodeName !== n.nodeName) { parent.replaceChild(n.cloneNode(true), o); return; }
|
||||
if (o.outerHTML === n.outerHTML) return; // поддерево не изменилось — не трогаем (скролл/выделение целы)
|
||||
var oa = o.attributes, na = n.attributes, j;
|
||||
for (j = oa.length - 1; j >= 0; j--) { if (!n.hasAttribute(oa[j].name)) o.removeAttribute(oa[j].name); }
|
||||
for (j = 0; j < na.length; j++) { if (o.getAttribute(na[j].name) !== na[j].value) o.setAttribute(na[j].name, na[j].value); }
|
||||
bjMorphKids(o, n); // рекурсивно внутрь
|
||||
}
|
||||
var bjRefreshing = false;
|
||||
function bjRefreshClaim(){
|
||||
if (bjRefreshing) return;
|
||||
bjRefreshing = true;
|
||||
fetch(location.href, {cache: 'no-store', credentials: 'same-origin'})
|
||||
.then(function(r){ return r.ok ? r.text() : Promise.reject(); })
|
||||
.then(function(html){
|
||||
if (dirty || (window.bjSelecting && window.bjSelecting())) return; // правит форму или выделяет — не трогаем
|
||||
var doc = new DOMParser().parseFromString(html, 'text/html');
|
||||
bjMorphKids(document.querySelector('main'), doc.querySelector('main'));
|
||||
if (window.bjInitCopyBars) window.bjInitCopyBars();
|
||||
})
|
||||
.catch(function(){})
|
||||
.then(function(){ bjRefreshing = false; });
|
||||
}
|
||||
try {
|
||||
var raw = sessionStorage.getItem(scrollKey);
|
||||
if (raw !== null) {
|
||||
@@ -895,7 +939,7 @@ button.dq-link, .dq-link { background:none !important; border:0 !important; padd
|
||||
if (!st) return;
|
||||
var big = e.classList.contains('live-big'), was = e.getAttribute('data-sig');
|
||||
if (big && was && st.sig && st.sig !== was) {
|
||||
if (!dirty) { bjReloadKeepScroll(); return; }
|
||||
if (!dirty) { bjRefreshClaim(); e.setAttribute('data-sig', st.sig); return; }
|
||||
meta(e, 'Заявка изменилась. <a href="' + location.pathname + location.search + '">Обновить страницу</a> (отмеченное в форме не сохранится)', 'changed');
|
||||
e.setAttribute('data-sig', st.sig);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user