MDL-50971 ActionMenu: Action menus cause page to jump when closing
This patch changes the behavior of open action menus when using a mouse. Before this patch when clicking on the page with an open action menu the focus would be returned to the action menu's call button. This could cause the page to jump when a mouse user did not close an action menu, scrolled and then tried to perform another action on the page. After this patch when clicking the focus will not be returned to the action menu's call button. The behavior of the script will not be changed when using the keyboard.
This commit is contained in:
@@ -498,7 +498,7 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
|
||||
};
|
||||
this.send_request(data);
|
||||
if (M.core.actionmenu && M.core.actionmenu.instance) {
|
||||
M.core.actionmenu.instance.hideMenu();
|
||||
M.core.actionmenu.instance.hideMenu(ev);
|
||||
}
|
||||
|
||||
}, this);
|
||||
@@ -745,7 +745,7 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
|
||||
|
||||
this.send_request(data, null, function(response) {
|
||||
if (M.core.actionmenu && M.core.actionmenu.instance) {
|
||||
M.core.actionmenu.instance.hideMenu();
|
||||
M.core.actionmenu.instance.hideMenu(ev);
|
||||
}
|
||||
|
||||
// Try to retrieve the existing string from the server
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -498,7 +498,7 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
|
||||
};
|
||||
this.send_request(data);
|
||||
if (M.core.actionmenu && M.core.actionmenu.instance) {
|
||||
M.core.actionmenu.instance.hideMenu();
|
||||
M.core.actionmenu.instance.hideMenu(ev);
|
||||
}
|
||||
|
||||
}, this);
|
||||
@@ -745,7 +745,7 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
|
||||
|
||||
this.send_request(data, null, function(response) {
|
||||
if (M.core.actionmenu && M.core.actionmenu.instance) {
|
||||
M.core.actionmenu.instance.hideMenu();
|
||||
M.core.actionmenu.instance.hideMenu(ev);
|
||||
}
|
||||
|
||||
// Try to retrieve the existing string from the server
|
||||
|
||||
+2
-2
@@ -294,7 +294,7 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
|
||||
};
|
||||
this.send_request(data);
|
||||
if (M.core.actionmenu && M.core.actionmenu.instance) {
|
||||
M.core.actionmenu.instance.hideMenu();
|
||||
M.core.actionmenu.instance.hideMenu(ev);
|
||||
}
|
||||
|
||||
}, this);
|
||||
@@ -541,7 +541,7 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
|
||||
|
||||
this.send_request(data, null, function(response) {
|
||||
if (M.core.actionmenu && M.core.actionmenu.instance) {
|
||||
M.core.actionmenu.instance.hideMenu();
|
||||
M.core.actionmenu.instance.hideMenu(ev);
|
||||
}
|
||||
|
||||
// Try to retrieve the existing string from the server
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 2.8.8 ===
|
||||
|
||||
* The actionmenu hideMenu() function now expects an EventFacade object to be passed to it,
|
||||
i.e. a call to M.core.actionmenu.instance.hideMenu() can be changed to M.core.actionmenu.instance.hideMenu(e) to ensure good
|
||||
behaviour when using custom action menus.
|
||||
|
||||
=== 2.8.7 ===
|
||||
|
||||
* New methods grade_grade::get_grade_max() and get_grade_min() must be used rather than directly the public properties rawgrademax and rawgrademin.
|
||||
|
||||
@@ -246,9 +246,10 @@ ACTIONMENU.prototype = {
|
||||
|
||||
/**
|
||||
* Hides the menu if it is visible.
|
||||
* @param {EventFacade} e
|
||||
* @method hideMenu
|
||||
*/
|
||||
hideMenu : function() {
|
||||
hideMenu : function(e) {
|
||||
if (this.dialogue) {
|
||||
Y.log('Hiding an action menu', 'debug', ACTIONMENU.NAME);
|
||||
this.dialogue.removeClass('show');
|
||||
@@ -267,7 +268,10 @@ ACTIONMENU.prototype = {
|
||||
}
|
||||
|
||||
if (this.menulink) {
|
||||
this.menulink.focus();
|
||||
if (!e || e.type != 'click') {
|
||||
// We needed to test !e to retain backwards compatiablity if the event is not passed.
|
||||
this.menulink.focus();
|
||||
}
|
||||
this.menulink = null;
|
||||
}
|
||||
},
|
||||
@@ -294,7 +298,7 @@ ACTIONMENU.prototype = {
|
||||
|
||||
// Prevent event propagation as it will trigger the hideIfOutside event handler in certain situations.
|
||||
e.halt(true);
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
if (menuvisible) {
|
||||
// The menu was visible and the user has clicked to toggle it again.
|
||||
return;
|
||||
@@ -323,7 +327,7 @@ ACTIONMENU.prototype = {
|
||||
this.lastMenuChild.focus();
|
||||
e.preventDefault();
|
||||
} else if (e.keyCode === 9 && e.shiftKey) {
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
e.preventDefault();
|
||||
}
|
||||
return this;
|
||||
@@ -331,7 +335,7 @@ ACTIONMENU.prototype = {
|
||||
|
||||
if (e.keyCode === 27) {
|
||||
// The escape key was pressed so close the menu.
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
e.preventDefault();
|
||||
|
||||
} else if (e.keyCode === 32) {
|
||||
@@ -342,10 +346,10 @@ ACTIONMENU.prototype = {
|
||||
// The tab key was pressed. Tab moves forwards, Shift + Tab moves backwards through the menu options.
|
||||
// We only override the Shift + Tab on the first option, and Tab on the last option to change where the focus is moved to.
|
||||
if (e.target === this.firstMenuChild && e.shiftKey) {
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
e.preventDefault();
|
||||
} else if (e.target === this.lastMenuChild && !e.shiftKey) {
|
||||
if (this.hideMenu()) {
|
||||
if (this.hideMenu(e)) {
|
||||
// Determine the next selector and focus on it.
|
||||
next = this.menulink.next(SELECTOR.CAN_RECEIVE_FOCUS_SELECTOR);
|
||||
if (next) {
|
||||
@@ -412,7 +416,7 @@ ACTIONMENU.prototype = {
|
||||
*/
|
||||
hideIfOutside : function(e) {
|
||||
if (!e.target.ancestor(SELECTOR.MENUCHILD, true)) {
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -464,7 +468,7 @@ ACTIONMENU.prototype = {
|
||||
if (e.currentTarget.test(SELECTOR.KEEPOPEN)) {
|
||||
return;
|
||||
}
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
}, SELECTOR.MENUCHILD, this));
|
||||
|
||||
return true;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -245,9 +245,10 @@ ACTIONMENU.prototype = {
|
||||
|
||||
/**
|
||||
* Hides the menu if it is visible.
|
||||
* @param {EventFacade} e
|
||||
* @method hideMenu
|
||||
*/
|
||||
hideMenu : function() {
|
||||
hideMenu : function(e) {
|
||||
if (this.dialogue) {
|
||||
this.dialogue.removeClass('show');
|
||||
this.dialogue.one(SELECTOR.MENUCONTENT).set('aria-hidden', true);
|
||||
@@ -265,7 +266,10 @@ ACTIONMENU.prototype = {
|
||||
}
|
||||
|
||||
if (this.menulink) {
|
||||
this.menulink.focus();
|
||||
if (!e || e.type != 'click') {
|
||||
// We needed to test !e to retain backwards compatiablity if the event is not passed.
|
||||
this.menulink.focus();
|
||||
}
|
||||
this.menulink = null;
|
||||
}
|
||||
},
|
||||
@@ -292,7 +296,7 @@ ACTIONMENU.prototype = {
|
||||
|
||||
// Prevent event propagation as it will trigger the hideIfOutside event handler in certain situations.
|
||||
e.halt(true);
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
if (menuvisible) {
|
||||
// The menu was visible and the user has clicked to toggle it again.
|
||||
return;
|
||||
@@ -321,7 +325,7 @@ ACTIONMENU.prototype = {
|
||||
this.lastMenuChild.focus();
|
||||
e.preventDefault();
|
||||
} else if (e.keyCode === 9 && e.shiftKey) {
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
e.preventDefault();
|
||||
}
|
||||
return this;
|
||||
@@ -329,7 +333,7 @@ ACTIONMENU.prototype = {
|
||||
|
||||
if (e.keyCode === 27) {
|
||||
// The escape key was pressed so close the menu.
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
e.preventDefault();
|
||||
|
||||
} else if (e.keyCode === 32) {
|
||||
@@ -340,10 +344,10 @@ ACTIONMENU.prototype = {
|
||||
// The tab key was pressed. Tab moves forwards, Shift + Tab moves backwards through the menu options.
|
||||
// We only override the Shift + Tab on the first option, and Tab on the last option to change where the focus is moved to.
|
||||
if (e.target === this.firstMenuChild && e.shiftKey) {
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
e.preventDefault();
|
||||
} else if (e.target === this.lastMenuChild && !e.shiftKey) {
|
||||
if (this.hideMenu()) {
|
||||
if (this.hideMenu(e)) {
|
||||
// Determine the next selector and focus on it.
|
||||
next = this.menulink.next(SELECTOR.CAN_RECEIVE_FOCUS_SELECTOR);
|
||||
if (next) {
|
||||
@@ -409,7 +413,7 @@ ACTIONMENU.prototype = {
|
||||
*/
|
||||
hideIfOutside : function(e) {
|
||||
if (!e.target.ancestor(SELECTOR.MENUCHILD, true)) {
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -460,7 +464,7 @@ ACTIONMENU.prototype = {
|
||||
if (e.currentTarget.test(SELECTOR.KEEPOPEN)) {
|
||||
return;
|
||||
}
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
}, SELECTOR.MENUCHILD, this));
|
||||
|
||||
return true;
|
||||
|
||||
+13
-9
@@ -244,9 +244,10 @@ ACTIONMENU.prototype = {
|
||||
|
||||
/**
|
||||
* Hides the menu if it is visible.
|
||||
* @param {EventFacade} e
|
||||
* @method hideMenu
|
||||
*/
|
||||
hideMenu : function() {
|
||||
hideMenu : function(e) {
|
||||
if (this.dialogue) {
|
||||
Y.log('Hiding an action menu', 'debug', ACTIONMENU.NAME);
|
||||
this.dialogue.removeClass('show');
|
||||
@@ -265,7 +266,10 @@ ACTIONMENU.prototype = {
|
||||
}
|
||||
|
||||
if (this.menulink) {
|
||||
this.menulink.focus();
|
||||
if (!e || e.type != 'click') {
|
||||
// We needed to test !e to retain backwards compatiablity if the event is not passed.
|
||||
this.menulink.focus();
|
||||
}
|
||||
this.menulink = null;
|
||||
}
|
||||
},
|
||||
@@ -292,7 +296,7 @@ ACTIONMENU.prototype = {
|
||||
|
||||
// Prevent event propagation as it will trigger the hideIfOutside event handler in certain situations.
|
||||
e.halt(true);
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
if (menuvisible) {
|
||||
// The menu was visible and the user has clicked to toggle it again.
|
||||
return;
|
||||
@@ -321,7 +325,7 @@ ACTIONMENU.prototype = {
|
||||
this.lastMenuChild.focus();
|
||||
e.preventDefault();
|
||||
} else if (e.keyCode === 9 && e.shiftKey) {
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
e.preventDefault();
|
||||
}
|
||||
return this;
|
||||
@@ -329,7 +333,7 @@ ACTIONMENU.prototype = {
|
||||
|
||||
if (e.keyCode === 27) {
|
||||
// The escape key was pressed so close the menu.
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
e.preventDefault();
|
||||
|
||||
} else if (e.keyCode === 32) {
|
||||
@@ -340,10 +344,10 @@ ACTIONMENU.prototype = {
|
||||
// The tab key was pressed. Tab moves forwards, Shift + Tab moves backwards through the menu options.
|
||||
// We only override the Shift + Tab on the first option, and Tab on the last option to change where the focus is moved to.
|
||||
if (e.target === this.firstMenuChild && e.shiftKey) {
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
e.preventDefault();
|
||||
} else if (e.target === this.lastMenuChild && !e.shiftKey) {
|
||||
if (this.hideMenu()) {
|
||||
if (this.hideMenu(e)) {
|
||||
// Determine the next selector and focus on it.
|
||||
next = this.menulink.next(SELECTOR.CAN_RECEIVE_FOCUS_SELECTOR);
|
||||
if (next) {
|
||||
@@ -410,7 +414,7 @@ ACTIONMENU.prototype = {
|
||||
*/
|
||||
hideIfOutside : function(e) {
|
||||
if (!e.target.ancestor(SELECTOR.MENUCHILD, true)) {
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -462,7 +466,7 @@ ACTIONMENU.prototype = {
|
||||
if (e.currentTarget.test(SELECTOR.KEEPOPEN)) {
|
||||
return;
|
||||
}
|
||||
this.hideMenu();
|
||||
this.hideMenu(e);
|
||||
}, SELECTOR.MENUCHILD, this));
|
||||
|
||||
return true;
|
||||
|
||||
+2
-2
@@ -386,7 +386,7 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
|
||||
Y.Moodle.mod_quiz.util.slot.remove(element);
|
||||
this.reorganise_edit_page();
|
||||
if (M.core.actionmenu && M.core.actionmenu.instance) {
|
||||
M.core.actionmenu.instance.hideMenu();
|
||||
M.core.actionmenu.instance.hideMenu(ev);
|
||||
}
|
||||
} else {
|
||||
window.location.reload(true);
|
||||
@@ -431,7 +431,7 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
|
||||
|
||||
this.send_request(data, null, function(response) {
|
||||
if (M.core.actionmenu && M.core.actionmenu.instance) {
|
||||
M.core.actionmenu.instance.hideMenu();
|
||||
M.core.actionmenu.instance.hideMenu(ev);
|
||||
}
|
||||
|
||||
// Try to retrieve the existing string from the server.
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -386,7 +386,7 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
|
||||
Y.Moodle.mod_quiz.util.slot.remove(element);
|
||||
this.reorganise_edit_page();
|
||||
if (M.core.actionmenu && M.core.actionmenu.instance) {
|
||||
M.core.actionmenu.instance.hideMenu();
|
||||
M.core.actionmenu.instance.hideMenu(ev);
|
||||
}
|
||||
} else {
|
||||
window.location.reload(true);
|
||||
@@ -431,7 +431,7 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
|
||||
|
||||
this.send_request(data, null, function(response) {
|
||||
if (M.core.actionmenu && M.core.actionmenu.instance) {
|
||||
M.core.actionmenu.instance.hideMenu();
|
||||
M.core.actionmenu.instance.hideMenu(ev);
|
||||
}
|
||||
|
||||
// Try to retrieve the existing string from the server.
|
||||
|
||||
+2
-2
@@ -172,7 +172,7 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
|
||||
Y.Moodle.mod_quiz.util.slot.remove(element);
|
||||
this.reorganise_edit_page();
|
||||
if (M.core.actionmenu && M.core.actionmenu.instance) {
|
||||
M.core.actionmenu.instance.hideMenu();
|
||||
M.core.actionmenu.instance.hideMenu(ev);
|
||||
}
|
||||
} else {
|
||||
window.location.reload(true);
|
||||
@@ -217,7 +217,7 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
|
||||
|
||||
this.send_request(data, null, function(response) {
|
||||
if (M.core.actionmenu && M.core.actionmenu.instance) {
|
||||
M.core.actionmenu.instance.hideMenu();
|
||||
M.core.actionmenu.instance.hideMenu(ev);
|
||||
}
|
||||
|
||||
// Try to retrieve the existing string from the server.
|
||||
|
||||
Reference in New Issue
Block a user