Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// This file is part of Moodle - http://moodle.org/
2
//
3
// Moodle is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, either version 3 of the License, or
6
// (at your option) any later version.
7
//
8
// Moodle is distributed in the hope that it will be useful,
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
// GNU General Public License for more details.
12
//
13
// You should have received a copy of the GNU General Public License
14
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
15
 
16
/**
17
 * Report builder columns editor
18
 *
19
 * @module      core_reportbuilder/local/editor/columns
20
 * @copyright   2021 Paul Holden <paulh@moodle.com>
21
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
23
 
24
"use strict";
25
 
26
import $ from 'jquery';
27
import {dispatchEvent} from 'core/event_dispatcher';
28
import 'core/inplace_editable';
29
import {eventTypes as inplaceEditableEvents} from 'core/local/inplace_editable/events';
30
import Notification from 'core/notification';
31
import Pending from 'core/pending';
32
import {prefetchStrings} from 'core/prefetch';
33
import {publish} from 'core/pubsub';
34
import SortableList from 'core/sortable_list';
35
import {getString} from 'core/str';
36
import {add as addToast} from 'core/toast';
37
import * as reportEvents from 'core_reportbuilder/local/events';
38
import * as reportSelectors from 'core_reportbuilder/local/selectors';
39
import {addColumn, deleteColumn, reorderColumn} from 'core_reportbuilder/local/repository/columns';
40
import {getColumnSorting} from 'core_reportbuilder/local/repository/sorting';
41
 
42
/**
43
 * Initialise module, prefetch all required strings
44
 *
45
 * @param {Boolean} initialized Ensure we only add our listeners once
46
 */
