def run(self):
        """
            process the multiplechoice directive and generate html for output.

            :param self:
            :return: An MChoiceNode.
            """

        super(MChoice, self).run()

        TEMPLATE_START = '''
            <div class="%(divclass)s">
            <ul data-component="multiplechoice" data-multipleanswers="%(multipleAnswers)s" %(random)s id="%(divid)s">
            '''

        OPTION = '''
            <li data-component="answer" %(is_correct)s id="%(divid)s_opt_%(alabel)s">%(atext)s</li><li data-component="feedback" id="%(divid)s_opt_%(alabel)s">%(feedtext)s</li>
            '''

        TEMPLATE_END = '''

            </ul>
            </div>
            '''
        addQuestionToDB(self)

        mcNode = MChoiceNode(self.options, rawsource=self.block_text)
        mcNode.source, mcNode.line = self.state_machine.get_source_and_line(self.lineno)
        mcNode.template_start = TEMPLATE_START
        mcNode.template_option = OPTION
        mcNode.template_end = TEMPLATE_END

        self.state.nested_parse(self.content, self.content_offset, mcNode)
        env = self.state.document.settings.env
        self.options['divclass'] = env.config.mchoice_div_class
        # Expected _`structure`, with assigned variable names and transformations made:
        #
        # .. code-block::
        #   :number-lines:
        #
        #   mcNode = MChoiceNode()
        #       Item 1 of problem text
        #       ...
        #       Item n of problem text
        #       answers_bullet_list = bullet_list() -> AnswersBulletList() <-- last item of mcNode may be a bulleted list of answers and feedback.
        #           answer_list_item = list_item() -> AnswerListItem()
        #               Item 1 of text for answer A
        #               ...
        #               Item n of text for answer A
        #               feedback_bullet_list = bullet_list() -> FeedbackBulletList() <-- last item must be a bulleted list containing feedback.
        #                   feedback_list_item = list_item() -> FeedbackListItem()   <-- A single item in the list, which contains the feedback.
        #           answer_list_item = list_item() -> AnswerListItem()
        #               Item 1 of text for answer B
        #               ...and so on...
        #
        # See if the last item is a list. If so, and questions/answers weren't specified as options, assume it contains questions and answers.
        answers_bullet_list = mcNode[-1] if len(mcNode) else None
        if isinstance(answers_bullet_list, nodes.bullet_list) and ('answer_a' not in self.options and ('correct' not in self.options)):
            # Accumulate the correct answers.
            correct_answers = []

            # Walk it, processing each answer and its associated feedback.
            for answer_list_item in answers_bullet_list:
                assert isinstance(answer_list_item, nodes.list_item)

                # Look for the feedback for this answer -- the last child of this answer list item.
                feedback_bullet_list = answer_list_item[-1]
                if ((not isinstance(feedback_bullet_list, nodes.bullet_list) or
                  # It should have just one item (the feedback itself).
                  (len(feedback_bullet_list) != 1))):
                    raise self.error('On line {}, a single-item list must be nested under each answer.'.format(get_node_line(feedback_bullet_list)))

                # Check for a correct answer.
                feedback_list_item = feedback_bullet_list[0]
                assert isinstance(feedback_list_item, nodes.list_item)
                if feedback_bullet_list['bullet'] == '+':
                    correct_answers.append(chr(answer_list_item.parent.index(answer_list_item) + ord('a')))

                # Change the feedback list item (which is currently a generic list_item) to our special node class (a FeedbackListItem).
                feedback_list_item.replace_self(FeedbackListItem(feedback_list_item.rawsource, *feedback_list_item.children, **feedback_list_item.attributes))

                # Change the feedback bulleted list (currently a bullet_list) to our class (a FeedbackBulletList).
                feedback_bullet_list.replace_self(FeedbackBulletList(feedback_bullet_list.rawsource, *feedback_bullet_list.children, **feedback_bullet_list.attributes))

                # Change the answer list item (currently a list_item) to an AnswerListItem.
                answer_list_item.replace_self(AnswerListItem(answer_list_item.rawsource, *answer_list_item.children, **answer_list_item.attributes))

            # Change the answer bulleted list (currently a bullet_list) to an AnswersBulletList.
            answers_bullet_list.replace_self(AnswersBulletList(answers_bullet_list.rawsource, *answers_bullet_list.children, **answers_bullet_list.attributes))
            # Store the correct answers.
            self.options['correct'] = ','.join(correct_answers)

        # Check that a correct answer was provided.
        if not self.options.get('correct'):
            raise self.error('No correct answer specified.')
        return [mcNode]
