diff options
Diffstat (limited to 'modules/FormValidationHandler.jsm')
-rw-r--r-- | modules/FormValidationHandler.jsm | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/modules/FormValidationHandler.jsm b/modules/FormValidationHandler.jsm new file mode 100644 index 0000000..387c221 --- /dev/null +++ b/modules/FormValidationHandler.jsm @@ -0,0 +1,157 @@ +/* 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/. */ + +/* + * Chrome side handling of form validation popup. + */ + +"use strict"; + +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cu = Components.utils; + +this.EXPORTED_SYMBOLS = [ "FormValidationHandler" ]; + +Cu.import("resource://gre/modules/Services.jsm"); + +var FormValidationHandler = +{ + _panel: null, + _anchor: null, + + /* + * Public apis + */ + + init: function () { + let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager); + mm.addMessageListener("FormValidation:ShowPopup", this); + mm.addMessageListener("FormValidation:HidePopup", this); + }, + + uninit: function () { + let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager); + mm.removeMessageListener("FormValidation:ShowPopup", this); + mm.removeMessageListener("FormValidation:HidePopup", this); + this._panel = null; + this._anchor = null; + }, + + hidePopup: function () { + this._hidePopup(); + }, + + /* + * Events + */ + + receiveMessage: function (aMessage) { + let window = aMessage.target.ownerDocument.defaultView; + let json = aMessage.json; + let tabBrowser = window.gBrowser; + switch (aMessage.name) { + case "FormValidation:ShowPopup": + // target is the <browser>, make sure we're receiving a message + // from the foreground tab. + if (tabBrowser && aMessage.target != tabBrowser.selectedBrowser) { + return; + } + this._showPopup(window, json); + break; + case "FormValidation:HidePopup": + this._hidePopup(); + break; + } + }, + + observe: function (aSubject, aTopic, aData) { + this._hidePopup(); + }, + + handleEvent: function (aEvent) { + switch (aEvent.type) { + case "FullZoomChange": + case "TextZoomChange": + case "ZoomChangeUsingMouseWheel": + case "scroll": + this._hidePopup(); + break; + case "popuphiding": + this._onPopupHiding(aEvent); + break; + } + }, + + /* + * Internal + */ + + _onPopupHiding: function (aEvent) { + aEvent.originalTarget.removeEventListener("popuphiding", this, true); + let tabBrowser = aEvent.originalTarget.ownerDocument.getElementById("content"); + tabBrowser.selectedBrowser.removeEventListener("scroll", this, true); + tabBrowser.selectedBrowser.removeEventListener("FullZoomChange", this, false); + tabBrowser.selectedBrowser.removeEventListener("TextZoomChange", this, false); + tabBrowser.selectedBrowser.removeEventListener("ZoomChangeUsingMouseWheel", this, false); + + this._panel.hidden = true; + this._panel = null; + this._anchor.hidden = true; + this._anchor = null; + }, + + /* + * Shows the form validation popup at a specified position or updates the + * messaging and position if the popup is already displayed. + * + * @aWindow - the chrome window + * @aPanelData - Object that contains popup information + * aPanelData stucture detail: + * contentRect - the bounding client rect of the target element. If + * content is remote, this is relative to the browser, otherwise its + * relative to the window. + * position - popup positional string constants. + * message - the form element validation message text. + */ + _showPopup: function (aWindow, aPanelData) { + let previouslyShown = !!this._panel; + this._panel = aWindow.document.getElementById("invalid-form-popup"); + this._panel.firstChild.textContent = aPanelData.message; + this._panel.hidden = false; + + let tabBrowser = aWindow.gBrowser; + this._anchor = tabBrowser.popupAnchor; + this._anchor.left = aPanelData.contentRect.left; + this._anchor.top = aPanelData.contentRect.top; + this._anchor.width = aPanelData.contentRect.width; + this._anchor.height = aPanelData.contentRect.height; + this._anchor.hidden = false; + + // Display the panel if it isn't already visible. + if (!previouslyShown) { + // Cleanup after the popup is hidden + this._panel.addEventListener("popuphiding", this, true); + + // Hide if the user scrolls the page + tabBrowser.selectedBrowser.addEventListener("scroll", this, true); + tabBrowser.selectedBrowser.addEventListener("FullZoomChange", this, false); + tabBrowser.selectedBrowser.addEventListener("TextZoomChange", this, false); + tabBrowser.selectedBrowser.addEventListener("ZoomChangeUsingMouseWheel", this, false); + + // Open the popup + this._panel.openPopup(this._anchor, aPanelData.position, 0, 0, false); + } + }, + + /* + * Hide the popup if currently displayed. Will fire an event to onPopupHiding + * above if visible. + */ + _hidePopup: function () { + if (this._panel) { + this._panel.hidePopup(); + } + } +}; |