diff options
| -rw-r--r-- | public/views/dashboard.html | 15 | ||||
| -rw-r--r-- | public/views/editPost.html | 137 | ||||
| -rw-r--r-- | routes/admin.js | 31 | ||||
| -rw-r--r-- | routes/blog.js | 49 | ||||
| -rw-r--r-- | routes/index.js | 3 | ||||
| -rw-r--r-- | routes/posts.js | 1 | ||||
| -rw-r--r-- | static/assets/js/pages/publish.js | 75 |
7 files changed, 294 insertions, 17 deletions
diff --git a/public/views/dashboard.html b/public/views/dashboard.html index 8692bb4..03dd653 100644 --- a/public/views/dashboard.html +++ b/public/views/dashboard.html @@ -18,13 +18,13 @@ <div class="container"> <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"></button> - <a class="brand" href="../">That Computer Scientist</a> + <a class="brand" href="/">That Computer Scientist</a> <div class="nav-collapse collapse"> <ul class="nav"> - <li><a href="../">Home</a></li> - <li><a href="../about">About</a></li> - <li><a href="../repos">Repositories</a></li> - <li class="active"><a href="./">Administration</a></li> + <li><a href="/">Home</a></li> + <li><a href="/about">About</a></li> + <li><a href="/repos">Repositories</a></li> + <li class="active"><a href="/admin">Administration</a></li> </ul> </div> </div> @@ -35,7 +35,7 @@ <div class="row"> <div class="span3 bs-docs-sidebar"> <ul class="nav nav-list bs-docs-sidenav affix-top"> - <li class="active"><a href="../admin/dashboard">All Posts</a></li> + <li class="active"><a href="/admin/dashboard">All Posts</a></li> <li><a href="/admin/dashboard/new">Add Post</a></li> <li><a href="#">Manage Comments</a></li> <li><a href="#">Manage Users</a></li> @@ -87,6 +87,7 @@ editButton.className = 'btn btn-primary'; editButton.innerHTML = 'Edit Post'; editButton.style.marginRight = '15px'; + editButton.href = `/admin/dashboard/edit/${post.slug}`; const deleteButton = document.createElement('a'); deleteButton.className = 'btn btn-danger'; deleteButton.innerHTML = 'Delete Post'; @@ -101,7 +102,7 @@ leadParagraphCotainer.appendChild(editButtonContainer); posts.appendChild(leadParagraphCotainer); }) - }, + }, error: (err) => { console.log(err); } diff --git a/public/views/editPost.html b/public/views/editPost.html new file mode 100644 index 0000000..371b455 --- /dev/null +++ b/public/views/editPost.html @@ -0,0 +1,137 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="UTF-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link href="/static/assets/css/bootstrap.css" rel="stylesheet"> + <link href="/static/assets/css/bootstrap-responsive.css" rel="stylesheet"> + <link rel="stylesheet" + href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.0/styles/base16/seti-ui.min.css"> + <link rel="preconnect" href="https://fonts.googleapis.com"> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> + <link href="https://fonts.googleapis.com/css2?family=Fira+Code&display=swap" rel="stylesheet"> + <link href="/static/assets/css/custom.css" rel="stylesheet"> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" + integrity="sha384-KiWOvVjnN8qwAZbuQyWDIbfCLFhLXNETzBQjA/92pIowpC0d2O3nppDGQVgwd2nB" crossorigin="anonymous"> + <link rel="shortcut icon" href="/static/images/favicon.png"> + <title>Dashboard - Add New Post</title> + <style type="text/css"> + input, + textarea { + width: 100%; + } + + code, + pre { + font-family: 'Fira Code', monospace !important; + font-size: 14px; + background-color: #1c1c1c; + color: #D4D4D5; + } + + pre { + padding: 10px; + } + </style> +</head> + +<body> + <div class="navbar navbar-inverse navbar-fixed-top"> + <div class="navbar-inner"> + <div class="container"> + <button type="button" class="btn btn-navbar" data-toggle="collapse" + data-target=".nav-collapse"></button> + <a class="brand" href="/">That Computer Scientist</a> + <div class="nav-collapse collapse"> + <ul class="nav"> + <li><a href="/">Home</a></li> + <li><a href="/about">About</a></li> + <li><a href="/repos">Repositories</a></li> + <li class="active"><a href="/admin">Administration</a></li> + </ul> + </div> + </div> + </div> + </div> + <div class="container margin-top-375" style="margin-top: 3.75rem;"> + <div class="container"> + <div class="row"> + <div class="span3 bs-docs-sidebar"> + <ul class="nav nav-list bs-docs-sidenav affix-top"> + <li><a href="/admin/dashboard">All Posts</a></li> + <li><a href="/admin/dashboard/new">Add Post</a></li> + <li><a href="#">Manage Comments</a></li> + <li><a href="#">Manage Users</a></li> + <li><a id="logout">Logout</a></li> + </ul> + </div> + <div class="span9"> + <header class="page-header"> + <h1>Editing Post</h1> + </header> + <div class="span9" style="padding: 0; margin: 0;"> + <div id="createPost" class="form"> + <div class="form-group"> + <label for="title">Title</label> + <input type="text" class="form-control" id="title" name="title" placeholder="Title" + style=" margin-left: 0;"> + </div> + <div class="form-group"> + <label for="content">Content</label> + <textarea class="form-control" id="content" name="content" rows="10" + placeholder="Content"></textarea> + </div> + <div class="container"> + <h1 style="margin-left: 0; padding-left: 0; transform: translate(-20px, 0px);">Render + Preview</h1> + <div class="span9" id="renderPreview" + style="padding: 10px 0px; margin: 20px 0px 20px -20px"></div> + </div> + <div class="form-group"> + <label for="tags">Tags</label> + <input type="text" class="form-control" id="tags" name="tags" placeholder="Tags" + style=" margin-left: 0;"> + </div> + <div class="form-group"> + <label for="publishDate">Publish Date</label> + <input type="date" class="form-control" id="publishDate" name="publishDate" + placeholder="Publish Date" style=" margin-left: 0;"> + </div> + <div id="error" class="alert alert-error hidden"> + <strong>Error!</strong> Please fill out all fields. + </div> + <div class="control-group"> + <div class="controls"> + <button type="submit" class="btn btn-primary" id="publishPost">Update + Post</button> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + <script src="https://www.gstatic.com/firebasejs/7.14.1/firebase-app.js"></script> + <script src="https://www.gstatic.com/firebasejs/7.14.1/firebase-auth.js"></script> + <script src="/static/assets/js/jquery.js"></script> + <script src="/static/assets/js/bootstrap-transition.js"></script> + <script src="/static/assets/js/bootstrap-collapse.js"></script> + <script src="/static/assets/js/pages/config.js"></script> + <script src="/static/assets/js/pages/authCheck.js"></script> + <script src="/static/assets/js/marked.js"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.0/highlight.min.js"></script> + <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js" + integrity="sha384-0fdwu/T/EQMsQlrHCCHoH10pkPLlKA1jL5dFyUOvB3lfeT2540/2g6YgSi2BL14p" + crossorigin="anonymous"></script> + <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js" + integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR" + crossorigin="anonymous"></script> + <script> + + </script> +</body> + +</html>
\ No newline at end of file diff --git a/routes/admin.js b/routes/admin.js index b6afab7..260f343 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -1,5 +1,8 @@ const express = require("express"); const router = express.Router(); +const cheerio = require("cheerio"); +const fs = require("fs"); +const firebase = require("../firebase"); router.get("/dashboard", function (req, res) { res.render("dashboard.html"); @@ -7,7 +10,33 @@ router.get("/dashboard", function (req, res) { router.get("/dashboard/new", function (req, res) { res.render("createPost.html"); -}) +}); + +router.get("/dashboard/edit/:slug", function (req, res) { + var html = fs.readFileSync( + __dirname + "/../public/views/editPost.html", + "utf8" + ); + var $ = cheerio.load(html); + const store = firebase.firestore(); + let query = store.collection("posts"); + query = query.where("slug", "==", req.params.slug); + query + .get() + .then(function (querySnapshot) { + querySnapshot.forEach(function (doc) { + $("#title").val(doc.data().title); + $("#content").val(Buffer.from(doc.data().content, "base64").toString()); + $("#tags").val(doc.data().tags); + $("#publishDate").val(doc.data().publishDate); + }); + }) + .then(() => { + const publishScript = `<script src="/static/assets/js/pages/publish.js"></script>`; + $("body").append(publishScript); + res.send($.html()); + }); +}); router.get("/", (req, res) => { // Send admin.html from public folder diff --git a/routes/blog.js b/routes/blog.js index fbdc1f2..8a8cb19 100644 --- a/routes/blog.js +++ b/routes/blog.js @@ -7,13 +7,50 @@ router.get("/posts", (req, res) => { const posts = []; let query = store.collection("posts"); query = query.select("slug", "tags", "title", "shortText", "publishDate"); - query.get().then(function (querySnapshot) { - querySnapshot.forEach(function (doc) { - posts.push(doc.data()); + query + .get() + .then(function (querySnapshot) { + querySnapshot.forEach(function (doc) { + posts.push(doc.data()); + }); + }) + .then(() => { + res.json(posts); + }); +}); + +router.put("/update/:slug", (req, res) => { + const store = firebase.firestore(); + const { title, content, tags, publishDate, shortText, slug } = req.body; + const base64 = Buffer.from(content).toString("base64"); + const post = { + title, + content: base64, + tags: String(tags).split(",").length > 0 ? String(tags).split(",") : [], + publishDate, + shortText, + slug, + }; + let query = store.collection("posts"); + query = query.where("slug", "==", slug); + query + .get() + .then(function (querySnapshot) { + querySnapshot.forEach(function (doc) { + doc.ref.update({ + title: post.title, + content: post.content, + tags: post.tags, + publishDate: post.publishDate, + }); + }); + }) + .then(() => { + res.json({ success: true }); + }) + .catch((err) => { + res.json({ success: false, err }); }); - }).then(() => { - res.json(posts); - }); }); router.post("/new", (req, res) => { diff --git a/routes/index.js b/routes/index.js index 659d50d..605f6ad 100644 --- a/routes/index.js +++ b/routes/index.js @@ -13,8 +13,8 @@ const home = require("./home"); router.use("/admin", admin); router.use("/api/blog", blog); router.use("/", repositories); -router.use("/", posts); router.use("/", home); +router.use("/", posts); // Create the routes @@ -22,6 +22,5 @@ router.get("/about", (req, res) => { res.render("about.html"); }); - // Export the routes module.exports = router; diff --git a/routes/posts.js b/routes/posts.js index bc22670..00b092f 100644 --- a/routes/posts.js +++ b/routes/posts.js @@ -6,7 +6,6 @@ const router = express.Router(); const marked = require("marked"); const hljs = require("highlight.js"); - router.get("/posts/:id", function (req, res) { const id = req.params.id; // get single document where slug === id diff --git a/static/assets/js/pages/publish.js b/static/assets/js/pages/publish.js new file mode 100644 index 0000000..7349fac --- /dev/null +++ b/static/assets/js/pages/publish.js @@ -0,0 +1,75 @@ +window.addEventListener("DOMContentLoaded", () => { + const content = document.getElementById("content"); + const renderPreview = document.getElementById("renderPreview"); + marked.setOptions({ + highlight: function (code) { + return hljs.highlightAuto(code).value; + }, + }); + content.addEventListener("input", () => { + renderPreview.innerHTML = marked.parse(content.value); + renderMathInElement(renderPreview, { + // customised options + // • auto-render specific keys, e.g.: + delimiters: [ + { left: "$$", right: "$$", display: true }, + { left: "$", right: "$", display: false }, + { left: "\\(", right: "\\)", display: false }, + { left: "\\[", right: "\\]", display: true }, + ], + // • rendering keys, e.g.: + throwOnError: false, + }); + }); +}); +$(document).on("click", "#publishPost", () => { + document.getElementById("error").classList.add("hidden"); + const content = $("#content").val(); + const title = $("#title").val(); + const publishDate = $("#publishDate").val(); + const slug = title + .toLowerCase() + .replace(/ /g, "-") + .replace(/[^\w-]+/g, ""); + const tags = $("#tags").val(); + if (title === "" || publishDate === "") { + document.getElementById("error").classList.remove("hidden"); + return; + } else { + // Publish post to api/blog/new + const body = { + title: title, + publishDate: publishDate, + tags: tags, + content: content, + shortText: marked.parse(content.substring(0, 120) + "..."), + slug: slug, + }; + if (window.location.href.includes(slug)) { + // Update post + $.ajax({ + url: `/api/blog/update/${slug}`, + type: "PUT", + data: body, + success: function (data) { + window.location.href = `/posts/${slug}`; + }, + error: function (err) { + console.log(err); + }, + }); + } else { + $.ajax({ + url: "/api/blog/new", + type: "POST", + data: body, + success: (data) => { + window.location.href = "/admin/dashboard"; + }, + error: (err) => { + console.log(err); + }, + }); + } + } +}); |
