Skip to main content

THIRD MILESTONE 4 OF 5
SOURCE CODE: My Pending and Delayed POSTs SUMMARY (Made by ChatGPT)

^^

S O U R C E  C O D E

 <!--PARENT FINAL SNIPPET (urlCrudData)-->

<!--======================================-->

<!--1. GLOBAL STYLES (CSS)-->

<!--======================================-->

<style>

body {

    font-family: Arial, sans-serif;

}

.section-title {

    text-align: center;

    font-size: 26px;

    margin-bottom: 25px;

}

.res-box {

    margin: auto;

    max-width: 900px;

    padding-bottom: 40px;

}

.search-bar {

    width: 100%;

    padding: 10px;

    border-radius: 6px;

    border: 1px solid #aaa;

    margin-bottom: 15px;

}

.sort-box {

    display: flex;

    gap: 10px;

    margin-bottom: 15px;

}

.sort-box select {

    padding: 8px;

    border-radius: 6px;

    border: 1px solid #999;

}

.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;

}

.col-date   { flex: 0 0 18%; max-width: 18%; padding: 5px; }

.col-status { flex: 0 0 10%; max-width: 10%; padding: 5px; text-align:center; }

.col-auto   { flex: 0 0 26%; max-width: 26%; padding: 5px; }

.col-my     { flex: 0 0 26%; max-width: 26%; padding: 5px; }

.col-url    { flex: 0 0 10%; max-width: 10%; padding: 5px; text-align:center; }

.col-act    { flex: 0 0 10%; max-width: 10%; padding: 5px; text-align:center; }

.link-btn {

    background: #0078ff;

    color: white;

    padding: 6px 12px;

    border-radius: 6px;

    text-decoration: none;

    display: inline-block;

}

.icon-btn {

    background: none;

    border: none;

    cursor: pointer;

    font-size: 20px;

    margin: 6px;

}

.icon-edit  { color: #ffaa00; }

.icon-del   { color: #ff4444; }

.done-row {

    background: #c2e6c2;

}

.inline-edit-row {

    display: none;

    width: 100%;

    box-sizing: border-box;

}

.inline-edit-inner {

    background: #f4f4f4;

    border: 1px solid #ccc;

    border-radius: 8px;

    padding: 10px;

    margin: 8px 0 4px 0;

}

.inline-edit-inner b {

    display: block;

    margin-bottom: 6px;

}

.inline-edit-inner input,

.inline-edit-inner textarea,

.inline-edit-inner select {

    width: 100%;

    padding: 6px;

    margin: 4px 0 10px 0;

    box-sizing: border-box;

    border-radius: 5px;

    border: 1px solid #aaa;

}

.inline-btn-row {

    display: flex;

    gap: 10px;

    flex-wrap: wrap;

}

.status-box {

    display: flex;

    align-items: center;

    gap: 25px;

    padding: 8px 14px;

    border: 1px solid #ccc;

    border-radius: 10px;

    background: #f5f5f5;

    width: max-content;

    margin: 6px 0;

}

.status-box label {

    display: flex;

    align-items: center;

    gap: 6px;

    font-size: 15px;

    white-space: nowrap;

}

.inline-edit-inner .status-box {

    margin-top: 10px;

}

@media (max-width: 768px) {

    .col-date,

    .col-status,

    .col-auto,

    .col-my,

    .col-url,

    .col-act {

        flex: 0 0 100%;

        max-width: 100%;

        text-align: left;

    }

}

</style>


<!--======================================-->

<!--2. FIREBASE CDN-->

<!--======================================-->

<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>


<!--======================================-->

<!--3. FIREBASE CONFIG + HELPERS-->

<!--======================================-->

<script>

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");


function nowDateTime() {

    const d  = new Date();

    const yy = d.getFullYear();

    const mm = String(d.getMonth() + 1).padStart(2, "0");

    const dd = String(d.getDate()).padStart(2, "0");

    const hh = String(d.getHours()).padStart(2, "0");

    const mi = String(d.getMinutes()).padStart(2, "0");

    const ss = String(d.getSeconds()).padStart(2, "0");

    return yy + "-" + mm + "-" + dd + " " + hh + ":" + mi + ":" + ss;

}

function todayLong() {

    return new Date().toLocaleString("en-US", {

        month: "short",

        day: "2-digit",

        year: "numeric"

    });

}

function formatDateWithFallback(val) {

    if (!val) return "";

    if (val.includes(":")) return val;

    return val + " 00:00:00";

}

function parseDateSafe(val) {

    if (!val) return 0;

    const t = Date.parse(val);

    if (!isNaN(t)) return t;

    return 0;

}

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, function(m){ return m.toUpperCase(); });

    } catch (e) {

        return url;

    }

}

