Skip to content

Commit

Permalink
Modify the JavaScript component so it works seamlessly with no-JS WP.
Browse files Browse the repository at this point in the history
With this commit, the JavaScript component now renders itself inside a
`FORM` element, rather than outside. This begins addressing the issues
listed in nrkbeta#1, and means that both JavaScript and non-JavaScript
variations work; the JavaScript now creates inputs as the WordPress
back-end expects them.

Further, this commit also fixes the error animation, and changes the
animation for when the user enters the quiz answers correctly.
Previously, this component hid the comment form and revealed it when the
quiz was answered, but this required rendering the quiz outside the
form. With the above change, the animation has been changed to disabling
the comment form's textareas and re-enabling them when the quiz is
answered correctly, along with showing a bolded green success message.
  • Loading branch information
fabacab committed Mar 12, 2017
1 parent 242bb97 commit 3f76395
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 97 deletions.
65 changes: 35 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,36 +19,41 @@ The plugin is made for Wordpress, but the JavaScript component can easily be imp

If you're using a different content management system, you can still use the JavaScript component to enable this functionality on your site.

The component requires a `DIV` right before the container which holds your comment form. The `DIV` has two data-attributes: `data-nrkbetaquiz` and `data-nrkbetaquiz-error`. The `DIV` also needs the class `nrkbetaquiz`.

`data-nrkbetaquiz-error` is a string with the error message in case the user has answered the quiz wrongfully.
`data-nrkbetaquiz` is an array with the following structure:

[{
text: 'Who is the current president of The Unites States?'
answers: ['Barack Obama', 'Donald Trump', 'Steve Bannon'],
correct: 1
}, {
text: 'What is the radius of Earth?'
answers: ['6 371 kilometers', '371 kilometers', '200 kilometers'],
correct: 0
}]

The component requires a `DIV` to be inserted as a direct child of your comment form. The `DIV` has three `data-`attributes: `data-nrkbetaquiz`, `data-nrkbetaquiz-error`, and `data-nrkbetaquiz-correct`. The `DIV` also needs the class `nrkbetaquiz`.

* `data-nrkbetaquiz-error` is a string with the error message in case the user has answered the quiz wrongfully.
* `data-nrkbetaquiz-correct` is a string with the success message when the user answers the quiz correctly.
* `data-nrkbetaquiz` is a [JSON](http://json.org/) array with the following structure:

```json
[{
"text": "Who is the current president of The Unites States?",
"answers": ["Barack Obama", "Donald Trump", "Steve Bannon"],
"correct": 1
}, {
"text": "What is the radius of Earth?",
"answers": ["6,371 kilometers", "371 kilometers", "200 kilometers"],
"correct": 0
}]
```

Here's a full example of the implementation:

<script src="nrkbetaquiz.js"></script>
<div class="nrkbetaquiz"
data-nrkbetaquiz="[{
text: 'Who is the current president of The Unites States?'
answers: ['Barack Obama', 'Donald Trump', 'Steve Bannon'],
correct: 1
}, {
text: 'What is the radius of Earth?'
answers: ['6 371 kilometers', '371 kilometers', '200 kilometers'],
correct: 0
}]"
data-nrkbetaquiz-error="You fail">
</div>

