Metadata
- Source
- FLUID-4681
- Type
- Bug
- Priority
- Major
- Status
- Closed
- Resolution
- Fixed
- Assignee
- Antranig Basman
- Reporter
- Antranig Basman
- Created
2012-03-27T02:51:16.832-0400 - Updated
2024-07-22T09:39:03.571-0400 - Versions
- N/A
- Fixed Versions
-
- 1.5
- Component
-
- Inline Edit
Description
Reported in today's IRC channel logs by NickMayne:
http://wiki.fluidproject.org/display/fluid/fluid-work+IRC+Logs-2012-03-26
The issue occurs on FF but not on Chrome. The issue appears to be a 3-way misunderstanding between the browser, jQuery and TinyMCE (and, naturally, us!). The user attempted to resolve "jumping on startup" issues by applying the option lazyInit = true, but this precipitated one of a number of failures on FF - most notably, that clicking on the editable region for the very first time to perform the edit causes it to immediately close up again. Tracing through the focus issues show this to be caused by the following interaction:
i) The InlineEditIntegrations.js attempts to apply focus to the newly created editable region, after applying a respectful delay - InlineEditIntegrations.js has
tinyMCE.execCommand('mceFocus', false, that.editField[0].id);
ii) the tinyMCE implementation attempts to honour this focus by calling the focus() method of the raw DOM node corresponding to the editor body (actually the "body" HTML node of an iframe!!) -
tiny_mce_src.js line 13187 has body.focus()
iii) this focus request leads DIRECTLY to a dispatch into the jQuery implementation for the blur handler for the proxy editable textarea element (no intervening stack frames are shown in Firebug). This leads to jQuery dispatching a synthetic "focusout" event for that element
jquery-1.7.1.js line 3684 has
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
where "fix" has the value "focusout"
iv) this triggers our deadMansBlur to start the blur timer for the end of the editing operation. Unfortunately,
v) the expected focus event dispatched by tinyMCE at step ii) never arrives. This is most likely a combination of Firefox's greater fastidiousness in refusing to trade in focus/blur events for nonfocusable DOM elements as defined by W3C, and the fact that the element receiving focus is nested within in iframe. As a result, the DMB timer elapses and the edit operation is cancelled.
Providing a fix for this issue will be messy, and will involve i) upgrading DMB to be potentially responsive to receiving NO focus event whatever within the timer period and still interpreting this as a "cancel handling blur" operation, and ii) being reponsive to (thankfully, new-style) "focusin" events anywhere in the document as well as explicit response to "click" to deal with the case where the user is "morally transfering focus to a nonfocusable element".
It's a shame, since some of these elements were present in the historic "globalDismissal" strategy which was used in CSpace for this task, but was considered unnecessary compared to the apparently superior power of deadMansBlur - especially considering the problems that arose with IE8 in propagating focus/blur events in the wrong order. See FLUID-3487 for the long history of finally getting this functionality to work cross-platform (as it now turns out, only temporarily) - also discussion on CSPACE-3304, the corresponding issue in CollectionSpace:
http://old.nabble.com/CSPACE-3304---dismissing-popup-areas-on-IE8-ts30470733.html
Comments
-
Antranig Basman commented
2012-03-27T02:53:16.272-0400 Current "globalDismissal" code from CSpace Utilities.js:
/** "Global Dismissal Handler" for the entire page. Attaches a click handler to the
- document root that will cause dismissal of any elements (typically dialogs) which
- have registered themselves. Dismissal through this route will automatically clean up
- the record - however, the dismisser themselves must take care to deregister in the case
- dismissal is triggered through the dialog interface itself. */
var dismissList = {};$(document).click(function (event) {
var target = event.target;
while (target) {
if (dismissList[target.id]) {
return;
}
target = target.parentNode;
}
fluid.each(dismissList, function (dismissFunc, key) {
dismissFunc();
delete dismissList[key];
});
});cspace.util.globalDismissal = function (nodes, dismissFunc) {
nodes = $(nodes);
fluid.each(nodes, function (node) {
var id = fluid.allocateSimpleId(node);
if (dismissFunc) {
dismissList[id] = dismissFunc;
}
else {
delete dismissList[id];
}
});
}; -
Michelle D'Souza commented
2012-04-30T07:14:01.618-0400 Merged into project repo at 88390cc667a227ba4f21e6ba4dfa070d23b1170e