Commit 001fc061 authored by Andrew Nicols's avatar Andrew Nicols
Browse files

MDL-52777 tool_usertours: Add the new User Tours plugin

parent 6a69cda9
......@@ -3,6 +3,8 @@
*/**/build/
node_modules/
vendor/
admin/tool/usertours/amd/src/tour.js
admin/tool/usertours/amd/src/popper.js
auth/cas/CAS/
auth/fc/fcFPP.php
enrol/lti/ims-blti/
......
......@@ -2,6 +2,8 @@
theme/bootstrapbase/style/
node_modules/
vendor/
admin/tool/usertours/amd/src/tour.js
admin/tool/usertours/amd/src/popper.js
auth/cas/CAS/
auth/fc/fcFPP.php
enrol/lti/ims-blti/
......
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
Description of External library imports into Moodle
Flexitour Instructions
----------------------
1. Clone https://github.com/andrewnicols/flexitour into an unrelated directory
2. Copy /build/tour.js to amd/src/tour.js
3. Open the amd/src/tour.js file and find the AMD module define.
4. Change the "popper" inclusion to "./popper"
5. Update thirdpartylibs.xml
6. Run `grunt amd`
Popper.js Instructions
----------------------
1. Clone https://github.com/FezVrasta/popper.js into an unrelated directory
2. Copy /build/popper.js to amd/src/popper.js
3. Update thirdpartylibs.xml
4. Run `grunt amd`
/**
* Step management code.
*
* @module tool_usertours/managesteps
* @class managesteps
* @package tool_usertours
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
*/
define(
['jquery', 'core/str', 'core/notification'],
function($, str, notification) {
var manager = {
/**
* Confirm removal of the specified step.
*
* @method removeStep
* @param {EventFacade} e The EventFacade
*/
removeStep: function(e) {
e.preventDefault();
str.get_strings([
{
key: 'confirmstepremovaltitle',
component: 'tool_usertours'
},
{
key: 'confirmstepremovalquestion',
component: 'tool_usertours'
},
{
key: 'yes',
component: 'moodle'
},
{
key: 'no',
component: 'moodle'
}
]).done(function(s) {
notification.confirm(s[0], s[1], s[2], s[3], $.proxy(function() {
window.location = $(this).attr('href');
}, e.currentTarget));
});
},
/**
* Setup the step management UI.
*
* @method setup
*/
setup: function() {
$('body').delegate('[data-action="delete"]', 'click', manager.removeStep);
}
};
return /** @alias module:tool_usertours/managesteps */ {
/**
* Setup the step management UI.
*
* @method setup
*/
setup: manager.setup
};
});
/**
* Tour management code.
*
* @module tool_usertours/managetours
* @class managetours
* @package tool_usertours
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
*/
define(
['jquery', 'core/ajax', 'core/str', 'core/notification'],
function($, ajax, str, notification) {
var manager = {
/**
* Confirm removal of the specified tour.
*
* @method removeTour
* @param {EventFacade} e The EventFacade
*/
removeTour: function(e) {
e.preventDefault();
str.get_strings([
{
key: 'confirmtourremovaltitle',
component: 'tool_usertours'
},
{
key: 'confirmtourremovalquestion',
component: 'tool_usertours'
},
{
key: 'yes',
component: 'moodle'
},
{
key: 'no',
component: 'moodle'
}
]).done(function(s) {
notification.confirm(s[0], s[1], s[2], s[3], $.proxy(function() {
window.location = $(this).attr('href');
}, e.currentTarget));
});
},
/**
* Setup the tour management UI.
*
* @method setup
*/
setup: function() {
$('body').delegate('[data-action="delete"]', 'click', manager.removeTour);
}
};
return /** @alias module:tool_usertours/managetours */ {
/**
* Setup the tour management UI.
*
* @method setup
*/
setup: manager.setup
};
});
This diff is collapsed.
This diff is collapsed.
/**
* User tour control library.
*
* @module tool_usertours/usertours
* @class usertours
* @package tool_usertours
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
*/
define(
['core/ajax', 'tool_usertours/tour', 'jquery', 'core/templates', 'core/str', 'core/log', 'core/notification'],
function(ajax, BootstrapTour, $, templates, str, log, notification) {
var usertours = {
tourId: null,
currentTour: null,
context: null,
/**
* Initialise the user tour for the current page.
*
* @method init
* @param {Number} tourId The ID of the tour to start.
* @param {Bool} startTour Attempt to start the tour now.
* @param {Number} context The context of the current page.
*/
init: function(tourId, startTour, context) {
// Only one tour per page is allowed.
usertours.tourId = tourId;
usertours.context = context;
if (typeof startTour === 'undefined') {
startTour = true;
}
if (startTour) {
// Fetch the tour configuration.
usertours.fetchTour(tourId);
}
usertours.addResetLink();
// Watch for the reset link.
$('body').on('click', '[data-action="tool_usertours/resetpagetour"]', function(e) {
e.preventDefault();
usertours.resetTourState(usertours.tourId);
});
},
/**
* Fetch the configuration specified tour, and start the tour when it has been fetched.
*
* @method fetchTour
* @param {Number} tourId The ID of the tour to start.
*/
fetchTour: function(tourId) {
$.when(
ajax.call([
{
methodname: 'tool_usertours_fetch_and_start_tour',
args: {
tourid: tourId,
context: usertours.context,
pageurl: window.location.href,
}
}
])[0],
templates.render('tool_usertours/tourstep', {})
).then(function(response, template) {
usertours.startBootstrapTour(tourId, template[0], response.tourconfig);
}).fail(notification.exception);
},
/**
* Add a reset link to the page.
*
* @method addResetLink
*/
addResetLink: function() {
str.get_string('resettouronpage', 'tool_usertours')
.done(function(s) {
// Grab the last item in the page of these.
$('footer, .logininfo')
.last()
.append(
'<div class="usertour">' +
'<a href="#" data-action="tool_usertours/resetpagetour">' +
s +
'</a>' +
'</div>'
);
});
},
/**
* Start the specified tour.
*
* @method startBootstrapTour
* @param {Number} tourId The ID of the tour to start.
* @param {String} template The template to use.
* @param {Object} tourConfig The tour configuration.
*/
startBootstrapTour: function(tourId, template, tourConfig) {
if (usertours.currentTour) {
// End the current tour, but disable end tour handler.
tourConfig.onEnd = null;
usertours.currentTour.endTour();
delete usertours.currentTour;
}
// Normalize for the new library.
tourConfig.eventHandlers = {
afterEnd: [usertours.markTourComplete],
afterRender: [usertours.markStepShown],
};
// Sort out the tour name.
tourConfig.tourName = tourConfig.name;
delete tourConfig.name;
// Add the template to the configuration.
// This enables translations of the buttons.
tourConfig.template = template;
tourConfig.steps = tourConfig.steps.map(function(step) {
if (typeof step.element !== 'undefined') {
step.target = step.element;
delete step.element;
}
if (typeof step.reflex !== 'undefined') {
step.moveOnClick = !!step.reflex;
delete step.reflex;
}
if (typeof step.content !== 'undefined') {
step.body = step.content;
delete step.content;
}
return step;
});
usertours.currentTour = new BootstrapTour(tourConfig);
usertours.currentTour.startTour();
},
/**
* Mark the specified step as being shownd by the user.
*
* @method markStepShown
*/
markStepShown: function() {
var stepConfig = this.getStepConfig(this.getCurrentStepNumber());
$.when(
ajax.call([
{
methodname: 'tool_usertours_step_shown',
args: {
tourid: usertours.tourId,
context: usertours.context,
pageurl: window.location.href,
stepid: stepConfig.stepid,
stepindex: this.getCurrentStepNumber(),
}
}
])[0]
).fail(log.error);
},
/**
* Mark the specified tour as being completed by the user.
*
* @method markTourComplete
*/
markTourComplete: function() {
var stepConfig = this.getStepConfig(this.getCurrentStepNumber());
$.when(
ajax.call([
{
methodname: 'tool_usertours_complete_tour',
args: {
tourid: usertours.tourId,
context: usertours.context,
pageurl: window.location.href,
stepid: stepConfig.stepid,
stepindex: this.getCurrentStepNumber(),
}
}
])[0]
).fail(log.error);
},
/**
* Reset the state, and restart the the tour on the current page.
*
* @method resetTourState
* @param {Number} tourId The ID of the tour to start.
*/
resetTourState: function(tourId) {
$.when(
ajax.call([
{
methodname: 'tool_usertours_reset_tour',
args: {
tourid: tourId,
context: usertours.context,
pageurl: window.location.href,
}
}
])[0]
).then(function(response) {
if (response.startTour) {
usertours.fetchTour(response.startTour);
}
}).fail(notification.exception);
}
};
return /** @alias module:tool_usertours/usertours */ {
/**
* Initialise the user tour for the current page.
*
* @method init
* @param {Number} tourId The ID of the tour to start.
* @param {Bool} startTour Attempt to start the tour now.
*/
init: usertours.init,
/**
* Reset the state, and restart the the tour on the current page.
*
* @method resetTourState
* @param {Number} tourId The ID of the tour to restart.
*/
resetTourState: usertours.resetTourState
};
});
<?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/>.
/**
* Step configuration detail class.
*
* @package tool_usertours
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_usertours;
defined('MOODLE_INTERNAL') || die();
/**
* Step configuration detail class.
*
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class configuration {
/**
* @var TOURDEFAULT
*/
const TOURDEFAULT = 'usetourdefault';
/**
* Get the list of keys which can be defaulted in the tour.
*
* @return array
*/
public static function get_defaultable_keys() {
return [
'placement',
'orphan',
'backdrop',
'reflex',
];
}
/**
* Get the default value for the specified key.
*
* @param string $key The key for the specified value
* @return mixed
*/
public static function get_default_value($key) {
switch($key) {
case 'placement':
return 'bottom';
case 'orphan':
case 'backdrop':
case 'reflex':
return false;
}
}
/**
* Get the default value for the specified key for the step form.
*
* @param string $key The key for the specified value
* @return mixed
*/
public static function get_step_default_value($key) {
switch($key) {
case 'placement':
case 'orphan':
case 'backdrop':
case 'reflex':
return self::TOURDEFAULT;
}
}
/**
* Get the list of possible placement options.
*
* @param string $default The default option.
* @return array
*/
public static function get_placement_options($default = null) {
$values = [
'top' => get_string('top', 'tool_usertours'),
'bottom' => get_string('bottom', 'tool_usertours'),
'left' => get_string('left', 'tool_usertours'),
'right' => get_string('right', 'tool_usertours'),
];
if ($default === null) {
return $values;
}
if (!isset($values[$default])) {
$default = self::get_default_value('placement');
}
$values = array_reverse($values, true);
$values[self::TOURDEFAULT] = get_string('defaultvalue', 'tool_usertours', $values[$default]);
$values = array_reverse($values, true);
return $values;
}
}
<?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/>.
/**
* The tool_usertours step_shown event.
*
* @package tool_usertours
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_usertours\event;
defined('MOODLE_INTERNAL') || die();
/**
* The tool_usertours step_shown event.
*
* @package tool_usertours
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* @property-read array $other {
* Extra information about the event.
*
* - int tourid: The id of the tour
* - string pageurl: The URL of the page viewing the tour
* }
*/
class step_shown extends \core\event\base {
/**
* Init method.
*/
protected function init() {
$this->data['crud'] = 'r';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
$this->data['objecttable'] = 'tool_usertours_steps';
}
/**
* Returns localised general event name.
*
* @return string
*/
public static function get_name() {
return get_string('event_step_shown', 'tool_usertours');
}
/**
* Custom validation.
*
* @throws \coding_exception
* @return void
*/
protected function validate_data() {
parent::validate_data();
if (!isset($this->other['tourid'])) {
throw new \coding_exception(