MDL-59369 user: User enrolment status JS controls
authorJun Pataleta <jun@moodle.com>
Thu, 13 Jul 2017 02:32:49 +0000 (10:32 +0800)
committerJun Pataleta <jun@moodle.com>
Wed, 26 Jul 2017 01:44:33 +0000 (09:44 +0800)
* Add actions for editing user enrolment and unenrol
* Render user enrolment details in a modal

lang/en/enrol.php
user/amd/build/status_field.min.js [new file with mode: 0644]
user/amd/src/status_field.js [new file with mode: 0644]
user/classes/participants_table.php
user/classes/status_field.php [new file with mode: 0644]
user/templates/status_details.mustache [new file with mode: 0644]
user/templates/status_field.mustache [new file with mode: 0644]

index d60f50a..ae18f7c 100644 (file)
@@ -49,6 +49,7 @@ $string['enrolcandidates'] = 'Not enrolled users';
 $string['enrolcandidatesmatching'] = 'Matching not enrolled users';
 $string['enrolcohort'] = 'Enrol cohort';
 $string['enrolcohortusers'] = 'Enrol users';
+$string['enroldetails'] = 'Enrolment details';
 $string['eventenrolinstancecreated'] = 'Enrolment instance created';
 $string['eventenrolinstancedeleted'] = 'Enrolment instance deleted';
 $string['eventenrolinstanceupdated'] = 'Enrolment instance updated';
@@ -59,6 +60,7 @@ $string['enrolme'] = 'Enrol me in this course';
 $string['enrolmentinstances'] = 'Enrolment methods';
 $string['enrolmentnew'] = 'New enrolment in {$a}';
 $string['enrolmentnewuser'] = '{$a->user} has enrolled in course "{$a->course}"';
+$string['enrolmentmethod'] = 'Enrolment method';
 $string['enrolments'] = 'Enrolments';
 $string['enrolmentoptions'] = 'Enrolment options';
 $string['enrolnotpermitted'] = 'You do not have permission or are not allowed to enrol someone in this course';
