Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ to complete the installation from the command line.

## License ##

The included DTD for SVG is licensed by the World Wide Web Consortium, see copyright
notice in pix/svg11.dtd

2021 ISB Bayern, Stefan Hanauska <stefan.hanauska@csg-in.de>
Icon by Dunja Speckner
Dragging of SVG elements by Peter Collingridge
Expand Down
10 changes: 10 additions & 0 deletions amd/build/linkmodal.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions amd/build/linkmodal.min.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 66 additions & 0 deletions amd/src/linkmodal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// 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/>.

import Modal from 'core/modal';
import Ajax from 'core/ajax';
import * as manualcompletion from 'core_course/manual_completion_toggle';
import {renderLearningmap} from 'mod_learningmap/renderer';
import CourseEvents from 'core_course/events';
import $ from 'jquery';

/**
* Helper for opening course modules in a modal that do not have a view page.
*
* @module mod_learningmap/linkmodal
* @copyright 2025 ISB Bayern
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

/**
* Initialize the link modal listener for a learning map.
*
* @param {number} learningmapcmid - The course module ID of the learning map.
*/
export const init = async(learningmapcmid) => {
document.getElementById('learningmap-render-container-' + learningmapcmid).addEventListener('click', async(event) => {
const target = event.target.closest('a[data-cmid]');
if (target && !target.hasAttribute('xlink:href')) {
event.preventDefault();
const cmid = target.getAttribute('data-cmid');
if (cmid) {
const data = await Ajax.call([{
methodname: 'mod_learningmap_get_cm',
args: {
cmid: cmid
},
}])[0];
let js = $.parseHTML(data.js, null, true).map(node => node.innerHTML).join("\n");
const modal = await Modal.create({
title: data.name,
body: data.completion + data.html,
show: false,
removeOnClose: true,
large: true,
});
modal.bodyJS = js;
modal.show();
manualcompletion.init();
document.addEventListener(CourseEvents.manualCompletionToggled, () => {
renderLearningmap(learningmapcmid);
});
}
}
});
};
122 changes: 122 additions & 0 deletions classes/external/get_cm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?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/>.

namespace mod_learningmap\external;

use core_external\external_api;
use core_external\external_value;
use core_external\external_single_structure;
use core_external\external_function_parameters;
use core_courseformat\output\local\content\cm\completion;
/**
* Class get_cm
*
* @package mod_learningmap
* @copyright 2025 ISB Bayern
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class get_cm extends external_api {
/**
* Returns description of method parameters
*
* @return \external_function_parameters
*/
public static function execute_parameters(): external_function_parameters {
return new external_function_parameters(
[
'cmid' => new external_value(PARAM_INT, 'Course module id'),
]
);
}

/**
* Returns course module data
*
* @param int $cmid Course module id
* @return array Course module data
* @throws \moodle_exception
*/
public static function execute(int $cmid): array {
global $PAGE, $OUTPUT;

define('LEARNINGMAP_NO_BACKLINK', true);

$cm = get_coursemodule_from_id('', $cmid, 0, false, MUST_EXIST);
$context = \context_module::instance($cm->id);
$course = get_course($cm->course);
self::validate_context($context);

require_capability('mod/' . $cm->modname . ':view', $context);

$modinfo = get_fast_modinfo($course);

if (!$cm->uservisible) {
require_capability('moodle/course:viewhiddenactivities', $context);
}

$PAGE->set_url($cm->url ?? new \moodle_url('/mod/' . $cm->modname . '/view.php', ['id' => $cm->id]));
$PAGE->set_context($context);
$PAGE->set_cm($cm, $cm->course);
$PAGE->set_pagelayout('embedded');

$completioninfo = new \completion_info($course);
$completioninfo->set_module_viewed($cm);

$data = (array)$cm;

// Remove description for labels, because it is already in html.
if ($cm->modname === 'label') {
$PAGE->activityheader->set_description('');
}

$data['completion'] = $OUTPUT->render_from_template(
'core/activity_header',
$PAGE->activityheader->export_for_template($OUTPUT)
);

$data['name'] = format_string($cm->name, true, ['context' => $context]);

$PAGE->start_collecting_javascript_requirements();
$data['html'] = $modinfo->get_cm($cmid)->get_formatted_content(['overflowdiv' => true, 'noclean' => true]);
$data['js'] = $PAGE->requires->get_end_code();

return $data;
}

