Merge branch 'MDL-36002-master' of git://github.com/damyon/moodle

Conflicts:
	theme/base/style/core.css
	theme/bootstrapbase/style/moodle.css
This commit is contained in:
Dan Poltawski
2013-08-12 11:56:37 +08:00
12 changed files with 301 additions and 13 deletions
+3
View File
@@ -2965,6 +2965,9 @@ function include_course_ajax($course, $usedmodules = array(), $enabledmodules =
'markedthistopic',
'move',
'movesection',
'movecontent',
'aftercontent',
'emptydragdropregion'
), 'moodle');
// Include format-specific strings
+1
View File
@@ -295,6 +295,7 @@ YUI.add('moodle-course-dragdrop', function(Y) {
resources.addClass(CSS.SECTION);
sectionnode.one('.'+CSS.CONTENT+' div.'+CSS.SUMMARY).insert(resources, 'after');
}
resources.setAttribute('data-draggroups', this.groups.join(' '));
// Define empty ul as droptarget, so that item could be moved to empty list
var tar = new Y.DD.Drop({
node: resources,
+3
View File
@@ -115,6 +115,7 @@ $string['administratorsandteachers'] = 'Administrators and teachers';
$string['advanced'] = 'Advanced';
$string['advancedfilter'] = 'Advanced search';
$string['advancedsettings'] = 'Advanced settings';
$string['aftercontent'] = 'After {$a}';
$string['again'] = 'again';
$string['aimid'] = 'AIM ID';
$string['ajaxuse'] = 'AJAX and Javascript';
@@ -638,6 +639,7 @@ $string['emailpasswordsent'] = 'Thank you for confirming the change of password.
An email containing your new password has been sent to your address at<br /><b>{$a->email}</b>.<br />
The new password was automatically generated - you might like to
<a href="{$a->link}">change your password</a> to something easier to remember.';
$string['emptydragdropregion'] = 'empty region';
$string['enable'] = 'Enable';
$string['encryptedcode'] = 'Encrypted code';
$string['english'] = 'English';
@@ -1073,6 +1075,7 @@ $string['moreinformation'] = 'More information about this error';
$string['moreprofileinfoneeded'] = 'Please tell us more about yourself';
$string['mostrecently'] = 'most recently';
$string['move'] = 'Move';
$string['movecontent'] = 'Move {$a}';
$string['movecategorycontentto'] = 'Move into';
$string['movecategoryto'] = 'Move category to:';
$string['movecontentstoanothercategory'] = 'Move contents to another category';
+5
View File
@@ -300,6 +300,11 @@ class page_requirements_manager {
if (!empty($page->cm->id)) {
$params['cmid'] = $page->cm->id;
}
// Strings for drag and drop.
$this->strings_for_js(array('movecontent',
'aftercontent',
'emptydragdropregion'),
'moodle');
$page->requires->yui_module('moodle-core-blocks', 'M.core_blocks.init_dragdrop', array($params), null, true);
}
}
@@ -115,7 +115,7 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, {
blocklist.each(function(blocknode) {
var move = blocknode.one('a.'+CSS.EDITINGMOVE);
if (move) {
move.remove();
move.replace(this.get_drag_handle(move.getAttribute('title'), '', 'icon', true));
blocknode.one('.'+CSS.HEADER).setStyle('cursor', 'move');
}
}, this);
@@ -379,7 +379,8 @@ M.core.blockdraganddrop.init = function(params) {
M.core_blocks = M.core_blocks || {};
M.core_blocks.init_dragdrop = function(params) {
M.core.blockdraganddrop.init(params);
};/**
};
/**
* This file contains the drag and drop manager class.
*
* Provides drag and drop functionality for blocks.
File diff suppressed because one or more lines are too long
+3 -2
View File
@@ -115,7 +115,7 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, {
blocklist.each(function(blocknode) {
var move = blocknode.one('a.'+CSS.EDITINGMOVE);
if (move) {
move.remove();
move.replace(this.get_drag_handle(move.getAttribute('title'), '', 'icon', true));
blocknode.one('.'+CSS.HEADER).setStyle('cursor', 'move');
}
}, this);
@@ -379,7 +379,8 @@ M.core.blockdraganddrop.init = function(params) {
M.core_blocks = M.core_blocks || {};
M.core_blocks.init_dragdrop = function(params) {
M.core.blockdraganddrop.init(params);
};/**
};
/**
* This file contains the drag and drop manager class.
*
* Provides drag and drop functionality for blocks.
+266 -4
View File
@@ -2,7 +2,8 @@ YUI.add('moodle-core-dragdrop', function(Y) {
var MOVEICON = {
pix: "i/move_2d",
largepix: "i/dragdrop",
component: 'moodle'
component: 'moodle',
cssclass: 'moodle-core-dragdrop-draghandle'
};
/*
@@ -33,6 +34,8 @@ YUI.add('moodle-core-dragdrop', function(Y) {
Y.DD.DDM.on('drop:hit', this.global_drop_hit, this);
// Listen for all drop:miss events
Y.DD.DDM.on('drag:dropmiss', this.global_drag_dropmiss, this);
Y.on('key', this.global_keydown, window, 'down:space,enter,esc', this);
},
get_drag_handle: function(title, classname, iconclass, large) {
@@ -53,17 +56,19 @@ YUI.add('moodle-core-dragdrop', function(Y) {
var dragelement = Y.Node.create('<span></span>')
.addClass(classname)
.setAttribute('title', title)
.setAttribute('tabIndex', 0)
.setAttribute('data-draggroups', this.groups);
dragelement.appendChild(dragicon);
dragelement.addClass(MOVEICON.cssclass);
return dragelement;
},
lock_drag_handle: function(drag, classname) {
// Disable dragging
drag.removeHandle('.'+classname);
},
unlock_drag_handle: function(drag, classname) {
// Enable dragging
drag.addHandle('.'+classname);
},
@@ -194,6 +199,263 @@ YUI.add('moodle-core-dragdrop', function(Y) {
this.drop_hit(e);
},
/**
* This is used to build the text for the heading of the keyboard
* drag drop menu and the text for the nodes in the list.
* @method find_element_text
* @param {Node} n The node to start searching for a valid text node.
* @returns {string} The text of the first text-like child node of n.
*/
find_element_text : function(n) {
// The valid node types to get text from.
var nodes = n.all('h2, h3, h4, h5, span, p');
var text = '';
nodes.each(function () {
if (text == '') {
if (Y.Lang.trim(this.get('text')) != '') {
text = this.get('text');
}
}
});
if (text != '') {
return text;
}
return M.util.get_string('emptydragdropregion', 'moodle');
},
/**
* This is used to initiate a keyboard version of a drag and drop.
* A dialog will open listing all the valid drop targets that can be selected
* using tab, tab, tab, enter.
* @method global_start_keyboard_drag
* @param {Event} e The keydown / click event on the grab handle.
* @param {Node} dragcontainer The resolved draggable node (an ancestor of the drag handle).
* @param {Node} draghandle The node that triggered this action.
*/
global_start_keyboard_drag : function(e, draghandle, dragcontainer) {
M.core.dragdrop.keydragcontainer = dragcontainer;
M.core.dragdrop.keydraghandle = draghandle;
// Indicate to a screenreader the node that is selected for drag and drop.
dragcontainer.setAttribute('aria-grabbed', 'true');
// Get the name of the thing to move.
var nodetitle = this.find_element_text(dragcontainer);
var dialogtitle = M.util.get_string('movecontent', 'moodle', nodetitle);
// Build the list of drop targets.
var droplist = Y.Node.create('<ul></ul>');
droplist.addClass('dragdrop-keyboard-drag');
var listitem;
var listitemtext;
// Search for possible drop targets.
var droptargets = Y.all('.' + this.samenodeclass + ', .' + this.parentnodeclass);
droptargets.each(function (node) {
var validdrop = false, labelroot = node;
if (node.drop && node.drop.inGroup(this.groups) && node.drop.get('node') != dragcontainer) {
// This is a drag and drop target with the same class as the grabbed node.
validdrop = true;
} else {
var elementgroups = node.getAttribute('data-draggroups').split(' ');
var i, j;
for (i = 0; i < elementgroups.length; i++) {
for (j = 0; j < this.groups.length; j++) {
if (elementgroups[i] == this.groups[j]) {
// This is a parent node of the grabbed node (used for dropping in empty sections).
validdrop = true;
// This node will have no text - so we get the first valid text from the parent.
labelroot = node.get('parentNode');
break;
}
}
if (validdrop) {
break;
}
}
}
if (validdrop) {
// It is a valid drop target - create a list item for it.
listitem = Y.Node.create('<li></li>');
listlink = Y.Node.create('<a></a>');
nodetitle = this.find_element_text(labelroot);
listitemtext = M.util.get_string('aftercontent', 'moodle', nodetitle);
listlink.setContent(listitemtext);
// Add a data attribute so we can get the real drop target.
listlink.setAttribute('data-drop-target', node.get('id'));
// Notify the screen reader this is a valid drop target.
listlink.setAttribute('aria-dropeffect', 'move');
// Allow tabbing to the link.
listlink.setAttribute('tabindex', '0');
// Set the event listeners for enter, space or click.
listlink.on('click', this.global_keyboard_drop, this);
listlink.on('key', this.global_keyboard_drop, 'down:enter,32', this);
// Add to the list or drop targets.
listitem.append(listlink);
droplist.append(listitem);
}
}, this);
// Create the dialog for the interaction.
M.core.dragdrop.dropui = new M.core.dialogue({
headerContent : dialogtitle,
bodyContent : droplist,
draggable : true
});
// Focus the first drop target.
if (droplist.one('a')) {
droplist.one('a').focus();
}
},
/**
* This is used as a simulated drag/drop event in order to prevent any
* subtle bugs from creating a real instance of a drag drop event. This means
* there are no state changes in the Y.DD.DDM and any undefined functions
* will trigger an obvious and fatal error.
* The end result is that we call all our drag/drop handlers but do not bubble the
* event to anyone else.
*
* The functions/properties implemented in the wrapper are:
* e.target
* e.drag
* e.drop
* e.drag.get('node')
* e.drop.get('node')
* e.drag.addHandle()
* e.drag.removeHandle()
*
* @class simulated_drag_drop_event
* @param {Node} dragnode The drag container node
* @param {Node} dropnode The node to initiate the drop on
*/
simulated_drag_drop_event : function(dragnode, dropnode) {
this.target = dropnode;
// Subclass for wrapping both drag and drop.
var dragdropwrapper = function(node) {
this.node = node;
}
// Method e.drag.get() - get the node.
dragdropwrapper.prototype.get = function(param) {
if (param == 'node' || param == 'dragNode' || param == 'dropNode') {
return this.node;
}
return null;
};
// Method e.drag.inGroup() - we have already run the group checks before triggering the event.
dragdropwrapper.prototype.inGroup = function() {
return true;
};
// Method e.drag.addHandle() - we don't want to run this.
dragdropwrapper.prototype.addHandle = function() {};
// Method e.drag.removeHandle() - we don't want to run this.
dragdropwrapper.prototype.removeHandle = function() {};
// Create instances of the dragdropwrapper.
this.drop = new dragdropwrapper(dropnode);
this.drag = new dragdropwrapper(dragnode);
},
/**
* This is used to complete a keyboard version of a drag and drop.
* A drop event will be simulated based on the drag and drop nodes.
* @method global_keyboard_drop
* @param {Event} e The keydown / click event on the proxy drop node.
*/
global_keyboard_drop : function(e) {
// The drag node was saved.
var dragcontainer = M.core.dragdrop.keydragcontainer;
dragcontainer.setAttribute('aria-grabbed', 'false');
// The real drop node is stored in an attribute of the proxy.
var droptarget = Y.one('#' + e.target.getAttribute('data-drop-target'));
// Close the dialog.
M.core.dragdrop.dropui.hide();
// Cancel the event.
e.preventDefault();
// Convert to a drag drop event.
var dropevent = new this.simulated_drag_drop_event(dragcontainer, droptarget);
this.global_drop_over(dropevent);
this.global_drop_hit(dropevent);
M.core.dragdrop.keydraghandle.focus();
},
/**
* This is used to cancel a keyboard version of a drag and drop.
*
* @method global_cancel_keyboard_drag
*/
global_cancel_keyboard_drag : function() {
if (M.core.dragdrop.keydragcontainer) {
M.core.dragdrop.keydragcontainer.setAttribute('aria-grabbed', 'false');
M.core.dragdrop.keydraghandle.focus();
M.core.dragdrop.keydragcontainer = null;
}
},
/**
* Process key events on the drag handles.
* @method global_keydown
* @param {Event} e The keydown / click event on the drag handle.
*/
global_keydown : function(e) {
var draghandle = e.target,
dragcontainer,
draggroups;
if (e.keyCode == 27 ) {
// Escape to cancel from anywhere.
this.global_cancel_keyboard_drag();
e.preventDefault();
return;
}
// Only process events on a drag handle.
if (!draghandle.hasClass(MOVEICON.cssclass)) {
return;
}
// Do nothing if not space or enter.
if (e.keyCode != 13 && e.keyCode != 32) {
return;
}
// Check the drag groups to see if we are the handler for this node.
draggroups = e.target.getAttribute('data-draggroups').split(' ');
var i, j, validgroup = false;
for (i = 0; i < draggroups.length; i++) {
for (j = 0; j < this.groups.length; j++) {
if (draggroups[i] == this.groups[j]) {
validgroup = true;
break;
}
}
if (validgroup) {
break;
}
}
if (!validgroup) {
return;
}
// Valid event - start the keyboard drag.
dragcontainer = draghandle.ancestor('.yui3-dd-drop');
this.global_start_keyboard_drag(e, draghandle, dragcontainer);
e.preventDefault();
},
/*
* Abstract functions definitions
*/
@@ -211,4 +473,4 @@ YUI.add('moodle-core-dragdrop', function(Y) {
M.core = M.core || {};
M.core.dragdrop = DRAGDROP;
}, '@VERSION@', {requires:['base', 'node', 'io', 'dom', 'dd', 'moodle-core-notification']});
}, '@VERSION@', {requires:['base', 'node', 'io', 'dom', 'dd', 'event-key', 'event-focus', 'moodle-core-notification']});
+2 -2
View File
@@ -113,7 +113,7 @@ Y.extend(DRAGBLOCK, M.core.dragdrop, {
blocklist.each(function(blocknode) {
var move = blocknode.one('a.'+CSS.EDITINGMOVE);
if (move) {
move.remove();
move.replace(this.get_drag_handle(move.getAttribute('title'), '', 'icon', true));
blocknode.one('.'+CSS.HEADER).setStyle('cursor', 'move');
}
}, this);
@@ -377,4 +377,4 @@ M.core.blockdraganddrop.init = function(params) {
M.core_blocks = M.core_blocks || {};
M.core_blocks.init_dragdrop = function(params) {
M.core.blockdraganddrop.init(params);
};
};
+3
View File
@@ -1444,3 +1444,6 @@ div.badge .expireimage { width: 100px; height: 100px; left: 20px; top: 0px; }
.dir-rtl .menu.align-tr-tr {right: auto;left: 0;}
.dir-rtl .menu.align-bl-tr {right: 100%;left: auto;}
.dir-rtl .menu.align-br-tr {right: auto;left: 0;}
ul.dragdrop-keyboard-drag li { list-style-type: none; }
.block-control-actions .moodle-core-dragdrop-draghandle img { width: 12px; height: 12px; }
@@ -2068,3 +2068,12 @@ div.badge .expireimage {
text-align: right;
}
}
ul.dragdrop-keyboard-drag li {
list-style-type: none;
}
.block-control-actions .moodle-core-dragdrop-draghandle img {
width: 12px;
height: 12px;
}
File diff suppressed because one or more lines are too long