Proyectos de Subversion Moodle

Rev

Rev 1 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1 Rev 1441
Línea 24... Línea 24...
24
 * @copyright  2021 Ferran Recio <ferran@moodle.com>
24
 * @copyright  2021 Ferran Recio <ferran@moodle.com>
25
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26
 */
26
 */
Línea 27... Línea 27...
27
 
27
 
-
 
28
import {BaseComponent} from 'core/reactive';
-
 
29
import {eventTypes} from 'core/local/inplace_editable/events';
-
 
30
import Collapse from 'theme_boost/bootstrap/collapse';
28
import {BaseComponent} from 'core/reactive';
31
import log from 'core/log';
29
import Modal from 'core/modal';
32
import Modal from 'core/modal';
30
import ModalSaveCancel from 'core/modal_save_cancel';
33
import ModalSaveCancel from 'core/modal_save_cancel';
-
 
34
import ModalDeleteCancel from 'core/modal_delete_cancel';
31
import ModalDeleteCancel from 'core/modal_delete_cancel';
35
import ModalCopyToClipboard from 'core/modal_copy_to_clipboard';
32
import ModalEvents from 'core/modal_events';
36
import ModalEvents from 'core/modal_events';
33
import Templates from 'core/templates';
37
import Templates from 'core/templates';
34
import {prefetchStrings} from 'core/prefetch';
38
import {prefetchStrings} from 'core/prefetch';
35
import {getString} from 'core/str';
39
import {getString} from 'core/str';
36
import {getFirst} from 'core/normalise';
40
import {getFirst} from 'core/normalise';
37
import {toggleBulkSelectionAction} from 'core_courseformat/local/content/actions/bulkselection';
41
import {toggleBulkSelectionAction} from 'core_courseformat/local/content/actions/bulkselection';
38
import * as CourseEvents from 'core_course/events';
42
import * as CourseEvents from 'core_course/events';
39
import Pending from 'core/pending';
43
import Pending from 'core/pending';
40
import ContentTree from 'core_courseformat/local/courseeditor/contenttree';
44
import ContentTree from 'core_courseformat/local/courseeditor/contenttree';
41
// The jQuery module is only used for interacting with Boostrap 4. It can we removed when MDL-71979 is integrated.
45
// The jQuery module is only used for interacting with Boostrap 4. It can we removed when MDL-71979 is integrated.
Línea 42... Línea 46...
42
import jQuery from 'jquery';
46
import Notification from "core/notification";
43
 
47
 
Línea 44... Línea 48...
44
// Load global strings.
48
// Load global strings.
Línea 73... Línea 77...
73
            ACTIONLINK: `[data-action]`,
77
            ACTIONLINK: `[data-action]`,
74
            // Move modal selectors.
78
            // Move modal selectors.
75
            SECTIONLINK: `[data-for='section']`,
79
            SECTIONLINK: `[data-for='section']`,
76
            CMLINK: `[data-for='cm']`,
80
            CMLINK: `[data-for='cm']`,
77
            SECTIONNODE: `[data-for='sectionnode']`,
81
            SECTIONNODE: `[data-for='sectionnode']`,
78
            MODALTOGGLER: `[data-toggle='collapse']`,
82
            MODALTOGGLER: `[data-bs-toggle='collapse']`,
79
            ADDSECTION: `[data-action='addSection']`,
83
            ADDSECTION: `[data-action='addSection']`,
80
            CONTENTTREE: `#destination-selector`,
84
            CONTENTTREE: `#destination-selector`,
81
            ACTIONMENU: `.action-menu`,
85
            ACTIONMENU: `.action-menu`,
82
            ACTIONMENUTOGGLER: `[data-toggle="dropdown"]`,
86
            ACTIONMENUTOGGLER: `[data-bs-toggle="dropdown"]`,
83
            // Availability modal selectors.
87
            // Availability modal selectors.
