/** * V.AI STUDIO — Product Editor v7 * * Approach: Monkey-patch showDetail() để CHẮC CHẮN inject edit icons * sau khi detail content được render. Không dùng MutationObserver. * * Edit bằng prompt() — đơn giản, hoạt động mọi browser. */ (function(){ 'use strict'; var AUTH_USER='V.AISTUDIO',AUTH_PASS='Khongbiet'; var EDITS_KEY='vai_product_edits',CUSTOM_KEY='vai_custom_products'; function getEdits(){try{return JSON.parse(localStorage.getItem(EDITS_KEY)||'{}');}catch(e){return {};}} function saveEdits(e){localStorage.setItem(EDITS_KEY,JSON.stringify(e));} function getCustom(){try{return JSON.parse(localStorage.getItem(CUSTOM_KEY)||'[]');}catch(e){return [];}} function saveCustom(a){localStorage.setItem(CUSTOM_KEY,JSON.stringify(a));} function getD(){return window.D||[];} function checkAuth(){return sessionStorage.getItem('vai_editor_auth')==='1';} function doLogin(cb){ if(checkAuth()){cb();return;} var pw=prompt('🔐 Nhập mật khẩu quản trị:'); if(pw===AUTH_PASS){sessionStorage.setItem('vai_editor_auth','1');cb();} else if(pw!==null)alert('Sai mật khẩu'); } // === Apply saved edits to D[] on load === function applyEdits(){ var D=getD();if(!D.length)return; var edits=getEdits(),applied=0; for(var i=0;i0){ p.priceNum=num;p.price=num.toLocaleString('vi-VN')+'đ'; var edits=getEdits();if(!edits[p.slug])edits[p.slug]={}; edits[p.slug].price=num;saveEdits(edits); priceEl.firstChild.textContent=p.price; } }); }; } // Add icon to name var nameEl=dv.querySelector('.detail-name'); if(nameEl&&!nameEl.querySelector('.vai-eic')){ nameEl.insertAdjacentHTML('beforeend',ICON); nameEl.querySelector('.vai-eic').onclick=function(e){ e.stopPropagation(); doLogin(function(){ var val=prompt('📝 Tên sản phẩm:',p.name||''); if(val===null||!val.trim())return; p.name=val.trim(); var edits=getEdits();if(!edits[p.slug])edits[p.slug]={}; edits[p.slug].name=val.trim();saveEdits(edits); nameEl.firstChild.textContent=val.trim(); }); }; } // Add icon on gallery (for image edit) var gallery=dv.querySelector('.gallery,.gallery-carousel'); if(gallery&&!gallery.querySelector('.vai-eic')){ var imgBtn=document.createElement('span'); imgBtn.className='vai-eic'; imgBtn.textContent='✏️'; imgBtn.style.cssText='position:absolute;top:10px;right:10px;z-index:50;background:rgba(255,255,255,.92);padding:5px 8px;border-radius:8px;cursor:pointer;font-size:15px;box-shadow:0 2px 8px rgba(0,0,0,.15);opacity:0.7'; imgBtn.onmouseenter=function(){this.style.opacity='1';}; imgBtn.onmouseleave=function(){this.style.opacity='0.7';}; imgBtn.onclick=function(e){ e.stopPropagation(); doLogin(function(){ var val=prompt('🖼️ URL hình ảnh mới:',p.image||''); if(val===null||!val.trim())return; p.image=val.trim(); if(p.images&&p.images.length)p.images[0]=val.trim(); var edits=getEdits();if(!edits[p.slug])edits[p.slug]={}; edits[p.slug].image=val.trim();saveEdits(edits); var img=dv.querySelector('.gallery-slide img,img'); if(img)img.src=val.trim(); }); }; gallery.style.position='relative'; gallery.appendChild(imgBtn); } } // === Thêm SP === var PROXIES=[function(u){return 'https://api.allorigins.win/get?url='+encodeURIComponent(u);}]; function openAddUrl(){ var o=document.getElementById('vai-addurl');if(o)o.remove(); var d=document.createElement('div');d.id='vai-addurl'; d.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:99999;display:flex;align-items:center;justify-content:center;padding:16px'; d.onclick=function(e){if(e.target===d)d.remove();}; d.innerHTML='
➕ Thêm SP
'; document.body.appendChild(d); document.getElementById('va-x').onclick=function(){d.remove();}; document.getElementById('va-fetch').onclick=function(){ var url=document.getElementById('va-url').value.trim();if(!url)return; document.getElementById('va-st').textContent='Đang crawl...'; fetch(PROXIES[0](url)).then(function(r){return r.json();}).then(function(j){ var html=j.contents||'';if(!html){document.getElementById('va-st').textContent='Lỗi';return;} var doc=(new DOMParser()).parseFromString(html,'text/html'); var h1=doc.querySelector('h1');if(h1)document.getElementById('va-name').value=h1.textContent.trim(); var og=doc.querySelector('meta[property="og:image"]');if(og)document.getElementById('va-img').value=og.content||''; var pr=doc.querySelector('[itemprop="price"],.price,[class*="price"]');if(pr){var n=(pr.content||pr.textContent||'').replace(/[^\d]/g,'');if(n&&parseInt(n)>1000)document.getElementById('va-price').value=n;} document.getElementById('va-st').textContent='✓ OK'; }).catch(function(){document.getElementById('va-st').textContent='Lỗi crawl';}); }; document.getElementById('va-save').onclick=function(){ var name=document.getElementById('va-name').value.trim();if(!name){alert('Nhập tên SP');return;} var model=document.getElementById('va-model').value.trim(); var price=parseInt((document.getElementById('va-price').value||'').replace(/\D/g,''))||0; var image=document.getElementById('va-img').value.trim(); var brand=document.getElementById('va-brand').value.trim(); var slug='c'+Date.now(); var _idx=(model+' '+brand+' '+name).toLowerCase(); if(typeof buildSearchIndex==='function')try{_idx=buildSearchIndex({name:name,model:model,sku:model,brand:brand,cat:'custom',specs:{}});}catch(e){} var np={name:name,model:model,sku:model,slug:slug,price:price?price.toLocaleString('vi-VN')+'đ':'Liên hệ',priceNum:price,discPrice:price,image:image,images:image?[image]:[],link:document.getElementById('va-url').value.trim(),cat:'custom',catSlug:'custom',brand:brand,_idx:_idx}; getD().push(np);var c=getCustom();c.push(np);saveCustom(c); d.remove(); if(typeof init==='function')try{init();}catch(e){} alert('✅ Đã thêm: '+name); }; } // === FAB button === function injectFAB(){ if(document.getElementById('vai-fab'))return; var b=document.createElement('button');b.id='vai-fab'; b.style.cssText='position:fixed;bottom:20px;left:20px;z-index:9000;width:46px;height:46px;border-radius:50%;background:linear-gradient(135deg,#0369a1,#059669);color:#fff;border:none;font-size:22px;cursor:pointer;box-shadow:0 4px 14px rgba(0,0,0,.25);transition:transform .2s'; b.textContent='+'; b.title='Thêm sản phẩm'; b.onmouseenter=function(){b.style.transform='scale(1.1)';}; b.onmouseleave=function(){b.style.transform='';}; b.onclick=function(){doLogin(openAddUrl);}; document.body.appendChild(b); } // === INIT === // Wait for D[] and showDetail to exist, then patch var _patchInterval=setInterval(function(){ if(getD().length>50&&typeof window.showDetail==='function'){ clearInterval(_patchInterval); applyEdits(); patchShowDetail(); } },300); setTimeout(function(){clearInterval(_patchInterval);},30000); setTimeout(injectFAB,1000); window.VAI_EDITOR={add:openAddUrl,patch:patchShowDetail}; console.log('[Editor v7] ready'); })();