<!------------------------------------------------------->
<!--FIREBASE CDN (COMPAT MODE FOR BLOGGER)-->
<!------------------------------------------------------->
<script src="https://www.gstatic.com/firebasejs/9.22.2/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.22.2/firebase-database-compat.js"></script>
<script>
/* ===================================================== */
/* FIREBASE INITIALIZATION */
/* ===================================================== */
const firebaseConfig = {
apiKey: "AIzaSyAF5r6Rvu-DmoV-vf47wYTZfarpVGmNYR0",
authDomain: "ronin-11938.firebaseapp.com",
databaseURL: "https://ronin-11938-default-rtdb.firebaseio.com",
projectId: "ronin-11938",
storageBucket: "ronin-11938.firebasestorage.app",
messagingSenderId: "823368889742",
appId: "1:823368889742:web:609e16ace214b94a0df"
};
if (!firebase.apps.length) firebase.initializeApp(firebaseConfig);
const rdb = firebase.database();
const refCRUD = rdb.ref("urlCrudData");
const refAPP = rdb.ref("webAppData");
/* DATE HELPERS */
function todayShort(){ return new Date().toLocaleString("en-US",{month:"short",day:"2-digit"}); }
function todayLong(){ return new Date().toLocaleString("en-US",{month:"short",day:"2-digit",year:"numeric"}); }
/* TITLE HELPERS */
function isBlog(url){ return url.includes("ronin1985.blogspot.com"); }
function blogTitle(url){
try {
let last = url.split("/").pop().replace(".html","");
return last.replace(/[-_]+/g," ").replace(/\b\w/g,m=>m.toUpperCase());
} catch { return url; }
}
function guessTitle(url){
return url.replace("https://","").replace("http://","").split("/")[0];
}
</script>
<!------------------------------------------------------->
<!--GLOBAL STYLES (RESPONSIVE FLEX GRID)-->
<!------------------------------------------------------->
<style>
body { font-family: Arial; }
.section-title {
text-align: center; font-size: 26px; margin-bottom: 25px;
}
.res-box {
margin: auto; max-width: 900px;
padding-bottom: 40px;
}
/* SEARCH BAR */
.search-bar {
width: 100%; padding: 10px; border-radius: 6px;
border:1px solid #aaa; margin-bottom: 15px;
}
/* SORT CONTROLS */
.sort-box {
display: flex; gap: 10px; margin-bottom: 15px;
}
.sort-box select {
padding: 8px; border-radius: 6px; border:1px solid #999;
}
/* FLEX TABLE */
.responsive-table { width: 100%; display: block; }
.responsive-row {
display: flex; flex-wrap: wrap;
border-bottom: 1px solid #ccc; padding: 10px 0;
}
.responsive-head {
background: #eee; font-weight: bold;
}
/* COLUMN WIDTHS */
.col-date { flex: 0 0 12%; max-width: 12%; padding: 5px; }
.col-auto { flex: 0 0 30%; max-width: 30%; padding: 5px; }
.col-my { flex: 0 0 30%; max-width: 30%; padding: 5px; }
.col-url { flex: 0 0 12%; max-width: 12%; padding: 5px; text-align:center; }
.col-act { flex: 0 0 16%; max-width: 16%; padding: 5px; text-align:center; }
/* LINK BUTTON */
.link-btn {
background:#0078ff; color:white; padding:6px 12px;
border-radius:6px; text-decoration:none; display:inline-block;
}
/* ICON BUTTONS */
.icon-btn {
background:none; border:none; cursor:pointer;
font-size:20px; margin:6px;
}
.icon-edit { color:#ffaa00; }
.icon-del { color:#ff4444; }
/* MOBILE */
@media(max-width:768px){
.col-date,.col-auto,.col-my,.col-url,.col-act {
flex:0 0 100%; max-width:100%; text-align:left;
}
}
</style>
<!------------------------------------------------------->
<!--===================================================-->
<!--PARENT MODULE — urlCrudData-->
<!--===================================================-->
<!------------------------------------------------------->
<div class="res-box">
<h2 class="section-title" id="todayHeader"></h2>
<h2 style="text-align: center;">🔗 My Pending and Delayed POSTs SUMMARY</h2>
<!--SEARCH + SORT-->
<input class="search-bar" id="searchCRUD" placeholder="Search title or URL…" />
<div class="sort-box">
<select id="sortByCRUD">
<option value="date">Sort by Date</option>
<option value="autoTitle">Sort by Auto Title</option>
<option value="myTitle">Sort by My Title</option>
</select>
<select id="sortOrderCRUD">
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</select>
</div>
<!--INPUT FORM-->
<div style="background: rgb(244, 244, 244); border-radius: 10px; border: 1px solid rgb(204, 204, 204); margin-bottom: 25px; padding: 15px;">
<b>Insert URL:</b><br />
<input id="urlInputCRUD" style="border-radius: 6px; border: 1px solid rgb(170, 170, 170); margin-top: 5px; padding: 10px; width: 100%;" />
<br /><br />
<b>Your Own Title (Optional):</b><br />
<input id="myTitleInputCRUD" style="border-radius: 6px; border: 1px solid rgb(170, 170, 170); margin-top: 5px; padding: 10px; width: 100%;" />
<br /><br />
<button onclick="autoAddCRUD()" style="background: rgb(0, 120, 255); border-radius: 8px; border: none; color: white; padding: 10px 18px;">
➕ ADD ENTRY
</button>
<button id="saveBtnCRUD" onclick="saveEditCRUD()" style="background: rgb(255, 170, 0); border-radius: 8px; border: none; color: white; display: none; padding: 10px 18px;">
💾 SAVE EDIT
</button>
</div>
<!--FLEX TABLE-->
<div class="responsive-table">
<div class="responsive-row responsive-head">
<div class="col-date">DATE</div>
<div class="col-auto">AUTO TITLE</div>
<div class="col-my">MY TITLE</div>
<div class="col-url">URL</div>
<div class="col-act">ACTIONS</div>
</div>
<div id="tableBodyCRUD"></div>
</div>
</div>
<!------------------------------------------------------->
<!--PARENT LOGIC-->
<!------------------------------------------------------->
<script>
document.getElementById("todayHeader").innerHTML = "📅 Today: " + todayLong();
let crudData = [];
/* REALTIME LISTENER */
refCRUD.on("value", snap=>{
crudData = snap.val() ? Object.values(snap.val()) : [];
renderCRUD();
});
/* SEARCH + SORT HANDLER */
document.getElementById("searchCRUD").oninput = renderCRUD;
document.getElementById("sortByCRUD").onchange = renderCRUD;
document.getElementById("sortOrderCRUD").onchange = renderCRUD;
/* MASTER RENDER FUNCTION */
function renderCRUD(){
let search = document.getElementById("searchCRUD").value.toLowerCase();
let sortBy = document.getElementById("sortByCRUD").value;
let order = document.getElementById("sortOrderCRUD").value;
let data = crudData.filter(e =>
(e.autoTitle.toLowerCase().includes(search) ||
(e.myTitle||"").toLowerCase().includes(search) ||
e.url.toLowerCase().includes(search))
);
data.sort((a,b)=>{
let x=a[sortBy]||"", y=b[sortBy]||"";
return order==="asc" ? x.localeCompare(y) : y.localeCompare(x);
});
document.getElementById("tableBodyCRUD").innerHTML =
data.map(e=>`
<div class="responsive-row">
<div class="col-date">${e.date}</div>
<div class="col-auto" style="font-weight:bold;">${e.autoTitle}</div>
<div class="col-my">${e.myTitle||""}</div>
<div class="col-url">
<a href="${e.url}" target="_blank" class="link-btn">LINK</a>
</div>
<div class="col-act">
<button class="icon-btn icon-edit" onclick="editCRUD('${e.id}')">✏</button>
<button class="icon-btn icon-del" onclick="deleteCRUD('${e.id}')">🗑</button>
</div>
</div>`).join("");
}
/* ADD */
function autoAddCRUD(){
let url = document.getElementById("urlInputCRUD").value.trim();
let myT = document.getElementById("myTitleInputCRUD").value.trim();
if(!url){ alert("URL cannot be empty."); return; }
let autoT = isBlog(url)? blogTitle(url) : guessTitle(url);
let key = refCRUD.push().key;
refCRUD.child(key).set({
id:key, date:todayShort(),
autoTitle:autoT, myTitle:myT,
url:url
});
document.getElementById("urlInputCRUD").value="";
document.getElementById("myTitleInputCRUD").value="";
}
/* EDIT */
let editID_CRUD = null;
function editCRUD(id){
refCRUD.child(id).once("value", snap=>{
let d=snap.val();
editID_CRUD=id;
document.getElementById("urlInputCRUD").value=d.url;
document.getElementById("myTitleInputCRUD").value=d.myTitle||"";
document.getElementById("saveBtnCRUD").style.display="inline-block";
});
}
function saveEditCRUD(){
if(!editID_CRUD) return;
let newUrl=document.getElementById("urlInputCRUD").value.trim();
let newMyT=document.getElementById("myTitleInputCRUD").value.trim();
refCRUD.child(editID_CRUD).update({
url:newUrl,
myTitle:newMyT,
autoTitle: isBlog(newUrl)? blogTitle(newUrl) : guessTitle(newUrl)
});
editID_CRUD=null;
document.getElementById("urlInputCRUD").value="";
document.getElementById("myTitleInputCRUD").value="";
document.getElementById("saveBtnCRUD").style.display="none";
}
/* DELETE */
function deleteCRUD(id){
if(confirm("Delete this entry?")) refCRUD.child(id).remove();
}
</script>
<!------------------------------------------------------->
<!--===================================================-->
<!--CHILD MODULE — webAppData-->
<!--===================================================-->
<!------------------------------------------------------->
<div class="res-box">
<h2 class="section-title" style="text-align: center;">📝 TO DO LIST SUMMARY </h2>
<!--SEARCH + SORT-->
<input class="search-bar" id="searchAPP" placeholder="Search header or detail…" />
<div class="sort-box">
<select id="sortByAPP">
<option value="date">Sort by Date</option>
<option value="header">Sort by Header</option>
<option value="detail">Sort by Detail</option>
</select>
<select id="sortOrderAPP">
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</select>
</div>
<!--FORM-->
<div style="background: rgb(244, 244, 244); border-radius: 10px; border: 1px solid rgb(204, 204, 204); margin-bottom: 25px; padding: 15px;">
<b>Header (Title):</b><br />
<input id="headerInputAPP" style="border-radius: 6px; border: 1px solid rgb(170, 170, 170); margin-top: 5px; padding: 10px; width: 100%;" />
<br /><br />
<b>Detail:</b><br />
<textarea id="detailInputAPP" style="border-radius: 6px; border: 1px solid rgb(170, 170, 170); height: 80px; margin-top: 5px; padding: 10px; width: 100%;"></textarea>
<br /><br />
<button onclick="addAPP()" style="background: rgb(0, 120, 255); border-radius: 8px; border: none; color: white; padding: 10px 18px;">
➕ ADD ENTRY
</button>
<button id="saveBtnAPP" onclick="saveAPP()" style="background: rgb(255, 170, 0); border-radius: 8px; border: none; color: white; display: none; padding: 10px 18px;">
💾 SAVE EDIT
</button>
</div>
<!--FLEX TABLE-->
<div class="responsive-table">
<div class="responsive-row responsive-head">
<div class="col-date">DATE</div>
<div class="col-auto">HEADER</div>
<div class="col-my">DETAIL</div>
<div class="col-act">ACTIONS</div>
</div>
<div id="tableBodyAPP"></div>
</div>
</div>
<!------------------------------------------------------->
<!--CHILD LOGIC-->
<!------------------------------------------------------->
<script>
let appData=[];
/* LIVE LISTENER */
refAPP.on("value", snap=>{
appData = snap.val()? Object.values(snap.val()) : [];
renderAPP();
});
/* SEARCH + SORT LISTENERS */
document.getElementById("searchAPP").oninput=renderAPP;
document.getElementById("sortByAPP").onchange=renderAPP;
document.getElementById("sortOrderAPP").onchange=renderAPP;
/* MAIN RENDER */
function renderAPP(){
let search=document.getElementById("searchAPP").value.toLowerCase();
let sortBy=document.getElementById("sortByAPP").value;
let order=document.getElementById("sortOrderAPP").value;
let data = appData.filter(e =>
(e.header.toLowerCase().includes(search) ||
e.detail.toLowerCase().includes(search))
);
data.sort((a,b)=>{
let x=a[sortBy]||"", y=b[sortBy]||"";
return order==="asc"? x.localeCompare(y) : y.localeCompare(x);
});
document.getElementById("tableBodyAPP").innerHTML =
data.map(e=>`
<div class="responsive-row">
<div class="col-date">${e.date}</div>
<div class="col-auto" style="font-weight:bold;">${e.header}</div>
<div class="col-my">${e.detail}</div>
<div class="col-act">
<button class="icon-btn icon-edit" onclick="editAPP('${e.id}')">✏</button>
<button class="icon-btn icon-del" onclick="deleteAPP('${e.id}')">🗑</button>
</div>
</div>
`).join("");
}
/* ADD */
function addAPP(){
let h=document.getElementById("headerInputAPP").value.trim();
let d=document.getElementById("detailInputAPP").value.trim();
if(!h){ alert("Header cannot be empty."); return; }
let key=refAPP.push().key;
refAPP.child(key).set({
id:key, date:todayShort(),
header:h, detail:d
});
document.getElementById("headerInputAPP").value="";
document.getElementById("detailInputAPP").value="";
}
/* EDIT */
let editID_APP=null;
function editAPP(id){
refAPP.child(id).once("value", snap=>{
let v=snap.val();
editID_APP=id;
document.getElementById("headerInputAPP").value=v.header;
document.getElementById("detailInputAPP").value=v.detail;
document.getElementById("saveBtnAPP").style.display="inline-block";
});
}
/* SAVE EDIT */
function saveAPP(){
if(!editID_APP) return;
let h=document.getElementById("headerInputAPP").value.trim();
let d=document.getElementById("detailInputAPP").value.trim();
refAPP.child(editID_APP).update({ header:h, detail:d });
editID_APP=null;
document.getElementById("headerInputAPP").value="";
document.getElementById("detailInputAPP").value="";
document.getElementById("saveBtnAPP").style.display="none";
}
/* DELETE */
function deleteAPP(id){
if(confirm("Delete entry?")) refAPP.child(id).remove();
}
</script>
Comments