From 01e8bfd745cea2fbcde09da2b6f399f4b1edd097 Mon Sep 17 00:00:00 2001 From: John Okely Date: Fri, 22 Jan 2016 08:35:15 +0000 Subject: [PATCH 1/3] MDL-45064 lti: LTI types in activity chooser --- course/lib.php | 9 ++++ lib/tests/behat/behat_forms.php | 14 ++++++ mod/lti/lib.php | 15 +++++++ mod/lti/locallib.php | 55 +++++++++++++++++++++-- mod/lti/mod_form.php | 8 ++++ mod/lti/tests/behat/addtool.feature | 37 +++++++++++++++ mod/lti/tests/fixtures/tool_provider.html | 8 ++++ 7 files changed, 142 insertions(+), 4 deletions(-) create mode 100644 mod/lti/tests/behat/addtool.feature create mode 100644 mod/lti/tests/fixtures/tool_provider.html diff --git a/course/lib.php b/course/lib.php index e005dc03431..bbc0eb1b288 100644 --- a/course/lib.php +++ b/course/lib.php @@ -1257,6 +1257,15 @@ function get_module_metadata($course, $modnames, $sectionreturn = null) { } include_once($libfile); + $aliases = component_callback($modname, 'get_aliases', array(), array()); + if (count($aliases) > 0) { + foreach ($aliases as $alias) { + $module = $alias; + $module->archetype = plugin_supports('mod', $modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER); + $return[$alias->name] = $module; + } + } + // NOTE: this is legacy stuff, module subtypes are very strongly discouraged!! $gettypesfunc = $modname.'_get_types'; $types = MOD_SUBTYPE_NO_CHILDREN; diff --git a/lib/tests/behat/behat_forms.php b/lib/tests/behat/behat_forms.php index 90507b8de06..e93e98c6540 100644 --- a/lib/tests/behat/behat_forms.php +++ b/lib/tests/behat/behat_forms.php @@ -143,6 +143,20 @@ class behat_forms extends behat_base { } + /** + * Sets the field to wwwroot plus the given path. Include the first slash. + * + * @Given /^I set the field "(?P(?:[^"]|\\")*)" to local url "(?P(?:[^"]|\\")*)"$/ + * @throws ElementNotFoundException Thrown by behat_base::find + * @param string $field + * @param string $path + * @return void + */ + public function i_set_the_field_to_local_url($field, $path) { + global $CFG; + $this->set_field_value($field, $CFG->wwwroot . $path); + } + /** * Sets the specified value to the field. * diff --git a/mod/lti/lib.php b/mod/lti/lib.php index 090ae808237..3adf748cd29 100644 --- a/mod/lti/lib.php +++ b/mod/lti/lib.php @@ -196,6 +196,21 @@ function lti_delete_instance($id) { return $DB->delete_records("lti", array("id" => $basiclti->id)); } +/** + * Return aliases of this activity. LTI should have an alias for each configured tool type + * This is so you can add an external tool types directly from the activity chooser + * + * @return array An array of aliases for this activity + **/ +function lti_get_aliases() { + global $CFG, $COURSE; + require_once($CFG->dirroot.'/mod/lti/locallib.php'); + + $types = lti_get_configured_types($COURSE->id); + + return $types; +} + function lti_get_types() { global $OUTPUT; diff --git a/mod/lti/locallib.php b/mod/lti/locallib.php index 19578c90095..317403dc398 100644 --- a/mod/lti/locallib.php +++ b/mod/lti/locallib.php @@ -1070,8 +1070,14 @@ function lti_filter_tool_types(array $tools, $state) { return $return; } -function lti_get_types_for_add_instance() { - global $DB, $SITE, $COURSE; +/** + * Returns all lti types visible in this course + * + * @param int $courseid The id of the course to retieve types for + * @return stdClass All the lti types visible in the given course + */ +function lti_get_lti_types_by_course($courseid) { + global $DB, $SITE; $query = "SELECT * FROM {lti_types} @@ -1079,8 +1085,18 @@ function lti_get_types_for_add_instance() { AND (course = :siteid OR course = :courseid) AND state = :active"; - $admintypes = $DB->get_records_sql($query, - array('siteid' => $SITE->id, 'courseid' => $COURSE->id, 'active' => LTI_TOOL_STATE_CONFIGURED)); + return $DB->get_records_sql($query, + array('siteid' => $SITE->id, 'courseid' => $courseid, 'active' => LTI_TOOL_STATE_CONFIGURED)); +} + +/** + * Returns tool types for lti add instance and edit page + * + * @return array Array of lti types + */ +function lti_get_types_for_add_instance() { + global $COURSE; + $admintypes = lti_get_lti_types_by_course($COURSE->id); $types = array(); $types[0] = (object)array('name' => get_string('automatic', 'lti'), 'course' => 0, 'toolproxyid' => null); @@ -1092,6 +1108,37 @@ function lti_get_types_for_add_instance() { return $types; } +/** + * Returns a list of configured types in the given course + * + * @param int $courseid The id of the course to retieve types for + * @return array Array of lti types + */ +function lti_get_configured_types($courseid) { + global $OUTPUT; + $types = array(); + $admintypes = lti_get_lti_types_by_course($courseid); + + foreach ($admintypes as $ltitype) { + $type = new stdClass(); + $type->modclass = MOD_CLASS_ACTIVITY; + $type->name = 'lti_type_' . $ltitype->id; + $type->title = $ltitype->name; + if (empty($ltitype->icon)) { + $type->icon = $OUTPUT->pix_icon('icon', '', 'lti', array('class' => 'icon')); + } else { + $type->icon = html_writer::empty_tag('img', array('src' => $ltitype->icon, 'alt' => $ltitype->name, 'class' => 'icon')); + } + if (!empty($ltitype->description)) { + $type->help = $ltitype->description; + } + $type->link = new moodle_url('/course/modedit.php', array('add' => 'lti', 'return' => 0, 'course' => $courseid, 'sr' => 0, + 'typeid' => $ltitype->id)); + $types[] = $type; + } + return $types; +} + function lti_get_domain_from_url($url) { $matches = array(); diff --git a/mod/lti/mod_form.php b/mod/lti/mod_form.php index efa2a884c7e..af3105da4d8 100644 --- a/mod/lti/mod_form.php +++ b/mod/lti/mod_form.php @@ -96,6 +96,8 @@ class mod_lti_mod_form extends moodleform_mod { // Tool settings. $tooltypes = $mform->addElement('select', 'typeid', get_string('external_tool_type', 'lti'), array()); + $typeid = optional_param('typeid', false, PARAM_INT); + $mform->getElement('typeid')->setValue($typeid); $mform->addHelpButton('typeid', 'external_tool_type', 'lti'); $toolproxy = array(); @@ -149,6 +151,7 @@ class mod_lti_mod_form extends moodleform_mod { $mform->addElement('select', 'launchcontainer', get_string('launchinpopup', 'lti'), $launchoptions); $mform->setDefault('launchcontainer', LTI_LAUNCH_CONTAINER_DEFAULT); $mform->addHelpButton('launchcontainer', 'launchinpopup', 'lti'); + $mform->setAdvanced('launchcontainer'); $mform->addElement('text', 'resourcekey', get_string('resourcekey', 'lti')); $mform->setType('resourcekey', PARAM_TEXT); @@ -243,6 +246,11 @@ class mod_lti_mod_form extends moodleform_mod { ), ); + if (!empty($typeid)) { + $mform->setAdvanced('typeid'); + $mform->setAdvanced('toolurl'); + } + $PAGE->requires->js_init_call('M.mod_lti.editor.init', array(json_encode($jsinfo)), true, $module); } diff --git a/mod/lti/tests/behat/addtool.feature b/mod/lti/tests/behat/addtool.feature new file mode 100644 index 00000000000..873f83802d7 --- /dev/null +++ b/mod/lti/tests/behat/addtool.feature @@ -0,0 +1,37 @@ +@mod @mod_lti +Feature: Add tool types + In order to provide activities for learners + As a teacher + I need to be able to add external tools to a course + + Background: + Given the following "users" exist: + | username | firstname | lastname | email | + | teacher1 | Terry1 | Teacher1 | teacher1@example.com | + And the following "courses" exist: + | fullname | shortname | category | + | Course 1 | C1 | 0 | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + And I log in as "admin" + And I navigate to "Manage external tool types" node in "Site administration > Plugins > Activity modules > LTI" + And I follow "Add external tool configuration" + And I set the following fields to these values: + | Tool name | Teaching Tool 1 | + | Show tool type when creating tool instances | 1 | + And I set the field "Tool base URL" to local url "/mod/lti/tests/fixtures/tool_provider.html" + And I press "Save changes" + And I log out + + @javascript + Scenario: Add a tool via the acitivity picker + When I log in as "teacher1" + And I follow "Course 1" + And I turn editing mode on + And I add a "Teaching Tool 1" to section "1" and I fill the form with: + | Activity name | Test tool activity 1 | + | Launch container | Embed | + And I open "Test tool activity 1" actions menu + And I follow "Edit settings" in the open menu + Then the field "External tool type" matches value "Teaching Tool 1" diff --git a/mod/lti/tests/fixtures/tool_provider.html b/mod/lti/tests/fixtures/tool_provider.html new file mode 100644 index 00000000000..543a796bf40 --- /dev/null +++ b/mod/lti/tests/fixtures/tool_provider.html @@ -0,0 +1,8 @@ + + + Tool provider + + +

