Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
/**
2
 * Section drag and drop.
3
 *
4
 * @class M.course.dragdrop.section
5
 * @constructor
6
 * @extends M.core.dragdrop
7
 */
8
var DRAGSECTION = function() {
9
    DRAGSECTION.superclass.constructor.apply(this, arguments);
10
};
11
Y.extend(DRAGSECTION, M.core.dragdrop, {
12
    sectionlistselector: null,
13
 
14
    initializer: function() {
15
        // Set group for parent class
16
        this.groups = [CSS.SECTIONDRAGGABLE];
17
        this.samenodeclass = M.course.format.get_sectionwrapperclass();
18
        this.parentnodeclass = M.course.format.get_containerclass();
19
        // Detect the direction of travel.
20
        this.detectkeyboarddirection = true;
21
 
22
        // Check if we are in single section mode
23
        if (Y.Node.one('.' + CSS.JUMPMENU)) {
24
            return false;
25
        }
26
        // Initialise sections dragging
27
        this.sectionlistselector = M.course.format.get_section_wrapper(Y);
28
        if (this.sectionlistselector) {
29
            this.sectionlistselector = '.' + CSS.COURSECONTENT + ' ' + this.sectionlistselector;
30
 
31
            this.setup_for_section(this.sectionlistselector);
32
 
33
            // Make each li element in the lists of sections draggable
34
            var del = new Y.DD.Delegate({
35
                container: '.' + CSS.COURSECONTENT,
36
                nodes: '.' + CSS.SECTIONDRAGGABLE,
37
                target: true,
38
                handles: ['.' + CSS.LEFT],
39
                dragConfig: {groups: this.groups}
40
            });
41
            del.dd.plug(Y.Plugin.DDProxy, {
42
                // Don't move the node at the end of the drag
43
                moveOnEnd: false
44
            });
45
            del.dd.plug(Y.Plugin.DDConstrained, {
46
                // Keep it inside the .course-content
47
                constrain: '#' + CSS.PAGECONTENT,
48
                stickY: true
49
            });
50
            del.dd.plug(Y.Plugin.DDWinScroll);
51
        }
52
    },
53
 
54
     /**
55
     * Apply dragdrop features to the specified selector or node that refers to section(s)
56
     *
57
     * @method setup_for_section
58
     * @param {String} baseselector The CSS selector or node to limit scope to
59
     */
60
    setup_for_section: function(baseselector) {
61
        Y.Node.all(baseselector).each(function(sectionnode) {
62
            // Determine the section ID
63
            var sectionid = Y.Moodle.core_course.util.section.getId(sectionnode);
64
 
65
            // We skip the top section as it is not draggable
66
            if (sectionid > 0) {
67
                // Remove move icons
68
                var movedown = sectionnode.one('.' + CSS.RIGHT + ' a.' + CSS.MOVEDOWN);
69
                var moveup = sectionnode.one('.' + CSS.RIGHT + ' a.' + CSS.MOVEUP);
70
 
71
                // Add dragger icon
72
                var title = M.util.get_string('movesection', 'moodle', sectionid);
73
                var cssleft = sectionnode.one('.' + CSS.LEFT);
74
 
75
                if ((movedown || moveup) && cssleft) {
76
                    cssleft.setStyle('cursor', 'move');
77
                    cssleft.appendChild(this.get_drag_handle(title, CSS.SECTIONHANDLE, 'icon', true));
78
 
79
                    if (moveup) {
80
                        if (moveup.previous('br')) {
81
                            moveup.previous('br').remove();
82
                        } else if (moveup.next('br')) {
83
                            moveup.next('br').remove();
84
                        }
85
 
86
                        if (moveup.ancestor('.section_action_menu') && moveup.ancestor().get('nodeName').toLowerCase() == 'li') {
87
                            moveup.ancestor().remove();
88
                        } else {
89
                            moveup.remove();
90
                        }
91
                    }
92
                    if (movedown) {
93
                        if (movedown.previous('br')) {
94
                            movedown.previous('br').remove();
95
                        } else if (movedown.next('br')) {
96
                            movedown.next('br').remove();
97
                        }
98
 
99
                        var movedownParentType = movedown.ancestor().get('nodeName').toLowerCase();
100
                        if (movedown.ancestor('.section_action_menu') && movedownParentType == 'li') {
101
                            movedown.ancestor().remove();
102
                        } else {
103
                            movedown.remove();
104
                        }
105
                    }
106
 
107
                    // This section can be moved - add the class to indicate this to Y.DD.
108
                    sectionnode.addClass(CSS.SECTIONDRAGGABLE);
109
                }
110
            }
111
        }, this);
112
    },
113
 
114
    /*
115
     * Drag-dropping related functions
116
     */
117
    drag_start: function(e) {
118
        // Get our drag object
119
        var drag = e.target;
120
        // This is the node that the user started to drag.
121
        var node = drag.get('node');
122
        // This is the container node that will follow the mouse around,
123
        // or during a keyboard drag and drop the original node.
124
        var dragnode = drag.get('dragNode');
125
        if (node === dragnode) {
126
            return;
127
        }
128
        // Creat a dummy structure of the outer elemnents for clean styles application
129
        var containernode = Y.Node.create('<' + M.course.format.get_containernode() +
130
                '></' + M.course.format.get_containernode() + '>');
131
        containernode.addClass(M.course.format.get_containerclass());
132
        var sectionnode = Y.Node.create('<' + M.course.format.get_sectionwrappernode() +
133
                '></' + M.course.format.get_sectionwrappernode() + '>');
134
        sectionnode.addClass(M.course.format.get_sectionwrapperclass());
135
        sectionnode.setStyle('margin', 0);
136
        sectionnode.setContent(node.get('innerHTML'));
137
        containernode.appendChild(sectionnode);
138
        dragnode.setContent(containernode);
139
        dragnode.addClass(CSS.COURSECONTENT);
140
    },
141
 
142
    drag_dropmiss: function(e) {
143
        // Missed the target, but we assume the user intended to drop it
144
        // on the last last ghost node location, e.drag and e.drop should be
145
        // prepared by global_drag_dropmiss parent so simulate drop_hit(e).
146
        this.drop_hit(e);
147
    },
148
 
149
    get_section_index: function(node) {
150
        var sectionlistselector = '.' + CSS.COURSECONTENT + ' ' + M.course.format.get_section_selector(Y),
151
            sectionList = Y.all(sectionlistselector),
152
            nodeIndex = sectionList.indexOf(node),
153
            zeroIndex = sectionList.indexOf(Y.one('#section-0'));
154
 
155
        return (nodeIndex - zeroIndex);
156
    },
157
 
158
    drop_hit: function(e) {
159
        var drag = e.drag;
160
 
161
        // Get references to our nodes and their IDs.
162
        var dragnode = drag.get('node'),
163
            dragnodeid = Y.Moodle.core_course.util.section.getId(dragnode),
164
            loopstart = dragnodeid,
165
 
166
            dropnodeindex = this.get_section_index(dragnode),
167
            loopend = dropnodeindex;
168
 
169
        if (dragnodeid === dropnodeindex) {
170
            Y.log("Skipping move - same location moving " + dragnodeid + " to " + dropnodeindex, 'debug', 'moodle-course-dragdrop');
171
            return;
172
        }
173
 
174
        Y.log("Moving from position " + dragnodeid + " to position " + dropnodeindex, 'debug', 'moodle-course-dragdrop');
175
 
176
        if (loopstart > loopend) {
177
            // If we're going up, we need to swap the loop order
178
            // because loops can't go backwards.
179
            loopstart = dropnodeindex;
180
            loopend = dragnodeid;
181
        }
182
 
183
        // Get the list of nodes.
184
        drag.get('dragNode').removeClass(CSS.COURSECONTENT);
185
        var sectionlist = Y.Node.all(this.sectionlistselector);
186
 
187
        // Add a lightbox if it's not there.
188
        var lightbox = M.util.add_lightbox(Y, dragnode);
189
 
190
        // Handle any variables which we must pass via AJAX.
191
        var params = {},
192
            pageparams = this.get('config').pageparams,
193
            varname;
194
 
195
        for (varname in pageparams) {
196
            if (!pageparams.hasOwnProperty(varname)) {
197
                continue;
198
            }
199
            params[varname] = pageparams[varname];
200
        }
201
 
202
        // Prepare request parameters
203
        params.sesskey = M.cfg.sesskey;
204
        params.courseId = this.get('courseid');
205
        params['class'] = 'section';
206
        params.field = 'move';
207
        params.id = dragnodeid;
208
        params.value = dropnodeindex;
209
 
210
        // Perform the AJAX request.
211
        var uri = M.cfg.wwwroot + this.get('ajaxurl');
212
        Y.io(uri, {
213
            method: 'POST',
214
            data: params,
215
            on: {
216
                start: function() {
217
                    lightbox.show();
218
                },
219
                success: function(tid, response) {
220
                    // Update section titles, we can't simply swap them as
221
                    // they might have custom title
222
                    try {
223
                        var responsetext = Y.JSON.parse(response.responseText);
224
                        if (responsetext.error) {
225
                            new M.core.ajaxException(responsetext);
226
                        }
227
                        M.course.format.process_sections(Y, sectionlist, responsetext, loopstart, loopend);
228
                    } catch (e) {
229
                        // Ignore.
230
                    }
231
 
232
                    // Update all of the section IDs - first unset them, then set them
233
                    // to avoid duplicates in the DOM.
234
                    var index;
235
 
236
                    // Classic bubble sort algorithm is applied to the section
237
                    // nodes between original drag node location and the new one.
238
                    var swapped = false;
239
                    do {
240
                        swapped = false;
241
                        for (index = loopstart; index <= loopend; index++) {
242
                            if (Y.Moodle.core_course.util.section.getId(sectionlist.item(index - 1)) >
243
                                        Y.Moodle.core_course.util.section.getId(sectionlist.item(index))) {
244
                                Y.log("Swapping " + Y.Moodle.core_course.util.section.getId(sectionlist.item(index - 1)) +
245
                                        " with " + Y.Moodle.core_course.util.section.getId(sectionlist.item(index)));
246
                                // Swap section id.
247
                                var sectionid = sectionlist.item(index - 1).get('id');
248
                                sectionlist.item(index - 1).set('id', sectionlist.item(index).get('id'));
249
                                sectionlist.item(index).set('id', sectionid);
250
 
251
                                // See what format needs to swap.
252
                                M.course.format.swap_sections(Y, index - 1, index);
253
 
254
                                // Update flag.
255
                                swapped = true;
256
                            }
257
                            sectionlist.item(index).setAttribute('data-sectionid',
258
                                Y.Moodle.core_course.util.section.getId(sectionlist.item(index)));
259
                        }
260
                        loopend = loopend - 1;
261
                    } while (swapped);
262
 
263
                    window.setTimeout(function() {
264
                        lightbox.hide();
265
                    }, 250);
266
 
267
                    // Update course state.
268
                    M.course.coursebase.invoke_function('updateMovedSectionState');
269
                },
270
 
271
                failure: function(tid, response) {
272
                    this.ajax_failure(response);
273
                    lightbox.hide();
274
                }
275
            },
276
            context: this
277
        });
278
    }
279
 
280
}, {
281
    NAME: 'course-dragdrop-section',
282
    ATTRS: {
283
        courseid: {
284
            value: null
285
        },
286
        ajaxurl: {
287
            value: 0
288
        },
289
        config: {
290
            value: 0
291
        }
292
    }
293
});
294
 
295
M.course = M.course || {};
296
M.course.init_section_dragdrop = function(params) {
297
    new DRAGSECTION(params);
298
};