mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
351263e4a5
- missing bits of Bug 1207245 - part 1 - move RefCounted<T> (dccd21b327) - Bug 1193583 - Fix out-of-date reftests. (r=jorendorff) (66ee3c50d5) - Bug 1193583 - Fix misc XPConnect and devtools tests. (r=jorendorff) (9ed7a460d1) - Bug 589199 - Make a global lexical scope and hook it up to JS entry points. (r=efaust) (1fde4fba9b) - Bug 589199 - Parse and emit bytecode for global lexicals. (r=efaust) (86d168b94d) - Bug 589199 - Support global lexicals in the interpreter. (r=efaust) (e5fa8ae995) - Bug 589199 - Support global lexicals in Baseline. (r=jandem) (7b744015fe) - Bug 589199 - Support global lexicals in Ion. (r=jandem) (446f05ce97) - Bug 589199 - Fix eval static scope to play with the global lexical scope. (r=efaust) (4a7e4face1) - Bug 589199 - Fix up the global lexical scope when merging off-thread compiled scripts. (r=bhackett) (30ff41230d) - Bug 589199 - Fix jit-tests and js reftests. (r=efaust) (6171fa2c62) - Bug 1202902 - Support non-syntactic extensible lexical scopes. (r=billm) (a2f553d464) - No bug - Rename Definition::CONST to Definition::CONSTANT to avoid macro name collision on Windows. (r=Waldo) (74dfc52b28) - Bug 589199 - Implement all-or-nothing redeclaration checks for global and eval scripts. (r=efaust) (33684af400) - fix misspatch of 589199 (0dbeca332b) - var->let and some misspatches (f2af7240b3) - Bug 1212183 - Fix DOM getter optimizations in the JITs. (r=jandem) (df74d3e88d) - Bug 1212605 - Emit global name conflicts check for Ion scripts regardless of scope chain usage. (r=efaust) (a370f28465) - Bug 1213552 - Fix typo in using TI to guard against introducing shadowing global lexical bindings. (r=efaust) (188f583410) - Bug 1213552 - Followup: add test. (b0ca61190b) - let-var + XP backport (40abaf773c) - Bug 1188290 - Remove an incomplete assertion about store buffer state; r=jandem (7344dd4819) - Bug 1209754 - Assert that all post-barriers happen on the main thread; r=jonco (9a7431aa6d) - comment of 854037 (c026b72e69) - fix definitions (9b140aaafb)
252 lines
7.4 KiB
JavaScript
252 lines
7.4 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/*
|
|
* Handles the validation callback from nsIFormFillController and
|
|
* the display of the help panel on invalid elements.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
var Cc = Components.classes;
|
|
var Ci = Components.interfaces;
|
|
var Cu = Components.utils;
|
|
|
|
var HTMLInputElement = Ci.nsIDOMHTMLInputElement;
|
|
var HTMLTextAreaElement = Ci.nsIDOMHTMLTextAreaElement;
|
|
var HTMLSelectElement = Ci.nsIDOMHTMLSelectElement;
|
|
var HTMLButtonElement = Ci.nsIDOMHTMLButtonElement;
|
|
|
|
this.EXPORTED_SYMBOLS = [ "FormSubmitObserver" ];
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
Cu.import("resource://gre/modules/BrowserUtils.jsm");
|
|
|
|
function FormSubmitObserver(aWindow, aTabChildGlobal) {
|
|
this.init(aWindow, aTabChildGlobal);
|
|
}
|
|
|
|
FormSubmitObserver.prototype =
|
|
{
|
|
_validationMessage: "",
|
|
_content: null,
|
|
_element: null,
|
|
|
|
/*
|
|
* Public apis
|
|
*/
|
|
|
|
init: function(aWindow, aTabChildGlobal)
|
|
{
|
|
this._content = aWindow;
|
|
this._tab = aTabChildGlobal;
|
|
this._mm =
|
|
this._content.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
.getInterface(Ci.nsIDocShell)
|
|
.sameTypeRootTreeItem
|
|
.QueryInterface(Ci.nsIDocShell)
|
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
.getInterface(Ci.nsIContentFrameMessageManager);
|
|
|
|
// nsIFormSubmitObserver callback about invalid forms. See HTMLFormElement
|
|
// for details.
|
|
Services.obs.addObserver(this, "invalidformsubmit", false);
|
|
this._tab.addEventListener("pageshow", this, false);
|
|
this._tab.addEventListener("unload", this, false);
|
|
},
|
|
|
|
uninit: function()
|
|
{
|
|
Services.obs.removeObserver(this, "invalidformsubmit");
|
|
this._content.removeEventListener("pageshow", this, false);
|
|
this._content.removeEventListener("unload", this, false);
|
|
this._mm = null;
|
|
this._element = null;
|
|
this._content = null;
|
|
this._tab = null;
|
|
},
|
|
|
|
/*
|
|
* Events
|
|
*/
|
|
|
|
handleEvent: function (aEvent) {
|
|
switch (aEvent.type) {
|
|
case "pageshow":
|
|
if (this._isRootDocumentEvent(aEvent)) {
|
|
this._hidePopup();
|
|
}
|
|
break;
|
|
case "unload":
|
|
this.uninit();
|
|
break;
|
|
case "input":
|
|
this._onInput(aEvent);
|
|
break;
|
|
case "blur":
|
|
this._onBlur(aEvent);
|
|
break;
|
|
}
|
|
},
|
|
|
|
/*
|
|
* nsIFormSubmitObserver
|
|
*/
|
|
|
|
notifyInvalidSubmit : function (aFormElement, aInvalidElements)
|
|
{
|
|
// We are going to handle invalid form submission attempt by focusing the
|
|
// first invalid element and show the corresponding validation message in a
|
|
// panel attached to the element.
|
|
if (!aInvalidElements.length) {
|
|
return;
|
|
}
|
|
|
|
// Insure that this is the FormSubmitObserver associated with the form
|
|
// element / window this notification is about.
|
|
if (this._content != aFormElement.ownerDocument.defaultView.top.document.defaultView) {
|
|
return;
|
|
}
|
|
|
|
let element = aInvalidElements.queryElementAt(0, Ci.nsISupports);
|
|
if (!(element instanceof HTMLInputElement ||
|
|
element instanceof HTMLTextAreaElement ||
|
|
element instanceof HTMLSelectElement ||
|
|
element instanceof HTMLButtonElement)) {
|
|
return;
|
|
}
|
|
|
|
// Don't connect up to the same element more than once.
|
|
if (this._element == element) {
|
|
this._showPopup(element);
|
|
return;
|
|
}
|
|
this._element = element;
|
|
|
|
element.focus();
|
|
|
|
this._validationMessage = element.validationMessage;
|
|
|
|
// Watch for input changes which may change the validation message.
|
|
element.addEventListener("input", this, false);
|
|
|
|
// Watch for focus changes so we can disconnect our listeners and
|
|
// hide the popup.
|
|
element.addEventListener("blur", this, false);
|
|
|
|
this._showPopup(element);
|
|
},
|
|
|
|
/*
|
|
* Internal
|
|
*/
|
|
|
|
/*
|
|
* Handles input changes on the form element we've associated a popup
|
|
* with. Updates the validation message or closes the popup if form data
|
|
* becomes valid.
|
|
*/
|
|
_onInput: function (aEvent) {
|
|
let element = aEvent.originalTarget;
|
|
|
|
// If the form input is now valid, hide the popup.
|
|
if (element.validity.valid) {
|
|
this._hidePopup();
|
|
return;
|
|
}
|
|
|
|
// If the element is still invalid for a new reason, we should update
|
|
// the popup error message.
|
|
if (this._validationMessage != element.validationMessage) {
|
|
this._validationMessage = element.validationMessage;
|
|
this._showPopup(element);
|
|
}
|
|
},
|
|
|
|
/*
|
|
* Blur event handler in which we disconnect from the form element and
|
|
* hide the popup.
|
|
*/
|
|
_onBlur: function (aEvent) {
|
|
aEvent.originalTarget.removeEventListener("input", this, false);
|
|
aEvent.originalTarget.removeEventListener("blur", this, false);
|
|
this._element = null;
|
|
this._hidePopup();
|
|
},
|
|
|
|
/*
|
|
* Send the show popup message to chrome with appropriate position
|
|
* information. Can be called repetitively to update the currently
|
|
* displayed popup position and text.
|
|
*/
|
|
_showPopup: function (aElement) {
|
|
// Collect positional information and show the popup
|
|
let panelData = {};
|
|
|
|
panelData.message = this._validationMessage;
|
|
|
|
// Note, this is relative to the browser and needs to be translated
|
|
// in chrome.
|
|
panelData.contentRect = this._msgRect(aElement);
|
|
|
|
// We want to show the popup at the middle of checkbox and radio buttons
|
|
// and where the content begin for the other elements.
|
|
let offset = 0;
|
|
let position = "";
|
|
|
|
if (aElement.tagName == 'INPUT' &&
|
|
(aElement.type == 'radio' || aElement.type == 'checkbox')) {
|
|
panelData.position = "bottomcenter topleft";
|
|
} else {
|
|
let win = aElement.ownerDocument.defaultView;
|
|
let style = win.getComputedStyle(aElement, null);
|
|
if (style.direction == 'rtl') {
|
|
offset = parseInt(style.paddingRight) + parseInt(style.borderRightWidth);
|
|
} else {
|
|
offset = parseInt(style.paddingLeft) + parseInt(style.borderLeftWidth);
|
|
}
|
|
let zoomFactor = this._getWindowUtils().fullZoom;
|
|
panelData.offset = Math.round(offset * zoomFactor);
|
|
panelData.position = "after_start";
|
|
}
|
|
this._mm.sendAsyncMessage("FormValidation:ShowPopup", panelData);
|
|
},
|
|
|
|
_hidePopup: function () {
|
|
this._mm.sendAsyncMessage("FormValidation:HidePopup", {});
|
|
},
|
|
|
|
_getWindowUtils: function () {
|
|
return this._content.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
|
},
|
|
|
|
_isRootDocumentEvent: function (aEvent) {
|
|
if (this._content == null) {
|
|
return true;
|
|
}
|
|
let target = aEvent.originalTarget;
|
|
return (target == this._content.document ||
|
|
(target.ownerDocument && target.ownerDocument == this._content.document));
|
|
},
|
|
|
|
/*
|
|
* Return a message manager rect for the element's bounding client rect
|
|
* in top level browser coords.
|
|
*/
|
|
_msgRect: function (aElement) {
|
|
let domRect = aElement.getBoundingClientRect();
|
|
let zoomFactor = this._getWindowUtils().fullZoom;
|
|
let { offsetX, offsetY } = BrowserUtils.offsetToTopLevelWindow(this._content, aElement);
|
|
return {
|
|
left: (domRect.left + offsetX) * zoomFactor,
|
|
top: (domRect.top + offsetY) * zoomFactor,
|
|
width: domRect.width * zoomFactor,
|
|
height: domRect.height * zoomFactor
|
|
};
|
|
},
|
|
|
|
QueryInterface : XPCOMUtils.generateQI([Ci.nsIFormSubmitObserver])
|
|
};
|