From 796be12cab8452f1372973529eb1c4674f2fb995 Mon Sep 17 00:00:00 2001 From: Abineshsuseendran Date: Fri, 14 Jun 2024 17:33:07 +0530 Subject: [PATCH 01/14] Support for Moodle-4.4. --- amd/build/designer_section.min.js | 2 +- amd/build/designer_section.min.js.map | 2 +- amd/src/designer_section.js | 12 -- .../restore_format_designer_plugin.class.php | 6 +- classes/external/set_section_options.php | 3 +- classes/output/cm_completion.php | 14 +- classes/output/courseformat/content.php | 75 ++++++++-- .../courseformat/content/cm/controlmenu.php | 9 +- .../output/courseformat/content/section.php | 54 +++++++- .../courseformat/content/section/cmitem.php | 1 + .../courseformat/content/section/cmlist.php | 5 +- .../content/section/controlmenu.php | 130 +++++++++++------ .../courseformat/content/section/header.php | 7 +- classes/output/courseformat/state/cm.php | 37 +---- classes/output/courseformat/state/section.php | 94 +++++++++++++ classes/output/renderer.php | 21 ++- editsection_form.php | 40 +++--- format.php | 2 +- lang/en/format_designer.php | 4 +- lib.php | 131 +++++++++++++----- settings.php | 6 +- styles.css | 128 ++++++++++++++--- templates/courseformat/content.mustache | 18 +-- .../content/section/header.mustache | 4 +- templates/section.mustache | 1 + templates/section_layout.mustache | 4 +- tests/behat/behat_format_designer.php | 28 ++-- tests/behat/edit_delete_sections.feature | 36 +---- tests/lib_test.php | 40 ------ tests/options_test.php | 11 +- version.php | 5 +- 31 files changed, 618 insertions(+), 312 deletions(-) create mode 100644 classes/output/courseformat/state/section.php diff --git a/amd/build/designer_section.min.js b/amd/build/designer_section.min.js index b5e6ed5..16c330e 100644 --- a/amd/build/designer_section.min.js +++ b/amd/build/designer_section.min.js @@ -5,6 +5,6 @@ * @copyright 2021 bdecent gmbh * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define("format_designer/designer_section",["jquery","core/fragment","core/templates","core/loadingicon","core/ajax","core_course/actions","core_message/toggle_contact_button","theme_boost/popover","core/notification"],(function($,Fragment,Templates,Loadingicon,Ajax,Actions,Contact,Notification){var SELECTOR={ACTIVITYLI:"li.activity",SECTIONLI:"li.section",ACTIVITYACTION:"a.cm-edit-action",SECTIONACTIONMENU:".section_action_menu.designer-menu"};Y.use("moodle-course-coursebase",(function(){var courseformatselector=M.course.format.get_section_selector();courseformatselector&&(SELECTOR.SECTIONLI=courseformatselector)}));let DesignerSection=function(courseId,contextId,popupActivities,videoTime,issubpanel,sectionreturn){var self=this;self.courseId=courseId,self.contextId=contextId,self.popupActivities=popupActivities,self.videoTime=videoTime,self.isSubpanel=issubpanel,self.sectionReturn=sectionreturn,$(".course-info-block .carousel .carousel-item:nth-child(1)").addClass("active"),$(".course-info-block #courseStaffinfoControls.carousel").addClass("active"),$("body").delegate(self.SectionController,"click",self.sectionLayoutaction.bind(this)),$("body").delegate(self.SectionSubmenuSwitcher,"click",self.sectionLayoutaction.bind(this)),$("body").delegate(self.RestrictInfo,"click",self.moduleHandler.bind(this)),$("body").delegate(self.sectionRestricted,"click",this.sectionRestrictHandler.bind(this)),$("body").delegate(self.fullDescription,"click",self.fullmodcontentHandler.bind(this)),$("body").delegate(self.trimDescription,"click",self.trimmodcontentHandler.bind(this)),$("body").delegate(self.goToURL,"click",self.redirectToModule.bind(this)),$("body").delegate(self.goToSectionURL,"click",self.redirectToSection.bind(this)),window.onhashchange=function(){self.expandSection()},this.expandSection(),$(".course-type-flow").length>0&&$(".collapse").on("show.bs.collapse",(function(){$(this).parents("li.section").addClass("stack-header-collapsing");var sectionid=$(this).parents("li.section").attr("id"),distance=document.getElementById(sectionid).offsetTop-document.body.scrollTop;setTimeout((()=>window.scroll(0,distance)),50)})).on("shown.bs.collapse",(function(){$(this).parents("li.section").removeClass("stack-header-collapsing")}));var contactModal=document.getElementsByClassName("toggle-contact-button");Array.from(contactModal).forEach((function(element){element.addEventListener("click",(function(e){e.preventDefault(),null!=e.currentTarget.dataset.userid&&Contact.enhance(e.currentTarget)}))})),$('.progress .progress-bar[data-toggle="popover"]').popover()};return DesignerSection.prototype.goToURL='.designer [data-action="go-to-url"]',DesignerSection.prototype.goToSectionURL='.designer [data-action="go-to-section-url"]',DesignerSection.prototype.SectionController=".designer #section-designer-action .dropdown-menu a",DesignerSection.prototype.SectionSubmenuSwitcher=".designer .section_action_menu .dropdown-subpanel a[data-value=section-designer-action] + .dropdown-menu a",DesignerSection.prototype.RestrictInfo=".designer .designer-section-content .call-action-block",DesignerSection.prototype.moduleBlock=".designer .designer-section-content li.activity",DesignerSection.prototype.loadingElement=".icon-loader-block",DesignerSection.prototype.sectionRestricted=".designer .availability-section-block .section-restricted-action",DesignerSection.prototype.fullDescription=".designer-section-content li .fullcontent-summary .mod-description-action",DesignerSection.prototype.trimDescription=".designer-section-content li .trim-summary .mod-description-action",DesignerSection.prototype.modules=null,DesignerSection.prototype.redirectToModule=function(event){let nodeName=event.target.nodeName,iscircle=event.target.closest("li.activity").classList.contains("circle-layout"),isDescription=event.target.classList.contains("mod-description-action"),isPadlock=event.target.classList.contains("fa-lock"),ispopupModule=event.target.closest("li.activity").classList.contains("popmodule"),isModHasURL=event.target.closest('li.activity div[data-action="go-to-url"]').getAttribute("data-url"),isCompletionButton=event.target.closest('button[data-action="toggle-manual-completion"]');if(nodeName in["a","button","form"]||document.body.classList.contains("editing")||iscircle||isDescription||isPadlock||ispopupModule||""==isModHasURL||isCompletionButton){if(ispopupModule&&!document.body.classList.contains("editing"))if(null===event.target.closest("button[data-action='toggle-manual-completion']")&&null===event.target.closest(".mod-description-action"))event.target.closest("li.activity").querySelector("a[href]").click();return null}let modurl=event.target.closest("[data-action=go-to-url]").getAttribute("data-url");return window.location.href=modurl,!0},DesignerSection.prototype.redirectToSection=function(event){let isPadlock=event.target.classList.contains("fa-lock");if(document.body.classList.contains("editing")||isPadlock)return null;var singlesection=event.target.closest("[data-action=go-to-section-url]");let sectionurl=singlesection.getAttribute("data-url"),sectiontarget="_self",target=singlesection.getAttribute("data-target");return target&&(sectiontarget=target),window.open(sectionurl,sectiontarget),!0},DesignerSection.prototype.expandSection=()=>{var sectionID=window.location.hash;if(sectionID){var id=sectionID.substring(1),section=document.getElementById(id);if(section){var title=section.querySelector(".section-header-content");title&&(title.classList.remove("collapsed"),title.setAttribute("aria-expanded",!0));var content=section.querySelector(".content");content&&content.classList.add("show"),null!==document.getElementById("section-course-accordion")&&(document.getElementById("section-head-0").classList.add("collapsed"),document.getElementById("section-content-0").classList.remove("show")),section.scrollIntoView()}}},DesignerSection.prototype.fullmodcontentHandler=function(event){var THIS=$(event.currentTarget);let fullContent=$(THIS).closest("li.activity").find(".fullcontent-summary"),trimcontent=$(THIS).closest("li.activity").find(".trim-summary");trimcontent.hasClass("summary-hide")&&(trimcontent.removeClass("summary-hide"),fullContent.addClass("summary-hide"))},DesignerSection.prototype.trimmodcontentHandler=function(event){var THIS=$(event.currentTarget);let fullContent=$(THIS).closest("li.activity").find(".fullcontent-summary"),trimcontent=$(THIS).closest("li.activity").find(".trim-summary");fullContent.hasClass("summary-hide")&&(fullContent.removeClass("summary-hide"),trimcontent.addClass("summary-hide"))},DesignerSection.prototype.sectionRestrictHandler=function(event){var sectionRestrictInfo=$(event.currentTarget).prev();sectionRestrictInfo&&(sectionRestrictInfo.hasClass("show")?sectionRestrictInfo.removeClass("show"):sectionRestrictInfo.addClass("show"))},DesignerSection.prototype.moduleHandler=function(event){event.preventDefault();var restrictBlock=$(event.currentTarget).parents(".restrict-block");restrictBlock.length&&(restrictBlock.hasClass("show")?restrictBlock.removeClass("show"):restrictBlock.addClass("show"))},DesignerSection.prototype.updateVideoTimeInstance=function(sectionId){var sectionVideotimes="body "+("#"+sectionId)+" .activity.videotime";0!=$(sectionVideotimes).length&&$(sectionVideotimes).each(function(index,module){this.CreateInstance(module)}.bind(this))},DesignerSection.prototype.CreateInstance=function(module){if($(module).find(".instancename").length&&($(module).find(".vimeo-embed").length||$(module).find(".video-js").length)){var args={cmid:module.getAttribute("data-id")};Ajax.call([{methodname:"format_designer_get_videotime_instace",args:args}],!0)[0].then((function(data){var template=JSON.parse(data);if("videojs"==template.playertype)var uniqueid=$(module).find(".video-js").first().attr("id").replace("vimeo-embed-","");else uniqueid=$(module).find(".vimeo-embed").first().attr("id").replace("vimeo-embed-","");template.uniqueid=uniqueid,Templates.render(template.templatename,template).then((function(html,js){return Templates.runTemplateJS(js),!0})).fail(Notification.exception)}))}},DesignerSection.prototype.sectionLayoutaction=function(event){event.preventDefault();var self=this;let sectionId=event.target.closest("li.section").getAttribute("id");var sectionid=event.target.closest("li.section").getAttribute("data-id"),sectionitem=document.getElementById(sectionId),iconBlock="#"+sectionId+" "+self.loadingElement,layout=$(event.currentTarget).data("value"),layouttext=$(event.currentTarget).text();$(event.target).parents(".dropdown").find(".btn").html(layouttext),$(event.target).parents(".dropdown").find(".btn").val(layout),$(event.target).parent().find("a.dropdown-item").each((function(){$(this).removeClass("active")})),$(event.target).addClass("active");let dataid=event.target.closest("li.section").getAttribute("data-id");var args={courseid:self.courseId,sectionid:dataid,options:[{name:$(event.currentTarget).data("option"),value:layout}]},promises=Ajax.call([{methodname:"format_designer_set_section_options",args:args}],!0);$.when.apply($,promises).done((function(){if(self.isSubpanel){Fragment.loadFragment("core_courseformat","section",self.contextId,{id:sectionid,courseid:self.courseId,sr:self.sectionReturn}).then(((html,js)=>{Templates.replaceNode(sectionitem,html,js)})).catch()}else{Actions.refreshSection("#"+sectionId,dataid,0).then((()=>"")).catch()}})),Loadingicon.addIconToContainerRemoveOnCompletion(iconBlock,promises),setTimeout((function(){self.videoTime&&self.updateVideoTimeInstance(sectionId)}),2e3)},{init:function(courseId,contextId,popupActivities,videoTime,issubpanel,sectionreturn){return new DesignerSection(courseId,contextId,popupActivities,videoTime,issubpanel,sectionreturn)}}})); +define("format_designer/designer_section",["jquery","core/fragment","core/templates","core/loadingicon","core/ajax","core_course/actions","core_message/toggle_contact_button","theme_boost/popover","core/notification"],(function($,Fragment,Templates,Loadingicon,Ajax,Actions,Contact,Notification){var SELECTOR={ACTIVITYLI:"li.activity",SECTIONLI:"li.section",ACTIVITYACTION:"a.cm-edit-action",SECTIONACTIONMENU:".section_action_menu.designer-menu"};Y.use("moodle-course-coursebase",(function(){var courseformatselector=M.course.format.get_section_selector();courseformatselector&&(SELECTOR.SECTIONLI=courseformatselector)}));let DesignerSection=function(courseId,contextId,popupActivities,videoTime,issubpanel,sectionreturn){var self=this;self.courseId=courseId,self.contextId=contextId,self.popupActivities=popupActivities,self.videoTime=videoTime,self.isSubpanel=issubpanel,self.sectionReturn=sectionreturn,$(".course-info-block .carousel .carousel-item:nth-child(1)").addClass("active"),$(".course-info-block #courseStaffinfoControls.carousel").addClass("active"),$("body").delegate(self.SectionController,"click",self.sectionLayoutaction.bind(this)),$("body").delegate(self.SectionSubmenuSwitcher,"click",self.sectionLayoutaction.bind(this)),$("body").delegate(self.RestrictInfo,"click",self.moduleHandler.bind(this)),$("body").delegate(self.sectionRestricted,"click",this.sectionRestrictHandler.bind(this)),$("body").delegate(self.fullDescription,"click",self.fullmodcontentHandler.bind(this)),$("body").delegate(self.trimDescription,"click",self.trimmodcontentHandler.bind(this)),$("body").delegate(self.goToURL,"click",self.redirectToModule.bind(this)),$("body").delegate(self.goToSectionURL,"click",self.redirectToSection.bind(this)),window.onhashchange=function(){self.expandSection()},this.expandSection();var contactModal=document.getElementsByClassName("toggle-contact-button");Array.from(contactModal).forEach((function(element){element.addEventListener("click",(function(e){e.preventDefault(),null!=e.currentTarget.dataset.userid&&Contact.enhance(e.currentTarget)}))})),$('.progress .progress-bar[data-toggle="popover"]').popover()};return DesignerSection.prototype.goToURL='.designer [data-action="go-to-url"]',DesignerSection.prototype.goToSectionURL='.designer [data-action="go-to-section-url"]',DesignerSection.prototype.SectionController=".designer #section-designer-action .dropdown-menu a",DesignerSection.prototype.SectionSubmenuSwitcher=".designer .section_action_menu .dropdown-subpanel a[data-value=section-designer-action] + .dropdown-menu a",DesignerSection.prototype.RestrictInfo=".designer .designer-section-content .call-action-block",DesignerSection.prototype.moduleBlock=".designer .designer-section-content li.activity",DesignerSection.prototype.loadingElement=".icon-loader-block",DesignerSection.prototype.sectionRestricted=".designer .availability-section-block .section-restricted-action",DesignerSection.prototype.fullDescription=".designer-section-content li .fullcontent-summary .mod-description-action",DesignerSection.prototype.trimDescription=".designer-section-content li .trim-summary .mod-description-action",DesignerSection.prototype.modules=null,DesignerSection.prototype.redirectToModule=function(event){let nodeName=event.target.nodeName,iscircle=event.target.closest("li.activity").classList.contains("circle-layout"),isDescription=event.target.classList.contains("mod-description-action"),isPadlock=event.target.classList.contains("fa-lock"),ispopupModule=event.target.closest("li.activity").classList.contains("popmodule"),isModHasURL=event.target.closest('li.activity div[data-action="go-to-url"]').getAttribute("data-url"),isCompletionButton=event.target.closest('button[data-action="toggle-manual-completion"]');if(nodeName in["a","button","form"]||document.body.classList.contains("editing")||iscircle||isDescription||isPadlock||ispopupModule||""==isModHasURL||isCompletionButton){if(ispopupModule&&!document.body.classList.contains("editing"))if(null===event.target.closest("button[data-action='toggle-manual-completion']")&&null===event.target.closest(".mod-description-action"))event.target.closest("li.activity").querySelector("a[href]").click();return null}let modurl=event.target.closest("[data-action=go-to-url]").getAttribute("data-url");return window.location.href=modurl,!0},DesignerSection.prototype.redirectToSection=function(event){let isPadlock=event.target.classList.contains("fa-lock");if(document.body.classList.contains("editing")||isPadlock)return null;var singlesection=event.target.closest("[data-action=go-to-section-url]");let sectionurl=singlesection.getAttribute("data-url"),sectiontarget="_self",target=singlesection.getAttribute("data-target");return target&&(sectiontarget=target),window.open(sectionurl,sectiontarget),!0},DesignerSection.prototype.expandSection=()=>{var sectionID=window.location.hash;if(sectionID){var id=sectionID.substring(1),section=document.getElementById(id);if(section){var title=section.querySelector(".section-header-content");title&&(title.classList.remove("collapsed"),title.setAttribute("aria-expanded",!0));var content=section.querySelector(".content");content&&content.classList.add("show"),null!==document.getElementById("section-course-accordion")&&(document.getElementById("section-head-0").classList.add("collapsed"),document.getElementById("section-content-0").classList.remove("show")),section.scrollIntoView()}}},DesignerSection.prototype.fullmodcontentHandler=function(event){var THIS=$(event.currentTarget);let fullContent=$(THIS).closest("li.activity").find(".fullcontent-summary"),trimcontent=$(THIS).closest("li.activity").find(".trim-summary");trimcontent.hasClass("summary-hide")&&(trimcontent.removeClass("summary-hide"),fullContent.addClass("summary-hide"))},DesignerSection.prototype.trimmodcontentHandler=function(event){var THIS=$(event.currentTarget);let fullContent=$(THIS).closest("li.activity").find(".fullcontent-summary"),trimcontent=$(THIS).closest("li.activity").find(".trim-summary");fullContent.hasClass("summary-hide")&&(fullContent.removeClass("summary-hide"),trimcontent.addClass("summary-hide"))},DesignerSection.prototype.sectionRestrictHandler=function(event){var sectionRestrictInfo=$(event.currentTarget).prev();sectionRestrictInfo&&(sectionRestrictInfo.hasClass("show")?sectionRestrictInfo.removeClass("show"):sectionRestrictInfo.addClass("show"))},DesignerSection.prototype.moduleHandler=function(event){event.preventDefault();var restrictBlock=$(event.currentTarget).parents(".restrict-block");restrictBlock.length&&(restrictBlock.hasClass("show")?restrictBlock.removeClass("show"):restrictBlock.addClass("show"))},DesignerSection.prototype.updateVideoTimeInstance=function(sectionId){var sectionVideotimes="body "+("#"+sectionId)+" .activity.videotime";0!=$(sectionVideotimes).length&&$(sectionVideotimes).each(function(index,module){this.CreateInstance(module)}.bind(this))},DesignerSection.prototype.CreateInstance=function(module){if($(module).find(".instancename").length&&($(module).find(".vimeo-embed").length||$(module).find(".video-js").length)){var args={cmid:module.getAttribute("data-id")};Ajax.call([{methodname:"format_designer_get_videotime_instace",args:args}],!0)[0].then((function(data){var template=JSON.parse(data);if("videojs"==template.playertype)var uniqueid=$(module).find(".video-js").first().attr("id").replace("vimeo-embed-","");else uniqueid=$(module).find(".vimeo-embed").first().attr("id").replace("vimeo-embed-","");template.uniqueid=uniqueid,Templates.render(template.templatename,template).then((function(html,js){return Templates.runTemplateJS(js),!0})).fail(Notification.exception)}))}},DesignerSection.prototype.sectionLayoutaction=function(event){event.preventDefault();var self=this;let sectionId=event.target.closest("li.section").getAttribute("id");var sectionid=event.target.closest("li.section").getAttribute("data-id"),sectionitem=document.getElementById(sectionId),iconBlock="#"+sectionId+" "+self.loadingElement,layout=$(event.currentTarget).data("value"),layouttext=$(event.currentTarget).text();$(event.target).parents(".dropdown").find(".btn").html(layouttext),$(event.target).parents(".dropdown").find(".btn").val(layout),$(event.target).parent().find("a.dropdown-item").each((function(){$(this).removeClass("active")})),$(event.target).addClass("active");let dataid=event.target.closest("li.section").getAttribute("data-id");var args={courseid:self.courseId,sectionid:dataid,options:[{name:$(event.currentTarget).data("option"),value:layout}]},promises=Ajax.call([{methodname:"format_designer_set_section_options",args:args}],!0);$.when.apply($,promises).done((function(){if(self.isSubpanel){Fragment.loadFragment("core_courseformat","section",self.contextId,{id:sectionid,courseid:self.courseId,sr:self.sectionReturn}).then(((html,js)=>{Templates.replaceNode(sectionitem,html,js)})).catch()}else{Actions.refreshSection("#"+sectionId,dataid,0).then((()=>"")).catch()}})),Loadingicon.addIconToContainerRemoveOnCompletion(iconBlock,promises),setTimeout((function(){self.videoTime&&self.updateVideoTimeInstance(sectionId)}),2e3)},{init:function(courseId,contextId,popupActivities,videoTime,issubpanel,sectionreturn){return new DesignerSection(courseId,contextId,popupActivities,videoTime,issubpanel,sectionreturn)}}})); //# sourceMappingURL=designer_section.min.js.map \ No newline at end of file diff --git a/amd/build/designer_section.min.js.map b/amd/build/designer_section.min.js.map index 423fe8a..c510728 100644 --- a/amd/build/designer_section.min.js.map +++ b/amd/build/designer_section.min.js.map @@ -1 +1 @@ -{"version":3,"file":"designer_section.min.js","sources":["../src/designer_section.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n\n/**\n * Implemented designer format js.\n *\n * @module format_designer/designer_section\n * @copyright 2021 bdecent gmbh \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n define(['jquery', 'core/fragment', 'core/templates', 'core/loadingicon', 'core/ajax',\n 'core_course/actions', 'core_message/toggle_contact_button', 'theme_boost/popover', 'core/notification',],\n function($, Fragment, Templates, Loadingicon, Ajax, Actions, Contact, Notification) {\n\n var SELECTOR = {\n ACTIVITYLI: 'li.activity',\n SECTIONLI: 'li.section',\n ACTIVITYACTION: 'a.cm-edit-action',\n SECTIONACTIONMENU: '.section_action_menu.designer-menu',\n };\n\n Y.use('moodle-course-coursebase', function() {\n var courseformatselector = M.course.format.get_section_selector();\n if (courseformatselector) {\n SELECTOR.SECTIONLI = courseformatselector;\n }\n });\n\n\n /**\n * Control designer format action\n * @param {int} courseId\n * @param {int} contextId\n * @param {array} popupActivities\n * @param {bool} videoTime\n * @param {bool} issubpanel\n * @param {int} sectionreturn\n */\n let DesignerSection = function(courseId, contextId, popupActivities, videoTime, issubpanel, sectionreturn) {\n var self = this;\n self.courseId = courseId;\n self.contextId = contextId;\n self.popupActivities = popupActivities;\n self.videoTime = videoTime;\n self.isSubpanel = issubpanel;\n self.sectionReturn = sectionreturn;\n\n $(\".course-info-block .carousel .carousel-item:nth-child(1)\").addClass('active');\n $(\".course-info-block #courseStaffinfoControls.carousel\").addClass('active');\n\n $('body').delegate(self.SectionController, 'click', self.sectionLayoutaction.bind(this));\n $('body').delegate(self.SectionSubmenuSwitcher, 'click', self.sectionLayoutaction.bind(this));\n\n $(\"body\").delegate(self.RestrictInfo, \"click\", self.moduleHandler.bind(this));\n $(\"body\").delegate(self.sectionRestricted, \"click\", this.sectionRestrictHandler.bind(this));\n $('body').delegate(self.fullDescription, \"click\", self.fullmodcontentHandler.bind(this));\n $('body').delegate(self.trimDescription, \"click\", self.trimmodcontentHandler.bind(this));\n $('body').delegate(self.goToURL, \"click\", self.redirectToModule.bind(this));\n $('body').delegate(self.goToSectionURL, \"click\", self.redirectToSection.bind(this));\n window.onhashchange = function() {\n self.expandSection();\n };\n this.expandSection();\n\n if ($('.course-type-flow').length > 0) {\n $('.collapse').on('show.bs.collapse', function() {\n $(this).parents('li.section').addClass('stack-header-collapsing');\n var sectionid = $(this).parents('li.section').attr('id');\n var section = document.getElementById(sectionid);\n var distance = section.offsetTop - document.body.scrollTop;\n setTimeout(() => window.scroll(0, distance), 50);\n }).on('shown.bs.collapse', function() {\n $(this).parents('li.section').removeClass('stack-header-collapsing');\n });\n }\n\n var contactModal = document.getElementsByClassName('toggle-contact-button');\n Array.from(contactModal).forEach(function(element) {\n element.addEventListener('click', function(e) {\n e.preventDefault();\n if (e.currentTarget.dataset.userid != undefined) {\n Contact.enhance(e.currentTarget);\n }\n });\n });\n\n $('.progress .progress-bar[data-toggle=\"popover\"]').popover();\n\n };\n\n /**\n * Selector section controller.\n */\n DesignerSection.prototype.goToURL = '.designer [data-action=\"go-to-url\"]';\n\n DesignerSection.prototype.goToSectionURL = '.designer [data-action=\"go-to-section-url\"]';\n\n DesignerSection.prototype.SectionController = \".designer #section-designer-action .dropdown-menu a\";\n\n DesignerSection.prototype.SectionSubmenuSwitcher\n = \".designer .section_action_menu .dropdown-subpanel a[data-value=section-designer-action] + .dropdown-menu a\";\n\n DesignerSection.prototype.RestrictInfo = \".designer .designer-section-content .call-action-block\";\n\n DesignerSection.prototype.moduleBlock = \".designer .designer-section-content li.activity\";\n\n DesignerSection.prototype.loadingElement = \".icon-loader-block\";\n\n DesignerSection.prototype.sectionRestricted = \".designer .availability-section-block .section-restricted-action\";\n\n DesignerSection.prototype.fullDescription = \".designer-section-content li .fullcontent-summary .mod-description-action\";\n\n DesignerSection.prototype.trimDescription = \".designer-section-content li .trim-summary .mod-description-action\";\n\n DesignerSection.prototype.modules = null;\n\n DesignerSection.prototype.redirectToModule = function(event) {\n let nodeName = event.target.nodeName;\n let preventionNodes = ['a', 'button', 'form'];\n let iscircle = event.target.closest('li.activity').classList.contains('circle-layout');\n let isDescription = event.target.classList.contains('mod-description-action');\n let isPadlock = event.target.classList.contains('fa-lock');\n let ispopupModule = event.target.closest('li.activity').classList.contains('popmodule');\n let isModHasURL = event.target.closest('li.activity div[data-action=\"go-to-url\"]').getAttribute('data-url');\n let isCompletionButton = event.target.closest('button[data-action=\"toggle-manual-completion\"]');\n if ((nodeName in preventionNodes)\n || document.body.classList.contains('editing') || iscircle || isDescription || isPadlock || ispopupModule\n || isModHasURL == '' || isCompletionButton) {\n if (ispopupModule && !document.body.classList.contains('editing')) {\n if (event.target.closest(\"button[data-action='toggle-manual-completion']\") === null &&\n event.target.closest(\".mod-description-action\") === null) {\n var li = event.target.closest('li.activity');\n li.querySelector('a[href]').click();\n }\n }\n return null;\n }\n var card = event.target.closest(\"[data-action=go-to-url]\");\n let modurl = card.getAttribute('data-url');\n window.location.href = modurl;\n return true;\n };\n\n DesignerSection.prototype.redirectToSection = function(event) {\n let isPadlock = event.target.classList.contains('fa-lock');\n if (document.body.classList.contains('editing') || isPadlock) {\n return null;\n }\n var singlesection = event.target.closest(\"[data-action=go-to-section-url]\");\n let sectionurl = singlesection.getAttribute('data-url');\n let sectiontarget = \"_self\";\n let target = singlesection.getAttribute('data-target');\n if (target) {\n sectiontarget = target;\n }\n window.open(sectionurl, sectiontarget);\n return true;\n };\n\n DesignerSection.prototype.expandSection = () => {\n var sectionID = window.location.hash;\n if (sectionID) {\n var id = sectionID.substring(1);\n var section = document.getElementById(id);\n if (section) {\n var title = section.querySelector('.section-header-content');\n if (title) {\n title.classList.remove('collapsed');\n title.setAttribute('aria-expanded', true);\n }\n var content = section.querySelector('.content');\n if (content) {\n content.classList.add('show');\n }\n if (document.getElementById('section-course-accordion') !== null) {\n document.getElementById('section-head-0').classList.add('collapsed');\n document.getElementById('section-content-0').classList.remove('show');\n }\n section.scrollIntoView();\n }\n }\n };\n\n DesignerSection.prototype.fullmodcontentHandler = function(event) {\n var THIS = $(event.currentTarget);\n let fullContent = $(THIS).closest('li.activity').find('.fullcontent-summary');\n let trimcontent = $(THIS).closest('li.activity').find('.trim-summary');\n if (trimcontent.hasClass('summary-hide')) {\n trimcontent.removeClass('summary-hide');\n fullContent.addClass('summary-hide');\n }\n };\n\n DesignerSection.prototype.trimmodcontentHandler = function(event) {\n var THIS = $(event.currentTarget);\n let fullContent = $(THIS).closest('li.activity').find('.fullcontent-summary');\n let trimcontent = $(THIS).closest('li.activity').find('.trim-summary');\n if (fullContent.hasClass('summary-hide')) {\n fullContent.removeClass('summary-hide');\n trimcontent.addClass('summary-hide');\n }\n };\n\n DesignerSection.prototype.sectionRestrictHandler = function(event) {\n var sectionRestrictInfo = $(event.currentTarget).prev();\n if (sectionRestrictInfo) {\n if (!sectionRestrictInfo.hasClass('show')) {\n sectionRestrictInfo.addClass('show');\n } else {\n sectionRestrictInfo.removeClass('show');\n }\n }\n };\n\n DesignerSection.prototype.moduleHandler = function(event) {\n event.preventDefault();\n var restrictBlock = $(event.currentTarget).parents('.restrict-block');\n if (restrictBlock.length) {\n if (!restrictBlock.hasClass('show')) {\n restrictBlock.addClass('show');\n } else {\n restrictBlock.removeClass('show');\n }\n }\n };\n\n DesignerSection.prototype.updateVideoTimeInstance = function(sectionId) {\n var section = \"#\" + sectionId;\n var sectionVideotimes = \"body \"+ section + \" .activity.videotime\";\n if ($(sectionVideotimes).length == 0) {\n return;\n }\n $(sectionVideotimes).each(function(index, module) {\n this.CreateInstance(module);\n }.bind(this));\n };\n\n DesignerSection.prototype.CreateInstance = function (module) {\n if (\n $(module).find('.instancename').length\n && ($(module).find('.vimeo-embed').length\n || $(module).find('.video-js').length)\n ) {\n var cmId = module.getAttribute(\"data-id\");\n var args = {cmid : cmId};\n // Get module instance.\n var promises = Ajax.call([{\n methodname: 'format_designer_get_videotime_instace',\n args: args\n }], true);\n promises[0].then(function(data) {\n var template = JSON.parse(data);\n if (template.playertype == 'videojs') {\n var uniqueid = $(module).find('.video-js').first().attr('id').replace('vimeo-embed-', '');\n } else {\n var uniqueid = $(module).find('.vimeo-embed').first().attr('id').replace('vimeo-embed-', '');\n }\n template.uniqueid = uniqueid;\n Templates.render(template.templatename, template).then(function(html, js) {\n Templates.runTemplateJS(js);\n return true;\n }).fail(Notification.exception);\n });\n }\n };\n\n /**\n * Implementaion swith the section layout.\n * @param {object} event\n */\n DesignerSection.prototype.sectionLayoutaction = function(event) {\n event.preventDefault();\n var self = this;\n let sectionId = event.target.closest('li.section').getAttribute('id');\n var sectionid = event.target.closest('li.section').getAttribute('data-id');\n var sectionitem = document.getElementById(sectionId);\n var iconBlock = \"#\" + sectionId + \" \" + self.loadingElement;\n var layout = $(event.currentTarget).data('value');\n var layouttext = $(event.currentTarget).text();\n $(event.target).parents(\".dropdown\").find(\".btn\").html(layouttext);\n $(event.target).parents(\".dropdown\").find(\".btn\").val(layout);\n $(event.target).parent().find(\"a.dropdown-item\").each(function() {\n $(this).removeClass('active');\n });\n $(event.target).addClass('active');\n let dataid = event.target.closest('li.section').getAttribute('data-id');\n var args = {\n courseid: self.courseId,\n sectionid: dataid,\n options: [{name: $(event.currentTarget).data('option'), value: layout}]\n };\n var promises = Ajax.call([{\n methodname: 'format_designer_set_section_options',\n args: args\n }], true);\n $.when.apply($, promises)\n .done(function() {\n if (self.isSubpanel) {\n const promise = Fragment.loadFragment(\n 'core_courseformat',\n 'section',\n self.contextId,\n {\n id: sectionid,\n courseid: self.courseId,\n sr: self.sectionReturn,\n }\n );\n promise.then((html, js) => {\n Templates.replaceNode(sectionitem, html, js);\n }).catch();\n } else {\n const sectionpromise = Actions.refreshSection('#' + sectionId, dataid, 0);\n sectionpromise.then(() => {\n return '';\n }).catch();\n }\n });\n Loadingicon.addIconToContainerRemoveOnCompletion(iconBlock, promises);\n // If videotime exist update the module.\n setTimeout(function() {\n if (self.videoTime) {\n self.updateVideoTimeInstance(sectionId);\n }\n }, 2000);\n };\n\n return {\n init: function(courseId, contextId, popupActivities, videoTime, issubpanel, sectionreturn) {\n return new DesignerSection(courseId, contextId, popupActivities, videoTime, issubpanel, sectionreturn);\n }\n };\n});\n"],"names":["define","$","Fragment","Templates","Loadingicon","Ajax","Actions","Contact","Notification","SELECTOR","ACTIVITYLI","SECTIONLI","ACTIVITYACTION","SECTIONACTIONMENU","Y","use","courseformatselector","M","course","format","get_section_selector","DesignerSection","courseId","contextId","popupActivities","videoTime","issubpanel","sectionreturn","self","this","isSubpanel","sectionReturn","addClass","delegate","SectionController","sectionLayoutaction","bind","SectionSubmenuSwitcher","RestrictInfo","moduleHandler","sectionRestricted","sectionRestrictHandler","fullDescription","fullmodcontentHandler","trimDescription","trimmodcontentHandler","goToURL","redirectToModule","goToSectionURL","redirectToSection","window","onhashchange","expandSection","length","on","parents","sectionid","attr","distance","document","getElementById","offsetTop","body","scrollTop","setTimeout","scroll","removeClass","contactModal","getElementsByClassName","Array","from","forEach","element","addEventListener","e","preventDefault","undefined","currentTarget","dataset","userid","enhance","popover","prototype","moduleBlock","loadingElement","modules","event","nodeName","target","iscircle","closest","classList","contains","isDescription","isPadlock","ispopupModule","isModHasURL","getAttribute","isCompletionButton","querySelector","click","modurl","location","href","singlesection","sectionurl","sectiontarget","open","sectionID","hash","id","substring","section","title","remove","setAttribute","content","add","scrollIntoView","THIS","fullContent","find","trimcontent","hasClass","sectionRestrictInfo","prev","restrictBlock","updateVideoTimeInstance","sectionId","sectionVideotimes","each","index","module","CreateInstance","args","cmid","call","methodname","then","data","template","JSON","parse","playertype","uniqueid","first","replace","render","templatename","html","js","runTemplateJS","fail","exception","sectionitem","iconBlock","layout","layouttext","text","val","parent","dataid","courseid","options","name","value","promises","when","apply","done","loadFragment","sr","replaceNode","catch","refreshSection","addIconToContainerRemoveOnCompletion","init"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"designer_section.min.js","sources":["../src/designer_section.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n\n/**\n * Implemented designer format js.\n *\n * @module format_designer/designer_section\n * @copyright 2021 bdecent gmbh \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n define(['jquery', 'core/fragment', 'core/templates', 'core/loadingicon', 'core/ajax',\n 'core_course/actions', 'core_message/toggle_contact_button', 'theme_boost/popover', 'core/notification',],\n function($, Fragment, Templates, Loadingicon, Ajax, Actions, Contact, Notification) {\n\n var SELECTOR = {\n ACTIVITYLI: 'li.activity',\n SECTIONLI: 'li.section',\n ACTIVITYACTION: 'a.cm-edit-action',\n SECTIONACTIONMENU: '.section_action_menu.designer-menu',\n };\n\n Y.use('moodle-course-coursebase', function() {\n var courseformatselector = M.course.format.get_section_selector();\n if (courseformatselector) {\n SELECTOR.SECTIONLI = courseformatselector;\n }\n });\n\n\n /**\n * Control designer format action\n * @param {int} courseId\n * @param {int} contextId\n * @param {array} popupActivities\n * @param {bool} videoTime\n * @param {bool} issubpanel\n * @param {int} sectionreturn\n */\n let DesignerSection = function(courseId, contextId, popupActivities, videoTime, issubpanel, sectionreturn) {\n var self = this;\n self.courseId = courseId;\n self.contextId = contextId;\n self.popupActivities = popupActivities;\n self.videoTime = videoTime;\n self.isSubpanel = issubpanel;\n self.sectionReturn = sectionreturn;\n\n $(\".course-info-block .carousel .carousel-item:nth-child(1)\").addClass('active');\n $(\".course-info-block #courseStaffinfoControls.carousel\").addClass('active');\n\n $('body').delegate(self.SectionController, 'click', self.sectionLayoutaction.bind(this));\n $('body').delegate(self.SectionSubmenuSwitcher, 'click', self.sectionLayoutaction.bind(this));\n\n $(\"body\").delegate(self.RestrictInfo, \"click\", self.moduleHandler.bind(this));\n $(\"body\").delegate(self.sectionRestricted, \"click\", this.sectionRestrictHandler.bind(this));\n $('body').delegate(self.fullDescription, \"click\", self.fullmodcontentHandler.bind(this));\n $('body').delegate(self.trimDescription, \"click\", self.trimmodcontentHandler.bind(this));\n $('body').delegate(self.goToURL, \"click\", self.redirectToModule.bind(this));\n $('body').delegate(self.goToSectionURL, \"click\", self.redirectToSection.bind(this));\n window.onhashchange = function() {\n self.expandSection();\n };\n this.expandSection();\n\n var contactModal = document.getElementsByClassName('toggle-contact-button');\n Array.from(contactModal).forEach(function(element) {\n element.addEventListener('click', function(e) {\n e.preventDefault();\n if (e.currentTarget.dataset.userid != undefined) {\n Contact.enhance(e.currentTarget);\n }\n });\n });\n\n $('.progress .progress-bar[data-toggle=\"popover\"]').popover();\n\n };\n\n /**\n * Selector section controller.\n */\n DesignerSection.prototype.goToURL = '.designer [data-action=\"go-to-url\"]';\n\n DesignerSection.prototype.goToSectionURL = '.designer [data-action=\"go-to-section-url\"]';\n\n DesignerSection.prototype.SectionController = \".designer #section-designer-action .dropdown-menu a\";\n\n DesignerSection.prototype.SectionSubmenuSwitcher\n = \".designer .section_action_menu .dropdown-subpanel a[data-value=section-designer-action] + .dropdown-menu a\";\n\n DesignerSection.prototype.RestrictInfo = \".designer .designer-section-content .call-action-block\";\n\n DesignerSection.prototype.moduleBlock = \".designer .designer-section-content li.activity\";\n\n DesignerSection.prototype.loadingElement = \".icon-loader-block\";\n\n DesignerSection.prototype.sectionRestricted = \".designer .availability-section-block .section-restricted-action\";\n\n DesignerSection.prototype.fullDescription = \".designer-section-content li .fullcontent-summary .mod-description-action\";\n\n DesignerSection.prototype.trimDescription = \".designer-section-content li .trim-summary .mod-description-action\";\n\n DesignerSection.prototype.modules = null;\n\n DesignerSection.prototype.redirectToModule = function(event) {\n let nodeName = event.target.nodeName;\n let preventionNodes = ['a', 'button', 'form'];\n let iscircle = event.target.closest('li.activity').classList.contains('circle-layout');\n let isDescription = event.target.classList.contains('mod-description-action');\n let isPadlock = event.target.classList.contains('fa-lock');\n let ispopupModule = event.target.closest('li.activity').classList.contains('popmodule');\n let isModHasURL = event.target.closest('li.activity div[data-action=\"go-to-url\"]').getAttribute('data-url');\n let isCompletionButton = event.target.closest('button[data-action=\"toggle-manual-completion\"]');\n if ((nodeName in preventionNodes)\n || document.body.classList.contains('editing') || iscircle || isDescription || isPadlock || ispopupModule\n || isModHasURL == '' || isCompletionButton) {\n if (ispopupModule && !document.body.classList.contains('editing')) {\n if (event.target.closest(\"button[data-action='toggle-manual-completion']\") === null &&\n event.target.closest(\".mod-description-action\") === null) {\n var li = event.target.closest('li.activity');\n li.querySelector('a[href]').click();\n }\n }\n return null;\n }\n var card = event.target.closest(\"[data-action=go-to-url]\");\n let modurl = card.getAttribute('data-url');\n window.location.href = modurl;\n return true;\n };\n\n DesignerSection.prototype.redirectToSection = function(event) {\n let isPadlock = event.target.classList.contains('fa-lock');\n if (document.body.classList.contains('editing') || isPadlock) {\n return null;\n }\n var singlesection = event.target.closest(\"[data-action=go-to-section-url]\");\n let sectionurl = singlesection.getAttribute('data-url');\n let sectiontarget = \"_self\";\n let target = singlesection.getAttribute('data-target');\n if (target) {\n sectiontarget = target;\n }\n window.open(sectionurl, sectiontarget);\n return true;\n };\n\n DesignerSection.prototype.expandSection = () => {\n var sectionID = window.location.hash;\n if (sectionID) {\n var id = sectionID.substring(1);\n var section = document.getElementById(id);\n if (section) {\n var title = section.querySelector('.section-header-content');\n if (title) {\n title.classList.remove('collapsed');\n title.setAttribute('aria-expanded', true);\n }\n var content = section.querySelector('.content');\n if (content) {\n content.classList.add('show');\n }\n if (document.getElementById('section-course-accordion') !== null) {\n document.getElementById('section-head-0').classList.add('collapsed');\n document.getElementById('section-content-0').classList.remove('show');\n }\n section.scrollIntoView();\n }\n }\n };\n\n DesignerSection.prototype.fullmodcontentHandler = function(event) {\n var THIS = $(event.currentTarget);\n let fullContent = $(THIS).closest('li.activity').find('.fullcontent-summary');\n let trimcontent = $(THIS).closest('li.activity').find('.trim-summary');\n if (trimcontent.hasClass('summary-hide')) {\n trimcontent.removeClass('summary-hide');\n fullContent.addClass('summary-hide');\n }\n };\n\n DesignerSection.prototype.trimmodcontentHandler = function(event) {\n var THIS = $(event.currentTarget);\n let fullContent = $(THIS).closest('li.activity').find('.fullcontent-summary');\n let trimcontent = $(THIS).closest('li.activity').find('.trim-summary');\n if (fullContent.hasClass('summary-hide')) {\n fullContent.removeClass('summary-hide');\n trimcontent.addClass('summary-hide');\n }\n };\n\n DesignerSection.prototype.sectionRestrictHandler = function(event) {\n var sectionRestrictInfo = $(event.currentTarget).prev();\n if (sectionRestrictInfo) {\n if (!sectionRestrictInfo.hasClass('show')) {\n sectionRestrictInfo.addClass('show');\n } else {\n sectionRestrictInfo.removeClass('show');\n }\n }\n };\n\n DesignerSection.prototype.moduleHandler = function(event) {\n event.preventDefault();\n var restrictBlock = $(event.currentTarget).parents('.restrict-block');\n if (restrictBlock.length) {\n if (!restrictBlock.hasClass('show')) {\n restrictBlock.addClass('show');\n } else {\n restrictBlock.removeClass('show');\n }\n }\n };\n\n DesignerSection.prototype.updateVideoTimeInstance = function(sectionId) {\n var section = \"#\" + sectionId;\n var sectionVideotimes = \"body \"+ section + \" .activity.videotime\";\n if ($(sectionVideotimes).length == 0) {\n return;\n }\n $(sectionVideotimes).each(function(index, module) {\n this.CreateInstance(module);\n }.bind(this));\n };\n\n DesignerSection.prototype.CreateInstance = function (module) {\n if (\n $(module).find('.instancename').length\n && ($(module).find('.vimeo-embed').length\n || $(module).find('.video-js').length)\n ) {\n var cmId = module.getAttribute(\"data-id\");\n var args = {cmid : cmId};\n // Get module instance.\n var promises = Ajax.call([{\n methodname: 'format_designer_get_videotime_instace',\n args: args\n }], true);\n promises[0].then(function(data) {\n var template = JSON.parse(data);\n if (template.playertype == 'videojs') {\n var uniqueid = $(module).find('.video-js').first().attr('id').replace('vimeo-embed-', '');\n } else {\n var uniqueid = $(module).find('.vimeo-embed').first().attr('id').replace('vimeo-embed-', '');\n }\n template.uniqueid = uniqueid;\n Templates.render(template.templatename, template).then(function(html, js) {\n Templates.runTemplateJS(js);\n return true;\n }).fail(Notification.exception);\n });\n }\n };\n\n /**\n * Implementaion swith the section layout.\n * @param {object} event\n */\n DesignerSection.prototype.sectionLayoutaction = function(event) {\n event.preventDefault();\n var self = this;\n let sectionId = event.target.closest('li.section').getAttribute('id');\n var sectionid = event.target.closest('li.section').getAttribute('data-id');\n var sectionitem = document.getElementById(sectionId);\n var iconBlock = \"#\" + sectionId + \" \" + self.loadingElement;\n var layout = $(event.currentTarget).data('value');\n var layouttext = $(event.currentTarget).text();\n $(event.target).parents(\".dropdown\").find(\".btn\").html(layouttext);\n $(event.target).parents(\".dropdown\").find(\".btn\").val(layout);\n $(event.target).parent().find(\"a.dropdown-item\").each(function() {\n $(this).removeClass('active');\n });\n $(event.target).addClass('active');\n let dataid = event.target.closest('li.section').getAttribute('data-id');\n var args = {\n courseid: self.courseId,\n sectionid: dataid,\n options: [{name: $(event.currentTarget).data('option'), value: layout}]\n };\n var promises = Ajax.call([{\n methodname: 'format_designer_set_section_options',\n args: args\n }], true);\n $.when.apply($, promises)\n .done(function() {\n if (self.isSubpanel) {\n const promise = Fragment.loadFragment(\n 'core_courseformat',\n 'section',\n self.contextId,\n {\n id: sectionid,\n courseid: self.courseId,\n sr: self.sectionReturn,\n }\n );\n promise.then((html, js) => {\n Templates.replaceNode(sectionitem, html, js);\n }).catch();\n } else {\n const sectionpromise = Actions.refreshSection('#' + sectionId, dataid, 0);\n sectionpromise.then(() => {\n return '';\n }).catch();\n }\n });\n Loadingicon.addIconToContainerRemoveOnCompletion(iconBlock, promises);\n // If videotime exist update the module.\n setTimeout(function() {\n if (self.videoTime) {\n self.updateVideoTimeInstance(sectionId);\n }\n }, 2000);\n };\n\n return {\n init: function(courseId, contextId, popupActivities, videoTime, issubpanel, sectionreturn) {\n return new DesignerSection(courseId, contextId, popupActivities, videoTime, issubpanel, sectionreturn);\n }\n };\n});\n"],"names":["define","$","Fragment","Templates","Loadingicon","Ajax","Actions","Contact","Notification","SELECTOR","ACTIVITYLI","SECTIONLI","ACTIVITYACTION","SECTIONACTIONMENU","Y","use","courseformatselector","M","course","format","get_section_selector","DesignerSection","courseId","contextId","popupActivities","videoTime","issubpanel","sectionreturn","self","this","isSubpanel","sectionReturn","addClass","delegate","SectionController","sectionLayoutaction","bind","SectionSubmenuSwitcher","RestrictInfo","moduleHandler","sectionRestricted","sectionRestrictHandler","fullDescription","fullmodcontentHandler","trimDescription","trimmodcontentHandler","goToURL","redirectToModule","goToSectionURL","redirectToSection","window","onhashchange","expandSection","contactModal","document","getElementsByClassName","Array","from","forEach","element","addEventListener","e","preventDefault","undefined","currentTarget","dataset","userid","enhance","popover","prototype","moduleBlock","loadingElement","modules","event","nodeName","target","iscircle","closest","classList","contains","isDescription","isPadlock","ispopupModule","isModHasURL","getAttribute","isCompletionButton","body","querySelector","click","modurl","location","href","singlesection","sectionurl","sectiontarget","open","sectionID","hash","id","substring","section","getElementById","title","remove","setAttribute","content","add","scrollIntoView","THIS","fullContent","find","trimcontent","hasClass","removeClass","sectionRestrictInfo","prev","restrictBlock","parents","length","updateVideoTimeInstance","sectionId","sectionVideotimes","each","index","module","CreateInstance","args","cmid","call","methodname","then","data","template","JSON","parse","playertype","uniqueid","first","attr","replace","render","templatename","html","js","runTemplateJS","fail","exception","sectionid","sectionitem","iconBlock","layout","layouttext","text","val","parent","dataid","courseid","options","name","value","promises","when","apply","done","loadFragment","sr","replaceNode","catch","refreshSection","addIconToContainerRemoveOnCompletion","setTimeout","init"],"mappings":"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"} \ No newline at end of file diff --git a/amd/src/designer_section.js b/amd/src/designer_section.js index dea6828..42d4f05 100644 --- a/amd/src/designer_section.js +++ b/amd/src/designer_section.js @@ -75,18 +75,6 @@ }; this.expandSection(); - if ($('.course-type-flow').length > 0) { - $('.collapse').on('show.bs.collapse', function() { - $(this).parents('li.section').addClass('stack-header-collapsing'); - var sectionid = $(this).parents('li.section').attr('id'); - var section = document.getElementById(sectionid); - var distance = section.offsetTop - document.body.scrollTop; - setTimeout(() => window.scroll(0, distance), 50); - }).on('shown.bs.collapse', function() { - $(this).parents('li.section').removeClass('stack-header-collapsing'); - }); - } - var contactModal = document.getElementsByClassName('toggle-contact-button'); Array.from(contactModal).forEach(function(element) { element.addEventListener('click', function(e) { diff --git a/backup/moodle2/restore_format_designer_plugin.class.php b/backup/moodle2/restore_format_designer_plugin.class.php index 2eaaf78..adc6d88 100644 --- a/backup/moodle2/restore_format_designer_plugin.class.php +++ b/backup/moodle2/restore_format_designer_plugin.class.php @@ -177,11 +177,13 @@ protected function after_restore_section() { } // Restore the courseheaderbgimage. - $this->add_related_files('local_designer', 'courseheaderbgimage', null, null, $this->step->get_task()->get_old_courseid()); + $this->add_related_files('local_designer', 'courseheaderbgimage', null, null, + $this->step->get_task()->get_old_courseid()); // Restore the coursebgimage. $this->add_related_files('local_designer', 'coursebgimage', null, null, $this->step->get_task()->get_old_courseid()); // Restore the additionalcontent. - $this->add_related_files('local_designer', 'additionalcontent', null, null, $this->step->get_task()->get_old_courseid()); + $this->add_related_files('local_designer', 'additionalcontent', null, null, + $this->step->get_task()->get_old_courseid()); // Restore the prerequisiteinfo. $this->add_related_files('local_designer', 'prerequisiteinfo', null, null, $this->step->get_task()->get_old_courseid()); } diff --git a/classes/external/set_section_options.php b/classes/external/set_section_options.php index 516433b..0f20354 100644 --- a/classes/external/set_section_options.php +++ b/classes/external/set_section_options.php @@ -146,8 +146,7 @@ public static function get_module($id, $sectionid, $sectionreturn = null) { $renderer = $PAGE->get_renderer('format_designer'); $format = course_get_format($course); - $sectiontype = $format->get_section_option($sectionid, 'sectiontype') ?: - get_config('format_designer', 'sectiontype'); + $sectiontype = $format->get_section_option($sectionid, 'sectiontype') ?: get_config('format_designer', 'sectiontype'); $section = (object) ['sectiontype' => $sectiontype]; $cmlistdata = $renderer->render_course_module($cm, $sectionreturn, [], $section); diff --git a/classes/output/cm_completion.php b/classes/output/cm_completion.php index 483279d..610494f 100644 --- a/classes/output/cm_completion.php +++ b/classes/output/cm_completion.php @@ -151,7 +151,7 @@ final public function get_completion_mode(): int { * @return int */ final public function get_completion_state(): int { - return $this->get_completion_data()->completionstate; + return !is_null($this->get_completion_data()->completionstate) ? $this->get_completion_data()->completionstate : 0; } /** @@ -211,7 +211,7 @@ final public function is_overridden(): bool { * @return int */ final public function get_completion_date(): int { - return $this->get_completion_data()->timemodified; + return !is_null($this->get_completion_data()->timemodified) ? $this->get_completion_data()->timemodified : 0; } /** @@ -466,8 +466,8 @@ private function get_time_ago(int $timestamp): string { $ago = new \DateTime('@' . $timestamp); $diff = $now->diff($ago); - $diff->w = floor($diff->d / 7); - $diff->d -= $diff->w * 7; + $weeks = floor($diff->d / 7); + $diff->d -= $weeks * 7; $string = [ 'y' => get_string('timeagoyear', 'format_designer'), @@ -479,13 +479,13 @@ private function get_time_ago(int $timestamp): string { 's' => get_string('timeagosecond', 'format_designer'), ]; foreach ($string as $k => &$v) { - if ($diff->$k) { - $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : ''); + $value = ($k == 'w') ? $weeks : $diff->$k; + if ($value) { + $v = $value . ' ' . $v . ($value > 1 ? 's' : ''); } else { unset($string[$k]); } } - $string = array_slice($string, 0, 1); return $string ? implode(', ', $string) . ' ' . get_string('timeago', 'format_designer') : get_string('timeagojustnow', 'format_designer'); diff --git a/classes/output/courseformat/content.php b/classes/output/courseformat/content.php index 5805637..bee06d5 100644 --- a/classes/output/courseformat/content.php +++ b/classes/output/courseformat/content.php @@ -43,16 +43,66 @@ class content extends content_base { */ protected $hasaddsection = true; + /** * Export this data so it can be used as the context for a mustache template (core/inplace_editable). * - * @param renderer_base $output typically, the renderer that's calling this function - * @return stdClass data context for a mustache template + * @param \renderer_base $output typically, the renderer that's calling this function + * @return \stdClass data context for a mustache template */ public function export_for_template(\renderer_base $output) { - global $PAGE; - $data = parent::export_for_template($output); - $data->course = $this->format->get_course(); + global $PAGE, $CFG; + $format = $this->format; + $course = $this->format->get_course(); + + $sections = $this->export_sections($output); + $initialsection = ''; + + $data = (object) [ + 'title' => $format->page_title(), // This method should be in the course_format class. + 'initialsection' => $initialsection, + 'sections' => $sections, + 'format' => $format->get_format(), + 'sectionreturn' => null, + ]; + + $singlesectionnum = $format->get_sectionnum(); + $singlesectionnumhandled = false; + if ($course->coursedisplay == COURSE_DISPLAY_MULTIPAGE && optional_param('section', -1, PARAM_INT) >= 0) { + $singlesectionnumhandled = true; + } + + // The single section format has extra navigation. + if ($singlesectionnumhandled) { + $singlesectionnum = empty($singlesectionnum) ? 0 : $singlesectionnum; + if (!$PAGE->theme->usescourseindex) { + $sectionnavigation = new $this->sectionnavigationclass($format, $singlesectionnum); + $data->sectionnavigation = $sectionnavigation->export_for_template($output); + + $sectionselector = new $this->sectionselectorclass($format, $sectionnavigation); + $data->sectionselector = $sectionselector->export_for_template($output); + } + $data->hasnavigation = true; + $data->singlesection = array_shift($data->sections); + $data->sectionreturn = $singlesectionnum; + } + + if ($this->hasaddsection) { + $addsection = new $this->addsectionclass($format); + $data->numsections = $addsection->export_for_template($output); + } + + if ($format->show_editor()) { + $bulkedittools = new $this->bulkedittoolsclass($format); + $data->bulkedittools = $bulkedittools->export_for_template($output); + } + + $data->course = $course; + + if ($course->coursetype == DESIGNER_TYPE_KANBAN) { + $data->initialsection = array_shift($sections); + $data->sections = $sections; + } return $data; } @@ -73,6 +123,7 @@ protected function export_sections(\renderer_base $output): array { $sections = []; $stealthsections = []; $numsections = $format->get_last_section_number(); + foreach ($this->get_sections_to_display($modinfo) as $sectionnum => $thissection) { // The course/view.php check the section existence but the output can be called // from other parts so we need to check it. @@ -124,15 +175,17 @@ protected function export_sections(\renderer_base $output): array { * @return section_info[] an array of section_info to display */ private function get_sections_to_display(course_modinfo $modinfo): array { - $singlesection = $this->format->get_section_number(); - if ($singlesection) { - return [ - $modinfo->get_section_info(0), + global $CFG; + $singlesection = $this->format->get_sectionnum(); + $course = $this->format->get_course(); + if ($course->coursedisplay == COURSE_DISPLAY_MULTIPAGE && optional_param('section', -1, PARAM_INT) >= 0) { + $singlesection = empty($singlesection) ? 0 : $singlesection; + $sections = [ $modinfo->get_section_info($singlesection), ]; + return $sections; } - - return $modinfo->get_section_info_all(); + return $modinfo->get_listed_section_info_all(); } } diff --git a/classes/output/courseformat/content/cm/controlmenu.php b/classes/output/courseformat/content/cm/controlmenu.php index 647bdea..39d4aca 100644 --- a/classes/output/courseformat/content/cm/controlmenu.php +++ b/classes/output/courseformat/content/cm/controlmenu.php @@ -61,18 +61,13 @@ public function get_action_menu(\renderer_base $output): ?action_menu { // Convert control array into an action_menu. $menu = new action_menu(); - if (method_exists($menu, 'set_kebab_trigger')) { - $menu->set_kebab_trigger(get_string('edit')); - } else { - $icon = $output->pix_icon('i/menu', get_string('edit')); - $menu->set_menu_trigger($icon, 'btn btn-icon d-flex align-items-center justify-content-center'); - } + $menu->set_kebab_trigger(get_string('edit')); $menu->attributes['class'] .= ' section-cm-edit-actions commands'; // Prioritise the menu ahead of all other actions. $menu->prioritise = true; - $ownerselector = $displayoptions['ownerselector'] ?? '#module-' . $mod->id; + $ownerselector = $this->displayoptions['ownerselector'] ?? '#module-' . $mod->id; $menu->set_owner_selector($ownerselector); foreach ($controls as $control) { diff --git a/classes/output/courseformat/content/section.php b/classes/output/courseformat/content/section.php index 80a019b..ad18a34 100644 --- a/classes/output/courseformat/content/section.php +++ b/classes/output/courseformat/content/section.php @@ -26,6 +26,7 @@ use renderer_base; use stdClass; +use context_course; /** * Base class to render a course section. @@ -45,7 +46,7 @@ class section extends \core_courseformat\output\local\content\section { * @return bool if the cm has name data */ protected function add_format_data(stdClass &$data, array $haspartials, renderer_base $output): bool { - global $PAGE; + global $PAGE, $CFG; $section = $this->section; $format = $this->format; @@ -56,6 +57,8 @@ protected function add_format_data(stdClass &$data, array $haspartials, renderer $data->collapsemenu = true; } + $data->contentcollapsed = $this->is_section_collapsed(); + if ($format->is_section_current($section)) { $data->iscurrent = true; $data->currentlink = get_accesshide( @@ -64,15 +67,58 @@ protected function add_format_data(stdClass &$data, array $haspartials, renderer } $renderer = $this->format->get_renderer($PAGE); - if ($data->iscoursedisplaymultipage && !$format->get_section_number()) { - $formatdata = (array) $renderer->render_section_data($this->section, $this->format->get_course(), false, true); + $sectionnum = $format->get_sectionnum(); + + if ($data->iscoursedisplaymultipage && !$sectionnum) { + $pagesection = optional_param('section', -1, PARAM_INT); + $sectionnum = empty($sectionnum) && ($pagesection >= 0) ? 0 : false; + if ($pagesection >= 0) { + $formatdata = (array) $renderer->render_section_data($this->section, $this->format->get_course(), $sectionnum); + } else { + $formatdata = (array) $renderer->render_section_data($this->section, $this->format->get_course(), false, true); + } } else { $formatdata = (array) $renderer->render_section_data( - $this->section, $this->format->get_course(), $format->get_section_number() + $this->section, $this->format->get_course(), $sectionnum ); } $data = (object) array_merge((array) $data, $formatdata); return true; } + + /** + * Add the section editor attributes to the data structure. + * + * @param stdClass $data the current cm data reference + * @param renderer_base $output typically, the renderer that's calling this function + * @return bool if the cm has name data + */ + protected function add_editor_data(stdClass &$data, renderer_base $output): bool { + $course = $this->format->get_course(); + $coursecontext = context_course::instance($course->id); + $editcaps = []; + if (has_capability('moodle/course:sectionvisibility', $coursecontext)) { + $editcaps = ['moodle/course:sectionvisibility']; + } + if (!$this->format->show_editor($editcaps)) { + return false; + } + + // In a single section page the control menu is located in the page header. + if (empty($this->hidecontrols)) { + $controlmenu = new $this->controlmenuclass($this->format, $this->section); + $data->controlmenu = $controlmenu->export_for_template($output); + } + + $singlesection = $this->format->get_sectionnum(); + if (!$this->isstealth) { + $data->cmcontrols = $output->course_section_add_cm_control( + $course, + $this->section->section, + $singlesection + ); + } + return true; + } } diff --git a/classes/output/courseformat/content/section/cmitem.php b/classes/output/courseformat/content/section/cmitem.php index 3d7cd2e..263808a 100644 --- a/classes/output/courseformat/content/section/cmitem.php +++ b/classes/output/courseformat/content/section/cmitem.php @@ -69,6 +69,7 @@ public function export_for_template(\renderer_base $output): stdClass { 'cmformat' => $item->export_for_template($output), 'hasinfo' => $hasinfo, 'indent' => ($format->uses_indentation()) ? $mod->indent : 0, + 'groupmode' => $mod->groupmode, ]; $this->render_course_module($mod, $data, $output); return (object) $data; diff --git a/classes/output/courseformat/content/section/cmlist.php b/classes/output/courseformat/content/section/cmlist.php index 87ff73f..463e3cc 100644 --- a/classes/output/courseformat/content/section/cmlist.php +++ b/classes/output/courseformat/content/section/cmlist.php @@ -100,8 +100,7 @@ public function render_section_content($output, $htmlparse = false) { } $sectionlayoutclass = 'link-layout'; - $sectiontype = $this->format->get_section_option($section->id, 'sectiontype') ?: - get_config('format_designer', 'sectiontype'); + $sectiontype = $this->format->get_section_option($section->id, 'sectiontype') ?: 'default'; if ($sectiontype == 'list') { $sectionlayoutclass = "list-layout"; } else if ($sectiontype == 'cards') { @@ -119,7 +118,6 @@ public function render_section_content($output, $htmlparse = false) { $templatename = 'layouts_' . $sectiontype . '/layout/section_layout_' . $sectiontype; } } - $templatename = $output->is_template_exists($templatename); $data->sectionlayoutclass = $sectionlayoutclass; $cmscontent = $OUTPUT->render_from_template($templatename, $data); @@ -127,6 +125,7 @@ public function render_section_content($output, $htmlparse = false) { return $cmscontent; } $data->cmscontent = $cmscontent; + $data->groupmode = isset($mod->groupmode) ? $mod->groupmode : ''; return $data; } } diff --git a/classes/output/courseformat/content/section/controlmenu.php b/classes/output/courseformat/content/section/controlmenu.php index c0631d9..2a9a31d 100644 --- a/classes/output/courseformat/content/section/controlmenu.php +++ b/classes/output/courseformat/content/section/controlmenu.php @@ -45,22 +45,44 @@ */ class controlmenu extends controlmenu_base { - /** @var course_format the course format class */ - protected $format; - - /** @var section_info the course section class */ - protected $section; - /** - * Constructor. + * Generate the default section action menu. + * + * This method is public in case some block needs to modify the menu before output it. * - * @param course_format $format the course format - * @param section_info $section the section info + * @param \renderer_base $output typically, the renderer that's calling this function + * @return action_menu|null the activity action menu */ - public function __construct(course_format $format, section_info $section) { - $this->format = $format; - $this->course = $format->get_course(); - $this->section = $section; + public function get_default_action_menu(\renderer_base $output): ?action_menu { + $controls = $this->section_control_items(); + if (empty($controls)) { + return null; + } + + // Convert control array into an action_menu. + $menu = new action_menu(); + $menu->set_kebab_trigger(get_string('edit')); + $menu->attributes['class'] .= ' section-actions'; + + foreach ($controls as $value) { + $value = (array) $value; + $url = empty($value['url']) ? '' : $value['url']; + $icon = empty($value['icon']) ? '' : $value['icon']; + if ($icon instanceof pix_icon) { + $icon = $icon->pix; + } + $name = empty($value['name']) ? '' : $value['name']; + $attr = empty($value['attr']) ? [] : $value['attr']; + $class = empty($value['pixattr']['class']) ? '' : $value['pixattr']['class']; + $al = new action_menu_link_secondary( + new moodle_url($url), + new pix_icon($icon, '', null, ['class' => "smallicon " . $class]), + $name, + $attr + ); + $menu->add($al); + } + return $menu; } /** @@ -74,8 +96,13 @@ public function export_for_template(\renderer_base $output): stdClass { $section = $this->section; $hassectiontypes = true; - if (($this->course->coursedisplay == COURSE_DISPLAY_MULTIPAGE && !$this->format->get_section_number()) - || $this->course->coursetype == DESIGNER_TYPE_FLOW) { + + $sectionnum = $this->format->get_sectionnum(); + + $course = $this->format->get_course(); + + if (($course->coursedisplay == COURSE_DISPLAY_MULTIPAGE && !$sectionnum) + || $course->coursetype == DESIGNER_TYPE_FLOW) { $hassectiontypes = false; } @@ -117,30 +144,30 @@ public function export_for_template(\renderer_base $output): stdClass { 'name' => get_string('link', 'format_designer'), 'active' => empty($this->format->get_section_option($section->id, 'sectiontype')) || $this->format->get_section_option($section->id, 'sectiontype') == 'default', - 'url' => new moodle_url('/course/view.php', ['id' => $this->course->id], 'section-' . $section->section), + 'url' => new moodle_url('/course/view.php', ['id' => $course->id], 'section-' . $section->section), ], [ 'type' => 'list', 'name' => get_string('list', 'format_designer'), 'active' => $this->format->get_section_option($section->id, 'sectiontype') == 'list', - 'url' => new moodle_url('/course/view.php', ['id' => $this->course->id], 'section-' . $section->section), + 'url' => new moodle_url('/course/view.php', ['id' => $course->id], 'section-' . $section->section), ], [ 'type' => 'cards', 'name' => get_string('cards', 'format_designer'), 'active' => $this->format->get_section_option($section->id, 'sectiontype') == 'cards', - 'url' => new moodle_url('/course/view.php', ['id' => $this->course->id], 'section-' . $section->section), + 'url' => new moodle_url('/course/view.php', ['id' => $course->id], 'section-' . $section->section), ], ]; if (format_designer_has_pro()) { - $prosectiontypes = \local_designer\info::get_layout_menu($this->format, $section, $this->course); + $prosectiontypes = \local_designer\info::get_layout_menu($this->format, $section, $course); $sectiontypes = array_merge($sectiontypes, $prosectiontypes); } } - $data = (object)[ + $data = (object) [ 'menu' => $output->render($menu), 'hasmenu' => true, 'id' => $section->id, @@ -148,7 +175,6 @@ public function export_for_template(\renderer_base $output): stdClass { 'is_subpanel' => format_designer_is_support_subpanel(), 'hassectiontypes' => $hassectiontypes, ]; - return $data; } @@ -162,12 +188,14 @@ public function export_for_template(\renderer_base $output): stdClass { * @return array of edit control items */ public function section_control_items() { - global $USER; + global $USER, $PAGE, $CFG; $format = $this->format; $section = $this->section; $course = $format->get_course(); - $sectionreturn = $format->get_section_number(); + + $sectionreturn = !is_null($format->get_sectionid()) ? $format->get_sectionnum() : null; + $user = $USER; $usecomponents = $format->supports_components(); @@ -178,16 +206,24 @@ public function section_control_items() { $baseurl = course_get_url($course, $sectionreturn); $baseurl->param('sesskey', sesskey()); + $course = $format->get_course(); + $controls = []; + // Only show the view link if we are not already in the section view page. + if ($PAGE->pagetype !== 'section-view-' . $course->format) { + $controls['view'] = [ + 'url' => new moodle_url('/course/view.php', ['id' => $course->id, 'section' => $section->section]), + 'icon' => 'i/viewsection', + 'name' => get_string('view'), + 'pixattr' => ['class' => ''], + 'attr' => ['class' => 'icon view'], + ]; + } + if (!$isstealth && has_capability('moodle/course:update', $coursecontext, $user)) { - if ($section->section > 0 - && get_string_manager()->string_exists('editsection', 'format_'.$format->get_format())) { - $streditsection = get_string('editsection', 'format_'.$format->get_format()); - } else { - $streditsection = get_string('editsection'); - } + $streditsection = get_string('editsection', 'format_'.$format->get_format()); $controls['edit'] = [ 'url' => new moodle_url('/course/editsection.php', ['id' => $section->id, 'sr' => $sectionreturn]), 'icon' => 'i/settings', @@ -197,8 +233,8 @@ public function section_control_items() { ]; $hassectiontypes = true; - if (($this->course->coursedisplay == COURSE_DISPLAY_MULTIPAGE && !$this->format->get_section_number()) - || $this->course->coursetype == DESIGNER_TYPE_FLOW) { + if (($course->coursedisplay == COURSE_DISPLAY_MULTIPAGE && !$sectionreturn) + || $course->coursetype == DESIGNER_TYPE_FLOW) { $hassectiontypes = false; } @@ -214,6 +250,11 @@ public function section_control_items() { $duplicatesectionurl = clone($baseurl); $duplicatesectionurl->param('section', $section->section); $duplicatesectionurl->param('duplicatesection', $section->section); + + if (!is_null($sectionreturn)) { + $duplicatesectionurl->param('sr', $sectionreturn); + } + $controls['duplicate'] = [ 'url' => $duplicatesectionurl, 'icon' => 't/copy', @@ -225,6 +266,11 @@ public function section_control_items() { if ($section->section) { $url = clone($baseurl); + + if (!is_null($sectionreturn)) { + $url->param('sectionid', $format->get_sectionid()); + } + if (!$isstealth) { if (has_capability('moodle/course:sectionvisibility', $coursecontext, $user)) { $strhidefromothers = get_string('hidefromothers', 'format_' . $course->format); @@ -319,14 +365,21 @@ public function section_control_items() { } else { $strdelete = get_string('deletesection'); } + + $params = [ + 'id' => $section->id, + 'delete' => 1, + 'sesskey' => sesskey(), + ]; + + if (!is_null($sectionreturn)) { + + $params['sr'] = $sectionreturn; + + } $url = new moodle_url( '/course/editsection.php', - [ - 'id' => $section->id, - 'sr' => $sectionreturn, - 'delete' => 1, - 'sesskey' => sesskey(), - ] + $params, ); $controls['delete'] = [ 'url' => $url, @@ -374,7 +427,6 @@ public function section_control_items() { * @return choicelist */ public function get_choice_list($section): choicelist { - $sectiontype = $this->format->get_section_option($section->id, 'sectiontype'); $sectiontype = $sectiontype ? $sectiontype : get_config('format_designer', 'sectiontype'); $choice = $this->create_choice_list($section); @@ -399,7 +451,7 @@ protected function create_choice_list($section): choicelist { 'cards' => get_string('cards', 'format_designer'), ]; if (format_designer_has_pro()) { - $prosectiontypes = \local_designer\info::get_layout_menu($this->format, $section, $this->course); + $prosectiontypes = \local_designer\info::get_layout_menu($this->format, $section, $this->format->get_course()); $lists = array_merge($lists, array_column($prosectiontypes, 'name', 'type')); } diff --git a/classes/output/courseformat/content/section/header.php b/classes/output/courseformat/content/section/header.php index 8c12ec5..a0cdff3 100644 --- a/classes/output/courseformat/content/section/header.php +++ b/classes/output/courseformat/content/section/header.php @@ -96,13 +96,12 @@ public function export_for_template(\renderer_base $output): stdClass { } } $data->name = get_section_name($course, $section); - if (method_exists($format, 'get_format_string')) { - $data->selecttext = $format->get_format_string('selectsection', $data->name); - } + $data->selecttext = $format->get_format_string('selectsection', $data->name); $bodyclasses = explode(" ", $PAGE->bodyclasses); - if ((!$format->get_section_number() || !in_array('format-designer-single-section', $bodyclasses)) + $sectionreturn = $format->get_sectionnum(); + if ((!$sectionreturn || !in_array('format-designer-single-section', $bodyclasses)) && class_exists('core_courseformat\output\local\content\bulkedittoggler')) { $data->sectionbulk = true; } diff --git a/classes/output/courseformat/state/cm.php b/classes/output/courseformat/state/cm.php index 5bccf0e..4d12ed0 100644 --- a/classes/output/courseformat/state/cm.php +++ b/classes/output/courseformat/state/cm.php @@ -38,53 +38,22 @@ public function export_for_template(\renderer_base $output): stdClass { global $USER, $CFG; $format = $this->format; - $section = $this->section; - $cm = $this->cm; $course = $format->get_course(); - if (class_exists("\core_external\util")) { - $name = \core_external\util::format_string($cm->name, $cm->context, true); - } else { - $name = external_format_string($cm->name, $cm->context, true); - } - $data = (object)[ - 'id' => $cm->id, - 'anchor' => "module-{$cm->id}", - 'name' => $name, - 'visible' => !empty($cm->visible), - 'sectionid' => $section->id, - 'sectionnumber' => $section->section, - 'uservisible' => $cm->uservisible, - 'hascmrestrictions' => $this->get_has_restrictions(), - ]; - + $format = $this->format; + $cm = $this->cm; + $data = parent::export_for_template($output); $usecourseindexcustom = \format_designer\options::get_option($cm->id, 'customtitleusecourseindex'); if ($usecourseindexcustom) { $data->designercmname = $format->get_cm_secondary_title($cm); } - // Check the user access type to this cm. - $info = new info_module($cm); - $data->accessvisible = ($data->visible && $info->is_available_for_all()); - - // Add url if the activity is compatible. - $url = $cm->url; - if ($url) { - $data->url = $url->out(); - } - - if ($this->exportcontent) { - $data->content = $output->course_section_updated_cm_item($format, $section, $cm); - } // Completion status. $completioninfo = new completion_info($course); - $data->istrackeduser = $completioninfo->is_tracked_user($USER->id); if ($data->istrackeduser && $completioninfo->is_enabled($cm)) { $completiondata = $completioninfo->get_data($cm); $data->completionstate = $completiondata->completionstate; } - return $data; } - } diff --git a/classes/output/courseformat/state/section.php b/classes/output/courseformat/state/section.php new file mode 100644 index 0000000..de9728a --- /dev/null +++ b/classes/output/courseformat/state/section.php @@ -0,0 +1,94 @@ +. + +namespace format_designer\output\courseformat\state; + +use moodle_url; +use stdClass; + +/** + * Contains the ajax update section structure. + * + * @package format_designer + * @copyright 2021 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class section extends \core_courseformat\output\local\state\section { + + /** + * Export this data so it can be used as state object in the course editor. + * + * @param \renderer_base $output typically, the renderer that's calling this function + * @return array data context for a mustache template + */ + public function export_for_template(\renderer_base $output): stdClass { + global $CFG; + $format = $this->format; + $course = $format->get_course(); + $section = $this->section; + $modinfo = $format->get_modinfo(); + + $indexcollapsed = false; + $contentcollapsed = false; + $preferences = $format->get_sections_preferences(); + if (isset($preferences[$section->id])) { + $sectionpreferences = $preferences[$section->id]; + if (!empty($sectionpreferences->contentcollapsed)) { + $contentcollapsed = true; + } + if (!empty($sectionpreferences->indexcollapsed)) { + $indexcollapsed = true; + } + } + $sectionurlinfo = course_get_url($course, $section->section, ['navigation' => true]); + $sectionurl = ''; + if ($sectionurlinfo instanceof moodle_url) { + $sectionurl = $sectionurlinfo->out(false); + } + $data = [ + 'id' => $section->id, + 'section' => $section->section, + 'number' => $section->section, + 'title' => $format->get_section_name($section), + 'hassummary' => !empty($section->summary), + 'rawtitle' => $section->name, + 'cmlist' => [], + 'visible' => !empty($section->visible), + 'sectionurl' => $sectionurl, + 'current' => $format->is_section_current($section), + 'indexcollapsed' => $indexcollapsed, + 'contentcollapsed' => $contentcollapsed, + 'hasrestrictions' => $this->get_has_restrictions(), + 'bulkeditable' => $this->is_bulk_editable(), + 'component' => $section->component, + 'itemid' => $section->itemid, + ]; + + $data = (object) $data; + + if (empty($modinfo->sections[$section->section])) { + return $data; + } + + foreach ($modinfo->sections[$section->section] as $modnumber) { + $mod = $modinfo->cms[$modnumber]; + if ($section->uservisible && $mod->is_visible_on_course_page()) { + $data->cmlist[] = $mod->id; + } + } + return $data; + } +} diff --git a/classes/output/renderer.php b/classes/output/renderer.php index 6244619..99e16ed 100644 --- a/classes/output/renderer.php +++ b/classes/output/renderer.php @@ -40,7 +40,6 @@ use format_designer\output\call_to_action; use format_designer\output\cm_completion; -require_once($CFG->dirroot.'/course/format/renderer.php'); require_once($CFG->dirroot.'/course/format/designer/lib.php'); /** @@ -100,13 +99,19 @@ public function render_content($widget) { $startclass[] = 'kanban-board'; $data->kanbanmode = true; } + $data->startid = $startid; - $data->issectionpageclass = ($data->initialsection->sectionreturnid != 0) ? 'section-page-layout' : ''; + $format = course_get_format($course); + $singlesection = $format->get_sectionnum(); + + $data->issectionpageclass = $singlesection || ($course->coursedisplay == COURSE_DISPLAY_MULTIPAGE) + ? 'section-page-layout' : ''; if (!format_designer_has_pro()) { $data->headermetadata = $this->course_header_metadata_details($course); } + if (format_designer_has_pro()) { $startclass[] = ($course->activitydisplaymode == 'bypurpose') ? 'activity-purpose-mode' : 'activity-default-mode'; } @@ -875,7 +880,7 @@ public function render_section_data(section_info $section, stdClass $course, $on $sectionrestrict = (!$section->uservisible && $section->availableinfo) ? true : false; if ($course->coursedisplay == COURSE_DISPLAY_MULTIPAGE && $sectionheader - && $section->section > 0 && $format->is_section_visible($section, false)) { + && $format->is_section_visible($section, false)) { $gotosection = true; } @@ -931,7 +936,7 @@ public function render_section_data(section_info $section, stdClass $course, $on $sectioncollapsestatus = 'show'; } // Calculate section width for single section format. - $section->widthclass = ($course->coursedisplay && !$this->page->user_is_editing() && !$onsectionpage && $sectionheader) + $sectionwidthclass = ($course->coursedisplay && !$this->page->user_is_editing() && !$onsectionpage && $sectionheader) ? $this->generate_section_widthclass($section) : ''; if ($course->coursedisplay && !$onsectionpage) { @@ -941,6 +946,8 @@ public function render_section_data(section_info $section, stdClass $course, $on $sectionstylerules = ($course->coursetype == DESIGNER_TYPE_KANBAN) ? (isset($course->listwidth) && $section->section != 0 ? sprintf('width: %s;', $course->listwidth) : '') : ''; + + $showprerequisites = ($section->section == 0) || $format->get_sectionid() ? true : false; $templatecontext = [ 'section' => $section, 'sectionvisible' => $format->is_section_visible($section, false), @@ -959,7 +966,7 @@ public function render_section_data(section_info $section, stdClass $course, $on 'sectioncontainerwidth' => $sectioncontainerwidth, 'sectioncontentwidth' => $sectioncontentwidth, 'sectiondesignwhole' => $sectiondesignwhole, - 'showprerequisites' => ($section->section == 0) ? true : false, + 'showprerequisites' => $showprerequisites, 'prerequisitesnewtab' => isset($course->prerequisitesnewtab) ? $course->prerequisitesnewtab : false, 'sectiondesignheader' => $sectiondesignheader, 'sectiondesigntextcolor' => $sectiondesigntextcolor, @@ -1029,7 +1036,7 @@ public function render_section_data(section_info $section, stdClass $course, $on $templatecontext['sectionmodcount'] = array_values($mods); $templatecontext['sectionsingle'] = true; } - if (format_designer_has_pro() && $section->section == 0) { + if (format_designer_has_pro() && $showprerequisites) { require_once($CFG->dirroot. "/local/designer/lib.php"); if ($course->displaycourseprerequisites == DESIGNER_PREREQUISITES_ABOVECOURSE && function_exists('local_designer_import_prerequisites_courses')) { @@ -1053,7 +1060,7 @@ public function render_section_data(section_info $section, stdClass $course, $on } $sectionclass = ' section-type-'.$sectiontype; $sectionclass .= ($sectionrestrict) ? 'restricted' : ''; - $sectionclass .= $section->widthclass; + $sectionclass .= $sectionwidthclass; $sectionclass .= ($templatecontext['sectionstyle']) ?? ' '.$templatecontext['sectionstyle']; $sectionclass .= isset($templatecontext['onlysummary']) && $templatecontext['onlysummary'] ? ' section-summary ' : ''; $sectionclass .= isset($templatecontext['ishidden']) && $templatecontext['ishidden'] ? ' hidden ' : ''; diff --git a/editsection_form.php b/editsection_form.php index 0481788..788c217 100644 --- a/editsection_form.php +++ b/editsection_form.php @@ -47,16 +47,22 @@ public function definition() { $mform->addElement('header', 'generalhdr', get_string('general')); - $mform->addElement('defaultcustom', 'name', get_string('sectionname'), [ - 'defaultvalue' => $this->_customdata['defaultsectionname'], - 'customvalue' => $sectioninfo->name, - ], ['size' => 30, 'maxlength' => 255]); - $mform->setDefault('name', false); - $mform->addGroupRule('name', ['name' => [[get_string('maximumchars', '', 255), 'maxlength', 255]]]); + $mform->addElement( + 'text', + 'name', + get_string('sectionname'), + [ + 'placeholder' => $this->_customdata['defaultsectionname'], + 'size' => 30, + 'maxlength' => 255, + ], + ); + $mform->setType('name', PARAM_RAW); + $mform->setDefault('name', $sectioninfo->name); + $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client'); // Prepare course and the editor. $mform->addElement('editor', 'summary_editor', get_string('summary'), null, $this->_customdata['editoroptions']); - $mform->addHelpButton('summary_editor', 'summary'); $mform->setType('summary_editor', PARAM_RAW); $mform->addElement('hidden', 'id'); @@ -68,8 +74,9 @@ public function definition() { if (!empty($formatoptions)) { $elements = $courseformat->create_edit_form_elements($mform, true); } + // Check the moodle 4.3 higher. - if ($CFG->version >= 2023092300 && !empty($CFG->enableavailability)) { + if (!empty($CFG->enableavailability)) { $mform->addElement('header', 'availabilityconditions', get_string('restrictaccess', 'availability')); @@ -104,18 +111,6 @@ public function definition_after_data() { $course = $this->_customdata['course']; if (!empty($CFG->enableavailability)) { - // Check the moodle 4.3 lower. - if ($CFG->version < 2023092300) { - $mform->addElement('header', 'availabilityconditions', - get_string('restrictaccess', 'availability')); - $mform->setExpanded('availabilityconditions', false); - - // Availability field. This is just a textarea; the user interface - // interaction is all implemented in JavaScript. The field is named - // availabilityconditionsjson for consistency with moodleform_mod. - $mform->addElement('textarea', 'availabilityconditionsjson', - get_string('accessrestrictions', 'availability')); - } \core_availability\frontend::include_all_javascript($course, null, $this->_customdata['cs']); } @@ -129,6 +124,7 @@ public function definition_after_data() { * @param stdClass|array $defaultvalues object or array of default values */ public function set_data($defaultvalues) { + global $CFG; if (!is_object($defaultvalues)) { // We need object for file_prepare_standard_editor. $defaultvalues = (object)$defaultvalues; @@ -143,10 +139,6 @@ public function set_data($defaultvalues) { $defaultvalues = \local_designer\options::prepare_sectioncardcta_editor_files($defaultvalues, $this->_customdata['course']); } - - if (strval($defaultvalues->name) === '') { - $defaultvalues->name = false; - } parent::set_data($defaultvalues); } diff --git a/format.php b/format.php index e5b3e2b..5d305ec 100644 --- a/format.php +++ b/format.php @@ -52,7 +52,7 @@ $renderer = $PAGE->get_renderer('format_designer'); if (!empty($displaysection)) { - $format->set_section_number($displaysection); + $format->set_sectionnum($displaysection); } $outputclass = $format->get_output_classname('content'); diff --git a/lang/en/format_designer.php b/lang/en/format_designer.php index cf79d7a..c0421c8 100644 --- a/lang/en/format_designer.php +++ b/lang/en/format_designer.php @@ -273,7 +273,6 @@ $string['courseheader'] = 'Course header'; $string['popupactivitiesnotinstalled'] = 'Popup format must be installed in order to display the activities in popup.'; $string['listwidth'] = 'List width'; - $string['general'] = 'General'; $string['general_settings'] = "General settings"; $string['flowanimationduration'] = 'Flow animation duration'; @@ -539,6 +538,7 @@ $string['purposecontent'] = 'Content'; $string['purposeinterface'] = 'Interface'; $string['purposeother'] = 'Other'; +$string['purposeinteractivecontent'] = "Interactive Content"; $string['purpose_created'] = 'Purpose successfully created'; $string['edit_purpose'] = 'Edit purposes'; @@ -556,6 +556,8 @@ $string['courseindicator'] = "Course status: "; $string['strsectionlayout'] = "Section Layout"; $string['completioncriteria'] = "Completion criteria"; +$string['plugin_description'] = 'Mix and match layouts to create unique and visually appealing course designs.'; $string['strsecondarymenucourse'] = "Course"; + $string['section_layout'] = "Section layout"; $string['section_layout_desc'] = ""; diff --git a/lib.php b/lib.php index 88eb267..b501b8f 100644 --- a/lib.php +++ b/lib.php @@ -951,6 +951,7 @@ public function create_edit_form_elements(&$mform, $forsection = false) { } array_unshift($elements, $element); } + if ($forsection) { $options = $this->section_format_options(true); } else { @@ -1155,6 +1156,81 @@ public static function section_format_options_list($foreditform) { return $sectionoptions; } + + /** + * Duplicate a section + * + * @param section_info $originalsection The section to be duplicated + * @return section_info The new duplicated section + * @since Moodle 4.2 + */ + public function duplicate_section(section_info $originalsection): section_info { + global $USER, $CFG; + $course = $this->get_course(); + + $fileareasections = [ + 'sectiondesignerbackgroundimage' => [ + 'filearea' => 'sectiondesignbackground', + 'component' => 'format_designer', + ], + 'sectiondesignercompletionbg' => [ + 'filearea' => 'sectiondesigncompletionbackground', + 'component' => 'format_designer', + ], + 'sectioncardcta' => [ + 'filearea' => 'sectioncardcta', + 'component' => 'local_designer', + ], + ]; + $sectioninfo = parent::duplicate_section($originalsection); + $oldsection = get_fast_modinfo($course)->get_section_info($originalsection->section); + $oldsectionoptions = $this->get_section_options($oldsection->id); + $coursecontext = \context_course::instance($course->id); + $fs = get_file_storage(); + if (!empty($oldsectionoptions)) { + foreach ($oldsectionoptions as $option => $value) { + if ($value) { + $this->set_section_option($sectioninfo->id, $option, $value); + } + + if (in_array($option, array_keys($fileareasections))) { + $files = $fs->get_area_files($coursecontext->id, $fileareasections[$option]['component'], + $fileareasections[$option]['filearea'], $oldsection->id, 'itemid, filepath, filename', false); + $file = current($files); + if ($file) { + $userdraft = [ + 'contextid' => $coursecontext->id, + 'component' => $fileareasections[$option]['component'], + 'filearea' => $fileareasections[$option]['filearea'], + 'itemid' => $sectioninfo->id, + 'filepath' => '/', + 'filename' => $file->get_filename(), + ]; + $fs->create_file_from_storedfile($userdraft, $file); + } + } + } + } + + // Prepare the section summary. + $files = $fs->get_area_files( + $coursecontext->id, 'course', 'section', $oldsection->id, 'itemid, filepath, filename', false); + $file = current($files); + if ($file) { + $userdraft = [ + 'contextid' => $coursecontext->id, + 'component' => 'course', + 'filearea' => 'section', + 'itemid' => $sectioninfo->id, + 'filepath' => '/', + 'filename' => $file->get_filename(), + ]; + $fs->create_file_from_storedfile($userdraft, $file); + } + return $sectioninfo; + } + + /** * Updates format options for a section * @@ -1704,6 +1780,21 @@ function format_designer_get_pro_layouts() { return $layouts; } +/** + * Get the designer format custom layouts + * @return array + */ +function format_designer_get_all_layouts() { + $layouts = [ + 'default' => get_string('link', 'format_designer'), + 'list' => get_string('list', 'format_designer'), + 'cards' => get_string('cards', 'format_designer') + ]; + $prolayouts = array_keys(core_component::get_plugin_list('layouts')); + $prolayouts = (array) get_strings($prolayouts, 'format_designer'); + return array_merge($layouts, $prolayouts); +} + /** * Get section background image url. * @@ -1971,26 +2062,9 @@ function format_designer_timemanagement_installed() { function format_designer_editsetting_style($page) { if ($page->user_is_editing()) { // Fixed the overlapping issue by make this css rule as important. Moodle CI doesn't allow important. - $style = '.format-designer .course-content ul.designer li.section .right .dropdown .dropdown-menu {'; - $style .= 'top: -50px !important;left: auto !important;right: 40px !important;transform: none !important;'; - $style .= '}'; - $style .= '.format-designer .designer .section .activity .actions .menubar .dropdown .dropdown-menu {'; - $style .= 'top: -50px !important;left: auto !important;right: 40px !important;transform: none !important;'; - $style .= '}'; - $style .= '.format-designer .course-content ul.designer li.section .right .dropdown.designer-menu .dropdown-menu {'; - $style .= 'top: -90px !important;'; - $style .= '}'; - $style .= '.format-designer .designer .section .activity .actions .menubar .dropdown .dropdown-menu .dropdown-subpanel - .dropdown-menu {'; - $style .= 'right: 100% !important;'; - $style .= '}'; - $style .= '.format-designer .course-content ul.designer li.section .right .dropdown .dropdown-menu .dropdown-subpanel - .dropdown-menu {'; - $style .= 'right: 100% !important;'; - $style .= '}'; - $style .= '.format-designer .course-content ul.designer.kanban-board li.section#section-1 .right .dropdown + $style .= '.format-designer .course-content ul.designer .kanban-board-activities li.section:first-child .right .dropdown .dropdown-menu .dropdown-subpanel .dropdown-menu {'; - $style .= 'right: 40px !important;'; + $style .= 'left: 100% !important;'; $style .= '}'; echo html_writer::tag('style', $style, []); } @@ -2154,7 +2228,8 @@ function format_designer_extend_navigation_course($navigation, $course, $context "class" => "nav-item", "role" => "none", "data-forceintomoremenu" => "true", ] ); $secondarymenutocoursecontent .= html_writer::link(new moodle_url('/course/view.php', ['id' => $course->id]), - get_string('strsecondarymenucourse', 'format_designer'), ['role' => 'menuitem', 'class' => 'designercoursehome', "tabindex" => "-1" ]); + get_string('strsecondarymenucourse', 'format_designer'), ['role' => 'menuitem', + 'class' => 'designercoursehome', "tabindex" => "-1" ]); $secondarymenutocoursecontent .= html_writer::end_tag("li"); if (format_designer_has_pro() && $course->prerequisitesbackmain @@ -2506,19 +2581,3 @@ function format_designer_is_support_subpanel() { } return false; } - -/** - * Get the list of all layouts. - * - * @return array list. - */ -function format_designer_get_all_layouts() { - $layouts = [ - 'default' => get_string('link', 'format_designer'), - 'list' => get_string('list', 'format_designer'), - 'cards' => get_string('cards', 'format_designer') - ]; - $prolayouts = array_keys(core_component::get_plugin_list('layouts')); - $prolayouts = (array) get_strings($prolayouts, 'format_designer'); - return array_merge($layouts, $prolayouts); -} diff --git a/settings.php b/settings.php index 7318abd..683d397 100644 --- a/settings.php +++ b/settings.php @@ -109,20 +109,24 @@ $settingspage->add($settings); $sectionpage = new admin_settingpage('format_designer_section', get_string('sectionsettings', 'format_designer')); + // Section mask images. $name = 'formaty_designer_sectiongeneral'; $heading = get_string('general', 'format_designer'); $information = ''; $setting = new admin_setting_heading($name, $heading, $information); $sectionpage->add($setting); + + // Section layout - Global setting - DES-866. $name = 'format_designer/sectiontype'; $title = get_string('strsectionlayout', 'format_designer'); $description = get_string('section_layout_desc', 'format_designer'); $layouts = []; - $setting = new admin_setting_configselect($name , $title, $description, 'link', format_designer_get_all_layouts()); + $setting = new admin_setting_configselect($name , $title, $description, 'default', format_designer_get_all_layouts()); $sectionpage->add($setting); + $activitypage = new admin_settingpage('format_designer_activity', get_string('stractivity', 'format_designer')); // Activity description length. diff --git a/styles.css b/styles.css index 752af89..e3e3e3c 100644 --- a/styles.css +++ b/styles.css @@ -250,7 +250,8 @@ li.section.main .section-content-wrapper { } /* Section goto link */ -.format-designer .course-content ul.designer:not(.course-type-flow) li.section .section-header-content .goto-section { +.format-designer .course-content ul.designer:not(.course-type-flow) li.section +.section-header-content:not(.flow-stack) .goto-section { float: right; clear: both; } @@ -526,8 +527,11 @@ body.format-designer.editing ul.designer .section .circles-layout .activity .edi border: 0; background-size: cover; background-repeat: no-repeat; + /* position: relative; + z-index: 0; */ +} +.format-designer .course-content ul.designer li.section.main .section-content-wrapper { position: relative; - z-index: 0; } .format-designer .course-content ul.designer li.section.main .section-background-style.section-design-whole { width: 100%; @@ -704,6 +708,7 @@ span.section-collapse-icon:before { vertical-align: middle; } .format-designer.path-course-view.pagelayout-course #page { + height: 100%; background-color: transparent; } .format-designer #page #page-content section#region-main { @@ -765,9 +770,9 @@ span.section-collapse-icon:before { } .format-designer .course-content ul.designer li.section .right { position: relative; - z-index: 1; + z-index: 2; } -.format-designer .course-content ul.designer li.section .right .dropdown { +.format-designer .course-content ul.designer li.section .right .dropdown:not(.dropdown-subpanel) { display: inline-block; margin-right: 10px; } @@ -995,8 +1000,6 @@ span.section-collapse-icon:before { padding: 0 0 5px 0; } .format-designer .designer .section.img-text .activity .activityinstance .img-block img { - width: 20px; - height: 20px; margin: 0 auto; } .format-designer .designer .section.img-text .activity .activityinstance .inplaceeditable { @@ -1065,6 +1068,10 @@ span.section-collapse-icon:before { .format-designer .designer .section.img-text.card-layout .activity .activityinstance .inplaceeditable { width: 90%; } +.format-designer.editing .designer .section.img-text.card-layout .activity .activityinstance +.inplaceeditable.inplaceeditingon input { + width: auto; +} /*v-4.0+*/ .format-designer .designer .section.img-text.card-layout .activity .activityinstance .inplaceeditable { @@ -1094,6 +1101,51 @@ span.section-collapse-icon:before { .format-designer .designer .section.card-layout .activity .actions { right: 10px; } +/* Course Edit dropdown menu */ +@media (min-width: 576px) and (max-width: 1690px) { + .format-designer .designer .section.desktop-five-column .section.link-layout .activity .action-menu .menubar .dropdown + .dropdown-menu .dropdown-subpanel .dropdown-menu, + .format-designer .designer .section.desktop-five-column .section.card-layout .activity .action-menu .menubar .dropdown + .dropdown-menu .dropdown-subpanel .dropdown-menu, + .format-designer .designer .section.desktop-five-column .section.circles-layout .activity .action-menu .menubar .dropdown + .dropdown-menu .dropdown-subpanel .dropdown-menu { + left: 0; + } +} + +@media (min-width: 576px) and (max-width: 1570px) { + .format-designer .designer .section.desktop-four-column .section.link-layout .activity .action-menu .menubar .dropdown + .dropdown-menu .dropdown-subpanel .dropdown-menu, + .format-designer .designer .section.desktop-four-column .section.card-layout .activity .action-menu .menubar .dropdown + .dropdown-menu .dropdown-subpanel .dropdown-menu, + .format-designer .designer .section.desktop-four-column .section.circles-layout .activity .action-menu .menubar .dropdown + .dropdown-menu .dropdown-subpanel .dropdown-menu { + left: 0; + } +} + +@media (min-width: 576px) and (max-width: 1380px) { + .format-designer .designer .section.desktop-three-column .section.link-layout .activity .action-menu .menubar .dropdown + .dropdown-menu .dropdown-subpanel .dropdown-menu, + .format-designer .designer .section.desktop-three-column .section.card-layout .activity .action-menu .menubar .dropdown + .dropdown-menu .dropdown-subpanel .dropdown-menu, + .format-designer .designer .section.desktop-three-column .section.circles-layout .activity .action-menu .menubar .dropdown + .dropdown-menu .dropdown-subpanel .dropdown-menu { + left: 0; + } +} + +@media (min-width: 576px) and (max-width: 991px) { + .format-designer .designer .section.desktop-two-column .section.link-layout .activity .action-menu .menubar .dropdown + .dropdown-menu .dropdown-subpanel .dropdown-menu, + .format-designer .designer .section.desktop-two-column .section.card-layout .activity .action-menu .menubar .dropdown + .dropdown-menu .dropdown-subpanel .dropdown-menu, + .format-designer .designer .section.desktop-two-column .section.circles-layout .activity .action-menu .menubar .dropdown + .dropdown-menu .dropdown-subpanel .dropdown-menu { + left: 0; + } +} +/* End of Course Edit dropdown menu */ .format-designer .designer .section.list-layout .activity .aalink img.activityicon, .format-designer .designer .section.card-layout .activity .aalink img.activityicon { width: 40px; @@ -1187,22 +1239,23 @@ span.section-collapse-icon:before { .format-designer.editing .course-content ul.designer li.section .section-header-content .section-head-text .bulkselect { position: absolute; top: 15px; + left: -2rem; } .format-designer .designer .section .content .section.link-layout li.activity .activity-block .bulkselect { top: 10px; left: 10px; - z-index: 0; + z-index: 1; } .format-designer .designer .section .content .section.list-layout li.activity .activity-block .bulkselect { top: 2rem; - z-index: 0; + z-index: 1; } .format-designer .designer .section .content .section.card-layout li.activity .bulkselect { position: absolute; top: 20px; left: 20px; - z-index: 0; + z-index: 1; } .format-designer .designer.kanban-board .section .content .section.card-layout li.activity .bulkselect { left: 20px; @@ -1214,7 +1267,7 @@ span.section-collapse-icon:before { .format-designer .designer .section .content .section.circles-layout li.activity .activity-block .bulkselect { top: 10px; left: 10px; - z-index: 0; + z-index: 1; } .format-designer .designer .section .content .section li.activity .activity-block.designer { height: 100%; @@ -1223,6 +1276,10 @@ span.section-collapse-icon:before { display: flex; position: relative; } +.format-designer.editing .designer .section .content .section li.activity .activity-block.designer:hover { + background: none; + box-shadow: none; +} .format-designer .designer .section .content .section li.activity .activity-block.designer .activity-background-style { width: 100%; height: 100%; @@ -1230,7 +1287,7 @@ span.section-collapse-icon:before { position: absolute; top: 0; left: 0; - z-index: -1; + z-index: 0; } .format-designer .designer .section .content .section li.activity .activity-block.designer .contentwithoutlink { padding: 0; @@ -1282,8 +1339,9 @@ span.section-collapse-icon:before { .format-designer.editing .designer .section .content .section li.activity .mod-indent-outer > .icon { position: absolute; } -.format-designer.editing .activity-item:hover { - background: none; +.format-designer .activity-item, +.format-designer .activity-item.hiddenactivity { + background-color: transparent; } .format-designer .designer .section .content .section li.activity .badge-restricted { background: #ced4da; @@ -2416,7 +2474,7 @@ body.format-designer.editing .designer .section .content .section.card-layout li .format-designer .course-content ul.designer.kanban-board li.section .section-progress-info { margin-top: 10px; } -.format-designer .course-content ul.designer.kanban-board li.section .section-progress-info .progress { +.format-designer .course-content ul.designer.kanban-board .kanban-board-activities li.section .section-progress-info .progress { height: 12px; background: #fff; } @@ -2630,6 +2688,7 @@ body.format-designer.editing .designer .section .content .section.card-layout li } .format-designer .designer .section .content .section.horizontal-circles-layout li.activity .card { border: 0; + background-color: transparent; box-shadow: none; } .format-designer .designer .section .content .section.horizontal-circles-layout li.activity .card .card-body { @@ -2835,6 +2894,21 @@ body.format-designer.editing .designer .section .content .section.card-layout li .format-designer .course-content ul.course-type-flow.designer .section.main .section-header-content.flow-stack.collapsed { width: 400px; } + +/* Single section flow layout */ +.format-designer .course-content .single-section-layout ul.course-type-flow.designer li.section .right, +.format-designer .course-content .single-section-layout ul.course-type-flow.designer li.section .content { + display: none; +} +.format-designer .course-content .single-section-layout ul.course-type-flow.designer +.section.main + .section.main.section-flow-none .section-header-content, +.format-designer .course-content .single-section-layout ul.course-type-flow.designer +.section.main.section-flow-none + .section.main.section-flow-none .section-header-content { + margin-right: 0; +} +/* End of Single section flow layout */ + + .format-designer .designer.course-type-flow .section .content .section.card-layout li.activity .card.card-list { min-height: 400px; } @@ -3051,6 +3125,20 @@ body.format-designer.editing .designer .section .content .section.card-layout li left: 10px; } .format-designer .course-content ul.designer.course-type-flow li.section .section-header-content +.section-progress-info + .goto-section { + margin-bottom: 20px; +} +.format-designer.editing .course-content ul.designer li.section .section-header-content.flow-stack .section-progress-info { + max-width: none; + float: none; +} +.format-designer.editing .course-content ul.designer li.section .section-header-content.flow-stack +.section-progress-info .progress-bar { + max-width: 300px; + margin-left: auto; + margin-right: 15px; +} +.format-designer .course-content ul.designer.course-type-flow li.section .section-header-content .section-progress-info > div:not(.progress-donut) .progress { height: 12px; background: #fff; @@ -3264,7 +3352,11 @@ li.section.main.section-background-color:not(.section-header-image) @media (min-width: 768px) and (max-width: 991px) { .format-designer .course-content ul.course-type-flow.designer .section.main .section-header-content.flow-card-small.flow-stack, .format-designer .course-content ul.course-type-flow.designer .section.main .section-header-content.flow-card-medium.flow-stack, - .format-designer .course-content ul.course-type-flow.designer .section.main .section-header-content.flow-card-large.flow-stack { + .format-designer .course-content ul.course-type-flow.designer .section.main .section-header-content.flow-card-large.flow-stack, + .format-designer .course-content .single-section-layout ul.course-type-flow.designer + .section.main + .section.main.section-flow-none .section-header-content, + .format-designer .course-content .single-section-layout ul.course-type-flow.designer + .section.main.section-flow-none + .section.main.section-flow-none .section-header-content { width: 46%; } .format-designer .course-content ul.designer.course-type-flow li.section ul.section.img-text li.activity.flow-card-small { @@ -3281,7 +3373,11 @@ li.section.main.section-background-color:not(.section-header-image) @media (max-width: 767px) { .format-designer .course-content ul.course-type-flow.designer .section.main .section-header-content.flow-card-small.flow-stack, .format-designer .course-content ul.course-type-flow.designer .section.main .section-header-content.flow-card-medium.flow-stack, - .format-designer .course-content ul.course-type-flow.designer .section.main .section-header-content.flow-card-large.flow-stack { + .format-designer .course-content ul.course-type-flow.designer .section.main .section-header-content.flow-card-large.flow-stack, + .format-designer .course-content .single-section-layout ul.course-type-flow.designer + .section.main + .section.main.section-flow-none .section-header-content, + .format-designer .course-content .single-section-layout ul.course-type-flow.designer + .section.main.section-flow-none + .section.main.section-flow-none .section-header-content { width: 94%; } .format-designer .course-content ul.designer.course-type-flow li.section ul.section.img-text li.activity.flow-card-small { diff --git a/templates/courseformat/content.mustache b/templates/courseformat/content.mustache index cef1b70..3357f7d 100644 --- a/templates/courseformat/content.mustache +++ b/templates/courseformat/content.mustache @@ -189,11 +189,11 @@ {{> core_courseformat/local/content/sectionnavigation }} {{/ core_courseformat/local/content/sectionnavigation }} {{/sectionnavigation}} -
    - {{#singlesection}} - {{$content}} {{/content}} - {{/singlesection}} -
+
    + {{#singlesection}} + {{$content}} {{/content}} + {{/singlesection}} +
{{#sectionselector}} {{$ core_courseformat/local/content/sectionselector }} {{> core_courseformat/local/content/sectionselector }} @@ -202,9 +202,11 @@ {{/hasnavigation}} {{#numsections}} - {{$ core_courseformat/local/content/addsection}} - {{> core_courseformat/local/content/addsection}} - {{/ core_courseformat/local/content/addsection}} + {{^singlesection}} + {{$ core_courseformat/local/content/addsection}} + {{> core_courseformat/local/content/addsection}} + {{/ core_courseformat/local/content/addsection}} + {{/singlesection}} {{/numsections}} {{#bulkedittools}} {{$ core_courseformat/local/content/bulkedittools}} diff --git a/templates/courseformat/content/section/header.mustache b/templates/courseformat/content/section/header.mustache index fd865c0..8c1245b 100644 --- a/templates/courseformat/content/section/header.mustache +++ b/templates/courseformat/content/section/header.mustache @@ -36,7 +36,7 @@ {{/ core_courseformat/local/content/section/bulkselect }} {{/sectionbulk}} -{{^section.hidesectiontitle}} +{{^hidesectiontitle}} {{#headerdisplaymultipage}}

{{{title}}} @@ -57,4 +57,4 @@ {{/sitehome}} {{/headerdisplaymultipage}} -{{/section.hidesectiontitle}} +{{/hidesectiontitle}} diff --git a/templates/section.mustache b/templates/section.mustache index 64eb55d..9d299f5 100644 --- a/templates/section.mustache +++ b/templates/section.mustache @@ -86,6 +86,7 @@ "highlightedlabel" : "Highlighted" } }} + {{{sectionhead}}} {{$ format_designer/section_layout }} diff --git a/templates/section_layout.mustache b/templates/section_layout.mustache index 7c45f35..29d02db 100644 --- a/templates/section_layout.mustache +++ b/templates/section_layout.mustache @@ -115,7 +115,7 @@ data-target="{{#sectioncardcontentdirect}}_blank{{/sectioncardcontentdirect}}" d {{> core_courseformat/local/content/section/badges }} {{/ core_courseformat/local/content/section/badges }} - {{^section.hidesectiontitle}} + {{^hidesectiontitle}} {{^flowcourse}} {{#section.categorisetitle}}
@@ -123,7 +123,7 @@ data-target="{{#sectioncardcontentdirect}}_blank{{/sectioncardcontentdirect}}" d
{{/section.categorisetitle}} {{/flowcourse}} - {{/section.hidesectiontitle}} + {{/hidesectiontitle}} {{! End of section badges }} diff --git a/tests/behat/behat_format_designer.php b/tests/behat/behat_format_designer.php index 60a51da..ee3f5f2 100644 --- a/tests/behat/behat_format_designer.php +++ b/tests/behat/behat_format_designer.php @@ -325,17 +325,23 @@ public function get_activity_idendifier_slug($activityidendifier) { */ public function i_turn_block_editing_mode_on() { global $CFG; - - if ($CFG->branch >= "400") { - $this->execute('behat_forms::i_set_the_field_to', [get_string('editmode'), 1]); - if (!$this->running_javascript()) { - $this->execute('behat_general::i_click_on', [ - get_string('setmode', 'core'), - 'button', - ]); - } - } else { - $this->execute('behat_general::i_click_on', ['Blocks editing on', 'button']); + $this->execute('behat_forms::i_set_the_field_to', [get_string('editmode'), 1]); + if (!$this->running_javascript()) { + $this->execute('behat_general::i_click_on', [ + get_string('setmode', 'core'), + 'button', + ]); } } + + /** + * Turns block editing mode on. + * @Given I check the designer section general section + */ + public function i_check_the_designer_section_general_section() { + global $CFG; + $this->execute('behat_forms::the_field_matches_value', ["Section name" , ""]); + $this->execute('behat_general::assert_page_contains_text', ["General"]); + } + } diff --git a/tests/behat/edit_delete_sections.feature b/tests/behat/edit_delete_sections.feature index 1b199f9..63bd082 100644 --- a/tests/behat/edit_delete_sections.feature +++ b/tests/behat/edit_delete_sections.feature @@ -10,7 +10,7 @@ Feature: Sections can be edited and deleted in designer format | teacher1 | Teacher | 1 | teacher1@example.com | And the following "courses" exist: | fullname | shortname | format | coursedisplay | numsections | - | Course 1 | C1 | designer | 0 | 5 | + | Course 1 | C1 | designer | 0 | 5 | And the following "activities" exist: | activity | name | intro | course | idnumber | section | | assign | Test assignment name | Test assignment description | C1 | assign1 | 0 | @@ -25,32 +25,13 @@ Feature: Sections can be edited and deleted in designer format Scenario: View the default name of the general section in designer format When I edit the section "0" - Then the field "Custom" matches value "0" - And the field "New value for Section name" matches value "General" - - Scenario: Edit the default name of the general section in designer format - When I edit the section "0" and I fill the form with: - | Custom | 1 | - | New value for Section name | This is the general section | - Then I should see "This is the general section" in the "li#section-0" "css_element" - - Scenario: View the default name of the second section in designer format - When I edit the section "2" - Then the field "Custom" matches value "0" - And the field "New value for Section name" matches value "Designer section 2" + Then I check the designer section general section Scenario: Edit section summary in designer format When I edit the section "2" and I fill the form with: | Summary | Welcome to section 2 | Then I should see "Welcome to section 2" in the "li#section-2" "css_element" - Scenario: Edit section default name in designer format - When I edit the section "2" and I fill the form with: - | Custom | 1 | - | New value for Section name | This is the second section | - Then I should see "This is the second section" in the "li#section-2" "css_element" - And I should not see "Designer section 2" in the "li#section-2" "css_element" - @javascript Scenario: Inline edit section name in designer format When I set the field "Edit designer section name" in the "li#section-1" "css_element" to "Midterm evaluation" @@ -67,20 +48,11 @@ Feature: Sections can be edited and deleted in designer format And I should not see "Designer section 5" And I should see "Designer section 4" - Scenario: Deleting the middle section in designer format - When I delete section "4" - Then I should see "Are you absolutely sure you want to completely delete \"Designer section 4\" and all the activities it contains?" - And I press "Delete" - Then I should not see "Designer section 5" - And I should not see "Test chat name" - And I should see "Test choice name" in the "li#section-4" "css_element" - And I should see "Designer section 4" - @javascript Scenario: Adding sections in designer format - When I follow "Add designer sections" + When I click on "a[data-action='addSection']" "css_element" And I should see "Designer section 6" in the "li#section-6" "css_element" And "li#section-7" "css_element" should not exist - And I follow "Add designer sections" + And I click on "a[data-action='addSection']" "css_element" And I should see "Designer section 7" in the "li#section-7" "css_element" And "li#section-8" "css_element" should not exist diff --git a/tests/lib_test.php b/tests/lib_test.php index 6841adb..0ac2284 100644 --- a/tests/lib_test.php +++ b/tests/lib_test.php @@ -250,46 +250,6 @@ public function test_default_course_enddate() { $weeksformat = course_get_format($course->id); $this->assertEquals($enddate, $weeksformat->get_default_course_enddate($courseform->get_quick_form())); - - } - - /** - * Test for get_view_url() to ensure that the url is only given for the correct cases. - * @covers ::get_view_url - * @return void - */ - public function test_get_view_url() { - global $CFG; - $this->resetAfterTest(); - - $linkcoursesections = $CFG->linkcoursesections; - - // Generate a course with two sections (0 and 1) and two modules. - $generator = $this->getDataGenerator(); - $course1 = $generator->create_course(['format' => 'designer']); - course_create_sections_if_missing($course1, [0, 1]); - - $data = (object)['id' => $course1->id]; - $format = course_get_format($course1); - $format->update_course_format_options($data); - - // In page. - $CFG->linkcoursesections = 0; - $this->assertNotEmpty($format->get_view_url(null)); - $this->assertNotEmpty($format->get_view_url(0)); - $this->assertNotEmpty($format->get_view_url(1)); - $CFG->linkcoursesections = 1; - $this->assertNotEmpty($format->get_view_url(null)); - $this->assertNotEmpty($format->get_view_url(0)); - $this->assertNotEmpty($format->get_view_url(1)); - - // Navigation. - $CFG->linkcoursesections = 0; - $this->assertNull($format->get_view_url(1, ['navigation' => 1])); - $this->assertNull($format->get_view_url(0, ['navigation' => 1])); - $CFG->linkcoursesections = 1; - $this->assertNotEmpty($format->get_view_url(1, ['navigation' => 1])); - $this->assertNotEmpty($format->get_view_url(0, ['navigation' => 1])); } /** diff --git a/tests/options_test.php b/tests/options_test.php index 5eb0d86..b6df197 100644 --- a/tests/options_test.php +++ b/tests/options_test.php @@ -40,13 +40,22 @@ */ class options_test extends \advanced_testcase { + /** + * @var object + */ + public $course; + + /** + * @var object + */ + public $coursecontext; + /** * Setup testing cases. * * @return void */ public function setUp(): void { - global $CFG; $this->resetAfterTest(true); // Remove the output display of cron task. diff --git a/version.php b/version.php index aa7519d..3a35c6b 100644 --- a/version.php +++ b/version.php @@ -24,10 +24,9 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2024060500; // The current plugin version (Date: YYYYMMDDXX). +$plugin->version = 2024061300; // The current plugin version (Date: YYYYMMDDXX). $plugin->requires = 2020061500; // Requires this Moodle version. $plugin->component = 'format_designer'; // Full name of the plugin (used for diagnostics). $plugin->release = 'Version 1.5'; -$plugin->incompatible = [404]; -$plugin->supported = [400, 403]; +$plugin->supported = [404, 404]; $plugin->maturity = MATURITY_STABLE; From 47565f4c9353f37fd707e58bc918a0595646ecf1 Mon Sep 17 00:00:00 2001 From: Abineshsuseendran Date: Fri, 14 Jun 2024 17:35:46 +0530 Subject: [PATCH 02/14] Update the plug-in CI. --- .github/workflows/moodle-ci.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/moodle-ci.yml b/.github/workflows/moodle-ci.yml index 92a0ddf..beca14d 100644 --- a/.github/workflows/moodle-ci.yml +++ b/.github/workflows/moodle-ci.yml @@ -28,17 +28,17 @@ jobs: fail-fast: false matrix: include: - - php: '8.0' - moodle-branch: 'MOODLE_403_STABLE' - database: 'pgsql' - - php: '8.0' - moodle-branch: 'MOODLE_402_STABLE' + - php: '8.2' + moodle-branch: 'MOODLE_404_STABLE' database: 'mariadb' - - php: '8.0' - moodle-branch: 'MOODLE_401_STABLE' + - php: '8.2' + moodle-branch: 'MOODLE_404_STABLE' + database: 'pgsql' + - php: '8.1' + moodle-branch: 'MOODLE_404_STABLE' database: 'pgsql' - - php: '7.4' - moodle-branch: 'MOODLE_400_STABLE' + - php: '8.1' + moodle-branch: 'MOODLE_404_STABLE' database: 'mariadb' steps: From 148039868a01c324030219e594e6cf5f46fc5134 Mon Sep 17 00:00:00 2001 From: Abineshsuseendran Date: Fri, 14 Jun 2024 17:47:04 +0530 Subject: [PATCH 03/14] Fixed the behat issues. --- lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib.php b/lib.php index b501b8f..40c65b5 100644 --- a/lib.php +++ b/lib.php @@ -2062,7 +2062,7 @@ function format_designer_timemanagement_installed() { function format_designer_editsetting_style($page) { if ($page->user_is_editing()) { // Fixed the overlapping issue by make this css rule as important. Moodle CI doesn't allow important. - $style .= '.format-designer .course-content ul.designer .kanban-board-activities li.section:first-child .right .dropdown + $style = '.format-designer .course-content ul.designer .kanban-board-activities li.section:first-child .right .dropdown .dropdown-menu .dropdown-subpanel .dropdown-menu {'; $style .= 'left: 100% !important;'; $style .= '}'; From a325df789fe7ed545c9ee247b73d384439cf2445 Mon Sep 17 00:00:00 2001 From: Vasanth LMSACE Date: Wed, 19 Jun 2024 19:44:29 +0530 Subject: [PATCH 04/14] Bug fixes - DES-871, DES-869, DES-872, DES-868, DES-874, DES-870. --- classes/output/courseformat/state/section.php | 2 +- classes/output/renderer.php | 7 ++--- settings.php | 29 +++++++++++++++++ styles.css | 31 ++++++++++++------- templates/cm_completion.mustache | 2 +- templates/course_time_management.mustache | 4 +-- version.php | 2 +- 7 files changed, 56 insertions(+), 21 deletions(-) diff --git a/classes/output/courseformat/state/section.php b/classes/output/courseformat/state/section.php index de9728a..e67c0a5 100644 --- a/classes/output/courseformat/state/section.php +++ b/classes/output/courseformat/state/section.php @@ -53,7 +53,7 @@ public function export_for_template(\renderer_base $output): stdClass { $indexcollapsed = true; } } - $sectionurlinfo = course_get_url($course, $section->section, ['navigation' => true]); + $sectionurlinfo = course_get_url($course, $section->section, ['navigation' => false]); $sectionurl = ''; if ($sectionurlinfo instanceof moodle_url) { $sectionurl = $sectionurlinfo->out(false); diff --git a/classes/output/renderer.php b/classes/output/renderer.php index 99e16ed..d5e3c6d 100644 --- a/classes/output/renderer.php +++ b/classes/output/renderer.php @@ -460,7 +460,6 @@ public function course_header_metadata_details(\stdClass $course, bool $dataonly // Get course staffs to show on course header. $coursestaffs = helper::create()->get_course_staff_users($course); - $data = [ 'course' => $course, 'enrolmentstartdate' => ($enrolmentstartdate) ? $enrolstartdate : '', @@ -1491,11 +1490,11 @@ public function course_section_updated_cm_item( public function get_flow_size($course) { $sizeclass = ''; if ($course->flowsize == 1) { - $sizeclass = 'flow-card-medium'; + $sizeclass = 'flow-card-medium '; } else if ($course->flowsize == 2) { - $sizeclass = 'flow-card-large'; + $sizeclass = 'flow-card-large '; } else { - $sizeclass = 'flow-card-small'; + $sizeclass = 'flow-card-small '; } $flowsizeclass = isset($course->flowsize) ? $sizeclass : ''; return $flowsizeclass; diff --git a/settings.php b/settings.php index 683d397..d242f48 100644 --- a/settings.php +++ b/settings.php @@ -147,6 +147,35 @@ get_string('modtrimlength_desc', 'format_designer'), 23, PARAM_INT); $activitypage->add($setting); + + // Activity elements list to manage the visibility - Activity page continue. + $elements = [ + 'icon' => 1, + 'visits' => 4, + 'calltoaction' => 4, + 'title' => 1, + 'description' => 1, + 'modname' => 4, + 'completionbadge' => 1, + ]; + + + $choice = [ + 1 => get_string('show'), + 0 => get_string('hide'), + 2 => get_string('showonhover', 'format_designer'), + 3 => get_string('hideonhover', 'format_designer'), + 4 => get_string('remove'), + ]; + foreach ($elements as $element => $defaultvalue) { + $name = 'format_designer/activityelements_'.$element; + $title = get_string('activity:'.$element, 'format_designer'); + $desc = ''; + $default = ['value' => $defaultvalue, 'fix' => 0]; + $setting = new admin_setting_configselect_with_advanced($name, $title, $desc, $default, $choice); + $activitypage->add($setting); + } + if (format_designer_has_pro() && file_exists($CFG->dirroot.'/local/designer/setting.php')) { require_once($CFG->dirroot.'/local/designer/setting.php'); diff --git a/styles.css b/styles.css index e3e3e3c..29edc06 100644 --- a/styles.css +++ b/styles.css @@ -189,7 +189,6 @@ margin-top: 10px; } .format-designer .course-content ul.designer.course-type-flow li.section .availability-section-block + div { - max-height: 66%; overflow: hidden; text-overflow: ellipsis; -webkit-box-orient: vertical; @@ -3085,6 +3084,8 @@ body.format-designer.editing .designer .section .content .section.card-layout li } .format-designer .course-content ul.designer.course-type-flow { margin-top: 30px; + display: flex; + flex-wrap: wrap; } .format-designer .course-content ul.course-type-flow.designer .section.main .section-content-wrapper { display: contents; @@ -3330,12 +3331,15 @@ li.section.main.section-background-color:not(.section-header-image) } .format-designer .course-content ul.designer.course-type-flow li.section ul.section.img-text li.activity.flow-card-small { width: 320px; + max-width: 320px; } .format-designer .course-content ul.designer.course-type-flow li.section ul.section.img-text li.activity.flow-card-medium { width: 360px; + max-width: 360px; } .format-designer .course-content ul.designer.course-type-flow li.section ul.section.img-text li.activity.flow-card-large { width: 400px; + max-width: 400px; } .format-designer .designer.course-type-flow .section .content .section.card-layout li.activity.flow-card-small .card.card-list { min-height: 320px; @@ -3357,16 +3361,16 @@ li.section.main.section-background-color:not(.section-header-image) .section.main + .section.main.section-flow-none .section-header-content, .format-designer .course-content .single-section-layout ul.course-type-flow.designer .section.main.section-flow-none + .section.main.section-flow-none .section-header-content { - width: 46%; + width: 47%; } .format-designer .course-content ul.designer.course-type-flow li.section ul.section.img-text li.activity.flow-card-small { - width: 46%; + width: 47%; } .format-designer .course-content ul.designer.course-type-flow li.section ul.section.img-text li.activity.flow-card-medium { - width: 46%; + width: 47%; } .format-designer .course-content ul.designer.course-type-flow li.section ul.section.img-text li.activity.flow-card-large { - width: 46%; + width: 47%; } } @@ -3378,16 +3382,19 @@ li.section.main.section-background-color:not(.section-header-image) .section.main + .section.main.section-flow-none .section-header-content, .format-designer .course-content .single-section-layout ul.course-type-flow.designer .section.main.section-flow-none + .section.main.section-flow-none .section-header-content { - width: 94%; + width: 97%; } - .format-designer .course-content ul.designer.course-type-flow li.section ul.section.img-text li.activity.flow-card-small { - width: 94%; + .format-designer .course-content ul.designer.course-type-flow li.section ul.section.img-text li.activity.flow-card-small + .activity-block { + width: 97%; } - .format-designer .course-content ul.designer.course-type-flow li.section ul.section.img-text li.activity.flow-card-medium { - width: 94%; + .format-designer .course-content ul.designer.course-type-flow li.section ul.section.img-text li.activity.flow-card-medium + .activity-block { + width: 97%; } - .format-designer .course-content ul.designer.course-type-flow li.section ul.section.img-text li.activity.flow-card-large { - width: 94%; + .format-designer .course-content ul.designer.course-type-flow li.section ul.section.img-text li.activity.flow-card-large + .activity-block { + width: 97%; } } diff --git a/templates/cm_completion.mustache b/templates/cm_completion.mustache index a0c84fa..e34232c 100644 --- a/templates/cm_completion.mustache +++ b/templates/cm_completion.mustache @@ -38,7 +38,7 @@ {{^ispreview}} {{! Show completion info for users/students }} {{#completiontrackingmanual}} -
+ {{#completioncheckbox}} {{{completioncheckbox.inputfield}}} {{/completioncheckbox}} {{#completionincomplete}}