зеркало из https://github.com/mozilla/gecko-dev.git
Bug 648026 - Move Content Popup Helper out of FormHelperUI [r=mfinkle]
This commit is contained in:
Родитель
e9b6bed064
Коммит
45415c336c
|
@ -0,0 +1,233 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
var ContentPopupHelper = {
|
||||
_popup: null,
|
||||
get popup() {
|
||||
return this._popup;
|
||||
},
|
||||
|
||||
set popup(aPopup) {
|
||||
// If there is nothing to do then bail out
|
||||
if (!this._popup && !aPopup)
|
||||
return;
|
||||
|
||||
if (aPopup) {
|
||||
// Keeps the new popup element hidden until it is positioned, but using
|
||||
// visibility: 'hidden' instead of display: 'none' will allow to
|
||||
// workaround some bugs with arrowscrollbox's arrows that does not
|
||||
// update their hidden state correctly when used as a child (because of
|
||||
// missed underflow events)
|
||||
//
|
||||
// Also the popup is moved to the left border of the window otherwise the
|
||||
// sidebars position are messed up when the content of the popup's child
|
||||
// is too wide, but since the size of the popup can't be larger than 75%
|
||||
// of the window width (see the update method) then the problem does not
|
||||
// appear if the popup is positioned between 0-25% percent of the window
|
||||
// width
|
||||
aPopup.left = 0;
|
||||
aPopup.firstChild.style.maxWidth = "0px";
|
||||
aPopup.style.visibility = "hidden";
|
||||
aPopup.hidden = false;
|
||||
|
||||
window.addEventListener("TabSelect", this, false);
|
||||
window.addEventListener("TabClose", this, false);
|
||||
window.addEventListener("AnimatedZoomBegin", this, false);
|
||||
window.addEventListener("AnimatedZoomEnd", this, false);
|
||||
window.addEventListener("MozBeforeResize", this, true);
|
||||
window.addEventListener("resize", this, false);
|
||||
Elements.browsers.addEventListener("PanBegin", this, false);
|
||||
Elements.browsers.addEventListener("PanFinished", this, false);
|
||||
} else {
|
||||
this._popup.hidden = true;
|
||||
this._anchorRect = null;
|
||||
|
||||
window.removeEventListener("TabSelect", this, false);
|
||||
window.removeEventListener("TabClose", this, false);
|
||||
window.removeEventListener("AnimatedZoomBegin", this, false);
|
||||
window.removeEventListener("AnimatedZoomEnd", this, false);
|
||||
window.removeEventListener("MozBeforeResize", this, true);
|
||||
window.removeEventListener("resize", this, false);
|
||||
Elements.browsers.removeEventListener("PanBegin", this, false);
|
||||
Elements.browsers.removeEventListener("PanFinished", this, false);
|
||||
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("contentpopuphidden", true, false);
|
||||
this._popup.dispatchEvent(event);
|
||||
}
|
||||
|
||||
this._popup = aPopup;
|
||||
},
|
||||
|
||||
/**
|
||||
* This method positioned an arrowbox on the screen using a 'virtual'
|
||||
* element as referrer that match the real content element
|
||||
* This method called element.getBoundingClientRect() many times and can be
|
||||
* expensive, do not called it too many times.
|
||||
*/
|
||||
anchorTo: function(aAnchorRect) {
|
||||
let popup = this._popup;
|
||||
if (!popup)
|
||||
return;
|
||||
|
||||
// Use the old rect until we get a new one
|
||||
this._anchorRect = aAnchorRect ? aAnchorRect : this._anchorRect;
|
||||
|
||||
// Calculate the maximum size of the arrowpanel by allowing it to live only
|
||||
// on the visible browser area
|
||||
let [leftVis, rightVis, leftW, rightW] = Browser.computeSidebarVisibility();
|
||||
let leftOffset = leftVis * leftW;
|
||||
let rightOffset = rightVis * rightW;
|
||||
let visibleAreaWidth = window.innerWidth - leftOffset - rightOffset;
|
||||
popup.firstChild.style.maxWidth = (visibleAreaWidth * 0.75) + "px";
|
||||
|
||||
let browser = getBrowser();
|
||||
let rect = this._anchorRect.clone().scale(browser.scale, browser.scale);
|
||||
let scroll = browser.getRootView().getPosition();
|
||||
|
||||
// The sidebars scroll needs to be taken into account, otherwise the arrows
|
||||
// can be misplaced if the sidebars are open
|
||||
let topOffset = (BrowserUI.toolbarH - Browser.getScrollboxPosition(Browser.pageScrollboxScroller).y);
|
||||
|
||||
// Notifications take height _before_ the browser if there any
|
||||
let notification = Browser.getNotificationBox().currentNotification;
|
||||
if (notification)
|
||||
topOffset += notification.getBoundingClientRect().height;
|
||||
|
||||
let virtualContentRect = {
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
left: Math.ceil(rect.left - scroll.x + leftOffset - rightOffset),
|
||||
right: Math.floor(rect.left + rect.width - scroll.x + leftOffset - rightOffset),
|
||||
top: Math.ceil(rect.top - scroll.y + topOffset),
|
||||
bottom: Math.floor(rect.top + rect.height - scroll.y + topOffset)
|
||||
};
|
||||
|
||||
// Translate the virtual rect inside the bounds of the viewable area if it
|
||||
// overflow
|
||||
if (virtualContentRect.left + virtualContentRect.width > visibleAreaWidth) {
|
||||
let offsetX = visibleAreaWidth - (virtualContentRect.left + virtualContentRect.width);
|
||||
virtualContentRect.width += offsetX;
|
||||
virtualContentRect.right -= offsetX;
|
||||
}
|
||||
|
||||
if (virtualContentRect.left < leftOffset) {
|
||||
let offsetX = (virtualContentRect.right - virtualContentRect.width);
|
||||
virtualContentRect.width += offsetX;
|
||||
virtualContentRect.left -= offsetX;
|
||||
}
|
||||
|
||||
// If the suggestions are out of view there is no need to display it
|
||||
let browserRect = Rect.fromRect(browser.getBoundingClientRect());
|
||||
if (BrowserUI.isToolbarLocked()) {
|
||||
// If the toolbar is locked, it can appear over the field in such a way
|
||||
// that the field is hidden
|
||||
let toolbarH = BrowserUI.toolbarH;
|
||||
browserRect = new Rect(leftOffset - rightOffset, Math.max(0, browserRect.top - toolbarH) + toolbarH,
|
||||
browserRect.width + leftOffset - rightOffset, browserRect.height - toolbarH);
|
||||
}
|
||||
|
||||
if (browserRect.intersect(Rect.fromRect(virtualContentRect)).isEmpty()) {
|
||||
popup.style.visibility = "hidden";
|
||||
return;
|
||||
}
|
||||
|
||||
// Adding rect.height to the top moves the arrowbox below the virtual field
|
||||
let left = rect.left - scroll.x + leftOffset - rightOffset;
|
||||
let top = rect.top - scroll.y + topOffset + (rect.height);
|
||||
|
||||
// Ensure parts of the arrowbox are not outside the window
|
||||
let arrowboxRect = Rect.fromRect(popup.getBoundingClientRect());
|
||||
if (left + arrowboxRect.width > window.innerWidth)
|
||||
left -= (left + arrowboxRect.width - window.innerWidth);
|
||||
else if (left < leftOffset)
|
||||
left += (leftOffset - left);
|
||||
popup.left = left;
|
||||
|
||||
// Do not position the suggestions over the navigation buttons
|
||||
let buttonsHeight = Elements.contentNavigator.getBoundingClientRect().height;
|
||||
if (top + arrowboxRect.height >= window.innerHeight - buttonsHeight)
|
||||
top -= (rect.height + arrowboxRect.height);
|
||||
popup.top = top;
|
||||
|
||||
// Create a virtual element to point to
|
||||
let virtualContentElement = {
|
||||
getBoundingClientRect: function() {
|
||||
return virtualContentRect;
|
||||
}
|
||||
};
|
||||
popup.anchorTo(virtualContentElement);
|
||||
popup.style.visibility = "visible";
|
||||
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("contentpopupshown", true, false);
|
||||
popup.dispatchEvent(event);
|
||||
},
|
||||
|
||||
handleEvent: function(aEvent) {
|
||||
let popup = this._popup;
|
||||
if (!popup || !this._anchorRect)
|
||||
return;
|
||||
|
||||
switch(aEvent.type) {
|
||||
case "TabSelect":
|
||||
case "TabClose":
|
||||
this.popup = null;
|
||||
break;
|
||||
|
||||
case "PanBegin":
|
||||
case "AnimatedZoomBegin":
|
||||
popup.left = 0;
|
||||
popup.style.visibility = "hidden";
|
||||
break;
|
||||
|
||||
case "PanFinished":
|
||||
case "AnimatedZoomEnd":
|
||||
popup.style.visibility = "visible";
|
||||
this.anchorTo();
|
||||
break;
|
||||
|
||||
case "MozBeforeResize":
|
||||
popup.left = 0;
|
||||
break;
|
||||
|
||||
case "resize":
|
||||
this.anchorTo();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -104,6 +104,7 @@ XPCOMUtils.defineLazyGetter(this, "CommonUI", function() {
|
|||
["PreferencesView", "chrome://browser/content/preferences.js"],
|
||||
["Sanitizer", "chrome://browser/content/sanitize.js"],
|
||||
["SelectHelperUI", "chrome://browser/content/SelectHelperUI.js"],
|
||||
["ContentPopupHelper", "chrome://browser/content/ContentPopupHelper.js"],
|
||||
["SharingUI", "chrome://browser/content/SharingUI.js"],
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
["WeaveGlue", "chrome://browser/content/sync.js"],
|
||||
|
|
|
@ -646,7 +646,6 @@ var FormHelperUI = {
|
|||
|
||||
init: function formHelperInit() {
|
||||
this._container = document.getElementById("content-navigator");
|
||||
this._suggestionsContainer = document.getElementById("form-helper-suggestions-container");
|
||||
this._cmdPrevious = document.getElementById(this.commands.previous);
|
||||
this._cmdNext = document.getElementById(this.commands.next);
|
||||
|
||||
|
@ -673,13 +672,9 @@ var FormHelperUI = {
|
|||
window.addEventListener("keyup", this, true);
|
||||
window.addEventListener("keypress", this, true);
|
||||
|
||||
// Listen some events to show/hide the autocomplete box
|
||||
// Listen some events to show/hide arrows
|
||||
Elements.browsers.addEventListener("PanBegin", this, false);
|
||||
Elements.browsers.addEventListener("PanFinished", this, false);
|
||||
window.addEventListener("AnimatedZoomBegin", this, false);
|
||||
window.addEventListener("AnimatedZoomEnd", this, false);
|
||||
window.addEventListener("MozBeforeResize", this, true);
|
||||
window.addEventListener("resize", this, false);
|
||||
},
|
||||
|
||||
_currentBrowser: null,
|
||||
|
@ -697,7 +692,6 @@ var FormHelperUI = {
|
|||
else
|
||||
this._container.removeAttribute("disabled");
|
||||
|
||||
this._hasSuggestions = false;
|
||||
this._open = true;
|
||||
|
||||
let lastElement = this._currentElement || null;
|
||||
|
@ -715,7 +709,6 @@ var FormHelperUI = {
|
|||
|
||||
this._updateContainerForSelect(lastElement, this._currentElement);
|
||||
this._zoom(Rect.fromRect(aElement.rect), Rect.fromRect(aElement.caretRect));
|
||||
this._updateSuggestionsFor(this._currentElement);
|
||||
|
||||
// Prevent the view to scroll automatically while typing
|
||||
this._currentBrowser.scrollSync = false;
|
||||
|
@ -733,7 +726,6 @@ var FormHelperUI = {
|
|||
this._currentCaretRect = null;
|
||||
|
||||
this._updateContainerForSelect(this._currentElement, null);
|
||||
this._resetSuggestions();
|
||||
|
||||
this._currentBrowser.messageManager.sendAsyncMessage("FormAssist:Closed", { });
|
||||
this._open = false;
|
||||
|
@ -758,28 +750,11 @@ var FormHelperUI = {
|
|||
// manual dblClick and navigation between the fields by clicking the
|
||||
// buttons
|
||||
this._container.style.visibility = "hidden";
|
||||
|
||||
case "AnimatedZoomBegin":
|
||||
// Changing the hidden attribute here create bugs with the scrollbox
|
||||
// arrows because the binding will miss some underflow events
|
||||
if (this._hasSuggestions) {
|
||||
// Because the suggestions container could be big in terms of width
|
||||
// (but never bigger than the screen) it's position needs to be
|
||||
// resetted to the left to ensure it does not push the content to
|
||||
// the right and misplaced sidebars as a result
|
||||
this._suggestionsContainer.left = 0;
|
||||
this._suggestionsContainer.style.visibility = "hidden";
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case "PanFinished":
|
||||
this._container.style.visibility = "visible";
|
||||
|
||||
case "AnimatedZoomEnd":
|
||||
if (this._hasSuggestions) {
|
||||
this._suggestionsContainer.style.visibility = "visible";
|
||||
this._ensureSuggestionsVisible();
|
||||
}
|
||||
break;
|
||||
|
||||
case "URLChanged":
|
||||
|
@ -813,16 +788,6 @@ var FormHelperUI = {
|
|||
self._zoom(self._currentElementRect, self._currentCaretRect);
|
||||
}, 0, this);
|
||||
break;
|
||||
|
||||
case "MozBeforeResize":
|
||||
if (this._hasSuggestions)
|
||||
this._suggestionsContainer.left = 0;
|
||||
break;
|
||||
|
||||
case "resize":
|
||||
if (this._hasSuggestions)
|
||||
this._ensureSuggestionsVisible();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -903,6 +868,7 @@ var FormHelperUI = {
|
|||
this._currentElement = null;
|
||||
this._container.hide(this);
|
||||
|
||||
ContentPopupHelper.popup = null;
|
||||
this._container.removeAttribute("disabled");
|
||||
|
||||
// Since the style is overrided when a popup is shown, it needs to be
|
||||
|
@ -915,35 +881,25 @@ var FormHelperUI = {
|
|||
this._container.dispatchEvent(evt);
|
||||
},
|
||||
|
||||
_hasSuggestions: false,
|
||||
_updateSuggestionsFor: function _formHelperUpdateAutocompleteFor(aElement) {
|
||||
let suggestions = this._getAutocompleteSuggestions(aElement);
|
||||
if (!suggestions.length) {
|
||||
this._resetSuggestions();
|
||||
ContentPopupHelper.popup = null;
|
||||
return;
|
||||
}
|
||||
// Keeps the suggestions element hidden while is it not positionned to the
|
||||
// correct place
|
||||
let suggestionsContainer = this._suggestionsContainer;
|
||||
suggestionsContainer.style.visibility = "hidden";
|
||||
suggestionsContainer.hidden = false;
|
||||
suggestionsContainer.left = 0;
|
||||
|
||||
// the scrollX/scrollY position can change because of the animated zoom so
|
||||
// delay the suggestions positioning
|
||||
if (AnimatedZoom.isZooming()) {
|
||||
let self = this;
|
||||
window.addEventListener("AnimatedZoomEnd", function() {
|
||||
window.removeEventListener("AnimatedZoomEnd", arguments.callee, true);
|
||||
// Ensure the current element has not changed during this interval
|
||||
if (self._currentElement != aElement)
|
||||
return;
|
||||
|
||||
self._updateSuggestionsFor(aElement);
|
||||
}, true);
|
||||
this._waitForZoom(function() {
|
||||
self._updateSuggestionsFor(aElement);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Declare which box is going to be the inside container of the content popup helper
|
||||
let suggestionsContainer = document.getElementById("form-helper-suggestions-container");
|
||||
let container = suggestionsContainer.firstChild;
|
||||
while (container.hasChildNodes())
|
||||
container.removeChild(container.lastChild);
|
||||
|
@ -959,8 +915,8 @@ var FormHelperUI = {
|
|||
}
|
||||
container.appendChild(fragment);
|
||||
|
||||
this._hasSuggestions = true;
|
||||
this._ensureSuggestionsVisible();
|
||||
ContentPopupHelper.popup = suggestionsContainer;
|
||||
ContentPopupHelper.anchorTo(this._currentElementRect);
|
||||
},
|
||||
|
||||
/** Retrieve the autocomplete list from the autocomplete service for an element */
|
||||
|
@ -993,114 +949,6 @@ var FormHelperUI = {
|
|||
return suggestions;
|
||||
},
|
||||
|
||||
_resetSuggestions: function _formHelperResetAutocomplete() {
|
||||
this._suggestionsContainer.hidden = true;
|
||||
this._hasSuggestions = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* This method positionned the list of suggestions on the screen using
|
||||
* a 'virtual' element as referrer that match the real content element
|
||||
* This method called element.getBoundingClientRect() many times and can be
|
||||
* expensive, do not called it too many times.
|
||||
*/
|
||||
_ensureSuggestionsVisible: function _formHelperEnsureSuggestionsVisible() {
|
||||
let container = this._suggestionsContainer;
|
||||
|
||||
// Calculate the maximum size of the arrowpanel by allowing it to live only
|
||||
// on the visible browser area
|
||||
let [leftVis, rightVis, leftW, rightW] = Browser.computeSidebarVisibility();
|
||||
let leftOffset = leftVis * leftW;
|
||||
let rightOffset = rightVis * rightW;
|
||||
let visibleAreaWidth = window.innerWidth - leftOffset - rightOffset;
|
||||
container.firstChild.style.maxWidth = (visibleAreaWidth * 0.75) + "px";
|
||||
|
||||
let browser = getBrowser();
|
||||
let rect = this._currentElementRect.clone().scale(browser.scale, browser.scale);
|
||||
let scroll = browser.getRootView().getPosition();
|
||||
|
||||
// The sidebars scroll needs to be taken into account, otherwise the arrows
|
||||
// can be misplaced if the sidebars are open
|
||||
let topOffset = (BrowserUI.toolbarH - Browser.getScrollboxPosition(Browser.pageScrollboxScroller).y);
|
||||
|
||||
// Notifications take height _before_ the browser if there any
|
||||
let notification = Browser.getNotificationBox().currentNotification;
|
||||
if (notification)
|
||||
topOffset += notification.getBoundingClientRect().height;
|
||||
|
||||
let virtualContentRect = {
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
left: Math.ceil(rect.left - scroll.x + leftOffset - rightOffset),
|
||||
right: Math.floor(rect.left + rect.width - scroll.x + leftOffset - rightOffset),
|
||||
top: Math.ceil(rect.top - scroll.y + topOffset),
|
||||
bottom: Math.floor(rect.top + rect.height - scroll.y + topOffset)
|
||||
};
|
||||
|
||||
// Translate the virtual rect inside the bounds of the viewable area if it
|
||||
// overflow
|
||||
if (virtualContentRect.left + virtualContentRect.width > visibleAreaWidth) {
|
||||
let offsetX = visibleAreaWidth - (virtualContentRect.left + virtualContentRect.width);
|
||||
virtualContentRect.width += offsetX;
|
||||
virtualContentRect.right -= offsetX;
|
||||
}
|
||||
|
||||
if (virtualContentRect.left < leftOffset) {
|
||||
let offsetX = (virtualContentRect.right - virtualContentRect.width);
|
||||
virtualContentRect.width += offsetX;
|
||||
virtualContentRect.left -= offsetX;
|
||||
}
|
||||
|
||||
// If the suggestions are out of view there is no need to display it
|
||||
let browserRect = Rect.fromRect(browser.getBoundingClientRect());
|
||||
if (BrowserUI.isToolbarLocked()) {
|
||||
// If the toolbar is locked, it can appear over the field in such a way
|
||||
// that the field is hidden
|
||||
let toolbarH = BrowserUI.toolbarH;
|
||||
browserRect = new Rect(leftOffset - rightOffset, Math.max(0, browserRect.top - toolbarH) + toolbarH,
|
||||
browserRect.width + leftOffset - rightOffset, browserRect.height - toolbarH);
|
||||
}
|
||||
|
||||
if (browserRect.intersect(Rect.fromRect(virtualContentRect)).isEmpty()) {
|
||||
container.style.visibility = "hidden";
|
||||
return;
|
||||
}
|
||||
|
||||
// Adding rect.height to the top moves the arrowbox below the virtual field
|
||||
let left = rect.left - scroll.x + leftOffset - rightOffset;
|
||||
let top = rect.top - scroll.y + topOffset + (rect.height);
|
||||
|
||||
// Ensure parts of the arrowbox are not outside the window
|
||||
let arrowboxRect = Rect.fromRect(container.getBoundingClientRect());
|
||||
if (left + arrowboxRect.width > window.innerWidth)
|
||||
left -= (left + arrowboxRect.width - window.innerWidth);
|
||||
else if (left < leftOffset)
|
||||
left += (leftOffset - left);
|
||||
container.left = left;
|
||||
|
||||
// Do not position the suggestions over the navigation buttons
|
||||
let buttonsHeight = this._container.getBoundingClientRect().height;
|
||||
if (top + arrowboxRect.height >= window.innerHeight - buttonsHeight)
|
||||
top -= (rect.height + arrowboxRect.height);
|
||||
container.top = top;
|
||||
|
||||
// Create a virtual element to point to
|
||||
let virtualContentElement = {
|
||||
getBoundingClientRect: function() {
|
||||
return virtualContentRect;
|
||||
}
|
||||
};
|
||||
container.anchorTo(virtualContentElement);
|
||||
container.style.visibility = "visible";
|
||||
},
|
||||
|
||||
/** Update the form helper container to reflect new element user is editing. */
|
||||
_updateContainer: function _formHelperUpdateContainer(aLastElement, aCurrentElement) {
|
||||
this._updateContainerForSelect(aLastElement, aCurrentElement);
|
||||
|
||||
this._container.contentHasChanged();
|
||||
},
|
||||
|
||||
/** Helper for _updateContainer that handles the case where the new element is a select. */
|
||||
_updateContainerForSelect: function _formHelperUpdateContainerForSelect(aLastElement, aCurrentElement) {
|
||||
let lastHasChoices = aLastElement && (aLastElement.choices != null);
|
||||
|
@ -1146,16 +994,10 @@ var FormHelperUI = {
|
|||
// the scrollX/scrollY position can change because of the animated zoom so
|
||||
// delay the caret adjustment
|
||||
if (AnimatedZoom.isZooming()) {
|
||||
let currentElement = this._currentElement;
|
||||
let self = this;
|
||||
window.addEventListener("AnimatedZoomEnd", function() {
|
||||
window.removeEventListener("AnimatedZoomEnd", arguments.callee, true);
|
||||
// Ensure the current element has not changed during this interval
|
||||
if (self._currentElement != currentElement)
|
||||
return;
|
||||
|
||||
self._ensureCaretVisible(aCaretRect);
|
||||
}, true);
|
||||
this._waitForZoom(function() {
|
||||
self._ensureCaretVisible(aCaretRect);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1200,6 +1042,19 @@ var FormHelperUI = {
|
|||
Browser.pageScrollboxScroller.scrollTo(restore.pageScrollOffset.x, restore.pageScrollOffset.y);
|
||||
},
|
||||
|
||||
_waitForZoom: function _formHelperWaitForZoom(aCallback) {
|
||||
let currentElement = this._currentElement;
|
||||
let self = this;
|
||||
window.addEventListener("AnimatedZoomEnd", function() {
|
||||
window.removeEventListener("AnimatedZoomEnd", arguments.callee, true);
|
||||
// Ensure the current element has not changed during this interval
|
||||
if (self._currentElement != currentElement)
|
||||
return;
|
||||
|
||||
aCallback();
|
||||
}, true);
|
||||
},
|
||||
|
||||
_getZoomLevelForRect: function _getZoomLevelForRect(aRect) {
|
||||
const margin = 30;
|
||||
let zoomLevel = getBrowser().getBoundingClientRect().width / (aRect.width + margin);
|
||||
|
|
|
@ -578,7 +578,7 @@ FormAssistant.prototype = {
|
|||
},
|
||||
|
||||
_isVisibleElement: function formHelperIsVisibleElement(aElement) {
|
||||
let style = aElement.ownerDocument.defaultView.getComputedStyle(aElement, null);
|
||||
let style = aElement ? aElement.ownerDocument.defaultView.getComputedStyle(aElement, null) : null;
|
||||
if (!style)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ chrome.jar:
|
|||
content/AwesomePanel.js (content/AwesomePanel.js)
|
||||
content/BookmarkHelper.js (content/BookmarkHelper.js)
|
||||
content/BookmarkPopup.js (content/BookmarkPopup.js)
|
||||
content/ContentPopupHelper.js (content/ContentPopupHelper.js)
|
||||
* content/ContextCommands.js (content/ContextCommands.js)
|
||||
content/IndexedDB.js (content/IndexedDB.js)
|
||||
content/MenuListHelperUI.js (content/MenuListHelperUI.js)
|
||||
|
|
|
@ -49,6 +49,7 @@ include $(topsrcdir)/config/rules.mk
|
|||
_BROWSER_FILES = \
|
||||
head.js \
|
||||
remote_autocomplete.js \
|
||||
remote_contentpopup.js \
|
||||
remote_head.js \
|
||||
remote_forms.js \
|
||||
remote_formsZoom.js \
|
||||
|
@ -67,6 +68,8 @@ _BROWSER_FILES = \
|
|||
browser_click_content.html \
|
||||
browser_click_content.js \
|
||||
browser_contacts.js \
|
||||
browser_contentpopup.html \
|
||||
browser_contentpopup.js \
|
||||
browser_dragger.js \
|
||||
browser_find.js \
|
||||
browser_forms.html \
|
||||
|
|
|
@ -21,6 +21,14 @@
|
|||
</datalist>
|
||||
<input id="input-datalist-2" list="datalist-2"></input>
|
||||
|
||||
<br /><br />
|
||||
|
||||
<datalist id="datalist-3">
|
||||
<option>foo</option>
|
||||
</datalist>
|
||||
<input id="input-datalist-3" list="datalist-3"></input>
|
||||
|
||||
<br /><br />
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
|
@ -20,7 +20,14 @@ function test() {
|
|||
}
|
||||
});
|
||||
|
||||
newTab = Browser.addTab(testURL, true);
|
||||
let startupInfo = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup).getStartupInfo();
|
||||
if (!("firstPaint" in startupInfo))
|
||||
waitFor(function() { newTab = Browser.addTab(testURL, true); }, function() {
|
||||
let startupInfo = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup).getStartupInfo();
|
||||
return ("firstPaint" in startupInfo);
|
||||
}, Date.now() + 3000);
|
||||
else
|
||||
newTab = Browser.addTab(testURL, true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -36,6 +43,9 @@ function runNextTest() {
|
|||
// Cleanup. All tests are completed at this point
|
||||
try {
|
||||
// Add any cleanup code here
|
||||
|
||||
// Close our tab when finished
|
||||
Browser.closeTab(newTab);
|
||||
}
|
||||
finally {
|
||||
// We must finialize the tests
|
||||
|
@ -130,11 +140,43 @@ gTests.push({
|
|||
// Close the form assistant
|
||||
FormHelperUI.hide();
|
||||
|
||||
// Close our tab when finished
|
||||
Browser.closeTab(newTab);
|
||||
|
||||
// We must finalize the tests
|
||||
finish();
|
||||
AsyncTests.waitFor("TestRemoteAutocomplete:Reset", { id: "input-datalist-1" }, function(json) {
|
||||
runNextTest();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Case: Check arrows visibility
|
||||
gTests.push({
|
||||
desc: "Check arrows visibility",
|
||||
|
||||
run: function() {
|
||||
let popup = document.getElementById("form-helper-suggestions-container");
|
||||
popup.addEventListener("contentpopupshown", function(aEvent) {
|
||||
aEvent.target.removeEventListener(aEvent.type, arguments.callee, false);
|
||||
waitFor(gCurrentTest.checkNoArrows, function() {
|
||||
return FormHelperUI._open;
|
||||
});
|
||||
}, false);
|
||||
|
||||
AsyncTests.waitFor("TestRemoteAutocomplete:Click",
|
||||
{ id: "input-datalist-3" }, function(json) {});
|
||||
},
|
||||
|
||||
checkNoArrows: function() {
|
||||
let scrollbox = document.getElementById("form-helper-suggestions");
|
||||
todo_is(scrollbox._scrollButtonUp.collapsed, true, "Left button should be collapsed");
|
||||
todo_is(scrollbox._scrollButtonDown.collapsed, true, "Right button should be collapsed");
|
||||
gCurrentTest.finish();
|
||||
},
|
||||
|
||||
finish: function() {
|
||||
// Close the form assistant
|
||||
FormHelperUI.hide();
|
||||
|
||||
runNextTest();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<html>
|
||||
<body>
|
||||
<datalist id="datalist-1">
|
||||
<option>foo</option>
|
||||
<option disabled="true">bar</option>
|
||||
<option value="bar">Somewhat bar</option>
|
||||
<option label="foobar" value="_"></option>
|
||||
</datalist>
|
||||
<input id="input-datalist-1" list="datalist-1"></input>
|
||||
|
||||
<br /><br />
|
||||
|
||||
<datalist id="datalist-2">
|
||||
<option>foo</option>
|
||||
<option>bar</option>
|
||||
<option>foobar</option>
|
||||
<option>foobar foo</option>
|
||||
<option>foobar foo titi</option>
|
||||
<option>foobar foo titi toto</option>
|
||||
<option>foobar foo titi toto tutu</option>
|
||||
</datalist>
|
||||
<input id="input-datalist-2" list="datalist-2"></input>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
let testURL = chromeRoot + "browser_contentpopup.html";
|
||||
messageManager.loadFrameScript(chromeRoot + "remote_contentpopup.js", true);
|
||||
|
||||
let newTab = null;
|
||||
|
||||
// A queue to order the tests and a handle for each test
|
||||
var gTests = [];
|
||||
var gCurrentTest = null;
|
||||
|
||||
function test() {
|
||||
// This test is async
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Need to wait until the page is loaded
|
||||
messageManager.addMessageListener("pageshow", function(aMessage) {
|
||||
if (newTab && newTab.browser.currentURI.spec != "about:blank") {
|
||||
messageManager.removeMessageListener(aMessage.name, arguments.callee);
|
||||
BrowserUI.closeAutoComplete(true);
|
||||
setTimeout(runNextTest, 0);
|
||||
}
|
||||
});
|
||||
|
||||
let startupInfo = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup).getStartupInfo();
|
||||
if (!("firstPaint" in startupInfo))
|
||||
waitFor(function() { newTab = Browser.addTab(testURL, true); }, function() {
|
||||
let startupInfo = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup).getStartupInfo();
|
||||
return ("firstPaint" in startupInfo);
|
||||
}, Date.now() + 3000);
|
||||
else
|
||||
newTab = Browser.addTab(testURL, true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Iterating tests by shifting test out one by one as runNextTest is called.
|
||||
function runNextTest() {
|
||||
// Run the next test until all tests completed
|
||||
if (gTests.length > 0) {
|
||||
gCurrentTest = gTests.shift();
|
||||
info(gCurrentTest.desc);
|
||||
gCurrentTest.run();
|
||||
}
|
||||
else {
|
||||
// Cleanup. All tests are completed at this point
|
||||
try {
|
||||
// Add any cleanup code here
|
||||
|
||||
// Close our tab when finished
|
||||
Browser.closeTab(newTab);
|
||||
}
|
||||
finally {
|
||||
// We must finialize the tests
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Case: Show/Hide the content popup helper
|
||||
gTests.push({
|
||||
desc: "Show/Hide the content popup helper",
|
||||
|
||||
run: function() {
|
||||
let popup = document.getElementById("form-helper-suggestions-container");
|
||||
popup.addEventListener("contentpopupshown", function(aEvent) {
|
||||
aEvent.target.removeEventListener(aEvent.type, arguments.callee, false);
|
||||
ok(!popup.hidden, "Content popup should be visible");
|
||||
waitFor(gCurrentTest.hidePopup, function() {
|
||||
return FormHelperUI._open;
|
||||
});
|
||||
}, false);
|
||||
|
||||
AsyncTests.waitFor("TestRemoteAutocomplete:Click",
|
||||
{ id: "input-datalist-1" }, function(json) {});
|
||||
},
|
||||
|
||||
hidePopup: function() {
|
||||
let popup = document.getElementById("form-helper-suggestions-container");
|
||||
popup.addEventListener("contentpopuphidden", function(aEvent) {
|
||||
popup.removeEventListener("contentpopuphidden", arguments.callee, false);
|
||||
ok(popup.hidden, "Content popup should be hidden");
|
||||
waitFor(gCurrentTest.finish, function() {
|
||||
return !FormHelperUI._open;
|
||||
});
|
||||
}, false);
|
||||
|
||||
// Close the form assistant
|
||||
FormHelperUI.hide();
|
||||
},
|
||||
|
||||
finish: function() {
|
||||
runNextTest();
|
||||
}
|
||||
});
|
||||
|
|
@ -16,3 +16,10 @@ AsyncTests.add("TestRemoteAutocomplete:Check", function(aMessage, aJson) {
|
|||
return element.value;
|
||||
});
|
||||
|
||||
AsyncTests.add("TestRemoteAutocomplete:Reset", function(aMessage, aJson) {
|
||||
gFocusManager.focusedElement = null;
|
||||
let element = content.document.getElementById(aJson.id);
|
||||
element.value = "";
|
||||
return true;
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
dump("====================== Content Script Loaded =======================\n");
|
||||
|
||||
let assistant = Content._formAssistant;
|
||||
|
||||
AsyncTests.add("TestRemoteAutocomplete:Click", function(aMessage, aJson) {
|
||||
let element = content.document.getElementById(aJson.id);
|
||||
assistant.open(element);
|
||||
assistant._executeDelayed(function(assistant) {
|
||||
sendAsyncMessage("FormAssist:AutoComplete", assistant._getJSON());
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
||||
AsyncTests.add("TestRemoteAutocomplete:Check", function(aMessage, aJson) {
|
||||
let element = content.document.getElementById(aJson.id);
|
||||
return element.value;
|
||||
});
|
||||
|
Загрузка…
Ссылка в новой задаче