Merge mozilla-central into mozilla-inbound

This commit is contained in:
Ehsan Akhgari 2011-06-24 21:17:16 -04:00
Родитель de40daaf73 2a63e793d7
Коммит 969491edef
55 изменённых файлов: 1666 добавлений и 330 удалений

Просмотреть файл

@ -999,9 +999,11 @@ pref("services.sync.prefs.sync.spellchecker.dictionary", true);
pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
#endif
// Disable the error console and inspector
// Disable the error console
pref("devtools.errorconsole.enabled", false);
pref("devtools.inspector.enabled", false);
// Enable the Inspector
pref("devtools.inspector.enabled", true);
// Enable the Scratchpad tool.
pref("devtools.scratchpad.enabled", true);
@ -1027,6 +1029,12 @@ pref("devtools.hud.loglimit.cssparser", 200);
pref("devtools.hud.loglimit.exception", 200);
pref("devtools.hud.loglimit.console", 200);
// The developer tools editor configuration:
// - tabsize: how many spaces to use when a Tab character is displayed.
// - expandtab: expand Tab characters to spaces.
pref("devtools.editor.tabsize", 4);
pref("devtools.editor.expandtab", true);
// Whether the character encoding menu is under the main Firefox button. This
// preference is a string so that localizers can alter it.
pref("browser.menu.showCharacterEncoding", "chrome://browser/locale/browser.properties");

Просмотреть файл

@ -242,7 +242,7 @@
<key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" oncommand="toJavaScriptConsole();" modifiers="accel,shift" disabled="true"/>
<key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();" modifiers="accel,shift"/>
<key id="key_inspect" key="&inspectMenu.commandkey;" command="Tools:Inspect" modifiers="accel,shift"/>
<key id="key_scratchpad" keycode="&scratchpad.keycode;"
<key id="key_scratchpad" keycode="&scratchpad.keycode;" modifiers="shift"
keytext="&scratchpad.keytext;" command="Tools:Scratchpad"/>
<key id="openFileKb" key="&openFileCmd.commandkey;" command="Browser:OpenFile" modifiers="accel"/>
<key id="key_savePage" key="&savePageCmd.commandkey;" command="Browser:SavePage" modifiers="accel"/>

Просмотреть файл

@ -224,15 +224,6 @@
</hbox>
</panel>
<panel id="highlighter-panel"
hidden="true"
ignorekeys="true"
noautofocus="true"
noautohide="true"
onclick="InspectorUI.stopInspecting();"
onmousemove="InspectorUI.highlighter.handleMouseMove(event);"
onMozMousePixelScroll="InspectorUI.highlighter.handlePixelScroll(event);"/>
<panel id="inspector-tree-panel"
orient="vertical"
hidden="true"
@ -1033,6 +1024,12 @@
#endif
</vbox>
# <iframe id="highlighter-frame"
# transparent="true"
# type="content"
# src="chrome://content/base/highlighter.html"/> is dynamically appended as
# the last child of #tab-view-deck, only when it is needed, for minimal
# performance impact.
# <iframe id="tab-view"> is dynamically appended as the 2nd child of #tab-view-deck.
# Introducing the iframe dynamically, as needed, was found to be better than
# starting with an empty iframe here in browser.xul from a Ts standpoint.

Просмотреть файл

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<!-- ***** 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 Inspector Highlighter code.
-
- The Initial Developer of the Original Code is The Mozilla Foundation.
- Portions created by the Initial Developer are Copyright (C) 2011
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Rob Campbell <rcampbell@mozilla.com> (Original Author)
- Paul Rouget <paul@mozilla.com>
-
- 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 LGPL or the GPL. 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 ***** -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" href="chrome://browser/skin/highlighter.css" type="text/css"/>
</head>
<body>
<div id="close-button" role="button" class="clickable"/>
<!--
To darken the page around the selected node, we use black-transparent
divs, organized in 3 rows, keeping the div in the middle transparent.
-->
<div id="veil-container">
<div id="veil">
<div id="veil-topbox" class="veil"/>
<div id="veil-middlebox">
<div id="veil-leftbox" class="veil"/>
<div id="veil-transparentbox"/>
<div id="veil-rightbox" class="veil"/>
</div>
<div id="veil-bottombox" class="veil"/>
</div>
</div>
</body>
</html>

Просмотреть файл

