diff options
author | Aaron O'Mullan <aaron.omullan@friendco.de> | 2014-10-13 15:50:12 +0200 |
---|---|---|
committer | Aaron O'Mullan <aaron.omullan@friendco.de> | 2014-10-13 15:50:12 +0200 |
commit | 676b2287ee2595843daa18bee4effeb6f021b2ed (patch) | |
tree | e2386d93c47f84e7c38b121f9b0c4cfa3344ce48 /lib/parse | |
parent | d730a3aac601f000d770dbccca02ac4bb2d07245 (diff) | |
download | gitbook-676b2287ee2595843daa18bee4effeb6f021b2ed.zip gitbook-676b2287ee2595843daa18bee4effeb6f021b2ed.tar.gz gitbook-676b2287ee2595843daa18bee4effeb6f021b2ed.tar.bz2 |
Rewrite quiz logic to be more robust
Fixes #470
Diffstat (limited to 'lib/parse')
-rw-r--r-- | lib/parse/is_quiz.js | 99 |
1 files changed, 68 insertions, 31 deletions
diff --git a/lib/parse/is_quiz.js b/lib/parse/is_quiz.js index aa6125a..4a24cfc 100644 --- a/lib/parse/is_quiz.js +++ b/lib/parse/is_quiz.js @@ -4,42 +4,79 @@ function isQuizNode(node) { return (/^[(\[][ x][)\]]/).test(node.text || node); } -function isQuiz(nodes) { - if (nodes.length < 3) { - return false; - } +function isTableQuestion(nodes) { + var block = questionBlock(nodes); + return ( + block.length === 1 && + block[0].type === 'table' && + _.all(block[0].cells[0].slice(1), isQuizNode) + ); +} - // Support having a first paragraph block - // before our series of questions - var quizNodes = nodes.slice(nodes[0].type === 'paragraph' ? 1 : 0); +function isListQuestion(nodes) { + var block = questionBlock(nodes); + // Counter of when we go in and out of lists + var inlist = 0; + // Number of lists we found + var lists = 0; + // Elements found outside a list + var outsiders = 0; + // Ensure that we have nothing except lists + _.each(block, function(node) { + if(node.type === 'list_start') { + inlist++; + } else if(node.type === 'list_end') { + inlist--; + lists++; + } else if(inlist === 0) { + // Found non list_start or list_end whilst outside a list + outsiders++; + } + }); + return lists > 0 && outsiders === 0; +} - // No questions - if (!_.some(quizNodes, { type: 'blockquote_start' })) { - return false; - } +function isQuestion(nodes) { + return isListQuestion(nodes) || isTableQuestion(nodes); +} - // Check if section has list of questions - // or table of questions - var listIdx = _.findIndex(quizNodes, { type: 'list_item_start' }); - var tableIdx = _.findIndex(quizNodes, { type: 'table' }); - - - if( - // List of questions - listIdx !== -1 && isQuizNode(quizNodes[listIdx + 1]) || - - // Table of questions - ( - tableIdx !== -1 && - // Last entry - tableIdx === nodes.length - 1 && - _.every(quizNodes[tableIdx].cells[0].slice(1), isQuizNode) - ) - ) { - return true; +// Remove (optional) paragraph header node and blockquote +function questionBlock(nodes) { + return nodes.slice( + nodes[0].type === 'paragraph' ? 1 : 0, + _.findIndex(nodes, { type: 'blockquote_start' }) + ); +} + +function splitQuestions(nodes) { + // Represents nodes in current question + var buffer = []; + return _.reduce(nodes, function(accu, node) { + // Add node to buffer + buffer.push(node); + + // Flush buffer once we hit the end of a question + if(node.type === 'blockquote_end') { + accu.push(buffer); + // Clear buffer + buffer = []; + } + + return accu; + }, []); +} + +function isQuiz(nodes) { + // Extract potential questions + var questions = splitQuestions(nodes); + + // Nothing that looks like questions + if(questions.length === 0) { + return false; } - return false; + // Ensure all questions are correctly structured + return _.all(questions, isQuestion); } module.exports = isQuiz; |