MDL-38517 JavaScript: Migrate moodle-core-blocks to use Shifter

This commit is contained in:
Andrew Robert Nicols
2013-03-24 18:39:57 +00:00
parent 373a8e052c
commit a94dd7d2b8
8 changed files with 1449 additions and 309 deletions
-309
View File
@@ -1,309 +0,0 @@
YUI.add('moodle-core-blocks', function(Y) {
var AJAXURL = '/lib/ajax/blocks.php',
CSS = {
BLOCK : 'block',
BLOCKREGION : 'block-region',
BLOCKADMINBLOCK : 'block_adminblock',
EDITINGMOVE : 'editing_move',
HEADER : 'header',
LIGHTBOX : 'lightbox',
REGIONCONTENT : 'region-content',
SKIPBLOCK : 'skip-block',
SKIPBLOCKTO : 'skip-block-to',
MYINDEX : 'page-my-index',
REGIONMAIN : 'region-main'
}
var DRAGBLOCK = function() {
DRAGBLOCK.superclass.constructor.apply(this, arguments);
};
Y.extend(DRAGBLOCK, M.core.dragdrop, {
skipnodetop : null,
skipnodebottom : null,
dragsourceregion : null,
initializer : function(params) {
// Set group for parent class
this.groups = ['block'];
this.samenodeclass = CSS.BLOCK;
this.parentnodeclass = CSS.REGIONCONTENT;
// Add relevant classes and ID to 'content' block region on My Home page.
var myhomecontent = Y.Node.all('body#'+CSS.MYINDEX+' #'+CSS.REGIONMAIN+' > .'+CSS.REGIONCONTENT);
if (myhomecontent.size() > 0) {
var contentregion = myhomecontent.item(0);
contentregion.addClass(CSS.BLOCKREGION);
contentregion.set('id', CSS.REGIONCONTENT);
contentregion.one('div').addClass(CSS.REGIONCONTENT);
}
// Initialise blocks dragging
// Find all block regions on the page
var blockregionlist = Y.Node.all('div.'+CSS.BLOCKREGION);
if (blockregionlist.size() === 0) {
return false;
}
// See if we are missing either of block regions,
// if yes we need to add an empty one to use as target
if (blockregionlist.size() != this.get('regions').length) {
var blockregion = Y.Node.create('<div></div>')
.addClass(CSS.BLOCKREGION);
var regioncontent = Y.Node.create('<div></div>')
.addClass(CSS.REGIONCONTENT);
blockregion.appendChild(regioncontent);
var pre = blockregionlist.filter('#region-pre');
var post = blockregionlist.filter('#region-post');
if (pre.size() === 0 && post.size() === 1) {
// pre block is missing, instert it before post
blockregion.setAttrs({id : 'region-pre'});
post.item(0).insert(blockregion, 'before');
blockregionlist.unshift(blockregion);
} else if (post.size() === 0 && pre.size() === 1) {
// post block is missing, instert it after pre
blockregion.setAttrs({id : 'region-post'});
pre.item(0).insert(blockregion, 'after');
blockregionlist.push(blockregion);
}
}
blockregionlist.each(function(blockregionnode) {
// Setting blockregion as droptarget (the case when it is empty)
// The region-post (the right one)
// is very narrow, so add extra padding on the left to drop block on it.
var tar = new Y.DD.Drop({
node: blockregionnode.one('div.'+CSS.REGIONCONTENT),
groups: this.groups,
padding: '40 240 40 240'
});
// Make each div element in the list of blocks draggable
var del = new Y.DD.Delegate({
container: blockregionnode,
nodes: '.'+CSS.BLOCK,
target: true,
handles: ['.'+CSS.HEADER],
invalid: '.block-hider-hide, .block-hider-show, .moveto',
dragConfig: {groups: this.groups}
});
del.dd.plug(Y.Plugin.DDProxy, {
// Don't move the node at the end of the drag
moveOnEnd: false
});
del.dd.plug(Y.Plugin.DDWinScroll);
var blocklist = blockregionnode.all('.'+CSS.BLOCK);
blocklist.each(function(blocknode) {
var move = blocknode.one('a.'+CSS.EDITINGMOVE);
if (move) {
move.remove();
blocknode.one('.'+CSS.HEADER).setStyle('cursor', 'move');
}
}, this);
}, this);
},
get_block_id : function(node) {
return Number(node.get('id').replace(/inst/i, ''));
},
get_block_region : function(node) {
var region = node.ancestor('div.'+CSS.BLOCKREGION).get('id').replace(/region-/i, '');
if (Y.Array.indexOf(this.get('regions'), region) === -1) {
// Must be standard side-X
if (right_to_left()) {
if (region == 'post') {
region = 'pre';
} else if (region == 'pre') {
region = 'post';
}
}
return 'side-' + region;
}
// Perhaps custom region
return region;
},
get_region_id : function(node) {
return node.get('id').replace(/region-/i, '');
},
drag_start : function(e) {
// Get our drag object
var drag = e.target;
// Store the parent node of original drag node (block)
// we will need it later for show/hide empty regions
this.dragsourceregion = drag.get('node').ancestor('div.'+CSS.BLOCKREGION);
// Determine skipnodes and store them
if (drag.get('node').previous() && drag.get('node').previous().hasClass(CSS.SKIPBLOCK)) {
this.skipnodetop = drag.get('node').previous();
}
if (drag.get('node').next() && drag.get('node').next().hasClass(CSS.SKIPBLOCKTO)) {
this.skipnodebottom = drag.get('node').next();
}
},
drop_over : function(e) {
// Get a reference to our drag and drop nodes
var drag = e.drag.get('node');
var drop = e.drop.get('node');
// We need to fix the case when parent drop over event has determined
// 'goingup' and appended the drag node after admin-block.
if (drop.hasClass(this.parentnodeclass) && drop.one('.'+CSS.BLOCKADMINBLOCK) && drop.one('.'+CSS.BLOCKADMINBLOCK).next('.'+CSS.BLOCK)) {
drop.prepend(drag);
}
// Block is moved within the same region
// stop here, no need to modify anything.
if (this.dragsourceregion.contains(drop)) {
return false;
}
// TODO: Hiding-displaying block region only works for base theme blocks
// (region-pre, region-post) at the moment. It should be improved
// to work with custom block regions as well.
// TODO: Fix this for the case when user drag block towards empty section,
// then the section appears, then user chnages his mind and moving back to
// original section. The opposite section remains opened and empty.
var documentbody = Y.one('body');
// Moving block towards hidden region-content, display it
var regionname = this.get_region_id(this.dragsourceregion);
if (documentbody.hasClass('side-'+regionname+'-only')) {
documentbody.removeClass('side-'+regionname+'-only');
}
// Moving from empty region-content towards the opposite one,
// hide empty one (only for region-pre, region-post areas at the moment).
regionname = this.get_region_id(drop.ancestor('div.'+CSS.BLOCKREGION));
if (this.dragsourceregion.all('.'+CSS.BLOCK).size() == 0 && this.dragsourceregion.get('id').match(/(region-pre|region-post)/i)) {
if (!documentbody.hasClass('side-'+regionname+'-only')) {
documentbody.addClass('side-'+regionname+'-only');
}
}
},
drop_end : function(e) {
// clear variables
this.skipnodetop = null;
this.skipnodebottom = null;
this.dragsourceregion = null;
},
drag_dropmiss : function(e) {
// Missed the target, but we assume the user intended to drop it
// on the last last ghost node location, e.drag and e.drop should be
// prepared by global_drag_dropmiss parent so simulate drop_hit(e).
this.drop_hit(e);
},
drop_hit : function(e) {
var drag = e.drag;
// Get a reference to our drag node
var dragnode = drag.get('node');
var dropnode = e.drop.get('node');
// Amend existing skipnodes
if (dragnode.previous() && dragnode.previous().hasClass(CSS.SKIPBLOCK)) {
// the one that belongs to block below move below
dragnode.insert(dragnode.previous(), 'after');
}
// Move original skipnodes
if (this.skipnodetop) {
dragnode.insert(this.skipnodetop, 'before');
}
if (this.skipnodebottom) {
dragnode.insert(this.skipnodebottom, 'after');
}
// Add lightbox if it not there
var lightbox = M.util.add_lightbox(Y, dragnode);
// Prepare request parameters
var params = {
sesskey : M.cfg.sesskey,
courseid : this.get('courseid'),
pagelayout : this.get('pagelayout'),
pagetype : this.get('pagetype'),
subpage : this.get('subpage'),
contextid : this.get('contextid'),
action : 'move',
bui_moveid : this.get_block_id(dragnode),
bui_newregion : this.get_block_region(dropnode)
};
if (this.get('cmid')) {
params.cmid = this.get('cmid');
}
if (dragnode.next('.'+this.samenodeclass) && !dragnode.next('.'+this.samenodeclass).hasClass(CSS.BLOCKADMINBLOCK)) {
params.bui_beforeid = this.get_block_id(dragnode.next('.'+this.samenodeclass));
}
// Do AJAX request
Y.io(M.cfg.wwwroot+AJAXURL, {
method: 'POST',
data: params,
on: {
start : function(tid) {
lightbox.show();
},
success: function(tid, response) {
window.setTimeout(function(e) {
lightbox.hide();
}, 250);
try {
var responsetext = Y.JSON.parse(response.responseText);
if (responsetext.error) {
new M.core.ajaxException(responsetext);
}
} catch (e) {}
},
failure: function(tid, response) {
this.ajax_failure(response);
lightbox.hide();
}
},
context:this
});
}
}, {
NAME : 'core-blocks-dragdrop',
ATTRS : {
courseid : {
value : null
},
cmid : {
value : null
},
contextid : {
value : null
},
pagelayout : {
value : null
},
pagetype : {
value : null
},
subpage : {
value : null
},
regions : {
value : null
}
}
});
M.core_blocks = M.core_blocks || {};
M.core_blocks.init_dragdrop = function(params) {
new DRAGBLOCK(params);
}
}, '@VERSION@', {requires:['base', 'node', 'io', 'dom', 'dd', 'dd-scroll', 'moodle-core-dragdrop', 'moodle-core-notification']});
File diff suppressed because one or more lines are too long
@@ -0,0 +1,321 @@
YUI.add('moodle-core-blocks', function (Y, NAME) {
var AJAXURL = '/lib/ajax/blocks.php',
CSS = {
BLOCK : 'block',
BLOCKREGION : 'block-region',
BLOCKADMINBLOCK : 'block_adminblock',
EDITINGMOVE : 'editing_move',
HEADER : 'header',
LIGHTBOX : 'lightbox',
REGIONCONTENT : 'region-content',
SKIPBLOCK : 'skip-block',
SKIPBLOCKTO : 'skip-block-to',
MYINDEX : 'page-my-index',
REGIONMAIN : 'region-main'
};
var DRAGBLOCK = function() {
DRAGBLOCK.superclass.constructor.apply(this, arguments);
};
Y.extend(DRAGBLOCK, M.core.dragdrop, {
skipnodetop : null,
skipnodebottom : null,
dragsourceregion : null,
initializer : function() {
// Set group for parent class
this.groups = ['block'];
this.samenodeclass = CSS.BLOCK;
this.parentnodeclass = CSS.REGIONCONTENT;
// Add relevant classes and ID to 'content' block region on My Home page.
var myhomecontent = Y.Node.all('body#'+CSS.MYINDEX+' #'+CSS.REGIONMAIN+' > .'+CSS.REGIONCONTENT);
if (myhomecontent.size() > 0) {
var contentregion = myhomecontent.item(0);
contentregion.addClass(CSS.BLOCKREGION);
contentregion.set('id', CSS.REGIONCONTENT);
contentregion.one('div').addClass(CSS.REGIONCONTENT);
}
// Initialise blocks dragging
// Find all block regions on the page
var blockregionlist = Y.Node.all('div.'+CSS.BLOCKREGION);
if (blockregionlist.size() === 0) {
return false;
}
// See if we are missing either of block regions,
// if yes we need to add an empty one to use as target
if (blockregionlist.size() != this.get('regions').length) {
var blockregion = Y.Node.create('<div></div>')
.addClass(CSS.BLOCKREGION);
var regioncontent = Y.Node.create('<div></div>')
.addClass(CSS.REGIONCONTENT);
blockregion.appendChild(regioncontent);
var pre = blockregionlist.filter('#region-pre');
var post = blockregionlist.filter('#region-post');
if (pre.size() === 0 && post.size() === 1) {
// pre block is missing, instert it before post
blockregion.setAttrs({id : 'region-pre'});
post.item(0).insert(blockregion, 'before');
blockregionlist.unshift(blockregion);
} else if (post.size() === 0 && pre.size() === 1) {
// post block is missing, instert it after pre
blockregion.setAttrs({id : 'region-post'});
pre.item(0).insert(blockregion, 'after');
blockregionlist.push(blockregion);
}
}
blockregionlist.each(function(blockregionnode) {
// Setting blockregion as droptarget (the case when it is empty)
// The region-post (the right one)
// is very narrow, so add extra padding on the left to drop block on it.
var tar = new Y.DD.Drop({
node: blockregionnode.one('div.'+CSS.REGIONCONTENT),
groups: this.groups,
padding: '40 240 40 240'
});
// Make each div element in the list of blocks draggable
var del = new Y.DD.Delegate({
container: blockregionnode,
nodes: '.'+CSS.BLOCK,
target: true,
handles: ['.'+CSS.HEADER],
invalid: '.block-hider-hide, .block-hider-show, .moveto',
dragConfig: {groups: this.groups}
});
del.dd.plug(Y.Plugin.DDProxy, {
// Don't move the node at the end of the drag
moveOnEnd: false
});
del.dd.plug(Y.Plugin.DDWinScroll);
var blocklist = blockregionnode.all('.'+CSS.BLOCK);
blocklist.each(function(blocknode) {
var move = blocknode.one('a.'+CSS.EDITINGMOVE);
if (move) {
move.remove();
blocknode.one('.'+CSS.HEADER).setStyle('cursor', 'move');
}
}, this);
}, this);
},
get_block_id : function(node) {
return Number(node.get('id').replace(/inst/i, ''));
},
get_block_region : function(node) {
var region = node.ancestor('div.'+CSS.BLOCKREGION).get('id').replace(/region-/i, '');
if (Y.Array.indexOf(this.get('regions'), region) === -1) {
// Must be standard side-X
if (right_to_left()) {
if (region === 'post') {
region = 'pre';
} else if (region === 'pre') {
region = 'post';
}
}
return 'side-' + region;
}
// Perhaps custom region
return region;
},
get_region_id : function(node) {
return node.get('id').replace(/region-/i, '');
},
drag_start : function(e) {
// Get our drag object
var drag = e.target;
// Store the parent node of original drag node (block)
// we will need it later for show/hide empty regions
this.dragsourceregion = drag.get('node').ancestor('div.'+CSS.BLOCKREGION);
// Determine skipnodes and store them
if (drag.get('node').previous() && drag.get('node').previous().hasClass(CSS.SKIPBLOCK)) {
this.skipnodetop = drag.get('node').previous();
}
if (drag.get('node').next() && drag.get('node').next().hasClass(CSS.SKIPBLOCKTO)) {
this.skipnodebottom = drag.get('node').next();
}
},
drop_over : function(e) {
// Get a reference to our drag and drop nodes
var drag = e.drag.get('node');
var drop = e.drop.get('node');
// We need to fix the case when parent drop over event has determined
// 'goingup' and appended the drag node after admin-block.
if (drop.hasClass(this.parentnodeclass) && drop.one('.'+CSS.BLOCKADMINBLOCK) && drop.one('.'+CSS.BLOCKADMINBLOCK).next('.'+CSS.BLOCK)) {
drop.prepend(drag);
}
// Block is moved within the same region
// stop here, no need to modify anything.
if (this.dragsourceregion.contains(drop)) {
return false;
}
// TODO: Hiding-displaying block region only works for base theme blocks
// (region-pre, region-post) at the moment. It should be improved
// to work with custom block regions as well.
// TODO: Fix this for the case when user drag block towards empty section,
// then the section appears, then user chnages his mind and moving back to
// original section. The opposite section remains opened and empty.
var documentbody = Y.one('body');
// Moving block towards hidden region-content, display it
var regionname = this.get_region_id(this.dragsourceregion);
if (documentbody.hasClass('side-'+regionname+'-only')) {
documentbody.removeClass('side-'+regionname+'-only');
}
// Moving from empty region-content towards the opposite one,
// hide empty one (only for region-pre, region-post areas at the moment).
regionname = this.get_region_id(drop.ancestor('div.'+CSS.BLOCKREGION));
if (this.dragsourceregion.all('.'+CSS.BLOCK).size() == 0 && this.dragsourceregion.get('id').match(/(region-pre|region-post)/i)) {
if (!documentbody.hasClass('side-'+regionname+'-only')) {
documentbody.addClass('side-'+regionname+'-only');
}
}
},
drop_end : function() {
// clear variables
this.skipnodetop = null;
this.skipnodebottom = null;
this.dragsourceregion = null;
},
drag_dropmiss : function(e) {
// Missed the target, but we assume the user intended to drop it
// on the last last ghost node location, e.drag and e.drop should be
// prepared by global_drag_dropmiss parent so simulate drop_hit(e).
this.drop_hit(e);
},
drop_hit : function(e) {
var drag = e.drag;
// Get a reference to our drag node
var dragnode = drag.get('node');
var dropnode = e.drop.get('node');
// Amend existing skipnodes
if (dragnode.previous() && dragnode.previous().hasClass(CSS.SKIPBLOCK)) {
// the one that belongs to block below move below
dragnode.insert(dragnode.previous(), 'after');
}
// Move original skipnodes
if (this.skipnodetop) {
dragnode.insert(this.skipnodetop, 'before');
}
if (this.skipnodebottom) {
dragnode.insert(this.skipnodebottom, 'after');
}
// Add lightbox if it not there
var lightbox = M.util.add_lightbox(Y, dragnode);
// Prepare request parameters
var params = {
sesskey : M.cfg.sesskey,
courseid : this.get('courseid'),
pagelayout : this.get('pagelayout'),
pagetype : this.get('pagetype'),
subpage : this.get('subpage'),
contextid : this.get('contextid'),
action : 'move',
bui_moveid : this.get_block_id(dragnode),
bui_newregion : this.get_block_region(dropnode)
};
if (this.get('cmid')) {
params.cmid = this.get('cmid');
}
if (dragnode.next('.'+this.samenodeclass) && !dragnode.next('.'+this.samenodeclass).hasClass(CSS.BLOCKADMINBLOCK)) {
params.bui_beforeid = this.get_block_id(dragnode.next('.'+this.samenodeclass));
}
// Do AJAX request
Y.io(M.cfg.wwwroot+AJAXURL, {
method: 'POST',
data: params,
on: {
start : function() {
lightbox.show();
},
success: function(tid, response) {
window.setTimeout(function() {
lightbox.hide();
}, 250);
try {
var responsetext = Y.JSON.parse(response.responseText);
if (responsetext.error) {
new M.core.ajaxException(responsetext);
}
} catch (e) {}
},
failure: function(tid, response) {
this.ajax_failure(response);
lightbox.hide();
}
},
context:this
});
}
}, {
NAME : 'core-blocks-dragdrop',
ATTRS : {
courseid : {
value : null
},
cmid : {
value : null
},
contextid : {
value : null
},
pagelayout : {
value : null
},
pagetype : {
value : null
},
subpage : {
value : null
},
regions : {
value : null
}
}
});
M.core_blocks = M.core_blocks || {};
M.core_blocks.init_dragdrop = function(params) {
new DRAGBLOCK(params);
};
}, '@VERSION@', {
"requires": [
"base",
"node",
"io",
"dom",
"dd",
"dd-scroll",
"moodle-core-dragdrop",
"moodle-core-notification"
]
});
@@ -0,0 +1 @@
YUI.add("moodle-core-blocks",function(e,t){var n="/lib/ajax/blocks.php",r={BLOCK:"block",BLOCKREGION:"block-region",BLOCKADMINBLOCK:"block_adminblock",EDITINGMOVE:"editing_move",HEADER:"header",LIGHTBOX:"lightbox",REGIONCONTENT:"region-content",SKIPBLOCK:"skip-block",SKIPBLOCKTO:"skip-block-to",MYINDEX:"page-my-index",REGIONMAIN:"region-main"},i=function(){i.superclass.constructor.apply(this,arguments)};e.extend(i,M.core.dragdrop,{skipnodetop:null,skipnodebottom:null,dragsourceregion:null,initializer:function(){this.groups=["block"],this.samenodeclass=r.BLOCK,this.parentnodeclass=r.REGIONCONTENT;var t=e.Node.all("body#"+r.MYINDEX+" #"+r.REGIONMAIN+" > ."+r.REGIONCONTENT);if(t.size()>0){var n=t.item(0);n.addClass(r.BLOCKREGION),n.set("id",r.REGIONCONTENT),n.one("div").addClass(r.REGIONCONTENT)}var i=e.Node.all("div."+r.BLOCKREGION);if(i.size()===0)return!1;if(i.size()!=this.get("regions").length){var s=e.Node.create("<div></div>").addClass(r.BLOCKREGION),o=e.Node.create("<div></div>").addClass(r.REGIONCONTENT);s.appendChild(o);var u=i.filter("#region-pre"),a=i.filter("#region-post");u.size()===0&&a.size()===1?(s.setAttrs({id:"region-pre"}),a.item(0).insert(s,"before"),i.unshift(s)):a.size()===0&&u.size()===1&&(s.setAttrs({id:"region-post"}),u.item(0).insert(s,"after"),i.push(s))}i.each(function(t){var n=new e.DD.Drop({node:t.one("div."+r.REGIONCONTENT),groups:this.groups,padding:"40 240 40 240"}),i=new e.DD.Delegate({container:t,nodes:"."+r.BLOCK,target:!0,handles:["."+r.HEADER],invalid:".block-hider-hide, .block-hider-show, .moveto",dragConfig:{groups:this.groups}});i.dd.plug(e.Plugin.DDProxy,{moveOnEnd:!1}),i.dd.plug(e.Plugin.DDWinScroll);var s=t.all("."+r.BLOCK);s.each(function(e){var t=e.one("a."+r.EDITINGMOVE);t&&(t.remove(),e.one("."+r.HEADER).setStyle("cursor","move"))},this)},this)},get_block_id:function(e){return Number(e.get("id").replace(/inst/i,""))},get_block_region:function(t){var n=t.ancestor("div."+r.BLOCKREGION).get("id").replace(/region-/i,"");return e.Array.indexOf(this.get("regions"),n)===-1?(right_to_left()&&(n==="post"?n="pre":n==="pre"&&(n="post")),"side-"+n):n},get_region_id:function(e){return e.get("id").replace(/region-/i,"")},drag_start:function(e){var t=e.target;this.dragsourceregion=t.get("node").ancestor("div."+r.BLOCKREGION),t.get("node").previous()&&t.get("node").previous().hasClass(r.SKIPBLOCK)&&(this.skipnodetop=t.get("node").previous()),t.get("node").next()&&t.get("node").next().hasClass(r.SKIPBLOCKTO)&&(this.skipnodebottom=t.get("node").next())},drop_over:function(t){var n=t.drag.get("node"),i=t.drop.get("node");i.hasClass(this.parentnodeclass)&&i.one("."+r.BLOCKADMINBLOCK)&&i.one("."+r.BLOCKADMINBLOCK).next("."+r.BLOCK)&&i.prepend(n);if(this.dragsourceregion.contains(i))return!1;var s=e.one("body"),o=this.get_region_id(this.dragsourceregion);s.hasClass("side-"+o+"-only")&&s.removeClass("side-"+o+"-only"),o=this.get_region_id(i.ancestor("div."+r.BLOCKREGION)),this.dragsourceregion.all("."+r.BLOCK).size()==0&&this.dragsourceregion.get("id").match(/(region-pre|region-post)/i)&&(s.hasClass("side-"+o+"-only")||s.addClass("side-"+o+"-only"))},drop_end:function(){this.skipnodetop=null,this.skipnodebottom=null,this.dragsourceregion=null},drag_dropmiss:function(e){this.drop_hit(e)},drop_hit:function(t){var i=t.drag,s=i.get("node"),o=t.drop.get("node");s.previous()&&s.previous().hasClass(r.SKIPBLOCK)&&s.insert(s.previous(),"after"),this.skipnodetop&&s.insert(this.skipnodetop,"before"),this.skipnodebottom&&s.insert(this.skipnodebottom,"after");var u=M.util.add_lightbox(e,s),a={sesskey:M.cfg.sesskey,courseid:this.get("courseid"),pagelayout:this.get("pagelayout"),pagetype:this.get("pagetype"),subpage:this.get("subpage"),contextid:this.get("contextid"),action:"move",bui_moveid:this.get_block_id(s),bui_newregion:this.get_block_region(o)};this.get("cmid")&&(a.cmid=this.get("cmid")),s.next("."+this.samenodeclass)&&!s.next("."+this.samenodeclass).hasClass(r.BLOCKADMINBLOCK)&&(a.bui_beforeid=this.get_block_id(s.next("."+this.samenodeclass))),e.io(M.cfg.wwwroot+n,{method:"POST",data:a,on:{start:function(){u.show()},success:function(t,n){window.setTimeout(function(){u.hide()},250);try{var r=e.JSON.parse(n.responseText);r.error&&new M.core.ajaxException(r)}catch(i){}},failure:function(e,t){this.ajax_failure(t),u.hide()}},context:this})}},{NAME:"core-blocks-dragdrop",ATTRS:{courseid:{value:null},cmid:{value:null},contextid:{value:null},pagelayout:{value:null},pagetype:{value:null},subpage:{value:null},regions:{value:null}}}),M.core_blocks=M.core_blocks||{},M.core_blocks.init_dragdrop=function(e){new i(e)}},"@VERSION@",{requires:["base","node","io","dom","dd","dd-scroll","moodle-core-dragdrop","moodle-core-notification"]});
+321
View File
@@ -0,0 +1,321 @@
YUI.add('moodle-core-blocks', function (Y, NAME) {
var AJAXURL = '/lib/ajax/blocks.php',
CSS = {
BLOCK : 'block',
BLOCKREGION : 'block-region',
BLOCKADMINBLOCK : 'block_adminblock',
EDITINGMOVE : 'editing_move',
HEADER : 'header',
LIGHTBOX : 'lightbox',
REGIONCONTENT : 'region-content',
SKIPBLOCK : 'skip-block',
SKIPBLOCKTO : 'skip-block-to',
MYINDEX : 'page-my-index',
REGIONMAIN : 'region-main'
};
var DRAGBLOCK = function() {
DRAGBLOCK.superclass.constructor.apply(this, arguments);
};
Y.extend(DRAGBLOCK, M.core.dragdrop, {
skipnodetop : null,
skipnodebottom : null,
dragsourceregion : null,
initializer : function() {
// Set group for parent class
this.groups = ['block'];
this.samenodeclass = CSS.BLOCK;
this.parentnodeclass = CSS.REGIONCONTENT;
// Add relevant classes and ID to 'content' block region on My Home page.
var myhomecontent = Y.Node.all('body#'+CSS.MYINDEX+' #'+CSS.REGIONMAIN+' > .'+CSS.REGIONCONTENT);
if (myhomecontent.size() > 0) {
var contentregion = myhomecontent.item(0);
contentregion.addClass(CSS.BLOCKREGION);
contentregion.set('id', CSS.REGIONCONTENT);
contentregion.one('div').addClass(CSS.REGIONCONTENT);
}
// Initialise blocks dragging
// Find all block regions on the page
var blockregionlist = Y.Node.all('div.'+CSS.BLOCKREGION);
if (blockregionlist.size() === 0) {
return false;
}
// See if we are missing either of block regions,
// if yes we need to add an empty one to use as target
if (blockregionlist.size() != this.get('regions').length) {
var blockregion = Y.Node.create('<div></div>')
.addClass(CSS.BLOCKREGION);
var regioncontent = Y.Node.create('<div></div>')
.addClass(CSS.REGIONCONTENT);
blockregion.appendChild(regioncontent);
var pre = blockregionlist.filter('#region-pre');
var post = blockregionlist.filter('#region-post');
if (pre.size() === 0 && post.size() === 1) {
// pre block is missing, instert it before post
blockregion.setAttrs({id : 'region-pre'});
post.item(0).insert(blockregion, 'before');
blockregionlist.unshift(blockregion);
} else if (post.size() === 0 && pre.size() === 1) {
// post block is missing, instert it after pre
blockregion.setAttrs({id : 'region-post'});
pre.item(0).insert(blockregion, 'after');
blockregionlist.push(blockregion);
}
}
blockregionlist.each(function(blockregionnode) {
// Setting blockregion as droptarget (the case when it is empty)
// The region-post (the right one)
// is very narrow, so add extra padding on the left to drop block on it.
var tar = new Y.DD.Drop({
node: blockregionnode.one('div.'+CSS.REGIONCONTENT),
groups: this.groups,
padding: '40 240 40 240'
});
// Make each div element in the list of blocks draggable
var del = new Y.DD.Delegate({
container: blockregionnode,
nodes: '.'+CSS.BLOCK,
target: true,
handles: ['.'+CSS.HEADER],
invalid: '.block-hider-hide, .block-hider-show, .moveto',
dragConfig: {groups: this.groups}
});
del.dd.plug(Y.Plugin.DDProxy, {
// Don't move the node at the end of the drag
moveOnEnd: false
});
del.dd.plug(Y.Plugin.DDWinScroll);
var blocklist = blockregionnode.all('.'+CSS.BLOCK);
blocklist.each(function(blocknode) {
var move = blocknode.one('a.'+CSS.EDITINGMOVE);
if (move) {
move.remove();
blocknode.one('.'+CSS.HEADER).setStyle('cursor', 'move');
}
}, this);
}, this);
},
get_block_id : function(node) {
return Number(node.get('id').replace(/inst/i, ''));
},
get_block_region : function(node) {
var region = node.ancestor('div.'+CSS.BLOCKREGION).get('id').replace(/region-/i, '');
if (Y.Array.indexOf(this.get('regions'), region) === -1) {
// Must be standard side-X
if (right_to_left()) {
if (region === 'post') {
region = 'pre';
} else if (region === 'pre') {
region = 'post';
}
}
return 'side-' + region;
}
// Perhaps custom region
return region;
},
get_region_id : function(node) {
return node.get('id').replace(/region-/i, '');
},
drag_start : function(e) {
// Get our drag object
var drag = e.target;
// Store the parent node of original drag node (block)
// we will need it later for show/hide empty regions
this.dragsourceregion = drag.get('node').ancestor('div.'+CSS.BLOCKREGION);
// Determine skipnodes and store them
if (drag.get('node').previous() && drag.get('node').previous().hasClass(CSS.SKIPBLOCK)) {
this.skipnodetop = drag.get('node').previous();
}
if (drag.get('node').next() && drag.get('node').next().hasClass(CSS.SKIPBLOCKTO)) {
this.skipnodebottom = drag.get('node').next();
}
},
drop_over : function(e) {
// Get a reference to our drag and drop nodes
var drag = e.drag.get('node');
var drop = e.drop.get('node');
// We need to fix the case when parent drop over event has determined
// 'goingup' and appended the drag node after admin-block.
if (drop.hasClass(this.parentnodeclass) && drop.one('.'+CSS.BLOCKADMINBLOCK) && drop.one('.'+CSS.BLOCKADMINBLOCK).next('.'+CSS.BLOCK)) {
drop.prepend(drag);
}
// Block is moved within the same region
// stop here, no need to modify anything.
if (this.dragsourceregion.contains(drop)) {
return false;
}
// TODO: Hiding-displaying block region only works for base theme blocks
// (region-pre, region-post) at the moment. It should be improved
// to work with custom block regions as well.
// TODO: Fix this for the case when user drag block towards empty section,
// then the section appears, then user chnages his mind and moving back to
// original section. The opposite section remains opened and empty.
var documentbody = Y.one('body');
// Moving block towards hidden region-content, display it
var regionname = this.get_region_id(this.dragsourceregion);
if (documentbody.hasClass('side-'+regionname+'-only')) {
documentbody.removeClass('side-'+regionname+'-only');
}
// Moving from empty region-content towards the opposite one,
// hide empty one (only for region-pre, region-post areas at the moment).
regionname = this.get_region_id(drop.ancestor('div.'+CSS.BLOCKREGION));
if (this.dragsourceregion.all('.'+CSS.BLOCK).size() == 0 && this.dragsourceregion.get('id').match(/(region-pre|region-post)/i)) {
if (!documentbody.hasClass('side-'+regionname+'-only')) {
documentbody.addClass('side-'+regionname+'-only');
}
}
},
drop_end : function() {
// clear variables
this.skipnodetop = null;
this.skipnodebottom = null;
this.dragsourceregion = null;
},
drag_dropmiss : function(e) {
// Missed the target, but we assume the user intended to drop it
// on the last last ghost node location, e.drag and e.drop should be
// prepared by global_drag_dropmiss parent so simulate drop_hit(e).
this.drop_hit(e);
},
drop_hit : function(e) {
var drag = e.drag;
// Get a reference to our drag node
var dragnode = drag.get('node');
var dropnode = e.drop.get('node');
// Amend existing skipnodes
if (dragnode.previous() && dragnode.previous().hasClass(CSS.SKIPBLOCK)) {
// the one that belongs to block below move below
dragnode.insert(dragnode.previous(), 'after');
}
// Move original skipnodes
if (this.skipnodetop) {
dragnode.insert(this.skipnodetop, 'before');
}
if (this.skipnodebottom) {
dragnode.insert(this.skipnodebottom, 'after');
}
// Add lightbox if it not there
var lightbox = M.util.add_lightbox(Y, dragnode);
// Prepare request parameters
var params = {
sesskey : M.cfg.sesskey,
courseid : this.get('courseid'),
pagelayout : this.get('pagelayout'),
pagetype : this.get('pagetype'),
subpage : this.get('subpage'),
contextid : this.get('contextid'),
action : 'move',
bui_moveid : this.get_block_id(dragnode),
bui_newregion : this.get_block_region(dropnode)
};
if (this.get('cmid')) {
params.cmid = this.get('cmid');
}
if (dragnode.next('.'+this.samenodeclass) && !dragnode.next('.'+this.samenodeclass).hasClass(CSS.BLOCKADMINBLOCK)) {
params.bui_beforeid = this.get_block_id(dragnode.next('.'+this.samenodeclass));
}
// Do AJAX request
Y.io(M.cfg.wwwroot+AJAXURL, {
method: 'POST',
data: params,
on: {
start : function() {
lightbox.show();
},
success: function(tid, response) {
window.setTimeout(function() {
lightbox.hide();
}, 250);
try {
var responsetext = Y.JSON.parse(response.responseText);
if (responsetext.error) {
new M.core.ajaxException(responsetext);
}
} catch (e) {}
},
failure: function(tid, response) {
this.ajax_failure(response);
lightbox.hide();
}
},
context:this
});
}
}, {
NAME : 'core-blocks-dragdrop',
ATTRS : {
courseid : {
value : null
},
cmid : {
value : null
},
contextid : {
value : null
},
pagelayout : {
value : null
},
pagetype : {
value : null
},
subpage : {
value : null
},
regions : {
value : null
}
}
});
M.core_blocks = M.core_blocks || {};
M.core_blocks.init_dragdrop = function(params) {
new DRAGBLOCK(params);
};
}, '@VERSION@', {
"requires": [
"base",
"node",
"io",
"dom",
"dd",
"dd-scroll",
"moodle-core-dragdrop",
"moodle-core-notification"
]
});
+10
View File
@@ -0,0 +1,10 @@
{
"name": "moodle-core-blocks",
"builds": {
"moodle-core-blocks": {
"jsfiles": [
"blocks.js"
]
}
}
}
+305
View File
@@ -0,0 +1,305 @@
var AJAXURL = '/lib/ajax/blocks.php',
CSS = {
BLOCK : 'block',
BLOCKREGION : 'block-region',
BLOCKADMINBLOCK : 'block_adminblock',
EDITINGMOVE : 'editing_move',
HEADER : 'header',
LIGHTBOX : 'lightbox',
REGIONCONTENT : 'region-content',
SKIPBLOCK : 'skip-block',
SKIPBLOCKTO : 'skip-block-to',
MYINDEX : 'page-my-index',
REGIONMAIN : 'region-main'
};
var DRAGBLOCK = function() {
DRAGBLOCK.superclass.constructor.apply(this, arguments);
};
Y.extend(DRAGBLOCK, M.core.dragdrop, {
skipnodetop : null,
skipnodebottom : null,
dragsourceregion : null,
initializer : function() {
// Set group for parent class
this.groups = ['block'];
this.samenodeclass = CSS.BLOCK;
this.parentnodeclass = CSS.REGIONCONTENT;
// Add relevant classes and ID to 'content' block region on My Home page.
var myhomecontent = Y.Node.all('body#'+CSS.MYINDEX+' #'+CSS.REGIONMAIN+' > .'+CSS.REGIONCONTENT);
if (myhomecontent.size() > 0) {
var contentregion = myhomecontent.item(0);
contentregion.addClass(CSS.BLOCKREGION);
contentregion.set('id', CSS.REGIONCONTENT);
contentregion.one('div').addClass(CSS.REGIONCONTENT);
}
// Initialise blocks dragging
// Find all block regions on the page
var blockregionlist = Y.Node.all('div.'+CSS.BLOCKREGION);
if (blockregionlist.size() === 0) {
return false;
}
// See if we are missing either of block regions,
// if yes we need to add an empty one to use as target
if (blockregionlist.size() != this.get('regions').length) {
var blockregion = Y.Node.create('<div></div>')
.addClass(CSS.BLOCKREGION);
var regioncontent = Y.Node.create('<div></div>')
.addClass(CSS.REGIONCONTENT);
blockregion.appendChild(regioncontent);
var pre = blockregionlist.filter('#region-pre');
var post = blockregionlist.filter('#region-post');
if (pre.size() === 0 && post.size() === 1) {
// pre block is missing, instert it before post
blockregion.setAttrs({id : 'region-pre'});
post.item(0).insert(blockregion, 'before');
blockregionlist.unshift(blockregion);
} else if (post.size() === 0 && pre.size() === 1) {
// post block is missing, instert it after pre
blockregion.setAttrs({id : 'region-post'});
pre.item(0).insert(blockregion, 'after');
blockregionlist.push(blockregion);
}
}
blockregionlist.each(function(blockregionnode) {
// Setting blockregion as droptarget (the case when it is empty)
// The region-post (the right one)
// is very narrow, so add extra padding on the left to drop block on it.
var tar = new Y.DD.Drop({
node: blockregionnode.one('div.'+CSS.REGIONCONTENT),
groups: this.groups,
padding: '40 240 40 240'
});
// Make each div element in the list of blocks draggable
var del = new Y.DD.Delegate({
container: blockregionnode,
nodes: '.'+CSS.BLOCK,
target: true,
handles: ['.'+CSS.HEADER],
invalid: '.block-hider-hide, .block-hider-show, .moveto',
dragConfig: {groups: this.groups}
});
del.dd.plug(Y.Plugin.DDProxy, {
// Don't move the node at the end of the drag
moveOnEnd: false
});
del.dd.plug(Y.Plugin.DDWinScroll);
var blocklist = blockregionnode.all('.'+CSS.BLOCK);
blocklist.each(function(blocknode) {
var move = blocknode.one('a.'+CSS.EDITINGMOVE);
if (move) {
move.remove();
blocknode.one('.'+CSS.HEADER).setStyle('cursor', 'move');
}
}, this);
}, this);
},
get_block_id : function(node) {
return Number(node.get('id').replace(/inst/i, ''));
},
get_block_region : function(node) {
var region = node.ancestor('div.'+CSS.BLOCKREGION).get('id').replace(/region-/i, '');
if (Y.Array.indexOf(this.get('regions'), region) === -1) {
// Must be standard side-X
if (right_to_left()) {
if (region === 'post') {
region = 'pre';
} else if (region === 'pre') {
region = 'post';
}
}
return 'side-' + region;
}
// Perhaps custom region
return region;
},
get_region_id : function(node) {
return node.get('id').replace(/region-/i, '');
},
drag_start : function(e) {
// Get our drag object
var drag = e.target;
// Store the parent node of original drag node (block)
// we will need it later for show/hide empty regions
this.dragsourceregion = drag.get('node').ancestor('div.'+CSS.BLOCKREGION);
// Determine skipnodes and store them
if (drag.get('node').previous() && drag.get('node').previous().hasClass(CSS.SKIPBLOCK)) {
this.skipnodetop = drag.get('node').previous();
}
if (drag.get('node').next() && drag.get('node').next().hasClass(CSS.SKIPBLOCKTO)) {
this.skipnodebottom = drag.get('node').next();
}
},
drop_over : function(e) {
// Get a reference to our drag and drop nodes
var drag = e.drag.get('node');
var drop = e.drop.get('node');
// We need to fix the case when parent drop over event has determined
// 'goingup' and appended the drag node after admin-block.
if (drop.hasClass(this.parentnodeclass) && drop.one('.'+CSS.BLOCKADMINBLOCK) && drop.one('.'+CSS.BLOCKADMINBLOCK).next('.'+CSS.BLOCK)) {
drop.prepend(drag);
}
// Block is moved within the same region
// stop here, no need to modify anything.
if (this.dragsourceregion.contains(drop)) {
return false;
}
// TODO: Hiding-displaying block region only works for base theme blocks
// (region-pre, region-post) at the moment. It should be improved
// to work with custom block regions as well.
// TODO: Fix this for the case when user drag block towards empty section,
// then the section appears, then user chnages his mind and moving back to
// original section. The opposite section remains opened and empty.
var documentbody = Y.one('body');
// Moving block towards hidden region-content, display it
var regionname = this.get_region_id(this.dragsourceregion);
if (documentbody.hasClass('side-'+regionname+'-only')) {
documentbody.removeClass('side-'+regionname+'-only');
}
// Moving from empty region-content towards the opposite one,
// hide empty one (only for region-pre, region-post areas at the moment).
regionname = this.get_region_id(drop.ancestor('div.'+CSS.BLOCKREGION));
if (this.dragsourceregion.all('.'+CSS.BLOCK).size() == 0 && this.dragsourceregion.get('id').match(/(region-pre|region-post)/i)) {
if (!documentbody.hasClass('side-'+regionname+'-only')) {
documentbody.addClass('side-'+regionname+'-only');
}
}
},
drop_end : function() {
// clear variables
this.skipnodetop = null;
this.skipnodebottom = null;
this.dragsourceregion = null;
},
drag_dropmiss : function(e) {
// Missed the target, but we assume the user intended to drop it
// on the last last ghost node location, e.drag and e.drop should be
// prepared by global_drag_dropmiss parent so simulate drop_hit(e).
this.drop_hit(e);
},
drop_hit : function(e) {
var drag = e.drag;
// Get a reference to our drag node
var dragnode = drag.get('node');
var dropnode = e.drop.get('node');
// Amend existing skipnodes
if (dragnode.previous() && dragnode.previous().hasClass(CSS.SKIPBLOCK)) {
// the one that belongs to block below move below
dragnode.insert(dragnode.previous(), 'after');
}
// Move original skipnodes
if (this.skipnodetop) {
dragnode.insert(this.skipnodetop, 'before');
}
if (this.skipnodebottom) {
dragnode.insert(this.skipnodebottom, 'after');
}
// Add lightbox if it not there
var lightbox = M.util.add_lightbox(Y, dragnode);
// Prepare request parameters
var params = {
sesskey : M.cfg.sesskey,
courseid : this.get('courseid'),
pagelayout : this.get('pagelayout'),
pagetype : this.get('pagetype'),
subpage : this.get('subpage'),
contextid : this.get('contextid'),
action : 'move',
bui_moveid : this.get_block_id(dragnode),
bui_newregion : this.get_block_region(dropnode)
};
if (this.get('cmid')) {
params.cmid = this.get('cmid');
}
if (dragnode.next('.'+this.samenodeclass) && !dragnode.next('.'+this.samenodeclass).hasClass(CSS.BLOCKADMINBLOCK)) {
params.bui_beforeid = this.get_block_id(dragnode.next('.'+this.samenodeclass));
}
// Do AJAX request
Y.io(M.cfg.wwwroot+AJAXURL, {
method: 'POST',
data: params,
on: {
start : function() {
lightbox.show();
},
success: function(tid, response) {
window.setTimeout(function() {
lightbox.hide();
}, 250);
try {
var responsetext = Y.JSON.parse(response.responseText);
if (responsetext.error) {
new M.core.ajaxException(responsetext);
}
} catch (e) {}
},
failure: function(tid, response) {
this.ajax_failure(response);
lightbox.hide();
}
},
context:this
});
}
}, {
NAME : 'core-blocks-dragdrop',
ATTRS : {
courseid : {
value : null
},
cmid : {
value : null
},
contextid : {
value : null
},
pagelayout : {
value : null
},
pagetype : {
value : null
},
subpage : {
value : null
},
regions : {
value : null
}
}
});
M.core_blocks = M.core_blocks || {};
M.core_blocks.init_dragdrop = function(params) {
new DRAGBLOCK(params);
};
+14
View File
@@ -0,0 +1,14 @@
{
"moodle-core-blocks": {
"requires": [
"base",
"node",
"io",
"dom",
"dd",
"dd-scroll",
"moodle-core-dragdrop",
"moodle-core-notification"
]
}
}