This represents a tool provider

+ + From 9ca0420e931fe877f33af54297f973c3beccaee3 Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Mon, 4 Apr 2016 08:57:09 +0800 Subject: [PATCH 2/3] MDL-45064 course: mod callback get_shortcuts() also deprecate callback get_types() --- course/format/singleactivity/lib.php | 14 ++- course/lib.php | 126 +++++++++++++++------------ course/renderer.php | 49 ++--------- lang/en/moodle.php | 1 + lib/moodlelib.php | 6 +- mod/upgrade.txt | 2 + 6 files changed, 99 insertions(+), 99 deletions(-) diff --git a/course/format/singleactivity/lib.php b/course/format/singleactivity/lib.php index 813e2c62c1c..f803e5985cc 100644 --- a/course/format/singleactivity/lib.php +++ b/course/format/singleactivity/lib.php @@ -341,7 +341,9 @@ class format_singleactivity extends format_base { } /** - * Checks if the activity type requires subtypes. + * Checks if the activity type has multiple items in the activity chooser. + * This may happen as a result of defining callback modulename_get_shortcuts() + * or [deprecated] modulename_get_types() - TODO MDL-53697 remove this line. * * @return bool|null (null if the check is not possible) */ @@ -349,7 +351,13 @@ class format_singleactivity extends format_base { if (!($modname = $this->get_activitytype())) { return null; } - return component_callback('mod_' . $modname, 'get_types', array(), MOD_SUBTYPE_NO_CHILDREN) !== MOD_SUBTYPE_NO_CHILDREN; + $metadata = get_module_metadata($this->get_course(), self::get_supported_activities()); + foreach ($metadata as $key => $moduledata) { + if (preg_match('/^'.$modname.':/', $key)) { + return true; + } + } + return false; } /** @@ -399,7 +407,7 @@ class format_singleactivity extends format_base { if ($this->can_add_activity()) { // This is a user who has capability to create an activity. if ($this->activity_has_subtypes()) { - // Activity that requires subtype can not be added automatically. + // Activity has multiple items in the activity chooser, it can not be added automatically. if (optional_param('addactivity', 0, PARAM_INT)) { return; } else { diff --git a/course/lib.php b/course/lib.php index bbc0eb1b288..9307e3c60ee 100644 --- a/course/lib.php +++ b/course/lib.php @@ -1226,7 +1226,7 @@ function set_section_visible($courseid, $sectionnumber, $visibility) { * module */ function get_module_metadata($course, $modnames, $sectionreturn = null) { - global $CFG, $OUTPUT; + global $OUTPUT; // get_module_metadata will be called once per section on the page and courses may show // different modules to one another @@ -1246,91 +1246,107 @@ function get_module_metadata($course, $modnames, $sectionreturn = null) { } if (isset($modlist[$course->id][$modname])) { // This module is already cached - $return[$modname] = $modlist[$course->id][$modname]; + $return += $modlist[$course->id][$modname]; continue; } + $modlist[$course->id][$modname] = array(); - // Include the module lib - $libfile = "$CFG->dirroot/mod/$modname/lib.php"; - if (!file_exists($libfile)) { - continue; - } - include_once($libfile); - - $aliases = component_callback($modname, 'get_aliases', array(), array()); - if (count($aliases) > 0) { - foreach ($aliases as $alias) { - $module = $alias; - $module->archetype = plugin_supports('mod', $modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER); - $return[$alias->name] = $module; + // Create an object for a default representation of this module type in the activity chooser. It will be used + // if module does not implement callback get_shortcuts() and it will also be passed to the callback if it exists. + $defaultmodule = new stdClass(); + $defaultmodule->title = $modnamestr; + $defaultmodule->name = $modname; + $defaultmodule->link = new moodle_url($urlbase, array('add' => $modname)); + $defaultmodule->icon = $OUTPUT->pix_icon('icon', '', $defaultmodule->name, array('class' => 'icon')); + $sm = get_string_manager(); + if ($sm->string_exists('modulename_help', $modname)) { + $defaultmodule->help = get_string('modulename_help', $modname); + if ($sm->string_exists('modulename_link', $modname)) { // Link to further info in Moodle docs. + $link = get_string('modulename_link', $modname); + $linktext = get_string('morehelp'); + $defaultmodule->help .= html_writer::tag('div', + $OUTPUT->doc_link($link, $linktext, true), array('class' => 'helpdoclink')); } } + $defaultmodule->archetype = plugin_supports('mod', $modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER); - // NOTE: this is legacy stuff, module subtypes are very strongly discouraged!! - $gettypesfunc = $modname.'_get_types'; - $types = MOD_SUBTYPE_NO_CHILDREN; - if (function_exists($gettypesfunc)) { - $types = $gettypesfunc(); + // Legacy support for callback get_types() - do not use any more, use get_shortcuts() instead! + $typescallbackexists = component_callback_exists($modname, 'get_types'); + + // Each module can implement callback modulename_get_shortcuts() in its lib.php and return the list + // of elements to be added to activity chooser. + $items = component_callback($modname, 'get_shortcuts', array($defaultmodule), null); + if ($items !== null) { + foreach ($items as $item) { + // Add all items to the return array. All items must have different links, use them as a key in the return array. + if (!isset($item->archetype)) { + $item->archetype = $defaultmodule->archetype; + } + if (!isset($item->icon)) { + $item->icon = $defaultmodule->icon; + } + // If plugin returned the only one item with the same link as default item - cache it as $modname, + // otherwise append the link url to the module name. + $item->name = (count($items) == 1 && + $item->link->out() === $defaultmodule->link->out()) ? $modname : $modname . ':' . $item->link; + $modlist[$course->id][$modname][$item->name] = $item; + } + $return += $modlist[$course->id][$modname]; + if ($typescallbackexists) { + debugging('Both callbacks get_shortcuts() and get_types() are found in module ' . $modname . + '. Callback get_types() will be completely ignored', DEBUG_DEVELOPER); + } + // If get_shortcuts() callback is defined, the default module action is not added. + // It is a responsibility of the callback to add it to the return value unless it is not needed. + continue; } + + if ($typescallbackexists) { + debugging('Callback get_types() is found in module ' . $modname . ', this functionality is deprecated, ' . + 'please use callback get_shortcuts() instead', DEBUG_DEVELOPER); + } + $types = component_callback($modname, 'get_types', array(), MOD_SUBTYPE_NO_CHILDREN); if ($types !== MOD_SUBTYPE_NO_CHILDREN) { + // Legacy support for deprecated callback get_types(). To be removed in Moodle 3.5. TODO MDL-53697. if (is_array($types) && count($types) > 0) { - $group = new stdClass(); - $group->name = $modname; - $group->icon = $OUTPUT->pix_icon('icon', '', $modname, array('class' => 'icon')); + $grouptitle = $modnamestr; + $icon = $OUTPUT->pix_icon('icon', '', $modname, array('class' => 'icon')); foreach($types as $type) { if ($type->typestr === '--') { continue; } if (strpos($type->typestr, '--') === 0) { - $group->title = str_replace('--', '', $type->typestr); + $grouptitle = str_replace('--', '', $type->typestr); continue; } - // Set the Sub Type metadata + // Set the Sub Type metadata. $subtype = new stdClass(); - $subtype->title = $type->typestr; + $subtype->title = get_string('activitytypetitle', '', + (object)['activity' => $grouptitle, 'type' => $type->typestr]); $subtype->type = str_replace('&', '&', $type->type); - $subtype->name = preg_replace('/.*type=/', '', $subtype->type); + $typename = preg_replace('/.*type=/', '', $subtype->type); $subtype->archetype = $type->modclass; - // The group archetype should match the subtype archetypes and all subtypes - // should have the same archetype - $group->archetype = $subtype->archetype; - if (!empty($type->help)) { $subtype->help = $type->help; } else if (get_string_manager()->string_exists('help' . $subtype->name, $modname)) { $subtype->help = get_string('help' . $subtype->name, $modname); } - $subtype->link = new moodle_url($urlbase, array('add' => $modname, 'type' => $subtype->name)); - $group->types[] = $subtype; + $subtype->link = new moodle_url($urlbase, array('add' => $modname, 'type' => $typename)); + $subtype->name = $modname . ':' . $subtype->link; + $subtype->icon = $icon; + $modlist[$course->id][$modname][$subtype->name] = $subtype; } - $modlist[$course->id][$modname] = $group; + $return += $modlist[$course->id][$modname]; } } else { - $module = new stdClass(); - $module->title = $modnamestr; - $module->name = $modname; - $module->link = new moodle_url($urlbase, array('add' => $modname)); - $module->icon = $OUTPUT->pix_icon('icon', '', $module->name, array('class' => 'icon')); - $sm = get_string_manager(); - if ($sm->string_exists('modulename_help', $modname)) { - $module->help = get_string('modulename_help', $modname); - if ($sm->string_exists('modulename_link', $modname)) { // Link to further info in Moodle docs - $link = get_string('modulename_link', $modname); - $linktext = get_string('morehelp'); - $module->help .= html_writer::tag('div', $OUTPUT->doc_link($link, $linktext, true), array('class' => 'helpdoclink')); - } - } - $module->archetype = plugin_supports('mod', $modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER); - $modlist[$course->id][$modname] = $module; - } - if (isset($modlist[$course->id][$modname])) { - $return[$modname] = $modlist[$course->id][$modname]; - } else { - debugging("Invalid module metadata configuration for {$modname}"); + // Neither get_shortcuts() nor get_types() callbacks found, use the default item for the activity chooser. + $modlist[$course->id][$modname][$modname] = $defaultmodule; + $return[$modname] = $defaultmodule; } } + core_collator::asort_objects_by_property($return, 'title'); return $return; } diff --git a/course/renderer.php b/course/renderer.php index 617f4e81315..787866a4853 100644 --- a/course/renderer.php +++ b/course/renderer.php @@ -252,14 +252,7 @@ class core_course_renderer extends plugin_renderer_base { protected function course_modchooser_module_types($modules) { $return = ''; foreach ($modules as $module) { - if (!isset($module->types)) { - $return .= $this->course_modchooser_module($module); - } else { - $return .= $this->course_modchooser_module($module, array('nonoption')); - foreach ($module->types as $type) { - $return .= $this->course_modchooser_module($type, array('option', 'subtype')); - } - } + $return .= $this->course_modchooser_module($module); } return $return; } @@ -443,39 +436,15 @@ class core_course_renderer extends plugin_renderer_base { $activities = array(MOD_CLASS_ACTIVITY => array(), MOD_CLASS_RESOURCE => array()); foreach ($modules as $module) { - if (isset($module->types)) { - // This module has a subtype - // NOTE: this is legacy stuff, module subtypes are very strongly discouraged!! - $subtypes = array(); - foreach ($module->types as $subtype) { - $link = $subtype->link->out(true, $urlparams); - $subtypes[$link] = $subtype->title; - } - - // Sort module subtypes into the list - $activityclass = MOD_CLASS_ACTIVITY; - if ($module->archetype == MOD_CLASS_RESOURCE) { - $activityclass = MOD_CLASS_RESOURCE; - } - if (!empty($module->title)) { - // This grouping has a name - $activities[$activityclass][] = array($module->title => $subtypes); - } else { - // This grouping does not have a name - $activities[$activityclass] = array_merge($activities[$activityclass], $subtypes); - } - } else { - // This module has no subtypes - $activityclass = MOD_CLASS_ACTIVITY; - if ($module->archetype == MOD_ARCHETYPE_RESOURCE) { - $activityclass = MOD_CLASS_RESOURCE; - } else if ($module->archetype === MOD_ARCHETYPE_SYSTEM) { - // System modules cannot be added by user, do not add to dropdown - continue; - } - $link = $module->link->out(true, $urlparams); - $activities[$activityclass][$link] = $module->title; + $activityclass = MOD_CLASS_ACTIVITY; + if ($module->archetype == MOD_ARCHETYPE_RESOURCE) { + $activityclass = MOD_CLASS_RESOURCE; + } else if ($module->archetype === MOD_ARCHETYPE_SYSTEM) { + // System modules cannot be added by user, do not add to dropdown. + continue; } + $link = $module->link->out(true, $urlparams); + $activities[$activityclass][$link] = $module->title; } $straddactivity = get_string('addactivity'); diff --git a/lang/en/moodle.php b/lang/en/moodle.php index 237e9205384..a5407741470 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -39,6 +39,7 @@ $string['activityreport'] = 'Activity report'; $string['activityreports'] = 'Activity reports'; $string['activityselect'] = 'Select this activity to be moved elsewhere'; $string['activitysince'] = 'Activity since {$a}'; +$string['activitytypetitle'] = '{$a->activity} - {$a->type}'; $string['activityweighted'] = 'Activity per user'; $string['add'] = 'Add'; $string['addactivity'] = 'Add an activity...'; diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 44dc966c352..ff73eb368d4 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -448,7 +448,11 @@ define('MOD_ARCHETYPE_ASSIGNMENT', 2); /** System (not user-addable) module archetype */ define('MOD_ARCHETYPE_SYSTEM', 3); -/** Return this from modname_get_types callback to use default display in activity chooser */ +/** + * Return this from modname_get_types callback to use default display in activity chooser. + * Deprecated, will be removed in 3.5, TODO MDL-53697. + * @deprecated since Moodle 3.1 + */ define('MOD_SUBTYPE_NO_CHILDREN', 'modsubtypenochildren'); /** diff --git a/mod/upgrade.txt b/mod/upgrade.txt index c8b4998da30..ad0c75de3b9 100644 --- a/mod/upgrade.txt +++ b/mod/upgrade.txt @@ -5,6 +5,8 @@ information provided here is intended especially for developers. * Old /mod/MODULENAME/pix/icon.gif and enrol/paypal/pix/icon.gif GIF icons have been removed. Please use pix_icon renderable instead. +* Callback get_types() is deprecated, instead activity modules can define callback get_shortcuts(). + See source code for get_module_metadata(). === 3.0 === From 2348c137322093cf0b3418d9768155cbdc2884bb Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Mon, 4 Apr 2016 08:58:12 +0800 Subject: [PATCH 3/3] MDL-45064 mod_lti: use callback get_shortcuts() deprecate callback for ltisource plugins get_types(), instead introduce get_shortcuts() --- mod/lti/lib.php | 83 +++++++++++++++++--------------------- mod/lti/locallib.php | 14 +++---- mod/lti/source/upgrade.txt | 7 ++++ 3 files changed, 50 insertions(+), 54 deletions(-) create mode 100644 mod/lti/source/upgrade.txt diff --git a/mod/lti/lib.php b/mod/lti/lib.php index 3adf748cd29..117b4bf91a5 100644 --- a/mod/lti/lib.php +++ b/mod/lti/lib.php @@ -198,60 +198,51 @@ function lti_delete_instance($id) { /** * Return aliases of this activity. LTI should have an alias for each configured tool type - * This is so you can add an external tool types directly from the activity chooser + * This is so you can add an external tool types directly to the activity chooser * - * @return array An array of aliases for this activity + * @param stdClass $defaultitem default item that would be added to the activity chooser if this callback was not present. + * It has properties: archetype, name, title, help, icon, link + * @return array An array of aliases for this activity. Each element is an object with same list of properties as $defaultitem. + * Properties title and link are required **/ -function lti_get_aliases() { +function lti_get_shortcuts($defaultitem) { global $CFG, $COURSE; require_once($CFG->dirroot.'/mod/lti/locallib.php'); - $types = lti_get_configured_types($COURSE->id); + $types = lti_get_configured_types($COURSE->id, $defaultitem->link->param('sr')); + $types[] = $defaultitem; - return $types; -} - -function lti_get_types() { - global $OUTPUT; - - $subtypes = array(); - foreach (get_plugin_list('ltisource') as $name => $dir) { - if ($moretypes = component_callback("ltisource_$name", 'get_types')) { - $subtypes = array_merge($subtypes, $moretypes); + // Add items defined in ltisource plugins. + foreach (core_component::get_plugin_list('ltisource') as $pluginname => $dir) { + if ($moretypes = component_callback("ltisource_$pluginname", 'get_types')) { + // Callback 'get_types()' in 'ltisource' plugins is deprecated in 3.1 and will be removed in 3.5, TODO MDL-53697. + debugging('Deprecated callback get_types() is found in ltisource_' . $pluginname . + ', use get_shortcuts() instead', DEBUG_DEVELOPER); + $grouptitle = get_string('modulenameplural', 'mod_lti'); + foreach ($moretypes as $subtype) { + // Instead of adding subitems combine the name of the group with the name of the subtype. + $subtype->title = get_string('activitytypetitle', '', + (object)['activity' => $grouptitle, 'type' => $subtype->typestr]); + // Re-implement the logic of get_module_metadata() in Moodle 3.0 and below for converting + // subtypes into items in activity chooser. + $subtype->type = str_replace('&', '&', $subtype->type); + $subtype->name = preg_replace('/.*type=/', '', $subtype->type); + $subtype->link = new moodle_url($defaultitem->link, array('type' => $subtype->name)); + if (empty($subtype->help) && !empty($subtype->name) && + get_string_manager()->string_exists('help' . $subtype->name, $pluginname)) { + $subtype->help = get_string('help' . $subtype->name, $pluginname); + } + unset($subtype->typestr); + $types[] = $subtype; + } + } + // LTISOURCE plugins can also implement callback get_shortcuts() to add items to the activity chooser. + // The return values are the same as of the 'mod' callbacks except that $defaultitem is only passed for reference and + // should not be added to the return value. + if ($moretypes = component_callback("ltisource_$pluginname", 'get_shortcuts', array($defaultitem))) { + $types = array_merge($types, $moretypes); } } - if (empty($subtypes)) { - return MOD_SUBTYPE_NO_CHILDREN; - } - - $types = array(); - - $type = new stdClass(); - $type->modclass = MOD_CLASS_ACTIVITY; - $type->type = 'lti_group_start'; - $type->typestr = '--'.get_string('modulenameplural', 'mod_lti'); - $types[] = $type; - - $link = get_string('modulename_link', 'mod_lti'); - $linktext = get_string('morehelp'); - $help = get_string('modulename_help', 'mod_lti'); - $help .= html_writer::tag('div', $OUTPUT->doc_link($link, $linktext, true), array('class' => 'helpdoclink')); - - $type = new stdClass(); - $type->modclass = MOD_CLASS_ACTIVITY; - $type->type = ''; - $type->typestr = get_string('generaltool', 'mod_lti'); - $type->help = $help; - $types[] = $type; - - $types = array_merge($types, $subtypes); - - $type = new stdClass(); - $type->modclass = MOD_CLASS_ACTIVITY; - $type->type = 'lti_group_end'; - $type->typestr = '--'; - $types[] = $type; - return $types; } diff --git a/mod/lti/locallib.php b/mod/lti/locallib.php index 317403dc398..bc6a9aa6a48 100644 --- a/mod/lti/locallib.php +++ b/mod/lti/locallib.php @@ -1074,7 +1074,7 @@ function lti_filter_tool_types(array $tools, $state) { * Returns all lti types visible in this course * * @param int $courseid The id of the course to retieve types for - * @return stdClass All the lti types visible in the given course + * @return stdClass[] All the lti types visible in the given course */ function lti_get_lti_types_by_course($courseid) { global $DB, $SITE; @@ -1112,9 +1112,10 @@ function lti_get_types_for_add_instance() { * Returns a list of configured types in the given course * * @param int $courseid The id of the course to retieve types for - * @return array Array of lti types + * @param int $sectionreturn section to return to for forming the URLs + * @return array Array of lti types. Each element is object with properties: name, title, icon, help, link */ -function lti_get_configured_types($courseid) { +function lti_get_configured_types($courseid, $sectionreturn = 0) { global $OUTPUT; $types = array(); $admintypes = lti_get_lti_types_by_course($courseid); @@ -1129,11 +1130,8 @@ function lti_get_configured_types($courseid) { } else { $type->icon = html_writer::empty_tag('img', array('src' => $ltitype->icon, 'alt' => $ltitype->name, 'class' => 'icon')); } - if (!empty($ltitype->description)) { - $type->help = $ltitype->description; - } - $type->link = new moodle_url('/course/modedit.php', array('add' => 'lti', 'return' => 0, 'course' => $courseid, 'sr' => 0, - 'typeid' => $ltitype->id)); + $type->link = new moodle_url('/course/modedit.php', array('add' => 'lti', 'return' => 0, 'course' => $courseid, + 'sr' => $sectionreturn, 'typeid' => $ltitype->id)); $types[] = $type; } return $types; diff --git a/mod/lti/source/upgrade.txt b/mod/lti/source/upgrade.txt new file mode 100644 index 00000000000..5bfcc6aa8d0 --- /dev/null +++ b/mod/lti/source/upgrade.txt @@ -0,0 +1,7 @@ +This files describes API changes in /mod/lti/source/* - LTI source plugins, +information provided here is intended especially for developers. + +=== 3.1 === + +* Callback get_types() is deprecated, instead ltisource plugins can define callback get_shortcuts(). + See source code for lti_get_shortcuts() and get_module_metadata().