MDL-33997 Repository should not support references by default
[moodle.git] / lib / yui / blocks / blocks.js
1 YUI.add('moodle-core-blocks', function(Y) {
3     var AJAXURL = '/lib/ajax/blocks.php',
4     CSS = {
5         BLOCK : 'block',
6         BLOCKREGION : 'block-region',
7         BLOCKADMINBLOCK : 'block_adminblock',
8         EDITINGMOVE : 'editing_move',
9         HEADER : 'header',
10         LIGHTBOX : 'lightbox',
11         PAGECONTENT : 'page-content',
12         REGIONCONTENT : 'region-content',
13         SKIPBLOCK : 'skip-block',
14         SKIPBLOCKTO : 'skip-block-to'
15     }
17     var DRAGBLOCK = function() {
18         DRAGBLOCK.superclass.constructor.apply(this, arguments);
19     };
20     Y.extend(DRAGBLOCK, M.core.dragdrop, {
21         skipnodetop : null,
22         skipnodebottom : null,
23         dragsourceregion : null,
24         initializer : function(params) {
25             // Set group for parent class
26             this.groups = ['block'];
27             this.samenodeclass = CSS.BLOCK;
28             this.parentnodeclass = CSS.REGIONCONTENT;
30             // Initialise blocks dragging
31             var blockregionlist = Y.Node.all('#'+CSS.PAGECONTENT+' div.'+CSS.BLOCKREGION);
33             if (blockregionlist.size() === 0) {
34                 return false;
35             }
37             // See if we are missing either of block regions,
38             // if yes we need to add an empty one to use as target
39             if (blockregionlist.size() != this.get('regions').length) {
40                 var blockregion = Y.Node.create('<div></div>')
41                     .addClass(CSS.BLOCKREGION);
42                 var regioncontent = Y.Node.create('<div></div>')
43                     .addClass(CSS.REGIONCONTENT);
44                 blockregion.appendChild(regioncontent);
46                 var regionid = this.get_region_id(blockregionlist.item(0));
47                 if (regionid === 'post') {
48                     // pre block is missing, instert it before post
49                     blockregion.setAttrs({id : 'region-pre'});
50                     blockregionlist.item(0).insert(blockregion, 'before');
51                     blockregionlist.unshift(blockregion);
52                 } else {
53                     // post block is missing, instert it after pre
54                     blockregion.setAttrs({id : 'region-post'});
55                     blockregionlist.item(0).insert(blockregion, 'after');
56                     blockregionlist.push(blockregion);
57                 }
58             }
60             blockregionlist.each(function(blockregionnode) {
62                 // Setting blockregion as droptarget (the case when it is empty)
63                 // The region-post (the right one)
64                 // is very narrow, so add extra padding on the left to drop block on it.
65                 var tar = new Y.DD.Drop({
66                     node: blockregionnode.one('div.'+CSS.REGIONCONTENT),
67                     groups: this.groups,
68                     padding: '40 240 40 240'
69                 });
71                 var blocklist = blockregionnode.all('.'+CSS.BLOCK);
72                 blocklist.each(function(blocknode) {
73                     var move = blocknode.one('a.'+CSS.EDITINGMOVE);
74                     if (move) {
75                         move.remove();
76                         blocknode.one('.'+CSS.HEADER).setStyle('cursor', 'move');
77                         // Make each div element in the list of blocks draggable
78                         var dd = new Y.DD.Drag({
79                             node: blocknode,
80                             groups: this.groups,
81                             // Make each div a Drop target too
82                             target: true,
83                             handles: ['.'+CSS.HEADER]
84                         }).plug(Y.Plugin.DDProxy, {
85                             // Don't move the node at the end of the drag
86                             moveOnEnd: false
87                         }).plug(Y.Plugin.DDConstrained, {
88                             // Keep it inside the .course-content
89                             constrain: '#'+CSS.PAGECONTENT
90                         });
91                     }
92                 }, this);
93             }, this);
94         },
96         get_block_id : function(node) {
97             return Number(node.get('id').replace(/inst/i, ''));
98         },
100         get_block_region : function(node) {
101             return node.ancestor('div.'+CSS.BLOCKREGION).get('id').replace(/region/i, 'side');
102         },
104         get_region_id : function(node) {
105             return node.get('id').replace(/region-/i, '');
106         },
108         drag_start : function(e) {
109             // Get our drag object
110             var drag = e.target;
112             // Store the parent node of original drag node (block)
113             // we will need it later for show/hide empty regions
114             this.dragsourceregion = drag.get('node').ancestor('div.'+CSS.BLOCKREGION);
116             // Determine skipnodes and store them
117             if (drag.get('node').previous() && drag.get('node').previous().hasClass(CSS.SKIPBLOCK)) {
118                 this.skipnodetop = drag.get('node').previous();
119             }
120             if (drag.get('node').next() && drag.get('node').next().hasClass(CSS.SKIPBLOCKTO)) {
121                 this.skipnodebottom = drag.get('node').next();
122             }
123         },
125         drop_over : function(e) {
126             // Get a reference to our drag and drop nodes
127             var drag = e.drag.get('node');
128             var drop = e.drop.get('node');
130             // We need to fix the case when parent drop over event has determined
131             // 'goingup' and appended the drag node after admin-block.
132             if (drop.hasClass(this.parentnodeclass) && drop.one('.'+CSS.BLOCKADMINBLOCK) && drop.one('.'+CSS.BLOCKADMINBLOCK).next('.'+CSS.BLOCK)) {
133                 drop.prepend(drag);
134             }
136             // Block is moved within the same region
137             // stop here, no need to modify anything.
138             if (this.dragsourceregion.contains(drop)) {
139                 return false;
140             }
142             // TODO: Fix this for the case when user drag block towards empty section,
143             // then the section appears, then user chnages his mind and moving back to
144             // original section. The opposite section remains opened and empty.
146             var documentbody = Y.one('body');
147             // Moving block towards hidden region-content, display it
148             var regionname = this.get_region_id(this.dragsourceregion);
149             if (documentbody.hasClass('side-'+regionname+'-only')) {
150                 documentbody.removeClass('side-'+regionname+'-only');
151             }
153             // Moving from empty region-content towards the opposite one,
154             // hide empty one
155             regionname = this.get_region_id(drop.ancestor('div.'+CSS.BLOCKREGION));
156             if (this.dragsourceregion.all('.'+CSS.BLOCK).size() == 0) {
157                 if (!documentbody.hasClass('side-'+regionname+'-only')) {
158                     documentbody.addClass('side-'+regionname+'-only');
159                 }
160             }
161         },
163         drop_end : function(e) {
164             // clear variables
165             this.skipnodetop = null;
166             this.skipnodebottom = null;
167             this.dragsourceregion = null;
168         },
170         drag_dropmiss : function(e) {
171             // Missed the target, but we assume the user intended to drop it
172             // on the last last ghost node location, e.drag and e.drop should be
173             // prepared by global_drag_dropmiss parent so simulate drop_hit(e).
174             this.drop_hit(e);
175         },
177         drop_hit : function(e) {
178             var drag = e.drag;
179             // Get a reference to our drag node
180             var dragnode = drag.get('node');
181             var dropnode = e.drop.get('node');
183             // Amend existing skipnodes
184             if (dragnode.previous() && dragnode.previous().hasClass(CSS.SKIPBLOCK)) {
185                 // the one that belongs to block below move below
186                 dragnode.insert(dragnode.previous(), 'after');
187             }
188             // Move original skipnodes
189             if (this.skipnodetop) {
190                 dragnode.insert(this.skipnodetop, 'before');
191             }
192             if (this.skipnodebottom) {
193                 dragnode.insert(this.skipnodebottom, 'after');
194             }
196             // Add lightbox if it not there
197             var lightbox = M.util.add_lightbox(Y, dragnode);
199             // Prepare request parameters
200             var params = {
201                 sesskey : M.cfg.sesskey,
202                 courseid : this.get('courseid'),
203                 pagelayout : this.get('pagelayout'),
204                 pagetype : this.get('pagetype'),
205                 action : 'move',
206                 bui_moveid : this.get_block_id(dragnode),
207                 bui_newregion : this.get_block_region(dropnode)
208             };
210             if (this.get('cmid')) {
211                 params.cmid = this.get('cmid');
212             }
214             if (dragnode.next('.'+this.samenodeclass) && !dragnode.next('.'+this.samenodeclass).hasClass(CSS.BLOCKADMINBLOCK)) {
215                 params.bui_beforeid = this.get_block_id(dragnode.next('.'+this.samenodeclass));
216             }
218             // Do AJAX request
219             Y.io(M.cfg.wwwroot+AJAXURL, {
220                 method: 'POST',
221                 data: params,
222                 on: {
223                     start : function(tid) {
224                         lightbox.show();
225                     },
226                     success: function(tid, response) {
227                         window.setTimeout(function(e) {
228                             lightbox.hide();
229                         }, 250);
230                         try {
231                             var responsetext = Y.JSON.parse(response.responseText);
232                             if (responsetext.error) {
233                                 new M.core.ajaxException(responsetext);
234                             }
235                         } catch (e) {}
236                     },
237                     failure: function(tid, response) {
238                         this.ajax_failure(response);
239                         lightbox.hide();
240                     }
241                 },
242                 context:this
243             });
244         }
245     }, {
246         NAME : 'core-blocks-dragdrop',
247         ATTRS : {
248             courseid : {
249                 value : null
250             },
251             cmid : {
252                 value : null
253             },
254             pagelayout : {
255                 value : null
256             },
257             pagetype : {
258                 value : null
259             },
260             regions : {
261                 value : null
262             }
263         }
264     });
266     M.core_blocks = M.core_blocks || {};
267     M.core_blocks.init_dragdrop = function(params) {
268         new DRAGBLOCK(params);
269     }
270 }, '@VERSION@', {requires:['base', 'node', 'io', 'dom', 'dd', 'moodle-core-dragdrop', 'moodle-enrol-notification']});