mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 12:32:08 +02:00
Merge branch 'MDL-65539' of https://github.com/NeillM/moodle
This commit is contained in:
commit
dad7f2ba1d
@ -50,6 +50,7 @@ M.course.format.swap_sections = function(Y, node1, node2) {
|
||||
* Process sections after ajax response
|
||||
*
|
||||
* @param {YUI} Y YUI3 instance
|
||||
* @param {NodeList} sectionlist of sections
|
||||
* @param {array} response ajax response
|
||||
* @param {string} sectionfrom first affected section
|
||||
* @param {string} sectionto last affected section
|
||||
@ -78,13 +79,14 @@ M.course.format.process_sections = function(Y, sectionlist, response, sectionfro
|
||||
// Update section title.
|
||||
var content = Y.Node.create('<span>' + response.sectiontitles[i] + '</span>');
|
||||
sectionlist.item(i).all('.'+CSS.SECTIONNAME).setHTML(content);
|
||||
// Update move icon.
|
||||
ele = sectionlist.item(i).one(SELECTORS.SECTIONLEFTSIDE);
|
||||
str = ele.getAttribute('alt');
|
||||
// Update the drag handle.
|
||||
ele = sectionlist.item(i).one(SELECTORS.SECTIONLEFTSIDE).ancestor('.section-handle');
|
||||
str = ele.getAttribute('title');
|
||||
stridx = str.lastIndexOf(' ');
|
||||
newstr = str.substr(0, stridx +1) + i;
|
||||
ele.setAttribute('alt', newstr);
|
||||
ele.setAttribute('title', newstr); // For FireFox as 'alt' is not refreshed.
|
||||
ele.setAttribute('title', newstr);
|
||||
// Update the aria-label for the section.
|
||||
sectionlist.item(i).setAttribute('aria-label', content.get('innerText').trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ M.course.format.swap_sections = function(Y, node1, node2) {
|
||||
* Process sections after ajax response
|
||||
*
|
||||
* @param {YUI} Y YUI3 instance
|
||||
* @param {NodeList} sectionlist of sections
|
||||
* @param {array} response ajax response
|
||||
* @param {string} sectionfrom first affected section
|
||||
* @param {string} sectionto last affected section
|
||||
@ -79,13 +80,14 @@ M.course.format.process_sections = function(Y, sectionlist, response, sectionfro
|
||||
var content = Y.Node.create('<span>' + response.sectiontitles[i] + '</span>');
|
||||
sectionlist.item(i).all('.'+CSS.SECTIONNAME).setHTML(content);
|
||||
|
||||
// Update move icon.
|
||||
ele = sectionlist.item(i).one(SELECTORS.SECTIONLEFTSIDE);
|
||||
str = ele.getAttribute('alt');
|
||||
// Update the drag handle.
|
||||
ele = sectionlist.item(i).one(SELECTORS.SECTIONLEFTSIDE).ancestor('.section-handle');
|
||||
str = ele.getAttribute('title');
|
||||
stridx = str.lastIndexOf(' ');
|
||||
newstr = str.substr(0, stridx +1) + i;
|
||||
ele.setAttribute('alt', newstr);
|
||||
ele.setAttribute('title', newstr); // For FireFox as 'alt' is not refreshed.
|
||||
ele.setAttribute('title', newstr);
|
||||
// Update the aria-label for the section.
|
||||
sectionlist.item(i).setAttribute('aria-label', content.get('innerText').trim());
|
||||
|
||||
// Remove the current class as section has been moved.
|
||||
sectionlist.item(i).removeClass('current');
|
||||
|
@ -48,6 +48,8 @@ Y.extend(DRAGSECTION, M.core.dragdrop, {
|
||||
this.groups = [CSS.SECTIONDRAGGABLE];
|
||||
this.samenodeclass = M.course.format.get_sectionwrapperclass();
|
||||
this.parentnodeclass = M.course.format.get_containerclass();
|
||||
// Detect the direction of travel.
|
||||
this.detectkeyboarddirection = true;
|
||||
|
||||
// Check if we are in single section mode
|
||||
if (Y.Node.one('.' + CSS.JUMPMENU)) {
|
||||
@ -147,6 +149,14 @@ Y.extend(DRAGSECTION, M.core.dragdrop, {
|
||||
drag_start: function(e) {
|
||||
// Get our drag object
|
||||
var drag = e.target;
|
||||
// This is the node that the user started to drag.
|
||||
var node = drag.get('node');
|
||||
// This is the container node that will follow the mouse around,
|
||||
// or during a keyboard drag and drop the original node.
|
||||
var dragnode = drag.get('dragNode');
|
||||
if (node === dragnode) {
|
||||
return;
|
||||
}
|
||||
// Creat a dummy structure of the outer elemnents for clean styles application
|
||||
var containernode = Y.Node.create('<' + M.course.format.get_containernode() +
|
||||
'></' + M.course.format.get_containernode() + '>');
|
||||
@ -155,10 +165,10 @@ Y.extend(DRAGSECTION, M.core.dragdrop, {
|
||||
'></' + M.course.format.get_sectionwrappernode() + '>');
|
||||
sectionnode.addClass(M.course.format.get_sectionwrapperclass());
|
||||
sectionnode.setStyle('margin', 0);
|
||||
sectionnode.setContent(drag.get('node').get('innerHTML'));
|
||||
sectionnode.setContent(node.get('innerHTML'));
|
||||
containernode.appendChild(sectionnode);
|
||||
drag.get('dragNode').setContent(containernode);
|
||||
drag.get('dragNode').addClass(CSS.COURSECONTENT);
|
||||
dragnode.setContent(containernode);
|
||||
dragnode.addClass(CSS.COURSECONTENT);
|
||||
},
|
||||
|
||||
drag_dropmiss: function(e) {
|
||||
@ -431,6 +441,11 @@ Y.extend(DRAGRESOURCE, M.core.dragdrop, {
|
||||
drag_start: function(e) {
|
||||
// Get our drag object
|
||||
var drag = e.target;
|
||||
if (drag.get('dragNode') === drag.get('node')) {
|
||||
// We do not want to modify the contents of the real node.
|
||||
// They will be the same during a keyboard drag and drop.
|
||||
return;
|
||||
}
|
||||
drag.get('dragNode').setContent(drag.get('node').get('innerHTML'));
|
||||
drag.get('dragNode').all('img.iconsmall').setStyle('vertical-align', 'baseline');
|
||||
},
|
||||
|
File diff suppressed because one or more lines are too long
@ -48,6 +48,8 @@ Y.extend(DRAGSECTION, M.core.dragdrop, {
|
||||
this.groups = [CSS.SECTIONDRAGGABLE];
|
||||
this.samenodeclass = M.course.format.get_sectionwrapperclass();
|
||||
this.parentnodeclass = M.course.format.get_containerclass();
|
||||
// Detect the direction of travel.
|
||||
this.detectkeyboarddirection = true;
|
||||
|
||||
// Check if we are in single section mode
|
||||
if (Y.Node.one('.' + CSS.JUMPMENU)) {
|
||||
@ -147,6 +149,14 @@ Y.extend(DRAGSECTION, M.core.dragdrop, {
|
||||
drag_start: function(e) {
|
||||
// Get our drag object
|
||||
var drag = e.target;
|
||||
// This is the node that the user started to drag.
|
||||
var node = drag.get('node');
|
||||
// This is the container node that will follow the mouse around,
|
||||
// or during a keyboard drag and drop the original node.
|
||||
var dragnode = drag.get('dragNode');
|
||||
if (node === dragnode) {
|
||||
return;
|
||||
}
|
||||
// Creat a dummy structure of the outer elemnents for clean styles application
|
||||
var containernode = Y.Node.create('<' + M.course.format.get_containernode() +
|
||||
'></' + M.course.format.get_containernode() + '>');
|
||||
@ -155,10 +165,10 @@ Y.extend(DRAGSECTION, M.core.dragdrop, {
|
||||
'></' + M.course.format.get_sectionwrappernode() + '>');
|
||||
sectionnode.addClass(M.course.format.get_sectionwrapperclass());
|
||||
sectionnode.setStyle('margin', 0);
|
||||
sectionnode.setContent(drag.get('node').get('innerHTML'));
|
||||
sectionnode.setContent(node.get('innerHTML'));
|
||||
containernode.appendChild(sectionnode);
|
||||
drag.get('dragNode').setContent(containernode);
|
||||
drag.get('dragNode').addClass(CSS.COURSECONTENT);
|
||||
dragnode.setContent(containernode);
|
||||
dragnode.addClass(CSS.COURSECONTENT);
|
||||
},
|
||||
|
||||
drag_dropmiss: function(e) {
|
||||
@ -427,6 +437,11 @@ Y.extend(DRAGRESOURCE, M.core.dragdrop, {
|
||||
drag_start: function(e) {
|
||||
// Get our drag object
|
||||
var drag = e.target;
|
||||
if (drag.get('dragNode') === drag.get('node')) {
|
||||
// We do not want to modify the contents of the real node.
|
||||
// They will be the same during a keyboard drag and drop.
|
||||
return;
|
||||
}
|
||||
drag.get('dragNode').setContent(drag.get('node').get('innerHTML'));
|
||||
drag.get('dragNode').all('img.iconsmall').setStyle('vertical-align', 'baseline');
|
||||
},
|
||||
|
5
course/yui/src/dragdrop/js/resource.js
vendored
5
course/yui/src/dragdrop/js/resource.js
vendored
@ -116,6 +116,11 @@ Y.extend(DRAGRESOURCE, M.core.dragdrop, {
|
||||
drag_start: function(e) {
|
||||
// Get our drag object
|
||||
var drag = e.target;
|
||||
if (drag.get('dragNode') === drag.get('node')) {
|
||||
// We do not want to modify the contents of the real node.
|
||||
// They will be the same during a keyboard drag and drop.
|
||||
return;
|
||||
}
|
||||
drag.get('dragNode').setContent(drag.get('node').get('innerHTML'));
|
||||
drag.get('dragNode').all('img.iconsmall').setStyle('vertical-align', 'baseline');
|
||||
},
|
||||
|
16
course/yui/src/dragdrop/js/section.js
vendored
16
course/yui/src/dragdrop/js/section.js
vendored
@ -16,6 +16,8 @@ Y.extend(DRAGSECTION, M.core.dragdrop, {
|
||||
this.groups = [CSS.SECTIONDRAGGABLE];
|
||||
this.samenodeclass = M.course.format.get_sectionwrapperclass();
|
||||
this.parentnodeclass = M.course.format.get_containerclass();
|
||||
// Detect the direction of travel.
|
||||
this.detectkeyboarddirection = true;
|
||||
|
||||
// Check if we are in single section mode
|
||||
if (Y.Node.one('.' + CSS.JUMPMENU)) {
|
||||
@ -115,6 +117,14 @@ Y.extend(DRAGSECTION, M.core.dragdrop, {
|
||||
drag_start: function(e) {
|
||||
// Get our drag object
|
||||
var drag = e.target;
|
||||
// This is the node that the user started to drag.
|
||||
var node = drag.get('node');
|
||||
// This is the container node that will follow the mouse around,
|
||||
// or during a keyboard drag and drop the original node.
|
||||
var dragnode = drag.get('dragNode');
|
||||
if (node === dragnode) {
|
||||
return;
|
||||
}
|
||||
// Creat a dummy structure of the outer elemnents for clean styles application
|
||||
var containernode = Y.Node.create('<' + M.course.format.get_containernode() +
|
||||
'></' + M.course.format.get_containernode() + '>');
|
||||
@ -123,10 +133,10 @@ Y.extend(DRAGSECTION, M.core.dragdrop, {
|
||||
'></' + M.course.format.get_sectionwrappernode() + '>');
|
||||
sectionnode.addClass(M.course.format.get_sectionwrapperclass());
|
||||
sectionnode.setStyle('margin', 0);
|
||||
sectionnode.setContent(drag.get('node').get('innerHTML'));
|
||||
sectionnode.setContent(node.get('innerHTML'));
|
||||
containernode.appendChild(sectionnode);
|
||||
drag.get('dragNode').setContent(containernode);
|
||||
drag.get('dragNode').addClass(CSS.COURSECONTENT);
|
||||
dragnode.setContent(containernode);
|
||||
dragnode.addClass(CSS.COURSECONTENT);
|
||||
},
|
||||
|
||||
drag_dropmiss: function(e) {
|
||||
|
@ -458,6 +458,8 @@ MANAGER.prototype = {
|
||||
this.groups = ['block'];
|
||||
this.samenodeclass = CSS.BLOCK;
|
||||
this.parentnodeclass = CSS.BLOCKREGION;
|
||||
// Detect the direction of travel.
|
||||
this.detectkeyboarddirection = true;
|
||||
|
||||
// Add relevant classes and ID to 'content' block region on Dashboard page.
|
||||
var myhomecontent = Y.Node.all('body#' + CSS.MYINDEX + ' #' + CSS.REGIONMAIN + ' > .' + CSS.REGIONCONTENT);
|
||||
|
File diff suppressed because one or more lines are too long
@ -454,6 +454,8 @@ MANAGER.prototype = {
|
||||
this.groups = ['block'];
|
||||
this.samenodeclass = CSS.BLOCK;
|
||||
this.parentnodeclass = CSS.BLOCKREGION;
|
||||
// Detect the direction of travel.
|
||||
this.detectkeyboarddirection = true;
|
||||
|
||||
// Add relevant classes and ID to 'content' block region on Dashboard page.
|
||||
var myhomecontent = Y.Node.all('body#' + CSS.MYINDEX + ' #' + CSS.REGIONMAIN + ' > .' + CSS.REGIONCONTENT);
|
||||
|
@ -101,6 +101,15 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
*/
|
||||
lastdroptarget: null,
|
||||
|
||||
/**
|
||||
* Should the direction of a keyboard drag and drop item be detected.
|
||||
*
|
||||
* @property detectkeyboarddirection
|
||||
* @type Boolean
|
||||
* @default false
|
||||
*/
|
||||
detectkeyboarddirection: false,
|
||||
|
||||
/**
|
||||
* Listeners.
|
||||
*
|
||||
@ -420,7 +429,7 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
var className = node.getAttribute("class").split(' ').join(', .');
|
||||
|
||||
if (node.drop && node.drop.inGroup(this.groups) && node.drop.get('node') !== dragcontainer &&
|
||||
node.next(className) !== dragcontainer) {
|
||||
!(node.next(className) === dragcontainer && !this.detectkeyboarddirection)) {
|
||||
// This is a drag and drop target with the same class as the grabbed node.
|
||||
validdrop = true;
|
||||
} else {
|
||||
@ -428,7 +437,7 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
var i, j;
|
||||
for (i = 0; i < elementgroups.length; i++) {
|
||||
for (j = 0; j < this.groups.length; j++) {
|
||||
if (elementgroups[i] === this.groups[j] && !(node == dragcontainer ||
|
||||
if (elementgroups[i] === this.groups[j] && !node.ancestor('.yui3-dd-proxy') && !(node == dragcontainer ||
|
||||
node.next(className) === dragcontainer || node.get('children').item(0) == dragcontainer)) {
|
||||
// This is a parent node of the grabbed node (used for dropping in empty sections).
|
||||
validdrop = true;
|
||||
@ -568,6 +577,16 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
M.core.dragdrop.dropui.hide();
|
||||
// Cancel the event.
|
||||
e.preventDefault();
|
||||
// Detect the direction of travel.
|
||||
if (this.detectkeyboarddirection && dragcontainer.getY() > droptarget.getY()) {
|
||||
// We can detect the keyboard direction and it is going up.
|
||||
this.absgoingup = true;
|
||||
this.goingup = true;
|
||||
} else {
|
||||
// The default behaviour is to treat everything as moving down.
|
||||
this.absgoingup = false;
|
||||
this.goingup = false;
|
||||
}
|
||||
// Convert to drag drop events.
|
||||
var dragevent = new this.simulated_drag_drop_event(dragcontainer, dragcontainer);
|
||||
var dropevent = new this.simulated_drag_drop_event(dragcontainer, droptarget);
|
||||
@ -576,10 +595,7 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
this.global_drop_over(dropevent);
|
||||
|
||||
if (droptarget.hasClass(this.parentnodeclass) && droptarget.contains(dragcontainer)) {
|
||||
// The global_drop_over function does not handle the case where an item was moved up, without the
|
||||
// 'goingup' variable being set, as is the case wih keyboard drag/drop. We must detect this case and
|
||||
// apply it after the drop_over, but before the drop_hit event in order for it to be moved to the
|
||||
// correct location.
|
||||
// Handle the case where an item is dropped into a container (for example an activity into a new section).
|
||||
droptarget.prepend(dragcontainer);
|
||||
}
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -101,6 +101,15 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
*/
|
||||
lastdroptarget: null,
|
||||
|
||||
/**
|
||||
* Should the direction of a keyboard drag and drop item be detected.
|
||||
*
|
||||
* @property detectkeyboarddirection
|
||||
* @type Boolean
|
||||
* @default false
|
||||
*/
|
||||
detectkeyboarddirection: false,
|
||||
|
||||
/**
|
||||
* Listeners.
|
||||
*
|
||||
@ -420,7 +429,7 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
var className = node.getAttribute("class").split(' ').join(', .');
|
||||
|
||||
if (node.drop && node.drop.inGroup(this.groups) && node.drop.get('node') !== dragcontainer &&
|
||||
node.next(className) !== dragcontainer) {
|
||||
!(node.next(className) === dragcontainer && !this.detectkeyboarddirection)) {
|
||||
// This is a drag and drop target with the same class as the grabbed node.
|
||||
validdrop = true;
|
||||
} else {
|
||||
@ -428,7 +437,7 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
var i, j;
|
||||
for (i = 0; i < elementgroups.length; i++) {
|
||||
for (j = 0; j < this.groups.length; j++) {
|
||||
if (elementgroups[i] === this.groups[j] && !(node == dragcontainer ||
|
||||
if (elementgroups[i] === this.groups[j] && !node.ancestor('.yui3-dd-proxy') && !(node == dragcontainer ||
|
||||
node.next(className) === dragcontainer || node.get('children').item(0) == dragcontainer)) {
|
||||
// This is a parent node of the grabbed node (used for dropping in empty sections).
|
||||
validdrop = true;
|
||||
@ -568,6 +577,16 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
M.core.dragdrop.dropui.hide();
|
||||
// Cancel the event.
|
||||
e.preventDefault();
|
||||
// Detect the direction of travel.
|
||||
if (this.detectkeyboarddirection && dragcontainer.getY() > droptarget.getY()) {
|
||||
// We can detect the keyboard direction and it is going up.
|
||||
this.absgoingup = true;
|
||||
this.goingup = true;
|
||||
} else {
|
||||
// The default behaviour is to treat everything as moving down.
|
||||
this.absgoingup = false;
|
||||
this.goingup = false;
|
||||
}
|
||||
// Convert to drag drop events.
|
||||
var dragevent = new this.simulated_drag_drop_event(dragcontainer, dragcontainer);
|
||||
var dropevent = new this.simulated_drag_drop_event(dragcontainer, droptarget);
|
||||
@ -576,10 +595,7 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
this.global_drop_over(dropevent);
|
||||
|
||||
if (droptarget.hasClass(this.parentnodeclass) && droptarget.contains(dragcontainer)) {
|
||||
// The global_drop_over function does not handle the case where an item was moved up, without the
|
||||
// 'goingup' variable being set, as is the case wih keyboard drag/drop. We must detect this case and
|
||||
// apply it after the drop_over, but before the drop_hit event in order for it to be moved to the
|
||||
// correct location.
|
||||
// Handle the case where an item is dropped into a container (for example an activity into a new section).
|
||||
droptarget.prepend(dragcontainer);
|
||||
}
|
||||
|
||||
|
2
lib/yui/src/blocks/js/manager.js
vendored
2
lib/yui/src/blocks/js/manager.js
vendored
@ -66,6 +66,8 @@ MANAGER.prototype = {
|
||||
this.groups = ['block'];
|
||||
this.samenodeclass = CSS.BLOCK;
|
||||
this.parentnodeclass = CSS.BLOCKREGION;
|
||||
// Detect the direction of travel.
|
||||
this.detectkeyboarddirection = true;
|
||||
|
||||
// Add relevant classes and ID to 'content' block region on Dashboard page.
|
||||
var myhomecontent = Y.Node.all('body#' + CSS.MYINDEX + ' #' + CSS.REGIONMAIN + ' > .' + CSS.REGIONCONTENT);
|
||||
|
28
lib/yui/src/dragdrop/js/dragdrop.js
vendored
28
lib/yui/src/dragdrop/js/dragdrop.js
vendored
@ -99,6 +99,15 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
*/
|
||||
lastdroptarget: null,
|
||||
|
||||
/**
|
||||
* Should the direction of a keyboard drag and drop item be detected.
|
||||
*
|
||||
* @property detectkeyboarddirection
|
||||
* @type Boolean
|
||||
* @default false
|
||||
*/
|
||||
detectkeyboarddirection: false,
|
||||
|
||||
/**
|
||||
* Listeners.
|
||||
*
|
||||
@ -418,7 +427,7 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
var className = node.getAttribute("class").split(' ').join(', .');
|
||||
|
||||
if (node.drop && node.drop.inGroup(this.groups) && node.drop.get('node') !== dragcontainer &&
|
||||
node.next(className) !== dragcontainer) {
|
||||
!(node.next(className) === dragcontainer && !this.detectkeyboarddirection)) {
|
||||
// This is a drag and drop target with the same class as the grabbed node.
|
||||
validdrop = true;
|
||||
} else {
|
||||
@ -426,7 +435,7 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
var i, j;
|
||||
for (i = 0; i < elementgroups.length; i++) {
|
||||
for (j = 0; j < this.groups.length; j++) {
|
||||
if (elementgroups[i] === this.groups[j] && !(node == dragcontainer ||
|
||||
if (elementgroups[i] === this.groups[j] && !node.ancestor('.yui3-dd-proxy') && !(node == dragcontainer ||
|
||||
node.next(className) === dragcontainer || node.get('children').item(0) == dragcontainer)) {
|
||||
// This is a parent node of the grabbed node (used for dropping in empty sections).
|
||||
validdrop = true;
|
||||
@ -566,6 +575,16 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
M.core.dragdrop.dropui.hide();
|
||||
// Cancel the event.
|
||||
e.preventDefault();
|
||||
// Detect the direction of travel.
|
||||
if (this.detectkeyboarddirection && dragcontainer.getY() > droptarget.getY()) {
|
||||
// We can detect the keyboard direction and it is going up.
|
||||
this.absgoingup = true;
|
||||
this.goingup = true;
|
||||
} else {
|
||||
// The default behaviour is to treat everything as moving down.
|
||||
this.absgoingup = false;
|
||||
this.goingup = false;
|
||||
}
|
||||
// Convert to drag drop events.
|
||||
var dragevent = new this.simulated_drag_drop_event(dragcontainer, dragcontainer);
|
||||
var dropevent = new this.simulated_drag_drop_event(dragcontainer, droptarget);
|
||||
@ -574,10 +593,7 @@ Y.extend(DRAGDROP, Y.Base, {
|
||||
this.global_drop_over(dropevent);
|
||||
|
||||
if (droptarget.hasClass(this.parentnodeclass) && droptarget.contains(dragcontainer)) {
|
||||
// The global_drop_over function does not handle the case where an item was moved up, without the
|
||||
// 'goingup' variable being set, as is the case wih keyboard drag/drop. We must detect this case and
|
||||
// apply it after the drop_over, but before the drop_hit event in order for it to be moved to the
|
||||
// correct location.
|
||||
// Handle the case where an item is dropped into a container (for example an activity into a new section).
|
||||
droptarget.prepend(dragcontainer);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user