. /** * This file contains local methods for the course format Tiles (not included in lib.php as that's widely called) * @since Moodle 2.7 * @package format_tiles * @copyright 2018 David Watson {@link http://evolutioncode.uk} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Experimental feature allowing a teacher to click and convert any label into a page * @param int $cmid the course module id of the label (which is recycled) * @param stdClass $course * @throws dml_exception * @throws required_capability_exception * @throws coding_exception */ function format_tiles_convert_label_to_page($cmid, $course) { global $DB; $cm = $DB->get_record('course_modules', array('id' => $cmid), '*', MUST_EXIST); $labelmoduleid = $DB->get_record('modules', array('name' => 'label'), 'id', MUST_EXIST)->id; if ($cm->module != $labelmoduleid) { debugging("Cannot convert a non label - course module id " . $cmid, DEBUG_DEVELOPER); return; } $label = $DB->get_record('label', array('id' => $cm->instance), '*', MUST_EXIST); if ($label->course !== $course->id || $cm->course !== $course->id) { debugging("Cannot convert label - incorrect course id " . $course->id, DEBUG_DEVELOPER); return; } $coursecontext = context_course::instance($course->id); require_capability('mod/page:addinstance', $coursecontext); require_capability('moodle/course:manageactivities', $coursecontext); // Prepare the new page database object using the label as a basis. $newpage = $label; // New page display name - label names may be multi line but we only want first line. $newpage->name = format_tiles_get_first_line($label->name); // Now the content - if the first line contains a repetition of the 'name', remove the repetition. $newpage->content = $label->intro; $firstline = format_tiles_get_first_line($newpage->content); if (strpos($firstline, $newpage->name) !== false && strpos($firstline, 'PLUGINFILE') === false) { // The first line seems to include what we are using for the name. // Also it does not seem to contain a file link so is not adding anything - remove it. $remainder = substr($newpage->content, strpos($newpage->content, $firstline) + strlen($firstline)); $newfirstline = str_replace($newpage->name, '', $firstline); $newpage->content = $newfirstline . $remainder; } $newpage->intro = ''; $newpage->contentformat = FORMAT_HTML; $newpage->display = 0; $newpage->displayoptions = serialize(array( 'printheading' => get_config('page', 'printheading'), 'printintro' => get_config('page', 'printintro') )); $newpage->timemodified = time(); $newpage->revision = 0; // Vars $newpage->legacyfiles and $newpage->legacyfileslast are left null. // Now add new record to the page table. $newpageid = $DB->insert_record('page', $newpage, true); // Make necessary changes to the course modules table. $cm->module = $DB->get_record('modules', array('name' => 'page'), 'id', MUST_EXIST)->id; $cm->instance = $newpageid; $cm->timemodified = time(); $DB->update_record('course_modules', $cm); // If label contained embedded images etc, update files table to show they now relate to page not label. $contextid = $DB->get_record('context', array('contextlevel' => CONTEXT_MODULE, 'instanceid' => $cmid), 'id', MUST_EXIST)->id; $files = $DB->get_records('files', array('component' => 'mod_label', 'contextid' => $contextid)); if (count($files) > 0) { $fs = get_file_storage(); foreach ($files as $file) { // We modify only the fields we need to in order to convert label to page i.e. component and filearea. // We ensure that we leave the others including contextid unchanged as they are needed to generate the file URL. // They are contextid, filepath ('/') and itemid ('0'). // We do change the pathnamehash as it is a hash of the other values so needs recalculating. // The embedded URL is like [wwwroot]/pluginfile.php/[contextid]/[component]/[filearea]/[itemid][filepath][filename]. // e.g. [wwwroot]/pluginfile.php/7577/mod_page/content/0/an_image.png. $pathnamehash = $fs->get_pathname_hash( $file->contextid, 'mod_page', // New component. 'content', // New filearea. $file->itemid, $file->filepath, $file->filename ); $params = array( 'pathnamehash' => $pathnamehash, 'timemodified' => time(), 'id' => $file->id ); $DB->execute( "UPDATE {files} SET pathnamehash = :pathnamehash, component = 'mod_page', filearea='content', timemodified = :timemodified WHERE id = :id", $params ); } } // Finally remove the old label. $DB->delete_records('label', array('id' => $label->id)); rebuild_course_cache($course->id, true); \core\notification::info(get_string('labelconverted', 'format_tiles')); $cm->modname = "page"; $cm->name = $newpage->name; $event = \format_tiles\event\label_converted::create_from_cm($cm); $event->trigger(); } /** * Get the first line of some text, i.e. all the text * before char with ASCII code 10 or 13 * @param string $text the text to search * @return string the resulting text */ function format_tiles_get_first_line($text) { $text = explode(chr(13), $text)[0]; // Newline char \n. if (strpos($text, chr(10))) { // Return char \r in case it is used instead. $text = explode(chr(10), $text)[0]; } return $text; } /** * Which course modules is the site administrator allowing to be displayed in a modal? * @return array the permitted modules including resource types e.g. page, pdf, HTML * @throws dml_exception */ function format_tiles_allowed_modal_modules() { $devicetype = \core_useragent::get_device_type(); if ($devicetype != \core_useragent::DEVICETYPE_TABLET && $devicetype != \core_useragent::DEVICETYPE_MOBILE && !(\core_useragent::is_ie())) { // JS navigation and modals in Internet Explorer are not supported by this plugin so we disable modals here. return array( 'resources' => explode(",", get_config('format_tiles', 'modalresources')), 'modules' => explode(",", get_config('format_tiles', 'modalmodules')) ); } else { return array('resources' => [], 'modules' => []); } } /** * If we are not on a mobile device we may want to ensure that tiles are nicely fitted depending on our screen width. * E.g. avoid a row with one tile, centre the tiles on screen. JS will handle this post page load. * However we want to handle it pre-page load if we can to avoid tiles moving around once page is loaded. * So we have JS send the width via AJAX on first load, and we remember the value and apply it next time using inline CSS. * This function gets the data to enable us to add the inline CSS. * This will hide the main tiles window on page load and display a loading icon instead. * Then post page load, JS will get the screen width, re-arrange the tiles, then hide the loading icon and show the tiles. * If session width var has already been set (because JS already ran), we set that width initially. * Then we can load the page immediately at that width without hiding anything. * The skipcheck URL param is there in case anyone gets stuck at loading icon and clicks it - they escape it for session. * @param int $courseid the course ID we are in. * @see format_tiles_external::set_session_width() for where the session vars are set from JS. * @return array the data to add to our mustache templates. * @throws coding_exception * @throws dml_exception */ function format_tiles_width_template_data($courseid) { global $SESSION, $PAGE; $data = []; if (get_config('format_tiles', 'fittilestowidth')) { if (optional_param('skipcheck', 0, PARAM_INT) || isset($SESSION->format_tiles_skip_width_check)) { $SESSION->format_tiles_skip_width_check = 1; return array('hidetilesinitially' => 0); } else if ($PAGE->user_is_editing() || !get_config('format_tiles', 'usejavascriptnav') || get_user_preferences('format_tiles_stopjsnav', 0)) { // Here we may don't tiles initially or restrict screen width. return array('hidetilesinitially' => 0); } else { // If session screen width has been set, send it to template so we can include in inline CSS. $sessionvar = 'format_tiles_width_' . $courseid; $sessionvarvalue = isset($SESSION->$sessionvar) ? $SESSION->$sessionvar : 0; $data['defaultscreenwidthsession'] = $sessionvarvalue; // If no session screen width has yet been set, we hide the tiles initally so we can calculate correct width. $data['hidetilesinitially'] = $sessionvarvalue == 0 ? 1 : 0; } return $data; } else { // Feature is disabled by site admin. return array('hidetilesinitially' => 0); } }