47
export const init = initialized => {
48
    prefetchStrings('core_reportbuilder', [
49
        'columnadded',
50
        'columnaggregated',
51
        'columndeleted',
52
        'columnmoved',
53
        'deletecolumn',
54
        'deletecolumnconfirm',
55
    ]);
56
 
57
    prefetchStrings('core', [
58
        'delete',
59
    ]);
60
 
61
    if (initialized) {
62
        return;
63
    }
64
 
65
    document.addEventListener('click', event => {
66
 
67
        // Add column to report.
68
        const reportAddColumn = event.target.closest(reportSelectors.actions.reportAddColumn);
69
        if (reportAddColumn) {
70
            event.preventDefault();
71
 
72
            const pendingPromise = new Pending('core_reportbuilder/columns:add');
73
            const reportElement = reportAddColumn.closest(reportSelectors.regions.report);
74
 
75
            addColumn(reportElement.dataset.reportId, reportAddColumn.dataset.uniqueIdentifier)
76
                .then(data => publish(reportEvents.publish.reportColumnsUpdated, data))
77
                .then(() => getString('columnadded', 'core_reportbuilder', reportAddColumn.dataset.name))
78
                .then(addToast)
79
                .then(() => {
80
                    dispatchEvent(reportEvents.tableReload, {preservePagination: true}, reportElement);
81
                    return pendingPromise.resolve();
82
                })
83
                .catch(Notification.exception);
84
        }
85
 
86
        // Remove column from report.
87
        const reportRemoveColumn = event.target.closest(reportSelectors.actions.reportRemoveColumn);
88
        if (reportRemoveColumn) {
89
            event.preventDefault();
90
 
91
            const reportElement = reportRemoveColumn.closest(reportSelectors.regions.report);
92
            const columnHeader = reportRemoveColumn.closest(reportSelectors.regions.columnHeader);
93
            const columnName = columnHeader.dataset.columnName;
94
 
95
            Notification.saveCancelPromise(
96
                getString('deletecolumn', 'core_reportbuilder', columnName),
97
                getString('deletecolumnconfirm', 'core_reportbuilder', columnName),
98
                getString('delete', 'core'),
99
                {triggerElement: reportRemoveColumn}
100
            ).then(() => {
101
                const pendingPromise = new Pending('core_reportbuilder/columns:remove');
102
 
103
                return deleteColumn(reportElement.dataset.reportId, columnHeader.dataset.columnId)
104
                    .then(data => publish(reportEvents.publish.reportColumnsUpdated, data))
105
                    .then(() => addToast(getString('columndeleted', 'core_reportbuilder', columnName)))
106
                    .then(() => {
107
                        dispatchEvent(reportEvents.tableReload, {preservePagination: true}, reportElement);
108
                        return pendingPromise.resolve();
109
                    })
110
                    .catch(Notification.exception);
111
            }).catch(() => {
112
                return;
113
            });
114
        }
115
    });
116
 
117
    // Initialize sortable list to handle column moving (note JQuery dependency, see MDL-72293 for resolution).
118
    var columnSortableList = new SortableList(`${reportSelectors.regions.reportTable} thead tr`, {isHorizontal: true});
119
    columnSortableList.getElementName = element => Promise.resolve(element.data('columnName'));
120
 
121
    $(document).on(SortableList.EVENTS.DRAG, `${reportSelectors.regions.report} th[data-column-id]`, (event, info) => {
122
        const reportElement = event.target.closest(reportSelectors.regions.report);
123
        const columnPosition = info.element.data('columnPosition');
124
        const targetColumnPosition = info.targetNextElement.data('columnPosition');
125
 
126
        $(reportElement).find('tbody tr').each(function() {
127
            const cell = $(this).children(`td.c${columnPosition - 1}`)[0];
128
            if (targetColumnPosition) {
129
                var beforeCell = $(this).children(`td.c${targetColumnPosition - 1}`)[0];
130
                this.insertBefore(cell, beforeCell);
131
            } else {
132
                this.appendChild(cell);
133
            }
134
        });
135
    });
136
 
137
    $(document).on(SortableList.EVENTS.DROP, `${reportSelectors.regions.report} th[data-column-id]`, (event, info) => {
138
        if (info.positionChanged) {
139
            const pendingPromise = new Pending('core_reportbuilder/columns:reorder');
140
            const reportElement = event.target.closest(reportSelectors.regions.report);
141
            const columnId = info.element.data('columnId');
142
            const columnName = info.element.data('columnName');
143
            const columnPosition = info.element.data('columnPosition');
144
 
145
            // Select target position, if moving to the end then count number of element siblings.
146
            let targetColumnPosition = info.targetNextElement.data('columnPosition') || info.element.siblings().length + 2;
147
            if (targetColumnPosition > columnPosition) {
148
                targetColumnPosition--;
149
            }
150
 
151
            // Re-order column, giving drop event transition time to finish.
152
            const reorderPromise = reorderColumn(reportElement.dataset.reportId, columnId, targetColumnPosition);
153
            Promise.all([reorderPromise, new Promise(resolve => setTimeout(resolve, 1000))])
154
                .then(() => getString('columnmoved', 'core_reportbuilder', columnName))
155
                .then(addToast)
156
                .then(() => {
157
                    dispatchEvent(reportEvents.tableReload, {preservePagination: true}, reportElement);
158
                    return pendingPromise.resolve();
159
                })
160
                .catch(Notification.exception);
161
        }
162
    });
163
 
164
    // Initialize inplace editable listeners for column aggregation.
165
    document.addEventListener(inplaceEditableEvents.elementUpdated, event => {
166
 
167
        const columnAggregation = event.target.closest('[data-itemtype="columnaggregation"]');
168
        if (columnAggregation) {
169
            const pendingPromise = new Pending('core_reportbuilder/columns:aggregate');
170
            const reportElement = columnAggregation.closest(reportSelectors.regions.report);
171
            const columnHeader = columnAggregation.closest(reportSelectors.regions.columnHeader);
172
 
173
            getString('columnaggregated', 'core_reportbuilder', columnHeader.dataset.columnName)
174
                .then(addToast)
175
                .then(() => {
176
                    // Pass preserveTriggerElement parameter so columnAggregationLink will be focused after the report reload.
177
                    const columnAggregationLink = `[data-itemtype="columnaggregation"][data-itemid="`
178
                        + `${columnAggregation.dataset.itemid}"] > a`;
179
 
180
                    // Now reload the table, and notify listeners that columns have been updated.
181
                    dispatchEvent(reportEvents.tableReload, {preserveTriggerElement: columnAggregationLink}, reportElement);
182
                    return getColumnSorting(reportElement.dataset.reportId);
183
                })
184
                .then(data => publish(reportEvents.publish.reportColumnsUpdated, data))
185
                .then(() => pendingPromise.resolve())
186
                .catch(Notification.exception);
187
        }
188
    });
189
};