<div id="YOUR_COMMENT_FORM_CONTAINER"></div>
```html
<form id="YOUR_COMMENT_FORM_CONTAINER">
<script src="nrkbetaquiz.js"></script>
<div class="nrkbetaquiz"
data-nrkbetaquiz='[{
"text": "Who is the current president of The Unites States?",
"answers": ["Barack Obama", "Donald Trump", "Steve Bannon"],
"correct": 1
}, {
"text": "What is the radius of Earth?",
"answers": ["6,371 kilometers", "371 kilometers", "200 kilometers"],
"correct": 0
}]'
data-nrkbetaquiz-error="You fail"
data-nrkbetaquiz-correct="You succeed"
></div>
</form>
```
46 changes: 23 additions & 23 deletions nrkbetaquiz.css
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
.nrkbetaquiz,
.nrkbetaquiz + * {
overflow: hidden;
transition: .5s;
height: 0;
}
.nrkbetaquiz { height: auto }
.nrkbetaquiz label {
cursor: pointer;
display: inline-block;
margin: 0 7px 6px 0;
border-radius: 5px;
padding: 10px 15px;
background: #eee;
transition: .2s;
.nrkbetaquiz label.answer {
cursor: pointer;
display: inline-block;
margin: 0 7px 6px 0;
border-radius: 5px;
padding: 10px 15px;
background: #eee;
}
.nrkbetaquiz label:hover {
background: #ccc;
background: #ccc;
}
.nrkbetaquiz p.correct,
.nrkbetaquiz p.error {
font: inherit;
animation: .5s nrkbetaquiz;
}
.nrkbetaquiz p.correct {
color: green;
font-weight: bold;
}
.nrkbetaquiz p.error {
color: red;
}
.nrkbetaquiz h3 {
color: red;
font: inherit;
animation: nrkbetaquiz forward;
@keyframes nrkbetaquiz {
from { transform: scale(0); }
to { transform: scale(1); }
}
@keyframes nrkbetaquiz{
from{transform:scale(0)}
}
46 changes: 28 additions & 18 deletions nrkbetaquiz.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,9 @@ document.addEventListener('DOMContentLoaded', function(){
catch(err){return []}
};

var removeQuiz = function(quizNode, formNode){
quizNode.style.height = quizNode.offsetHeight + 'px';
formNode.style.height = formNode.scrollHeight + 'px';
quizNode.style.height = '0px';
setTimeout(function(){
quizNode.style.display = 'none';
formNode.style.height = 'auto';
}, 500);
};

var buildAnswer = function(text, name, value){
var label = document.createElement('label');
label.className = 'answer';
var input = label.appendChild(document.createElement('input'));
var title = label.appendChild(document.createTextNode(text));

Expand All @@ -28,11 +19,15 @@ document.addEventListener('DOMContentLoaded', function(){
};

var buildQuiz = function(quizNode){
var formNode = quizNode.nextElementSibling;
var formNode = quizNode.parentNode;
var errorText = quizNode.getAttribute('data-' + NRKBCQ + '-error');
var correctText = quizNode.getAttribute('data-' + NRKBCQ + '-correct');
var questions = parseQuiz(quizNode.getAttribute('data-' + NRKBCQ));
var correctId = NRKBCQ + location.pathname + questions.map(function(q){return q.correct}).join('');
var errorNode = document.createElement('h3').appendChild(document.createTextNode(errorText)).parentNode;
var errorNode = document.createElement('p').appendChild(document.createTextNode(errorText)).parentNode;
errorNode.className = 'error';
var correctNode = document.createElement('p').appendChild(document.createTextNode(correctText)).parentNode;
correctNode.className = 'correct';
var container = document.createElement('div');

if(localStorage.getItem(correctId) === correctId){ //Skip quiz if already solved
Expand All @@ -47,20 +42,35 @@ document.addEventListener('DOMContentLoaded', function(){
.forEach(function(node){node && container.appendChild(node)});
});

// Disable form textareas until quiz is answered correctly.
var el;
formNode.querySelectorAll( 'textarea' ).forEach( function (el) {
el.setAttribute( 'disabled', 'disabled' );
});

quizNode.appendChild(container);
quizNode.addEventListener('change', function(){
var checked = questions.map(function(q,i){return container.querySelector('input[name="' + NRKBCQ + i + '"]:checked')});
var correct = questions.every(function(q,i){return checked[i] && Number(checked[i].value) === Number(q.correct)});
var failure = !correct && checked.filter(Boolean).length === questions.length;

if(correct){
localStorage.setItem(correctId, correctId);
removeQuiz(quizNode, formNode);
}else if(failure){
container.appendChild(errorNode);
if ( correct ) {
if ( el = quizNode.querySelector('.error') ) {
el.parentNode.removeChild( el );
}
localStorage.setItem( correctId, correctId );
container.appendChild( correctNode );
formNode.querySelectorAll( 'textarea' ).forEach( function (el) {
el.removeAttribute( 'disabled' );
});
} else if ( failure ) {
if ( el = quizNode.querySelector('.correct') ) {
el.parentNode.removeChild( el );
}
container.appendChild( errorNode );
}
});
};

[].forEach.call(document.querySelectorAll('.' + NRKBCQ), buildQuiz);
});
});
49 changes: 23 additions & 26 deletions nrkbetaquiz.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,50 +25,45 @@
wp_enqueue_style( NRKBCQ, plugins_url( 'nrkbetaquiz.css', __FILE__ ) );
});

add_action( 'comment_form_before', 'nrkbetaquiz_form' );
add_action( 'comment_form_top', 'nrkbetaquiz_form' );
/**
* Prints the commenting quiz before WordPress's comment form.
* Prints the comment quiz atop WordPress's comment form.
*
* @TODO This functionality should be moved into the `nrkbetaquiz_form_top()`
* function, but I don't want to move it quite yet because I'm not yet
* touching any of the JavaScript, and a lot of the code still uses
* DOM hierarchy to function properly.
* This outputs the JavaScript-hooked element and initial greeting. A
* different function, `nrkbetaquiz_form_no_js`, prints the HTML-only
* version of the same quiz and is used when JavaScript is disabled.
*/
function nrkbetaquiz_form() {
global $post;
if ( nrkbetaquiz_post_has_quiz( $post ) ) {
?>
<div class="<?php esc_attr_e( NRKBCQ ); ?>"
data-<?php esc_attr_e( NRKBCQ ); ?>="<?php echo esc_attr( rawurlencode( json_encode( get_post_meta( get_the_ID(), 'nrkbetaquiz' ) ) ) ); ?>"
data-<?php esc_attr_e( NRKBCQ ); ?>-error="<?php esc_attr_e( 'You have not answered the quiz correctly. Try again.', 'nrkbetaquiz' ); ?>">
data-<?php esc_attr_e( NRKBCQ ); ?>-error="<?php esc_attr_e( 'You have not answered the quiz correctly. Try again.', 'nrkbetaquiz' ); ?>"
data-<?php esc_attr_e( NRKBCQ ); ?>-correct="<?php esc_attr_e( 'You answered the quiz correctly! You may now post your comment.', 'nrkbetaquiz' ); ?>"
>
<h2><?php esc_html_e( 'Would you like to comment? Please answer some quiz questions from the story.', 'nrkbetaquiz' );?></h2>
<p><?php esc_html_e( "
We care about our comments.
<p><?php esc_html_e( "We care about our comments.
That's why we want to make sure that everyone who comments have actually read the story.
Answer a short quiz about the story to post your comment.
", 'nrkbetaquiz' ); ?></p>
</div>
<?php
nrkbetaquiz_form_no_js();
}
}

add_action( 'comment_form_top', 'nrkbetaquiz_form_top' );
/**
* Prints the commenting quiz at the top of the WordPress comment form.
* Prints the HTML-only quiz at the top of the WordPress comment form.
*/
function nrkbetaquiz_form_top() {
function nrkbetaquiz_form_no_js() {
global $post;
if ( nrkbetaquiz_post_has_quiz( $post ) ) {
$quiz = get_post_meta( $post->ID, NRKBCQ );
$answer_hash = hash( 'sha256', serialize( $quiz ) );
?>
<noscript>
<?php
// TODO: Remove this CSS once JS-dependant quiz is not needed.
echo '<style>#respond { height: auto; }</style>';

if ( isset( $_GET[ NRKBCQ . '_quiz_error' ] ) ) {
?>
<?php if ( isset( $_GET[ NRKBCQ . '_quiz_error' ] ) ) { ?>
<p class="error"><?php esc_html_e( 'You have not answered the quiz correctly. Try again.', 'nrkbetaquiz' ); ?></p>
<?php
}
Expand Down Expand Up @@ -253,15 +248,17 @@ function nrkbetaquiz_print_quiz_question_edit_html ( $post ) {
*
* @link https://developer.wordpress.org/reference/hooks/save_post/
*/
function nrkbetaquiz_save($post_id, $post, $update){
if(isset($_POST[NRKBCQ], $_POST[NRKBCQ_NONCE]) && wp_verify_nonce($_POST[NRKBCQ_NONCE], NRKBCQ)){
delete_post_meta($post_id, NRKBCQ); //Clean up previous quiz meta
foreach($_POST[NRKBCQ] as $k=>$v){
if($v['text'] && array_filter($v['answer'], 'strlen')){ //Only save filled in questions
add_post_meta($post_id, NRKBCQ, $v);
}
function nrkbetaquiz_save( $post_id, $post, $update ) {
if( isset( $_POST[NRKBCQ], $_POST[NRKBCQ_NONCE] ) && wp_verify_nonce( $_POST[NRKBCQ_NONCE], NRKBCQ ) ) {
// Clean up previous quiz meta
delete_post_meta( $post_id, NRKBCQ );
foreach( $_POST[NRKBCQ] as $k => $v ) {
// Only save filled in questions
if( $v['text'] && array_filter( $v['answer'], 'strlen' ) ) {
add_post_meta( $post_id, NRKBCQ, $v );
}
}
}
}
}

/**
Expand Down

0 comments on commit 3f76395

Please sign in to comment.