AI Survival Blog
AI Survival Blog
Clear reporting, practical preparedness, policy updates, and community discussion.
About
A simple live blog with shared cloud posts and comments.
' +
'';
}
function downloadHtmlFile(filename, htmlContent){
var blob = new Blob([htmlContent], { type: "text/html;charset=utf-8" });
var url = URL.createObjectURL(blob);
var a = document.createElement("a");
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
setTimeout(function(){
URL.revokeObjectURL(url);
}, 1000);
}
function slugify(text){
return String(text || "post")
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "")
.slice(0, 80) || "post";
}
function buildPostHtml(post){
var comments = getSortedComments(post);
var searchTerm = searchInput.value.trim();
var authorHtml = highlightHtmlText(esc(post.author || "Anonymous"), searchTerm);
var categoryHtml = highlightHtmlText(esc(post.category || "General"), searchTerm);
var titleHtml = highlightHtmlText(esc(post.title || "Untitled"), searchTerm);
var contentHtml = highlightHtmlText(linkify(post.content || ""), searchTerm);
return (
'
' +
'' +
(post.image ? '
' : '') +
'' + contentHtml + '
' +
'' +
''
);
}
function renderFeatured(posts){
if (!posts.length) {
featuredStory.className = "featured-story";
featuredStory.innerHTML = "";
return;
}
var post = posts[0];
var excerpt = String(post.content || "");
if (excerpt.length > 260) excerpt = excerpt.slice(0,260) + "...";
var searchTerm = searchInput.value.trim();
featuredStory.className = "featured-story active";
featuredStory.innerHTML =
'
' +
'
Featured
' +
'
' + highlightHtmlText(esc(post.category || "General"), searchTerm) + '
' +
'
' + highlightHtmlText(esc(post.title || "Untitled"), searchTerm) + '
' +
'
By ' + highlightHtmlText(esc(post.author || "Anonymous"), searchTerm) + ' • ' + formatDate(post.createdAt) + ' • ' + getCommentCount(post) + ' comments
' +
'
' + highlightHtmlText(esc(excerpt), searchTerm) + '
' +
'
' +
'' +
'' +
'' +
'' +
'' +
'
' +
'
';
}
function updateSearchMatches(){
currentSearchMatches = Array.prototype.slice.call(document.querySelectorAll(".search-highlight"));
currentSearchIndex = -1;
var term = searchInput.value.trim();
if (!term) {
searchStatus.textContent = "";
return;
}
if (currentSearchMatches.length) {
searchStatus.textContent = currentSearchMatches.length + " occurrence" + (currentSearchMatches.length === 1 ? "" : "s") + " found";
} else {
searchStatus.textContent = "0 occurrences found";
}
}
function goToNextSearchMatch(){
var term = searchInput.value.trim();
if (!term) {
searchStatus.textContent = "Enter a search term first";
return;
}
if (!currentSearchMatches.length) {
searchStatus.textContent = "0 occurrences found";
return;
}
for (var i = 0; i < currentSearchMatches.length; i++) {
currentSearchMatches[i].classList.remove("active");
}
currentSearchIndex = (currentSearchIndex + 1) % currentSearchMatches.length;
var activeMatch = currentSearchMatches[currentSearchIndex];
activeMatch.classList.add("active");
var postEl = activeMatch.closest(".post, .featured-story");
if (postEl) {
postEl.scrollIntoView({ behavior:"smooth", block:"center" });
} else {
activeMatch.scrollIntoView({ behavior:"smooth", block:"center" });
}
searchStatus.textContent = (currentSearchIndex + 1) + " of " + currentSearchMatches.length + " occurrences";
}
function clearSearch(){
searchInput.value = "";
currentSearchMatches = [];
currentSearchIndex = -1;
visiblePosts = 5;
renderPosts();
searchStatus.textContent = "";
searchInput.focus();
}
function renderPosts(){
var posts = getFilteredPosts();
renderFeatured(posts);
postCounter.textContent = "(" + posts.length + (posts.length === 1 ? " post" : " posts") + ")";
if (!posts.length) {
postList.innerHTML = '
No posts found.
';
loadMoreBtn.style.display = "none";
updateSearchMatches();
return;
}
var visibleRenderedPosts = posts.slice(0, visiblePosts);
var html = "";
for (var i = 0; i < visibleRenderedPosts.length; i++) {
html += buildPostHtml(visibleRenderedPosts[i]);
}
postList.innerHTML = html;
loadMoreBtn.style.display = visibleRenderedPosts.length < posts.length ? "inline-block" : "none";
updateSearchMatches();
}
function loadPosts(){
setStatus("Firebase connected. Loading posts...", "ok");
db.ref(POSTS_PATH).on("value", function(snapshot){
allPosts = [];
snapshot.forEach(function(child){
var post = child.val() || {};
post._key = child.key;
allPosts.push(post);
});
renderPosts();
}, function(error){
console.error(error);
setStatus("Connected to Firebase, but could not load blog data. Check Realtime Database rules.", "warn");
postList.innerHTML = '
Could not load posts from Firebase.
';
});
}
postForm.addEventListener("submit", function(e){
e.preventDefault();
var author = document.getElementById("author").value.trim();
var title = document.getElementById("title").value.trim();
var category = document.getElementById("category").value;
var content = document.getElementById("content").value.trim();
var editId = editingPostId.value.trim();
if (!author || !title || !content) {
alert("Please fill in all required fields.");
return;
}
var now = new Date();
if (editId) {
var existingPost = allPosts.find(function(post){ return post._key === editId; });
var updatePayload = {
author: author,
title: title,
category: category,
content: content,
image: selectedImageBase64 !== null ? selectedImageBase64 : ((existingPost && existingPost.image) || ""),
updatedAt: now.toISOString(),
updatedAtMs: now.getTime()
};
db.ref(POSTS_PATH + "/" + editId).update(updatePayload)
.then(function(){
resetFormState();
togglePublishPanel(false);
})
.catch(function(error){
console.error(error);
alert("Could not update post. Check Firebase database permissions.");
});
return;
}
var payload = {
author: author,
title: title,
category: category,
content: content,
image: selectedImageBase64 || "",
status: "published",
createdAt: now.toISOString(),
createdAtMs: now.getTime(),
comments: {}
};
db.ref(POSTS_PATH).push(payload)
.then(function(){
resetFormState();
togglePublishPanel(false);
visiblePosts = Math.max(visiblePosts, 5);
})
.catch(function(error){
console.error(error);
alert("Could not publish post. Check Firebase database permissions.");
});
});
seedDemoBtn.addEventListener("click", function(){
if (allPosts.length > 0) {
var ok = confirm("Demo posts will be added alongside existing posts. Continue?");
if (!ok) return;
}
var demoPosts = [
{
author: "Sofia — Argentina",
title: "Maintaining offline continuity during AI-linked service failures",
category: "Preparedness",
content: "Communities should maintain paper copies of critical contacts, backup payment methods, and manual operating procedures for essential services and local organizations.",
image: "",
status: "published",
createdAt: new Date(Date.now() - 86400000).toISOString(),
createdAtMs: Date.now() - 86400000,
comments: {
c1: {
author: "Omar — Jordan",
text: "Paper copies and offline payment fallback are especially important for small local businesses.",
createdAt: new Date(Date.now() - 7200000).toISOString(),
createdAtMs: Date.now() - 7200000
}
}
},
{
author: "Kareem — UAE",
title: "How to recognize coordinated synthetic influence campaigns",
category: "Threat Watch",
content: "Look for repeated phrasing, synchronized posting schedules, low-quality sourcing, artificial urgency, and unusually uniform account behavior across platforms.",
image: "",
status: "published",
createdAt: new Date(Date.now() - 43200000).toISOString(),
createdAtMs: Date.now() - 43200000,
comments: {}
},
{
author: "Iris — Netherlands",
title: "Why local institutions need fallback procedures for automated decisions",
category: "Policy",
content: "Human review paths and clearly defined override systems can reduce harm from large-scale automation errors in public services and private platforms.",
image: "",
status: "published",
createdAt: new Date().toISOString(),
createdAtMs: Date.now(),
comments: {}
}
];
var pushes = demoPosts.map(function(post){
return db.ref(POSTS_PATH).push(post);
});
Promise.all(pushes).catch(function(error){
console.error(error);
alert("Could not add demo posts.");
});
});
searchInput.addEventListener("input", function(){
visiblePosts = 5;
currentSearchIndex = -1;
renderPosts();
});
searchInput.addEventListener("keydown", function(e){
if (e.key === "Enter") {
e.preventDefault();
goToNextSearchMatch();
}
});
nextSearchBtn.addEventListener("click", function(){
goToNextSearchMatch();
});
clearSearchBtn.addEventListener("click", function(){
clearSearch();
});
categoryFilter.addEventListener("change", function(){
visiblePosts = 5;
currentSearchIndex = -1;
renderPosts();
});
loadMoreBtn.addEventListener("click", function(){
visiblePosts += 5;
renderPosts();
});
window.toggleCommentForm = function(id){
var el = document.getElementById("comment-form-" + id);
if (!el) return;
var isHidden = el.style.display === "none" || !el.style.display;
el.style.display = isHidden ? "grid" : "none";
if (isHidden) {
setTimeout(function(){
el.scrollIntoView({ behavior: "smooth", block: "center" });
var authorInput = document.getElementById("comment-author-" + id);
if (authorInput) {
authorInput.focus();
}
}, 50);
}
};
window.toggleAdminActions = function(id){
var el = document.getElementById("admin-actions-" + id);
if (!el) return;
el.classList.toggle("show");
};
window.editPost = function(id){
var post = allPosts.find(function(item){ return item._key === id; });
if (!post) {
alert("Post not found.");
return;
}
document.getElementById("author").value = post.author || "";
document.getElementById("title").value = post.title || "";
document.getElementById("category").value = post.category || "Preparedness";
document.getElementById("content").value = post.content || "";
editingPostId.value = id;
publishSubmitBtn.textContent = "Update Post";
cancelEditBtn.style.display = "inline-block";
if (post.image) {
selectedImageBase64 = post.image;
imagePreview.src = post.image;
imagePreviewBox.style.display = "block";
} else {
resetImage();
}
togglePublishPanel(true);
};
window.addComment = function(id){
var authorEl = document.getElementById("comment-author-" + id);
var textEl = document.getElementById("comment-text-" + id);
var author = authorEl.value.trim();
var text = textEl.value.trim();
if (!author || !text) {
alert("Please enter your name/region and comment.");
return;
}
var now = new Date();
var commentPayload = {
author: author,
text: text,
createdAt: now.toISOString(),
createdAtMs: now.getTime()
};
db.ref(POSTS_PATH + "/" + id + "/comments").push(commentPayload)
.then(function(){
authorEl.value = "";
textEl.value = "";
})
.catch(function(error){
console.error(error);
alert("Could not post comment.");
});
};
window.deletePost = function(id){
var ok = confirm("Delete this post?");
if (!ok) return;
db.ref(POSTS_PATH + "/" + id).remove()
.catch(function(error){
console.error(error);
alert("Could not delete post.");
});
};
window.scrollToPost = function(id){
var el = document.getElementById("post-" + id);
if (el) {
el.scrollIntoView({ behavior: "smooth", block: "start" });
}
};
window.sharePost = function(title){
var shareText = title + " — " + window.location.href;
if (navigator.share) {
navigator.share({
title: title,
text: title,
url: window.location.href
}).catch(function(){});
} else {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(shareText).then(function(){
alert("Post link copied to clipboard.");
}).catch(function(){
alert("Share this post: " + shareText);
});
} else {
alert("Share this post: " + shareText);
}
}
};
window.copyPostWithReplies = function(id){
var post = allPosts.find(function(item){ return item._key === id; });
if (!post) {
alert("Post not found.");
return;
}
var text = buildPostPlainText(post);
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(function(){
alert("Post and replies copied to clipboard.");
}).catch(function(){
alert("Could not copy automatically. Please try again.");
});
} else {
var temp = document.createElement("textarea");
temp.value = text;
document.body.appendChild(temp);
temp.select();
try {
document.execCommand("copy");
alert("Post and replies copied to clipboard.");
} catch (e) {
alert("Could not copy automatically.");
}
document.body.removeChild(temp);
}
};
window.savePostAsHtml = function(id){
var post = allPosts.find(function(item){ return item._key === id; });
if (!post) {
alert("Post not found.");
return;
}
var html = buildStandalonePostHtml(post);
var filename = slugify(post.title || "post") + ".html";
downloadHtmlFile(filename, html);
};
window.copyPostHtmlToClipboard = function(id){
var post = allPosts.find(function(item){ return item._key === id; });
if (!post) {
alert("Post not found.");
return;
}
var html = buildStandalonePostHtml(post);
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(html).then(function(){
alert("HTML copied to clipboard.");
}).catch(function(){
alert("Could not copy HTML automatically. Please try again.");
});
} else {
var temp = document.createElement("textarea");
temp.value = html;
document.body.appendChild(temp);
temp.select();
try {
document.execCommand("copy");
alert("HTML copied to clipboard.");
} catch (e) {
alert("Could not copy HTML automatically.");
}
document.body.removeChild(temp);
}
};
try {
loadPosts();
} catch (error) {
console.error(error);
setStatus("Firebase setup failed. Check your configuration values.", "warn");
postList.innerHTML = '
Firebase initialization failed.
';
}
No comments yet.
' ) + '