diff --git a/user/amd/build/status_field.min.js b/user/amd/build/status_field.min.js
new file mode 100644 (file)
index 0000000..bd35c47
Binary files /dev/null and b/user/amd/build/status_field.min.js differ
diff --git a/user/amd/src/status_field.js b/user/amd/src/status_field.js
new file mode 100644 (file)
index 0000000..51a0687
--- /dev/null
@@ -0,0 +1,322 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * AMD module for the user enrolment status field in the course participants page.
+ *
+ * @module     core_user/status_field
+ * @copyright  2017 Jun Pataleta
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['core/templates',
+        'jquery',
+        'core/str',
+        'core/config',
+        'core/notification',
+        'core/modal_factory',
+        'core/modal_events',
+        'core/fragment',
+        'core/ajax'
+    ],
+    function(Template, $, Str, Config, Notification, ModalFactory, ModalEvents, Fragment, Ajax) {
+
+        /**
+         * Action selectors.
+         *
+         * @access private
+         * @type {{EDIT_ENROLMENT: string, SHOW_DETAILS: string, UNENROL: string}}
+         */
+        var SELECTORS = {
+            EDIT_ENROLMENT: '[data-action="editenrolment"]',
+            SHOW_DETAILS: '[data-action="showdetails"]',
+            UNENROL: '[data-action="unenrol"]'
+        };
+
+        /**
+         * Constructor
+         *
+         * @param {Object} options Object containing options. The only valid option at this time is contextid.
+         * Each call to templates.render gets it's own instance of this class.
+         */
+        var StatusFieldActions = function(options) {
+            this.contextid = options.contextid;
+            this.courseid = options.courseid;
+
+            // Bind click event to editenrol buttons.
+            this.bindEditEnrol();
+
+            // Bind click event to unenrol buttons.
+            this.bindUnenrol();
+
+            // Bind click event to status details buttons.
+            this.bindStatusDetails();
+        };
+        // Class variables and functions.
+
+        /** @var {number} courseid The course ID. */
+        StatusFieldActions.prototype.courseid = 0;
+
+        /**
+         * Private method
+         *
+         * @method initModal
+         * @private
+         */
+        StatusFieldActions.prototype.bindEditEnrol = function() {
+            var statusFieldInstsance = this;
+
+            $(SELECTORS.EDIT_ENROLMENT).click(function(e) {
+                e.preventDefault();
+
+                // The particular edit button that was clicked.
+                var clickedEditTrigger = $(this);
+                // Get the parent container (it contains the data attributes associated with the status field).
+                var parentContainer = clickedEditTrigger.parent();
+                // Get the name of the user whose enrolment status is being edited.
+                var fullname = parentContainer.data('fullname');
+                // Get the user enrolment ID.
+                var ueid = clickedEditTrigger.attr('rel');
+
+                $.when(Str.get_string('edituserenrolment', 'enrol', fullname)).then(function(modalTitle) {
+                    return ModalFactory.create({
+                        large: true,
+                        title: modalTitle,
+                        type: ModalFactory.types.SAVE_CANCEL
+                    });
+                }).done(function(modal) {
+                    // Handle save event.
+                    modal.getRoot().on(ModalEvents.save, function(e) {
+                        // Don't close the modal yet.
+                        e.preventDefault();
+                        // Submit form data.
+                        statusFieldInstsance.submitEditFormAjax(modal);
+                    });
+
+                    // Handle hidden event.
+                    modal.getRoot().on(ModalEvents.hidden, function() {
+                        // Destroy when hidden.
+                        modal.destroy();
+                    });
+
+                    // Set the modal body.
+                    modal.setBody(statusFieldInstsance.getBody(ueid));
+
+                    // Show the modal!
+                    modal.show();
+                }).fail(Notification.exception);
+            });
+        };
+
+        /**
+         * Private method
+         *
+         * @method bindUnenrol
+         * @private
+         */
+        StatusFieldActions.prototype.bindUnenrol = function() {
+            $(SELECTORS.UNENROL).click(function(e) {
+                e.preventDefault();
+                var unenrolLink = $(this);
+                var parentContainer = unenrolLink.parent();
+                var strings = [
+                    {
+                        key: 'unenrol',
+                        component: 'enrol'
+                    },
+                    {
+                        key: 'unenrolconfirm',
+                        component: 'enrol',
+                        param: {
+                            user: parentContainer.data('fullname'),
+                            course: parentContainer.data('coursename')
+                        }
+                    }
+                ];
+
+                $.when(Str.get_strings(strings)).then(function(results) {
+                    var title = results[0];
+                    var confirmMessage = results[1];
+                    return ModalFactory.create({
+                        body: confirmMessage,
+                        large: true,
+                        title: title,
+                        type: ModalFactory.types.CONFIRM
+                    });
+                }).done(function(modal) {
+                    // Handle confirm event.
+                    modal.getRoot().on(ModalEvents.yes, function() {
+                        // Build params.
+                        var unenrolParams = {
+                            confirm: 1,
+                            sesskey: Config.sesskey,
+                            ue: $(unenrolLink).attr('rel')
+                        };
+                        // Send data to unenrol page (which will redirect back to the participants page after unenrol).
+                        window.location.href = Config.wwwroot + '/enrol/unenroluser.php?' + $.param(unenrolParams);
+                    });
+
+                    // Handle hidden event.
+                    modal.getRoot().on(ModalEvents.hidden, function() {
+                        // Destroy when hidden.
+                        modal.destroy();
+                    });
+
+                    // Display the delete confirmation modal.
+                    modal.show();
+                }).fail(Notification.exception);
+            });
+        };
+
+        /**
+         * Private method
+         *
+         * @method bindStatusDetails
+         * @private
+         */
+        StatusFieldActions.prototype.bindStatusDetails = function() {
+            $(SELECTORS.SHOW_DETAILS).click(function(e) {
+                e.preventDefault();
+
+                var detailsButton = $(this);
+                var parentContainer = detailsButton.parent();
+                var context = {
+                    "fullname": parentContainer.data('fullname'),
+                    "coursename": parentContainer.data('coursename'),
+                    "enrolinstancename": parentContainer.data('enrolinstancename'),
+                    "status": parentContainer.data('status'),
+                    "timestart": parentContainer.data('timestart'),
+                    "timeend": parentContainer.data('timeend')
+                };
+
+                var modalTitlePromise = Str.get_string('enroldetails', 'enrol');
+                var modalPromise = ModalFactory.create({large: true, type: ModalFactory.types.CANCEL});
+                $.when(modalTitlePromise, modalPromise).done(function(modalTitle, modal) {
+                    var modalBodyPromise = Template.render('core_user/status_details', context);
+                    modal.setTitle(modalTitle);
+                    modal.setBody(modalBodyPromise);
+                    modal.show();
+
+                    // Handle hidden event.
+                    modal.getRoot().on(ModalEvents.hidden, function() {
+                        // Destroy when hidden.
+                        modal.destroy();
+                    });
+                }).fail(Notification.exception);
+            });
+        };
+
+        /**
+         * Private method
+         *
+         * @method submitEditFormAjax
+         * @param {Object} modal The the AMD modal object containing the form.
+         * @private
+         */
+        StatusFieldActions.prototype.submitEditFormAjax = function(modal) {
+            var statusFieldInstsance = this;
+            var form = modal.getRoot().find('form');
+
+            // User enrolment ID.
+            var ueid = $(form).find('[name="ue"]').val();
+            // Status.
+            var status = $(form).find('[name="status"]').val();
+
+            var params = {
+                'courseid': this.courseid,
+                'ueid': ueid,
+                'status': status
+            };
+
+            // Enrol time start.
+            var timeStartEnabled = $(form).find('[name="timestart[enabled]"]');
+            if (timeStartEnabled.is(':checked')) {
+                var timeStartYear = $(form).find('[name="timestart[year]"]').val();
+                var timeStartMonth = $(form).find('[name="timestart[month]"]').val() - 1;
+                var timeStartDay = $(form).find('[name="timestart[day]"]').val();
+                var timeStartHour = $(form).find('[name="timestart[hour]"]').val();
+                var timeStartMinute = $(form).find('[name="timestart[minute]"]').val();
+                var timeStart = new Date(timeStartYear, timeStartMonth, timeStartDay, timeStartHour, timeStartMinute);
+                params.timestart = timeStart.getTime() / 1000;
+            }
+
+            // Enrol time end.
+            var timeEndEnabled = $(form).find('[name="timeend[enabled]"]');
+            if (timeEndEnabled.is(':checked')) {
+                var timeEndYear = $(form).find('[name="timeend[year]"]').val();
+                var timeEndMonth = $(form).find('[name="timeend[month]"]').val() - 1;
+                var timeEndDay = $(form).find('[name="timeend[day]"]').val();
+                var timeEndHour = $(form).find('[name="timeend[hour]"]').val();
+                var timeEndMinute = $(form).find('[name="timeend[minute]"]').val();
+                var timeEnd = new Date(timeEndYear, timeEndMonth, timeEndDay, timeEndHour, timeEndMinute);
+                params.timeend = timeEnd.getTime() / 1000;
+            }
+
+            var request = {
+                methodname: 'core_enrol_edit_user_enrolment',
+                args: params
+            };
+
+            Ajax.call([request])[0].done(function(data) {
+                if (data.result) {
+                    // Dismiss the modal.
+                    modal.hide();
+
+                    // Reload the page, don't show changed data warnings.
+                    if (typeof window.M.core_formchangechecker !== "undefined") {
+                        window.M.core_formchangechecker.reset_form_dirty_state();
+                    }
+                    window.location.reload();
+
+                } else {
+                    // Serialise the form data and reload the form fragment to show validation errors.
+                    var formData = JSON.stringify(form.serialize());
+                    modal.setBody(statusFieldInstsance.getBody(ueid, formData));
+                }
+            }).fail(Notification.exception);
+        };
+
+        /**
+         * Private method
+         *
+         * @method getBody
+         * @private
+         * @param {Number} ueid The user enrolment ID associated with the user.
+         * @param {string} formData Serialized string of the edit enrolment form data.
+         * @return {Promise}
+         */
+        StatusFieldActions.prototype.getBody = function(ueid, formData) {
+            var params = {
+                'ueid': ueid
+            };
+            if (typeof formData !== 'undefined') {
+                params.formdata = formData;
+            }
+            return Fragment.loadFragment('enrol', 'user_enrolment_form', this.contextid, params).fail(Notification.exception);
+        };
+
+        return /** @alias module:core_user/editenrolment */ {
+            // Public variables and functions.
+            /**
+             * Every call to init creates a new instance of the class with it's own event listeners etc.
+             *
+             * @method init
+             * @public
+             * @param {object} config - config variables for the module.
+             */
+            init: function(config) {
+                (new StatusFieldActions(config));
+            }
+        };
+    });
\ No newline at end of file
index 0ee1dae..a162001 100644 (file)
@@ -26,7 +26,6 @@ namespace core_user;
 
 use context;
 use DateTime;
