Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | 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 {dispatchEvent} from 'core/event_dispatcher';
27
import 'core/inplace_editable';
28
import {eventTypes as inplaceEditableEvents} from 'core/local/inplace_editable/events';
29
import Notification from 'core/notification';
30
import Pending from 'core/pending';
31
import {prefetchStrings} from 'core/prefetch';
32
import {publish} from 'core/pubsub';
33
import SortableList from 'core/sortable_list';
34
import {getString} from 'core/str';
35
import {add as addToast} from 'core/toast';
36
import * as reportEvents from 'core_reportbuilder/local/events';
37
import * as reportSelectors from 'core_reportbuilder/local/selectors';
38
import {addColumn, deleteColumn, reorderColumn} from 'core_reportbuilder/local/repository/columns';
39
import {getColumnSorting} from 'core_reportbuilder/local/repository/sorting';
40
 
41
/**
42
 * Initialise module, prefetch all required strings
43
 *
44
 * @param {Boolean} initialized Ensure we only add our listeners once
45
 */
46
export const init = initialized => {
47
    prefetchStrings('core_reportbuilder', [
48
        'columnadded',
49
        'columnaggregated',
50
        'columndeleted',
51
        'columnmoved',
52
        'deletecolumn',
53
        'deletecolumnconfirm',
54
    ]);
55
 
56
    prefetchStrings('core', [
57
        'delete',
58
    ]);
59
 
60
    if (initialized) {
61
        return;
62
    }
63
 
64
    document.addEventListener('click', event => {
65
 
66
        // Add column to report.
67
        const reportAddColumn = event.target.closest(reportSelectors.actions.reportAddColumn);
68
        if (reportAddColumn) {
69
            event.preventDefault();
70
 
71
            const pendingPromise = new Pending('core_reportbuilder/columns:add');
72
            const reportElement = reportAddColumn.closest(reportSelectors.regions.report);
73
 
74
            addColumn(reportElement.dataset.reportId, reportAddColumn.dataset.uniqueIdentifier)
75
                .then(data => publish(reportEvents.publish.reportColumnsUpdated, data))
76
                .then(() => getString('columnadded', 'core_reportbuilder', reportAddColumn.dataset.name))
77
                .then(addToast)
78
                .then(() => {
79
                    dispatchEvent(reportEvents.tableReload, {preservePagination: true}, reportElement);
80
                    return pendingPromise.resolve();
81
                })
82
                .catch(Notification.exception);
83
        }
84
 
85
        // Remove column from report.
86
        const reportRemoveColumn = event.target.closest(reportSelectors.actions.reportRemoveColumn);
87
        if (reportRemoveColumn) {
88
            event.preventDefault();
89
 
90
            const reportElement = reportRemoveColumn.closest(reportSelectors.regions.report);
91
            const columnHeader = reportRemoveColumn.closest(reportSelectors.regions.columnHeader);
92
            const columnName = columnHeader.dataset.columnName;
93
 
94
            Notification.saveCancelPromise(
95
                getString('deletecolumn', 'core_reportbuilder', columnName),
96
                getString('deletecolumnconfirm', 'core_reportbuilder', columnName),
97
                getString('delete', 'core'),
98
                {triggerElement: reportRemoveColumn}
99
            ).then(() => {
100
                const pendingPromise = new Pending('core_reportbuilder/columns:remove');
101
 
102
                return deleteColumn(reportElement.dataset.reportId, columnHeader.dataset.columnId)
103
                    .then(data => publish(reportEvents.publish.reportColumnsUpdated, data))
104
                    .then(() => addToast(getString('columndeleted', 'core_reportbuilder', columnName)))
105
                    .then(() => {
106
                        dispatchEvent(reportEvents.tableReload, {preservePagination: true}, reportElement);
107
                        return pendingPromise.resolve();
108
                    })
109
                    .catch(Notification.exception);
110
            }).catch(() => {
111
                return;
112
            });
113
        }
114
    });
115
 
1441 ariadna 116
    // Initialize sortable list to handle column moving.
117
    const columnHeadingSelector = `${reportSelectors.regions.reportTable} thead tr`;
118
    const columnHeadingSortableList = new SortableList(columnHeadingSelector, {isHorizontal: true});
119
    columnHeadingSortableList.getElementName = element => Promise.resolve(element.data('columnName'));
1 efrain 120
 
1441 ariadna 121
    document.addEventListener(SortableList.EVENTS.elementDrag, event => {
122
        const reportOrderColumn = event.target.closest(`${columnHeadingSelector} ${reportSelectors.regions.columnHeader}`);
123
        if (reportOrderColumn) {
124
            const reportElement = event.target.closest(reportSelectors.regions.report);
125
            const {columnPosition} = reportOrderColumn.dataset;
1 efrain 126
 
1441 ariadna 127
            // Select target position, shift table columns to match.
128
            const targetColumnPosition = event.detail.targetNextElement.data('columnPosition');
129
 
130
            const reportTableRows = reportElement.querySelectorAll(`${reportSelectors.regions.reportTable} tbody tr`);
131
            reportTableRows.forEach(reportTableRow => {
132
                const reportTableRowCell = reportTableRow.querySelector(`td.c${columnPosition - 1}`);
133
                if (targetColumnPosition) {
134
                    const reportTableRowCellTarget = reportTableRow.querySelector(`td.c${targetColumnPosition - 1}`);
135
                    reportTableRow.insertBefore(reportTableRowCell, reportTableRowCellTarget);
136
                } else {
137
                    reportTableRow.appendChild(reportTableRowCell);
138
                }
139
            });
140
        }
1 efrain 141
    });
142
 
1441 ariadna 143
    document.addEventListener(SortableList.EVENTS.elementDrop, event => {
144
        const reportOrderColumn = event.target.closest(`${columnHeadingSelector} ${reportSelectors.regions.columnHeader}`);
145
        if (reportOrderColumn && event.detail.positionChanged) {
1 efrain 146
            const pendingPromise = new Pending('core_reportbuilder/columns:reorder');
147
 
1441 ariadna 148
            const reportElement = reportOrderColumn.closest(reportSelectors.regions.report);
149
            const {columnId, columnPosition, columnName} = reportOrderColumn.dataset;
150
 
1 efrain 151
            // Select target position, if moving to the end then count number of element siblings.
1441 ariadna 152
            let targetColumnPosition = event.detail.targetNextElement.data('columnPosition')
153
                || event.detail.element.siblings().length + 2;
1 efrain 154
            if (targetColumnPosition > columnPosition) {
155
                targetColumnPosition--;
156
            }
157
 
158
            // Re-order column, giving drop event transition time to finish.
159
            const reorderPromise = reorderColumn(reportElement.dataset.reportId, columnId, targetColumnPosition);
160
            Promise.all([reorderPromise, new Promise(resolve => setTimeout(resolve, 1000))])
161
                .then(() => getString('columnmoved', 'core_reportbuilder', columnName))
162
                .then(addToast)
163
                .then(() => {
164
                    dispatchEvent(reportEvents.tableReload, {preservePagination: true}, reportElement);
165
                    return pendingPromise.resolve();
166
                })
167
                .catch(Notification.exception);
168
        }
169
    });
170
 
171
    // Initialize inplace editable listeners for column aggregation.
172
    document.addEventListener(inplaceEditableEvents.elementUpdated, event => {
173
        const columnAggregation = event.target.closest('[data-itemtype="columnaggregation"]');
174
        if (columnAggregation) {
175
            const pendingPromise = new Pending('core_reportbuilder/columns:aggregate');
176
            const reportElement = columnAggregation.closest(reportSelectors.regions.report);
177
            const columnHeader = columnAggregation.closest(reportSelectors.regions.columnHeader);
178
 
179
            getString('columnaggregated', 'core_reportbuilder', columnHeader.dataset.columnName)
180
                .then(addToast)
181
                .then(() => {
182
                    // Pass preserveTriggerElement parameter so columnAggregationLink will be focused after the report reload.
183
                    const columnAggregationLink = `[data-itemtype="columnaggregation"][data-itemid="`
184
                        + `${columnAggregation.dataset.itemid}"] > a`;
185
 
186
                    // Now reload the table, and notify listeners that columns have been updated.
187
                    dispatchEvent(reportEvents.tableReload, {preserveTriggerElement: columnAggregationLink}, reportElement);
188
                    return getColumnSorting(reportElement.dataset.reportId);
189
                })
190
                .then(data => publish(reportEvents.publish.reportColumnsUpdated, data))
191
                .then(() => pendingPromise.resolve())
192
                .catch(Notification.exception);
193
        }
194
    });
195
};