@ -192,12 +192,19 @@ InsideOutBox.prototype =
* Force the object box open by expanding all elements in the tree?
* @param scrollIntoView
* Scroll the objectBox into view?
* @returns objectBox
* @returns nsIDOMNode|null
* A DOM node that represents the "object box", the element that
* holds/displays the given aObject representation in the tree. If
* the object cannot be selected, if it is a stale object, null is
* returned.
*/
select:
function IOBox_select(aObject, makeBoxVisible, forceOpen, scrollIntoView)
{
let objectBox = this.createObjectBox(aObject);
if (!objectBox) {
return null;
}
this.selectObjectBox(objectBox, forceOpen);
if (makeBoxVisible) {
this.openObjectBox(objectBox);

Просмотреть файл

@ -25,6 +25,7 @@
* Rob Campbell <rcampbell@mozilla.com> (original author)
* Mihai Șucan <mihai.sucan@gmail.com>
* Julian Viereck <jviereck@mozilla.com>
* Paul Rouget <paul@mozilla.com>
*
* 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
@ -55,152 +56,256 @@ const INSPECTOR_INVISIBLE_ELEMENTS = {
"title": true,
};
// Inspector notifications dispatched through the nsIObserverService.
const INSPECTOR_NOTIFICATIONS = {
// Fires once the Inspector highlighter is initialized and ready for use.
HIGHLIGHTER_READY: "highlighter-ready",
// Fires once the Inspector highlights an element in the page.
HIGHLIGHTING: "inspector-highlighting",
// Fires once the Inspector stops highlighting any element.
UNHIGHLIGHTING: "inspector-unhighlighting",
// Fires once the Inspector completes the initialization and opens up on
// screen.
OPENED: "inspector-opened",
// Fires once the Inspector is closed.
CLOSED: "inspector-closed",
};
///////////////////////////////////////////////////////////////////////////
//// PanelHighlighter
//// IFrameHighlighter
/**
* A highlighter mechanism using xul panels.
* A highlighter mechanism using a transparent xul iframe.
*
* @param aBrowser
* The XUL browser object for the content window being highlighted.
* @param nsIDOMNode aBrowser
* The xul:browser object for the content window being highlighted.
*/
function PanelHighlighter(aBrowser)
function IFrameHighlighter(aBrowser)
{
this.panel = document.getElementById("highlighter-panel");
this.panel.hidden = false;
this.browser = aBrowser;
this.win = this.browser.contentWindow;
this._init(aBrowser);
}
PanelHighlighter.prototype = {
IFrameHighlighter.prototype = {
_init: function IFH__init(aBrowser)
{
this.browser = aBrowser;
let stack = this.browser.parentNode;
this.win = this.browser.contentWindow;
this._highlighting = false;
let div = document.createElement("div");
div.flex = 1;
div.setAttribute("style", "pointer-events: none; -moz-user-focus: ignore");
let iframe = document.createElement("iframe");
iframe.setAttribute("id", "highlighter-frame");
iframe.setAttribute("transparent", "true");
iframe.setAttribute("type", "content");
iframe.addEventListener("DOMTitleChanged", function(aEvent) {
aEvent.stopPropagation();
}, true);
iframe.flex = 1;
iframe.setAttribute("style", "-moz-user-focus: ignore");
this.listenOnce(iframe, "load", (function iframeLoaded() {
this.iframeDoc = iframe.contentDocument;
this.veilTopDiv = this.iframeDoc.getElementById("veil-topbox");
this.veilLeftDiv = this.iframeDoc.getElementById("veil-leftbox");
this.veilMiddleDiv = this.iframeDoc.getElementById("veil-middlebox");
this.veilTransparentDiv = this.iframeDoc.getElementById("veil-transparentbox");
let closeButton = this.iframeDoc.getElementById("close-button");
this.listenOnce(closeButton, "click",
InspectorUI.closeInspectorUI.bind(InspectorUI, false), false);
this.browser.addEventListener("click", this, true);
iframe.contentWindow.addEventListener("resize", this, false);
this.handleResize();
Services.obs.notifyObservers(null,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTER_READY, null);
}).bind(this), true);
iframe.setAttribute("src", "chrome://browser/content/highlighter.xhtml");
div.appendChild(iframe);
stack.appendChild(div);
this.iframe = iframe;
this.iframeContainer = div;
},
/**
* Destroy the iframe and its nodes.
*/
destroy: function IFH_destroy()
{
this.browser.removeEventListener("click", this, true);
this._highlightRect = null;
this._highlighting = false;
this.veilTopDiv = null;
this.veilLeftDiv = null;
this.veilMiddleDiv = null;
this.veilTransparentDiv = null;
this.node = null;
this.iframeDoc = null;
this.browser.parentNode.removeChild(this.iframeContainer);
this.iframeContainer = null;
this.iframe = null;
this.win = null
this.browser = null;
},
/**
* Is the highlighter highlighting? Public method for querying the state
* of the highlighter.
*/
get isHighlighting() {
return this._highlighting;
},
/**
* Highlight this.node, unhilighting first if necessary.
*
* @param scroll
* @param boolean aScroll
* Boolean determining whether to scroll or not.
*/
highlight: function PanelHighlighter_highlight(scroll)
highlight: function IFH_highlight(aScroll)
{
// node is not set or node is not highlightable, bail
if (!this.isNodeHighlightable()) {
if (!this.node || !this.isNodeHighlightable()) {
return;
}
this.unhighlight();
let clientRect = this.node.getBoundingClientRect();
let rect = this.node.getBoundingClientRect();
// clientRect is read-only, we need to be able to change properties.
let rect = {top: clientRect.top,
left: clientRect.left,
width: clientRect.width,
height: clientRect.height};
let oldRect = this._highlightRect;
if (scroll) {
if (oldRect && rect.top == oldRect.top && rect.left == oldRect.left &&
rect.width == oldRect.width && rect.height == oldRect.height) {
return; // same rectangle
}
if (aScroll) {
this.node.scrollIntoView();
}
if (this.viewContainsRect(rect)) {
// TODO check for offscreen boundaries, bug565301
this.panel.openPopup(this.node, "overlap", 0, 0, false, false);
this.panel.sizeTo(rect.width, rect.height);
} else {
this.highlightVisibleRegion(rect);
// Go up in the tree of frames to determine the correct rectangle
// coordinates and size.
let frameWin = this.node.ownerDocument.defaultView;
do {
let frameRect = frameWin.frameElement ?
frameWin.frameElement.getBoundingClientRect() :
{top: 0, left: 0};
if (rect.top < 0) {
rect.height += rect.top;
rect.top = 0;
}
if (rect.left < 0) {
rect.width += rect.left;
rect.left = 0;
}
let diffx = frameWin.innerWidth - rect.left - rect.width;
if (diffx < 0) {
rect.width += diffx;
}
let diffy = frameWin.innerHeight - rect.top - rect.height;
if (diffy < 0) {
rect.height += diffy;
}
rect.left += frameRect.left;
rect.top += frameRect.top;
frameWin = frameWin.parent;
} while (frameWin != this.win);
this.highlightRectangle(rect);
if (this._highlighting) {
Services.obs.notifyObservers(null,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, null);
}
},
/**
* Highlight the given node.
*
* @param aNode
* @param nsIDOMNode aNode
* a DOM element to be highlighted
* @param aParams
* @param object aParams
* extra parameters object
*/
highlightNode: function PanelHighlighter_highlightNode(aNode, aParams)
highlightNode: function IFH_highlightNode(aNode, aParams)
{
this.node = aNode;
this.highlight(aParams && aParams.scroll);
},
/**
* Highlight the visible region of the region described by aRect, if any.
* Highlight a rectangular region.
*
* @param aRect
* @param object aRect
* The rectangle region to highlight.
* @returns boolean
* was a region highlighted?
* True if the rectangle was highlighted, false otherwise.
*/
highlightVisibleRegion: function PanelHighlighter_highlightVisibleRegion(aRect)
highlightRectangle: function IFH_highlightRectangle(aRect)
{
let offsetX = 0;
let offsetY = 0;
let width = 0;
let height = 0;
let visibleWidth = this.win.innerWidth;
let visibleHeight = this.win.innerHeight;
if (aRect.left >= 0 && aRect.top >= 0 &&
aRect.width > 0 && aRect.height > 0) {
// The bottom div and the right div are flexibles (flex=1).
// We don't need to resize them.
this.veilTopDiv.style.height = aRect.top + "px";
this.veilLeftDiv.style.width = aRect.left + "px";
this.veilMiddleDiv.style.height = aRect.height + "px";
this.veilTransparentDiv.style.width = aRect.width + "px";
// If any of these edges are out-of-bounds, the node's rectangle is
// completely out-of-view and we can return.
if (aRect.top > visibleHeight || aRect.left > visibleWidth ||
aRect.bottom < 0 || aRect.right < 0) {
return false;
this._highlighting = true;
} else {
this.unhighlight();
}
// Calculate node offsets, if values are negative, then start the offsets
// at their absolute values from node origin. The delta should be the edge
// of view.
offsetX = aRect.left < 0 ? Math.abs(aRect.left) : 0;
offsetY = aRect.top < 0 ? Math.abs(aRect.top) : 0;
this._highlightRect = aRect;
// Calculate actual node width, taking into account the available visible
// width and then subtracting the offset for the final dimension.
width = aRect.right > visibleWidth ? visibleWidth - aRect.left :
aRect.width;
width -= offsetX;
// Calculate actual node height using the same formula as above for width.
height = aRect.bottom > visibleHeight ? visibleHeight - aRect.top :
aRect.height;
height -= offsetY;
// If width and height are non-negative, open the highlighter popup over the
// node and sizeTo width and height.
if (width > 0 && height > 0) {
this.panel.openPopup(this.node, "overlap", offsetX, offsetY, false,
false);
this.panel.sizeTo(width, height);
return true;
}
return false;
return this._highlighting;
},
/**
* Close the highlighter panel.
* Clear the highlighter surface.
*/
unhighlight: function PanelHighlighter_unhighlight()
unhighlight: function IFH_unhighlight()
{
if (this.isHighlighting) {
this.panel.hidePopup();
}
},
/**
* Is the highlighter panel open?
*
* @returns boolean
*/
get isHighlighting()
{
return this.panel.state == "open";
this._highlighting = false;
this.veilMiddleDiv.style.height = 0;
this.veilTransparentDiv.style.width = 0;
Services.obs.notifyObservers(null,
INSPECTOR_NOTIFICATIONS.UNHIGHLIGHTING, null);
},
/**
* Return the midpoint of a line from pointA to pointB.
*
* @param aPointA
* @param object aPointA
* An object with x and y properties.
* @param aPointB
* @param object aPointB
* An object with x and y properties.
* @returns aPoint
* @returns object
* An object with x and y properties.
*/
midPoint: function PanelHighlighter_midPoint(aPointA, aPointB)
midPoint: function IFH_midPoint(aPointA, aPointB)
{
let pointC = { };
pointC.x = (aPointB.x - aPointA.x) / 2 + aPointA.x;
@ -213,28 +318,25 @@ PanelHighlighter.prototype = {
* Calculation based on midpoint of diagonal from top left to bottom right
* of panel.
*
* @returns a DOM node or null if none
* @returns nsIDOMNode|null
* Returns the node under the current highlighter rectangle. Null is
* returned if there is no node highlighted.
*/
get highlitNode()
{
// No highlighter panel? Bail.
if (!this.isHighlighting) {
// Not highlighting? Bail.
if (!this._highlighting || !this._highlightRect) {
return null;
}
let browserRect = this.browser.getBoundingClientRect();
let clientRect = this.panel.getBoundingClientRect();
// Calculate top left point offset minus browser chrome.
let a = {
x: clientRect.left - browserRect.left,
y: clientRect.top - browserRect.top
x: this._highlightRect.left,
y: this._highlightRect.top
};
// Calculate bottom right point minus browser chrome.
let b = {
x: clientRect.right - browserRect.left,
y: clientRect.bottom - browserRect.top
x: a.x + this._highlightRect.width,
y: a.y + this._highlightRect.height
};
// Get midpoint of diagonal line.
@ -248,80 +350,195 @@ PanelHighlighter.prototype = {
* Is this.node highlightable?
*
* @returns boolean
* True if the node is highlightable or false otherwise.
*/
isNodeHighlightable: function PanelHighlighter_isNodeHighlightable()
isNodeHighlightable: function IFH_isNodeHighlightable()
{
if (!this.node) {
if (!this.node || this.node.nodeType != Node.ELEMENT_NODE) {
return false;
}
let nodeName = this.node.nodeName.toLowerCase();
if (nodeName[0] == '#') {
return false;
}
return !INSPECTOR_INVISIBLE_ELEMENTS[nodeName];
},
/**
* Returns true if the given viewport-relative rect is within the visible area
* of the window.
*
* @param aRect
* a CSS rectangle object
* @returns boolean
*/
viewContainsRect: function PanelHighlighter_viewContainsRect(aRect)
{
let visibleWidth = this.win.innerWidth;
let visibleHeight = this.win.innerHeight;
return ((0 <= aRect.left) && (aRect.right <= visibleWidth) &&
(0 <= aRect.top) && (aRect.bottom <= visibleHeight))
},
/////////////////////////////////////////////////////////////////////////
//// Event Handling
attachInspectListeners: function IFH_attachInspectListeners()
{
this.browser.addEventListener("mousemove", this, true);
this.browser.addEventListener("dblclick", this, true);
this.browser.addEventListener("mousedown", this, true);
this.browser.addEventListener("mouseup", this, true);
},
detachInspectListeners: function IFH_detachInspectListeners()
{
this.browser.removeEventListener("mousemove", this, true);
this.browser.removeEventListener("dblclick", this, true);
this.browser.removeEventListener("mousedown", this, true);
this.browser.removeEventListener("mouseup", this, true);
},
/**
* Generic event handler.
*
* @param nsIDOMEvent aEvent
* The DOM event object.
*/
handleEvent: function IFH_handleEvent(aEvent)
{
switch (aEvent.type) {
case "click":
this.handleClick(aEvent);
break;
case "mousemove":
this.handleMouseMove(aEvent);
break;
case "resize":
this.handleResize(aEvent);
break;
case "dblclick":
case "mousedown":
case "mouseup":
aEvent.stopPropagation();
aEvent.preventDefault();
break;
}
},
/**
* Handle clicks on the iframe.
*
* @param nsIDOMEvent aEvent
* The DOM event.
*/
handleClick: function IFH_handleClick(aEvent)
{
// Proxy the click event to the iframe.
let x = aEvent.clientX;
let y = aEvent.clientY;
let frameWin = aEvent.view;
while (frameWin != this.win) {
if (frameWin.frameElement) {
let frameRect = frameWin.frameElement.getBoundingClientRect();
x += frameRect.left;
y += frameRect.top;
}
frameWin = frameWin.parent;
}
let element = this.iframeDoc.elementFromPoint(x, y);
if (element && element.classList &&
element.classList.contains("clickable")) {
let newEvent = this.iframeDoc.createEvent("MouseEvents");
newEvent.initMouseEvent(aEvent.type, aEvent.bubbles, aEvent.cancelable,
this.iframeDoc.defaultView, aEvent.detail, aEvent.screenX,
aEvent.screenY, x, y, aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey,
aEvent.metaKey, aEvent.button, null);
element.dispatchEvent(newEvent);
aEvent.preventDefault();
aEvent.stopPropagation();
return;
}
// Stop inspection when the user clicks on a node.
if (InspectorUI.inspecting) {
if (aEvent.button == 0) {
let win = aEvent.target.ownerDocument.defaultView;
InspectorUI.stopInspecting();
win.focus();
}
aEvent.preventDefault();
aEvent.stopPropagation();
}
},
/**
* Handle mousemoves in panel when InspectorUI.inspecting is true.
*
* @param aEvent
* @param nsiDOMEvent aEvent
* The MouseEvent triggering the method.
*/
handleMouseMove: function PanelHighlighter_handleMouseMove(aEvent)
handleMouseMove: function IFH_handleMouseMove(aEvent)
{
if (!InspectorUI.inspecting) {
return;
}
let browserRect = this.browser.getBoundingClientRect();
let element = InspectorUI.elementFromPoint(this.win.document,
aEvent.clientX - browserRect.left, aEvent.clientY - browserRect.top);
let element = InspectorUI.elementFromPoint(aEvent.target.ownerDocument,
aEvent.clientX, aEvent.clientY);
if (element && element != this.node) {
InspectorUI.inspectNode(element);
}
},
/**
* Handle MozMousePixelScroll in panel when InspectorUI.inspecting is true.
* Handle window resize events.
*/
handleResize: function IFH_handleResize()
{
let style = this.iframeContainer.style;
if (this.win.scrollMaxY && this.win.scrollbars.visible) {
style.paddingRight = this.getScrollbarWidth() + "px";
} else {
style.paddingRight = 0;
}
if (this.win.scrollMaxX && this.win.scrollbars.visible) {
style.paddingBottom = this.getScrollbarWidth() + "px";
} else {
style.paddingBottom = 0;
}
this.highlight();
},
/**
* Determine the scrollbar width in the current document.
*
* @param aEvent
* The onMozMousePixelScrollEvent triggering the method.
* @returns number
* The scrollbar width in pixels.
*/
getScrollbarWidth: function IFH_getScrollbarWidth()
{
if (this._scrollbarWidth) {
return this._scrollbarWidth;
}
let hbox = document.createElement("hbox");
hbox.setAttribute("style", "height: 0%; overflow: hidden");
let scrollbar = document.createElement("scrollbar");
scrollbar.setAttribute("orient", "vertical");
hbox.appendChild(scrollbar);
document.documentElement.appendChild(hbox);
this._scrollbarWidth = scrollbar.clientWidth;
document.documentElement.removeChild(hbox);
return this._scrollbarWidth;
},
/**
* Helper to listen for an event only once.
*
* @param nsIDOMEventTarget aTarget
* The DOM event target you want to add an event listener to.
* @param string aName
* The event name you want to listen for.
* @param function aCallback
* The function you want to execute once for the given event.
* @param boolean aCapturing
* Tells if you want to use capture for the event listener.
* @returns void
*/
handlePixelScroll: function PanelHighlighter_handlePixelScroll(aEvent) {
if (!InspectorUI.inspecting) {
return;
}
let browserRect = this.browser.getBoundingClientRect();
let element = InspectorUI.elementFromPoint(this.win.document,
aEvent.clientX - browserRect.left, aEvent.clientY - browserRect.top);
let win = element.ownerDocument.defaultView;
if (aEvent.axis == aEvent.HORIZONTAL_AXIS) {
win.scrollBy(aEvent.detail, 0);
} else {
win.scrollBy(0, aEvent.detail);
}
}
listenOnce: function IFH_listenOnce(aTarget, aName, aCallback, aCapturing)
{
aTarget.addEventListener(aName, function listenOnce_handler(aEvent) {
aTarget.removeEventListener(aName, listenOnce_handler, aCapturing);
aCallback.call(this, aEvent);
}, aCapturing);
},
};
///////////////////////////////////////////////////////////////////////////
@ -332,7 +549,6 @@ PanelHighlighter.prototype = {
*/
var InspectorUI = {
browser: null,
selectEventsSuppressed: false,
showTextNodesWithWhitespace: false,
inspecting: false,
treeLoaded: false,
@ -395,16 +611,8 @@ var InspectorUI = {
this.ioBox.createObjectBox(this.win.document.documentElement);
this.treeLoaded = true;
// setup highlighter and start inspecting
// initialize the highlighter
this.initializeHighlighter();
// Setup the InspectorStore or restore state
this.initializeStore();
if (InspectorStore.getValue(this.winID, "inspecting"))
this.startInspecting();
this.notifyReady();
},
/**
@ -584,11 +792,9 @@ var InspectorUI = {
this.domplateUtils.setDOM(window);
}
// open inspector UI
this.openTreePanel();
this.win.document.addEventListener("scroll", this, false);
this.win.addEventListener("resize", this, false);
this.browser.addEventListener("scroll", this, true);
this.inspectCmd.setAttribute("checked", true);
},
@ -597,7 +803,9 @@ var InspectorUI = {
*/
initializeHighlighter: function IUI_initializeHighlighter()
{
this.highlighter = new PanelHighlighter(this.browser);
Services.obs.addObserver(this.highlighterReady,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTER_READY, false);
this.highlighter = new IFrameHighlighter(this.browser);
},
/**
@ -658,11 +866,10 @@ var InspectorUI = {
gBrowser.tabContainer.removeEventListener("TabSelect", this, false);
}
this.win.document.removeEventListener("scroll", this, false);
this.win.removeEventListener("resize", this, false);
this.browser.removeEventListener("scroll", this, true);
this.stopInspecting();
if (this.highlighter) {
this.highlighter.unhighlight();
this.highlighter.destroy();
this.highlighter = null;
}
@ -693,7 +900,7 @@ var InspectorUI = {
this.treePanel.addEventListener("popuphidden", function treePanelHidden() {
InspectorUI.closing = false;
Services.obs.notifyObservers(null, "inspector-closed", null);
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.CLOSED, null);
}, false);
this.treePanel.hidePopup();
@ -716,12 +923,16 @@ var InspectorUI = {
*/
stopInspecting: function IUI_stopInspecting()
{
if (!this.inspecting)
if (!this.inspecting) {
return;
}
this.detachPageListeners();
this.inspecting = false;
if (this.highlighter.node) {
this.select(this.highlighter.node, true, true);
} else {
this.select(null, true, true);
}
},
@ -741,11 +952,10 @@ var InspectorUI = {
if (forceUpdate || aNode != this.selection) {
this.selection = aNode;
let box = this.ioBox.createObjectBox(this.selection);
if (!this.inspecting) {
this.highlighter.highlightNode(this.selection);
}
this.ioBox.select(aNode, true, true, aScroll);
this.ioBox.select(this.selection, true, true, aScroll);
}
},
@ -754,7 +964,22 @@ var InspectorUI = {
notifyReady: function IUI_notifyReady()
{
Services.obs.notifyObservers(null, "inspector-opened", null);
// Setup the InspectorStore or restore state
this.initializeStore();
if (InspectorStore.getValue(this.winID, "inspecting")) {
this.startInspecting();
}
this.win.focus();
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.OPENED, null);
},
highlighterReady: function IUI_highlighterReady()
{
Services.obs.removeObserver(InspectorUI.highlighterReady,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTER_READY, false);
InspectorUI.notifyReady();
},
/**
@ -781,9 +1006,10 @@ var InspectorUI = {
if (inspectorClosed && this.closing) {
Services.obs.addObserver(function reopenInspectorForTab() {
Services.obs.removeObserver(reopenInspectorForTab,
"inspector-closed", false);
INSPECTOR_NOTIFICATIONS.CLOSED, false);
InspectorUI.openInspectorUI();
}, "inspector-closed", false);
}, INSPECTOR_NOTIFICATIONS.CLOSED, false);
} else {
this.openInspectorUI();
}
@ -815,22 +1041,15 @@ var InspectorUI = {
switch (event.keyCode) {
case KeyEvent.DOM_VK_RETURN:
case KeyEvent.DOM_VK_ESCAPE:
this.stopInspecting();
if (this.inspecting) {
this.stopInspecting();
event.preventDefault();
event.stopPropagation();
}
break;
}
break;
case "mousemove":
let element = this.elementFromPoint(event.target.ownerDocument,
event.clientX, event.clientY);
if (element && element != this.node) {
this.inspectNode(element);
}
break;
case "click":
this.stopInspecting();
break;
case "scroll":
case "resize":
this.highlighter.highlight();
break;
}
@ -866,9 +1085,8 @@ var InspectorUI = {
*/
attachPageListeners: function IUI_attachPageListeners()
{
this.win.addEventListener("keypress", this, true);
this.browser.addEventListener("mousemove", this, true);
this.browser.addEventListener("click", this, true);
this.browser.addEventListener("keypress", this, true);
this.highlighter.attachInspectListeners();
},
/**
@ -877,9 +1095,8 @@ var InspectorUI = {
*/
detachPageListeners: function IUI_detachPageListeners()
{
this.win.removeEventListener("keypress", this, true);
this.browser.removeEventListener("mousemove", this, true);
this.browser.removeEventListener("click", this, true);
this.browser.removeEventListener("keypress", this, true);
this.highlighter.detachInspectListeners();
},
/////////////////////////////////////////////////////////////////////////
@ -894,10 +1111,8 @@ var InspectorUI = {
*/
inspectNode: function IUI_inspectNode(aNode)
{
this.highlighter.highlightNode(aNode);
this.selectEventsSuppressed = true;
this.select(aNode, true, true);
this.selectEventsSuppressed = false;
this.highlighter.highlightNode(aNode);
},
/**

Просмотреть файл

@ -64,6 +64,9 @@ const SCRATCHPAD_L10N = "chrome://browser/locale/scratchpad.properties";
const SCRATCHPAD_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
const DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled";
const PREF_TABSIZE = "devtools.editor.tabsize";
const PREF_EXPANDTAB = "devtools.editor.expandtab";
/**
* The scratchpad object handles the Scratchpad window functionality.
*/
@ -628,7 +631,53 @@ var Scratchpad = {
errorConsoleCommand.removeAttribute("disabled");
chromeContextCommand.removeAttribute("disabled");
}
let tabsize = Services.prefs.getIntPref(PREF_TABSIZE);
if (tabsize < 1) {
// tabsize is invalid, clear back to the default value.
Services.prefs.clearUserPref(PREF_TABSIZE);
tabsize = Services.prefs.getIntPref(PREF_TABSIZE);
}
let expandtab = Services.prefs.getBoolPref(PREF_EXPANDTAB);
this._tabCharacter = expandtab ? (new Array(tabsize + 1)).join(" ") : "\t";
this.textbox.style.MozTabSize = tabsize;
this.insertIntro();
// Make the Tab key work.
this.textbox.addEventListener("keypress", this.onKeypress.bind(this), false);
this.textbox.focus();
},
/**
* The textbox keypress event handler which allows users to indent code using
* the Tab key.
*
* @param nsIDOMEvent aEvent
*/
onKeypress: function SP_onKeypress(aEvent)
{
if (aEvent.keyCode == aEvent.DOM_VK_TAB) {
this.insertTextAtCaret(this._tabCharacter);
aEvent.preventDefault();
}
},
/**
* Insert text at the current caret location.
*
* @param string aText
*/
insertTextAtCaret: function SP_insertTextAtCaret(aText)
{
let firstPiece = this.textbox.value.substring(0, this.textbox.selectionStart);
let lastPiece = this.textbox.value.substring(this.textbox.selectionEnd);
this.textbox.value = firstPiece + aText + lastPiece;
let newCaretPosition = firstPiece.length + aText.length;
this.selectRange(newCaretPosition, newCaretPosition);
},
};

Просмотреть файл

@ -40,7 +40,10 @@ srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = browser/base/content/test
DIRS += tabview
DIRS += \
tabview \
inspector \
$(NULL)
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
@ -184,16 +187,6 @@ _BROWSER_FILES = \
browser_gestureSupport.js \
browser_getshortcutoruri.js \
browser_hide_removing.js \
browser_inspector_initialization.js \
browser_inspector_treeSelection.js \
browser_inspector_highlighter.js \
browser_inspector_iframeTest.js \
browser_inspector_scrolling.js \
browser_inspector_store.js \
browser_inspector_tab_switch.js \
browser_inspector_treePanel_output.js \
browser_inspector_treePanel_input.html \
browser_inspector_treePanel_result.html \
browser_scratchpad_initialization.js \
browser_scratchpad_contexts.js \
browser_scratchpad_tab_switch.js \
@ -202,6 +195,7 @@ _BROWSER_FILES = \
browser_scratchpad_files.js \
browser_scratchpad_ui.js \
browser_scratchpad_bug_646070_chrome_context_pref.js \
browser_scratchpad_bug_660560_tab.js \
browser_overflowScroll.js \
browser_locationBarExternalLoad.js \
browser_pageInfo.js \

Просмотреть файл

@ -0,0 +1,116 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Reference to the Scratchpad chrome window object.
let gScratchpadWindow;
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
ok(window.Scratchpad, "Scratchpad variable exists");
Services.prefs.setIntPref("devtools.editor.tabsize", 5);
gScratchpadWindow = Scratchpad.openScratchpad();
gScratchpadWindow.addEventListener("load", runTests, false);
}, true);
content.location = "data:text/html,Scratchpad test for the Tab key, bug 660560";
}
function runTests()
{
gScratchpadWindow.removeEventListener("load", arguments.callee, false);
let sp = gScratchpadWindow.Scratchpad;
ok(sp, "Scratchpad object exists in new window");
is(gScratchpadWindow.document.activeElement, sp.textbox.inputField,
"The textbox has focus");
is(sp.textbox.style.MozTabSize, 5, "-moz-tab-size is correct");
sp.textbox.value = "window.foo;";
sp.selectRange(1, 3);
EventUtils.synthesizeKey("VK_TAB", {}, gScratchpadWindow);
is(sp.textbox.value, "w dow.foo;",
"Tab key added 5 spaces");
is(sp.textbox.selectionStart, 6, "caret location is correct");
is(sp.textbox.selectionStart, sp.textbox.selectionEnd,
"caret location is correct, confirmed");
// Test the new insertTextAtCaret() method.
sp.insertTextAtCaret("omg");
is(sp.textbox.value, "w omgdow.foo;", "insertTextAtCaret() works");
is(sp.textbox.selectionStart, 9, "caret location is correct after update");
is(sp.textbox.selectionStart, sp.textbox.selectionEnd,
"caret location is correct, confirmed");
gScratchpadWindow.close();
Services.prefs.setIntPref("devtools.editor.tabsize", 6);
Services.prefs.setBoolPref("devtools.editor.expandtab", false);
gScratchpadWindow = Scratchpad.openScratchpad();
gScratchpadWindow.addEventListener("load", runTests2, false);
}
function runTests2()
{
gScratchpadWindow.removeEventListener("load", arguments.callee, false);
let sp = gScratchpadWindow.Scratchpad;
is(sp.textbox.style.MozTabSize, 6, "-moz-tab-size is correct");
sp.textbox.value = "window.foo;";
sp.selectRange(1, 3);
EventUtils.synthesizeKey("VK_TAB", {}, gScratchpadWindow);
is(sp.textbox.value, "w\tdow.foo;", "Tab key added the tab character");
is(sp.textbox.selectionStart, 2, "caret location is correct");
is(sp.textbox.selectionStart, sp.textbox.selectionEnd,
"caret location is correct, confirmed");
gScratchpadWindow.close();
// check with an invalid tabsize value.
Services.prefs.setIntPref("devtools.editor.tabsize", 0);
Services.prefs.setBoolPref("devtools.editor.expandtab", true);
gScratchpadWindow = Scratchpad.openScratchpad();
gScratchpadWindow.addEventListener("load", runTests3, false);
}
function runTests3()
{
gScratchpadWindow.removeEventListener("load", arguments.callee, false);
let sp = gScratchpadWindow.Scratchpad;
is(sp.textbox.style.MozTabSize, 4, "-moz-tab-size is correct");
Services.prefs.clearUserPref("devtools.editor.tabsize");
Services.prefs.clearUserPref("devtools.editor.expandtab");
gScratchpadWindow.close();
gScratchpadWindow = null;
gBrowser.removeCurrentTab();
finish();
}

Просмотреть файл

@ -0,0 +1,60 @@
# ***** 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) 2007
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either of 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 *****
DEPTH = ../../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = browser/base/content/test/inspector
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = \
browser_inspector_initialization.js \
browser_inspector_treeSelection.js \
browser_inspector_highlighter.js \
browser_inspector_iframeTest.js \
browser_inspector_scrolling.js \
browser_inspector_store.js \
browser_inspector_tab_switch.js \
browser_inspector_treePanel_output.js \
browser_inspector_treePanel_input.html \
browser_inspector_treePanel_result.html \
$(NULL)
libs:: $(_BROWSER_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

Просмотреть файл

@ -22,6 +22,7 @@
*
* Contributor(s):
* Rob Campbell <rcampbell@mozilla.com>
* Mihai Sucan <mihai.sucan@gmail.com>
*
* 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
@ -78,35 +79,40 @@ function setupHighlighterTests()
{
h1 = doc.querySelectorAll("h1")[0];
ok(h1, "we have the header node");
Services.obs.addObserver(runSelectionTests, "inspector-opened", false);
Services.obs.addObserver(runSelectionTests,
INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI();
}
function runSelectionTests()
{
Services.obs.removeObserver(runSelectionTests, "inspector-opened", false);
document.addEventListener("popupshown", performTestComparisons, false);
EventUtils.synthesizeMouse(h1, 2, 2, {type: "mousemove"}, content);
Services.obs.removeObserver(runSelectionTests,
INSPECTOR_NOTIFICATIONS.OPENED, false);
executeSoon(function() {
Services.obs.addObserver(performTestComparisons,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
EventUtils.synthesizeMouse(h1, 2, 2, {type: "mousemove"}, content);
});
}
function performTestComparisons(evt)
{
if (evt.target.id != "highlighter-panel")
return true;
document.removeEventListener("popupshown", performTestComparisons, false);
is(h1, InspectorUI.selection, "selection matches node");
ok(InspectorUI.highlighter.isHighlighting, "panel is highlighting");
is(InspectorUI.highlighter.highlitNode, h1, "highlighter matches selection");
Services.obs.removeObserver(performTestComparisons,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
Services.obs.addObserver(finishUp, "inspector-closed", false);
InspectorUI.closeInspectorUI();
InspectorUI.stopInspecting();
ok(InspectorUI.highlighter.isHighlighting, "highlighter is highlighting");
is(InspectorUI.highlighter.highlitNode, h1, "highlighter matches selection")
is(InspectorUI.selection, h1, "selection matches node");
is(InspectorUI.selection, InspectorUI.highlighter.highlitNode, "selection matches highlighter");
doc = h1 = null;
executeSoon(finishUp);
}
function finishUp() {
Services.obs.removeObserver(finishUp, "inspector-closed", false);
ok(!InspectorUI.highlighter, "panel is not highlighting");
doc = h1 = null;
InspectorUI.closeInspectorUI();
gBrowser.removeCurrentTab();
finish();
}
@ -120,7 +126,7 @@ function test()
doc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = "data:text/html,basic tests for inspector";
}

Просмотреть файл

@ -43,6 +43,7 @@ let div1;
let div2;
let iframe1;
let iframe2;
let highlighterFrame;
function createDocument()
{
@ -77,53 +78,59 @@ function createDocument()
doc.body.appendChild(iframe1);
}
function moveMouseOver(aElement)
{
EventUtils.synthesizeMouse(aElement, 2, 2, {type: "mousemove"},
aElement.ownerDocument.defaultView);
}
function setupIframeTests()
{
Services.obs.addObserver(runIframeTests, "inspector-opened", false);
Services.obs.addObserver(runIframeTests,
INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.openInspectorUI();
}
function runIframeTests()
{
Services.obs.removeObserver(runIframeTests, "inspector-opened", false);
document.addEventListener("popupshown", performTestComparisons1, false);
EventUtils.synthesizeMouse(div1, 2, 2, {type: "mousemove"},
iframe1.contentWindow);
Services.obs.removeObserver(runIframeTests,
INSPECTOR_NOTIFICATIONS.OPENED, false);
Services.obs.addObserver(performTestComparisons1,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
highlighterFrame = InspectorUI.highlighter.iframe;
executeSoon(moveMouseOver.bind(this, div1));
}
function performTestComparisons1(evt)
function performTestComparisons1()
{
if (evt.target.id != "highlighter-panel") {
return true;
}
document.removeEventListener(evt.type, arguments.callee, false);
Services.obs.removeObserver(performTestComparisons1,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
Services.obs.addObserver(performTestComparisons2,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
is(InspectorUI.selection, div1, "selection matches div1 node");
is(InspectorUI.highlighter.highlitNode, div1, "highlighter matches selection");
document.addEventListener("popupshown", performTestComparisons2, false);
EventUtils.synthesizeMouse(div2, 2, 2, {type: "mousemove"},
iframe2.contentWindow);
executeSoon(moveMouseOver.bind(this, div2));
}
function performTestComparisons2(evt)
function performTestComparisons2()
{
if (evt.target.id != "highlighter-panel") {
return true;
}
document.removeEventListener(evt.type, arguments.callee, false);
Services.obs.removeObserver(performTestComparisons2,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
is(InspectorUI.selection, div2, "selection matches div2 node");
is(InspectorUI.highlighter.highlitNode, div2, "highlighter matches selection");
executeSoon(finishUp);
finishUp();
}
function finishUp() {
InspectorUI.closeInspectorUI();
InspectorUI.closeInspectorUI(true);
doc = div1 = div2 = iframe1 = iframe2 = highlighterFrame = null;
gBrowser.removeCurrentTab();
finish();
}

Просмотреть файл

@ -37,31 +37,41 @@
*
* ***** END LICENSE BLOCK ***** */
let doc;
function startInspectorTests()
{
ok(InspectorUI, "InspectorUI variable exists");
Services.obs.addObserver(runInspectorTests, "inspector-opened", false);
Services.obs.addObserver(runInspectorTests,
INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI();
}
function runInspectorTests()
{
Services.obs.removeObserver(runInspectorTests, "inspector-opened", false);
Services.obs.addObserver(finishInspectorTests, "inspector-closed", false);
Services.obs.removeObserver(runInspectorTests,
INSPECTOR_NOTIFICATIONS.OPENED, false);
Services.obs.addObserver(finishInspectorTests,
INSPECTOR_NOTIFICATIONS.CLOSED, false);
let iframe = document.getElementById("inspector-tree-iframe");
is(InspectorUI.treeIFrame, iframe, "Inspector IFrame matches");
ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.inspecting, "Inspector is inspecting");
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open");
InspectorUI.closeInspectorUI();
ok(InspectorUI.highlighter, "Highlighter is up");
executeSoon(function() {
InspectorUI.closeInspectorUI();
});
}
function finishInspectorTests()
{
Services.obs.removeObserver(finishInspectorTests, "inspector-closed", false);
Services.obs.removeObserver(finishInspectorTests,
INSPECTOR_NOTIFICATIONS.CLOSED, false);
ok(!InspectorUI.highlighter, "Highlighter is gone");
ok(!InspectorUI.isTreePanelOpen, "Inspector Tree Panel is closed");
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(!InspectorUI.inspecting, "Inspector is not inspecting");
gBrowser.removeCurrentTab();
finish();
}
@ -72,10 +82,9 @@ function test()
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
doc = content.document;
waitForFocus(startInspectorTests, content);
}, true);
content.location = "data:text/html,basic tests for inspector";
}

Просмотреть файл

@ -65,34 +65,42 @@ function createDocument()
function toggleInspector()
{
Services.obs.addObserver(inspectNode, "inspector-opened", false);
Services.obs.addObserver(inspectNode, INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI();
}
function inspectNode()
{
Services.obs.removeObserver(inspectNode, "inspector-opened", false);
document.addEventListener("popupshown", performScrollingTest, false);
Services.obs.removeObserver(inspectNode,
INSPECTOR_NOTIFICATIONS.OPENED, false);
Services.obs.addObserver(performScrollingTest,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
InspectorUI.inspectNode(div)
executeSoon(function() {
InspectorUI.inspectNode(div);
});
}
function performScrollingTest(aEvent)
function performScrollingTest()
{
if (aEvent.target.id != "highlighter-panel") {
return true;
}
Services.obs.removeObserver(performScrollingTest,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
document.removeEventListener("popupshown", performScrollingTest, false);
EventUtils.synthesizeMouseScroll(div, 10, 10,
{axis:"vertical", delta:50, type:"MozMousePixelScroll"},
iframe.contentWindow);
EventUtils.synthesizeMouseScroll(aEvent.target, 10, 10,
{axis:"vertical", delta:50, type:"MozMousePixelScroll"}, window);
gBrowser.selectedBrowser.addEventListener("scroll", function() {
gBrowser.selectedBrowser.removeEventListener("scroll", arguments.callee,
false);
is(iframe.contentDocument.body.scrollTop, 50, "inspected iframe scrolled");
is(iframe.contentDocument.body.scrollTop, 50, "inspected iframe scrolled");
InspectorUI.closeInspectorUI();
gBrowser.removeCurrentTab();
finish();
div = iframe = doc = null;
InspectorUI.closeInspectorUI();
gBrowser.removeCurrentTab();
finish();
}, false);
}
function test()

Просмотреть файл

@ -39,7 +39,7 @@
function test()
{
ok(InspectorUI, "InspectorUI variable exists");
ok(window.InspectorUI, "InspectorUI variable exists");
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
is(InspectorStore.length, 0, "InspectorStore is empty");
ok(InspectorStore.isEmpty(), "InspectorStore is empty (confirmed)");

Просмотреть файл

@ -45,17 +45,19 @@ let tab1window;
function inspectorTabOpen1()
{
ok(InspectorUI, "InspectorUI variable exists");
ok(window.InspectorUI, "InspectorUI variable exists");
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(InspectorStore.isEmpty(), "InspectorStore is empty");
Services.obs.addObserver(inspectorUIOpen1, "inspector-opened", false);
Services.obs.addObserver(inspectorUIOpen1,
INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.openInspectorUI();
}
function inspectorUIOpen1()
{
Services.obs.removeObserver(inspectorUIOpen1, "inspector-opened", false);
Services.obs.removeObserver(inspectorUIOpen1,
INSPECTOR_NOTIFICATIONS.OPENED, false);
// Make sure the inspector is open.
ok(InspectorUI.inspecting, "Inspector is highlighting");
@ -90,14 +92,16 @@ function inspectorTabOpen2()
// Activate the inspector again.
executeSoon(function() {
Services.obs.addObserver(inspectorUIOpen2, "inspector-opened", false);
Services.obs.addObserver(inspectorUIOpen2,
INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.openInspectorUI();
});
}
function inspectorUIOpen2()
{
Services.obs.removeObserver(inspectorUIOpen2, "inspector-opened", false);
Services.obs.removeObserver(inspectorUIOpen2,
INSPECTOR_NOTIFICATIONS.OPENED, false);
// Make sure the inspector is open.
ok(InspectorUI.inspecting, "Inspector is highlighting");
@ -110,14 +114,16 @@ function inspectorUIOpen2()
// Switch back to tab 1.
executeSoon(function() {
Services.obs.addObserver(inspectorFocusTab1, "inspector-opened", false);
Services.obs.addObserver(inspectorFocusTab1,
INSPECTOR_NOTIFICATIONS.OPENED, false);
gBrowser.selectedTab = tab1;
});
}
function inspectorFocusTab1()
{
Services.obs.removeObserver(inspectorFocusTab1, "inspector-opened", false);
Services.obs.removeObserver(inspectorFocusTab1,
INSPECTOR_NOTIFICATIONS.OPENED, false);
// Make sure the inspector is still open.
ok(InspectorUI.inspecting, "Inspector is highlighting");
@ -126,13 +132,15 @@ function inspectorFocusTab1()
is(InspectorUI.selection, div, "selection matches the div element");
// Switch back to tab 2.
Services.obs.addObserver(inspectorFocusTab2, "inspector-opened", false);
Services.obs.addObserver(inspectorFocusTab2,
INSPECTOR_NOTIFICATIONS.OPENED, false);
gBrowser.selectedTab = tab2;
}
function inspectorFocusTab2()
{
Services.obs.removeObserver(inspectorFocusTab2, "inspector-opened", false);
Services.obs.removeObserver(inspectorFocusTab2,
INSPECTOR_NOTIFICATIONS.OPENED, false);
// Make sure the inspector is still open.
ok(!InspectorUI.inspecting, "Inspector is not highlighting");

Просмотреть файл

@ -15,17 +15,17 @@
<body arbitrary:attribute="value">
<p>Inspector tree panel test.</p>
<div id="foo" class="foo bar baz" style="border:1px solid red;
<div id="foo" class="foo bar baz" style="border:1px solid red;
unknownProperty: unknownValue; color: withUnkownValue">
<unknownTag unknownAttribute="fooBar">
<p unknownAttribute="fooBar" data-test1="value">hello world!</p>
</unknownTag>
</div>
<div id="duplicate" id="duplicate" id="different" class="test" class="foo"
<div id="duplicate" id="duplicate" id="different" class="test" class="foo"
fooBar="baz" fooBar="bazbaz">test</div>
<iframe src="data:text/html,&lt;div&gt;hello from an iframe!&lt;/div&gt;">no
<iframe src="data:text/html,&lt;div&gt;hello from an iframe!&lt;/div&gt;">no
frames!</iframe>
<!-- hello world from a comment! -->

Просмотреть файл

@ -42,8 +42,8 @@ let doc = null;
let xhr = null;
let expectedResult = "";
const TEST_URI = "http://mochi.test:8888/browser/browser/base/content/test/browser_inspector_treePanel_input.html";
const RESULT_URI = "http://mochi.test:8888/browser/browser/base/content/test/browser_inspector_treePanel_result.html";
const TEST_URI = "http://mochi.test:8888/browser/browser/base/content/test/inspector/browser_inspector_treePanel_input.html";
const RESULT_URI = "http://mochi.test:8888/browser/browser/base/content/test/inspector/browser_inspector_treePanel_result.html";
function tabFocused()
{
@ -63,13 +63,15 @@ function xhr_onReadyStateChange() {
expectedResult = xhr.responseText.replace(/^\s+|\s+$/mg, '');
xhr = null;
Services.obs.addObserver(inspectorOpened, "inspector-opened", false);
Services.obs.addObserver(inspectorOpened,
INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.openInspectorUI();
}
function inspectorOpened()
{
Services.obs.removeObserver(inspectorOpened, "inspector-opened", false);
Services.obs.removeObserver(inspectorOpened,
INSPECTOR_NOTIFICATIONS.OPENED, false);
ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open");
@ -94,13 +96,15 @@ function inspectorOpened()
expectedResult, "treePanelDiv.innerHTML is correct");
expectedResult = null;
Services.obs.addObserver(inspectorClosed, "inspector-closed", false);
Services.obs.addObserver(inspectorClosed,
INSPECTOR_NOTIFICATIONS.CLOSED, false);
InspectorUI.closeInspectorUI();
}
function inspectorClosed()
{
Services.obs.removeObserver(inspectorClosed, "inspector-closed", false);
Services.obs.removeObserver(inspectorClosed,
INSPECTOR_NOTIFICATIONS.CLOSED, false);
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(!InspectorUI.isTreePanelOpen, "Inspector Tree Panel is not open");
@ -118,6 +122,6 @@ function test()
doc = content.document;
waitForFocus(tabFocused, content);
}, true);
content.location = TEST_URI;
}

Просмотреть файл

@ -59,7 +59,6 @@ function createDocument()
div.appendChild(h1);
div.appendChild(p1);
div.appendChild(p2);
// doc.body.addEventListener("DOMSubtreeModified", , false);
doc.body.appendChild(div);
setupSelectionTests();
}
@ -68,31 +67,37 @@ function setupSelectionTests()
{
h1 = doc.querySelectorAll("h1")[0];
ok(h1, "we have the header node");
Services.obs.addObserver(runSelectionTests, "inspector-opened", false);
Services.obs.addObserver(runSelectionTests,
INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.openInspectorUI();
}
function runSelectionTests()
{
Services.obs.removeObserver(runSelectionTests, "inspector-opened", false);
InspectorUI.stopInspecting();
document.addEventListener("popupshown", performTestComparisons, false);
InspectorUI.inspectNode(h1);
Services.obs.removeObserver(runSelectionTests,
INSPECTOR_NOTIFICATIONS.OPENED, false);
Services.obs.addObserver(performTestComparisons,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
executeSoon(function() {
InspectorUI.inspectNode(h1);
});
}
function performTestComparisons(evt)
{
if (evt.target.id != "highlighter-panel")
return true;
document.removeEventListener("popupshown", performTestComparisons, false);
Services.obs.removeObserver(performTestComparisons,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
is(h1, InspectorUI.selection, "selection matches node");
ok(InspectorUI.highlighter.isHighlighting, "panel is highlighting");
is(h1, InspectorUI.highlighter.highlitNode, "highlighter highlighting correct node");
ok(InspectorUI.highlighter.isHighlighting, "highlighter is highlighting");
is(InspectorUI.highlighter.highlitNode, h1, "highlighter highlighting correct node");
finishUp();
}
function finishUp() {
InspectorUI.closeInspectorUI();
doc = h1 = null;
gBrowser.removeCurrentTab();
finish();
}
@ -106,7 +111,7 @@ function test()
doc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = "data:text/html,basic tests for inspector";
}

Просмотреть файл

@ -30,6 +30,7 @@ browser.jar:
* content/browser/browser.xul (content/browser.xul)
* content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml)
* content/browser/fullscreen-video.xhtml (content/fullscreen-video.xhtml)
content/browser/highlighter.xhtml (content/highlighter.xhtml)
* content/browser/inspector.html (content/inspector.html)
* content/browser/scratchpad.xul (content/scratchpad.xul)
* content/browser/scratchpad.js (content/scratchpad.js)

Просмотреть файл

@ -0,0 +1,104 @@
/* ***** 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 the Mozilla Inspector Module.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Rob Campbell <rcampbell@mozilla.com> (original author)
* Paul Rouget <paul@mozilla.com>
*
* 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 ***** */
body {
margin: 0;
overflow: hidden;
}
#close-button {
background-image: url("KUI-close.png");
border: none;
padding: 0;
width: 24px;
height: 24px;
position: fixed;
top: 12px;
right: 12px;
z-index: 1;
cursor: pointer;
}
.veil {
background-color: rgba(0, 0, 0, 0.5);
}
.veil, #veil-middlebox, #veil-transparentbox {
-moz-transition: 0.1s;
-moz-transition-timing-function: linear;
}
#veil-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#veil {
width: 100%;
height: 100%;
display: -moz-box;
-moz-box-orient: vertical;
}
#veil-topbox, #veil-bottombox {
width: 100%;
}
#veil-bottombox {
-moz-box-flex: 1;
}
#veil-middlebox {
display: -moz-box;
-moz-box-orient: horizontal;
}
#veil-leftbox, #veil-rightbox {
height: 100%;
}
#veil-rightbox {
-moz-box-flex: 1;
}
#veil {
vertical-align: top;
}

Просмотреть файл

@ -17,6 +17,7 @@ browser.jar:
skin/classic/browser/Geolocation-16.png
skin/classic/browser/Geolocation-64.png
skin/classic/browser/Go-arrow.png
* skin/classic/browser/highlighter.css
skin/classic/browser/identity.png
skin/classic/browser/Info.png
skin/classic/browser/KUI-close.png

Просмотреть файл

@ -0,0 +1,104 @@
/* ***** 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 the Mozilla Inspector Module.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Rob Campbell <rcampbell@mozilla.com> (original author)
* Paul Rouget <paul@mozilla.com>
*
* 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 ***** */
body {
margin: 0;
overflow: hidden;
}
#close-button {
background-image: url("KUI-close.png");
border: none;
padding: 0;
width: 24px;
height: 24px;
position: fixed;
top: 12px;
right: 12px;
z-index: 1;
cursor: pointer;
}
.veil {
background-color: rgba(0, 0, 0, 0.5);
}
.veil, #veil-middlebox, #veil-transparentbox {
-moz-transition: 0.1s;
-moz-transition-timing-function: linear;
}
#veil-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#veil {
width: 100%;
height: 100%;
display: -moz-box;
-moz-box-orient: vertical;
}
#veil-topbox, #veil-bottombox {
width: 100%;
}
#veil-bottombox {
-moz-box-flex: 1;
}
#veil-middlebox {
display: -moz-box;
-moz-box-orient: horizontal;
}
#veil-leftbox, #veil-rightbox {
height: 100%;
}
#veil-rightbox {
-moz-box-flex: 1;
}
#veil {
vertical-align: top;
}

Просмотреть файл

@ -15,6 +15,7 @@ browser.jar:
skin/classic/browser/Geolocation-16.png
skin/classic/browser/Geolocation-64.png
skin/classic/browser/Go-arrow.png
* skin/classic/browser/highlighter.css
skin/classic/browser/home.png
skin/classic/browser/hud-style-check-box-checked.png
skin/classic/browser/hud-style-check-box-empty.png

Просмотреть файл

@ -0,0 +1,105 @@
/* ***** 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 the Mozilla Inspector Module.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Rob Campbell <rcampbell@mozilla.com> (original author)
* Paul Rouget <paul@mozilla.com>
*
* 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 ***** */
body {
margin: 0;
overflow: hidden;
}
#close-button {
background-image: url("KUI-close.png");
border: none;
padding: 0;
width: 24px;
height: 24px;
position: fixed;
top: 12px;
right: 12px;
z-index: 1;
cursor: pointer;
}
.veil {
background-color: rgba(0, 0, 0, 0.5);
}
.veil, #veil-middlebox, #veil-transparentbox {
-moz-transition: 0.1s;
-moz-transition-timing-function: linear;
}
#veil-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#veil {
width: 100%;
height: 100%;
display: -moz-box;
-moz-box-orient: vertical;
}
#veil-topbox, #veil-bottombox {
width: 100%;
}
#veil-bottombox {
-moz-box-flex: 1;
}
#veil-middlebox {
display: -moz-box;
-moz-box-orient: horizontal;
}
#veil-leftbox, #veil-rightbox {
height: 100%;
}
#veil-rightbox {
-moz-box-flex: 1;
}
#veil {
vertical-align: top;
}

