MDL-49609 mod_lti: Add Content-Item message

Added option for tools to support Content-Item message and redirect
to/from tool provider when creating an instance.
This commit is contained in:
spvickers 2015-03-21 01:10:38 +11:00 committed by Jun Pataleta
parent 1f2744851f
commit d8f9109a12
10 changed files with 729 additions and 34 deletions

89
mod/lti/contentitem.php Normal file
View File

@ -0,0 +1,89 @@
<?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/>.
/**
* Display a page containing an iframe for the content-item selection process.
*
* @package mod_lti
* @copyright 2015 Vital Source Technologies http://vitalsource.com
* @author Stephen Vickers
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once('../../config.php');
require_once($CFG->dirroot.'/mod/lti/lib.php');
require_once($CFG->dirroot.'/mod/lti/locallib.php');
$courseid = required_param('course', PARAM_INT);
$sectionid = required_param('section', PARAM_INT);
$id = required_param('id', PARAM_INT);
$sectionreturn = required_param('sr', PARAM_INT);
$title = optional_param('title', null, PARAM_TEXT);
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
require_login($course);
$url = new moodle_url('/mod/lti/contentitem.php', array('course' => $courseid));
$contentitem = new moodle_url('/mod/lti/contentitem2.php',
array('course' => $courseid, 'section' => $sectionid, 'id' => $id, 'sr' => $sectionreturn, 'title' => $title));
echo "<p id=\"id_warning\" style=\"display: none; color: red; font-weight: bold; margin-top: 1em; padding-top: 1em;\">\n";
echo get_string('register_warning', 'lti');
echo "\n</p>\n";
echo '<iframe id="contentframe" height="600px" width="100%" src="' . $contentitem->out() . '" onload="doOnload()"></iframe>';
// Output script to make the object tag be as large as possible.
$resize = '
<script type="text/javascript">
//<![CDATA[
function doReveal() {
var el = document.getElementById(\'id_warning\');
el.style.display = \'block\';
}
function doOnload() {
window.clearTimeout(mod_lti_timer);
parent.M.mod_lti.editor.removeLoading();
}
var mod_lti_timer = window.setTimeout(doReveal, 20000);
parent.YUI().use("node", "event", function(Y) {
//Take scrollbars off the outer document to prevent double scroll bar effect
var doc = parent.Y.one("body");
doc.setStyle("overflow", "hidden");
var frame = parent.Y.one("#contentframe");
var padding = 15; //The bottom of the iframe wasn\'t visible on some themes. Probably because of border widths, etc.
var lastHeight;
var resize = function(e) {
var viewportHeight = doc.get("winHeight");
if(lastHeight !== Math.min(doc.get("docHeight"), viewportHeight)){
frame.setStyle("height", viewportHeight - frame.getY() - padding + "px");
lastHeight = Math.min(doc.get("docHeight"), doc.get("winHeight"));
}
};
resize();
parent.Y.on("windowresize", resize);
});
//]]
</script>
';
echo $resize;

196
mod/lti/contentitem2.php Normal file
View File

@ -0,0 +1,196 @@
<?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/>.
/**
* Handle sending a user to a tool provider to initiate a content-item selection.
*
* @package mod_lti
* @copyright 2015 Vital Source Technologies http://vitalsource.com
* @author Stephen Vickers
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once("../../config.php");
require_once($CFG->dirroot.'/mod/lti/lib.php');
require_once($CFG->dirroot.'/mod/lti/locallib.php');
$courseid = required_param('course', PARAM_INT);
$sectionid = required_param('section', PARAM_INT);
$id = required_param('id', PARAM_INT);
$sectionreturn = required_param('sr', PARAM_INT);
require_login($PAGE->course);
$tool = lti_get_type($id);
$typeconfig = lti_get_type_config($id);
if (isset($tool->toolproxyid)) {
$toolproxy = lti_get_tool_proxy($tool->toolproxyid);
$key = $toolproxy->guid;
$secret = $toolproxy->secret;
} else {
$toolproxy = null;
if (!empty($instance->resourcekey)) {
$key = $instance->resourcekey;
} else if (!empty($typeconfig['resourcekey'])) {
$key = $typeconfig['resourcekey'];
} else {
$key = '';
}
if (!empty($instance->password)) {
$secret = $instance->password;
} else if (!empty($typeconfig['password'])) {
$secret = $typeconfig['password'];
} else {
$secret = '';
}
}
$tool->enabledcapability = $typeconfig['enabledcapability_ContentItemSelectionRequest'];
$tool->parameter = $typeconfig['parameter_ContentItemSelectionRequest'];
$title = optional_param('title', $tool->name, PARAM_TEXT);
if (isset($typeconfig['toolurl_ContentItemSelectionRequest'])) {
$endpoint = $typeconfig['toolurl_ContentItemSelectionRequest'];
} else {
$endpoint = !empty($instance->toolurl) ? $instance->toolurl : $typeconfig['toolurl'];
}
$endpoint = trim($endpoint);
// If the current request is using SSL and a secure tool URL is specified, use it.
if (lti_request_is_using_ssl() && !empty($instance->securetoolurl)) {
$endpoint = trim($instance->securetoolurl);
}
// If SSL is forced, use the secure tool url if specified. Otherwise, make sure https is on the normal launch URL.
if (isset($typeconfig['forcessl']) && ($typeconfig['forcessl'] == '1')) {
if (!empty($instance->securetoolurl)) {
$endpoint = trim($instance->securetoolurl);
}
$endpoint = lti_ensure_url_is_https($endpoint);
} else {
if (!strstr($endpoint, '://')) {
$endpoint = 'http://' . $endpoint;
}
}
$orgid = (isset($typeconfig['organizationid'])) ? $typeconfig['organizationid'] : '';
$course = $PAGE->course;
$islti2 = isset($tool->toolproxyid);
$instance = new stdClass();
$instance->course = $courseid;
$allparams = lti_build_request($instance, $typeconfig, $course, $id, $islti2);
if ($islti2) {
$requestparams = lti_build_request_lti2($tool, $allparams);
} else {
$requestparams = $allparams;
}
$requestparams = array_merge($requestparams, lti_build_standard_request(null, $orgid, $islti2));
$customstr = '';
if (isset($typeconfig['customparameters'])) {
$customstr = $typeconfig['customparameters'];
}
$requestparams = array_merge($requestparams, lti_build_custom_parameters($toolproxy, $tool, $instance, $allparams, $customstr,
'', $islti2));
// Allow request params to be updated by sub-plugins.
$plugins = core_component::get_plugin_list('ltisource');
foreach (array_keys($plugins) as $plugin) {
$pluginparams = component_callback('ltisource_'.$plugin, 'before_launch',
array($instance, $endpoint, $requestparams), array());
if (!empty($pluginparams) && is_array($pluginparams)) {
$requestparams = array_merge($requestparams, $pluginparams);
}
}
if ($islti2) {
$requestparams['lti_version'] = 'LTI-2p0';
} else {
$requestparams['lti_version'] = 'LTI-1p0';
}
$requestparams['lti_message_type'] = 'ContentItemSelectionRequest';
$requestparams['accept_media_types'] = 'application/vnd.ims.lti.v1.ltilink';
$requestparams['accept_presentation_document_targets'] = 'frame,iframe,window';
$requestparams['accept_unsigned'] = 'false';
$requestparams['accept_multiple'] = 'false';
$requestparams['auto_create'] = 'true';
$requestparams['can_confirm'] = 'false';
$requestparams['accept_copy_advice'] = 'false';
$requestparams['title'] = $title;
$returnurlparams = array('course' => $courseid,
'section' => $sectionid,
'id' => $id,
'sr' => $sectionreturn,
'sesskey' => sesskey());
// Add the return URL. We send the launch container along to help us avoid frames-within-frames when the user returns.
$url = new \moodle_url('/mod/lti/contentitem_return.php', $returnurlparams);
$returnurl = $url->out(false);
if (isset($typeconfig['forcessl']) && ($typeconfig['forcessl'] == '1')) {
$returnurl = lti_ensure_url_is_https($returnurl);
}
$requestparams['content_item_return_url'] = $returnurl;
$parms = lti_sign_parameters($requestparams, $endpoint, "POST", $key, $secret);
$endpointurl = new \moodle_url($endpoint);
$endpointparams = $endpointurl->params();
// Strip querystring params in endpoint url from $parms to avoid duplication.
if (!empty($endpointparams) && !empty($parms)) {
foreach (array_keys($endpointparams) as $paramname) {
if (isset($parms[$paramname])) {
unset($parms[$paramname]);
}
}
}
echo "<p id=\"id_warning\" style=\"display: none; color: red; font-weight: bold; margin-top: 1em; padding-top: 1em;\">\n";
echo get_string('register_warning', 'lti');
echo "\n</p>\n";
$loading = $OUTPUT->render(new \pix_icon('i/loading', '', 'moodle',
array('style' => 'margin:auto;vertical-align:middle;margin-top:125px;',
'opacity' => '0.5')));
echo "<p style=\"text-align:center;\">\n";
echo $loading;
echo "\n</p>\n";
$script = '
<script type="text/javascript">
//<![CDATA[
function doReveal() {
var el = document.getElementById(\'id_warning\');
el.style.display = \'block\';
}
var mod_lti_timer = window.setTimeout(doReveal, 20000);
//]]
</script>
';
echo $script;
$content = lti_post_launch_html($parms, $endpoint, false);
echo $content;

View File

@ -0,0 +1,226 @@
<?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/>.
/**
* Handle the return from the Tool Provider after selecting a content item.
*
* @package mod_lti
* @copyright 2015 Vital Source Technologies http://vitalsource.com
* @author Stephen Vickers
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once('../../config.php');
require_once($CFG->dirroot . '/course/modlib.php');
require_once($CFG->dirroot . '/mod/lti/lib.php');
require_once($CFG->dirroot . '/mod/lti/locallib.php');
require_once($CFG->dirroot . '/mod/lti/OAuth.php');
require_once($CFG->dirroot . '/mod/lti/TrivialStore.php');
use moodle\mod\lti as lti;
$courseid = required_param('course', PARAM_INT);
$sectionid = required_param('section', PARAM_INT);
$id = required_param('id', PARAM_INT);
$sectionreturn = required_param('sr', PARAM_INT);
$messagetype = required_param('lti_message_type', PARAM_TEXT);
$version = required_param('lti_version', PARAM_TEXT);
$consumer_key = required_param('oauth_consumer_key', PARAM_RAW);
$items = optional_param('content_items', '', PARAM_RAW);
$errormsg = optional_param('lti_errormsg', '', PARAM_TEXT);
$msg = optional_param('lti_msg', '', PARAM_TEXT);
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
$module = $DB->get_record('modules', array('name' => 'lti'), '*', MUST_EXIST);
$tool = lti_get_type($id);
$typeconfig = lti_get_type_config($id);
require_login($course);
require_sesskey();
if (isset($tool->toolproxyid)) {
$toolproxy = lti_get_tool_proxy($tool->toolproxyid);
$key = $toolproxy->guid;
$secret = $toolproxy->secret;
} else {
$toolproxy = null;
if (!empty($instance->resourcekey)) {
$key = $instance->resourcekey;
} else if (!empty($typeconfig['resourcekey'])) {
$key = $typeconfig['resourcekey'];
} else {
$key = '';
}
if (!empty($instance->password)) {
$secret = $instance->password;
} else if (!empty($typeconfig['password'])) {
$secret = $typeconfig['password'];
} else {
$secret = '';
}
}
if ($consumer_key !== $key) {
throw new Exception('Consumer key is incorrect.');
}
$store = new lti\TrivialOAuthDataStore();
$store->add_consumer($key, $secret);
$server = new lti\OAuthServer($store);
$method = new lti\OAuthSignatureMethod_HMAC_SHA1();
$server->add_signature_method($method);
$request = lti\OAuthRequest::from_request();
try {
$server->verify_request($request);
} catch (\Exception $e) {
$message = $e->getMessage();
debugging($e->getMessage() . "\n");
throw new lti\OAuthException("OAuth signature failed: " . $message);
}
if ($items) {
$items = json_decode($items);
if ($items->{'@context'} !== 'http://purl.imsglobal.org/ctx/lti/v1/ContentItem') {
throw new Exception('Invalid media type.');
}
if (!isset($items->{'@graph'}) || !is_array($items->{'@graph'}) || (count($items->{'@graph'}) > 1)) {
throw new Exception('Invalid format.');
}
}
$continueurl = course_get_url($course, $sectionid, array('sr' => $sectionreturn));
if (count($items->{'@graph'}) > 0) {
foreach ($items->{'@graph'} as $item) {
$moduleinfo = new stdClass();
$moduleinfo->modulename = 'lti';
$moduleinfo->name = '';
if (isset($item->title)) {
$moduleinfo->name = $item->title;
}
if (empty($moduleinfo->name)) {
$moduleinfo->name = $tool->name;
}
$moduleinfo->module = $module->id;
$moduleinfo->section = $sectionid;
$moduleinfo->visible = 1;
if (isset($item->url)) {
$moduleinfo->toolurl = $item->url;
$moduleinfo->typeid = 0;
} else {
$moduleinfo->typeid = $id;
}
$moduleinfo->instructorchoicesendname = LTI_SETTING_NEVER;
$moduleinfo->instructorchoicesendemailaddr = LTI_SETTING_NEVER;
$moduleinfo->instructorchoiceacceptgrades = LTI_SETTING_NEVER;
$moduleinfo->launchcontainer = LTI_LAUNCH_CONTAINER_DEFAULT;
if (isset($item->placementAdvice->presentationDocumentTarget)) {
if ($item->placementAdvice->presentationDocumentTarget === 'window') {
$moduleinfo->launchcontainer = LTI_LAUNCH_CONTAINER_WINDOW;
} else if ($item->placementAdvice->presentationDocumentTarget === 'frame') {
$moduleinfo->launchcontainer = LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS;
} else if ($item->placementAdvice->presentationDocumentTarget === 'iframe') {
$moduleinfo->launchcontainer = LTI_LAUNCH_CONTAINER_EMBED;
}
}
if (isset($item->custom)) {
$moduleinfo->instructorcustomparameters = '';
$first = true;
foreach ($item->custom as $key => $value) {
if (!$first) {
$moduleinfo->instructorcustomparameters .= "\n";
}
$moduleinfo->instructorcustomparameters .= "{$key}={$value}";
$first = false;
}
}
$moduleinfo = add_moduleinfo($moduleinfo, $course, null);
}
$clickhere = get_string('click_to_continue', 'lti', (object)array('link' => $continueurl->out()));
} else {
$clickhere = get_string('return_to_course', 'lti', (object)array('link' => $continueurl->out()));
}
if (!empty($errormsg) || !empty($msg)) {
$url = new moodle_url('/mod/lti/contentitem_return.php',
array('course' => $courseid));
$PAGE->set_url($url);
$pagetitle = strip_tags($course->shortname);
$PAGE->set_title($pagetitle);
$PAGE->set_heading($course->fullname);
$PAGE->set_pagelayout('embedded');
echo $OUTPUT->header();
if (!empty($lti) and !empty($context)) {
echo $OUTPUT->heading(format_string($lti->name, true, array('context' => $context)));
}
if (!empty($errormsg)) {
echo '<p style="color: #f00; font-weight: bold; margin: 1em;">';
echo get_string('lti_launch_error', 'lti') . ' ';
p($errormsg);
echo "</p>\n";
}
if (!empty($msg)) {
echo '<p style="margin: 1em;">';
p($msg);
echo "</p>\n";
}
echo "<p style=\"margin: 1em;\">{$clickhere}</p>";
echo $OUTPUT->footer();
} else {
$url = $continueurl->out();
echo '<html><body>';
$script = "
<script type=\"text/javascript\">
//<![CDATA[
if(window != top){
top.location.href = '{$url}';
}
//]]
</script>
";
$noscript = "
<noscript>
{$clickhere}
</noscript>
";
echo $script;
echo $noscript;
echo '</body></html>';
}

View File

@ -101,6 +101,7 @@ class mod_lti_edit_types_form extends moodleform{
$mform->addElement('textarea', 'lti_customparameters', get_string('custom', 'lti'), array('rows' => 4, 'cols' => 60));
$mform->setType('lti_customparameters', PARAM_TEXT);
$mform->addHelpButton('lti_customparameters', 'custom', 'lti');
$mform->setAdvanced('lti_customparameters');
if (!empty($this->_customdata->isadmin)) {
$options = array(
@ -136,6 +137,14 @@ class mod_lti_edit_types_form extends moodleform{
$mform->setDefault('lti_launchcontainer', LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS);
$mform->addHelpButton('lti_launchcontainer', 'default_launch_container', 'lti');
$mform->setType('lti_launchcontainer', PARAM_INT);
$mform->setAdvanced('lti_launchcontainer');
$mform->addElement('checkbox', 'lti_contentitem', '&nbsp;', ' ' . get_string('contentitem', 'lti'));
$mform->addHelpButton('lti_contentitem', 'contentitem', 'lti');
$mform->setAdvanced('lti_contentitem');
if ($istool) {
$mform->disabledIf('lti_contentitem', null);
}
$mform->addElement('hidden', 'oldicon');
$mform->setType('oldicon', PARAM_URL);

View File

@ -107,6 +107,10 @@ $string['configured'] = 'Configured';
$string['confirmtoolactivation'] = 'Are you sure you would like to activate this tool?';
$string['courseactivitiesorresources'] = 'Course activities or resources';
$string['course_tool_types'] = 'Course tools';
$string['configure_item'] = 'Configure item';
$string['contentitem'] = 'Tool supports Content-Item message';
$string['contentitem_help'] = 'If selected, the tool provider will participate in the creation of new links added to courses.';
$string['course_tool_types'] = 'Course tool types';
$string['courseid'] = 'Course ID number';
$string['courseinformation'] = 'Course information';
$string['courselink'] = 'Go to course';

View File

@ -376,18 +376,7 @@ function lti_build_request($instance, $typeconfig, $course, $typeid = null, $isl
$role = lti_get_ims_role($USER, $instance->cmid, $instance->course, $islti2);
$intro = '';
if (!empty($instance->cmid)) {
$intro = format_module_intro('lti', $instance, $instance->cmid);
$intro = html_to_text($intro, 0, false);
// This may look weird, but this is required for new lines
// so we generate the same OAuth signature as the tool provider.
$intro = str_replace("\n", "\r\n", $intro);
}
$requestparams = array(
'resource_link_title' => $instance->name,
'resource_link_description' => $intro,
'user_id' => $USER->id,
'lis_person_sourcedid' => $USER->idnumber,
'roles' => $role,
@ -395,6 +384,29 @@ function lti_build_request($instance, $typeconfig, $course, $typeid = null, $isl
'context_label' => $course->shortname,
'context_title' => $course->fullname,
);
if (!empty($instance->name)) {
$requestparams['resource_link_title'] = $instance->name;
}
if (!empty($instance->cmid)) {
$intro = format_module_intro('lti', $instance, $instance->cmid);
$intro = html_to_text($intro, 0, false);
// This may look weird, but this is required for new lines
// so we generate the same OAuth signature as the tool provider.
$intro = str_replace("\n", "\r\n", $intro);
$requestparams['resource_link_description'] = $intro;
}
if (!empty($instance->servicesalt)) {
$placementsecret = $instance->servicesalt;
if ( isset($placementsecret) && ($islti2 ||
$typeconfig['acceptgrades'] == LTI_SETTING_ALWAYS ||
($typeconfig['acceptgrades'] == LTI_SETTING_DELEGATE &&
$instance->instructorchoiceacceptgrades == LTI_SETTING_ALWAYS))) {
$sourcedid = json_encode(lti_build_sourcedid($instance->id, $USER->id, $placementsecret, $typeid));
$requestparams['lis_result_sourcedid'] = $sourcedid;
}
}
if (!empty($instance->id)) {
$requestparams['resource_link_id'] = $instance->id;
}
@ -407,7 +419,6 @@ function lti_build_request($instance, $typeconfig, $course, $typeid = null, $isl
$requestparams['context_type'] = 'CourseSection';
$requestparams['lis_course_section_sourcedid'] = $course->idnumber;
}
$placementsecret = $instance->servicesalt;
if ( !empty($instance->id) && isset($placementsecret) && ($islti2 ||
$typeconfig['acceptgrades'] == LTI_SETTING_ALWAYS ||
@ -492,9 +503,11 @@ function lti_build_standard_request($instance, $orgid, $islti2) {
$requestparams = array();
$requestparams['resource_link_id'] = $instance->id;
if (property_exists($instance, 'resource_link_id') and !empty($instance->resource_link_id)) {
$requestparams['resource_link_id'] = $instance->resource_link_id;
if ($instance) {
$requestparams['resource_link_id'] = $instance->id;
if (property_exists($instance, 'resource_link_id') and !empty($instance->resource_link_id)) {
$requestparams['resource_link_id'] = $instance->resource_link_id;
}
}
$requestparams['launch_presentation_locale'] = current_language();
@ -560,10 +573,14 @@ function lti_build_custom_parameters($toolproxy, $tool, $instance, $params, $cus
$tool->parameter, true), $custom);
$settings = lti_get_tool_settings($tool->toolproxyid);
$custom = array_merge($custom, lti_get_custom_parameters($toolproxy, $tool, $params, $settings));
$settings = lti_get_tool_settings($tool->toolproxyid, $instance->course);
$custom = array_merge($custom, lti_get_custom_parameters($toolproxy, $tool, $params, $settings));
$settings = lti_get_tool_settings($tool->toolproxyid, $instance->course, $instance->id);
$custom = array_merge($custom, lti_get_custom_parameters($toolproxy, $tool, $params, $settings));
if (!empty($instance->course)) {
$settings = lti_get_tool_settings($tool->toolproxyid, $instance->course);
$custom = array_merge($custom, lti_get_custom_parameters($toolproxy, $tool, $params, $settings));
if (!empty($instance->id)) {
$settings = lti_get_tool_settings($tool->toolproxyid, $instance->course, $instance->id);
$custom = array_merge($custom, lti_get_custom_parameters($toolproxy, $tool, $params, $settings));
}
}
}
return $custom;
@ -1454,6 +1471,10 @@ function lti_get_type_type_config($id) {
$type->lti_coursevisible = $config['coursevisible'];
}
if (isset($config['contentitem'])) {
$type->lti_contentitem = $config['contentitem'];
}
if (isset($config['debuglaunch'])) {
$type->lti_debuglaunch = $config['debuglaunch'];
}
@ -1489,6 +1510,10 @@ function lti_prepare_type_for_save($type, $config) {
$type->forcessl = !empty($config->lti_forcessl) ? $config->lti_forcessl : 0;
$config->lti_forcessl = $type->forcessl;
if (isset($config->lti_contentitem)) {
$type->contentitem = !empty($config->lti_contentitem) ? $config->lti_contentitem : 0;
$config->lti_contentitem = $type->contentitem;
}
$type->timemodified = time();
@ -2147,6 +2172,7 @@ function lti_get_capabilities() {
$capabilities = array(
'basic-lti-launch-request' => '',
'ContentItemSelectionRequest' => '',
'Context.id' => 'context_id',
'CourseSection.title' => 'context_title',
'CourseSection.label' => 'context_label',

View File

@ -19,11 +19,26 @@
* @package mod
* @subpackage lti
* @copyright Copyright (c) 2011 Moodlerooms Inc. (http://www.moodlerooms.com)
* @copyright 2015 Vital Source Technologies http://vitalsource.com
* @author Stephen Vickers
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
(function(){
var Y;
var LTICIP = {
BASE : 'base',
};
var CSS = {
PANEL : 'lti-contentitem-panel',
HIDDEN : 'hidden',
WRAP : 'lticip-wrap',
HEADER : 'lticip-header',
CLOSE : 'close',
CONTENT : 'lticip-content',
};
M.mod_lti = M.mod_lti || {};
M.mod_lti.LTI_SETTING_NEVER = 0;
@ -31,6 +46,13 @@
M.mod_lti.LTI_SETTING_DELEGATE = 2;
M.mod_lti.editor = {
_base : null,
_escCloseEvent : null,
_headingNode : null,
_contentNode : null,
_toolList : null,
_onResize : null,
_timer : null,
init: function(yui3, settings){
if(yui3){
Y = yui3;
@ -49,6 +71,21 @@
self.updateAutomaticToolMatch(Y.one('#id_securetoolurl'));
};
var create = Y.Node.create;
this._base = create('<div class="'+CSS.PANEL+' '+CSS.HIDDEN+'"></div>')
.append(create('<div class="'+CSS.WRAP+'"></div>')
.append(create('<div class="'+CSS.HEADER+' header"></div>')
.append(create('<div class="'+CSS.CLOSE+'"></div>'))
.append(create('<h2>'+M.util.get_string('configure_item', 'lti')+'</h2>')))
.append(create('<div class="'+CSS.CONTENT+'">' +
'<iframe class="id_contentitem_if" src="about:blank" style="width: 99%;"></iframe></div>'))
);
Y.one('.lti_contentitem').on('change', this.show, this);
this._base.one('.'+CSS.HEADER+' .'+CSS.CLOSE).on('click', this.hide, this);
this._headingNode = this._base.one('.'+CSS.HEADER);
this._contentNode = this._base.one('.'+CSS.CONTENT);
Y.one(document.body).append(this._base);
var typeSelector = Y.one('#id_typeid');
typeSelector.on('change', function(e){
updateToolMatches();
@ -492,6 +529,69 @@
}
}
});
},
contentItem: function(el){
var opt = el.options[el.selectedIndex];
if(opt.getAttribute('contentitem') == '1') {
window.location.href = opt.getAttribute('contentitemurl') + '&title=' +
encodeURIComponent(document.getElementById('id_name').value);
}
},
show : function(e) {
var opt = e.target.get('options').item(e.target.get('selectedIndex'));
if (opt.getAttribute('contentitem') == '1') {
this._toolList = e.target;
e.preventDefault();
e.halt();
this._timer = window.setTimeout(this.doReveal, 20000);
this._base.removeClass(CSS.HIDDEN);
var w = this._base.get('winWidth') * 0.8;
var h = this._base.get('winHeight') * 0.8;
var x = (this._base.get('winWidth') - w) / 2;
var y = (this._base.get('winHeight') - h) / 2;
this._base.setStyle('width', '' + w + 'px');
this._base.setStyle('height', '' + h + 'px');
this._base.setXY([x,y]);
var padding = 15; //The bottom of the iframe wasn\'t visible on some themes. Probably because of border widths, etc.
var viewportHeight = h - parseInt(this._headingNode.getStyle('height')) - padding;
this._escCloseEvent = Y.on('key', this.hide, document.body, 'down:27', this);
var url = opt.getAttribute('contentitemurl') + '&title=' +
encodeURIComponent(Y.one('#id_name').get('value'));
var ifr = Y.one('.id_contentitem_if');
ifr.setAttribute('src', url);
ifr.on('load', this.loaded, this);
ifr.setStyle("height", viewportHeight);
var frm = Y.one('.mform');
frm.reset();
}
},
doReveal : function() {
var el = Y.one('#id_warning');
el.removeClass(CSS.HIDDEN);
},
loaded : function() {
window.clearTimeout(this._timer);
},
hide : function(e) {
this.loaded();
if (this._escCloseEvent) {
this._escCloseEvent.detach();
this._escCloseEvent = null;
}
this._base.addClass(CSS.HIDDEN);
var ifr = Y.one('.id_contentitem_if');
ifr.setAttribute('src', 'about:blank');
}
};

View File

@ -43,6 +43,8 @@
* @author Jordi Piguillem
* @author Nikolas Galanis
* @author Chris Scribner
* @copyright 2015 Vital Source Technologies http://vitalsource.com
* @author Stephen Vickers
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
@ -54,11 +56,12 @@ require_once($CFG->dirroot.'/mod/lti/locallib.php');
class mod_lti_mod_form extends moodleform_mod {
public function definition() {
global $DB, $PAGE, $OUTPUT, $USER, $COURSE;
global $DB, $PAGE, $OUTPUT, $USER, $COURSE, $sesskey, $section;
if ($type = optional_param('type', false, PARAM_ALPHA)) {
component_callback("ltisource_$type", 'add_instance_hook');
}
$sectionreturn = optional_param('sr', 0, PARAM_INT);
$this->typeid = 0;
@ -95,7 +98,12 @@ class mod_lti_mod_form extends moodleform_mod {
$mform->addHelpButton('showdescriptionlaunch', 'display_description', 'lti');
// Tool settings.
$tooltypes = $mform->addElement('select', 'typeid', get_string('external_tool_type', 'lti'), array());
$attributes = array();
if ($update = optional_param('update', false, PARAM_INT)) {
$attributes['disabled'] = 'disabled';
}
$attributes['class'] = 'lti_contentitem';
$tooltypes = $mform->addElement('select', 'typeid', get_string('external_tool_type', 'lti'), array(), $attributes);
$typeid = optional_param('typeid', false, PARAM_INT);
$mform->getElement('typeid')->setValue($typeid);
$mform->addHelpButton('typeid', 'external_tool_type', 'lti');
@ -123,6 +131,15 @@ class mod_lti_mod_form extends moodleform_mod {
} else {
$attributes = array();
}
if (!$update && $id) {
$config = lti_get_type_config($id);
if (isset($config['contentitem']) && $config['contentitem']) {
$contentitemurl = new moodle_url('/mod/lti/contentitem2.php',
array('course' => $COURSE->id, 'section' => $section, 'id' => $id, 'sr' => $sectionreturn));
$attributes['contentitem'] = 1;
$attributes['contentitemurl'] = $contentitemurl->out(false);
}
}
$tooltypes->addOption($type->name, $id, $attributes);
}
@ -247,7 +264,8 @@ class mod_lti_mod_form extends moodleform_mod {
array('tooltypedeleted', 'lti'),
array('tooltypenotdeleted', 'lti'),
array('tooltypeupdated', 'lti'),
array('forced_help', 'lti')
array('forced_help', 'lti'),
array('configure_item', 'lti')
),
);

View File

@ -150,7 +150,8 @@ class toolproxy extends \mod_lti\local\ltiservice\resource_base {
if ($ok) {
$resources = $toolproxyjson->tool_profile->resource_handler;
foreach ($resources as $resource) {
$found = false;
$launchable = false;
$messages = array();
$tool = new \stdClass();
$iconinfo = null;
@ -164,19 +165,17 @@ class toolproxy extends \mod_lti\local\ltiservice\resource_base {
}
foreach ($resource->message as $message) {
if ($message->message_type == 'basic-lti-launch-request') {
$found = true;
$tool->path = $message->path;
$tool->enabled_capability = $message->enabled_capability;
$tool->parameter = $message->parameter;
break;
if (($message->message_type === 'basic-lti-launch-request') ||
($message->message_type === 'ContentItemSelectionRequest')) {
$launchable = $launchable || ($message->message_type === 'basic-lti-launch-request');
$messages[$message->message_type] = $message;
}
}
if (!$found) {
if (!$launchable) {
continue;
}
$tool->name = $resource->resource_name->default_value;
$tool->messages = $messages;
$tools[] = $tool;
}
$ok = count($tools) > 0;
@ -196,17 +195,27 @@ class toolproxy extends \mod_lti\local\ltiservice\resource_base {
$securebaseurl = $toolproxyjson->tool_profile->base_url_choice[0]->secure_base_url;
}
foreach ($tools as $tool) {
$messages = $tool->messages;
$config = new \stdClass();
$config->lti_toolurl = "{$baseurl}{$tool->path}";
$config->lti_toolurl = "{$baseurl}{$messages['basic-lti-launch-request']->path}";
$config->lti_typename = $tool->name;
$config->lti_coursevisible = 1;
$config->lti_forcessl = 0;
if (isset($messages['ContentItemSelectionRequest'])) {
$config->lti_contentitem = 1;
if ($messages['basic-lti-launch-request']->path !== $messages['ContentItemSelectionRequest']->path) {
$config->lti_toolurl_ContentItemSelectionRequest =
"{$baseurl}{$messages['ContentItemSelectionRequest']->path}";
}
$config->lti_enabledcapability_ContentItemSelectionRequest = implode("\n", $messages['ContentItemSelectionRequest']->enabled_capability);
$config->lti_parameter_ContentItemSelectionRequest = self::lti_extract_parameters($messages['ContentItemSelectionRequest']->parameter);
}
$type = new \stdClass();
$type->state = LTI_TOOL_STATE_PENDING;
$type->toolproxyid = $toolproxy->id;
$type->enabledcapability = implode("\n", $tool->enabled_capability);
$type->parameter = self::lti_extract_parameters($tool->parameter);
$type->enabledcapability = implode("\n", $messages['basic-lti-launch-request']->enabled_capability);
$type->parameter = self::lti_extract_parameters($messages['basic-lti-launch-request']->parameter);
if (!empty($tool->iconpath)) {
$type->icon = "{$baseurl}{$tool->iconpath}";

View File

@ -380,3 +380,21 @@
border: 1px solid #ddd;
border-radius: 4px;
}
/* Styles for mod_form.php to support Content-Item */
.lti-contentitem-panel {width:400px;background-color:#666;position:absolute;top:10%;left:10%;border:1px solid #666;border-width:0 5px 5px 0;}
.lti-contentitem-panel.hidden {display:none;}
.lti-contentitem-panel .lticip-wrap {margin-top:-5px;margin-left:-5px;background-color:#FFF;border:1px solid #999;height:inherit;}
.lti-contentitem-panel .lticip-header {background-color:#eee;padding:1px;}
.lti-contentitem-panel .lticip-header h2 {margin:3px 1em 0.5em 1em;font-size:1em;}
.lti-contentitem-panel .lticip-header .close {width:25px;height:15px;position:absolute;top:2px;right:1em;cursor:pointer;background:url("../../../../mod/lti/pix/close.png") no-repeat scroll 0 0 transparent;}
.lti-contentitem-panel .lticip-content {text-align:center;position:relative;width:100%;border-top:1px solid #999;border-bottom:1px solid #999;}
.lti-contentitem-panel .lticip-ajax-content {overflow:auto;}
.lti-contentitem-panel .lticip-loading-lightbox {position:absolute;width:100%;height:100%;top:0;left:0;background-color:#FFF;min-width:50px;min-height:50px;}
.lti-contentitem-panel .lticip-loading-lightbox.hidden {display:none;}
.lti-contentitem-panel .lticip-loading-lightbox .loading-icon {margin:auto;vertical-align:middle;margin-top:125px;}
.dir-rtl .lti-contentitem-panel .lticip-header .close {right: auto;left:1em;}