84
            OPTIONSRADIO: `[type='radio']`,
88
            OPTIONSRADIO: `[type='radio']`,
-
 
89
            COURSEADDSECTION: `#course-addsection`,
-
 
90
            MAXSECTIONSWARNING: `[data-region='max-sections-warning']`,
-
 
91
            ADDSECTIONREGION: `[data-region='section-addsection']`,
85
        };
92
        };
86
        // Component css classes.
93
        // Component css classes.
87
        this.classes = {
94
        this.classes = {
88
            DISABLED: `text-body`,
95
            DISABLED: `disabled`,
89
            ITALIC: `font-italic`,
96
            ITALIC: `fst-italic`,
-
 
97
            DISPLAYNONE: `d-none`,
90
        };
98
        };
91
    }
99
    }
Línea 92... Línea 100...
92
 
100
 
93
    /**
101
    /**
Línea 123... Línea 131...
123
        this.addEventListener(
131
        this.addEventListener(
124
            this.element,
132
            this.element,
125
            CourseEvents.sectionRefreshed,
133
            CourseEvents.sectionRefreshed,
126
            () => this._checkSectionlist({state})
134
            () => this._checkSectionlist({state})
127
        );
135
        );
-
 
136
        // Any inplace editable update needs state refresh.
-
 
137
        this.addEventListener(
-
 
138
            this.element,
-
 
139
            eventTypes.elementUpdated,
-
 
140
            this._inplaceEditableHandler
-
 
141
        );
128
    }
142
    }
Línea 129... Línea 143...
129
 
143
 
130
    /**
144
    /**
131
     * Return the component watchers.
145
     * Return the component watchers.
Línea 184... Línea 198...
184
        // Disable "add section" actions if the course max sections has been exceeded.
198
        // Disable "add section" actions if the course max sections has been exceeded.
185
        this._setAddSectionLocked(state.course.sectionlist.length > state.course.maxsections);
199
        this._setAddSectionLocked(state.course.sectionlist.length > state.course.maxsections);
186
    }
200
    }
Línea 187... Línea 201...
187
 
201
 
-
 
202
    /**
-
 
203
     * Handle inplace editable updates.
-
 
204
     *
-
 
205
     * @param {Event} event the triggered event
-
 
206
     * @private
-
 
207
     */
-
 
208
    _inplaceEditableHandler(event) {
-
 
209
        const itemtype = event.detail?.ajaxreturn?.itemtype;
-
 
210
        const itemid = parseInt(event.detail?.ajaxreturn?.itemid);
-
 
211
        if (!Number.isFinite(itemid) || !itemtype) {
-
 
212
            return;
-
 
213
        }
-
 
214
 
-
 
215
        if (itemtype === 'activityname') {
-
 
216
            this.reactive.dispatch('cmState', [itemid]);
-
 
217
            return;
-
 
218
        }
-
 
219
        // Sections uses sectionname for normal sections and sectionnamenl for the no link sections.
-
 
220
        if (itemtype === 'sectionname' || itemtype === 'sectionnamenl') {
-
 
221
            this.reactive.dispatch('sectionState', [itemid]);
-
 
222
            return;
-
 
223
        }
-
 
224
    }
-
 
225
 
