]> _ Git - fluidbook-toolbox-quiz.git/commitdiff
wip #6182 @3
authorVincent Vanwaelscappel <vincent@cubedesigners.com>
Fri, 18 Aug 2023 15:59:07 +0000 (17:59 +0200)
committerVincent Vanwaelscappel <vincent@cubedesigners.com>
Fri, 18 Aug 2023 15:59:07 +0000 (17:59 +0200)
14 files changed:
1  2 
.editorconfig
js/quiz.accessibility.js
js/quiz.animations.js
js/quiz.js
js/quiz.question.js
js/quiz.screen.intro.js
js/quiz.screens.js
js/quiz.utils.js
style/103-question-multiple.sass
views/footer.blade.php
views/header_question.blade.php
views/index.blade.php
views/screens/question_draganddrop.blade.php
views/screens/question_multiple.blade.php

diff --cc .editorconfig
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2436a504935fa1194af4971ded5cedd4cf78ea21
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,20 @@@
++root = true
++
++[*]
++charset = utf-8
++end_of_line = lf
++insert_final_newline = true
++indent_style = space
++indent_size = 4
++trim_trailing_whitespace = true
++
++[*.sh]
++charset = utf-8
++end_of_line = lf
++insert_final_newline = true
++
++[*.md]
++trim_trailing_whitespace = false
++
++[*.{yml,yaml}]
++indent_size = 2
index 17a49fd701e2191ab312a956a86f636eaecec458,0000000000000000000000000000000000000000..bf3459686c758a1788c34c36aa81fc75449fee73
mode 100644,000000..100644
--- /dev/null
@@@ -1,28 -1,0 +1,28 @@@
-             console.log(e);
 +function QuizAccessibility(quiz) {
 +    this.quiz = quiz;
 +    this.initShortcuts();
 +}
 +
 +
 +QuizAccessibility.prototype = {
 +    initShortcuts: function () {
 +        let $this = this;
 +        $(document).on('keyup', function (e) {
-                 if ($this.quiz.utils.isVisible($(this))) {
-                     console.log('click ',$(this));
++
 +            let key = e.key.toLocaleUpperCase();
 +            if (key === ' ') {
 +                key = 'Space';
 +            }
 +            $('[aria-keyshortcuts="' + key + '"]').each(function () {
++                if ($this.quiz.utils.isEnabled($(this))) {
++                    console.log('click ', $(this));
 +                    $(this).get(0).click();
 +                    return true;
 +                }
 +            });
 +        });
 +    },
 +}
 +
 +export default QuizAccessibility;
 +
index bd83cbaa073851ea321f1205a987031629106121,e71b64a18d140b3a3d1616750136b545cf6927d9..97bc6b7b5b943821e41cf8a4f274d632b75a53cd
@@@ -1,12 -1,12 +1,26 @@@
++import gsap from "gsap";
++
  const lottie = require("lottie-web");
  const $ = require("cash-dom");
  
--
  function QuizAnimations(quiz) {
      this.quiz = quiz;
++    this.initEvents();
  }
  
  QuizAnimations.prototype = {
++
++    initEvents:function(){
++        // Animate buttons on mouse down and up
++        $(document).on("mousedown", ".btn", function () {
++            gsap.to($(this), {scale: .95, duration: .2, ease: "back.inOut"});
++        }).on("mouseup", ".btn", function () {
++            gsap.to($(this), {scale: 1, duration: .2});
++        });
++    },
++
++
++
      // Load the animation "name" in container
      load: function (name, container, replace) {
          let json = this.quiz.data.animations[name];
diff --cc js/quiz.js
index fc6ae4f7521e40a71fd931b53e497b97a1eb1976,10dafa22b9f6d113c21f5a598c20ff1aad0dac33..3f7428192c7d07daceb2c99051dafcf100dae3f9
@@@ -57,38 -61,91 +57,9 @@@ Quiz.prototype = 
          });
          this.quizResize();
  
 -        //animer le texte d'intro
 -        let title = new SplitType("#welcome h2", { types: 'words, chars' })
 -        let text = new SplitType("#welcome p", { types: 'words, chars' })
 -        gsap.from(title.words, {
 -            opacity: 0,
 -            y: 20,
 -            duration: 1,
 -            stagger: 0.05,
 -            onStart: () => {
 -                $(title.elements).removeClass("none")
 -            }
 -        })
 -        gsap.to(text.words, {
 -            opacity: 1,
 -            y: 0,
 -            duration: 1,
 -            ease: "power1.inOut",
 -            stagger: {
 -                amount: 0.2
 -            },
 -            onStart: () => {
 -                $(text.elements).removeClass("none")
 -            }
 -        })
 -
 -        // Préparer les réponses du joueur dans l'objet this.responses
 -        // à chaque fois que le formulaire change de valeur
 -        $(document).on("change", ".active-screen form", function(e) {
 -            $this.responses = []
 -            $(this).find("input:checked").each(function() {
 -                $this.responses.push(parseInt($(this).val()))
 -            });
 -        })
 -
 -        // Passer à la page suivante
 -        // Valider les réponses
 -        $(document).on("click", ".next .action", function () {
 -            let responses = $this.responses
 -            $this.next(responses);
 -            $this.responses = []
 -        })
 -        key('space', function (e){
 -            e.preventDefault()
 -            $this.next();
 -        })
 -
 -        // Réinitialiser les réponses
 -        $(document).on("click", ".btn.reset", function() {
 -            $this.resetForm()
 -        })
 -        key('r', function (e){
 -            e.preventDefault()
 -            $this.resetForm()
 -        })
 -
 -        if(key.isPressed('R')) {
 -            alert('r')
 -        }
 -
 -        $(document).on("mousedown", ".btn", function() {
 -            gsap.to($(this), { scale: .95, duration: .2, ease: "back.inOut" });
 -        }).on("mouseup", ".btn", function() {
 -            gsap.to($(this), { scale: 1, duration: .2 });
 -        })
 -
 -        //
 -        $(document).on("click", ".toggle-answers-review", function() {
 -            $(".score-answers-review_container").toggleClass("active")
 -        })
 -
 -        //
 -        this.activeNav()
 -    },
 -
 -    start: function() {
 -        const $this = this
 -        gsap.timeline().to("#welcome-screen", {
 -            opacity: 0,
 -            onComplete: function() {
 -                let responses = $this.responses
 -                $this.next(responses);
 -                $("#welcome-screen").removeClass("next active-screen").addClass("none").next(".container-screen").removeClass("none").addClass("next active-screen")
 -                $this.activeNav(1)
 -            }
 -        })
 +        // Afficher l'écran d'introduction et lancer l'animation
 +        this.screens.intro.show();
-         // Préparer les réponses du joueur dans l'objet this.responses
-         // à chaque fois que le formulaire change de valeur
-         $(document).on("change", ".active-screen form", function (e) {
-             $this.responses = []
-             $(this).find("input:checked").each(function () {
-                 $this.responses.push(parseInt($(this).val()))
-             });
-         })
-         // Passer à la page suivante
-         // Valider les réponses
-         $(document).on("click", ".next .action", function () {
-             let responses = $this.responses
-             $this.next(responses);
-             $this.responses = []
-         })
-         // Réinitialiser les réponses
-         $(document).on("click", ".btn.reset", function () {
-             $this.resetForm()
-         })
-         $(document).on("mousedown", ".btn", function () {
-             gsap.to($(this), {scale: .95, duration: .2, ease: "back.inOut"});
-         }).on("mouseup", ".btn", function () {
-             gsap.to($(this), {scale: 1, duration: .2});
-         })
 +        this.progressbar.update();
      },
  
      updateIcons: function () {
index 8c90f4da931d3ed084546cf9d75a265f00796d54,f659d07e05fddaa8e2224f047ad3b88601bb66b0..97c7c0dace3d39ed8b8eee770ea54f93250878e3
@@@ -1,35 -1,35 +1,47 @@@
--var QuizQuestion = function(quiz) {
++var QuizQuestion = function (quiz) {
      this.quiz = quiz;
      this.init();
  }
  
  QuizQuestion.prototype = {
--    init: function(){
++    init: function () {
  
      },
  
--    getAll: function() {
--      return this.quiz.data.questions
++    getAll: function () {
++        return this.quiz.data.questions
      },
  
--    byPosition: function(pos) {
++    byPosition: function (pos) {
          return this.quiz.data.questions[parseInt(pos)]
      },
  
--    currentPosition: function() {
--        return $(document).find(".active-screen").data("position");
++    /**
++     *
++     * @returns {number}
++     */
++    currentPosition: function () {
++        let screenName = this.quiz.screens.getActiveScreen().data('screen');
++        if (screenName.indexOf('q-') === 0) {
++            return parseInt(screenName.substring(2));
++        }
++        return -1;
      },
  
--    current: function() {
++    current: function () {
          let currentPosition = this.currentPosition()
          return this.byPosition(currentPosition)
      },
  
--    last: function(position) {
--        return this.quiz.data.questions.length === parseInt(position)
++    last: function (position) {
++        return this.count() === parseInt(position)
      },
  
--    getFormData: function(responses) {
++    count: function () {
++        return this.quiz.data.questions.length;
++    },
++
++    getFormData: function (responses) {
          //
      },
  }
index 195be8504078b7cf309d7ecf0cb4fb6faa70bc8a,0000000000000000000000000000000000000000..b468f2d6a43a3f6ba928c712e40a4fb17cd0dc15
mode 100644,000000..100644
--- /dev/null
@@@ -1,39 -1,0 +1,38 @@@
-                 $this.screens.showScreen('q0');
 +import gsap from "gsap";
 +import SplitType from 'split-type';
 +
 +function QuizScreenIntro(screens) {
 +    this.quiz = screens.quiz;
 +    this.screens = screens;
 +}
 +
 +QuizScreenIntro.prototype = {
 +    show: function () {
 +        let $this = this;
 +
 +        this.screens.showScreen('welcome', function () {
 +            $this.animate();
 +            $("#start").on("click", function () {
-         console.log('animate');
++                $this.screens.showScreen('q-0');
 +                return false;
 +            });
 +        });
 +    },
 +
 +    animate: function () {
- export default QuizScreenIntro;
 +        //animer le texte d'intro
 +        let title = new SplitType("#welcome h2", {types: 'words, chars'})
 +        let text = new SplitType("#welcome p", {types: 'words, chars'})
 +        gsap.from(title.words, {
 +            opacity: 0, y: 20, duration: 1, stagger: 0.05
 +        })
 +        gsap.to(text.words, {
 +            opacity: 1, y: 0, duration: 1, ease: "power1.inOut", stagger: {
 +                amount: 0.2
 +            }
 +        })
 +    },
 +
 +}
 +
++export default QuizScreenIntro;
index 6daca92be9aeefb970a0f7b2fbbdafae7581d2d1,0000000000000000000000000000000000000000..72f59554886c2c2ac54a69ad143336bd83e69996
mode 100644,000000..100644
--- /dev/null
@@@ -1,152 -1,0 +1,253 @@@
-      * @param screen
 +import gsap from "gsap";
 +
 +import QuizScreenIntro from './quiz.screen.intro';
 +import QuizScreenOutro from "./quiz.screen.outro";
 +
 +function QuizScreens(quiz) {
 +    this.quiz = quiz;
++    this.activeScreen = null;
 +    this.intro = new QuizScreenIntro(this);
 +    this.outro = new QuizScreenOutro(this);
++    this.initEvents();
 +}
 +
 +QuizScreens.prototype = {
++
++    initEvents: function () {
++        const $this = this;
++        // Réinitialiser les réponses
++        $(document).on("click", ".btn.reset", function () {
++            $this.resetForm();
++        });
++
++        // Préparer les réponses du joueur dans l'objet this.responses
++        // à chaque fois que le formulaire change de valeur
++        $(document).on("change", ".active-screen form:not(.disabled)", function (e) {
++            $this.updateUserAnswers();
++        });
++
++        // Cliquer sur le bouton suivant
++        $(document).on("click", ".next .action", function () {
++            if ($(this).hasClass('validate')) {
++                let review = $this.sendUserAnswers();
++                // Si la revue instantanée est activée, on affiche les résultats
++                if (this.quiz.data.instantReview) {
++                    $this.instantReview(review);
++                } else {
++                    // Sinon, on passe directement à la question suivante
++                    $this.nextQuestion();
++                }
++            } else {
++                // Bouton continuer, on était dans la revue instantanée, on passe à la question suivante
++                $this.nextQuestion();
++            }
++        });
++    },
++
++    instantReview: function (review) {
++        let form = this.getCurrentForm();
++        let activeScreen = this.getActiveScreen();
++        // Disable form, we don't want the user be able to click on items
++        $(form).addClass('disabled');
++
++        // Remove validate button and show continue button
++        $(activeScreen).find('.btn.validate').addClass('none');
++        $(activeScreen).find('.btn.continue').removeClass('none');
++
++        for (let k in results) {
++            let answerResult = results[k];
++
++            let n = (parseInt(k) + 1);
++            let icon = getSpriteIcon("quiz-ok");
++            let $el = form.fid(".list-item:nth-of-type(" + n + ") label");
++            $el.addClass(answerResult);
++            if (answerResult === "nok") {
++                icon = getSpriteIcon("quiz-wrong");
++            }
++            if (answerResult !== "neutral") {
++                $el.find(".access").addClass(answerResult).html(icon);
++            } else {
++                $el.find(".access").remove();
++            }
++        }
++    },
++
++    nextQuestion: function () {
++        let nextQuestionIndex = this.quiz.question.currentPosition() + 1;
++        let nextScreen;
++        if (nextQuestionIndex >= this.quiz.question.count()) {
++            nextScreen = 'review';
++        } else {
++            nextScreen = 'q-' + nextQuestionIndex;
++        }
++        this.showScreen(nextScreen);
++    },
++
++    sendUserAnswers: function () {
++        return this.quiz.score.setAnswer(this.quiz.question.currentPosition(), this.currentQuestionAnswers)
++    },
++
++    updateUserAnswers: function () {
++        const $this = this;
++        this.currentQuestionAnswers = []
++        $(".active-screen form").find("input:checked").each(function () {
++            $this.currentQuestionAnswers.push(parseInt($(this).val()));
++        });
++    },
++
 +    /**
 +     *
-             callback();
++     * @param screen string
++     * @param callback function
 +     */
 +    showScreen: function (screen, callback) {
 +        const $this = this;
 +        let screenToShow = $('[data-screen="' + screen + '"]');
 +        this.hideCurrentScreen(function () {
 +            screenToShow.removeClass("none").addClass("next active-screen");
-                 if (status[this.question.currentPosition()].ok === "not answered") {
++            if (callback !== undefined) {
++                callback();
++            }
++            $this.activeScreen = screenToShow;
 +        });
 +    },
 +
 +    next: function (responses) {
 +        // on arrête l'animation si le joueur passe à la question suivante
 +        this.stopAnimationValidation()
 +
 +        let status = quiz.score.questionStatus
 +        let currentPosition = quiz.score.lastAnsweredQuestion + 1
 +
 +        const $el = $(".active-screen .btn.action")
 +
 +        this.quiz.score.updateScore()
 +        // if form exist and responses are validated
 +        // dont miss to add this second condition
 +        if ($(".active-screen form").length > 0) {
 +            if (status.length > 0) {
-         $("form").find("input").prop("checked", false)
++                if (status[this.quiz.question.currentPosition()].ok === "not answered") {
 +                    this.validateResponse(responses);
 +                    this.updateBtnValidation("validated")
 +                    return false
 +                }
 +            }
 +        }
 +
 +        $el.parents(".container-screen").addClass("none").removeClass("next active-screen").next(".container-screen").removeClass("none").addClass("next active-screen")
 +        this.resetForm()
 +        // on incrémente de 1 la position actuelle de la question (qui commence à l'index zero)
 +        // pour récupérer le premier enfant de la nav
 +        this.quiz.progressbar.update((parseInt(this.quiz.question.currentPosition()) + 1))
 +        this.updateBtnValidation()
 +        // si c'est la dernière question a été validée alors on affiche le résultat au prochain screen
 +        if (this.quiz.question.last(currentPosition)) {
 +            this.outro.show();
 +        }
 +    },
 +
++    getCurrentForm: function () {
++        return $(this.activeScreen).find('form');
++    },
 +
 +    resetForm: () => {
-         const form = $(".active-screen form")
-         const activeScreen = $(".active-screen")
-         const position = activeScreen.data("position")
++        this.getCurrentForm().find("input").prop("checked", false)
 +    },
 +
 +    updateBtnValidation: function (status) {
 +        let $btnAction = $(".footer-question .action"), validationText = $btnAction.data("validation-text"),
 +            continueText = $btnAction.data("continue-text")
 +
 +        $btnAction.find('.text').text(status === "validated" ? continueText : validationText)
 +    },
 +
 +    animationValidation: function (status) {
 +        let selector = $("#anim")
 +        let text = status === "NOK" ? "Not quite" : "Perfect"
 +        let $this = this
 +        this.quiz.animations.load(status, selector, {'\\$text': text});
 +        selector.addClass("active")
 +        this.timeoutAnimation = setTimeout(function (e) {
 +            $this.stopAnimationValidation()
 +        }, 10000)
 +    },
 +
 +    stopAnimationValidation: function () {
 +        $("#anim").removeClass("active").empty()
 +        if (this.timeoutAnimation) {
 +            clearTimeout(this.timeoutAnimation);
 +        }
 +    },
 +
++    getActiveScreen() {
++        return this.activeScreen;
++    },
++
 +
 +    validateResponse: function (responses) {
-                 let validated = quiz.score.setAnswer(position, responses);
++        const form = this.getCurrentForm();
++        const questionIndex = this.quiz.question.currentPosition();
 +
 +        if (form) {
 +            if (form.length > 0) {
-                 this.resultAfterValidation(validated.status[position].answers)
++                let validated = quiz.score.setAnswer(questionIndex, responses);
 +                if (validated.ok === "ok") {
 +                    this.animationValidation("OK")
 +                } else {
 +                    this.animationValidation("NOK")
 +                }
-     resultAfterValidation: function (datas) {
-         for (let k in datas) {
++                this.resultAfterValidation(validated.status[questionIndex].answers)
 +            }
 +            return false
 +        }
 +    },
 +
 +
-             $el.addClass(datas[k])
-             if (datas[k] === "nok") {
++    resultAfterValidation: function (results) {
++        for (let k in results) {
++            let answerResult = results[k];
++
 +            let n = (parseInt(k) + 1)
 +            let icon = getSpriteIcon("quiz-ok")
 +            let $el = $(".active-screen .question-multiple .list-item:nth-of-type(" + n + ") label")
-             if (datas[k] !== "neutral") {
-                 $el.find(".access").addClass(datas[k]).html(icon)
++            $el.addClass(answerResult)
++            if (answerResult === "nok") {
 +                icon = getSpriteIcon("quiz-wrong")
 +            }
-             callback();
++            if (answerResult !== "neutral") {
++                $el.find(".access").addClass(answerResult).html(icon)
++            } else {
++                $el.find(".access").remove();
 +            }
 +        }
 +    },
 +
 +
 +    /**
 +     * Si un écran est affiché, on le masque puis on exécute le callback. Sinon, on exécute immédiatement le callback
 +     * @param callback
 +     */
 +    hideCurrentScreen: function (callback) {
 +        let cb = function (screen) {
 +            if (screen.length > 0) {
 +                $(screen).removeClass("next active-screen").addClass("none");
 +            }
- export default QuizScreens;
++            if (callback !== undefined) {
++                callback();
++            }
 +        };
 +
 +        let currentScreen = $('.container-screen:not(.none)');
 +        if (currentScreen.length > 0) {
 +            gsap.timeline().to(currentScreen, {
 +                autoAlpha: 0, onComplete: function () {
 +                    cb(currentScreen);
 +                }
 +            })
 +        } else {
 +            cb(currentScreen);
 +        }
 +    },
 +};
 +
++export default QuizScreens;
index 4e289013395786f6899d81a9153fe2714221115e,0000000000000000000000000000000000000000..a0abb1e117dbcc455eb06e7d296ab77c7e7364c1
mode 100644,000000..100644
--- /dev/null
@@@ -1,15 -1,0 +1,27 @@@
 +function QuizUtils() {
 +
 +}
 +
 +QuizUtils.prototype = {
 +    isVisible(e) {
 +        if ($(e).length == 0) {
 +            return false;
 +        }
 +        let elt = $(e).get(0);
 +        return elt.offsetWidth || elt.offsetHeight || elt.getClientRects().length;
++    },
++    isEnabled: function (e) {
++        if (!this.isVisible(e)) {
++            return false;
++        }
++        if ($(e).css('pointer-events') === 'none') {
++            return false;
++        }
++        if ($(e).hasClass('disabled') || $(e).closest('.disabled').length > 0) {
++            return false;
++        }
++        return true;
 +    }
 +}
 +
 +export default QuizUtils;
index fed8e2e90815a5da11077a8ada24b05c60e89047,7dc8c3a26baa63c8968271c00a7d570a059222a0..8f61c6cd6743ceb97eb8be7d3f8ba544bcc1d91f
@@@ -1,21 -1,29 +1,29 @@@
  .screen.question-multiple
 -    top: 45px
 -    +above(992px)
 -        top: 93px
 +    top: 93px
++
++    form
++        &.disabled
++            label
++                pointer-events: none
++
      .list
          display: grid
 +        grid-template-columns: repeat(2, 1fr)
          grid-gap: 16px
 -        +below($screenSizeMobile)
 -            grid-gap: 8px
 -        +breakpoint(md)
 -            grid-template-columns: repeat(2, 1fr)
++
          &-item
              label
                  width: 100%
                  height: 58px
                  @extend .radius
--                +opacity(.80,background-color,$neutral-color)
--                +flex-config(space-between,false,false,center)
++                +opacity(.80, background-color, $neutral-color)
++                +flex-config(space-between, false, false, center)
                  padding: 0 16px
                  cursor: pointer
                  border: 2px solid rgba($texts-color, .24)
                  position: relative
                  overflow: hidden
 -                +below($screenSizeMobile)
 -                    height: 56px
 -                    +font-size(14)
++
                  &:after
                      content: ""
                      width: 100%
                      top: 0
                      left: 0
                      transition: background-color .1s ease-out
++
                  &.ok:after,
                  &.missed:after
                      //
--                    +opacity(.24,background-color,$ok-color)
++                    +opacity(.24, background-color, $ok-color)
++
                  *
                      z-index: 1
  
--            input:checked+label
++            input:checked + label
                  border-color: $texts-color
                  transition: border-color .1s ease-out
++
                  &:after
                      +opacity(.16)
++
                  &.nok:after
                      background: transparent
index 6aee4f12a975bc89a3f6c1b797b781add9813535,bcadcbaa49674b1cd73db1ee5125dfc3c780bd28..dc75cc1413aa0d74e5377ed5aa9b544eee053072
@@@ -5,16 -5,15 +5,21 @@@
              <span class="access">R</span>
          </a>
      @endisset
-     <a class="btn primary action" data-validation-text="Validate answer" data-continue-text="Continue"
-        aria-keyshortcuts="Space">
 -    <a class="btn primary action" data-validation-text="Validate answer" data-continue-text="Continue">
--        <span class="text">{{$text}}</span>
++    <a class="btn primary action validate" aria-keyshortcuts="Space">
++        <span class="text">Validate answer</span>
          <span class="access space">space</span>
          @isset($time)
              <span data-icon="running-man"></span>
          @endisset
      </a>
++    @if($data['instantReview'])
++        <a class="btn primary action none continue" aria-keyshortcuts="Space">
++            <span class="text">Continue</span>
++            <span class="access space">space</span>
++        </a>
++    @endif
      @isset($info)
 -        <a class="btn secondary none">
 +        <a class="btn secondary none" aria-keyshortcuts="F1">
              More infos
              <span class="access infos">F1</span>
          </a>
index dda7f1fa03380a083bf3fc9b5f0deb03ac61173f,dda7f1fa03380a083bf3fc9b5f0deb03ac61173f..59098798d09461884844cd6272bfcb15073dd513
@@@ -5,7 -5,7 +5,7 @@@
              <span class="progress-item"></span>
          @endfor
      </div>
--    <h1 id="titleQuestion">{{$data['question']}}</h1>
++    <h1 id="titleQuestion">{{$question['question']}}</h1>
      @if($data['type'] === "draganddrop")
          <h2 class="subtitle">Use arrow keys to move the cards to the corresponding zone</h2>
      @endif
index 1a501d7e153353846c88df79307260e97d209e49,88b61a07452bb2ccebbad3ad7d2dffc0dc7785d5..c4f77a5186325146c35a3fbf54f5f985e258ed88
@@@ -21,7 -21,7 +21,7 @@@
              @include('screens.intro', ['data'=> $data])
          @endif
          @foreach($data->questions as $key => $question)
--            @include('screens.question_'.$question['type'], ['theme' => $data->theme, 'data'=> $question, 'max' => $totalQuestion, 'position' => $key, 'alphabet' => $alphabet])
++            @include('screens.question_'.$question['type'], ['theme' => $data->theme,'data'=>$data, 'question'=> $question, 'max' => $totalQuestion, 'position' => $key, 'alphabet' => $alphabet])
          @endforeach
          @include('screens.outro', ['data'=> $data])
          <div id="anim"></div>
index a0e65496ed07669862e18791247a3a6653f1b9ce,469b4bc7cd23c7744690c29ce657eb26f828ec1a..7d1645f0c9a00554fa80d27ce7ad1ee5706010fd
@@@ -1,4 -1,4 +1,4 @@@
- <div class="container-screen none question-draganddrop" data-screen="q{{$position}}">
 -<div class="container-screen none question-draganddrop" data-position="{{$position}}">
++<div class="container-screen none question-draganddrop" data-screen="q-{{$position}}">
      <div class="screen-image zone-1">
          <img src="{{$theme->draganddropArea1Image}}" />
          <div class="zone-content">
index f1339119c8fccdb0c7f36e56f666e3b809e21bb9,34f66ccaa540eb999d1743cb8ef34e60a829c602..958ff393d8a58348c4e4f960c128df8b79758171
@@@ -1,12 -1,12 +1,12 @@@
- <div class="container-screen none" data-screen="q{{$position}}">
 -<div class="container-screen none" data-position="{{$position}}">
--    @include('header_question', ['data' => $data, 'max' => $max, 'position' => $position])
++<div class="container-screen none" data-screen="q-{{$position}}">
++    @include('header_question', ['question' =>$question, 'max' => $max, 'position' => $position])
      <div class="screen question-multiple">
          <form id="form-{{$position}}">
              <ul class="list">
--                @foreach($data['answers'] as $key => $answer)
++                @foreach($question['answers'] as $key => $answer)
                      <li class="list-item">
 -                        <input type="{{ $data['type'] === "multiple" ? 'checkbox' : 'radio' }}"
 -                               name="{{ $data['type'] === "multiple" ? 'answer-'.$position.$key : 'answer' }}"
 +                        <input type="{{ $data['multiple'] ? 'checkbox' : 'radio' }}"
 +                               name="{{  'answer' }}"
                                 id="question-{{$position.$key}}" class="none" value="{{$key}}">
                          <label for="question-{{$position.$key}}" aria-keyshortcuts="{{$alphabet[$key]}}">
                              <span class="relative">{{$answer['answer']}}</span>
@@@ -18,7 -18,8 +18,7 @@@
          </form>
      </div>
      <div class="screen-image">
 -        <img src="{{$theme->standardImage}}"/>
 -        <img class="mobile question-multiple" src="{{$theme->standardImageMobile}}"/>
 +        <img src="{{$theme->standardImage}}">
      </div>
--    @include('footer', ['data' => $data, 'reset' => true, 'text' => 'Validate answer', 'info' => true])
++    @include('footer', ['question' =>$question, 'data' => $data, 'reset' => true, 'info' => true])
  </div>