Difference between revisions of "Creating mobile question types"

Jump to: navigation, search
(mobile/styles_app.css)
(html template)
Line 38: Line 38:
  
 
==== html template ====
 
==== html template ====
Your question type will need an html/ionic markup template file that controls how it is displayed at runtime. This is the template from the core shortanswer question type and gives an idea of some of the options. You can see a real world examples of this file at  
+
Your question type will need an html/ionic markup template file that controls how it is displayed at runtime. You can see a real world examples of this file at  
 +
 
 
https://github.com/Beedell/moodle-qtype_oumultiresponse/blob/wip1/mobile/oumr.html
 
https://github.com/Beedell/moodle-qtype_oumultiresponse/blob/wip1/mobile/oumr.html
 
and
 
and
 +
 
https://github.com/marcusgreen/moodle-qtype_gapfill/blob/master/mobile/addon-qtype-gapfill.html
 
https://github.com/marcusgreen/moodle-qtype_gapfill/blob/master/mobile/addon-qtype-gapfill.html
 +
 
(oumr.html is probably a more sensible naming convetion)
 
(oumr.html is probably a more sensible naming convetion)
  
Line 47: Line 50:
  
 
<code>
 
<code>
<section ion-list *ngIf="question.text || question.text === ''">
+
<section class="list qtype-YOURQTYPENAME-container qtype-YOURQTYPENAME" ion-list *ngIf="question.text || question.text === ''">
     <ion-item text-wrap>
+
     <ion-item text-wrap class="addon-qtype-YOURQTYPENAME-container qtext">
         <p><core-format-text [component]="component" [componentId]="componentId" [text]="question.text"></core-format-text></p>
+
         <p><core-format-text [component]="component" [componentId]="componentId"  
 +
            [text]="question.text" (afterRender)="questionRendered()"></core-format-text></p>    
 
     </ion-item>
 
     </ion-item>
    <ion-input padding-left type="text" placeholder="{{ 'core.question.answer' | translate }}"
 
    [attr.name]="question.input.name" [value]="question.input.value" autocorrect="off"
 
    [disabled]="question.input.readOnly" [ngClass]="[question.input.correctClass]">
 
    </ion-input>
 
 
</section>
 
</section>
 
</code>
 
</code>

Revision as of 20:10, 1 January 2019

An empty template for creating quiz question types with mobile support is available from here

https://github.com/marcusgreen/moodle-qtype_TEMPLATE

The files that need to be modified/added are

db/mobile.php

defined('MOODLE_INTERNAL') || die();
 
$addons = [
    "qtype_YOURQTYPENAME" => [
        "handlers" => [ // Different places where the add-on will display content.
            'YOURQTYPENAME' => [ // Handler unique name (can be anything).
                'displaydata' => [
                    'title' => 'YOURQTYPENAME question',
                    'icon' => '/question/type/YOURQTYPENAME/pix/icon.gif',
                    'class' => '',
                ],
                'delegate' => 'CoreQuestionDelegate', // Delegate (where to display the link to the add-on).
                'method' => 'mobile_get_YOURQTYPENAME',
                'offlinefunctions' => [
                    'mobile_get_YOURQTYPENAME' => [],// function in classes/output/mobile.php
                ], // Function needs caching for offline.
                'styles' => [
                    'url' => '/question/type/YOURQTYPENAME/mobile/styles_app.css',
                    'version' => '1.00'
                ]
            ]
        ],
        'lang' => [
                    ['pluginname', 'qtype_YOURQTYPENAME'], // matching value in  lang/en/qtype_YOURQTYPENAME
        ],
    ]
];

html template

Your question type will need an html/ionic markup template file that controls how it is displayed at runtime. You can see a real world examples of this file at

https://github.com/Beedell/moodle-qtype_oumultiresponse/blob/wip1/mobile/oumr.html and

https://github.com/marcusgreen/moodle-qtype_gapfill/blob/master/mobile/addon-qtype-gapfill.html

(oumr.html is probably a more sensible naming convetion)

Create a file named mobile/addon-qtype-YOURQTYPENAME.html

<section class="list qtype-YOURQTYPENAME-container qtype-YOURQTYPENAME" ion-list *ngIf="question.text || question.text === ''">
    <ion-item text-wrap class="addon-qtype-YOURQTYPENAME-container qtext">
        <p><core-format-text  [component]="component" [componentId]="componentId" 
            [text]="question.text" (afterRender)="questionRendered()"></core-format-text></p>     
    </ion-item>
</section>

classes/output/mobile.php

This file connects PHP with the html/ionic markup template and the mobile.js javascript which contains most of the runtime logic

namespace qtype_YOURQTYPENAME\output;

defined('MOODLE_INTERNAL') || die();

class mobile {

class mobile {
    public static function mobile_get_YOURQTYPENAME() {
        global $CFG;
        return [
            'templates' => [
                [
                    'id' => 'main',
                    'html' => file_get_contents($CFG->dirroot .'/question/type/YOURQTYPENAME/mobile/addon-qtype-YOURQTYPENAME.html')
                    ]
            ],
            'javascript' => file_get_contents($CFG->dirroot . '/question/type/YOURQTYPENAME/mobile/mobile.js')
        ];
    }
}
   

mobile/mobile.js

var that = this;
var result = {

    componentInit: function() {
        /**
         * If the question is in a readonly state, e.g. after being
         * answered or in the review page then stop any further
         * selections.
         *
         * @param {NodeList} draggables
         * @param {MouseEvent} event
         * @return {string} value of target
         **/
        if (!this.question) {
            console.warn('Aborting because of no question received.');
            return that.CoreQuestionHelperProvider.showComponentError(that.onAbort);
        }
        const div = document.createElement('div');
        div.innerHTML = this.question.html;
         // Get question questiontext.
        const questiontext = div.querySelector('.qtext');

        // Replace Moodle's correct/incorrect and feedback classes with our own.
        this.CoreQuestionHelperProvider.replaceCorrectnessClasses(div);
        this.CoreQuestionHelperProvider.replaceFeedbackClasses(div);

         // Treat the correct/incorrect icons.
        this.CoreQuestionHelperProvider.treatCorrectnessIcons(div);

 
        if (div.querySelector('.readonly') !== null) {
            this.question.readonly = true;
        }
        if (div.querySelector('.feedback') !== null) {
            this.question.feedback = div.querySelector('.feedback');
            this.question.feedbackHTML = true;
        }

        if (typeof this.question.text == 'undefined') {
            this.logger.warn('Aborting because of an error parsing question.', this.question.name);
            return this.CoreQuestionHelperProvider.showComponentError(this.onAbort);
        }

        // Wait for the DOM to be rendered.
        setTimeout(() => {
 
        });
        return true;
    }
};
result;

mobile/styles_app.css

.qtype-YOURQTYPENAME .yourclassname {

    attributename: attributevalue;

}