-use html_writer;
 
 defined('MOODLE_INTERNAL') || die;
 
@@ -204,6 +203,24 @@ class participants_table extends \table_sql {
         $this->assignableroles = get_assignable_roles($this->context, ROLENAME_ALIAS, false);
     }
 
+    /**
+     * Render the participants table.
+     *
+     * @param int $pagesize Size of page for paginated displayed table.
+     * @param bool $useinitialsbar Whether to use the initials bar which will only be used if there is a fullname column defined.
+     * @param string $downloadhelpbutton
+     */
+    public function out($pagesize, $useinitialsbar, $downloadhelpbutton = '') {
+        global $PAGE;
+
+        parent::out($pagesize, $useinitialsbar, $downloadhelpbutton);
+
+        if (has_capability('moodle/course:enrolreview', $this->context)) {
+            $params = ['contextid' => $this->context->id, 'courseid' => $this->course->id];
+            $PAGE->requires->js_call_amd('core_user/status_field', 'init', [$params]);
+        }
+    }
+
     /**
      * Generate the select column.
      *
@@ -305,7 +322,7 @@ class participants_table extends \table_sql {
     /**
      * Generate the status column.
      *
-     * @param stdClass $data The data object.
+     * @param \stdClass $data The data object.
      * @return string
      */
     public function col_status($data) {
@@ -315,15 +332,14 @@ class participants_table extends \table_sql {
         $canreviewenrol = has_capability('moodle/course:enrolreview', $this->context);
         if ($canreviewenrol) {
             $fullname = fullname($data);
+            $coursename = $this->course->fullname;
             require_once($CFG->dirroot . '/enrol/locallib.php');
             $manager = new \course_enrolment_manager($PAGE, $this->course);
             $userenrolments = $manager->get_user_enrolments($data->id);
             foreach ($userenrolments as $ue) {
-                $enrolactions = $ue->enrolmentplugin->get_user_enrolment_actions($manager, $ue);
                 $timestart = $ue->timestart;
                 $timeend = $ue->timeend;
                 $status = '';
-                $dimmed = '';
                 switch ($ue->status) {
                     case ENROL_USER_ACTIVE:
                         $currentdate = new DateTime();
@@ -332,24 +348,17 @@ class participants_table extends \table_sql {
                             $status = get_string('participationactive', 'enrol');
                         } else {
                             $status = get_string('participationnotcurrent', 'enrol');
-                            $dimmed = 'dimmed_text';
                         }
                         break;
                     case ENROL_USER_SUSPENDED:
                         $status = get_string('participationsuspended', 'enrol');
-                        $dimmed = 'dimmed_text';
                         break;
                 }
-                $statusout = html_writer::span($status, $dimmed, ['title' => "{$ue->enrolmentinstancename}: {$status}"]);
-                $enrolactionsout = '';
-                foreach ($enrolactions as $action) {
-                    $icon = $OUTPUT->render($action->get_icon());
-                    $attributes = $action->get_attributes();
-                    $attributes['data-fullname'] = $fullname;
-                    $attributes['data-coursename'] = $this->course->fullname;
-                    $enrolactionsout .= html_writer::link($action->get_url(), $icon, $attributes);
-                }
-                $enrolstatusoutput .= html_writer::div($statusout . $enrolactionsout);
+                $actions = $ue->enrolmentplugin->get_user_enrolment_actions($manager, $ue);
+                $instancename = $ue->enrolmentinstancename;
+                $statusfield = new status_field($instancename, $coursename, $fullname, $status, $timestart, $timeend, $actions);
+                $statusfielddata = $statusfield->export_for_template($OUTPUT);
+                $enrolstatusoutput .= $OUTPUT->render_from_template('core_user/status_field', $statusfielddata);
             }
         }
         return $enrolstatusoutput;
diff --git a/user/classes/status_field.php b/user/classes/status_field.php
new file mode 100644 (file)
index 0000000..3bb7576
--- /dev/null
@@ -0,0 +1,127 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Class containing the data necessary for rendering the status field in the course participants page.
+ *
+ * @package    core_user
+ * @copyright  2017 Jun Pataleta
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_user;
+
+defined('MOODLE_INTERNAL') || die();
+
+use renderable;
+use renderer_base;
+use stdClass;
+use templatable;
+use user_enrolment_action;
+
+/**
+ * Class containing the data for the status field.
+ *
+ * @package    core_user
+ * @copyright  2017 Jun Pataleta
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class status_field implements renderable, templatable {
+
+    /** @var string $enrolinstancename The enrolment instance name. */
+    protected $enrolinstancename;
+
+    /** @var string $coursename The course's full name. */
+    protected $coursename;
+
+    /** @var string $fullname The user's full name. */
+    protected $fullname;
+
+    /** @var string $status The user enrolment status. */
+    protected $status;
+
+    /** @var int $timestart The timestamp when the user's enrolment starts. */
+    protected $timestart;
+
+    /** @var int $timeend The timestamp when the user's enrolment ends. */
+    protected $timeend;
+
+    /** @var user_enrolment_action[] $enrolactions Array of enrol action objects for the given enrolment method. */
+    protected $enrolactions;
+
+    /**
+     * status_field constructor.
+     *
+     * @param string $enrolinstancename The enrolment instance name.
+     * @param string $coursename The course's full name.
+     * @param string $fullname The user's full name.
+     * @param string $status The user enrolment status.
+     * @param int|null $timestart The timestamp when the user's enrolment starts.
+     * @param int|null $timeend The timestamp when the user's enrolment ends.
+     * @param user_enrolment_action[] $enrolactions Array of enrol action objects for the given enrolment method.
+     */
+    public function __construct($enrolinstancename, $coursename, $fullname, $status,
+                                $timestart = null, $timeend = null, $enrolactions = []) {
+        $this->enrolinstancename = $enrolinstancename;
+        $this->coursename = $coursename;
+        $this->fullname = $fullname;
+        $this->status = $status;
+        $this->timestart = $timestart;
+        $this->timeend = $timeend;
+        $this->enrolactions = $enrolactions;
+    }
+
+    /**
+     * Function to export the renderer data in a format that is suitable for a
+     * mustache template. This means:
+     * 1. No complex types - only stdClass, array, int, string, float, bool
+     * 2. Any additional info that is required for the template is pre-calculated (e.g. capability checks).
+     *
+     * @param renderer_base $output Used to do a final render of any components that need to be rendered for export.
+     * @return stdClass|array
+     */
+    public function export_for_template(renderer_base $output) {
+        $data = new stdClass();
+        $data->enrolinstancename = $this->enrolinstancename;
+        $data->coursename = $this->coursename;
+        $data->fullname = $this->fullname;
+        $data->status = $this->status;
+        if ($this->timestart) {
+            $data->timestart = userdate($this->timestart);
+        }
+        if ($this->timeend) {
+            $data->timeend = userdate($this->timeend);
+        }
+        $data->enrolactions = [];
+
+        foreach ($this->enrolactions as $enrolaction) {
+            $action = new stdClass();
+            $action->url = $enrolaction->get_url()->out(false);
+            $action->icon = $output->render($enrolaction->get_icon());
+            $action->attributes = [];
+            foreach ($enrolaction->get_attributes() as $name => $value) {
+                $attribute = (object) [
+                    'name' => $name,
+                    'value' => $value
+                ];
+                $action->attributes[] = $attribute;
+            }
+            $data->enrolactions[] = $action;
+        }
+
+        return $data;
+    }
+}
diff --git a/user/templates/status_details.mustache b/user/templates/status_details.mustache
new file mode 100644 (file)
index 0000000..dd2c940
--- /dev/null
@@ -0,0 +1,93 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template core_user/status_details
+
+    Template for the user enrolment status details.
+
+    Context variables required for this template:
+    * fullname string - The user's full name.
+    * coursename string - The course name.
+    * enrolinstancename string - The enrolment instance name.
+    * status string - The enrolment status.
+    * timestart string - Optional. The enrolment time start.
+    * timeend string - Optional. The enrolment time end.
+
+    Example context (json):
+    {
+        "fullname": "Student John",
+        "coursename": "TC 1",
+        "enrolinstancename": "Manual enrolment",
+        "status": "Active",
+        "timestart": "1 January 2017",
+        "timeend": "31 January 2018"
+    }
+}}
+<table class="table user-enrol-details">
+    <tr>
+        <th>
+            {{#str}}fullname{{/str}}
+        </th>
+        <td class="user-fullname">
+            {{fullname}}
+        </td>
+    </tr>
+    <tr>
+        <th>
+            {{#str}}course{{/str}}
+        </th>
+        <td class="user-course">
+            {{coursename}}
+        </td>
+    </tr>
+    <tr>
+        <th>
+            {{#str}}enrolmentmethod, enrol{{/str}}
+        </th>
+        <td class="user-enrol-instance">
+            {{enrolinstancename}}
+        </td>
+    </tr>
+    <tr>
+        <th>
+            {{#str}}participationstatus, enrol{{/str}}
+        </th>
+        <td class="user-enrol-status">
+            {{status}}
+        </td>
+    </tr>
+    {{#timestart}}
+    <tr>
+        <th>
+            {{#str}}enroltimestart, enrol{{/str}}
+        </th>
+        <td  class="user-enrol-timestart">
+            {{timestart}}
+        </td>
+    </tr>
+    {{/timestart}}
+    {{#timeend}}
+    <tr>
+        <th>
+            {{#str}}enroltimeend, enrol{{/str}}
+        </th>
+        <td class="user-enrol-timeend">
+            {{timeend}}
+        </td>
+    </tr>
+    {{/timeend}}
+</table>
diff --git a/user/templates/status_field.mustache b/user/templates/status_field.mustache
new file mode 100644 (file)
index 0000000..2873889
--- /dev/null
@@ -0,0 +1,67 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template core_user/status_field
+
+    Template for the enrolment status field.
+
+    Context variables required for this template:
+    * fullname string - The user's full name.
+    * coursename string - The course name.
+    * enrolinstancename string - The enrolment instance name.
+    * status string - The enrolment status.
+    * timestart string - Optional. The enrolment time start.
+    * timeend string - Optional. The enrolment time end.
+    * enrolactions array - Optional. Array of enrol actions consisting of:
+      * url string - The URL of the enrol action link.
+      * attributes array - The array of attributes for the enrol action link.
+      * icon string - The HTML output for the enrol action icon.
+
+    Example context (json):
+    {
+        "fullname": "Student John",
+        "coursename": "TC 1",
+        "enrolinstancename": "Manual enrolment",
+        "status": "Active",
+        "timestart": "1 January 2017",
+        "timeend": "31 January 2018",
+        "enrolactions": [
+            {
+                "url": "#",
+                "attributes": [
+                    {
+                        "name": "class",
+                        "value": "action-class"
+                    }
+                ],
+                "icon": "<i class=\"icon fa fa-cog fa-fw\" aria-hidden=\"true\" title=\"Edit enrolment\" aria-label=\"\"></i>"
+            }
+        ]
+    }
+}}
+<div data-fullname="{{fullname}}" data-coursename="{{coursename}}" data-enrolinstancename="{{enrolinstancename}}"
+     data-status="{{status}}" data-timestart="{{timestart}}" data-timeend="{{timeend}}">
+    <span>{{status}}</span>
+    <a data-action="showdetails" role="button" tabindex="0">
+        {{#pix}}docs, core, {{#str}}enroldetails, enrol{{/str}}{{/pix}}
+    </a>
+    {{#enrolactions}}
+    <a href="{{url}}" role="button" {{#attributes}}{{name}}="{{value}}" {{/attributes}}>
+        {{{icon}}}
+    </a>
+    {{/enrolactions}}
+</div>