Siteβ―Builder
Editing:
admin.php
writable 0666
<script src="/ai-business-research/admin-protect.js"></script> <?php $questionsFile = __DIR__ . "/ai-questions.json"; $backupFile = __DIR__ . "/ai-questions-backup-" . date("Ymd-His") . ".json"; // Handle save if ($_SERVER['REQUEST_METHOD'] === 'POST') { $data = json_decode($_POST['json'] ?? '', true); if (is_array($data)) { copy($questionsFile, $backupFile); // auto-backup file_put_contents($questionsFile, json_encode($data, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE)); echo "OK"; exit; } else { http_response_code(400); echo "Invalid data"; exit; } } // Load questions file $data = is_readable($questionsFile) ? json_decode(file_get_contents($questionsFile), true) : []; $cats = array_keys($data); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>AI Question Editor | BestDealOn</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> body {background:#f6f8fb;font-family:system-ui,Arial,sans-serif;margin:0;} h1 {margin-top:1em;text-align:center;color:#3133b9;} #main {max-width:860px;margin:2em auto;background:#fff;border-radius:16px;box-shadow:0 2px 18px #d3dbfa44;padding:1.8em 2em;} .catlist {margin-bottom:1.9em;display:flex;flex-wrap:wrap;gap:.5em;} .catbtn {background:#e9eefe;border-radius:8px;border:1.5px solid #bbd2f6;font-weight:700;font-size:1.1em;padding:.38em 1.5em;cursor:pointer;transition:.14s;} .catbtn.active {background:#5b36ff;color:#fff;border-color:#5b36ff;} .catbtn:hover:not(.active){background:#ebdbff;} .addcat {margin-left:1em;background:#28c19c;color:#fff;} .addcat:hover {background:#27a585;} #qedit {margin-top:.4em;} .qarea {background:#f8faff;padding:1.1em 1.4em;border-radius:10px;border:1.5px solid #d4e0ee;} .qtitle {font-size:1.17em;font-weight:700;color:#2d4fcf;margin-bottom:1.1em;} .qitem {display:flex;align-items:center;margin-bottom:.58em;} .qtext {flex:1;padding:.32em .7em;border-radius:7px;border:1.5px solid #e6eaf3;font-size:1.08em;} .qdel {background:#fff;color:#e14b4b;font-size:1.18em;border:none;cursor:pointer;border-radius:7px;margin-left:.5em;} .qdel:hover {background:#f8d0d0;} .qmove {cursor:grab;color:#aaa;font-size:1.1em;margin-right:.6em;} .qadd {margin-top:.8em;background:#6c48ff;color:#fff;padding:.4em 1.7em;border:none;border-radius:7px;font-weight:700;cursor:pointer;} .qadd:hover {background:#4a36b6;} #saveBtn, #undoBtn {margin-top:1.5em;padding:.6em 1.9em;font-size:1.13em;font-weight:700;border:none;border-radius:8px;cursor:pointer;} #saveBtn {background:#5b36ff;color:#fff;} #saveBtn.saved {background:#3cbb6b;} #saveBtn:disabled {background:#aaa;} #undoBtn {background:#ffead7;color:#ca4a2a;margin-left:.8em;} #status {font-size:1.04em;margin-top:1.4em;color:#399154;font-weight:700;} .err {color:#e14141;} .catdel {margin-left:.4em;background:#fff;color:#ca3b3b;font-size:.97em;border:none;border-radius:7px;padding:.23em 1.2em;cursor:pointer;} .catdel:hover {background:#fde3e3;} .catnew {margin-left:1.3em;} @media (max-width:700px){ #main{padding:.6em .6em;} } </style> </head> <body> <h1>π AI Business Questions Editor</h1> <div id="main"> <div> <b>Categories:</b> <span class="catlist" id="catlist"> <!-- rendered by JS --> </span> <input id="catnew" class="catnew" placeholder="Add Category..." style="display:none;" autocomplete="off"> <button class="addcat" id="catAddBtn" title="Add Category">+ Add</button> </div> <div id="qedit" style="display:none;"> <div class="qarea"> <div class="qtitle"><span id="catname"></span> <button class="catdel" id="catdelBtn" title="Delete this category">Delete Category</button> </div> <div id="qlist"></div> <button class="qadd" id="qAddBtn">+ Add Question</button> </div> </div> <button id="saveBtn" style="display:none;">πΎ Save Changes</button> <button id="undoBtn" style="display:none;">Undo</button> <div id="status"></div> </div> <script> let qData = <?= json_encode($data) ?>; let backup = JSON.stringify(qData); let cat = Object.keys(qData)[0] || ''; let curCat = cat; const catlist = document.getElementById('catlist'); const catnew = document.getElementById('catnew'); const qedit = document.getElementById('qedit'); const qlist = document.getElementById('qlist'); const catname = document.getElementById('catname'); const saveBtn = document.getElementById('saveBtn'); const undoBtn = document.getElementById('undoBtn'); const statusDiv = document.getElementById('status'); const qAddBtn = document.getElementById('qAddBtn'); const catAddBtn = document.getElementById('catAddBtn'); const catdelBtn = document.getElementById('catdelBtn'); function renderCats() { catlist.innerHTML = ''; Object.keys(qData).forEach(c=>{ let b = document.createElement('button'); b.className = "catbtn"+(c===curCat?" active":""); b.textContent = c; b.onclick = ()=>{ curCat=c; renderCats(); renderQs(); }; catlist.appendChild(b); }); } function renderQs() { qedit.style.display = curCat ? '' : 'none'; catname.textContent = curCat; qlist.innerHTML = ''; if(!curCat) return; (qData[curCat]||[]).forEach((q, idx) => { let div = document.createElement('div'); div.className = 'qitem'; div.draggable = true; div.ondragstart = e=>{ e.dataTransfer.setData("idx", idx); }; div.ondragover = e=>{ e.preventDefault(); }; div.ondrop = e=>{ let from = +e.dataTransfer.getData("idx"); let to = idx; if(from===to) return; let arr = qData[curCat]; let [moved] = arr.splice(from,1); arr.splice(to,0,moved); renderQs(); saveBtn.style.display=''; }; let move = document.createElement('span'); move.className = "qmove"; move.title = "Drag to reorder"; move.innerHTML = "☰"; div.appendChild(move); let inp = document.createElement('input'); inp.type="text"; inp.className="qtext"; inp.value=q; inp.oninput = ()=>{ qData[curCat][idx]=inp.value; saveBtn.style.display=''; }; div.appendChild(inp); let del = document.createElement('button'); del.className = 'qdel'; del.title = "Delete"; del.innerHTML = "✕"; del.onclick = ()=>{ if(confirm('Delete this question?')){ qData[curCat].splice(idx,1); renderQs(); saveBtn.style.display='';}}; div.appendChild(del); qlist.appendChild(div); }); } function addCat(catName) { if(!catName || qData[catName]) return; qData[catName]=[]; curCat=catName; renderCats(); renderQs(); saveBtn.style.display=''; } catAddBtn.onclick = ()=>{ catAddBtn.style.display='none'; catnew.style.display=''; catnew.value=''; catnew.focus(); }; catnew.onblur = ()=>{ catAddBtn.style.display=''; catnew.style.display='none'; }; catnew.onkeydown = e=>{ if(e.key==='Enter'){ addCat(catnew.value.trim()); catAddBtn.style.display=''; catnew.style.display='none'; } }; qAddBtn.onclick = ()=>{ if(!curCat) return; qData[curCat].push(''); renderQs(); saveBtn.style.display=''; }; catdelBtn.onclick = ()=>{ if(!curCat) return; if(confirm('Delete category and all questions?')){ delete qData[curCat]; curCat = Object.keys(qData)[0] || ''; renderCats(); renderQs(); saveBtn.style.display=''; } }; saveBtn.onclick = ()=>{ saveBtn.disabled=true; statusDiv.textContent='Saving...'; fetch(window.location.href, { method:'POST', headers:{'Content-Type':'application/x-www-form-urlencoded'}, body:'json='+encodeURIComponent(JSON.stringify(qData)) }).then(r=>r.text()).then(res=>{ saveBtn.disabled=false; if(res.trim()==='OK'){ saveBtn.classList.add('saved'); setTimeout(()=>saveBtn.classList.remove('saved'), 1200); backup = JSON.stringify(qData); statusDiv.textContent='Saved!'; saveBtn.style.display='none'; } else { statusDiv.innerHTML='<span class="err">'+res+'</span>'; } }).catch(e=>{ saveBtn.disabled=false; statusDiv.innerHTML='<span class="err">Save failed.</span>'; }); }; undoBtn.onclick = ()=>{ if(confirm('Undo all unsaved changes?')){ qData = JSON.parse(backup); renderCats(); renderQs(); saveBtn.style.display='none'; } }; document.onkeydown = e=>{ if(e.ctrlKey && e.key==='s'){ e.preventDefault(); if(saveBtn.style.display!=='none') saveBtn.onclick(); } if(e.ctrlKey && e.key==='z'){ e.preventDefault(); undoBtn.onclick(); } }; renderCats(); renderQs(); saveBtn.style.display='none'; undoBtn.style.display=''; </script> </body> </html>
Save changes
Create folder
writable 0777
Create
Cancel