MDL-39824 theme_bootstrapbase: converted $PAGE use to new $OUTPUT methods.
[moodle.git] / lib / yui / src / blocks / js / blocks.js
CommitLineData
a94dd7d2
ARN
1var AJAXURL = '/lib/ajax/blocks.php',
2CSS = {
3 BLOCK : 'block',
4 BLOCKREGION : 'block-region',
5 BLOCKADMINBLOCK : 'block_adminblock',
6 EDITINGMOVE : 'editing_move',
7 HEADER : 'header',
8 LIGHTBOX : 'lightbox',
9 REGIONCONTENT : 'region-content',
10 SKIPBLOCK : 'skip-block',
11 SKIPBLOCKTO : 'skip-block-to',
12 MYINDEX : 'page-my-index',
13 REGIONMAIN : 'region-main'
14};
15
16var DRAGBLOCK = function() {
17 DRAGBLOCK.superclass.constructor.apply(this, arguments);
18};
19Y.extend(DRAGBLOCK, M.core.dragdrop, {
20 skipnodetop : null,
21 skipnodebottom : null,
22 dragsourceregion : null,
23 initializer : function() {
24 // Set group for parent class
25 this.groups = ['block'];
26 this.samenodeclass = CSS.BLOCK;
27 this.parentnodeclass = CSS.REGIONCONTENT;
28
29 // Add relevant classes and ID to 'content' block region on My Home page.
30 var myhomecontent = Y.Node.all('body#'+CSS.MYINDEX+' #'+CSS.REGIONMAIN+' > .'+CSS.REGIONCONTENT);
31 if (myhomecontent.size() > 0) {
32 var contentregion = myhomecontent.item(0);
33 contentregion.addClass(CSS.BLOCKREGION);
34 contentregion.set('id', CSS.REGIONCONTENT);
35 contentregion.one('div').addClass(CSS.REGIONCONTENT);
36 }
37
38 // Initialise blocks dragging
39 // Find all block regions on the page
40 var blockregionlist = Y.Node.all('div.'+CSS.BLOCKREGION);
41
42 if (blockregionlist.size() === 0) {
43 return false;
44 }
45
46 // See if we are missing either of block regions,
47 // if yes we need to add an empty one to use as target
48 if (blockregionlist.size() != this.get('regions').length) {
49 var blockregion = Y.Node.create('<div></div>')
50 .addClass(CSS.BLOCKREGION);
51 var regioncontent = Y.Node.create('<div></div>')
52 .addClass(CSS.REGIONCONTENT);
53 blockregion.appendChild(regioncontent);
54 var pre = blockregionlist.filter('#region-pre');
55 var post = blockregionlist.filter('#region-post');
56
57 if (pre.size() === 0 && post.size() === 1) {
58 // pre block is missing, instert it before post
59 blockregion.setAttrs({id : 'region-pre'});
60 post.item(0).insert(blockregion, 'before');
61 blockregionlist.unshift(blockregion);
62 } else if (post.size() === 0 && pre.size() === 1) {
63 // post block is missing, instert it after pre
64 blockregion.setAttrs({id : 'region-post'});
65 pre.item(0).insert(blockregion, 'after');
66 blockregionlist.push(blockregion);
67 }
68 }
69
70 blockregionlist.each(function(blockregionnode) {
71
72 // Setting blockregion as droptarget (the case when it is empty)
73 // The region-post (the right one)
74 // is very narrow, so add extra padding on the left to drop block on it.
75 var tar = new Y.DD.Drop({
76 node: blockregionnode.one('div.'+CSS.REGIONCONTENT),
77 groups: this.groups,
78 padding: '40 240 40 240'
79 });
80
81 // Make each div element in the list of blocks draggable
82 var del = new Y.DD.Delegate({
83 container: blockregionnode,
84 nodes: '.'+CSS.BLOCK,
85 target: true,
86 handles: ['.'+CSS.HEADER],
87 invalid: '.block-hider-hide, .block-hider-show, .moveto',
88 dragConfig: {groups: this.groups}
89 });
90 del.dd.plug(Y.Plugin.DDProxy, {
91 // Don't move the node at the end of the drag
92 moveOnEnd: false
93 });
94 del.dd.plug(Y.Plugin.DDWinScroll);
95
96 var blocklist = blockregionnode.all('.'+CSS.BLOCK);
97 blocklist.each(function(blocknode) {
98 var move = blocknode.one('a.'+CSS.EDITINGMOVE);
99 if (move) {
100 move.remove();
101 blocknode.one('.'+CSS.HEADER).setStyle('cursor', 'move');
102 }
103 }, this);
104 }, this);
105 },
106
107 get_block_id : function(node) {
108 return Number(node.get('id').replace(/inst/i, ''));
109 },
110
111 get_block_region : function(node) {
112 var region = node.ancestor('div.'+CSS.BLOCKREGION).get('id').replace(/region-/i, '');
113 if (Y.Array.indexOf(this.get('regions'), region) === -1) {
114 // Must be standard side-X
115 if (right_to_left()) {
116 if (region === 'post') {
117 region = 'pre';
118 } else if (region === 'pre') {
119 region = 'post';
120 }
121 }
122 return 'side-' + region;
123 }
124 // Perhaps custom region
125 return region;
126 },
127
128 get_region_id : function(node) {
129 return node.get('id').replace(/region-/i, '');
130 },
131
132 drag_start : function(e) {
133 // Get our drag object
134 var drag = e.target;
135
136 // Store the parent node of original drag node (block)
137 // we will need it later for show/hide empty regions
138 this.dragsourceregion = drag.get('node').ancestor('div.'+CSS.BLOCKREGION);
139
140 // Determine skipnodes and store them
141 if (drag.get('node').previous() && drag.get('node').previous().hasClass(CSS.SKIPBLOCK)) {
142 this.skipnodetop = drag.get('node').previous();
143 }
144 if (drag.get('node').next() && drag.get('node').next().hasClass(CSS.SKIPBLOCKTO)) {
145 this.skipnodebottom = drag.get('node').next();
146 }
147 },
148
149 drop_over : function(e) {
150 // Get a reference to our drag and drop nodes
151 var drag = e.drag.get('node');
152 var drop = e.drop.get('node');
153
154 // We need to fix the case when parent drop over event has determined
155 // 'goingup' and appended the drag node after admin-block.
156 if (drop.hasClass(this.parentnodeclass) && drop.one('.'+CSS.BLOCKADMINBLOCK) && drop.one('.'+CSS.BLOCKADMINBLOCK).next('.'+CSS.BLOCK)) {
157 drop.prepend(drag);
158 }
159
160 // Block is moved within the same region
161 // stop here, no need to modify anything.
162 if (this.dragsourceregion.contains(drop)) {
163 return false;
164 }
165
166 // TODO: Hiding-displaying block region only works for base theme blocks
167 // (region-pre, region-post) at the moment. It should be improved
168 // to work with custom block regions as well.
169
170 // TODO: Fix this for the case when user drag block towards empty section,
171 // then the section appears, then user chnages his mind and moving back to
172 // original section. The opposite section remains opened and empty.
173
174 var documentbody = Y.one('body');
175 // Moving block towards hidden region-content, display it
176 var regionname = this.get_region_id(this.dragsourceregion);
177 if (documentbody.hasClass('side-'+regionname+'-only')) {
178 documentbody.removeClass('side-'+regionname+'-only');
179 }
180
181 // Moving from empty region-content towards the opposite one,
182 // hide empty one (only for region-pre, region-post areas at the moment).
183 regionname = this.get_region_id(drop.ancestor('div.'+CSS.BLOCKREGION));
184 if (this.dragsourceregion.all('.'+CSS.BLOCK).size() == 0 && this.dragsourceregion.get('id').match(/(region-pre|region-post)/i)) {
185 if (!documentbody.hasClass('side-'+regionname+'-only')) {
186 documentbody.addClass('side-'+regionname+'-only');
187 }
188 }
189 },
190
191 drop_end : function() {
192 // clear variables
193 this.skipnodetop = null;
194 this.skipnodebottom = null;
195 this.dragsourceregion = null;
196 },
197
198 drag_dropmiss : function(e) {
199 // Missed the target, but we assume the user intended to drop it
200 // on the last last ghost node location, e.drag and e.drop should be
201 // prepared by global_drag_dropmiss parent so simulate drop_hit(e).
202 this.drop_hit(e);
203 },
204
205 drop_hit : function(e) {
206 var drag = e.drag;
207 // Get a reference to our drag node
208 var dragnode = drag.get('node');
209 var dropnode = e.drop.get('node');
210
211 // Amend existing skipnodes
212 if (dragnode.previous() && dragnode.previous().hasClass(CSS.SKIPBLOCK)) {
213 // the one that belongs to block below move below
214 dragnode.insert(dragnode.previous(), 'after');
215 }
216 // Move original skipnodes
217 if (this.skipnodetop) {
218 dragnode.insert(this.skipnodetop, 'before');
219 }
220 if (this.skipnodebottom) {
221 dragnode.insert(this.skipnodebottom, 'after');
222 }
223
224 // Add lightbox if it not there
225 var lightbox = M.util.add_lightbox(Y, dragnode);
226
227 // Prepare request parameters
228 var params = {
229 sesskey : M.cfg.sesskey,
230 courseid : this.get('courseid'),
231 pagelayout : this.get('pagelayout'),
232 pagetype : this.get('pagetype'),
233 subpage : this.get('subpage'),
234 contextid : this.get('contextid'),
235 action : 'move',
236 bui_moveid : this.get_block_id(dragnode),
237 bui_newregion : this.get_block_region(dropnode)
238 };
239
240 if (this.get('cmid')) {
241 params.cmid = this.get('cmid');
242 }
243
244 if (dragnode.next('.'+this.samenodeclass) && !dragnode.next('.'+this.samenodeclass).hasClass(CSS.BLOCKADMINBLOCK)) {
245 params.bui_beforeid = this.get_block_id(dragnode.next('.'+this.samenodeclass));
246 }
247
248 // Do AJAX request
249 Y.io(M.cfg.wwwroot+AJAXURL, {
250 method: 'POST',
251 data: params,
252 on: {
253 start : function() {
254 lightbox.show();
255 },
256 success: function(tid, response) {
257 window.setTimeout(function() {
258 lightbox.hide();
259 }, 250);
260 try {
261 var responsetext = Y.JSON.parse(response.responseText);
262 if (responsetext.error) {
263 new M.core.ajaxException(responsetext);
264 }
265 } catch (e) {}
266 },
267 failure: function(tid, response) {
268 this.ajax_failure(response);
269 lightbox.hide();
270 }
271 },
272 context:this
273 });
274 }
275}, {
276 NAME : 'core-blocks-dragdrop',
277 ATTRS : {
278 courseid : {
279 value : null
280 },
281 cmid : {
282 value : null
283 },
284 contextid : {
285 value : null
286 },
287 pagelayout : {
288 value : null
289 },
290 pagetype : {
291 value : null
292 },
293 subpage : {
294 value : null
295 },
296 regions : {
297 value : null
298 }
299 }
300});
301
302M.core_blocks = M.core_blocks || {};
303M.core_blocks.init_dragdrop = function(params) {
304 new DRAGBLOCK(params);
305};