Bug 622577 - Most content is not rendered after these steps on bed4less.nl [r=mfinkle]

This commit is contained in:
Vivien Nicolas 2011-01-04 15:56:29 +01:00
parent 88ac4690d9
commit 620be5f496
6 changed files with 203 additions and 49 deletions

View File

@ -1986,6 +1986,9 @@ var FormHelperUI = {
},
receiveMessage: function formHelperReceiveMessage(aMessage) {
if (!this._open && aMessage.name != "FormAssist:Show" && aMessage.name != "FormAssist:Hide")
return;
let json = aMessage.json;
switch (aMessage.name) {
case "FormAssist:Show":
@ -1996,15 +1999,16 @@ var FormHelperUI = {
: SelectHelperUI.show(json.current.choices);
break;
case "FormAssist:Hide":
this.enabled ? this.hide()
: SelectHelperUI.hide();
break;
case "FormAssist:Resize":
let element = json.current;
this._zoom(Rect.fromRect(element.rect), Rect.fromRect(element.caretRect));
break;
case "FormAssist:Hide":
this.hide();
break;
case "FormAssist:AutoComplete":
this._updateAutocompleteFor(json.current);
this._container.contentHasChanged();
@ -2017,14 +2021,14 @@ var FormHelperUI = {
break;
case "DOMWillOpenModalDialog":
if (this._open && aMessage.target == Browser.selectedBrowser) {
if (aMessage.target == Browser.selectedBrowser) {
this._container.style.display = "none";
this._container._spacer.hidden = true;
}
break;
case "DOMModalDialogClosed":
if (this._open && aMessage.target == Browser.selectedBrowser) {
if (aMessage.target == Browser.selectedBrowser) {
this._container.style.display = "-moz-box";
this._container._spacer.hidden = false;
}

View File

@ -71,8 +71,8 @@ function FormAssistant() {
addEventListener("keyup", this, false);
addEventListener("focus", this, true);
addEventListener("DOMWindowCreated", this, false);
addEventListener("pageshow", this, false);
addEventListener("pagehide", this, false);
this._enabled = Services.prefs.getBoolPref("formhelper.enabled");
};
@ -93,10 +93,8 @@ FormAssistant.prototype = {
set currentIndex(aIndex) {
let element = this._elements[aIndex];
if (element) {
this.focusSync = false;
gFocusManager.setFocus(element, Ci.nsIFocusManager.FLAG_NOSCROLL);
this.focusSync = true;
this._currentIndex = aIndex;
gFocusManager.setFocus(element, Ci.nsIFocusManager.FLAG_NOSCROLL);
sendAsyncMessage("FormAssist:Show", this._getJSON());
}
return element;
@ -105,7 +103,7 @@ FormAssistant.prototype = {
_open: false,
open: function formHelperOpen(aElement) {
// if the click is on an option element we want to check if the parent is a valid target
if (aElement instanceof HTMLOptionElement && aElement.parentNode instanceof HTMLSelectElement) {
if (aElement instanceof HTMLOptionElement && aElement.parentNode instanceof HTMLSelectElement && !aElement.disabled) {
aElement = aElement.parentNode;
}
@ -119,10 +117,7 @@ FormAssistant.prototype = {
passiveButtons[aElement.type] && !aElement.disabled)
return false;
sendAsyncMessage("FormAssist:Hide", { });
this._currentIndex = -1;
this._elements = [];
return this._open = false;
return this.close();
}
// Look for a top editable element
@ -144,23 +139,19 @@ FormAssistant.prototype = {
// it we need to inform the UI of such a change to keep in sync with the
// new selected options once the event is finished
if (aElement instanceof HTMLSelectElement) {
let self = this;
let timer = new Util.Timeout(function() {
this._executeDelayed(function(self) {
sendAsyncMessage("FormAssist:Show", self._getJSON());
});
timer.once(0);
}
return false;
}
// If form assistant is disabled but the element of a type of choice list
// If form assistant is disabled but the element is a type of choice list
// we still want to show the simple select list
this._enabled = Services.prefs.getBoolPref("formhelper.enabled");
if (!this._enabled && !this._isSelectElement(aElement)) {
sendAsyncMessage("FormAssist:Hide", { });
return this._open = false;
}
if (!this._enabled && !this._isSelectElement(aElement))
return this.close();
if (this._enabled) {
this._elements = [];
@ -174,6 +165,17 @@ FormAssistant.prototype = {
return this._open = true;
},
close: function close() {
if (this._open) {
this._currentIndex = -1;
this._elements = [];
sendAsyncMessage("FormAssist:Hide", { });
this._open = false;
}
return this._open;
},
receiveMessage: function receiveMessage(aMessage) {
let currentElement = this.currentElement;
if ((!this._enabled && !getWrapperForElement(currentElement)) || !currentElement)
@ -210,8 +212,7 @@ FormAssistant.prototype = {
// reconstruct the inner elements array and to take care of possible
// focus change, this is why we use "self.currentElement" instead of
// using directly "currentElement".
let self = this;
let timer = new Util.Timeout(function() {
this._executeDelayed(function(self) {
let currentElement = self.currentElement;
if (!currentElement)
return;
@ -219,7 +220,6 @@ FormAssistant.prototype = {
self._elements = [];
self._currentIndex = self._getAllElements(currentElement);
});
timer.once(0);
break;
}
@ -256,43 +256,44 @@ FormAssistant.prototype = {
focusSync: false,
handleEvent: function formHelperHandleEvent(aEvent) {
if (!this._enabled || (!this.currentElement && aEvent.type != "focus") || (aEvent.type == "focus" && !this.focusSync))
// focus changes should be taken into account only if the user has done a
// manual operation like manually clicking
let shouldIgnoreFocus = (aEvent.type == "focus" && !this._open && !this.focusSync);
if ((!this._open && aEvent.type != "focus") || shouldIgnoreFocus)
return;
switch (aEvent.type) {
case "DOMWindowCreated":
this.focusSync = false;
break;
case "pagehide":
case "pageshow":
this.focusSync = true;
// When reacting to a page show/hide, if the focus is different this
// could mean the web page has dramatically changed because of
// an Ajax change based on fragment identifier
if (gFocusManager.focusedElement != this.currentElement)
this.close();
break;
case "focus":
let focusedElement = gFocusManager.getFocusedElementForWindow(content, true, {}) || aEvent.target;
// If a body element is editable and the body is the child of an
// iframe we can assume this is an advanced HTML editor, so let's
// iframe we can assume this is an advanced HTML editor, so let's
// redirect the form helper selection to the iframe element
if (focusedElement && this._isEditable(focusedElement)) {
let editableElement = this._getTopLevelEditable(focusedElement);
if (this._isValidElement(editableElement)) {
let self = this;
let timer = new Util.Timeout(function() {
this._executeDelayed(function(self) {
self.open(editableElement);
});
timer.once(0);
}
return;
}
// if an element is focused while we're closed but the element can be handle
// by the assistant, try to activate it
// by the assistant, try to activate it (only during mouseup)
if (!this.currentElement) {
if (focusedElement && this._isValidElement(focusedElement)) {
let self = this;
let timer = new Util.Timeout(function() {
this._executeDelayed(function(self) {
self.open(focusedElement);
});
timer.once(0);
}
return;
}
@ -350,6 +351,14 @@ FormAssistant.prototype = {
}
},
_executeDelayed: function formHelperExecuteSoon(aCallback) {
let self = this;
let timer = new Util.Timeout(function() {
aCallback(self);
});
timer.once(0);
},
_filterEditables: function formHelperFilterEditables(aNodes) {
let result = [];
for (let i = 0; i < aNodes.length; i++) {
@ -367,7 +376,7 @@ FormAssistant.prototype = {
}
return result;
},
_isEditable: function formHelperIsEditable(aElement) {
let canEdit = false;

View File

@ -20,7 +20,7 @@
<div contenteditable="true" tabindex="8"></div>
<textarea id="next">textarea</textarea>
<select id="select">
<option>option 1</option>
<option id="option">option 1</option>
<option>option 2</option>
</select>
<input id="dumb" type="dumb">dumb type</input>

View File

@ -32,25 +32,85 @@ function testMouseEvents() {
is(json.result, false, "Form Assistant should stay closed");
});
AsyncTests.waitFor("Test:Open", { value: "*[tabindex='0']" }, function(json) {
ok(FormHelperUI._open, "Form Assistant should be open");
testShowUIForElements();
AsyncTests.waitFor("Test:Focus", { value: "#root" }, function(json) {
is(json.result, false, "Form Assistant should stay closed");
});
AsyncTests.waitFor("Test:FocusRedirect", { value: "*[tabindex='0']" }, function(json) {
is(json.result, false, "Form Assistant should stay closed");
testOpenUIWithSyncFocus();
});
};
function testOpenUIWithSyncFocus() {
AsyncTests.waitFor("Test:Open", { value: "*[tabindex='0']" }, function(json) {
ok(FormHelperUI._open, "Form Assistant should be open");
testOpenUI();
});
};
function testOpenUI() {
AsyncTests.waitFor("Test:Open", { value: "*[tabindex='0']" }, function(json) {
ok(FormHelperUI._open, "Form Assistant should be open");
testOpenUIWithFocusRedirect();
});
};
function testOpenUIWithFocusRedirect() {
AsyncTests.waitFor("Test:OpenWithFocusRedirect", { value: "*[tabindex='0']" }, function(json) {
ok(FormHelperUI._open, "Form Assistant should be open");
testShowUIForSelect();
});
};
function testShowUIForSelect() {
AsyncTests.waitFor("Test:CanShowUI", { value: "#select"}, function(json) {
ok(json.result, "canShowUI for select element'");
});
AsyncTests.waitFor("Test:CanShowUI", { value: "#select", disabled: true }, function(json) {
is(json.result, false, "!canShowUI for disabled select element'");
});
AsyncTests.waitFor("Test:CanShowUI", { value: "#option"}, function(json) {
ok(json.result, "canShowUI for option element'");
});
AsyncTests.waitFor("Test:CanShowUISelect", { value: "#option", disabled: true }, function(json) {
is(json.result, false, "!canShowUI for option element with a disabled parent select element'");
});
AsyncTests.waitFor("Test:CanShowUI", { value: "#option", disabled: true }, function(json) {
is(json.result, false, "!canShowUI for disabled option element'");
testShowUIForElements();
});
}
function testShowUIForElements() {
AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='1']" }, function(json) {
ok(json.result, "canShowUI for input type='text'");
});
AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='1']", disabled: true }, function(json) {
is(json.result, false, "!canShowUI for disabled input type='text'");
});
AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='2']" }, function(json) {
ok(json.result, "canShowUI for input type='password'");
});
AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='2']", disabled: true }, function(json) {
is(json.result, false, "!canShowUI for disabled input type='password'");
});
AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='8']" }, function(json) {
ok(json.result, "canShowUI for contenteditable div");
});
AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='8']", disabled: true }, function(json) {
is(json.result, false, "!canShowUI for disabled contenteditable div");
});
AsyncTests.waitFor("Test:CanShowUI", { value: "*[tabindex='3']" }, function(json) {
is(json.result, false, "!canShowUI for input type='submit'");
});
@ -112,7 +172,7 @@ function testTabIndexNavigation() {
let ids = ["next", "select", "dumb", "reset", "checkbox", "radio0", "radio4", "last", "last"];
for (let i = 0; i < ids.length; i++) {
let id = ids[i];
AsyncTests.waitFor("Test:Next", { value: "*[id='" + id + "']" }, function(json) {
AsyncTests.waitFor("Test:Next", { value: "#" + id }, function(json) {
is(json.result, true, "Focus should be on element with #id: " + id + "");
});
};
@ -121,10 +181,27 @@ function testTabIndexNavigation() {
let container = document.getElementById("content-navigator");
is(container.hidden, true, "Form Assistant should be close");
loadNestedIFrames();
AsyncTests.waitFor("Test:Open", { value: "*[tabindex='0']" }, function(json) {
ok(FormHelperUI._open, "Form Assistant should be open");
testFocusChanges();
});
};
function testFocusChanges() {
AsyncTests.waitFor("Test:Focus", { value: "*[tabindex='1']" }, function(json) {
ok(json.result, "Form Assistant should be open");
});
AsyncTests.waitFor("Test:Focus", { value: "#select" }, function(json) {
ok(json.result, "Form Assistant should stay open");
});
AsyncTests.waitFor("Test:Focus", { value: "*[type='hidden']" }, function(json) {
ok(json.result, "Form Assistant should stay open");
loadNestedIFrames();
});
}
function loadNestedIFrames() {
AsyncTests.waitFor("Test:Iframe", { }, function(json) {
is(json.result, true, "Iframe should have loaded");

View File

@ -58,7 +58,9 @@ let AsyncTests = {
this._tests[aMessage] = [];
this._tests[aMessage].push(aCallback || function() {});
Browser.selectedBrowser.messageManager.sendAsyncMessage(aMessage, aData || { });
setTimeout(function() {
Browser.selectedBrowser.messageManager.sendAsyncMessage(aMessage, aData || { });
}, 0);
},
receiveMessage: function(aMessage) {

View File

@ -50,15 +50,77 @@ AsyncTests.add("Test:Click", function(aMessage, aJson) {
return assistant._open;
});
AsyncTests.add("Test:Focus", function(aMessage, aJson) {
let targetElement = content.document.querySelector(aJson.value);
targetElement.focus();
assistant._executeDelayed(function() {
sendAsyncMessage(aMessage, { result: assistant._open });
});
});
AsyncTests.add("Test:FocusRedirect", function(aMessage, aJson) {
let element = content.document.querySelector(aJson.value);
element.addEventListener("focus", function(aEvent) {
element.removeEventListener("focus", arguments.callee, false);
content.document.getElementById("root").focus();
}, false);
element.focus();
assistant._executeDelayed(function() {
sendAsyncMessage(aMessage, { result: assistant._open });
});
});
// It should be only 2 ways to open the FormAssistant, the first one is
// by manually synchronizing the focus to the form helper and the other
// one is by a user click on an authorized element
AsyncTests.add("Test:OpenUIWithSyncFocus", function(aMessage, aJson) {
let element = content.document.querySelector(aJson.value);
assistant._open = false;
assitant.focusSync = true;
element.focus();
assistant._executeDelayed(function() {
assistant.focusSync = false;
sendAsyncMessage(aMessage, { result: assistant._open });
});
});
AsyncTests.add("Test:Open", function(aMessage, aJson) {
let element = content.document.querySelector(aJson.value);
assistant._open = false;
return assistant.open(element);
});
AsyncTests.add("Test:OpenWithFocusRedirect", function(aMessage, aJson) {
let element = content.document.querySelector(aJson.value);
assistant._open = false;
assistant.focusSync = true;
assistant.open(element);
assistant._executeDelayed(function() {
assistant.focusSync = false;
sendAsyncMessage(aMessage, { result: assistant._open });
});
});
AsyncTests.add("Test:CanShowUI", function(aMessage, aJson) {
let element = content.document.querySelector(aJson.value);
element.disabled = aJson.disabled;
assistant._open = false;
return assistant.open(element);
let open = assistant.open(element);
element.disabled = false;
return open;
});
AsyncTests.add("Test:CanShowUISelect", function(aMessage, aJson) {
let select = content.document.getElementById("select");
select.disabled = aJson.disabled;
let element = content.document.querySelector(aJson.value);
assistant._open = false;
let open = assistant.open(element);
select.disabled = false;
return open;
});
AsyncTests.add("Test:Previous", function(aMessage, aJson) {