Skip to main content

SECOND MILESTONE 0 of X: My Pending and Delayed POSTs SUMMARY [SOURCE CODE]

<!------------------------------------------------------->
<!--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&nbsp;</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

Popular posts from this blog

PART 0.1.0 RAD PROTOTYPE Web-App: Post-Video & Comments [program]

Video List — JP Kanji Ultra Translation CONTROL SECTION — Login (Admin) Username: Password: Login CONTROL SECTION — Admin Panel Enable Comments Disable Comments Logout Activity Log Show Video COMMENTS DISABLED BY ADMIN Leave a Comment: Additional Comment Show Video COMMENTS DISABLED BY ADMIN Leave a Comment: Additional Comment Show Video COMMENTS DISABLED BY ADMIN Leave a Comment: Additional Comment Show Video COMMENTS DISABLED BY ADMIN Leave a Comment: Additional Comment

My Pending and Delayed POSTs SUMMARY [APPs]
MADE by ChatGPT

🔗 My Pending and Delayed POSTs SUMMARY Sort by Date Sort by Auto Title Sort by My Title Ascending Descending (Newest First) Insert URL: Your Own Title (Optional): Status: Pending Done ➕ ADD ENTRY 💾 SAVE EDIT (MAIN FORM) DATE / TIME AUTO TITLE MY TITLE STATUS URL ACTIONS 📝 TO DO LIST SUMMARY Sort by Date Sort by Header Sort by Detail ...

Tablet Holder di Mobil dan Konsep DOUBLE Tablet Holder aka +secondary supporting holder

Gw udah pasang Holder khusus Tablet yg menurut gw sudah pilihan terbaik! Karena memiliki Arm KERAS/RIGID yg dibutuhkan utk menggenggam ERAT Dalam hal menopang Tablet yg lebih berat dr HP biasa Cekidot Lapak (click here!!) Namun .. Setelah gw pasang Bukan tidak bagus Tapi kalau melewati jalan jelek GOYANG (sikit) juga Gan! Akan tetapi .... Gw rasa bisa makin dimaksimalkan KERIGIDAN dengan menambah PENOPANG KEDUA Check it out: Dari searching2 di MarketPlace Gw ketemu yg mirip holder lampu belajar zaman doeloe Dan .. namun .. tiba2 gw menemukan Ide (lanjutan) Mekanisme yg bisa diReApplied kalau suatu saat diperlukan di Kreasi Agan2 lain  Gunakan Kombo 2 Perangkat berikut apabila membutuhkan holdingan tablet tambahan yg memiliki  "hold area"  yg lebih sempit karena holder kedua "takutnya/dirasa" tidak akan muat utk menggenggam Tablet sebagai penopang kedua, sebagai akibat holder pertama/utama sudah "cukup banyak" memakan tempat Perangkat Pertama (kon...