function guessTitle(url) {

    return url.replace("https://", "").replace("http://", "").split("/")[0];

}

</script>


<!--======================================-->

<!--PARENT MODULE — urlCrudData (Pending)-->

<!--======================================-->


<div class="res-box">

    <h2 class="section-title" id="todayHeader"></h2>

    <h2 style="text-align: center;">šŸ”— My Pending and Delayed POSTs SUMMARY</h2>


    <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 selected="" value="desc">Descending (Newest First)</option>

        </select>

    </div>


    <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 />


        <b>Status:</b><br />

        <div class="status-box">

            <label>

                <input checked="" name="statusCRUD" type="radio" value="PENDING" /> Pending

            </label>

            <label>

                <input name="statusCRUD" type="radio" value="DONE" /> Done

            </label>

        </div>


        <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 (MAIN FORM)

        </button>

    </div>


    <div class="responsive-table">

        <div class="responsive-row responsive-head">

            <div class="col-date">DATE / TIME</div>

            <div class="col-auto">AUTO TITLE</div>

            <div class="col-my">MY TITLE</div>

            <div class="col-status">STATUS</div>

            <div class="col-url">URL</div>

            <div class="col-act">ACTIONS</div>

        </div>

        <div id="tableBodyCRUD"></div>

    </div>

</div>


<script>

document.getElementById("todayHeader").innerHTML = "šŸ“… Today: " + todayLong();


let crudData = [];

let currentEditID_CRUD = null;


refCRUD.on("value", function(snap){

    crudData = snap.val() ? Object.values(snap.val()) : [];

    renderCRUD();

});


document.getElementById("searchCRUD").oninput    = renderCRUD;

document.getElementById("sortByCRUD").onchange   = renderCRUD;

document.getElementById("sortOrderCRUD").onchange= renderCRUD;


function getStatusCRUD(){

    const radios = document.querySelectorAll('input[name="statusCRUD"]');

    for (const r of radios) {

        if (r.checked) return r.value;

    }

    return "PENDING";

}

function findCRUDById(id){

    return crudData.find(function(e){ return e.id === id; }) || null;

}

function closeAllInlineCRUD(){

    crudData.forEach(function(e){

        const box = document.getElementById("inlineCRUD-" + e.id);

        if (box) box.style.display = "none";

    });

}


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(function(e){

        const autoT = (e.autoTitle || "").toLowerCase();

        const myT   = (e.myTitle   || "").toLowerCase();

        const url   = (e.url       || "").toLowerCase();

        return autoT.includes(search) || myT.includes(search) || url.includes(search);

    });


    data.sort(function(a,b){

        if (sortBy === "date") {

            const x = parseDateSafe(a.date);

            const y = parseDateSafe(b.date);

            return (order === "asc") ? (x - y) : (y - x);

        } else {

            let x = (a[sortBy] || "").toString().toLowerCase();

            let y = (b[sortBy] || "").toString().toLowerCase();

            return (order === "asc") ? x.localeCompare(y) : y.localeCompare(x);

        }

    });


    let html = "";

    data.forEach(function(e){

        const statusLabel = e.status || "PENDING";

        const rowClass    = (statusLabel === "DONE") ? "responsive-row done-row" : "responsive-row";


        html += ""

        + "<div class='" + rowClass + "'>"

        +   "<div class='col-date'>" + formatDateWithFallback(e.date) + "</div>"

        +   "<div class='col-auto' style='font-weight:bold;'>" + (e.autoTitle || "") + "</div>"

        +   "<div class='col-my'>"   + (e.myTitle   || "") + "</div>"

        +   "<div class='col-status'><span>" + statusLabel + "</span></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=\"openInlineCRUD('" + e.id + "')\">✏</button>"

        +       "<button class='icon-btn icon-del'  onclick=\"deleteCRUD('" + e.id + "')\">šŸ—‘</button>"

        +   "</div>"

        + "</div>"

        + "<div class='inline-edit-row' id='inlineCRUD-" + e.id + "'>"

        +   "<div class='inline-edit-inner'>"

        +       "<b>Inline Edit — Pending POST</b>"

        +       "<label>URL:</label>"

        +       "<input id='inlineCRUD-url-" + e.id + "' value='" + (e.url || "") + "' />"

        +       "<label>My Title:</label>"

        +       "<input id='inlineCRUD-myTitle-" + e.id + "' value='" + (e.myTitle || "") + "' />"

        +       "<label>Status:</label>"

        +       "<div class='status-box'>"

        +         "<label><input type='radio' name='inlineCRUD-status-" + e.id + "' value='PENDING'" + (statusLabel === "PENDING" ? " checked" : "") + "> Pending</label>"

        +         "<label><input type='radio' name='inlineCRUD-status-" + e.id + "' value='DONE'"    + (statusLabel === "DONE"    ? " checked" : "") + "> Done</label>"

        +       "</div>"

        +       "<div class='inline-btn-row'>"

        +           "<button onclick=\"saveInlineCRUD('" + e.id + "')\">šŸ’¾ Save Inline</button>"

        +           "<button onclick=\"closeInlineCRUD('" + e.id + "')\">✖ Cancel</button>"

        +       "</div>"

        +   "</div>"

        + "</div>";

    });


    document.getElementById("tableBodyCRUD").innerHTML = html;

}


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;

    let status = getStatusCRUD();


    refCRUD.child(key).set({

        id:        key,

        date:      nowDateTime(),

        autoTitle: autoT,

        myTitle:   myT,

        url:       url,

        status:    status

    });


    document.getElementById("urlInputCRUD").value     = "";

    document.getElementById("myTitleInputCRUD").value = "";

}


