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:
Neill Magill
2015-08-28 12:16:46 +01:00
parent f66090899d
commit 70fb7ac4b3
13 changed files with 62 additions and 44 deletions
@@ -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
View File
@@ -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
+6
View File
@@ -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
View File
@@ -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;
@@ -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.
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
View File
@@ -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.