188
    /**
226
    /**
189
     * Return the ids represented by this element.
227
     * Return the ids represented by this element.
190
     *
228
     *
191
     * Depending on the dataset attributes the action could represent a single id
229
     * Depending on the dataset attributes the action could represent a single id
192
     * or a bulk actions with all the current selected ids.
230
     * or a bulk actions with all the current selected ids.
Línea 275... Línea 313...
275
            true
313
            true
276
        );
314
        );
Línea 277... Línea 315...
277
 
315
 
278
        // Capture click.
316
        // Capture click.
279
        modalBody.addEventListener('click', (event) => {
317
        modalBody.addEventListener('click', (event) => {
280
            const target = event.target;
318
            const target = event.target.closest('a');
281
            if (!target.matches('a') || target.dataset.for != 'section' || target.dataset.id === undefined) {
319
            if (!target || target.dataset.for != 'section' || target.dataset.id === undefined) {
282
                return;
320
                return;
283
            }
321
            }
284
            if (target.getAttribute('aria-disabled')) {
322
            if (target.getAttribute('aria-disabled')) {
285
                return;
323
                return;
Línea 320... Línea 358...
320
        if (cmIds.length == 1) {
358
        if (cmIds.length == 1) {
321
            const cmInfo = this.reactive.get('cm', cmIds[0]);
359
            const cmInfo = this.reactive.get('cm', cmIds[0]);
322
            data.cmid = cmInfo.id;
360
            data.cmid = cmInfo.id;
323
            data.cmname = cmInfo.name;
361
            data.cmname = cmInfo.name;
324
            data.information = await this.reactive.getFormatString('cmmove_info', data.cmname);
362
            data.information = await this.reactive.getFormatString('cmmove_info', data.cmname);
-
 
363
            if (cmInfo.hasdelegatedsection) {
-
 
364
                titleText = this.reactive.getFormatString('cmmove_subsectiontitle');
-
 
365
            } else {
325
            titleText = this.reactive.getFormatString('cmmove_title');
366
                titleText = this.reactive.getFormatString('cmmove_title');
-
 
367
            }
326
        } else {
368
        } else {
327
            data.information = await this.reactive.getFormatString('cmsmove_info', cmIds.length);
369
            data.information = await this.reactive.getFormatString('cmsmove_info', cmIds.length);
328
            titleText = this.reactive.getFormatString('cmsmove_title');
370
            titleText = this.reactive.getFormatString('cmsmove_title');
329
        }
371
        }
Línea 352... Línea 394...
352
                COLLAPSE: this.selectors.MODALTOGGLER,
394
                COLLAPSE: this.selectors.MODALTOGGLER,
353
                ENTER: this.selectors.SECTIONLINK,
395
                ENTER: this.selectors.SECTIONLINK,
354
            }
396
            }
355
        );
397
        );
Línea 356... Línea -...
356
 
-
 
357
        // Open the cm section node if possible (Bootstrap 4 uses jQuery to interact with collapsibles).
-
 
358
        // All jQuery in this code can be replaced when MDL-71979 is integrated.
398
 
359
        cmIds.forEach(cmId => {
399
        cmIds.forEach(cmId => {
360
            const currentElement = modalBody.querySelector(`${this.selectors.CMLINK}[data-id='${cmId}']`);
400
            const cmInfo = this.reactive.get('cm', cmId);
361
            const sectionnode = currentElement.closest(this.selectors.SECTIONNODE);
401
            let selector;
362
            const toggler = jQuery(sectionnode).find(this.selectors.MODALTOGGLER);
402
            if (!cmInfo.hasdelegatedsection) {
363
            let collapsibleId = toggler.data('target') ?? toggler.attr('href');
403
                selector = `${this.selectors.CMLINK}[data-id='${cmId}']`;
364
            if (collapsibleId) {
-
 
365
                // We cannot be sure we have # in the id element name.
-
 
366
                collapsibleId = collapsibleId.replace('#', '');
404
            } else {
367
                const expandNode = modalBody.querySelector(`#${collapsibleId}`);
-
 
368
                jQuery(expandNode).collapse('show');
405
                selector = `${this.selectors.SECTIONLINK}[data-id='${cmInfo.sectionid}']`;
-
 
406
            }
-
 
407
            const currentElement = modalBody.querySelector(selector);
369
            }
408
            this._expandCmMoveModalParentSections(modalBody, currentElement);
Línea 370... Línea 409...
370
        });
409
        });
371
 
410
 
372
        modalBody.addEventListener('click', (event) => {
411
        modalBody.addEventListener('click', (event) => {
373
            const target = event.target;
412
            const target = event.target.closest('a');
374
            if (!target.matches('a') || target.dataset.for === undefined || target.dataset.id === undefined) {
413
            if (!target || target.dataset.for === undefined || target.dataset.id === undefined) {
375
                return;
414
                return;
376
            }
415
            }
377
            if (target.getAttribute('aria-disabled')) {
416
            if (target.getAttribute('aria-disabled')) {
378
                return;
417
                return;
Línea 379... Línea 418...
379
            }
418
            }
380
            event.preventDefault();
419
            event.preventDefault();
-
 
420
 
381
 
421
            let targetSectionId;
382
            let targetSectionId;
422
            let targetCmId;
383
            let targetCmId;
423
            let droppedCmIds = [...cmIds];
384
            if (target.dataset.for == 'cm') {
424
            if (target.dataset.for == 'cm') {
385
                const dropData = exporter.cmDraggableData(this.reactive.state, target.dataset.id);
425
                const dropData = exporter.cmDraggableData(this.reactive.state, target.dataset.id);
386
                targetSectionId = dropData.sectionid;
426
                targetSectionId = dropData.sectionid;
387
                targetCmId = dropData.nextcmid;
427
                targetCmId = dropData.nextcmid;
388
            } else {
428
            } else {
389
                const section = this.reactive.get('section', target.dataset.id);
429
                const section = this.reactive.get('section', target.dataset.id);
-
 
430
                targetSectionId = target.dataset.id;
-
 
431
                targetCmId = section?.cmlist[0];
-
 
432
            }
-
 
433
            const section = this.reactive.get('section', targetSectionId);
-
 
434
            if (section.component) {
-
 
435
                // Remove cmIds which are not allowed to be moved to this delegated section (mostly
-
 
436
                // all other delegated cm).
-
 
437
                droppedCmIds = droppedCmIds.filter(cmId => {
-
 
438
                    const cmInfo = this.reactive.get('cm', cmId);
-
 
439
                    return !cmInfo.hasdelegatedsection;
-
 
440
                });
-
 
441
            }
390
                targetSectionId = target.dataset.id;
442
            if (droppedCmIds.length === 0) {
391
                targetCmId = section?.cmlist[0];
443
                return; // No cm to move.
392
            }
444
            }
Línea 393... Línea 445...
393
            this.reactive.dispatch('cmMove', cmIds, targetSectionId, targetCmId);
445
            this.reactive.dispatch('cmMove', droppedCmIds, targetSectionId, targetCmId);
394
            this._destroyModal(modal, editTools);
446
            this._destroyModal(modal, editTools);
Línea 395... Línea 447...
395
        });
447
        });
-
 
448
 
-
 
449
        pendingModalReady.resolve();
-
 
450
    }
-
 
451
 
-
 
452
    /**
-
 
453
     * Expand all the modal tree branches that contains the element.
-
 
454
     *
-
 
455
     * @private
-
 
456
     * @param {HTMLElement} modalBody the modal body element
-
 
457
     * @param {HTMLElement} element the element to display
-
 
458
     */
