+
Add a post
+
-
+
diff --git a/main.js b/main.js
index 0273890d..055c32f0 100644
--- a/main.js
+++ b/main.js
@@ -1,3 +1,6 @@
+import { commentEl } from './commentEl.js';
+import { postEl } from './postEl.js';
+
const main = document.querySelector('.main');
const posts = document.querySelector('.posts');
const postForm = document.querySelector('.post-form');
@@ -5,33 +8,78 @@ const postForm = document.querySelector('.post-form');
main.addEventListener('click', (e) => {
e.preventDefault();
if (e.target.classList.contains('add-post')) {
- appendToMain(posts, createPostElement(getPostInput()));
+ posts.appendChild(createPostEl(getPostInput()));
clearInput();
}
-})
+ if (e.target.classList.contains('delete-btn')) {
+
+ }
+ if (e.target.classList.contains('show-comments')) {
+ showComments(e.target);
+ }
+});
function getPostInput() {
- return Array.from(postForm.querySelectorAll('input')).reduce((struct, current) => {
- struct[current.name] = current.value;
- return struct;
- }, {})
+ return Array.from(postForm.querySelectorAll('.form-control')).reduce(
+ (struct, current) => {
+ struct[current.name] = current.value;
+ return struct;
+ },
+ {}
+ );
}
function clearInput() {
- postForm.querySelectorAll('input').forEach(input => {
+ postForm.querySelectorAll('.form-control').forEach((input) => {
input.value = '';
- })
+ });
}
-function createPostElement(obj) {
- const el = document.createElement('div');
- el.classList.add('py-3')
- el.appendChild(document.createTextNode(`${obj.text} - Posted by: ${obj.name}`));
+function createPostEl(obj) {
+ const el = buildFragment(postEl);
+ el.querySelector('.card-title').innerText = `${obj.title}`;
+ el.querySelector('.card-subtitle').innerText = `Posted by: ${obj.name}`;
+ el.querySelector('.card-text').innerText = `${obj.text}`;
+ el.lastChild.appendChild(buildFragment(commentEl));
return el;
}
-function appendToMain(domElement, htmlElement) {
- return domElement.appendChild(htmlElement);
+function showComments(eventTarget) {
+ if (eventTarget.classList.contains('d-none'))
+ console.log(event)
}
+function buildFragment(arrayObj) {
+ const fr = new DocumentFragment();
+
+ arrayObj.forEach((obj) => {
+ fr.appendChild(buildElement(obj));
+ });
+
+ function buildElement(obj) {
+ const el = document.createElement(obj.type);
+ if (obj.attributes) {
+ for (const key in obj.attributes) {
+ const a = document.createAttribute(key);
+ a.value = obj.attributes[key];
+ el.setAttributeNode(a);
+ }
+ }
+
+ if (obj.children) {
+ if (typeof obj.children[0] === 'string') {
+ const newContent = document.createTextNode(obj.children);
+ el.appendChild(newContent);
+ } else {
+ obj.children.forEach((element) => {
+ const child = buildElement(element);
+ el.appendChild(child);
+ });
+ }
+ }
+ return el;
+ }
+
+ return fr;
+}
diff --git a/postEl.js b/postEl.js
new file mode 100644
index 00000000..553cb427
--- /dev/null
+++ b/postEl.js
@@ -0,0 +1,33 @@
+export const postEl = [
+ {
+ type: 'div',
+ attributes: { class: 'card mb-3' },
+ children: [
+ {
+ type: 'div',
+ attributes: { class: 'card-body' },
+ children: [
+ {
+ type: 'h5',
+ attributes: { class: 'card-title' },
+ },
+ {
+ type: 'h6',
+ attributes: { class: 'card-subtitle mb-2 text-body-secondary' },
+ },
+ { type: 'p', attributes: { class: 'card-text' } },
+ {
+ type: 'a',
+ attributes: { class: 'card-link delete-btn' },
+ children: ['delete'],
+ },
+ {
+ type: 'a',
+ attributes: { class: 'card-link show-comments' },
+ children: ['comments'],
+ },
+ ],
+ },
+ ],
+ },
+];
From dac2ef4d8b21618cbcea8ce12eb567b70fec6414 Mon Sep 17 00:00:00 2001
From: Tom Winskell <129330818+tomwinskell@users.noreply.github.com>
Date: Mon, 3 Feb 2025 17:56:48 -0500
Subject: [PATCH 04/16] Comments being posted but not in the correct place in
the DOM. Therefore show hide does not currently work on comments.
---
commentEl.js | 14 +++++++-------
main.js | 34 +++++++++++++++++++++++++++-------
2 files changed, 34 insertions(+), 14 deletions(-)
diff --git a/commentEl.js b/commentEl.js
index 606e1ed3..3e566c4a 100644
--- a/commentEl.js
+++ b/commentEl.js
@@ -1,18 +1,18 @@
export const commentEl = [
{
- type: 'div',
- attributes: { class: 'm-3 d' },
+ type: 'form',
+ attributes: { class: 'mt-2 d-none comment-form' },
children: [
{
type: 'div',
- attributes: { class: 'mb-3' },
+ attributes: { class: 'mb-2' },
children: [
{
type: 'input',
attributes: {
type: 'text',
name: 'name',
- placeholder: 'name',
+ placeholder: 'Name',
class: 'form-control',
},
},
@@ -20,14 +20,14 @@ export const commentEl = [
},
{
type: 'div',
- attributes: { class: 'mb-3' },
+ attributes: { class: 'mb-2' },
children: [
{
type: 'input',
attributes: {
type: 'text',
name: 'comment',
- placeholder: 'comment',
+ placeholder: 'Comment',
class: 'form-control',
},
},
@@ -35,7 +35,7 @@ export const commentEl = [
},
{
type: 'button',
- attributes: { class: 'btn btn-primary' },
+ attributes: { class: 'btn btn-primary add-comment' },
children: ['Comment'],
},
],
diff --git a/main.js b/main.js
index 055c32f0..5ab070b9 100644
--- a/main.js
+++ b/main.js
@@ -8,19 +8,31 @@ const postForm = document.querySelector('.post-form');
main.addEventListener('click', (e) => {
e.preventDefault();
if (e.target.classList.contains('add-post')) {
- posts.appendChild(createPostEl(getPostInput()));
+ posts.appendChild(createPostEl(getFormInput(postForm)));
clearInput();
}
if (e.target.classList.contains('delete-btn')) {
-
+ deletePost(e.target);
}
if (e.target.classList.contains('show-comments')) {
showComments(e.target);
}
+ if (e.target.classList.contains('add-comment')) {
+ addComment(e.target);
+ }
});
-function getPostInput() {
- return Array.from(postForm.querySelectorAll('.form-control')).reduce(
+function addComment(eventTarget) {
+ const formEl = eventTarget.closest('form');
+ const parent = eventTarget.closest('.card-body')
+ const obj = getFormInput(formEl);
+ const comment = buildFragment([{type: 'p'}]);
+ comment.querySelector('p').innerText = `${obj.comment} - Posted by: ${obj.name}`;
+ parent.insertBefore(comment, formEl);
+}
+
+function getFormInput(formElement) {
+ return Array.from(formElement.querySelectorAll('.form-control')).reduce(
(struct, current) => {
struct[current.name] = current.value;
return struct;
@@ -40,13 +52,21 @@ function createPostEl(obj) {
el.querySelector('.card-title').innerText = `${obj.title}`;
el.querySelector('.card-subtitle').innerText = `Posted by: ${obj.name}`;
el.querySelector('.card-text').innerText = `${obj.text}`;
- el.lastChild.appendChild(buildFragment(commentEl));
+ el.querySelector('.card-body').appendChild(buildFragment(commentEl));
return el;
}
function showComments(eventTarget) {
- if (eventTarget.classList.contains('d-none'))
- console.log(event)
+ const cl = eventTarget.nextSibling.classList;
+ if (cl.contains('d-none')) {
+ cl.remove('d-none');
+ } else {
+ cl.add('d-none');
+ }
+}
+
+function deletePost(eventTarget) {
+ eventTarget.closest('.card').remove();
}
function buildFragment(arrayObj) {
From b4bc1e5c3199a2747dda87cd0129445c4b0ebcf1 Mon Sep 17 00:00:00 2001
From: Tom Winskell <129330818+tomwinskell@users.noreply.github.com>
Date: Mon, 3 Feb 2025 17:59:46 -0500
Subject: [PATCH 05/16] User can post and add comments, comments can be shown
or hidden, post can be deleted.
---
main.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/main.js b/main.js
index 5ab070b9..1688820f 100644
--- a/main.js
+++ b/main.js
@@ -24,11 +24,10 @@ main.addEventListener('click', (e) => {
function addComment(eventTarget) {
const formEl = eventTarget.closest('form');
- const parent = eventTarget.closest('.card-body')
const obj = getFormInput(formEl);
const comment = buildFragment([{type: 'p'}]);
comment.querySelector('p').innerText = `${obj.comment} - Posted by: ${obj.name}`;
- parent.insertBefore(comment, formEl);
+ formEl.insertBefore(comment, formEl.firstChild);
}
function getFormInput(formElement) {
From 278652269c583207b4c374179317f6d582363215 Mon Sep 17 00:00:00 2001
From: Tom Winskell <129330818+tomwinskell@users.noreply.github.com>
Date: Tue, 4 Feb 2025 11:49:20 -0500
Subject: [PATCH 06/16] Add readme
---
commentEl.js | 2 +-
index.html | 4 ++--
main.js | 11 +++++++----
postEl.js | 8 ++++----
readme.md | 24 ++++++++++++++++++++++++
5 files changed, 38 insertions(+), 11 deletions(-)
create mode 100644 readme.md
diff --git a/commentEl.js b/commentEl.js
index 3e566c4a..4665209f 100644
--- a/commentEl.js
+++ b/commentEl.js
@@ -36,7 +36,7 @@ export const commentEl = [
{
type: 'button',
attributes: { class: 'btn btn-primary add-comment' },
- children: ['Comment'],
+ children: ['Add Comment'],
},
],
},
diff --git a/index.html b/index.html
index 07d47eff..8e5e59ff 100644
--- a/index.html
+++ b/index.html
@@ -23,7 +23,7 @@
ReReddit
diff --git a/main.js b/main.js
index 1688820f..ffeabc00 100644
--- a/main.js
+++ b/main.js
@@ -9,7 +9,6 @@ main.addEventListener('click', (e) => {
e.preventDefault();
if (e.target.classList.contains('add-post')) {
posts.appendChild(createPostEl(getFormInput(postForm)));
- clearInput();
}
if (e.target.classList.contains('delete-btn')) {
deletePost(e.target);
@@ -31,17 +30,19 @@ function addComment(eventTarget) {
}
function getFormInput(formElement) {
- return Array.from(formElement.querySelectorAll('.form-control')).reduce(
+ const input = Array.from(formElement.querySelectorAll('.form-control')).reduce(
(struct, current) => {
struct[current.name] = current.value;
return struct;
},
{}
);
+ clearInput(formElement);
+ return input;
}
-function clearInput() {
- postForm.querySelectorAll('.form-control').forEach((input) => {
+function clearInput(formElement) {
+ formElement.querySelectorAll('.form-control').forEach((input) => {
input.value = '';
});
}
@@ -59,8 +60,10 @@ function showComments(eventTarget) {
const cl = eventTarget.nextSibling.classList;
if (cl.contains('d-none')) {
cl.remove('d-none');
+ eventTarget.innerText = 'Hide Comments'
} else {
cl.add('d-none');
+ eventTarget.innerText = 'Show Comments'
}
}
diff --git a/postEl.js b/postEl.js
index 553cb427..8490968a 100644
--- a/postEl.js
+++ b/postEl.js
@@ -18,13 +18,13 @@ export const postEl = [
{ type: 'p', attributes: { class: 'card-text' } },
{
type: 'a',
- attributes: { class: 'card-link delete-btn' },
- children: ['delete'],
+ attributes: { class: 'card-link delete-btn', style: 'cursor: pointer' },
+ children: ['Delete Post'],
},
{
type: 'a',
- attributes: { class: 'card-link show-comments' },
- children: ['comments'],
+ attributes: { class: 'card-link show-comments', style: 'cursor: pointer' },
+ children: ['Show Comments'],
},
],
},
diff --git a/readme.md b/readme.md
new file mode 100644
index 00000000..d63f53ea
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,24 @@
+# Simple Post & Comment App
+
+This project provides a basic structure for creating, displaying, and managing posts and comments dynamically using JavaScript.
+
+## Features
+
+- Add new posts with a title, author, and text
+- Delete posts
+- Show/hide comments for each post
+- Add comments to posts
+
+## How It Works
+
+- Clicking **Add Post** creates a new post from the input fields.
+- Clicking **Delete** removes a post.
+- Clicking **Show Comments** toggles visibility of the comments section.
+- Clicking **Add Comment** adds a comment to the corresponding post.
+
+## File Structure
+
+- `index.html` - Main HTML file
+- `script.js` - Handles post and comment interactions
+- `commentEl.js` - Template for comment elements
+- `postEl.js` - Template for post elements
From 893a25f2cbd6cf438bb935c4636413088c8221c0 Mon Sep 17 00:00:00 2001
From: Tom Winskell <129330818+tomwinskell@users.noreply.github.com>
Date: Tue, 4 Feb 2025 12:28:57 -0500
Subject: [PATCH 07/16] Separated files.
---
buildMethods.js | 39 +++++++++++++
commentMethods.js | 18 ++++++
commentEl.js => commentTemplate.js | 2 +-
formMethods.js | 17 ++++++
main.js | 94 ++----------------------------
postMethods.js | 16 +++++
postEl.js => postTemplate.js | 12 +++-
7 files changed, 104 insertions(+), 94 deletions(-)
create mode 100644 buildMethods.js
create mode 100644 commentMethods.js
rename commentEl.js => commentTemplate.js (96%)
create mode 100644 formMethods.js
create mode 100644 postMethods.js
rename postEl.js => postTemplate.js (70%)
diff --git a/buildMethods.js b/buildMethods.js
new file mode 100644
index 00000000..d294cdd2
--- /dev/null
+++ b/buildMethods.js
@@ -0,0 +1,39 @@
+import { getFormInput } from './formMethods.js';
+
+export function buildConst(eventTarget, template) {
+ const formEl = eventTarget.closest('form');
+ const obj = getFormInput(formEl);
+ const el = buildFragment(template);
+ return { formEl, obj, el };
+}
+
+export function buildFragment(arrayObj) {
+ const fr = new DocumentFragment();
+ arrayObj.forEach((obj) => {
+ fr.appendChild(buildElement(obj));
+ });
+ return fr;
+
+ function buildElement(obj) {
+ const el = document.createElement(obj.type);
+ if (obj.attributes) {
+ for (const key in obj.attributes) {
+ const a = document.createAttribute(key);
+ a.value = obj.attributes[key];
+ el.setAttributeNode(a);
+ }
+ }
+ if (obj.children) {
+ if (typeof obj.children[0] === 'string') {
+ const newContent = document.createTextNode(obj.children);
+ el.appendChild(newContent);
+ } else {
+ obj.children.forEach((element) => {
+ const child = buildElement(element);
+ el.appendChild(child);
+ });
+ }
+ }
+ return el;
+ }
+}
\ No newline at end of file
diff --git a/commentMethods.js b/commentMethods.js
new file mode 100644
index 00000000..c2adcbf7
--- /dev/null
+++ b/commentMethods.js
@@ -0,0 +1,18 @@
+import { buildConst } from "./buildMethods.js";
+
+export function addComment(eventTarget) {
+ const { formEl, obj, el } = buildConst(eventTarget, [{type: 'p'}]);
+ el.querySelector('p').innerText = `${obj.comment} - Posted by: ${obj.name}`;
+ formEl.insertBefore(el, formEl.firstChild);
+}
+
+export function showComments(eventTarget) {
+ const cl = eventTarget.nextSibling.classList;
+ if (cl.contains('d-none')) {
+ cl.remove('d-none');
+ eventTarget.innerText = 'Hide Comments'
+ } else {
+ cl.add('d-none');
+ eventTarget.innerText = 'Show Comments'
+ }
+}
\ No newline at end of file
diff --git a/commentEl.js b/commentTemplate.js
similarity index 96%
rename from commentEl.js
rename to commentTemplate.js
index 4665209f..f40c9e84 100644
--- a/commentEl.js
+++ b/commentTemplate.js
@@ -1,4 +1,4 @@
-export const commentEl = [
+export const commentTemplate = [
{
type: 'form',
attributes: { class: 'mt-2 d-none comment-form' },
diff --git a/formMethods.js b/formMethods.js
new file mode 100644
index 00000000..8ab36910
--- /dev/null
+++ b/formMethods.js
@@ -0,0 +1,17 @@
+export function getFormInput(formElement) {
+ const input = Array.from(formElement.querySelectorAll('.form-control')).reduce(
+ (struct, current) => {
+ struct[current.name] = current.value;
+ return struct;
+ },
+ {}
+ );
+ clearInput(formElement);
+ return input;
+
+ function clearInput(formElement) {
+ formElement.querySelectorAll('.form-control').forEach((input) => {
+ input.value = '';
+ });
+ }
+}
\ No newline at end of file
diff --git a/main.js b/main.js
index ffeabc00..006d3d90 100644
--- a/main.js
+++ b/main.js
@@ -1,14 +1,13 @@
-import { commentEl } from './commentEl.js';
-import { postEl } from './postEl.js';
+import { addPost, deletePost } from './postMethods.js';
+import { showComments, addComment } from './commentMethods.js';
const main = document.querySelector('.main');
const posts = document.querySelector('.posts');
-const postForm = document.querySelector('.post-form');
main.addEventListener('click', (e) => {
e.preventDefault();
if (e.target.classList.contains('add-post')) {
- posts.appendChild(createPostEl(getFormInput(postForm)));
+ addPost(e.target, posts);
}
if (e.target.classList.contains('delete-btn')) {
deletePost(e.target);
@@ -19,89 +18,4 @@ main.addEventListener('click', (e) => {
if (e.target.classList.contains('add-comment')) {
addComment(e.target);
}
-});
-
-function addComment(eventTarget) {
- const formEl = eventTarget.closest('form');
- const obj = getFormInput(formEl);
- const comment = buildFragment([{type: 'p'}]);
- comment.querySelector('p').innerText = `${obj.comment} - Posted by: ${obj.name}`;
- formEl.insertBefore(comment, formEl.firstChild);
-}
-
-function getFormInput(formElement) {
- const input = Array.from(formElement.querySelectorAll('.form-control')).reduce(
- (struct, current) => {
- struct[current.name] = current.value;
- return struct;
- },
- {}
- );
- clearInput(formElement);
- return input;
-}
-
-function clearInput(formElement) {
- formElement.querySelectorAll('.form-control').forEach((input) => {
- input.value = '';
- });
-}
-
-function createPostEl(obj) {
- const el = buildFragment(postEl);
- el.querySelector('.card-title').innerText = `${obj.title}`;
- el.querySelector('.card-subtitle').innerText = `Posted by: ${obj.name}`;
- el.querySelector('.card-text').innerText = `${obj.text}`;
- el.querySelector('.card-body').appendChild(buildFragment(commentEl));
- return el;
-}
-
-function showComments(eventTarget) {
- const cl = eventTarget.nextSibling.classList;
- if (cl.contains('d-none')) {
- cl.remove('d-none');
- eventTarget.innerText = 'Hide Comments'
- } else {
- cl.add('d-none');
- eventTarget.innerText = 'Show Comments'
- }
-}
-
-function deletePost(eventTarget) {
- eventTarget.closest('.card').remove();
-}
-
-function buildFragment(arrayObj) {
- const fr = new DocumentFragment();
-
- arrayObj.forEach((obj) => {
- fr.appendChild(buildElement(obj));
- });
-
- function buildElement(obj) {
- const el = document.createElement(obj.type);
-
- if (obj.attributes) {
- for (const key in obj.attributes) {
- const a = document.createAttribute(key);
- a.value = obj.attributes[key];
- el.setAttributeNode(a);
- }
- }
-
- if (obj.children) {
- if (typeof obj.children[0] === 'string') {
- const newContent = document.createTextNode(obj.children);
- el.appendChild(newContent);
- } else {
- obj.children.forEach((element) => {
- const child = buildElement(element);
- el.appendChild(child);
- });
- }
- }
- return el;
- }
-
- return fr;
-}
+});
\ No newline at end of file
diff --git a/postMethods.js b/postMethods.js
new file mode 100644
index 00000000..7c9edc6c
--- /dev/null
+++ b/postMethods.js
@@ -0,0 +1,16 @@
+import { commentTemplate } from './commentTemplate.js';
+import { postTemplate } from './postTemplate.js';
+import { buildConst, buildFragment } from './buildMethods.js';
+
+export function addPost(eventTarget, appendTo) {
+ const { _, obj, el } = buildConst(eventTarget, postTemplate);
+ el.querySelector('.card-title').innerText = `${obj.title}`;
+ el.querySelector('.card-subtitle').innerText = `Posted by: ${obj.name}`;
+ el.querySelector('.card-text').innerText = `${obj.text}`;
+ el.querySelector('.card-body').appendChild(buildFragment(commentTemplate));
+ appendTo.insertBefore(el, appendTo.firstChild);
+}
+
+export function deletePost(eventTarget) {
+ eventTarget.closest('.card').remove();
+}
diff --git a/postEl.js b/postTemplate.js
similarity index 70%
rename from postEl.js
rename to postTemplate.js
index 8490968a..98027829 100644
--- a/postEl.js
+++ b/postTemplate.js
@@ -1,4 +1,4 @@
-export const postEl = [
+export const postTemplate = [
{
type: 'div',
attributes: { class: 'card mb-3' },
@@ -18,12 +18,18 @@ export const postEl = [
{ type: 'p', attributes: { class: 'card-text' } },
{
type: 'a',
- attributes: { class: 'card-link delete-btn', style: 'cursor: pointer' },
+ attributes: {
+ class: 'card-link delete-btn',
+ style: 'cursor: pointer',
+ },
children: ['Delete Post'],
},
{
type: 'a',
- attributes: { class: 'card-link show-comments', style: 'cursor: pointer' },
+ attributes: {
+ class: 'card-link show-comments',
+ style: 'cursor: pointer',
+ },
children: ['Show Comments'],
},
],
From 7eabd365618faec1fdafed85e6aa74799ae921a8 Mon Sep 17 00:00:00 2001
From: Tom Winskell <129330818+tomwinskell@users.noreply.github.com>
Date: Tue, 4 Feb 2025 12:41:55 -0500
Subject: [PATCH 08/16] Delete README.md
---
README.md | 5 -----
1 file changed, 5 deletions(-)
delete mode 100644 README.md
diff --git a/README.md b/README.md
deleted file mode 100644
index 20395898..00000000
--- a/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-## Project Reddit
-
-This project has been created by a student at Parsity, an online software engineering course. The work in this repository is wholly of the student based on a sample starter project that can be accessed by looking at the repository that this project forks.
-
-If you have any questions about this project or the program in general, visit [parsity.io](https://parsity.io/) or email hello@parsity.io.
From 7054eaaba6cad31158d2ffb5f7e3fc0ecee724b2 Mon Sep 17 00:00:00 2001
From: Tom Winskell <129330818+tomwinskell@users.noreply.github.com>
Date: Tue, 4 Feb 2025 12:43:18 -0500
Subject: [PATCH 09/16] Update readme
---
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index d63f53ea..b7917dda 100644
--- a/readme.md
+++ b/readme.md
@@ -21,4 +21,4 @@ This project provides a basic structure for creating, displaying, and managing p
- `index.html` - Main HTML file
- `script.js` - Handles post and comment interactions
- `commentEl.js` - Template for comment elements
-- `postEl.js` - Template for post elements
+- `postEl.js` - Template for post elements
\ No newline at end of file
From 7925dbe2809c0601eac6a8351acfea450748e41c Mon Sep 17 00:00:00 2001
From: Tom Winskell <129330818+tomwinskell@users.noreply.github.com>
Date: Tue, 4 Feb 2025 12:44:23 -0500
Subject: [PATCH 10/16] Readme
---
readme.md | 25 +++----------------------
1 file changed, 3 insertions(+), 22 deletions(-)
diff --git a/readme.md b/readme.md
index b7917dda..20395898 100644
--- a/readme.md
+++ b/readme.md
@@ -1,24 +1,5 @@
-# Simple Post & Comment App
+## Project Reddit
-This project provides a basic structure for creating, displaying, and managing posts and comments dynamically using JavaScript.
+This project has been created by a student at Parsity, an online software engineering course. The work in this repository is wholly of the student based on a sample starter project that can be accessed by looking at the repository that this project forks.
-## Features
-
-- Add new posts with a title, author, and text
-- Delete posts
-- Show/hide comments for each post
-- Add comments to posts
-
-## How It Works
-
-- Clicking **Add Post** creates a new post from the input fields.
-- Clicking **Delete** removes a post.
-- Clicking **Show Comments** toggles visibility of the comments section.
-- Clicking **Add Comment** adds a comment to the corresponding post.
-
-## File Structure
-
-- `index.html` - Main HTML file
-- `script.js` - Handles post and comment interactions
-- `commentEl.js` - Template for comment elements
-- `postEl.js` - Template for post elements
\ No newline at end of file
+If you have any questions about this project or the program in general, visit [parsity.io](https://parsity.io/) or email hello@parsity.io.
From 703feda36be5693b2d1cffd86ca9868ebec89fa8 Mon Sep 17 00:00:00 2001
From: Tom Winskell <129330818+tomwinskell@users.noreply.github.com>
Date: Tue, 4 Feb 2025 12:46:05 -0500
Subject: [PATCH 11/16] Readme
---
readme.md | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/readme.md b/readme.md
index 20395898..d63f53ea 100644
--- a/readme.md
+++ b/readme.md
@@ -1,5 +1,24 @@
-## Project Reddit
+# Simple Post & Comment App
-This project has been created by a student at Parsity, an online software engineering course. The work in this repository is wholly of the student based on a sample starter project that can be accessed by looking at the repository that this project forks.
+This project provides a basic structure for creating, displaying, and managing posts and comments dynamically using JavaScript.
-If you have any questions about this project or the program in general, visit [parsity.io](https://parsity.io/) or email hello@parsity.io.
+## Features
+
+- Add new posts with a title, author, and text
+- Delete posts
+- Show/hide comments for each post
+- Add comments to posts
+
+## How It Works
+
+- Clicking **Add Post** creates a new post from the input fields.
+- Clicking **Delete** removes a post.
+- Clicking **Show Comments** toggles visibility of the comments section.
+- Clicking **Add Comment** adds a comment to the corresponding post.
+
+## File Structure
+
+- `index.html` - Main HTML file
+- `script.js` - Handles post and comment interactions
+- `commentEl.js` - Template for comment elements
+- `postEl.js` - Template for post elements
From 7d3151b92ed3856a44cfea2eb3d83b476bce1c7d Mon Sep 17 00:00:00 2001
From: Tom Winskell <129330818+tomwinskell@users.noreply.github.com>
Date: Tue, 4 Feb 2025 14:33:53 -0500
Subject: [PATCH 12/16] Added some simple client side validation
---
.vscode/settings.json | 3 +++
buildMethods.js | 2 ++
commentMethods.js | 17 ++++++++++-------
commentTemplate.js | 32 +++++++++++++++++++++++++++++++-
formMethods.js | 43 ++++++++++++++++++++++++++++++-------------
index.html | 24 ++++++++++++++++++++++--
main.js | 2 +-
postMethods.js | 15 +++++++++------
8 files changed, 108 insertions(+), 30 deletions(-)
create mode 100644 .vscode/settings.json
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..6b665aaa
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "liveServer.settings.port": 5501
+}
diff --git a/buildMethods.js b/buildMethods.js
index d294cdd2..35230220 100644
--- a/buildMethods.js
+++ b/buildMethods.js
@@ -3,8 +3,10 @@ import { getFormInput } from './formMethods.js';
export function buildConst(eventTarget, template) {
const formEl = eventTarget.closest('form');
const obj = getFormInput(formEl);
+ if (obj) {
const el = buildFragment(template);
return { formEl, obj, el };
+ }
}
export function buildFragment(arrayObj) {
diff --git a/commentMethods.js b/commentMethods.js
index c2adcbf7..4917875e 100644
--- a/commentMethods.js
+++ b/commentMethods.js
@@ -1,18 +1,21 @@
-import { buildConst } from "./buildMethods.js";
+import { buildConst } from './buildMethods.js';
export function addComment(eventTarget) {
- const { formEl, obj, el } = buildConst(eventTarget, [{type: 'p'}]);
- el.querySelector('p').innerText = `${obj.comment} - Posted by: ${obj.name}`;
- formEl.insertBefore(el, formEl.firstChild);
+ const p = buildConst(eventTarget, [{ type: 'p' }]);
+ if (p) {
+ const { formEl, obj, el } = p;
+ el.querySelector('p').innerText = `${obj.comment} - Posted by: ${obj.name}`;
+ formEl.insertBefore(el, formEl.firstChild);
+ }
}
export function showComments(eventTarget) {
const cl = eventTarget.nextSibling.classList;
if (cl.contains('d-none')) {
cl.remove('d-none');
- eventTarget.innerText = 'Hide Comments'
+ eventTarget.innerText = 'Hide Comments';
} else {
cl.add('d-none');
- eventTarget.innerText = 'Show Comments'
+ eventTarget.innerText = 'Show Comments';
}
-}
\ No newline at end of file
+}
diff --git a/commentTemplate.js b/commentTemplate.js
index f40c9e84..74680ba2 100644
--- a/commentTemplate.js
+++ b/commentTemplate.js
@@ -1,7 +1,7 @@
export const commentTemplate = [
{
type: 'form',
- attributes: { class: 'mt-2 d-none comment-form' },
+ attributes: { class: 'mt-2 d-none needs-validation comment-form' },
children: [
{
type: 'div',
@@ -14,8 +14,23 @@ export const commentTemplate = [
name: 'name',
placeholder: 'Name',
class: 'form-control',
+ required: true,
},
},
+ {
+ type: 'div',
+ attributes: {
+ class: 'invalid-feedback',
+ },
+ children: ['Please provide a name.'],
+ },
+ {
+ type: 'div',
+ attributes: {
+ class: 'valid-feedback',
+ },
+ children: ['Looks good.'],
+ },
],
},
{
@@ -29,7 +44,22 @@ export const commentTemplate = [
name: 'comment',
placeholder: 'Comment',
class: 'form-control',
+ required: true,
+ },
+ },
+ {
+ type: 'div',
+ attributes: {
+ class: 'invalid-feedback',
+ },
+ children: ['Please provide a name.'],
+ },
+ {
+ type: 'div',
+ attributes: {
+ class: 'valid-feedback',
},
+ children: ['Looks good.'],
},
],
},
diff --git a/formMethods.js b/formMethods.js
index 8ab36910..a4fe9cf2 100644
--- a/formMethods.js
+++ b/formMethods.js
@@ -1,17 +1,34 @@
-export function getFormInput(formElement) {
- const input = Array.from(formElement.querySelectorAll('.form-control')).reduce(
- (struct, current) => {
- struct[current.name] = current.value;
- return struct;
- },
- {}
- );
- clearInput(formElement);
- return input;
+export function getFormInput(formEl) {
+ if (!formEl.checkValidity()) {
+ formEl.classList.add('was-validated');
+ return;
+ } else {
+ const input = Array.from(formEl.querySelectorAll('.form-control')).reduce(
+ (struct, current) => {
+ struct[current.name] = current.value;
+ return struct;
+ },
+ {}
+ );
+ clearInput(formEl);
+ formEl.classList.remove('was-validated');
+ return input;
+ }
- function clearInput(formElement) {
- formElement.querySelectorAll('.form-control').forEach((input) => {
+ function clearInput(formEl) {
+ formEl.querySelectorAll('.form-control').forEach((input) => {
input.value = '';
});
}
-}
\ No newline at end of file
+}
+
+export function validateInput(eventTarget) {
+ const formEl = eventTarget.closest('form');
+ const arr = [];
+ formEl.querySelectorAll('.form-control').forEach((input) => {
+ if (input.value.length < 5 || input.value.length > 200) {
+ arr.push(false);
+ }
+ });
+ return arr.every((v) => v);
+}
diff --git a/index.html b/index.html
index 8e5e59ff..dc03f42d 100644
--- a/index.html
+++ b/index.html
@@ -22,7 +22,7 @@