Creating mobile course formats

Revision as of 10:54, 16 April 2019 by Mark Johnson (talk | contribs) (Initial example of a course format plugin.)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Course format plugins can be supported in the app using the CoureCourseFormatDelegate.

To begin, add a handler for this delegate to your course format's db/mobile.php file:

$addons = [
    'format_myformat' => [
        'handlers' => [ // Different places where the plugin will display content.
            'myformat' => [ // Handler unique name (alphanumeric).
                'delegate' => 'CoreCourseFormatDelegate', // Delegate (where to display the link to the plugin)
                'method' => 'mobile_course_view', // Main function in \format_myformat\output\mobile.
                'styles' => [
                    'url' => $CFG->wwwroot . '/course/format/myformat/mobile.css',
                    'version' => 2019041000
                ],
                'displaysectionselector' => true, // Set to false to disable the default section selector.
                'displayenabledownload' => true, // Set to false to hide the "Enable download" option in the course context menu.
                'init' => 'myformat_init'
            ]
    ]
];

As with other plugins, you then use a function in your plugin's classes/output/mobile.php to return a template:

class mobile {
 
    /**
     * Main course page.
     *
     * @param array $args Standard mobile web service arguments
     * @return array
     */
    public static function mobile_course_view($args) {
        global $OUTPUT, $CFG;
 
        $course = get_course($args['courseid']);
        require_login($course);
        $html = $OUTPUT->render_from_template('format_oustudyplan/mobile_course');
 
        return [
            'templates' => [
                [
                    'id' => 'main',
                    'html' => $html
                ]
            ],
            'otherdata' => [
               ...
            ]
        ];
    }

Then your templates/mobile_course.mustache file will contain the angular template to display your page

{{=<% %>=}}
<core-dynamic-component [component]="allSectionsComponent" [data]="data" class="format-myformat">
    <ng-container *ngFor="let section of sections">
        <ion-item-divider color="light">
        <core-format-text [text]="section.name"></core-format-text>
        <!-- Section download. -->
        <div *ngIf="section && downloadEnabled" class="core-button-spinner" float-end>
            <!-- Download button. -->
            <button *ngIf="section.showDownload && !section.isDownloading && !section.isCalculating" (click)="prefetch($event, section)" ion-button icon-only clear color="dark" [attr.aria-label]="'core.download' | translate">
                <ion-icon name="cloud-download"></ion-icon>
            </button>
            <!-- Refresh button. -->
            <button *ngIf="section.showRefresh && !section.isDownloading && !section.isCalculating" (click)="prefetch($event, section)" ion-button icon-only clear color="dark" [attr.aria-label]="'core.refresh' | translate">
                <ion-icon name="refresh"></ion-icon>
            </button>
            <!-- Download progress. -->
            <ion-badge class="core-course-download-section-progress" *ngIf="section.isDownloading && section.total > 0 && section.count < section.total">{{section.count}} / {{section.total}}</ion-badge>
            <!-- Spinner (downloading or calculating status). -->
            <ion-spinner *ngIf="(section.isDownloading && section.total > 0) || section.isCalculating"></ion-spinner>
        </div>
    </ion-item-divider>

    <ion-item text-wrap *ngIf="section.summary">
        <core-format-text [text]="section.summary"></core-format-text>
    </ion-item>

    <ng-container *ngFor="let module of section.modules">
        <ng-container *ngIf="module.visibleoncoursepage !== 0">
            <core-course-module text-wrap [module]="module" [courseId]="course.id" [downloadEnabled]="downloadEnabled" (completionChanged)="onCompletionChange($event)">
            </core-course-module>
        </ng-container>
    </ng-container>
</core-dynamic-component>

You don't have to use a mustache template, you can just use a static angular template.

This will get you to a stage where you have something similar to the core format plugin - a list of sections with headers, each containing its list of course modules. From here, you can make customisations to support your course format's features.