-
 
459
    _expandCmMoveModalParentSections(modalBody, element) {
-
 
460
        const sectionnode = element.closest(this.selectors.SECTIONNODE);
-
 
461
        if (!sectionnode) {
-
 
462
            return;
-
 
463
        }
-
 
464
 
-
 
465
        const toggler = sectionnode.querySelector(this.selectors.MODALTOGGLER);
-
 
466
        let collapsibleId = toggler.dataset.target ?? toggler.getAttribute('href');
-
 
467
        if (collapsibleId) {
-
 
468
            // We cannot be sure we have # in the id element name.
-
 
469
            collapsibleId = collapsibleId.replace('#', '');
-
 
470
            const expandNode = modalBody.querySelector(`#${collapsibleId}`);
-
 
471
            new Collapse(expandNode, {toggle: false}).show();
-
 
472
        }
-
 
473
 
396
 
474
        // Section are a tree structure, we need to expand all the parents.
397
        pendingModalReady.resolve();
475
        this._expandCmMoveModalParentSections(modalBody, sectionnode.parentElement);
398
    }
476
    }
399
 
477
 
400
    /**
478
    /**
Línea 407... Línea 485...
407
        event.preventDefault();
485
        event.preventDefault();
408
        this.reactive.dispatch('addSection', target.dataset.id ?? 0);
486
        this.reactive.dispatch('addSection', target.dataset.id ?? 0);
409
    }
487
    }
Línea 410... Línea 488...
410
 
488
 
-
 
489
    /**
-
 
490
     * Handle a create subsection request.
-
 
491
     *
-
 
492
     * @deprecated since Moodle 5.0 MDL-83469.
-
 
493
     * @todo MDL-83851 This will be deleted in Moodle 6.0.
-
 
494
     * @param {Element} target the dispatch action element
-
 
495
     * @param {Event} event the triggered event
-
 
496
     */