function openInlineCRUD(id){

    const rec = findCRUDById(id);

    if (!rec) return;


    currentEditID_CRUD = id;

    closeAllInlineCRUD();


    const box = document.getElementById("inlineCRUD-" + id);

    if (box) box.style.display = "block";


    const urlInput = document.getElementById("inlineCRUD-url-" + id);

    const myInput  = document.getElementById("inlineCRUD-myTitle-" + id);

    if (urlInput) urlInput.value = rec.url || "";

    if (myInput)  myInput.value  = rec.myTitle || "";


    const radios = document.querySelectorAll("input[name='inlineCRUD-status-" + id + "']");

    radios.forEach(function(r){

        r.checked = (r.value === (rec.status || "PENDING"));

    });


    document.getElementById("urlInputCRUD").value     = rec.url || "";

    document.getElementById("myTitleInputCRUD").value = rec.myTitle || "";

    document.getElementById("saveBtnCRUD").style.display = "inline-block";


    const mainStatus = rec.status || "PENDING";

    const mainRadios = document.querySelectorAll('input[name="statusCRUD"]');

    mainRadios.forEach(function(r){

        r.checked = (r.value === mainStatus);

    });

}


function closeInlineCRUD(id){

    const box = document.getElementById("inlineCRUD-" + id);

    if (box) box.style.display = "none";

}


function saveEditCRUD(){

    if (!currentEditID_CRUD){

        alert("No record selected for editing (click ✏ Edit first).");

        return;

    }

    let newUrl    = document.getElementById("urlInputCRUD").value.trim();

    let newMyT    = document.getElementById("myTitleInputCRUD").value.trim();

    let newStatus = getStatusCRUD();


    refCRUD.child(currentEditID_CRUD).update({

        url:       newUrl,

        myTitle:   newMyT,

        autoTitle: isBlog(newUrl) ? blogTitle(newUrl) : guessTitle(newUrl),

        status:    newStatus

    });


    currentEditID_CRUD = null;

    document.getElementById("urlInputCRUD").value     = "";

    document.getElementById("myTitleInputCRUD").value = "";

    document.getElementById("saveBtnCRUD").style.display = "none";

    closeAllInlineCRUD();

}


function saveInlineCRUD(id){

    const urlInput = document.getElementById("inlineCRUD-url-" + id);

    const myInput  = document.getElementById("inlineCRUD-myTitle-" + id);

    if (!urlInput || !myInput) return;


    const radios = document.querySelectorAll("input[name='inlineCRUD-status-" + id + "']");

    let st = "PENDING";

    radios.forEach(function(r){

        if (r.checked) st = r.value;

    });


    const newUrl = urlInput.value.trim();

    const newMyT = myInput.value.trim();


    refCRUD.child(id).update({

        url:       newUrl,

        myTitle:   newMyT,

        autoTitle: isBlog(newUrl) ? blogTitle(newUrl) : guessTitle(newUrl),

        status:    st

    });


    currentEditID_CRUD = null;

    document.getElementById("urlInputCRUD").value     = "";

    document.getElementById("myTitleInputCRUD").value = "";

    document.getElementById("saveBtnCRUD").style.display = "none";

    closeInlineCRUD(id);

}


function deleteCRUD(id){

    if (confirm("Delete this entry?")){

        refCRUD.child(id).remove();

    }

}

</script>


Comments