Ejemplo n.º 2
0
    def run(self):
        """
            process the multiplechoice directive and generate html for output.

            :param self:
            :return: An MChoiceNode.
            """

        super(MChoice, self).run()

        TEMPLATE_START = """
            <div class="%(divclass)s">
            <ul data-component="multiplechoice" data-question_label="%(question_label)s" data-multipleanswers="%(multipleAnswers)s" %(random)s id="%(divid)s" %(optional)s>
            """

        OPTION = """
            <li data-component="answer" %(is_correct)s id="%(divid)s_opt_%(alabel)s">%(atext)s</li><li data-component="feedback">%(feedtext)s</li>
            """

        TEMPLATE_END = """

            </ul>
            </div>
            """
        addQuestionToDB(self)

        mcNode = MChoiceNode(self.options, rawsource=self.block_text)
        mcNode.source, mcNode.line = self.state_machine.get_source_and_line(
            self.lineno)
        mcNode.template_start = TEMPLATE_START
        mcNode.template_option = OPTION
        mcNode.template_end = TEMPLATE_END

        # For MChoice its better to insert the qnum into the content before further processing.
        self.updateContent()

        self.state.nested_parse(self.content, self.content_offset, mcNode)
        env = self.state.document.settings.env
        self.options["divclass"] = env.config.mchoice_div_class
        # Expected _`structure`, with assigned variable names and transformations made:
        #
        # .. code-block::
        #   :number-lines:
        #
        #   mcNode = MChoiceNode()
        #       Item 1 of problem text
        #       ...
        #       Item n of problem text
        #       answers_bullet_list = bullet_list() -> AnswersBulletList() <-- last item of mcNode may be a bulleted list of answers and feedback.
        #           answer_list_item = list_item() -> AnswerListItem()
        #               Item 1 of text for answer A
        #               ...
        #               Item n of text for answer A
        #               feedback_bullet_list = bullet_list() -> FeedbackBulletList() <-- last item must be a bulleted list containing feedback.
        #                   feedback_list_item = list_item() -> FeedbackListItem()   <-- A single item in the list, which contains the feedback.
        #           answer_list_item = list_item() -> AnswerListItem()
        #               Item 1 of text for answer B
        #               ...and so on...
        #
        # See if the last item is a list. If so, and questions/answers weren't specified as options, assume it contains questions and answers.
        answers_bullet_list = mcNode[-1] if len(mcNode) else None
        if isinstance(answers_bullet_list,
                      nodes.bullet_list) and ("answer_a" not in self.options
                                              and
                                              ("correct" not in self.options)):
            # Accumulate the correct answers.
            correct_answers = []

            # Walk it, processing each answer and its associated feedback.
            for answer_list_item in answers_bullet_list:
                assert isinstance(answer_list_item, nodes.list_item)

                # Look for the feedback for this answer -- the last child of this answer list item.
                feedback_bullet_list = answer_list_item[-1]
                if (not isinstance(feedback_bullet_list, nodes.bullet_list) or
                        # It should have just one item (the feedback itself).
                    (len(feedback_bullet_list) != 1)):
                    raise self.error(
                        "On line {}, a single-item list must be nested under each answer."
                        .format(get_node_line(feedback_bullet_list)))

                # Check for a correct answer.
                feedback_list_item = feedback_bullet_list[0]
                assert isinstance(feedback_list_item, nodes.list_item)
                if feedback_bullet_list["bullet"] == "+":
                    correct_answers.append(
                        chr(
                            answer_list_item.parent.index(answer_list_item) +
                            ord("a")))

                # Change the feedback list item (which is currently a generic list_item) to our special node class (a FeedbackListItem).
                feedback_list_item.replace_self(
                    FeedbackListItem(feedback_list_item.rawsource,
                                     *feedback_list_item.children,
                                     **feedback_list_item.attributes))

                # Change the feedback bulleted list (currently a bullet_list) to our class (a FeedbackBulletList).
                feedback_bullet_list.replace_self(
                    FeedbackBulletList(feedback_bullet_list.rawsource,
                                       *feedback_bullet_list.children,
                                       **feedback_bullet_list.attributes))

                # Change the answer list item (currently a list_item) to an AnswerListItem.
                answer_list_item.replace_self(
                    AnswerListItem(answer_list_item.rawsource,
                                   *answer_list_item.children,
                                   **answer_list_item.attributes))

            # Change the answer bulleted list (currently a bullet_list) to an AnswersBulletList.
            answers_bullet_list.replace_self(
                AnswersBulletList(answers_bullet_list.rawsource,
                                  *answers_bullet_list.children,
                                  **answers_bullet_list.attributes))
            # Store the correct answers.
            self.options["correct"] = ",".join(correct_answers)

        maybeAddToAssignment(self)
        # Check that a correct answer was provided.
        if not self.options.get("correct"):
            raise self.error("No correct answer specified.")
        return [mcNode]
        # See if the last item is a list. If so, and questions/answers weren't specified as options, assume it contains questions and answers.
        answers_bullet_list = mcNode[-1] if len(mcNode) else None
        if isinstance(answers_bullet_list, nodes.bullet_list) and ('answer_a' not in self.options and ('correct' not in self.options)):
            # Accumulate the correct answers.
            correct_answers = []

            # Walk it, processing each answer and its associated feedback.
            for answer_list_item in answers_bullet_list:
                assert isinstance(answer_list_item, nodes.list_item)

                # Look for the feedback for this answer -- the last child of this answer list item.
                feedback_bullet_list = answer_list_item[-1]
                if ((not isinstance(feedback_bullet_list, nodes.bullet_list) or
                  # It should have just one item (the feedback itself).
                  (len(feedback_bullet_list) != 1))):
                    raise self.error('On line {}, a single-item list must be nested under each answer.'.format(get_node_line(feedback_bullet_list)))

                # Check for a correct answer.
                feedback_list_item = feedback_bullet_list[0]
                assert isinstance(feedback_list_item, nodes.list_item)
                if feedback_bullet_list['bullet'] == '+':
                    correct_answers.append(chr(answer_list_item.parent.index(answer_list_item) + ord('a')))

                # Change the feedback list item (which is currently a generic list_item) to our special node class (a FeedbackListItem).
                feedback_list_item.replace_self(FeedbackListItem(feedback_list_item.rawsource, *feedback_list_item.children, **feedback_list_item.attributes))

                # Change the feedback bulleted list (currently a bullet_list) to our class (a FeedbackBulletList).
                feedback_bullet_list.replace_self(FeedbackBulletList(feedback_bullet_list.rawsource, *feedback_bullet_list.children, **feedback_bullet_list.attributes))

                # Change the answer list item (currently a list_item) to an AnswerListItem.
                answer_list_item.replace_self(AnswerListItem(answer_list_item.rawsource, *answer_list_item.children, **answer_list_item.attributes))