-
 
497
    async _requestAddModule(target, event) {
-
 
498
        log.debug('AddModule action is deprecated. Use newModule instead');
-
 
499
        event.preventDefault();
-
 
500
        this.reactive.dispatch('addModule', target.dataset.modname, target.dataset.sectionnum, target.dataset.beforemod);
-
 
501
    }
-
 
502
 
-
 
503
    /**
-
 
504
     * Handle a new create subsection request.
-
 
505
     *
-
 
506
     * @param {Element} target the dispatch action element
-
 
507
     * @param {Event} event the triggered event
-
 
508
     */
-
 
509
    async _requestNewModule(target, event) {
-
 
510
        event.preventDefault();
-
 
511
        this.reactive.dispatch('newModule', target.dataset.modname, target.dataset.sectionid, target.dataset.beforemod);
-
 
512
    }
-
 
513
 
411
    /**
514
    /**
412
     * Handle a delete section request.
515
     * Handle a delete section request.
413
     *
516
     *
414
     * @param {Element} target the dispatch action element
517
     * @param {Element} target the dispatch action element
415
     * @param {Event} event the triggered event
518
     * @param {Event} event the triggered event
Línea 427... Línea 530...
427
            const sectionInfo = this.reactive.get('section', sectionId);
530
            const sectionInfo = this.reactive.get('section', sectionId);
428
            const cmList = sectionInfo.cmlist ?? [];
531
            const cmList = sectionInfo.cmlist ?? [];
429
            return (cmList.length || sectionInfo.hassummary || sectionInfo.rawtitle);
532
            return (cmList.length || sectionInfo.hassummary || sectionInfo.rawtitle);
430
        });
533
        });
431
        if (!needsConfirmation) {
534
        if (!needsConfirmation) {
432
            this.reactive.dispatch('sectionDelete', sectionIds);
535
            this._dispatchSectionDelete(sectionIds, target);
433
            return;
536
            return;
434
        }
537
        }
Línea 435... Línea 538...
435
 
538
 
436
        let bodyText = null;
539
        let bodyText = null;
Línea 453... Línea 556...
453
            ModalEvents.delete,
556
            ModalEvents.delete,
454
            e => {
557
            e => {
455
                // Stop the default save button behaviour which is to close the modal.
558
                // Stop the default save button behaviour which is to close the modal.
456
                e.preventDefault();
559
                e.preventDefault();
457
                modal.destroy();
560
                modal.destroy();
458
                this.reactive.dispatch('sectionDelete', sectionIds);
561
                this._dispatchSectionDelete(sectionIds, target);
459
            }
562
            }
460
        );
563
        );
461
    }
564
    }
Línea 462... Línea 565...
462
 
565
 
-
 
566
    /**
-
 
567
     * Dispatch the section delete action and handle the redirection if necessary.
-
 
568
     *
-
 
569
     * @param {Array} sectionIds  the IDs of the sections to delete.
-
 
570
     * @param {Element} target the dispatch action element
-
 
571
     */
