UNPKG

queez

Version:

A simple Javascript library to create quizz

767 lines (599 loc) 23.1 kB
# Queez A simple Javascript library to create quizz. ![](https://travis-ci.org/arncet/queez.svg?branch=master) ## Navigation : * [How to use](#how-to-use-) * [Documentation](#documentation-) * [Examples](#examples-) * [License](#license-) * [Development](#development-) ## How to use : Install `queez` via npm : ``` npm install --save queez ``` Use it : ```javascript import Queez from 'queez' const quizz = new Queez(config) ``` `config` is an object containing all your quizz configuration An example of the `congif` content : ```javascript const config = { questions: [...], categories: [...], results: [...], callbacks: {...} } ``` All informations relating to `config` content are available in the section below. ## Documentation : ### Queez : <u>Properties :</u> The `config` object has `questions`, `categories`, `resultats` and `callbacks` properties. Other properties may be added, they will automatically injected within the `custom` property of `queez` instance. <br/> There is an example for a custom property named `titre`: ```javascript const config = { title: 'An awesome quizz', ... } const quizz = new Queez(config) //quizz.title => undefined //quizz.custom.title => 'An awesome quizz' ``` * `question` : Represents quizz's questions (see doc [here](#question-)). * `categories` : Represents results's categories of the quizz (voir la doc [here](#category-)). * `results` : Represents possibles quizz's results (voir la doc [here](#result-)). * `callbacks` : Represents available quizz's callbacks (voir la doc [here](#callbacks-)). You will find below the details of the main property `config` : | Name | Type | Required | Default value | |:------------- |:----------------| :-------------| :-------------| | questions | Array | false | [ ] | | categories | Array | false | [ ] | | results | Array | false | [ ] | | callbacks | Object | false | { } | If a property has a wrong type, the default value will be assigned. <u>Methods :</u> #### `getQuestion(questionId)` => [Question](#question-) : Retrieve a question from its id. <br/> * `questionId` (Integer | String) : Question id. --------------------------------------- #### `getQuestionsBy(attribut, value)` => Array of [Question](#question-) : Retrieve an array of questions from the value of a given attribute * `attribute` (String | Array) : Attribute (ot attribute's path, e.g `['custom', 'title']` for `title` attribute of `custom`)<br/> * `value` : Attribute's value. --------------------------------------- #### `getQuestionByAnswer` => [Question](#question-) : Retrieve a question from an answer id. * `answerId` (Integer \| String) : Answer's id. --------------------------------------- #### `getResult` => [Result](#result-) : Retrieve a result from its id. * `resultId` (Integer \| String) : Result's id. --------------------------------------- #### `getResultsBy` => Array of [Result](#result-) : Retrieve an array of result from the value of a given attribute. * `attribute` (String | Array) : Attribute (ot attribute's path, e.g `['custom', 'title']` for `title` attribute of `custom`)<br/> * `value` : Attribute's value. --------------------------------------- #### `getCategory` => [Category](#category-) : Retrieve a category from its id. * `categoryId` : L'id de la categorie. --------------------------------------- #### `getCategoriesBy` => Array of [Category](#category-) : Retrieve an array of category from the value of a given attribute. * `attribute` (String | Array) : Attribute (ot attribute's path, e.g `['custom', 'title']` for `title` attribute of `custom`)<br/> * `value` : Attribute's value. --------------------------------------- #### `isComplete` => Boolean : Check if all questions has been answered. --------------------------------------- #### `getResponse` => Array of [Result](#result-) | Array of [Question](#question-) (props less): Get finals quizz's results. <br/> If there is elements in `config.results`, `getResponse` return an `result` array, else return quizz's `question` as 'props less' (just contain properties : `id`, `content`, `custom` and `answer` (props less)). --------------------------------------- ### Question : Questions are the main quizz element.<br/> There is a example of question : ```javascript { "id": "question-1", "content": "What is yout favorite color ?", "categoryId": "favorite-color", "answers": [...], "multiple": false } ``` <u>Properties :</u> * `id` : Represents the question identifier (unique). * `content` : Represents the content of the question * `categoryId` : Represent the id of the category to which belongs the question. * `answers ` : Represnete the proposed answers to the question (see doc [here](#answer-)). * `multiple`: Define if a question can be answered several times, with different answers. Other properties may be added, they will automatically injected within the question `custom` property. <br/> | Name | Type | Required | Default value | |:------------- |:-------------------| :-------------| :----------------------| | id | Integer \| String | false | Random string (9 char.)| | content | Integer \| String | false | / | | categoryId | Integer \| String | false | Empty string | | answers | Array | false | [ ] | | multiple | Boolean | false | false | <u>Methods :</u> ##### `getAnswer(answerId)` => [Answer](#answer-) : Retrieve a answer from its id. * `answerId ` (Integer | String) : L'id de la reponse. --------------------------------------- #### `getAnswersBy(attribut, value)` => Array : Retrieve an array of answer from the value of a given attribute. * `attribute` (String | Array) : Attribute (ot attribute's path, e.g `['custom', 'title']` for `title` attribute of `custom`)<br/> * `value` : Attribute's value. --------------------------------------- #### `isAnswered` => Boolean : Return `true` if the question is answered. --------------------------------------- #### `respond` : Respond to the question. * `answerId` : Answer's id. --------------------------------------- #### `unRespond` : Un-resopnd to the question * `answerId` : Answer's id. --------------------------------------- #### `toPropsLess` : Return the `question` with just `id`, `content`, `custom` and `answers` properties (props less). ### Answer : `Answer` are several proposals for a question. <br/> Here is an example of a response : ```javascript { "id": "answer-1", "content": "Yellow", "value": "yellow", coefficient: 1 } ``` <u>Properties :</u> * `id` : Represents the answer identifier (unique). * `content` : Represents the answer content. * `value` : Represents the answer value. * `coefficient ` : Represents the answer coefficient. Other properties may be added, they will automatically injected within the answer `custom` property. <br/> | Name | Type | Required | Default value | |:------------- |:-------------------| :-------------| :-----------------------| | id | Integer \| String | false | Random string (9 char.) | | content | Integer \| String | false | Empty string | | value | Integer \| String | false | Empty string | | coefficient | Integer | false | 1 | <u>Methods :</u> #### `toPropsLess` : Return `answer` with `id`, `content` and `custom` properties. ### Category : `category` objects are the elements that make the connection between the questions and possible quiz's result. These may be characterized as the type of question. <br/> Here is an example of category : ```javascript { "id": "favorite-color" } ``` <u>Properties :</u> * `id` : Represents the category identifier (unique). Other properties may be added, they will automatically injected within the category `custom` property. <br/> | Name | Type | Required | Default value | |:------------- |:-------------------| :-------------| :-----------------------| | id | Integer \| String | true | Random string (9 char.) | ### Result : `result` objects are the different results possible for the quiz.<br/> Here is an example of results : ```javascript { "id": "result-1", "filter": { "favorite-color": "yellow", "favorite-food": "burger" } } ``` <u>Properties :</u> * `id` : Represents the result identifier (unique). * `filter` : Represents the conditions to obtain this result. A `result` without filter will always be returned in the final results of the quiz (via the method [getResponse](#getResponse-)). <br/> Each `filter` object is a condition, the key represents the `category`'s id and value define its value (the value of `answer.value`) ```javascript { { "favorite-color": "yellow" } } ``` In this case, to obtain this result, it is necessary that the question (or most questions) has `favorite-color` as categoryId have one (or most) response with `yellow` value. Conditions can be combined to build most impressive or strict conditions. An `object` represents an `ET` and an `array` represents an `OR`: To define a result with the following condition : "favorite color" is "yellow" `AND` "favorite food" is "burger", must be : ```javascript { "filter": { "favorite-color": "yellow", "favorite-food": "burger" } } ``` To define a result with the following condition : "favorite colors" are "green" `AND` "pink", must be : ```javascript { "filter": { "favrite-colors": {"green": true, "pink": true} } } ``` **Note: In case a category is defined by an "AND" key values ​​can take any value type. Filter just need to be defines as an object.** Other exemples : ```javascript { "filter": { "favorite-color": ["blue", "red"] } } //favorite color is blue OR red { "filter": [ "favorite-color": "yellow", "favorite-food": "burger" ] } //favorite color est yellow OR favorite food is burger { "filter": { "favorite-color": ["blue", "red"], "favorite-food": "rice" } } //favorite color is blue OR red, AND favorite food is rice { "filter": [ {"favorite-color": "green", "favorite-food": "rice"}, {"favorite-color": ["blue", "red"], "favorite-food": "burger"} ] } //favorite color is green AND favorite food is rice, //OR favorite color is blue OR red AND favorite food is burger ``` * `content` : Represents the result content. Other properties may be added, they will automatically injected within the result `custom` property. <br/> | Name | Type | Required | Default value | |:------------- |:-------------------| :-------------| :-----------------------| | id | Integer \| String | false | Random string (9 char.) | | filter | Object \| Array | false | { } | | content | Integer \| String | false | Empty string | ### Callbacks : `callback` are functions that are called at the end of a specific action. <br/> Here is an example of callback: ```javascript { onQuestionRespond: [ function(question, answer, error) { console.log('onQuestionRespond', question, answer, error) } ], } ``` Each `callback` is an `array` of function`, each function will be called once the specific action performed in the order in which they defined summers. <u>Avaliable callbacks list :</u> * `onQuestionRespond` : Execute all associated functions when a question is answered. Callbacks will have the following properties : * `question` [Question](#question-): The answered question. * `answer` [Answer](#answer-): The question's answer. * `error` null | string : Error, `null` If there is no error. * `onQuestionUnRespond` : Execute all associated functions when a question is un-answered. Callbacks will have the following properties : * `question` [Question](#question-): The answered question. * `answer` [Answer](#answer-): The question's answer. * `error` null | string : Error, `null` If there is no error. * `onQuizzComplete` : Execute all associated functions when the quiz ends (when all the questions have summers reponsues). Callbacks will have the following properties : * `quizz` [Queez](#queez-): L'instance du quizz. ## Examples : ### Example 1 : Preferences survey : [Sources here](https://github.com/arncet/queez/blob/master/example/quizz-config-survey.js) Here the quizz's questions as text : ``` 1 - Among the following colors, which do you prefer ? Green, Yellow, Red ou Blue. 2 - Among the following foods, which do you prefer ? Burger, Salad, Pizza ou Rice. 3 - Among the following car brand, which do you prefer? Audi, BMW, Aston Martin ou Chevrolet. 4 - Among the following OS, which do you prefer ? Mac OS, Windows, Linux. ``` The `questions` property of the object `config` will be: ```javascript [ { "id": "favorite-color", "content": "Among the following colors, which do you prefer ?", "answers": [ { "id": "c-answer-1", "content": "Green", "value": "green" }, { "id": "c-answer-2", "content": "Yellow", "value": "yellow" }, { "id": "c-answer-3", "content": "Red", "value": "red" }, { "id": "c-answer-4", "content": "Blue", "value": "blue" } ] }, { "id": "favorite-food", "content": "Among the following foods, which do you prefer ?", "answers": [ { "id": "f-answer-1", "content": "Burger", "value": "burger" }, { "id": "f-answer-2", "content": "Salad", "value": "salad" }, { "id": "f-answer-3", "content": "Pizza", "value": "pizza" }, { "id": "f-answer-4", "content": "Rice", "value": "rice" } ] }, { "id": "favorite-car-brand", "content": "Among the following car brand, which do you prefer ?", "answers": [ { "id": "c-b-answer-1", "content": "Audi", "value": "audi" }, { "id": "c-b-answer-2", "content": "BMW", "value": "bmw" }, { "id": "c-b-answer-3", "content": "Aston Martin", "value": "aston-martin" }, { "id": "c-b-answer-4", "content": "Chevrolet", "value": "chevrolet" } ] }, { "id": "favorite-os", "content": "Among the following OS, which do you prefer?", "answers": [ { "id": "os-answer-1", "content": "Mac OS", "value": "mac-os" }, { "id": "os-answer-2", "content": "Windows", "value": "windows" }, { "id": "os-answer-3", "content": "Linux", "value": "linux" } ] } ] ``` ### Example 2 : Quizz Super-héros : [Sources here](https://github.com/arncet/queez/blob/master/example/quizz-config-super-hero.js) Here the quizz's questions as text : ``` 1 - You are a man or a woman ? Man, Woman. 2 - What is your favorite color ? Red, Blue, Noir, Green. 3 - What attribute you would like to have ? Strength, Speed, Agility. ``` Here the possibles results : | Nom | Sexe | Couleur | Attribut | |:--------------|:------|:----------------|:----------------------| | Superman | Man | Red && Blue | Strength | | Batman | Man | Noir | Agility | | Batman | Man | Noir | Strength | | Hulk | Man | Green | Strength | | Flash | Man | Red | Agility & Speed | | Wonder Woman | Woman | Red \|\| Blue | Strength | | Spider-man | Man | Red && Blue | Agility | | Thor | Man | Red \|\| Black | Agility & Elementaire | | Tornade | Woman | Noir | Elementaire | | Iron-man | Man | Red | Strength | | Green Lantern | Man | Green | Agility & Elementaire | The `categories` property of the object `config` will be: ```javascript [ { "id": "sexe" }, { "id": "color" }, { "id": "attribute" } ] ``` The `questions` property of the object `config` will be: **Note : Do not forget the `multiple` property to the question `question-color` and question `question-attribute` To select multiple colors and / or attributes** ```javascript [ { "id": "question-sexe", "content": "You are a man or a woman ?", "categoryId": "sexe", "answers": [ { "id": "answer-sexe-1", "content": "Man", "value": "man" }, { "id": "answer-sexe-2", "content": "Woman", "value": "women" } ] }, { "id": "question-color", "content": "What is your favorite color ?", "categoryId": "color", "multiple": true, "answers": [ { "id": "answer-color-1", "content": "Red", "value": "red" }, { "id": "answer-color-2", "content": "Blue", "value": "blue" }, { "id": "answer-color-3", "content": "Black", "value": "black" }, { "id": "answer-color-4", "content": "Green", "value": "green" } ] }, { "id": "question-attribut", "content": "What attribute you would like to have ?", "categoryId": "attribute", "multiple": true, "answers": [ { "id": "answer-attribute-1", "content": "Strength", "value": "strength" }, { "id": "answer-attribute-2", "content": "Speed", "value": "speed" }, { "id": "answer-attribute-3", "content": "agility", "value": "agility" }, { "id": "answer-attribute-4", "content": "Elementary", "value": "elementary" } ] } ] ``` The `results` property of the object `config` will be: ```javascript [ { "id": "result-1", "content": "Superman", "filter": { "sexe": "man", "color": {"red": true, "blue": true}, "attribute": "strength" } }, { "id": "result-2", "content": "Batman", "filter": [ { "sexe": "man", "color": "black", "attribute": "agility" }, { "sexe": "man", "color": "black", "attribute": "strength" } ] }, { "id": "result-3", "content": "Hulk", "filter": { "sexe": "man", "color": "green", "attribute": "strength" } }, { "id": "result-4", "content": "Flash", "filter": { "sexe": "man", "color": "red", "attribute": {"agility": true, "speed": true} } }, { "id": "result-5", "content": "Wonder Woman", "filter": { "sexe": "woman", "color": ["red", "blue"], "attribute": "strength" } }, { "id": "result-6", "content": "Spider-man", "filter": { "sexe": "man", "color": {"red": true, "blue": true}, "attribute": "agility" } }, { "id": "result-7", "content": "Thor", "filter": { "sexe": "man", "color": ["red", "black"], "attribute": {"strength": true, "elementary": true} } }, { "id": "result-8", "content": "Tornade", "filter": { "sexe": "woman", "color": "black", "attribute": "elementary" } }, { "id": "result-9", "content": "Iron-man", "filter": { "sexe": "man", "color": "red", "attribute": "strength" } }, { "id": "result-10", "content": "Green Lantern", "filter": { "sexe": "man", "color": "green", "attribute": {"strength": true, "elementary": true} } } ] ``` ### Example 3 : With React : [Demo here](https://arncet.github.io/queez-react-demo/) ```javascript import React, { Component } from 'react' import Queez from 'queez' import configSuperHero from './configSuperHero' import configSurvey from './configSurvey' import JSONTree from 'react-json-tree' //Callback for complete event (super hero quizz) const superHeroQuizzCompleteCallback = quizz => { return quizz.getResponse().map(result => result.content) } //Callback for complete event (survey quizz) const surveyQuizzCompleteCallback = quizz => { return quizz.getResponse().map(result => ({question: result.content, answer: result.answers[0].content})) } class App extends Component { constructor(props) { super(props) //Quizz instantiation const quizz = new Queez(this.getCompleteConfig(configSuperHero, superHeroQuizzCompleteCallback)) this.state = {quizz} } render() { const {quizz, results} = this.state if (!quizz) return <div>No quizz found :(</div> return ( <div className="App"> <QuizzTabs reset={(config, callback) => this.reset(config, callback)}/> <h1>{quizz.custom.title}</h1> <ul> {quizz.questions.map((question, i) => { return ( <Question question={question} key={i} respond={(questionId, answerId) => this.respond(questionId, answerId)} unRespond={(questionId, answerId) => this.unRespond(questionId, answerId)} /> )}) } </ul> {results ? <JSONTree data={results} /> : null} </div> ) } respond(questionId, answerId) { const quizz = this.state.quizz quizz.getQuestion(questionId).respond(answerId) this.setState({quizz}) } unRespond(questionId, answerId) { const quizz = this.state.quizz quizz.getQuestion(questionId).unRespond(answerId) this.setState({quizz}) } //Add complete event callback to the given config getCompleteConfig(config, callback) { config.callbacks = { onQuizzComplete: [ quizz => this.setState({results: callback(quizz)}) ] } return config } reset(config, callback) { const quizz = new Queez(this.getCompleteConfig(config, callback)) this.setState({quizz, results: null}) } } const QuizzTabs = ({reset}) => ( <div> <button onClick={() => reset(configSuperHero, superHeroQuizzCompleteCallback)}>Super hero</button> <button onClick={() => reset(configSurvey, surveyQuizzCompleteCallback)}>Survey</button> </div> ) const Question = ({question, respond, unRespond}) => ( <li> <p>{question.content}</p> <ul> {question.answers.map((answer, i) => { return ( <Answer answer={answer} key={i} respond={answerId => respond(question.id, answerId)} unRespond={answerId => unRespond(question.id, answerId)} isSelected={question.answersIds.includes(answer.id)} /> ) })} </ul> </li> ) const Answer = ({answer, respond, unRespond, isSelected}) => { const style = isSelected ? {color: 'red'} : {} const onClick = isSelected ? unRespond : respond return <button onClick={() => onClick(answer.id)} style={style}>{answer.content}</button> } export default App; ``` ## Development: ``` npm install //Install node modules gulp //Start gulp watching and compile src npm test //Run tests ``` ## License : MIT