/**
* Returns description of method result value
*
* @return \external_description
*/
public static function execute_returns(): external_single_structure {
return new external_single_structure(
[
'id' => new external_value(PARAM_INT, 'Course module id'),
'course' => new external_value(PARAM_INT, 'Course id'),
'module' => new external_value(PARAM_INT, 'Module id'),
'instance' => new external_value(PARAM_INT, 'Instance id'),
'section' => new external_value(PARAM_INT, 'Section id'),
'name' => new external_value(PARAM_TEXT, 'Course module name'),
'visible' => new external_value(PARAM_INT, 'Visible'),
'groupmode' => new external_value(PARAM_INT, 'Group mode'),
'groupingid' => new external_value(PARAM_INT, 'Grouping id'),
'html' => new external_value(PARAM_RAW, 'Course module html'),
'js' => new external_value(PARAM_RAW, 'Course module javascript'),
'completion' => new external_value(PARAM_RAW, 'Completion html'),
]
);
}
}
24 changes: 23 additions & 1 deletion classes/helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,19 @@ class helper {
public static function show_map_on_course_page($cm): bool {
global $DB;
$showmaponcoursepage = $DB->get_field('learningmap', 'showmaponcoursepage', ['id' => $cm->instance]);
return !empty($showmaponcoursepage) && !self::is_learningmap_format($cm);
}

/**
* Checks if the course format of the course the given cm belongs to is 'learningmap'.
*
* @param cm_info $cm The course module info object.
* @return bool True if the course format is 'learningmap', false otherwise.
*/
public static function is_learningmap_format($cm): bool {
[$course, ] = get_course_and_cm_from_cmid($cm->id);
$courseformat = $course->format;
return !empty($showmaponcoursepage) && $courseformat !== 'learningmap';
return $courseformat === 'learningmap';
}

/**
Expand Down Expand Up @@ -89,4 +99,16 @@ public static function repair_learningmap_record(int $learningmapid): void {
}
}
}

/**
* Determines if the current request is an AJAX request for getting a course module.
*
* @return bool True if the request is an AJAX request for getting a course module, false otherwise.
*/
public static function is_ajax_request(): bool {
global $_REQUEST;
return
!empty($_REQUEST['info']) &&
in_array($_REQUEST['info'], ['core_course_get_module', 'mod_learningmap_get_cm']);
}
}
4 changes: 4 additions & 0 deletions classes/local/hook_callbacks.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ class hook_callbacks {
public static function inject_backlinks_into_activity_header(before_http_headers $beforehttpheadershook): void {
global $OUTPUT, $PAGE;

if (defined('LEARNINGMAP_NO_BACKLINK')) {
return;
}

// Don't run during initial install.
if (during_initial_install()) {
return;
Expand Down
20 changes: 14 additions & 6 deletions classes/mapworker.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class mapworker {
*
* @param string $svgcode The SVG code to build the map from
* @param array $placestore The placestore data to use while processing the map
* @param cm_info|null $cm The course module that belongs to the map (null by default)
* @param \cm_info|null $cm The course module that belongs to the map (null by default)
* @param bool $edit Whether the mapworker should prepare the map for edit mode (false by default)
* @param int $group Group id to use (default 0 means no group)
*/
Expand Down Expand Up @@ -163,17 +163,25 @@ public function process_map_objects(): void {

$placecm = $modinfo->get_cm($place['linkedActivity']);

$url = '';
// Set the link URL in the map.
if (!empty($placecm->url)) {
// Link modules that have a view page to their corresponding url.
$url = '' . $placecm->url;
$url = $placecm->url->out();
} else {
// Other modules (like labels) are shown on the course page. Link to the corresponding anchor.
$url = $CFG->wwwroot . '/course/view.php?id=' . $placecm->course .
'&section=' . $placecm->sectionnum . '#module-' . $placecm->id;
// Other modules (like labels) are shown on the course page.
if (empty($this->placestore['usemodal'])) {
// Link to the corresponding anchor.
$url = $CFG->wwwroot . '/course/view.php?id=' . $placecm->course .
'&section=' . $placecm->sectionnum . '#module-' . $placecm->id;
}
}
if (!$this->edit) {
$this->svgmap->set_link($place['linkId'], $url);
$this->svgmap->set_attribute($place['linkId'], 'data-cmid', $placecm->id);
$this->svgmap->remove_link($place['linkId']);
if (!empty($url)) {
$this->svgmap->set_link($place['linkId'], $url);
}
}
$links[$place['id']] = $place['linkId'];
$this->svgmap->update_text_and_title(
Expand Down
Loading
Loading