-
 
572
    async _dispatchSectionDelete(sectionIds, target) {
-
 
573
        await this.reactive.dispatch('sectionDelete', sectionIds);
-
 
574
        if (target.baseURI.includes('section.php')) {
-
 
575
            // Redirect to the course main page if the section is the current page.
-
 
576
            window.location.href = this.reactive.get('course').baseurl;
-
 
577
        }
-
 
578
    }
-
 
579
 
463
    /**
580
    /**
464
     * Handle a toggle cm selection.
581
     * Handle a toggle cm selection.
465
     *
582
     *
466
     * @param {Element} target the dispatch action element
583
     * @param {Element} target the dispatch action element
467
     * @param {Event} event the triggered event
584
     * @param {Event} event the triggered event
Línea 499... Línea 616...
499
            this.reactive.dispatch(mutationName, [target.dataset.id]);
616
            this.reactive.dispatch(mutationName, [target.dataset.id]);
500
        }
617
        }
501
    }
618
    }
Línea 502... Línea 619...
502
 
619
 
-
 
620
    /**
-
 
621
     * Handle a course permalink modal request.
-
 
622
     *
-
 
623
     * @param {Element} target the dispatch action element
-
 
624
     * @param {Event} event the triggered event
-
 
625
     */
-
 
626
    _requestPermalink(target, event) {
-
 
627
        event.preventDefault();
-
 
628
        ModalCopyToClipboard.create(
-
 
629
            {
-
 
630
                text: target.getAttribute('href'),
-
 
631
            },
-
 
632
            getString('sectionlink', 'course')
-
 
633
        );
-
 
634
        return;
-
 
635
    }
-
 
636
 
503
    /**
637
    /**
504
     * Handle a course module duplicate request.
638
     * Handle a course module duplicate request.
505
     *
639
     *
506
     * @param {Element} target the dispatch action element
640
     * @param {Element} target the dispatch action element
507
     * @param {Event} event the triggered event
641
     * @param {Event} event the triggered event
Línea 530... Línea 664...
530
 
664
 
Línea 531... Línea 665...
531
        event.preventDefault();
665
        event.preventDefault();
532
 
666
 
-
 
667
        let bodyText = null;
533
        let bodyText = null;
668
        let titleText = null;
534
        let titleText = null;
669
        let delegatedsection = null;
-
 
670
        if (cmIds.length == 1) {
-
 
671
            const cmInfo = this.reactive.get('cm', cmIds[0]);
-
 
672
            if (cmInfo.hasdelegatedsection) {
-
 
673
                delegatedsection = cmInfo.delegatesectionid;
-
 
674
                titleText = this.reactive.getFormatString('cmdelete_subsectiontitle');
-
 
675
                bodyText = getString(
-
 
676
                    'sectiondelete_info',
-
 
677
                    'core_courseformat',
-
 
678
                    {
-
 
679
                        type: cmInfo.modname,
-
 
680
                        name: cmInfo.name,
-
 
681
                    }
535
        if (cmIds.length == 1) {
682
                );
536
            const cmInfo = this.reactive.get('cm', cmIds[0]);
683
            } else {
537
            titleText = getString('cmdelete_title', 'core_courseformat');
684
                titleText = this.reactive.getFormatString('cmdelete_title');
538
            bodyText = getString(
685
                bodyText = getString(
539
                'cmdelete_info',
686
                    'cmdelete_info',
540
                'core_courseformat',
687
                    'core_courseformat',
541
                {
688
                    {
-
 
689
                        type: cmInfo.modname,
542
                    type: cmInfo.modname,
690
                        name: cmInfo.name,
543
                    name: cmInfo.name,
691
                    }
544
                }
692
                );
545
            );
693
            }
546
        } else {
694
        } else {
547
            titleText = getString('cmsdelete_title', 'core_courseformat');
695
            titleText = getString('cmsdelete_title', 'core_courseformat');
548
            bodyText = getString(
696
            bodyText = getString(
Línea 562... Línea 710...
562
            e => {
710
            e => {
563
                // Stop the default save button behaviour which is to close the modal.
711
                // Stop the default save button behaviour which is to close the modal.
564
                e.preventDefault();
712
                e.preventDefault();
565
                modal.destroy();
713
                modal.destroy();
566
                this.reactive.dispatch('cmDelete', cmIds);
714
                this.reactive.dispatch('cmDelete', cmIds);
-
 
715
                if (cmIds.length == 1 && delegatedsection && target.baseURI.includes('section.php')) {
-
 
716
                    // Redirect to the course main page if the subsection is the current page.
-
 
717
                    let parameters = new URLSearchParams(window.location.search);
-
 
718
                    if (parameters.has('id') && parameters.get('id') == delegatedsection) {
-
 
719
                        this._dispatchSectionDelete([delegatedsection], target);
-
 
720
                    }
-
 
721
                }
567
            }
722
            }
568
        );
723
        );
569
    }
724
    }
Línea 570... Línea 725...
570
 
725
 
Línea 662... Línea 817...
662
     * Disable all add sections actions.
817
     * Disable all add sections actions.
663
     *
818
     *
664
     * @param {boolean} locked the new locked value.
819
     * @param {boolean} locked the new locked value.
665
     */
