diff --git a/public/app-runtime.js b/public/app-runtime.js index 2dd8054..a497832 100644 --- a/public/app-runtime.js +++ b/public/app-runtime.js @@ -284,6 +284,29 @@ window.SUN_LEGACY_CATALOG_V175=[{"id":"1","name":"Фуршетный бокс @media print{.sun-doc-title-with-qr{gap:8mm}.sun-doc-qr{width:25mm;height:25mm}.sun-receipt .sun-receipt-party{padding:1.5mm 2mm;margin:1mm 0}.sun-receipt .sun-receipt-party-grid{grid-template-columns:repeat(4,minmax(0,1fr));gap:.5mm 2mm}} `; document.head.appendChild(style); + const banquetStyle=document.createElement('style'); + banquetStyle.id='sun-banquet-constructor-style'; + banquetStyle.textContent=` + #tiles .sun-banquet-constructor{grid-column:1/-1;display:flex;flex-direction:column;gap:16px} + .sun-banquet-list{min-width:0} + .sun-banquet-group{margin-bottom:6px} + .sun-banquet-group h4{margin:16px 0 6px;font-size:12px;letter-spacing:.04em;text-transform:uppercase;color:#a3806f;border-bottom:1px solid #efe1d8;padding-bottom:5px} + .sun-banquet-group:first-child h4{margin-top:0} + .sun-banquet-row{display:flex;align-items:center;gap:10px;padding:8px 6px;border-radius:9px;cursor:pointer} + .sun-banquet-row:hover{background:#faf5f0} + .sun-banquet-row input[type=checkbox]{width:17px;height:17px;flex:0 0 auto;accent-color:#c0554f} + .sun-banquet-row-name{flex:1 1 auto;font-size:13px;font-weight:600;color:#2c2620;display:flex;flex-direction:column;gap:2px;min-width:0} + .sun-banquet-row-name small{font-weight:500;color:#8a7f74;font-size:11px} + .sun-banquet-row-price{font-weight:700;color:#c0554f;font-size:13px;white-space:nowrap} + .sun-banquet-edit{border:none;background:none;color:#b1a599;cursor:pointer;font-size:13px;padding:2px 6px;flex:0 0 auto} + .sun-banquet-edit:hover{color:#5b4f45} + .sun-banquet-summary{background:#fff;border:1px solid #efe1d8;border-radius:16px;padding:16px 18px} + .sun-banquet-summary h3{margin:0 0 10px;font-size:14px} + .sun-banquet-summary-row{display:flex;justify-content:space-between;gap:12px;padding:6px 0;font-size:12.5px;border-bottom:1px dashed #f1e7de} + .sun-banquet-summary-total{display:flex;justify-content:space-between;align-items:center;margin-top:10px;padding-top:10px;border-top:2px solid #2c2620;font-size:16px;font-weight:800} + @media(min-width:820px){#tiles .sun-banquet-constructor{flex-direction:row;align-items:flex-start}.sun-banquet-list{flex:1 1 auto}.sun-banquet-summary{flex:0 0 260px;position:sticky;top:12px}} + `; + document.head.appendChild(banquetStyle); // ---------------- Catalog categories + search ---------------- const CAT_KEY='sunCatalogCategoriesV2'; @@ -293,7 +316,8 @@ window.SUN_LEGACY_CATALOG_V175=[{"id":"1","name":"Фуршетный бокс {id:3,name:'Напитки',accent:'#4f9bd8',prep:false,hidden:false,order:2}, {id:2,name:'Дополнения',accent:'#56a889',prep:false,hidden:false,order:3}, {id:1,name:'Посуда',accent:'#a78bfa',prep:false,hidden:false,order:4}, - {id:4,name:'Доставка',accent:'#cf9f83',prep:false,hidden:false,order:5} + {id:4,name:'Доставка',accent:'#cf9f83',prep:false,hidden:false,order:5}, + {id:6,name:'Банкетное меню',accent:'#c0554f',prep:false,hidden:false,order:6} ]; function readCats(){ let saved=[];try{saved=JSON.parse(localStorage.getItem(CAT_KEY)||'[]');if(!Array.isArray(saved))saved=[]}catch(_){saved=[]} @@ -386,6 +410,20 @@ window.SUN_LEGACY_CATALOG_V175=[{"id":"1","name":"Фуршетный бокс } function ensureBoxPiecesEditor(){const weight=ensureBoxWeightEditor(),dialog=document.querySelector('#editor .dialog');if(!dialog)return null;let label=$('sunBoxPiecesLabel');if(!label){label=document.createElement('label');label.id='sunBoxPiecesLabel';label.className='sun-box-pieces-field';label.innerHTML='Количество канапе / шт. в боксеЭто общее количество готовых единиц в одном боксе. Не добавляйте его отдельной строкой в «Состав / ТТК».';weight?.insertAdjacentElement('afterend',label)}return label} function syncBoxWeightEditor(category,item){const label=ensureBoxWeightEditor(),input=$('boxWeightGrams'),piecesLabel=ensureBoxPiecesEditor(),piecesInput=$('boxPiecesCount');if(!label||!input)return;const isBox=[0,5].includes(Number(category));label.style.display=isBox?'flex':'none';if(piecesLabel)piecesLabel.style.display=isBox?'flex':'none';if(isBox){input.value=parseWeightGrams(item?.weight)||'';if(piecesInput)piecesInput.value=inferBoxPieces(item)||''}} + function ensureBanquetEditor(){ + const price=$('boxPrice'),dialog=document.querySelector('#editor .dialog');if(!price||!dialog)return null; + let section=$('sunBanquetSectionLabel'); + if(!section){section=document.createElement('label');section.id='sunBanquetSectionLabel';section.className='sun-box-weight-field';section.innerHTML='Раздел меню';price.closest('label')?.insertAdjacentElement('afterend',section)} + let weight=$('sunBanquetWeightLabel'); + if(!weight){weight=document.createElement('label');weight.id='sunBanquetWeightLabel';weight.className='sun-box-weight-field';weight.innerHTML='Вес на 1 гостя, г';section.insertAdjacentElement('afterend',weight)} + return {section,weight}; + } + function syncBanquetEditor(category,item){ + const fields=ensureBanquetEditor();if(!fields)return;const isBanquet=Number(category)===BANQUET_CATEGORY; + fields.section.style.display=isBanquet?'flex':'none';fields.weight.style.display=isBanquet?'flex':'none'; + const caption=$('boxPriceCaption');if(caption)caption.textContent=isBanquet?'Цена на 1 гостя, ₽':'Цена, ₽'; + if(isBanquet){if($('banquetSection'))$('banquetSection').value=item?.catalogSection||'';if($('banquetWeightGrams'))$('banquetWeightGrams').value=parseWeightGrams(item?.weight)||''} + } function installIngredientEditorV175(){window.renderIngredients=()=>{if(!edited)return;normalizeBoxItem(edited);const root=$('ingredients');if(!root)return;const head='
Вид / названиеКол-воЕд.Вес 1 шт., г
';root.innerHTML=head+edited.ingredients.map((row,i)=>{const w=ingredientUnitWeight(row);return `
`}).join('')};window.addIngredient=()=>{if(!edited)return;if(!Array.isArray(edited.ingredients))edited.ingredients=[];edited.ingredients.push(['Новая позиция',1,'шт.',0]);window.renderIngredients();};} installIngredientEditorV175(); function renderOrderLines(){ @@ -398,9 +436,24 @@ window.SUN_LEGACY_CATALOG_V175=[{"id":"1","name":"Фуршетный бокс function boxNumber(item){const explicit=Number(item?.boxNumber);if(Number.isInteger(explicit)&&explicit>=0)return explicit;const name=String(item?.name||'');const match=name.match(/(?:бокс\s*)?№\s*0*(\d+)/i)||name.match(/^\s*№\s*0*(\d+)/i);return match?Number(match[1]):null} function wantedBoxNumber(query){const raw=String(query||'').trim();if(!raw)return null;const match=raw.match(/^(?:бокс\s*)?(?:№\s*)?0*(\d+)\s*$/i);return match?Number(match[1]):null} function itemMatches(item,query){if(!query)return true;if(Number(activeCat)===0){const wanted=wantedBoxNumber(query);return wanted!==null&&boxNumber(item)===wanted}const q=query.trim().toLowerCase();const parts=[item.name,item.catalogSection,item.weight,...(Array.isArray(item.composition)?item.composition:[]),...(Array.isArray(item.ingredients)?item.ingredients.map(x=>x?.[0]):[])];return parts.join(' ').toLowerCase().includes(q)} + const BANQUET_CATEGORY=6; + function banquetSelection(){if(!Array.isArray(draft.banquetSelection))draft.banquetSelection=[];return draft.banquetSelection} + window.toggleBanquetItem=id=>{const sel=banquetSelection();const i=sel.indexOf(String(id));if(i>=0)sel.splice(i,1);else sel.push(String(id));renderCatalogV5();}; + function renderBanquetView(items){ + const sel=new Set(banquetSelection().map(String)); + const groups=new Map(); + items.forEach(item=>{const g=String(item.catalogSection||'Без раздела').trim()||'Без раздела';if(!groups.has(g))groups.set(g,[]);groups.get(g).push(item)}); + const groupsHtml=[...groups.entries()].map(([section,list])=>`

${esc(section)}

${list.map(item=>``).join('')}
`).join(''); + const selectedItems=items.filter(item=>sel.has(String(item.id))); + const total=selectedItems.reduce((s,i)=>s+Number(i.price||0),0); + const summaryRows=selectedItems.map(item=>`
${esc(item.name)}${money(item.price||0)}
`).join(''); + const summaryHtml=`

Меню на 1 гостя

${selectedItems.length?summaryRows:'

Отметьте блюда слева.

'}
Итого на 1 гостя${money(total)}
`; + return `
${groups.size?groupsHtml:'
В разделе «Банкетное меню» пока нет позиций.
'}
${summaryHtml}
`; + } function renderCatalogV5(){ renderCategoryTabs();ensureCatalogTools();const catalogSearch=$('sunCatalogSearch');if(catalogSearch){const boxMode=[0,5].includes(Number(activeCat));catalogSearch.placeholder=boxMode?'Поиск по № бокса':'Поиск по позиции';catalogSearch.inputMode=boxMode?'numeric':'search';}const title=document.querySelector('#new .catalog h1');if(title)title.textContent=catName(activeCat); const all=boxes.filter(item=>Number(item.category||0)===Number(activeCat)),items=all.filter(item=>itemMatches(item,catalogQuery));const cat=catById(activeCat)||{name:'Каталог',prep:true}; + if(Number(activeCat)===BANQUET_CATEGORY){$('tiles').innerHTML=renderBanquetView(items);renderOrderLines();updateOrderSummary();return;} const cards=items.map(item=>``).join(''); const addText=Number(activeCat)===0?'Добавить бокс':(Number(activeCat)===5?'Добавить премиум':'Добавить позицию'); const empty=items.length?'':`
${catalogQuery?'По вашему запросу ничего не найдено.':`В разделе «${esc(cat.name)}» пока нет позиций.`}
`; @@ -423,11 +476,11 @@ window.SUN_LEGACY_CATALOG_V175=[{"id":"1","name":"Фуршетный бокс window.openManager=()=>{managerQuery='';ensureManagerToolbar();if($('sunManagerSearch'))$('sunManagerSearch').value='';renderManagerV5();window.modal?.('manager');}; window.editBox=id=>{ edited=id?structuredClone(boxes.find(x=>String(x.id)===String(id))):{id:'',name:Number(activeCat)===0?'Новый бокс':(Number(activeCat)===5?'Новая премиум позиция':'Новая позиция'),category:Number(activeCat),price:0,oldPrice:0,ingredients:[]};if(!edited)return; - if(!Array.isArray(edited.ingredients))edited.ingredients=[];normalizeBoxItem(edited);syncEditorCategoryOptions();$('itemCategory').value=String(edited.category??activeCat);$('boxName').value=edited.name||'';$('boxPrice').value=Number(edited.price||0);if($('boxOldPrice'))$('boxOldPrice').value=Number(edited.oldPrice||0);if($('boxCompositionText'))$('boxCompositionText').value=(Array.isArray(edited.composition)?edited.composition:[]).join('\n');syncBoxWeightEditor(edited.category??activeCat,edited);$('editPhoto').style.display=edited.photo?'block':'none';$('editPhoto').src=edited.photo||'';$('deleteBox').style.display=edited.id?'block':'none'; + if(!Array.isArray(edited.ingredients))edited.ingredients=[];normalizeBoxItem(edited);syncEditorCategoryOptions();$('itemCategory').value=String(edited.category??activeCat);$('boxName').value=edited.name||'';$('boxPrice').value=Number(edited.price||0);if($('boxOldPrice'))$('boxOldPrice').value=Number(edited.oldPrice||0);if($('boxCompositionText'))$('boxCompositionText').value=(Array.isArray(edited.composition)?edited.composition:[]).join('\n');syncBoxWeightEditor(edited.category??activeCat,edited);syncBanquetEditor(edited.category??activeCat,edited);$('editPhoto').style.display=edited.photo?'block':'none';$('editPhoto').src=edited.photo||'';$('deleteBox').style.display=edited.id?'block':'none'; const cat=catById(edited.category)||{name:'Каталог',prep:true};$('editTitle').textContent=edited.id?`Изменить: ${cat.name}`:(Number(edited.category)===0?'Новый бокс':(Number(edited.category)===5?'Новая премиум позиция':'Новая позиция'));const zone=document.querySelector('#editor .ingredient-zone');if(zone)zone.style.display=cat.prep?'block':'none';window.renderIngredients?.();window.modal?.('editor'); }; - if($('itemCategory'))$('itemCategory').onchange=function(){if(!edited)return;edited.category=Number(this.value);const c=catById(edited.category)||{name:'Каталог',prep:true};const zone=document.querySelector('#editor .ingredient-zone');if(zone)zone.style.display=c.prep?'block':'none';syncBoxWeightEditor(edited.category,edited);$('editTitle').textContent=edited.id?`Изменить: ${c.name}`:(Number(edited.category)===0?'Новый бокс':(Number(edited.category)===5?'Новая премиум позиция':'Новая позиция'));}; - window.saveBox=()=>{if(!edited)return;edited.name=$('boxName').value.trim();edited.price=Math.max(0,Number($('boxPrice').value||0));edited.oldPrice=Math.max(0,Number($('boxOldPrice')?.value||0));if(!(edited.oldPrice>edited.price))delete edited.oldPrice;edited.sale=Boolean(edited.oldPrice&&edited.oldPrice>edited.price);edited.category=Number($('itemCategory').value);if([0,5].includes(edited.category)){const grams=Math.max(0,Math.round(Number($('boxWeightGrams')?.value||0)));edited.weight=grams?`${grams} г`:'';edited.pieces=Math.max(0,Math.round(Number($('boxPiecesCount')?.value||0)));}edited.ingredients=Array.isArray(edited.ingredients)?edited.ingredients:[];if([0,5].includes(edited.category)&&$('boxCompositionText')){const next=$('boxCompositionText').value.split(/\r?\n/).map(x=>x.trim()).filter(Boolean);const before=JSON.stringify(Array.isArray(edited.composition)?edited.composition:[]);edited.composition=next;if(JSON.stringify(next)!==before)edited.compositionSource='manual';}normalizeBoxItem(edited,{cleanup:true});if(!edited.name)return alert('Введите название.');if(!edited.id){edited.id=(typeof sunUUID==='function'?sunUUID():`item-${Date.now()}`);boxes.push(edited)}else{const i=boxes.findIndex(x=>String(x.id)===String(edited.id));if(i>=0)boxes[i]=edited}if(!catById(edited.category)?.hidden)activeCat=edited.category;persist();closeModal('editor');closeModal('manager');renderCatalogV5();renderOrders?.();window.sunClientOfferCatalogChanged?.(edited.id);}; + if($('itemCategory'))$('itemCategory').onchange=function(){if(!edited)return;edited.category=Number(this.value);const c=catById(edited.category)||{name:'Каталог',prep:true};const zone=document.querySelector('#editor .ingredient-zone');if(zone)zone.style.display=c.prep?'block':'none';syncBoxWeightEditor(edited.category,edited);syncBanquetEditor(edited.category,edited);$('editTitle').textContent=edited.id?`Изменить: ${c.name}`:(Number(edited.category)===0?'Новый бокс':(Number(edited.category)===5?'Новая премиум позиция':'Новая позиция'));}; + window.saveBox=()=>{if(!edited)return;edited.name=$('boxName').value.trim();edited.price=Math.max(0,Number($('boxPrice').value||0));edited.oldPrice=Math.max(0,Number($('boxOldPrice')?.value||0));if(!(edited.oldPrice>edited.price))delete edited.oldPrice;edited.sale=Boolean(edited.oldPrice&&edited.oldPrice>edited.price);edited.category=Number($('itemCategory').value);if([0,5].includes(edited.category)){const grams=Math.max(0,Math.round(Number($('boxWeightGrams')?.value||0)));edited.weight=grams?`${grams} г`:'';edited.pieces=Math.max(0,Math.round(Number($('boxPiecesCount')?.value||0)));}if(edited.category===BANQUET_CATEGORY){edited.catalogSection=($('banquetSection')?.value||'').trim();const grams=Math.max(0,Math.round(Number($('banquetWeightGrams')?.value||0)));edited.weight=grams?`${grams} г`:'';}edited.ingredients=Array.isArray(edited.ingredients)?edited.ingredients:[];if([0,5].includes(edited.category)&&$('boxCompositionText')){const next=$('boxCompositionText').value.split(/\r?\n/).map(x=>x.trim()).filter(Boolean);const before=JSON.stringify(Array.isArray(edited.composition)?edited.composition:[]);edited.composition=next;if(JSON.stringify(next)!==before)edited.compositionSource='manual';}normalizeBoxItem(edited,{cleanup:true});if(!edited.name)return alert('Введите название.');if(!edited.id){edited.id=(typeof sunUUID==='function'?sunUUID():`item-${Date.now()}`);boxes.push(edited)}else{const i=boxes.findIndex(x=>String(x.id)===String(edited.id));if(i>=0)boxes[i]=edited}if(!catById(edited.category)?.hidden)activeCat=edited.category;persist();closeModal('editor');closeModal('manager');renderCatalogV5();renderOrders?.();window.sunClientOfferCatalogChanged?.(edited.id);}; window.removeBox=()=>{if(!edited?.id||!confirm(`Удалить «${edited.name}» из каталога?`))return;boxes=boxes.filter(x=>String(x.id)!==String(edited.id));draft.lines=(draft.lines||[]).filter(x=>String(x.id)!==String(edited.id));persist();closeModal('editor');closeModal('manager');renderCatalogV5();renderOrders?.();}; function fileAsDataUrl(file){return new Promise((resolve,reject)=>{const reader=new FileReader();reader.onerror=()=>reject(reader.error||new Error('FileReader error'));reader.onload=()=>resolve(String(reader.result||''));reader.readAsDataURL(file)})} diff --git a/public/index.html b/public/index.html index 33dcc89..32cbc3a 100644 --- a/public/index.html +++ b/public/index.html @@ -95,7 +95,7 @@ button{touch-action:manipulation} #sunGlobalSearchBtn kbd{display:none!important} #sunSyncSettingsCard>div[style*="grid-template-columns"]{grid-template-columns:1fr!important} -}
Caterium

Стоимость позиций0 ₽

Предоплата0 ₽

К оплате0 ₽

Заказы

МероприятиеДата и времяАдресСуммаСтатусДействия

Нажмите «Изменить», чтобы открыть заказ. Сумма, предоплата и остаток сохраняются вместе с заказом.

Склад

В этой версии каталог продуктов пополняется из составов боксов. Остатки и цены добавим следующим шагом.

Статистика

- + diff --git a/tests/release-check.mjs b/tests/release-check.mjs index 3e57ea4..4877597 100644 --- a/tests/release-check.mjs +++ b/tests/release-check.mjs @@ -15,7 +15,7 @@ check((runtime.match(/\/Type \/Catalog/g)||[]).length===0,'runtime contains no P check(read('core/pdf-engine.js').includes('595.28')&&read('core/pdf-engine.js').includes('841.89'),'PDF engine uses A4 MediaBox'); check([...index.matchAll(/@page\{([^}]*)\}/g)].every(m=>/size:A4/i.test(m[1])),'compact @page rules use A4'); check(sw.includes('v81-20260912-account-center-loader')&&sw.includes('data-layer-v1773.js')&&sw.includes('server-automation-v1770.js')&&sw.includes('offer-workspace-v1769.js'),'service worker cache is v17.7.3'); -check(index.includes('20260916-v18-1-0-cache-bust-fix')&&index.includes('classic-offer-pdf-v1767.js')&&!index.includes('20260907-v17-6-0-stability-security'),'index cache-busting points to v17.7.3'); +check(index.includes('20260916-v18-1-2-banquet-menu-tab')&&index.includes('classic-offer-pdf-v1767.js')&&!index.includes('20260907-v17-6-0-stability-security'),'index cache-busting points to v17.7.3'); check(performance.includes('SunAttachmentGuard')&&performance.includes('TARGET=2*1024*1024'),'chat photo auto-compression is versioned'); check(performance.includes("rpc('sun_dev_dashboard')")&&performance.includes('server_size')&&performance.includes('storage_size'),'Developer Console server/storage counters are versioned'); check(performance.includes('MEMORY_REFRESH_MS=30000')&&performance.includes('MEMORY_TIMEOUT_MS=8000')&&performance.includes('memoryPromise'),'Developer Console memory refresh is bounded'); @@ -65,7 +65,7 @@ check(offerWorkspace.includes('PDF и предпросмотр')&&offerWorkspace check(offerWorkspace.includes('SunClassicOfferPDFV1767')&&offerWorkspace.includes('finalGallery=galleryFor'),'custom gallery is injected into PDF renderer'); check(releaseManifest.offerWorkspaceTabs===true&&releaseManifest.offerTemplatesSeparateTab===true&&releaseManifest.offerTwoCustomGalleryPhotos===true,'release manifest records offer workspace changes'); check(pkg.version==='17.7.3','package version is v17.7.3'); -check(index.includes('20260916-v18-1-0-cache-bust-fix'),'index cache bust is v17.7.3'); +check(index.includes('20260916-v18-1-2-banquet-menu-tab'),'index cache bust is v17.7.3'); check(sw.includes('v81-20260912-account-center-loader')&&sw.includes('data-layer-v1773.js')&&sw.includes('server-automation-v1770.js'),'PWA caches v17.7.3 client foundation modules'); check(fs.existsSync(path.join(root,'public/core/data-layer-v1773.js'))&&fs.existsSync(path.join(root,'public/core/server-automation-v1770.js')),'data layer and server automation modules exist'); check(ux.includes('CateriumServerAutomationV1770?.enabled'),'cloud browser auto completion is disabled when server automation is active'); diff --git a/tests/static-security.mjs b/tests/static-security.mjs index e0f7321..0139c1e 100644 --- a/tests/static-security.mjs +++ b/tests/static-security.mjs @@ -29,7 +29,7 @@ if(legacyCount!==60)fail(`legacy catalog photo count ${legacyCount}, expected 60 const gallery=fs.readdirSync(path.join(pub,'offer-gallery')).filter(x=>/\.jpg$/i.test(x)); if(gallery.length!==2)fail(`offer gallery contains ${gallery.length} jpg files, expected 2`);else ok('offer gallery trimmed'); if(!sw.includes('20260912-account-center-loader')||!sw.includes('login-signature-v1776.js')||!sw.includes('data-layer-v1773.js')||!sw.includes('server-automation-v1770.js')||!sw.includes('offer-workspace-v1769.js')||sw.includes('offer-gallery-data.js'))fail('service worker cache is stale');else ok('PWA cache updated for login refresh'); -if(html.includes('20260907-v17-6-0-stability-security')||html.includes('20260909-v17-7-3-clients-server-read')||!html.includes('20260916-v18-1-0-cache-bust-fix')||!html.includes('classic-offer-pdf-v1767.js'))fail('index still serves stale core asset version');else ok('index cache-busting is current'); +if(html.includes('20260907-v17-6-0-stability-security')||html.includes('20260909-v17-7-3-clients-server-read')||!html.includes('20260916-v18-1-2-banquet-menu-tab')||!html.includes('classic-offer-pdf-v1767.js'))fail('index still serves stale core asset version');else ok('index cache-busting is current'); if(!performance.includes('SunAttachmentGuard')||!performance.includes('MAX_SIDE=2048'))fail('chat photo compression guard missing');else ok('chat photo compression guard present'); if(!performance.includes("rpc('sun_dev_dashboard')")||!performance.includes('storage_size')||!performance.includes('server_size'))fail('Developer Console memory counters missing');else ok('Developer Console memory counters present'); if(performance.includes('records.forEach(r=>r.addedNodes.forEach(n=>{if(n.nodeType===1)scan(n)}));enhanceDeveloperMemory()'))fail('Developer Console memory refresh is still coupled to MutationObserver');else ok('Developer Console memory refresh loop removed');