Просмотреть файл

@ -19,6 +19,7 @@ browser.jar:
skin/classic/browser/fullscreen-video.css
skin/classic/browser/Geolocation-16.png
skin/classic/browser/Geolocation-64.png
* skin/classic/browser/highlighter.css
skin/classic/browser/Info.png (Info.png)
skin/classic/browser/identity.png (identity.png)
skin/classic/browser/keyhole-forward-mask.svg
@ -133,6 +134,7 @@ browser.jar:
skin/classic/aero/browser/fullscreen-video.css
skin/classic/aero/browser/Geolocation-16.png
skin/classic/aero/browser/Geolocation-64.png
* skin/classic/aero/browser/highlighter.css
skin/classic/aero/browser/Info.png (Info-aero.png)
skin/classic/aero/browser/identity.png (identity-aero.png)
skin/classic/aero/browser/keyhole-forward-mask.svg

Просмотреть файл

@ -84,6 +84,11 @@ struct BaseIC : public MacroAssemblerTypedefs {
// Slow path stub call.
CodeLocationCall slowPathCall;
// Offset from start of stub to jump target of second shape guard as Nitro
// asm data location. This is 0 if there is only one shape guard in the
// last stub.
int32 secondShapeGuard;
// Whether or not the callsite has been hit at least once.
bool hit : 1;
bool slowCallPatched : 1;
@ -91,11 +96,6 @@ struct BaseIC : public MacroAssemblerTypedefs {
// Number of stubs generated.
uint32 stubsGenerated : 5;
// Offset from start of stub to jump target of second shape guard as Nitro
// asm data location. This is 0 if there is only one shape guard in the
// last stub.
int32 secondShapeGuard : 11;
// Opcode this was compiled for.
JSOp op : 9;

Просмотреть файл

@ -179,7 +179,7 @@ IsFrameDescendantOfAny(nsIFrame* aChild,
const TextOverflow::FrameHashtable& aSetOfFrames,
nsIFrame* aCommonAncestor)
{
for (nsIFrame* f = aChild; f != aCommonAncestor;
for (nsIFrame* f = aChild; f && f != aCommonAncestor;
f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
if (aSetOfFrames.GetEntry(f)) {
return true;

Просмотреть файл

@ -362,3 +362,5 @@ load 650499-1.html
load 660416.html
load text-overflow-form-elements.html
load text-overflow-iframe.html
load text-overflow-bug666751-1.html
load text-overflow-bug666751-2.html

Просмотреть файл

@ -0,0 +1,12 @@
<html class="reftest-wait"><head><script>
function finish() {
window.removeEventListener("MozAfterPaint", finish, false);
document.documentElement.removeAttribute("class");
}
</script>
</head><body onload="window.addEventListener('MozAfterPaint', finish, false); document.body.style.backgroundColor='lime';">
<div style="overflow: scroll; text-indent: -100px; white-space: pre; text-overflow: ellipsis;"><span style="font-family: -moz-fixed; white-space: normal;"></code><p style="position: fixed;">m
</p>
</div>
</body></html>

Просмотреть файл

@ -0,0 +1,12 @@
<html class="reftest-wait"><head><script>
function finish() {
window.removeEventListener("MozAfterPaint", finish, false);
document.documentElement.removeAttribute("class");
}
</script>
</head><body onload="window.addEventListener('MozAfterPaint', finish, false); document.body.style.backgroundColor='lime';">
<div style="overflow: scroll; text-indent: -100px; white-space: pre; text-overflow: ellipsis;"><span style="font-family: -moz-fixed; white-space: normal;"></code><p style="position: absolute;">m
</p>
</div>
</body></html>

Просмотреть файл

@ -530,7 +530,6 @@
<body>
<![CDATA[
let bcr = this.getBoundingClientRect();
let view = this.getRootView();
let scroll = this.getRootView().getPosition();
return { x: (clientX + scroll.x - bcr.left) / this.scale,
y: (clientY + scroll.y - bcr.top) / this.scale };
@ -538,6 +537,19 @@
</body>
</method>
<method name="transformBrowserToClient">
<parameter name="browserX"/>
<parameter name="browserY"/>
<body>
<![CDATA[
let bcr = this.getBoundingClientRect();
let scroll = this.getRootView().getPosition();
return { x: (browserX * this.scale - scroll.x + bcr.left) ,
y: (browserY * this.scale - scroll.y + bcr.top)};
]]>
</body>
</method>
<constructor>
<![CDATA[
this._frameLoader = this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;

Просмотреть файл

@ -71,6 +71,7 @@ XPCOMUtils.defineLazyGetter(this, "CommonUI", function() {
["FullScreenVideo"],
["BadgeHandlers"],
["ContextHelper"],
["SelectionHelper"],
["FormHelperUI"],
["FindHelperUI"],
["NewTabPopup"],

Просмотреть файл

@ -1754,11 +1754,13 @@ const ContentTouchHandler = {
case "Browser:ContextMenu":
// Long tap
let contextMenu = { name: aMessage.name, json: json, target: aMessage.target };
if (ContextHelper.showPopup(contextMenu)) {
// Stop all input sequences
let event = document.createEvent("Events");
event.initEvent("CancelTouchSequence", true, false);
document.dispatchEvent(event);
if (!SelectionHelper.showPopup(contextMenu)) {
if (ContextHelper.showPopup(contextMenu)) {
// Stop all input sequences
let event = document.createEvent("Events");
event.initEvent("CancelTouchSequence", true, false);
document.dispatchEvent(event);
}
}
break;
case "Browser:CaptureEvents": {

Просмотреть файл

@ -663,6 +663,9 @@
</vbox>
</hbox>
<toolbarbutton id="selectionhandle-start" label="^" left="0" top="0" hidden="true"/>
<toolbarbutton id="selectionhandle-end" label="^" left="0" top="0" hidden="true"/>
<hbox id="menulist-container" class="window-width window-height context-block" top="0" left="0" hidden="true" flex="1">
<vbox id="menulist-popup" class="dialog-dark">
<label id="menulist-title" class="options-title" crop="center" flex="1"/>

Просмотреть файл

@ -1235,6 +1235,167 @@ var ContextHelper = {
}
};
var SelectionHelper = {
enabled: true,
popupState: null,
target: null,
deltaX: -1,
deltaY: -1,
get _start() {
delete this._start;
return this._start = document.getElementById("selectionhandle-start");
},
get _end() {
delete this._end;
return this._end = document.getElementById("selectionhandle-end");
},
showPopup: function ch_showPopup(aMessage) {
if (!this.enabled || aMessage.json.types.indexOf("content-text") == -1)
return false;
this.popupState = aMessage.json;
this.popupState.target = aMessage.target;
this._start.customDragger = {
isDraggable: function isDraggable(target, content) { return { x: true, y: false }; },
dragStart: function dragStart(cx, cy, target, scroller) {},
dragStop: function dragStop(dx, dy, scroller) { return false; },
dragMove: function dragMove(dx, dy, scroller) { return false; }
};
this._end.customDragger = {
isDraggable: function isDraggable(target, content) { return { x: true, y: false }; },
dragStart: function dragStart(cx, cy, target, scroller) {},
dragStop: function dragStop(dx, dy, scroller) { return false; },
dragMove: function dragMove(dx, dy, scroller) { return false; }
};
this._start.addEventListener("TapDown", this, true);
this._start.addEventListener("TapUp", this, true);
this._end.addEventListener("TapDown", this, true);
this._end.addEventListener("TapUp", this, true);
messageManager.addMessageListener("Browser:SelectionRange", this);
messageManager.addMessageListener("Browser:SelectionCopied", this);
Services.prefs.setBoolPref("accessibility.browsewithcaret", true);
this.popupState.target.messageManager.sendAsyncMessage("Browser:SelectionStart", { x: this.popupState.x, y: this.popupState.y });
BrowserUI.pushPopup(this, [this._start, this._end]);
// Hide the selection handles
window.addEventListener("resize", this, true);
window.addEventListener("keypress", this, true);
Elements.browsers.addEventListener("URLChanged", this, true);
Elements.browsers.addEventListener("SizeChanged", this, true);
Elements.browsers.addEventListener("ZoomChanged", this, true);
let event = document.createEvent("Events");
event.initEvent("CancelTouchSequence", true, false);
this.popupState.target.dispatchEvent(event);
return true;
},
hide: function ch_hide() {
if (this._start.hidden)
return;
this.popupState.target.messageManager.sendAsyncMessage("Browser:SelectionEnd", {});
this.popupState = null;
Services.prefs.setBoolPref("accessibility.browsewithcaret", false);
this._start.hidden = true;
this._end.hidden = true;
this._start.removeEventListener("TapDown", this, true);
this._start.removeEventListener("TapUp", this, true);
this._end.removeEventListener("TapDown", this, true);
this._end.removeEventListener("TapUp", this, true);
messageManager.removeMessageListener("Browser:SelectionRange", this);
window.removeEventListener("resize", this, true);
window.removeEventListener("keypress", this, true);
Elements.browsers.removeEventListener("URLChanged", this, true);
Elements.browsers.removeEventListener("SizeChanged", this, true);
Elements.browsers.removeEventListener("ZoomChanged", this, true);
BrowserUI.popPopup(this);
},
handleEvent: function handleEvent(aEvent) {
switch (aEvent.type) {
case "TapDown":
this.target = aEvent.target;
this.deltaX = (aEvent.clientX - this.target.left);
this.deltaY = (aEvent.clientY - this.target.top);
window.addEventListener("TapMove", this, true);
break;
case "TapUp":
window.removeEventListener("TapMove", this, true);
this.target = null;
this.deltaX = -1;
this.deltaY = -1;
break;
case "TapMove":
if (this.target) {
this.target.left = aEvent.clientX - this.deltaX;
this.target.top = aEvent.clientY - this.deltaY;
let rect = this.target.getBoundingClientRect();
let data = this.target == this._start ? { x: rect.right, y: rect.top, type: "start" } : { x: rect.left, y: rect.top, type: "end" };
let pos = this.popupState.target.transformClientToBrowser(data.x || 0, data.y || 0);
let json = {
type: data.type,
x: pos.x,
y: pos.y
};
this.popupState.target.messageManager.sendAsyncMessage("Browser:SelectionMove", json);
}
break;
case "resize":
case "keypress":
case "URLChanged":
case "SizeChanged":
case "ZoomChanged":
this.hide();
break;
}
},
receiveMessage: function sh_receiveMessage(aMessage) {
let json = aMessage.json;
switch (aMessage.name) {
case "Browser:SelectionRange": {
let pos = this.popupState.target.transformBrowserToClient(json.start.x || 0, json.start.y || 0);
this._start.left = pos.x - 32;
this._start.top = pos.y + this.deltaY;
this._start.hidden = false;
pos = this.popupState.target.transformBrowserToClient(json.end.x || 0, json.end.y || 0);
this._end.left = pos.x;
this._end.top = pos.y;
this._end.hidden = false;
break;
}
case "Browser:SelectionCopied": {
messageManager.removeMessageListener("Browser:SelectionCopied", this);
if (json.succeeded) {
let toaster = Cc["@mozilla.org/toaster-alerts-service;1"].getService(Ci.nsIAlertsService);
toaster.showAlertNotification(null, Strings.browser.GetStringFromName("selectionHelper.textCopied"), "", false, "", null);
}
break;
}
}
}
};
var BadgeHandlers = {
_handlers: [
{

Просмотреть файл

@ -918,6 +918,14 @@ var ContextHandler = {
if (hasData && !elem.readOnly)
state.types.push("paste");
break;
} else if (elem instanceof Ci.nsIDOMHTMLParagraphElement ||
elem instanceof Ci.nsIDOMHTMLDivElement ||
elem instanceof Ci.nsIDOMHTMLLIElement ||
elem instanceof Ci.nsIDOMHTMLPreElement ||
elem instanceof Ci.nsIDOMHTMLHeadingElement ||
elem instanceof Ci.nsIDOMHTMLTableCellElement) {
state.types.push("content-text");
break;
}
}
@ -1281,6 +1289,7 @@ var TouchEventHandler = {
if (!this.element)
return;
let cancelled = !this.sendEvent(type, json, this.element);
if (type == "touchend")
this.element = null;
@ -1316,6 +1325,93 @@ var TouchEventHandler = {
}
return aElement.dispatchEvent(evt);
}
}
};
TouchEventHandler.init();
var SelectionHandler = {
cache: {},
init: function() {
addMessageListener("Browser:SelectionStart", this);
addMessageListener("Browser:SelectionEnd", this);
addMessageListener("Browser:SelectionMove", this);
},
receiveMessage: function(aMessage) {
let scrollOffset = ContentScroll.getScrollOffset(content);
let utils = Util.getWindowUtils(content);
let json = aMessage.json;
switch (aMessage.name) {
case "Browser:SelectionStart": {
// Position the caret using a fake mouse click
utils.sendMouseEventToWindow("mousedown", json.x - scrollOffset.x, json.y - scrollOffset.y, 0, 1, 0, true);
utils.sendMouseEventToWindow("mouseup", json.x - scrollOffset.x, json.y - scrollOffset.y, 0, 1, 0, true);
// Select the word nearest the caret
try {
let selcon = docShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsISelectionDisplay).QueryInterface(Ci.nsISelectionController);
selcon.wordMove(false, false);
selcon.wordMove(true, true);
} catch(e) {
// If we couldn't select the word at the given point, bail
return;
}
// Find the selected text rect and send it back so the handles can position correctly
let selection = content.getSelection();
if (selection.rangeCount == 0)
return;
let range = selection.getRangeAt(0).QueryInterface(Ci.nsIDOMNSRange);
this.cache = { start: {}, end: {} };
let rects = range.getClientRects();
for (let i=0; i<rects.length; i++) {
if (i == 0) {
this.cache.start.x = rects[i].left + scrollOffset.x;
this.cache.start.y = rects[i].bottom + scrollOffset.y;
}
this.cache.end.x = rects[i].right + scrollOffset.x;
this.cache.end.y = rects[i].bottom + scrollOffset.y;
}
sendAsyncMessage("Browser:SelectionRange", this.cache);
break;
}
case "Browser:SelectionEnd": {
let selection = content.getSelection();
let str = selection.toString();
selection.collapseToStart();
if (str.length) {
let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
clipboard.copyString(str);
sendAsyncMessage("Browser:SelectionCopied", { succeeded: true });
} else {
sendAsyncMessage("Browser:SelectionCopied", { succeeded: false });
}
break;
}
case "Browser:SelectionMove":
if (json.type == "end") {
this.cache.end.x = json.x - scrollOffset.x;
this.cache.end.y = json.y - scrollOffset.y;
utils.sendMouseEventToWindow("mousedown", this.cache.end.x, this.cache.end.y, 0, 1, Ci.nsIDOMNSEvent.SHIFT_MASK, true);
utils.sendMouseEventToWindow("mouseup", this.cache.end.x, this.cache.end.y, 0, 1, Ci.nsIDOMNSEvent.SHIFT_MASK, true);
} else {
this.cache.start.x = json.x - scrollOffset.x;
this.cache.start.y = json.y - scrollOffset.y;
utils.sendMouseEventToWindow("mousedown", this.cache.start.x, this.cache.start.y, 0, 1, 0, true);
// Don't cause a click. A mousedown is enough to move the caret
//utils.sendMouseEventToWindow("mouseup", this.cache.start.x, this.cache.start.y, 0, 1, 0, true);
utils.sendMouseEventToWindow("mousedown", this.cache.end.x, this.cache.end.y, 0, 1, Ci.nsIDOMNSEvent.SHIFT_MASK, true);
utils.sendMouseEventToWindow("mouseup", this.cache.end.x, this.cache.end.y, 0, 1, Ci.nsIDOMNSEvent.SHIFT_MASK, true);
}
break;
}
}
};
SelectionHandler.init();

Просмотреть файл

@ -90,6 +90,8 @@ function test() {
gCurrentTab = Browser.addTab(testURL, true);
ok(gCurrentTab, "Tab Opened");
SelectionHelper.enabled = false;
window.addEventListener("TapSingle", dumpEvents, true);
window.addEventListener("TapDouble", dumpEvents, true);
window.addEventListener("TapLong", dumpEvents, true);
@ -125,6 +127,7 @@ function runNextTest() {
window.removeEventListener("TapDouble", dumpEvents, true);
window.removeEventListener("TapLong", dumpEvents, true);
SelectionHelper.enabled = true;
Browser.closeTab(gCurrentTab);
finish();
@ -277,7 +280,7 @@ gTests.push({
contextPlainImageTest: function() {
waitForContextMenu(function() {
ok(checkContextTypes(["image","image-shareable","image-loaded"]), "Plain image context types");
ok(checkContextTypes(["image","image-shareable","image-loaded", "content-text"]), "Plain image context types");
}, gCurrentTest.contextNestedImageTest);
let browser = gCurrentTab.browser;

Просмотреть файл

@ -235,3 +235,6 @@ intl.charsetmenu.browser.static=iso-8859-1,utf-8,x-gbk,big5,iso-2022-jp,shift_ji
#Application Menu
appMenu.more=More
#Text Selection
selectionHelper.textCopied=Text copied to clipboard

Просмотреть файл

@ -1531,3 +1531,20 @@ setting {
90% { -moz-transform: translateX(@sidebar_width_minimum@); }
to { -moz-transform: translateX(0); }
}
#selectionhandle-start,
#selectionhandle-end {
min-width: 35px !important;
width: 35px !important;
padding: 0 !important;
margin: 0 !important;
}
#selectionhandle-start {
list-style-image: url("chrome://browser/skin/images/handle-start.png");
}
#selectionhandle-end {
list-style-image: url("chrome://browser/skin/images/handle-end.png");
}

Просмотреть файл

@ -1497,3 +1497,20 @@ setting {
90% { -moz-transform: translateX(-@sidebar_width_minimum@); }
to { -moz-transform: translateX(0); }
}
#selectionhandle-start,
#selectionhandle-end {
min-width: 35px !important;
width: 35px !important;
padding: 0 !important;
margin: 0 !important;
}
#selectionhandle-start {
list-style-image: url("chrome://browser/skin/images/handle-start.png");
}
#selectionhandle-end {
list-style-image: url("chrome://browser/skin/images/handle-end.png");
}

Двоичные данные
mobile/themes/core/gingerbread/images/handle-end.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Двоичные данные
mobile/themes/core/gingerbread/images/handle-start.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Двоичные данные
mobile/themes/core/images/handle-end.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Двоичные данные
mobile/themes/core/images/handle-start.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Просмотреть файл

@ -122,6 +122,8 @@ chrome.jar:
skin/images/mute-hdpi.png (images/mute-hdpi.png)
skin/images/unmute-hdpi.png (images/unmute-hdpi.png)
skin/images/scrubber-hdpi.png (images/scrubber-hdpi.png)
skin/images/handle-start.png (images/handle-start.png)
skin/images/handle-end.png (images/handle-end.png)
chrome.jar:
% skin browser classic/1.0 %skin/gingerbread/ os=Android osversion=2.3 osversion=2.3.3 osversion=2.3.4
@ -240,6 +242,8 @@ chrome.jar:
skin/gingerbread/images/mute-hdpi.png (gingerbread/images/mute-hdpi.png)
skin/gingerbread/images/unmute-hdpi.png (gingerbread/images/unmute-hdpi.png)
skin/gingerbread/images/scrubber-hdpi.png (gingerbread/images/scrubber-hdpi.png)
skin/gingerbread/images/handle-start.png (gingerbread/images/handle-start.png)
skin/gingerbread/images/handle-end.png (gingerbread/images/handle-end.png)
chrome.jar:
% skin browser classic/1.0 %skin/honeycomb/ os=Android osversion>=3.0
@ -360,4 +364,5 @@ chrome.jar:
skin/honeycomb/images/mute-hdpi.png (honeycomb/images/mute-hdpi.png)
skin/honeycomb/images/unmute-hdpi.png (honeycomb/images/unmute-hdpi.png)
skin/honeycomb/images/scrubber-hdpi.png (honeycomb/images/scrubber-hdpi.png)
skin/honeycomb/images/handle-start.png (images/handle-start.png)
skin/honeycomb/images/handle-end.png (images/handle-end.png)

Просмотреть файл

@ -2823,6 +2823,10 @@ HUD_SERVICE.prototype =
let windowUI = nBox.ownerDocument.getElementById("console_window_" + hudId);
if (windowUI) {
// The Web Console popup is already open, no need to continue.
if (aContentWindow == aContentWindow.top) {
let hud = this.hudReferences[hudId];
hud.reattachConsole(aContentWindow);
}
return;
}
@ -3227,10 +3231,8 @@ HeadsUpDisplay.prototype = {
let panel = this.chromeDocument.createElementNS(XUL_NS, "panel");
let label = this.getStr("webConsoleOwnWindowTitle");
let config = { id: "console_window_" + this.hudId,
label: label,
label: this.getPanelTitle(),
titlebar: "normal",
noautohide: "true",
norestorefocus: "true",
@ -3359,6 +3361,17 @@ HeadsUpDisplay.prototype = {
return panel;
},
/**
* Retrieve the Web Console panel title.
*
* @return string
* The Web Console panel title.
*/
getPanelTitle: function HUD_getPanelTitle()
{
return this.getFormatStr("webConsoleWindowTitleAndURL", [this.uriSpec]);
},
positions: {
above: 0, // the childNode index
below: 2,
@ -3510,6 +3523,10 @@ HeadsUpDisplay.prototype = {
this.contentDocument = this.contentWindow.document;
this.uriSpec = this.contentWindow.location.href;
if (this.consolePanel) {
this.consolePanel.label = this.getPanelTitle();
}
if (!this.jsterm) {
this.createConsoleInput(this.contentWindow, this.consoleWrap, this.outputNode);
}
@ -4931,6 +4948,7 @@ JSTerm.prototype = {
setInputValue: function JST_setInputValue(aNewValue)
{
this.inputNode.value = aNewValue;
this.lastInputValue = aNewValue;
this.completeNode.value = "";
this.resizeInput();
},

Просмотреть файл

@ -141,6 +141,8 @@ _BROWSER_TEST_FILES = \
browser_webconsole_bug_642615_autocomplete.js \
browser_webconsole_bug_585991_autocomplete_popup.js \
browser_webconsole_bug_585991_autocomplete_keys.js \
browser_webconsole_bug_663443_panel_title.js \
browser_webconsole_bug_660806_history_nav.js \
head.js \
$(NULL)

Просмотреть файл

@ -0,0 +1,48 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "data:text/html,<p>bug 660806 - history navigation must not show the autocomplete popup";
function test() {
addTab(TEST_URI);
browser.addEventListener("load", tabLoaded, true);
}
function tabLoaded()
{
browser.removeEventListener("load", tabLoaded, true);
openConsole();
content.wrappedJSObject.foobarBug660806 = {
"location": "value0",
"locationbar": "value1",
};
let hudId = HUDService.getHudIdByWindow(content);
let HUD = HUDService.hudReferences[hudId];
let jsterm = HUD.jsterm;
let popup = jsterm.autocompletePopup;
popup._panel.addEventListener("popupshown", function() {
popup._panel.removeEventListener("popupshown", arguments.callee, false);
ok(false, "popup shown");
}, false);
ok(!popup.isOpen, "popup is not open");
ok(!jsterm.lastInputValue, "no lastInputValue");
jsterm.setInputValue("window.foobarBug660806.location");
is(jsterm.lastInputValue, "window.foobarBug660806.location",
"lastInputValue is correct");
EventUtils.synthesizeKey("VK_RETURN", {});
EventUtils.synthesizeKey("VK_UP", {});
is(jsterm.lastInputValue, "window.foobarBug660806.location",
"lastInputValue is correct, again");
executeSoon(function() {
ok(!popup.isOpen, "popup is not open");
executeSoon(finishTest);
});
}

Просмотреть файл

@ -0,0 +1,45 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "data:text/html,<p>test for bug 663443. test1";
const POSITION_PREF = "devtools.webconsole.position";
function tabLoad(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
Services.prefs.setCharPref(POSITION_PREF, "window");
openConsole();
document.addEventListener("popupshown", function() {
document.removeEventListener("popupshown", arguments.callee, false);
let hudId = HUDService.getHudIdByWindow(content);
ok(hudId, "Web Console is open");
let HUD = HUDService.hudReferences[hudId];
ok(HUD.consolePanel, "Web Console opened in a panel");
isnot(HUD.consolePanel.label.indexOf("test1"), -1, "panel title is correct");
browser.addEventListener("load", function() {
browser.removeEventListener("load", arguments.callee, true);
isnot(HUD.consolePanel.label.indexOf("test2"), -1,
"panel title is correct after page navigation");
Services.prefs.clearUserPref(POSITION_PREF);
executeSoon(finish);
}, true);
content.location = "data:text/html,<p>test2 for bug 663443";
}, false);
}
function test() {
addTab(TEST_URI);
browser.addEventListener("load", tabLoad, true);
}

Просмотреть файл

@ -135,9 +135,9 @@ webConsolePositionBelow=Below
# Web Console interface is displayed in a floating panel.
webConsolePositionWindow=Window
# LOCALIZATION NOTE (webConsoleOwnWindowTitle): The Web Console floating panel
# title.
webConsoleOwnWindowTitle=Web Console
# LOCALIZATION NOTE (webConsoleWindowTitleAndURL): The Web Console floating
# panel title, followed by the web page URL.
webConsoleWindowTitleAndURL=Web Console - %S
# LOCALIZATION NOTE (Autocomplete.label):
# The autocomplete popup panel label/title.

Просмотреть файл

@ -90,6 +90,7 @@
margin-bottom: 3px;
-moz-margin-start: 3px;
-moz-margin-end: 6px;
white-space: pre-wrap;
}
.webconsole-msg-body-piece {

Просмотреть файл

@ -93,6 +93,7 @@
margin-bottom: 3px;
-moz-margin-start: 3px;
-moz-margin-end: 6px;
white-space: pre-wrap;
}
.webconsole-msg-body-piece {

Просмотреть файл

@ -89,6 +89,7 @@
margin-bottom: 3px;
-moz-margin-start: 3px;
-moz-margin-end: 6px;
white-space: pre-wrap;
}
.webconsole-msg-body-piece {