820
     */
666
    _setAddSectionLocked(locked) {
821
    _setAddSectionLocked(locked) {
667
        const targets = this.getElements(this.selectors.ADDSECTION);
822
        const targets = this.getElements(this.selectors.ADDSECTIONREGION);
668
        targets.forEach(element => {
823
        targets.forEach(element => {
669
            element.classList.toggle(this.classes.DISABLED, locked);
824
            element.classList.toggle(this.classes.DISABLED, locked);
-
 
825
            const addSectionElement = element.querySelector(this.selectors.ADDSECTION);
670
            element.classList.toggle(this.classes.ITALIC, locked);
826
            addSectionElement.classList.toggle(this.classes.DISABLED, locked);
671
            this.setElementLocked(element, locked);
827
            this.setElementLocked(addSectionElement, locked);
-
 
828
            // We tweak the element to show a tooltip as a title attribute.
-
 
829
            if (locked) {
-
 
830
                getString('sectionaddmax', 'core_courseformat')
-
 
831
                    .then((text) => addSectionElement.setAttribute('title', text))
-
 
832
                    .catch(Notification.exception);
-
 
833
                addSectionElement.style.pointerEvents = null; // Unlocks the pointer events.
-
 
834
                addSectionElement.style.userSelect = null; // Unlocks the pointer events.
-
 
835
            } else {
-
 
836
                addSectionElement.setAttribute('title', addSectionElement.dataset.addSections);
-
 
837
            }
672
        });
838
        });
-
 
839
        const courseAddSection = this.getElement(this.selectors.COURSEADDSECTION);
-
 
840
        if (courseAddSection) {
-
 
841
            const addSection = courseAddSection.querySelector(this.selectors.ADDSECTION);
-
 
842
            addSection.classList.toggle(this.classes.DISPLAYNONE, locked);
-
 
843
            const noMoreSections = courseAddSection.querySelector(this.selectors.MAXSECTIONSWARNING);
-
 
844
            noMoreSections.classList.toggle(this.classes.DISPLAYNONE, !locked);
-
 
845
        }
673
    }
846
    }
Línea 674... Línea 847...
674
 
847
 
675
    /**
848
    /**
676
     * Replace an element with a copy with a different tag name.
849
     * Replace an element with a copy with a different tag name.