Inline commenting functionality
This commit is contained in:
@@ -4,12 +4,17 @@
|
|||||||
padding-bottom: var(--space-sm);
|
padding-bottom: var(--space-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comment-respond__title-text {
|
||||||
|
margin-right: var(--space-xs);
|
||||||
|
}
|
||||||
|
|
||||||
.comment-respond__text {
|
.comment-respond__text {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-respond__item {
|
.comment-respond__item {
|
||||||
margin-bottom: var(--space-sm);
|
margin-bottom: var(--space-sm);
|
||||||
|
max-width: 360px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-respond__label {
|
.comment-respond__label {
|
||||||
@@ -21,6 +26,7 @@
|
|||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 1px solid var(--color-near-black);
|
border: 1px solid var(--color-near-black);
|
||||||
padding: var(--space-xs);
|
padding: var(--space-xs);
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-respond__input:focus {
|
.comment-respond__input:focus {
|
||||||
@@ -38,3 +44,30 @@
|
|||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
padding: var(--space-xs);
|
padding: var(--space-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comment-respond__cancel {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-respond__cancel a,
|
||||||
|
.comment-respond__cancel a:visited {
|
||||||
|
position: relative;
|
||||||
|
color: var(--color-light-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-respond__cancel a:after {
|
||||||
|
background-color: var(--color-light-blue);
|
||||||
|
bottom: -1px;
|
||||||
|
content: '';
|
||||||
|
left: 0;
|
||||||
|
height: 2px;
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
transition: opacity var(--transition-md) ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-respond__cancel a:focus:after,
|
||||||
|
.comment-respond__cancel a:hover:after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,6 +28,10 @@
|
|||||||
margin-bottom: var(--space-sm);
|
margin-bottom: var(--space-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comment__reply.is-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.comment__reply:focus,
|
.comment__reply:focus,
|
||||||
.comment__reply:hover {
|
.comment__reply:hover {
|
||||||
color: var(--color-light-blue);
|
color: var(--color-light-blue);
|
||||||
|
|||||||
47
js/reply-to-comment.js
Normal file
47
js/reply-to-comment.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
export default class ReplyToComment {
|
||||||
|
constructor(cfg = {}) {
|
||||||
|
if (!cfg.form || cfg.form.className !== 'comments__foot') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!cfg.links || cfg.links.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.form = cfg.form;
|
||||||
|
this.backupForm = cfg.form.querySelector('#respond').cloneNode(true);
|
||||||
|
this.links = Array.prototype.slice.call(cfg.links);
|
||||||
|
this.links.forEach((link) => {
|
||||||
|
link.addEventListener('click', e => this.handleLinkClick(e, link));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
insertForm(container, id, author) {
|
||||||
|
const form = this.backupForm.cloneNode(true);
|
||||||
|
const cancel = form.querySelector('#cancel-comment-reply-link');
|
||||||
|
form.querySelector('.comment-respond__title-text').innerHTML = `Reply to ${author}`;
|
||||||
|
form.querySelector('#submit').value = 'Post reply';
|
||||||
|
form.querySelector('#comment_parent').value = id;
|
||||||
|
cancel.style.display = 'inline-block';
|
||||||
|
cancel.addEventListener('click', e => this.handleCancelClick(e, container));
|
||||||
|
container.appendChild(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCancelClick(e, container) {
|
||||||
|
e.preventDefault();
|
||||||
|
container.parentNode.querySelector('.comment__reply').classList.remove('is-hidden');
|
||||||
|
while (container.firstChild) {
|
||||||
|
container.removeChild(container.firstChild);
|
||||||
|
}
|
||||||
|
this.form.appendChild(this.backupForm);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleLinkClick(e, link) {
|
||||||
|
e.preventDefault();
|
||||||
|
link.classList.add('is-hidden');
|
||||||
|
while (this.form.firstChild) {
|
||||||
|
this.form.removeChild(this.form.firstChild);
|
||||||
|
}
|
||||||
|
const container = link.parentNode.querySelector('.comment__inline-reply');
|
||||||
|
const { commentId, commentAuthor } = link.dataset;
|
||||||
|
this.insertForm(container, commentId, commentAuthor);
|
||||||
|
}
|
||||||
|
}
|
||||||
139
js/reply-to-comment.spec.js
Normal file
139
js/reply-to-comment.spec.js
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
import ReplyToComment from './reply-to-comment';
|
||||||
|
|
||||||
|
const commentHtml = `
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment__head">
|
||||||
|
<div class="comment__avatar"></div>
|
||||||
|
<div class="comment__metadata">
|
||||||
|
<span class="comment__author">Mr Smith</span>
|
||||||
|
<span class="comment__date">21st September, 2018 at 15:36</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comment__body">This is a comment.</div>
|
||||||
|
<div class="comment__foot">
|
||||||
|
<a class="comment__reply" data-comment-author="Mr Smith" data-comment-id="1234" href="?replytocom=1234#respond">
|
||||||
|
<span class="comment__reply-text">Reply</span>
|
||||||
|
</a>
|
||||||
|
<div class="comment__inline-reply"></div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
const formHtml = `
|
||||||
|
<div class="comments__foot">
|
||||||
|
<div id="respond" class="comment-respond">
|
||||||
|
<h3 id="reply-title" class="comment-respond__title">
|
||||||
|
<span class="comment-respond__title-text">
|
||||||
|
Leave a Reply
|
||||||
|
</span>
|
||||||
|
<div class="comment-respond__cancel">
|
||||||
|
<a rel="nofollow" id="cancel-comment-reply-link" href="#respond">Cancel reply</a>
|
||||||
|
</div>
|
||||||
|
</h3>
|
||||||
|
<form action="/wp-comments-post.php" method="post" id="commentform" class="comment-respond__form">
|
||||||
|
<p class="comment-respond__notes">Your email address will not be published.</p>
|
||||||
|
<label class="comment-respond__label" for="comment">Comment</label>
|
||||||
|
<textarea class="comment-respond__input" id="comment" name="comment" cols="25" rows="8" aria-required="true"></textarea>
|
||||||
|
<div class="comment-respond__item">
|
||||||
|
<label class="comment-respond__label" for="author">Name</label>
|
||||||
|
<input class="comment-respond__input" id="author" name="author" type="text" value="" size="30">
|
||||||
|
</div>
|
||||||
|
<div class="comment-respond__item">
|
||||||
|
<label class="comment-respond__label" for="email">Email</label>
|
||||||
|
<input class="comment-respond__input id="email" name="email" type="text" value="" size="30">
|
||||||
|
</div>
|
||||||
|
<div class="comment-respond__item">
|
||||||
|
<label class="comment-respond__label" for="url">Website</label>
|
||||||
|
<input class="comment-respond__input" id="url" name="url" type="text" value="" size="30">
|
||||||
|
</div>
|
||||||
|
<p class="form-submit">
|
||||||
|
<input name="submit" type="submit" id="submit" class="comment-respond__submit" value="Post Comment">
|
||||||
|
<input type="hidden" name="comment_post_ID" value="2683" id="comment_post_ID">
|
||||||
|
<input type="hidden" name="comment_parent" id="comment_parent" value="0">
|
||||||
|
</p>
|
||||||
|
<p style="display: none;">
|
||||||
|
<input type="hidden" id="akismet_comment_nonce" name="akismet_comment_nonce" value="123456789">
|
||||||
|
</p>
|
||||||
|
<input type="hidden" id="ak_js" name="ak_js" value="987654321">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
let comments;
|
||||||
|
let form;
|
||||||
|
let links;
|
||||||
|
let inlineReply;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
document.body.innerHTML = `${commentHtml}${formHtml}`;
|
||||||
|
form = document.querySelector('.comments__foot');
|
||||||
|
links = document.querySelectorAll('.comment__reply');
|
||||||
|
inlineReply = document.querySelector('.comment__inline-reply');
|
||||||
|
comments = new ReplyToComment({ form, links });
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ReplyToComment', () => {
|
||||||
|
it('Should initialise', () => {
|
||||||
|
expect(comments.form).toBeInstanceOf(HTMLDivElement);
|
||||||
|
expect(comments.links).toBeInstanceOf(Array);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should fail to initialise if form is missing', () => {
|
||||||
|
expect(new ReplyToComment()).toEqual({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should fail to initialise if there are no links', () => {
|
||||||
|
expect(new ReplyToComment({
|
||||||
|
form: document.querySelector('#respond'),
|
||||||
|
})).toEqual({});
|
||||||
|
expect(new ReplyToComment({
|
||||||
|
form: document.querySelector('#respond'),
|
||||||
|
links: document.querySelectorAll('.no-links-here'),
|
||||||
|
})).toEqual({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should remove the form from the DOM when a reply link is clicked', () => {
|
||||||
|
const event = new Event('click');
|
||||||
|
comments.handleLinkClick(event, links[0]);
|
||||||
|
expect(form.innerHTML).toEqual('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should hide the link when it is clicked', () => {
|
||||||
|
const event = new Event('click');
|
||||||
|
comments.handleLinkClick(event, links[0]);
|
||||||
|
expect(links[0].classList.contains('is-hidden')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should insert the form into the inline reply container', () => {
|
||||||
|
comments.insertForm(inlineReply);
|
||||||
|
const inlineForm = inlineReply.querySelectorAll('form');
|
||||||
|
expect(inlineForm.length).toEqual(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should update the comment_parent hidden element', () => {
|
||||||
|
comments.insertForm(inlineReply, '123', 'Mr Smith');
|
||||||
|
const { value } = inlineReply.querySelector('#comment_parent');
|
||||||
|
expect(value).toEqual('123');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should add a cancel link to the inline form', () => {
|
||||||
|
comments.insertForm(inlineReply);
|
||||||
|
const el = inlineReply.querySelector('#cancel-comment-reply-link');
|
||||||
|
expect(el.style.display).toEqual('inline-block');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should restore the reply link when the cancel link is clicked', () => {
|
||||||
|
const event = new Event('click');
|
||||||
|
comments.insertForm(inlineReply);
|
||||||
|
comments.handleCancelClick(event, inlineReply);
|
||||||
|
expect(links[0].classList.contains('is-hidden')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should remove the inline form when the cancel link is clicked', () => {
|
||||||
|
const event = new Event('click');
|
||||||
|
comments.insertForm(inlineReply);
|
||||||
|
comments.handleCancelClick(event, inlineReply);
|
||||||
|
expect(inlineReply.innerHTML).toEqual('');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import Menu from './menu';
|
import Menu from './menu';
|
||||||
import Navigation from './navigation';
|
import Navigation from './navigation';
|
||||||
import Image from './image';
|
import Image from './image';
|
||||||
|
import ReplyToComment from './reply-to-comment';
|
||||||
|
|
||||||
const windy = {
|
const windy = {
|
||||||
images: [],
|
images: [],
|
||||||
@@ -21,4 +22,8 @@ export default function init() {
|
|||||||
});
|
});
|
||||||
windy.menu.init();
|
windy.menu.init();
|
||||||
windy.navigation.init();
|
windy.navigation.init();
|
||||||
|
windy.comments = new ReplyToComment({
|
||||||
|
form: document.querySelector('.comments__foot'),
|
||||||
|
links: document.querySelectorAll('.comment__reply'),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
$form_settings = array(
|
$form_settings = array(
|
||||||
class_form => 'comment-respond__form',
|
class_form => 'comment-respond__form',
|
||||||
class_submit => 'comment-respond__submit',
|
class_submit => 'comment-respond__submit',
|
||||||
comment_field => '<label class="comment-respond__label" for="comment">Comment</label><textarea class="comment-respond__input" id="comment" name="comment" cols="25" rows="8" aria-required="true"></textarea></p>',
|
comment_field => '<div class="comment-respond__item"><label class="comment-respond__label" for="comment">Comment</label><textarea class="comment-respond__input" id="comment" name="comment" cols="25" rows="8" aria-required="true"></textarea></div>',
|
||||||
logged_in_as => '<p class="comment-respond__text">' . sprintf( __( 'Logged in as <a class="link" href="%1$s">%2$s</a>. <a class="link" href="%3$s" title="Log out of this account">Log out?</a>' ), admin_url( 'profile.php' ), $user_identity, wp_logout_url( apply_filters( 'the_permalink', get_permalink( ) ) ) ) . '</p>',
|
logged_in_as => '<p class="comment-respond__text">' . sprintf( __( 'Logged in as <a class="link" href="%1$s">%2$s</a>. <a class="link" href="%3$s" title="Log out of this account">Log out?</a>' ), admin_url( 'profile.php' ), $user_identity, wp_logout_url( apply_filters( 'the_permalink', get_permalink( ) ) ) ) . '</p>',
|
||||||
title_reply_before => '<h3 id="reply-title" class="comment-respond__title">',
|
title_reply_before => '<h3 id="reply-title" class="comment-respond__title">',
|
||||||
|
title_reply => '<span class="comment-respond__title-text">Reply</span>',
|
||||||
|
cancel_reply_before => '<span class="comment-respond__cancel">',
|
||||||
|
cancel_reply_after => '</span>',
|
||||||
comment_notes_before => '<p class="comment-respond__notes">' . __( 'Your email address will not be published.' ) . ( $req ? $required_text : '' ) . '</p>',
|
comment_notes_before => '<p class="comment-respond__notes">' . __( 'Your email address will not be published.' ) . ( $req ? $required_text : '' ) . '</p>',
|
||||||
fields => array(
|
fields => array(
|
||||||
author => '<div class="comment-respond__item"><label class="comment-respond__label" for="author">' . __( 'Name', 'domainreference' ) . ( $req ? '<span class="comment-respond__required">*</span>' : '' ) . '</label>' . '<input class="comment-respond__input" id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30"' . $aria_req . ' /></div>',
|
author => '<div class="comment-respond__item"><label class="comment-respond__label" for="author">' . __( 'Name', 'domainreference' ) . ( $req ? '<span class="comment-respond__required">*</span>' : '' ) . '</label>' . '<input class="comment-respond__input" id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30"' . $aria_req . ' /></div>',
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
class Windycoys_Walker_Comment extends Walker_Comment {
|
class Windycoys_Walker_Comment extends Walker_Comment {
|
||||||
function start_el(&$output, $comment, $depth = 0, $args = array(), $id = 0) {
|
function start_el(&$output, $comment, $depth = 0) {
|
||||||
$id = $comment->comment_ID;
|
$id = $comment->comment_ID;
|
||||||
|
$post_id = $comment->comment_post_ID;
|
||||||
|
$reply_link = get_permalink($post_id) . '?replytocom='.$id.'#respond';
|
||||||
$author_email = $comment->comment_author_email;
|
$author_email = $comment->comment_author_email;
|
||||||
$author = $comment->comment_author;
|
$author = $comment->comment_author;
|
||||||
$avatar = get_avatar($comment, 128);
|
$avatar = get_avatar($comment, 128);
|
||||||
@@ -19,10 +21,11 @@ class Windycoys_Walker_Comment extends Walker_Comment {
|
|||||||
$output .= '</div></div>';
|
$output .= '</div></div>';
|
||||||
$output .= '<div class="comment__body">'.$content.'</div>';
|
$output .= '<div class="comment__body">'.$content.'</div>';
|
||||||
$output .= '<div class="comment__foot">';
|
$output .= '<div class="comment__foot">';
|
||||||
$output .= '<a class="comment__reply" href="'.get_comment_reply_link().'">';
|
$output .= '<a class="comment__reply" data-comment-author="'.$author.'" data-comment-id="'.$id.'" href="'.$reply_link.'">';
|
||||||
$output .= '<span class="comment__reply-icon">';
|
$output .= '<span class="comment__reply-icon">';
|
||||||
$output .= '<svg class="icon icon--extra-small"><use href="#icon-reply"></use></svg></span>';
|
$output .= '<svg class="icon icon--extra-small"><use href="#icon-reply"></use></svg></span>';
|
||||||
$output .= '<span class="comment__reply-text">Reply</span></a>';
|
$output .= '<span class="comment__reply-text">Reply</span></a>';
|
||||||
|
$output .= '<div class="comment__inline-reply"></div>';
|
||||||
$output .= '</div></div></li>';
|
$output .= '</div></div></li>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user