Skip to content

Commit

Permalink
MDL-81683 core_courseformat: Add subsection to the move activity modal
Browse files Browse the repository at this point in the history
* Add subsection in the tree hierarchy
* Split the mustache templates to avoid repetitive code
  • Loading branch information
laurentdavid committed Jul 17, 2024
1 parent fd487cd commit 7f7d4a9
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 74 deletions.
2 changes: 1 addition & 1 deletion course/format/amd/build/local/content/actions.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion course/format/amd/build/local/content/actions.min.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion course/format/amd/build/local/courseeditor/exporter.min.js

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

Large diffs are not rendered by default.

63 changes: 52 additions & 11 deletions course/format/amd/src/local/content/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export default class extends BaseComponent {
};
// Component css classes.
this.classes = {
DISABLED: `text-body`,
DISABLED: `disabled`,
ITALIC: `font-italic`,
};
}
Expand Down Expand Up @@ -357,16 +357,15 @@ export default class extends BaseComponent {
// Open the cm section node if possible (Bootstrap 4 uses jQuery to interact with collapsibles).
// All jQuery in this code can be replaced when MDL-71979 is integrated.
cmIds.forEach(cmId => {
const currentElement = modalBody.querySelector(`${this.selectors.CMLINK}[data-id='${cmId}']`);
const sectionnode = currentElement.closest(this.selectors.SECTIONNODE);
const toggler = jQuery(sectionnode).find(this.selectors.MODALTOGGLER);
let collapsibleId = toggler.data('target') ?? toggler.attr('href');
if (collapsibleId) {
// We cannot be sure we have # in the id element name.
collapsibleId = collapsibleId.replace('#', '');
const expandNode = modalBody.querySelector(`#${collapsibleId}`);
jQuery(expandNode).collapse('show');
const cmInfo = this.reactive.get('cm', cmId);
let selector;
if (!cmInfo.hasdelegatedsection) {
selector = `${this.selectors.CMLINK}[data-id='${cmId}']`;
} else {
selector = `${this.selectors.SECTIONLINK}[data-id='${cmInfo.sectionid}']`;
}
const currentElement = modalBody.querySelector(selector);
this._expandCmMoveModalParentSections(modalBody, currentElement);
});

modalBody.addEventListener('click', (event) => {
Expand All @@ -381,6 +380,7 @@ export default class extends BaseComponent {

let targetSectionId;
let targetCmId;
let droppedCmIds = [...cmIds];
if (target.dataset.for == 'cm') {
const dropData = exporter.cmDraggableData(this.reactive.state, target.dataset.id);
targetSectionId = dropData.sectionid;
Expand All @@ -390,13 +390,54 @@ export default class extends BaseComponent {
targetSectionId = target.dataset.id;
targetCmId = section?.cmlist[0];
}
this.reactive.dispatch('cmMove', cmIds, targetSectionId, targetCmId);
const section = this.reactive.get('section', targetSectionId);
if (section.component) {
// Remove cmIds which are not allowed to be moved to this delegated section (mostly
// all other delegated cm).
droppedCmIds = droppedCmIds.filter(cmId => {
const cmInfo = this.reactive.get('cm', cmId);
return !cmInfo.hasdelegatedsection;
});
}
if (droppedCmIds.length === 0) {
return; // No cm to move.
}
this.reactive.dispatch('cmMove', droppedCmIds, targetSectionId, targetCmId);
this._destroyModal(modal, editTools);
});

pendingModalReady.resolve();
}

/**
* Expand all the modal tree branches that contains the element.
*
* Bootstrap 4 uses jQuery to interact with collapsibles.
* All jQuery in this code can be replaced when MDL-71979 is integrated.
*
* @private
* @param {HTMLElement} modalBody the modal body element
* @param {HTMLElement} element the element to display
*/
_expandCmMoveModalParentSections(modalBody, element) {
const sectionnode = element.closest(this.selectors.SECTIONNODE);
if (!sectionnode) {
return;
}

const toggler = jQuery(sectionnode).find(this.selectors.MODALTOGGLER);
let collapsibleId = toggler.data('target') ?? toggler.attr('href');
if (collapsibleId) {
// We cannot be sure we have # in the id element name.
collapsibleId = collapsibleId.replace('#', '');
const expandNode = modalBody.querySelector(`#${collapsibleId}`);
jQuery(expandNode).collapse('show');
}

// Section are a tree structure, we need to expand all the parents.
this._expandCmMoveModalParentSections(modalBody, sectionnode.parentElement);
}

/**
* Handle a create section request.
*
Expand Down
1 change: 1 addition & 0 deletions course/format/amd/src/local/courseeditor/exporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export default class {
const cm = {
...cminfo,
isactive: false,
sectioninfo: false, // Init to false to prevent mustache recursion loops.
};
if (cminfo.hasdelegatedsection) {
const sectioninfo = state.section.get(cminfo.delegatesectionid);
Expand Down
87 changes: 28 additions & 59 deletions course/format/templates/local/content/movecm.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,34 @@
{
"name": "Glossary of characters",
"id": "10",
"url": "#"
"url": "#",
"sectioninfo": false
},
{
"name": "World Cinema forum",
"id": "11",
"url": "#"
"url": "#",
"sectioninfo": {
"title": "World Cinema forum",
"id": "11",
"number": "5",
"sectionurl": "#",
"hascms": true,
"cms": [
{
"name": "Announcements",
"id": "12",
"url": "#",
"sectioninfo": false
}
]
}
},
{
"name": "Announcements",
"id": "12",
"url": "#"
"url": "#",
"sectioninfo": false
}
]
},
Expand All @@ -58,17 +75,20 @@
{
"name": "Resources",
"id": "13",
"url": "#"
"url": "#",
"sectioninfo": false
},
{
"name": "Studying City of God by Stephen Smith Bergman-Messerschmidt",
"id": "14",
"url": "#"
"url": "#",
"sectioninfo": false
},
{
"name": "Film education study guide",
"id": "15",
"url": "#"
"url": "#",
"sectioninfo": false
}
]
}
Expand All @@ -79,59 +99,8 @@
<p data-for="sectionname">{{information}}:</p>
<nav class="collapse-list" id="destination-selector" role="tree">
{{#sections}}
<div data-for="sectionnode"
role="treeitem"
>
<div class="collapse-list-item d-flex"
id="movemodalsection{{number}}"
data-for="section_item"
>
<a data-toggle="collapse"
href="#movemodalcollapse{{number}}"
aria-expanded="false"
aria-controls="movemodalcollapse{{number}}"
class="collapse-list-link icons-collapse-expand collapsed"
>
<span class="collapsed-icon icon-no-margin mr-1"
data-toggle="tooltip" title="{{#str}} expand, core {{/str}}">
{{#pix}} t/collapsed, core {{/pix}}
<span class="sr-only">{{#str}} expand, core {{/str}}</span>
</span>
<span class="expanded-icon icon-no-margin mr-1"
data-toggle="tooltip" title="{{#str}} collapse, core {{/str}}">
{{#pix}} t/expanded, core {{/pix}}
<span class="sr-only">{{#str}} collapse, core {{/str}}</span>
</span>
</a>
<a href="#"
class="collapse-list-link text-truncate"
data-for="section"
data-id="{{id}}"
data-number="{{number}}"
>
{{{title}}}
</a>
<span class="dragicon ml-auto">{{#pix}}i/dragdrop{{/pix}}</span>
<div data-for="sectionnode" role="treeitem">
{{> core_courseformat/local/content/movecmsection}}
</div>
<div id="movemodalcollapse{{number}}"
class="collapse-list-item-content collapse"
aria-labelledby="movemodalsection{{number}}"
role="group"
>
<ul class="unlist" data-for="cmlist" data-id="{{id}}">
{{#cms}}
<li class="collapse-list-item d-flex" role="treeitem">
<a class="collapse-list-link text-truncate"
href="#"
data-for="cm"
data-id="{{id}}"
>
{{{name}}}
</a>
</li>
{{/cms}}
</ul>
</div>
</div>
{{/sections}}
</nav>
Loading

0 comments on commit 7f7d4a9

Please sign in to comment.