Merge central and inbound

This commit is contained in:
Marco Bonardo 2012-04-14 13:56:15 +02:00
commit be570c6dfc
27 changed files with 770 additions and 159 deletions

View File

@ -0,0 +1,301 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
/**
* The function that creates the root actor. DebuggerServer expects to find this
* function in the loaded actors in order to initialize properly.
*/
function createRootActor(connection) {
return new DeviceRootActor(connection);
}
/**
* Creates the root actor that client-server communications always start with.
* The root actor is responsible for the initial 'hello' packet and for
* responding to a 'listTabs' request that produces the list of currently open
* tabs.
*
* @param connection DebuggerServerConnection
* The conection to the client.
*/
function DeviceRootActor(connection) {
this.conn = connection;
this._tabActors = new WeakMap();
this._tabActorPool = null;
this._actorFactories = null;
this.browser = Services.wm.getMostRecentWindow('navigator:browser');
}
DeviceRootActor.prototype = {
/**
* Return a 'hello' packet as specified by the Remote Debugging Protocol.
*/
sayHello: function DRA_sayHello() {
return {
from: 'root',
applicationType: 'browser',
traits: []
};
},
/**
* Disconnects the actor from the browser window.
*/
disconnect: function DRA_disconnect() {
let actor = this._tabActors.get(this.browser);
if (actor) {
actor.exit();
}
},
/**
* Handles the listTabs request. Builds a list of actors for the single
* tab (window) running in the process. The actors will survive
* until at least the next listTabs request.
*/
onListTabs: function DRA_onListTabs() {
let actor = this._tabActors.get(this.browser);
if (!actor) {
actor = new DeviceTabActor(this.conn, this.browser);
// this.actorID is set by ActorPool when an actor is put into one.
actor.parentID = this.actorID;
this._tabActors.set(this.browser, actor);
}
let actorPool = new ActorPool(this.conn);
actorPool.addActor(actor);
// Now drop the old actorID -> actor map. Actors that still mattered were
// added to the new map, others will go away.
if (this._tabActorPool) {
this.conn.removeActorPool(this._tabActorPool);
}
this._tabActorPool = actorPool;
this.conn.addActorPool(this._tabActorPool);
return {
'from': 'root',
'selected': 0,
'tabs': [actor.grip()]
};
}
};
/**
* The request types this actor can handle.
*/
DeviceRootActor.prototype.requestTypes = {
'listTabs': DeviceRootActor.prototype.onListTabs
};
/**
* Creates a tab actor for handling requests to the single tab, like attaching
* and detaching.
*
* @param connection DebuggerServerConnection
* The connection to the client.
* @param browser browser
* The browser instance that contains this tab.
*/
function DeviceTabActor(connection, browser) {
this.conn = connection;
this._browser = browser;
}
DeviceTabActor.prototype = {
get browser() {
return this._browser;
},
get exited() {
return !this.browser;
},
get attached() {
return !!this._attached
},
_tabPool: null,
get tabActorPool() {
return this._tabPool;
},
_contextPool: null,
get contextActorPool() {
return this._contextPool;
},
actorPrefix: 'tab',
grip: function DTA_grip() {
dbg_assert(!this.exited,
'grip() should not be called on exited browser actor.');
dbg_assert(this.actorID,
'tab should have an actorID.');
return {
'actor': this.actorID,
'title': this.browser.contentTitle,
'url': this.browser.document.documentURI
}
},
/**
* Called when the actor is removed from the connection.
*/
disconnect: function DTA_disconnect() {
this._detach();
},
/**
* Called by the root actor when the underlying tab is closed.
*/
exit: function DTA_exit() {
if (this.exited) {
return;
}
if (this.attached) {
this._detach();
this.conn.send({
'from': this.actorID,
'type': 'tabDetached'
});
}
this._browser = null;
},
/**
* Does the actual work of attaching to a tab.
*/
_attach: function DTA_attach() {
if (this._attached) {
return;
}
// Create a pool for tab-lifetime actors.
dbg_assert(!this._tabPool, 'Should not have a tab pool if we were not attached.');
this._tabPool = new ActorPool(this.conn);
this.conn.addActorPool(this._tabPool);
// ... and a pool for context-lifetime actors.
this._pushContext();
this._attached = true;
},
/**
* Creates a thread actor and a pool for context-lifetime actors. It then sets
* up the content window for debugging.
*/
_pushContext: function DTA_pushContext() {
dbg_assert(!this._contextPool, "Can't push multiple contexts");
this._contextPool = new ActorPool(this.conn);
this.conn.addActorPool(this._contextPool);
this.threadActor = new ThreadActor(this);
this._addDebuggees(this.browser.content.wrappedJSObject);
this._contextPool.addActor(this.threadActor);
},
/**
* Add the provided window and all windows in its frame tree as debuggees.
*/
_addDebuggees: function DTA__addDebuggees(content) {
this.threadActor.addDebuggee(content);
let frames = content.frames;
for (let i = 0; i < frames.length; i++) {
this._addDebuggees(frames[i]);
}
},
/**
* Exits the current thread actor and removes the context-lifetime actor pool.
* The content window is no longer being debugged after this call.
*/
_popContext: function DTA_popContext() {
dbg_assert(!!this._contextPool, 'No context to pop.');
this.conn.removeActorPool(this._contextPool);
this._contextPool = null;
this.threadActor.exit();
this.threadActor = null;
},
/**
* Does the actual work of detaching from a tab.
*/
_detach: function DTA_detach() {
if (!this.attached) {
return;
}
this._popContext();
// Shut down actors that belong to this tab's pool.
this.conn.removeActorPool(this._tabPool);
this._tabPool = null;
this._attached = false;
},
// Protocol Request Handlers
onAttach: function DTA_onAttach(aRequest) {
if (this.exited) {
return { type: 'exited' };
}
this._attach();
return { type: 'tabAttached', threadActor: this.threadActor.actorID };
},
onDetach: function DTA_onDetach(aRequest) {
if (!this.attached) {
return { error: 'wrongState' };
}
this._detach();
return { type: 'detached' };
},
/**
* Prepare to enter a nested event loop by disabling debuggee events.
*/
preNest: function DTA_preNest() {
let windowUtils = this.browser.content
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.suppressEventHandling(true);
windowUtils.suspendTimeouts();
},
/**
* Prepare to exit a nested event loop by enabling debuggee events.
*/
postNest: function DTA_postNest(aNestData) {
let windowUtils = this.browser.content
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.resumeTimeouts();
windowUtils.suppressEventHandling(false);
}
};
/**
* The request types this actor can handle.
*/
DeviceTabActor.prototype.requestTypes = {
'attach': DeviceTabActor.prototype.onAttach,
'detach': DeviceTabActor.prototype.onDetach
};

View File

@ -45,6 +45,11 @@ XPCOMUtils.defineLazyServiceGetter(Services, 'fm', function() {
.getService(Ci.nsFocusManager);
});
XPCOMUtils.defineLazyGetter(this, 'DebuggerServer', function() {
Cu.import('resource://gre/modules/devtools/dbg-server.jsm');
return DebuggerServer;
});
// FIXME Bug 707625
// until we have a proper security model, add some rights to
// the pre-installed web applications
@ -541,3 +546,24 @@ var WebappsHelper = {
}
}
}
// Start the debugger server.
function startDebugger() {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addActors('chrome://browser/content/dbg-browser-actors.js');
}
let port = Services.prefs.getIntPref('devtools.debugger.port') || 6000;
try {
DebuggerServer.openListener(port, false);
} catch (e) {
dump('Unable to start debugger server: ' + e + '\n');
}
}
window.addEventListener('ContentStart', function(evt) {
if (Services.prefs.getBoolPref('devtools.debugger.enabled')) {
startDebugger();
}
}, false);

View File

@ -4,6 +4,7 @@ chrome.jar:
% content branding %content/branding/
% content browser %content/
content/dbg-browser-actors.js (content/dbg-browser-actors.js)
* content/shell.xul (content/shell.xul)
* content/shell.js (content/shell.js)
#ifndef MOZ_TOUCH

View File

@ -8,7 +8,7 @@
* Keeps thumbnails of open web pages up-to-date.
*/
let gBrowserThumbnails = {
_captureDelayMS: 2000,
_captureDelayMS: 1000,
/**
* Map of capture() timeouts assigned to their browsers.
@ -98,6 +98,11 @@ let gBrowserThumbnails = {
},
_shouldCapture: function Thumbnails_shouldCapture(aBrowser) {
// Capture only if it's the currently selected tab.
if (aBrowser != gBrowser.selectedBrowser)
return false;
// Don't capture in private browsing mode.
if (gPrivateBrowsingUI.privateBrowsingEnabled)
return false;

View File

@ -49,20 +49,29 @@
-moz-transition-timing-function: linear;
}
#highlighter-nodeinfobar {
display: block;
white-space: nowrap;
direction: ltr;
#highlighter-nodeinfobar-text {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
direction: ltr;
}
#highlighter-nodeinfobar-container[locked] > #highlighter-nodeinfobar {
.highlighter-nodeinfobar-button > .toolbarbutton-text {
display: none;
}
#highlighter-nodeinfobar-container:not([locked]):not(:hover) > #highlighter-nodeinfobar > .highlighter-nodeinfobar-button {
visibility: hidden;
}
#highlighter-nodeinfobar-container[locked] > #highlighter-nodeinfobar,
#highlighter-nodeinfobar-container:not([locked]):hover > #highlighter-nodeinfobar {
pointer-events: auto;
}
html|*#highlighter-nodeinfobar-id,
html|*#highlighter-nodeinfobar-classes,
html|*#highlighter-nodeinfobar-pseudo-classes,
html|*#highlighter-nodeinfobar-tagname {
-moz-user-select: text;
cursor: text;

View File

@ -119,10 +119,13 @@ Site.prototype = {
* Renders the site's data (fills the HTML fragment).
*/
_render: function Site_render() {
let title = this.title || this.url;
let url = this.url;
let title = this.title || url;
let tooltip = (title == url ? title : title + "\n" + url);
let link = this._querySelector(".newtab-link");
link.setAttribute("title", title);
link.setAttribute("href", this.url);
link.setAttribute("title", tooltip);
link.setAttribute("href", url);
this._querySelector(".newtab-title").textContent = title;
if (this.isPinned())

View File

@ -20,6 +20,7 @@ _BROWSER_FILES = \
browser_newtab_reset.js \
browser_newtab_tabsync.js \
browser_newtab_unpin.js \
browser_newtab_bug721442.js \
browser_newtab_bug722273.js \
browser_newtab_bug723102.js \
browser_newtab_bug723121.js \

View File

@ -0,0 +1,23 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function runTests() {
setLinks("0,1,2,3,4,5,6,7,8");
NewTabUtils.pinnedLinks._links = [
{url: "about:blank#7", title: ""},
{url: "about:blank#8", title: "title"},
{url: "about:blank#9", title: "about:blank#9"}
];
yield addNewTabPageTab();
checkGrid("7p,8p,9p,0,1,2,3,4,5");
checkTooltip(0, "about:blank#7", "1st tooltip is correct");
checkTooltip(1, "title\nabout:blank#8", "2nd tooltip is correct");
checkTooltip(2, "about:blank#9", "3rd tooltip is correct");
}
function checkTooltip(aIndex, aExpected, aMessage) {
let link = getCell(aIndex).node.querySelector(".newtab-link");
is(link.getAttribute("title"), aExpected, aMessage);
}

View File

@ -194,7 +194,7 @@ function addNewTabPageTab() {
function checkGrid(aSitesPattern, aSites) {
let length = aSitesPattern.split(",").length;
let sites = (aSites || getGrid().sites).slice(0, length);
let expected = sites.map(function (aSite) {
let current = sites.map(function (aSite) {
if (!aSite)
return "";
@ -208,7 +208,7 @@ function checkGrid(aSitesPattern, aSites) {
return aSite.url.replace(/^about:blank#(\d+)$/, "$1") + (pinned ? "p" : "");
});
is(aSitesPattern, expected, "grid status = " + aSitesPattern);
is(current, aSitesPattern, "grid status = " + aSitesPattern);
}
/**

View File

@ -0,0 +1,141 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
let FavIcons = {
// Pref that controls whether to display site icons.
PREF_CHROME_SITE_ICONS: "browser.chrome.site_icons",
// Pref that controls whether to display fav icons.
PREF_CHROME_FAVICONS: "browser.chrome.favicons",
// Lazy getter for pref browser.chrome.site_icons.
get _prefSiteIcons() {
delete this._prefSiteIcons;
this._prefSiteIcons = Services.prefs.getBoolPref(this.PREF_CHROME_SITE_ICONS);
},
// Lazy getter for pref browser.chrome.favicons.
get _prefFavicons() {
delete this._prefFavicons;
this._prefFavicons = Services.prefs.getBoolPref(this.PREF_CHROME_FAVICONS);
},
get defaultFavicon() this._favIconService.defaultFavicon.spec,
init: function FavIcons_init() {
XPCOMUtils.defineLazyServiceGetter(this, "_favIconService",
"@mozilla.org/browser/favicon-service;1", "nsIFaviconService");
Services.prefs.addObserver(this.PREF_CHROME_SITE_ICONS, this, false);
Services.prefs.addObserver(this.PREF_CHROME_FAVICONS, this, false);
},
uninit: function FavIcons_uninit() {
Services.prefs.removeObserver(this.PREF_CHROME_SITE_ICONS, this);
Services.prefs.removeObserver(this.PREF_CHROME_FAVICONS, this);
},
observe: function FavIcons_observe(subject, topic, data) {
let value = Services.prefs.getBoolPref(data);
if (data == this.PREF_CHROME_SITE_ICONS)
this._prefSiteIcons = value;
else if (data == this.PREF_CHROME_FAVICONS)
this._prefFavicons = value;
},
// ----------
// Function: getFavIconUrlForTab
// Gets the "favicon link URI" for the given xul:tab, or null if unavailable.
getFavIconUrlForTab: function FavIcons_getFavIconUrlForTab(tab, callback) {
this._isImageDocument(tab, function (isImageDoc) {
if (isImageDoc) {
callback(tab.pinned ? tab.image : null);
} else {
this._getFavIconForNonImageDocument(tab, callback);
}
}.bind(this));
},
// ----------
// Function: _getFavIconForNonImageDocument
// Retrieves the favicon for a tab containing a non-image document.
_getFavIconForNonImageDocument:
function FavIcons_getFavIconForNonImageDocument(tab, callback) {
if (tab.image)
this._getFavIconFromTabImage(tab, callback);
else if (this._shouldLoadFavIcon(tab))
this._getFavIconForHttpDocument(tab, callback);
else
callback(null);
},
// ----------
// Function: _getFavIconFromTabImage
// Retrieves the favicon for tab with a tab image.
_getFavIconFromTabImage:
function FavIcons_getFavIconFromTabImage(tab, callback) {
let tabImage = tab.image;
// If the tab image's url starts with http(s), fetch icon from favicon
// service via the moz-anno protocol.
if (/^https?:/.test(tabImage)) {
let tabImageURI = gWindow.makeURI(tabImage);
tabImage = this._favIconService.getFaviconLinkForIcon(tabImageURI).spec;
}
callback(tabImage);
},
// ----------
// Function: _getFavIconForHttpDocument
// Retrieves the favicon for tab containg a http(s) document.
_getFavIconForHttpDocument:
function FavIcons_getFavIconForHttpDocument(tab, callback) {
let {currentURI} = tab.linkedBrowser;
this._favIconService.getFaviconURLForPage(currentURI, function (uri) {
if (uri) {
callback(this._favIconService.getFaviconLinkForIcon(uri).spec);
} else {
callback(this.defaultFavicon);
}
}.bind(this));
},
// ----------
// Function: _isImageDocument
// Checks whether an image is loaded into the given tab.
_isImageDocument: function UI__isImageDocument(tab, callback) {
let mm = tab.linkedBrowser.messageManager;
let message = "Panorama:isImageDocument";
mm.addMessageListener(message, function onMessage(cx) {
mm.removeMessageListener(cx.name, onMessage);
callback(cx.json.isImageDocument);
});
mm.sendAsyncMessage(message);
},
// ----------
// Function: _shouldLoadFavIcon
// Checks whether fav icon should be loaded for a given tab.
_shouldLoadFavIcon: function FavIcons_shouldLoadFavIcon(tab) {
// No need to load a favicon if the user doesn't want site or favicons.
if (!this._prefSiteIcons || !this._prefFavicons)
return false;
let uri = tab.linkedBrowser.currentURI;
// Stop here if we don't have a valid nsIURI.
if (!uri || !(uri instanceof Ci.nsIURI))
return false;
// Load favicons for http(s) pages only.
return uri.schemeIs("http") || uri.schemeIs("https");
}
};

View File

@ -2107,8 +2107,8 @@ let GroupItems = {
// Function: getAppTabFavIconUrl
// Gets the fav icon url for app tab.
getAppTabFavIconUrl: function GroupItems_getAppTabFavIconUrl(xulTab, callback) {
UI.getFavIconUrlForTab(xulTab, function GroupItems_getAppTabFavIconUrl_getFavIconUrlForTab(iconUrl) {
callback(iconUrl || gFavIconService.defaultFavicon.spec);
FavIcons.getFavIconUrlForTab(xulTab, function GroupItems_getAppTabFavIconUrl_getFavIconUrlForTab(iconUrl) {
callback(iconUrl || FavIcons.defaultFavicon);
});
},

View File

@ -1010,7 +1010,7 @@ let TabItems = {
// Even if the page hasn't loaded, display the favicon and title
// ___ icon
UI.getFavIconUrlForTab(tab, function TabItems__update_getFavIconUrlCallback(iconUrl) {
FavIcons.getFavIconUrlForTab(tab, function TabItems__update_getFavIconUrlCallback(iconUrl) {
let favImage = tabItem.$favImage[0];
let fav = tabItem.$fav;
if (iconUrl) {

View File

@ -30,11 +30,6 @@ XPCOMUtils.defineLazyGetter(this, "gPrivateBrowsing", function() {
getService(Ci.nsIPrivateBrowsingService);
});
XPCOMUtils.defineLazyGetter(this, "gFavIconService", function() {
return Cc["@mozilla.org/browser/favicon-service;1"].
getService(Ci.nsIFaviconService);
});
XPCOMUtils.defineLazyGetter(this, "gNetUtil", function() {
var obj = {};
Cu.import("resource://gre/modules/NetUtil.jsm", obj);
@ -80,6 +75,7 @@ let AllTabs = {
#include items.js
#include groupitems.js
#include tabitems.js
#include favicons.js
#include drag.js
#include trench.js
#include thumbnailStorage.js

View File

@ -51,12 +51,6 @@ let Keys = { meta: false };
// Class: UI
// Singleton top-level UI manager.
let UI = {
// Pref that controls whether to display site icons
PREF_CHROME_SITE_ICONS: "browser.chrome.site_icons",
// Pref that controls whether to display fav icons
PREF_CHROME_FAVICONS: "browser.chrome.favicons",
// Variable: _frameInitialized
// True if the Tab View UI frame has been initialized.
_frameInitialized: false,
@ -147,12 +141,6 @@ let UI = {
// Used to keep track of the tab strip smooth scroll value.
_originalSmoothScroll: null,
// Used to keep track of the browser.chrome.site_icons pref value.
_prefSiteIcons: null,
// Used to keep track of the browser.chrome.favicons pref value.
_prefFavicons: null,
// ----------
// Function: toString
// Prints [UI] for debug use
@ -253,10 +241,6 @@ let UI = {
// ___ add tab action handlers
this._addTabActionHandlers();
// ___ add preference observers
Services.prefs.addObserver(this.PREF_CHROME_SITE_ICONS, this, false);
Services.prefs.addObserver(this.PREF_CHROME_FAVICONS, this, false);
// ___ groups
GroupItems.init();
GroupItems.pauseArrange();
@ -266,6 +250,9 @@ let UI = {
TabItems.init();
TabItems.pausePainting();
// ___ favicons
FavIcons.init();
if (!hasGroupItemsData)
this.reset();
@ -330,12 +317,10 @@ let UI = {
// additional clean up
TabItems.uninit();
GroupItems.uninit();
FavIcons.uninit();
Storage.uninit();
StoragePolicy.uninit();
Services.prefs.removeObserver(this.PREF_CHROME_SITE_ICONS, this);
Services.prefs.removeObserver(this.PREF_CHROME_FAVICONS, this);
this._removeTabActionHandlers();
this._currentTab = null;
this._pageBounds = null;
@ -873,19 +858,6 @@ let UI = {
AllTabs.unregister(name, this._eventListeners[name]);
},
// ----------
// Function: observe
// Observes different preference value changes.
observe: function UI_observe(subject, topic, data) {
if (data == this.PREF_CHROME_SITE_ICONS) {
this._prefSiteIcons =
Services.prefs.getBoolPref(this.PREF_CHROME_SITE_ICONS);
} else if (data == this.PREF_CHROME_FAVICONS) {
this._prefFavicons =
Services.prefs.getBoolPref(this.PREF_CHROME_FAVICONS);
}
},
// ----------
// Function: goToTab
// Selects the given xul:tab in the browser.
@ -1655,79 +1627,6 @@ let UI = {
TabItems.saveAll();
},
// ----------
// Function: _isImageDocument
// Checks whether an image is loaded into the given tab.
_isImageDocument: function UI__isImageDocument(tab, callback) {
let mm = tab.linkedBrowser.messageManager;
let message = "Panorama:isImageDocument";
mm.addMessageListener(message, function onMessage(cx) {
mm.removeMessageListener(cx.name, onMessage);
callback(cx.json.isImageDocument);
});
mm.sendAsyncMessage(message);
},
// ----------
// Function: _shouldLoadFavIcon
// Checks whether fav icon should be loaded for a given tab.
_shouldLoadFavIcon: function UI__shouldLoadFavIcon(tab) {
let uri = tab.linkedBrowser.currentURI;
if (!uri)
return false;
if (this._prefSiteIcons == null)
this._prefSiteIcons =
Services.prefs.getBoolPref(this.PREF_CHROME_SITE_ICONS);
if (!this._prefSiteIcons)
return false;
if (this._prefFavicons == null)
this._prefFavicons =
Services.prefs.getBoolPref(this.PREF_CHROME_FAVICONS);
return (this._prefFavicons && ("schemeIs" in uri) &&
(uri.schemeIs("http") || uri.schemeIs("https")));
},
// ----------
// Function: getFavIconUrlForTab
// Gets the "favicon link URI" for the given xul:tab, or null if unavailable.
getFavIconUrlForTab: function UI_getFavIconUrlForTab(tab, callback) {
this._isImageDocument(tab, function(isImageDoc) {
if (isImageDoc) {
callback(tab.pinned ? tab.image : null);
} else {
let tabImage = tab.image;
if (tabImage) {
// if starts with http/https, fetch icon from favicon service via the moz-anno protocal
if (/^https?:/.test(tabImage))
tabImage = gFavIconService.getFaviconLinkForIcon(gWindow.makeURI(tab.image)).spec;
callback(tabImage);
} else {
// ensure we don't show the default icon for about:-style error pages
if (!this._shouldLoadFavIcon(tab)) {
callback(null);
} else {
// determine to load the default/cached icon or not
gFavIconService.getFaviconURLForPage(tab.linkedBrowser.currentURI,
function (uri) {
if (!uri) {
callback(gFavIconService.defaultFavicon.spec);
} else {
callback(gFavIconService.getFaviconLinkForIcon(uri).spec);
}
});
}
}
}
}.bind(this));
},
// ----------
// Function: notifySessionRestoreEnabled
// Notify the user that session restore has been automatically enabled

View File

@ -46,6 +46,7 @@ const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@ -77,7 +78,7 @@ const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
*
* // Constructor and destructor.
* // @param aWindow - browser.xul window.
* Highlighter(aWindow);
* Highlighter(aWindow);
* void destroy();
*
* // Highlight a node.
@ -253,7 +254,7 @@ Highlighter.prototype = {
* @param aPseudo - The pseudo-class to toggle, e.g. ":hover".
*/
pseudoClassLockToggled: function Highlighter_pseudoClassLockToggled(aPseudo)
{
{
this.emitEvent("pseudoclasstoggled", [aPseudo]);
this.updateInfobar();
},
@ -430,9 +431,14 @@ Highlighter.prototype = {
* <box id="highlighter-nodeinfobar-container">
* <box id="Highlighter-nodeinfobar-arrow-top"/>
* <hbox id="highlighter-nodeinfobar">
* <xhtml:span id="highlighter-nodeinfobar-tagname"/>
* <xhtml:span id="highlighter-nodeinfobar-id"/>
* <xhtml:span id="highlighter-nodeinfobar-classes"/>
* <toolbarbutton class="highlighter-nodeinfobar-button" id="highlighter-nodeinfobar-inspectbutton"/>
* <hbox id="highlighter-nodeinfobar-text">
* <xhtml:span id="highlighter-nodeinfobar-tagname"/>
* <xhtml:span id="highlighter-nodeinfobar-id"/>
* <xhtml:span id="highlighter-nodeinfobar-classes"/>
* <xhtml:span id="highlighter-nodeinfobar-pseudo-classes"/>
* </hbox>
* <toolbarbutton class="highlighter-nodeinfobar-button" id="highlighter-nodeinfobar-menu"/>
* </hbox>
* <box id="Highlighter-nodeinfobar-arrow-bottom"/>
* </box>
@ -466,17 +472,52 @@ Highlighter.prototype = {
let classesBox = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "span");
classesBox.id = "highlighter-nodeinfobar-classes";
let pseudoClassesBox = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "span");
pseudoClassesBox.id = "highlighter-nodeinfobar-pseudo-classes";
// Add some content to force a better boundingClientRect down below.
pseudoClassesBox.textContent = "&nbsp;";
nodeInfobar.appendChild(tagNameLabel);
nodeInfobar.appendChild(idLabel);
nodeInfobar.appendChild(classesBox);
nodeInfobar.appendChild(pseudoClassesBox);
// Create buttons
let inspect = this.chromeDoc.createElement("toolbarbutton");
inspect.id = "highlighter-nodeinfobar-inspectbutton";
inspect.className = "highlighter-nodeinfobar-button"
let toolbarInspectButton =
this.chromeDoc.getElementById("inspector-inspect-toolbutton");
inspect.setAttribute("tooltiptext",
toolbarInspectButton.getAttribute("tooltiptext"));
inspect.setAttribute("command", "Inspector:Inspect");
let nodemenu = this.chromeDoc.createElement("toolbarbutton");
nodemenu.setAttribute("type", "menu");
nodemenu.id = "highlighter-nodeinfobar-menu";
nodemenu.className = "highlighter-nodeinfobar-button"
nodemenu.setAttribute("tooltiptext",
this.strings.GetStringFromName("nodeMenu.tooltiptext"));
let menu = this.chromeDoc.getElementById("inspector-node-popup");
menu = menu.cloneNode(true);
menu.id = "highlighter-node-menu";
nodemenu.appendChild(menu);
// <hbox id="highlighter-nodeinfobar-text"/>
let texthbox = this.chromeDoc.createElement("hbox");
texthbox.id = "highlighter-nodeinfobar-text";
texthbox.setAttribute("align", "center");
texthbox.setAttribute("flex", "1");
texthbox.appendChild(tagNameLabel);
texthbox.appendChild(idLabel);
texthbox.appendChild(classesBox);
texthbox.appendChild(pseudoClassesBox);
nodeInfobar.appendChild(inspect);
nodeInfobar.appendChild(texthbox);
nodeInfobar.appendChild(nodemenu);
container.appendChild(arrowBoxTop);
container.appendChild(nodeInfobar);
container.appendChild(arrowBoxBottom);
@ -511,13 +552,13 @@ Highlighter.prototype = {
let popupSet = this.chromeDoc.getElementById("mainPopupSet");
popupSet.appendChild(menu);
let fragment = this.buildPseudoClassMenu();
menu.appendChild(fragment);
menu.openPopup(this.nodeInfo.pseudoClassesBox, "end_before", 0, 0, true, false);
},
},
/**
* Create the menuitems for toggling the selection's pseudo-class state
*
@ -887,3 +928,9 @@ Highlighter.prototype = {
XPCOMUtils.defineLazyGetter(this, "DOMUtils", function () {
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils)
});
XPCOMUtils.defineLazyGetter(Highlighter.prototype, "strings",
function () {
return Services.strings.createBundle(
"chrome://browser/locale/devtools/inspector.properties");
});

View File

@ -32,3 +32,9 @@ ruleView.tooltiptext=View and Edit CSS
# "Return" key # changes that state. %S is the keyboard shortcut (VK_RETURN in
# chrome://global/locale/keys.properties).
inspectButton.tooltiptext=Select element with mouse (%S)
# LOCALIZATION NOTE (nodeMenu.tooltiptext)
# This menu appears in the Infobar (on top of the highlighted node) once
# the node is selected.
nodeMenu.tooltiptext=Node operations

View File

@ -2036,8 +2036,21 @@ panel[dimmed="true"] {
/* Highlighter - Node Infobar */
#highlighter-nodeinfobar {
color: hsl(200, 100%, 65%);
border: 1px solid hsla(210, 19%, 63%, .5);
border-radius: 3px;
background: -moz-linear-gradient(hsl(209, 18%, 30%), hsl(210, 24%, 16%)) no-repeat padding-box;
}
/* Highlighter - Node Infobar - text */
#highlighter-nodeinfobar-text {
/* 100% - size of the buttons and margins */
max-width: -moz-calc(100% - 2 * (26px + 6px));
padding-bottom: 1px;
}
html|*#highlighter-nodeinfobar-tagname {
color: white;
}
@ -2050,16 +2063,52 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
color: hsl(20, 100%, 70%);
}
/* Highlighter - Node Infobar - box & arrow */
/* Highlighter - Node Infobar - buttons */
#highlighter-nodeinfobar {
color: hsl(200, 100%, 65%);
border: 1px solid hsla(210, 19%, 63%, .5);
border-radius: 3px;
padding: 8px 16px;
background: -moz-linear-gradient(hsl(209, 18%, 30%), hsl(210, 24%, 16%)) no-repeat padding-box;
.highlighter-nodeinfobar-button {
-moz-appearance: none;
border: 0 solid hsla(210,8%,5%,.45);
padding: 0;
width: 26px;
min-height: 26px;
}
#highlighter-nodeinfobar-inspectbutton {
-moz-border-end-width: 1px;
box-shadow: 1px 0 0 hsla(210,16%,76%,.15), -1px 0 0 hsla(210,16%,76%,.15) inset;
-moz-margin-end: 6px;
list-style-image: url("chrome://browser/skin/devtools/inspect-button.png");
-moz-image-region: rect(0px 16px 16px 0px);
}
#highlighter-nodeinfobar-inspectbutton:-moz-locale-dir(rtl) {
box-shadow: -1px 0 0 hsla(210,16%,76%,.15), 1px 0 0 hsla(210,16%,76%,.15) inset;
}
#highlighter-nodeinfobar-inspectbutton:active:hover,
#highlighter-nodeinfobar-container:not([locked]) > #highlighter-nodeinfobar > #highlighter-nodeinfobar-inspectbutton {
-moz-image-region: rect(0px 32px 16px 16px);
}
#highlighter-nodeinfobar-menu {
-moz-border-start-width: 1px;
box-shadow: -1px 0 0 hsla(210,16%,76%,.15), 1px 0 0 hsla(210,16%,76%,.15) inset;
-moz-margin-start: 6px;
}
#highlighter-nodeinfobar-menu:-moz-locale-dir(rtl) {
box-shadow: 1px 0 0 hsla(210,16%,76%,.15), -1px 0 0 hsla(210,16%,76%,.15) inset;
}
#highlighter-nodeinfobar-menu > .toolbarbutton-menu-dropmarker {
-moz-appearance: none !important;
list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
-moz-box-align: center;
-moz-margin-start: -1px;
}
/* Highlighter - Node Infobar - box & arrow */
.highlighter-nodeinfobar-arrow {
width: 14px;
height: 14px;

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View File

@ -131,6 +131,7 @@ browser.jar:
skin/classic/browser/devtools/itemArrow-rtl.png (devtools/itemArrow-rtl.png)
skin/classic/browser/devtools/itemArrow-ltr.png (devtools/itemArrow-ltr.png)
skin/classic/browser/devtools/inspect-button.png (devtools/inspect-button.png)
skin/classic/browser/devtools/dropmarker.png (devtools/dropmarker.png)
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/sync-16-throbber.png
skin/classic/browser/sync-16.png

View File

@ -2781,8 +2781,21 @@ panel[dimmed="true"] {
/* Highlighter - Node Infobar */
#highlighter-nodeinfobar {
color: hsl(200, 100%, 65%);
border: 1px solid hsla(210, 19%, 63%, .5);
border-radius: 3px;
background: -moz-linear-gradient(hsl(209, 18%, 30%), hsl(210, 24%, 16%)) no-repeat padding-box;
}
/* Highlighter - Node Infobar - text */
#highlighter-nodeinfobar-text {
/* 100% - size of the buttons + margins */
max-width: -moz-calc(100% - 2 * (26px + 6px));
padding-bottom: 1px;
}
html|*#highlighter-nodeinfobar-tagname {
color: white;
}
@ -2795,16 +2808,52 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
color: hsl(20, 100%, 70%);
}
/* Highlighter - Node Infobar - box & arrow */
/* Highlighter - Node Infobar - buttons */
#highlighter-nodeinfobar {
color: hsl(200, 100%, 65%);
border: 1px solid hsla(210, 19%, 63%, .5);
border-radius: 3px;
padding: 8px 16px;
background: -moz-linear-gradient(hsl(209, 18%, 30%), hsl(210, 24%, 16%)) no-repeat padding-box;
.highlighter-nodeinfobar-button {
-moz-appearance: none;
border: 0 solid hsla(210,8%,5%,.45);
padding: 0;
width: 26px;
min-height: 26px;
}
#highlighter-nodeinfobar-inspectbutton {
-moz-border-end-width: 1px;
box-shadow: 1px 0 0 hsla(210,16%,76%,.15), -1px 0 0 hsla(210,16%,76%,.15) inset;
-moz-margin-end: 6px;
list-style-image: url("chrome://browser/skin/devtools/inspect-button.png");
-moz-image-region: rect(0px 16px 16px 0px);
}
#highlighter-nodeinfobar-inspectbutton:-moz-locale-dir(rtl) {
box-shadow: -1px 0 0 hsla(210,16%,76%,.15), 1px 0 0 hsla(210,16%,76%,.15) inset;
}
#highlighter-nodeinfobar-inspectbutton:active:hover,
#highlighter-nodeinfobar-container:not([locked]) > #highlighter-nodeinfobar > #highlighter-nodeinfobar-inspectbutton {
-moz-image-region: rect(0px 32px 16px 16px);
}
#highlighter-nodeinfobar-menu {
-moz-border-start-width: 1px;
box-shadow: -1px 0 0 hsla(210,16%,76%,.15), 1px 0 0 hsla(210,16%,76%,.15) inset;
-moz-margin-start: 6px;
}
#highlighter-nodeinfobar-menu:-moz-locale-dir(rtl) {
box-shadow: 1px 0 0 hsla(210,16%,76%,.15), -1px 0 0 hsla(210,16%,76%,.15) inset;
}
#highlighter-nodeinfobar-menu > .toolbarbutton-menu-dropmarker {
-moz-appearance: none !important;
list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
-moz-box-align: center;
-moz-margin-start: -1px;
}
/* Highlighter - Node Infobar - box & arrow */
.highlighter-nodeinfobar-arrow {
width: 14px;
height: 14px;

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View File

@ -172,6 +172,7 @@ browser.jar:
skin/classic/browser/devtools/itemArrow-ltr.png (devtools/itemArrow-ltr.png)
skin/classic/browser/devtools/background-noise-toolbar.png (devtools/background-noise-toolbar.png)
skin/classic/browser/devtools/inspect-button.png (devtools/inspect-button.png)
skin/classic/browser/devtools/dropmarker.png (devtools/dropmarker.png)
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/sync-throbber.png
skin/classic/browser/sync-16.png

View File

@ -2703,8 +2703,21 @@ panel[dimmed="true"] {
/* Highlighter - Node Infobar */
#highlighter-nodeinfobar {
color: hsl(200, 100%, 65%);
border: 1px solid hsla(210, 19%, 63%, .5);
border-radius: 3px;
background: -moz-linear-gradient(hsl(209, 18%, 30%), hsl(210, 24%, 16%)) no-repeat padding-box;
}
/* Highlighter - Node Infobar - text */
#highlighter-nodeinfobar-text {
/* 100% - size of the buttons and margins */
max-width: -moz-calc(100% - 2 * (26px + 6px));
padding-bottom: 1px;
}
html|*#highlighter-nodeinfobar-tagname {
color: white;
}
@ -2717,16 +2730,52 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
color: hsl(20, 100%, 70%);
}
/* Highlighter - Node Infobar - box & arrow */
/* Highlighter - Node Infobar - buttons */
#highlighter-nodeinfobar {
color: hsl(200, 100%, 65%);
border: 1px solid hsla(210, 19%, 63%, .5);
border-radius: 3px;
padding: 8px 16px;
background: -moz-linear-gradient(hsl(209, 18%, 30%), hsl(210, 24%, 16%)) no-repeat padding-box;
.highlighter-nodeinfobar-button {
-moz-appearance: none;
border: 0 solid hsla(210,8%,5%,.45);
padding: 0;
width: 26px;
min-height: 26px;
}
#highlighter-nodeinfobar-inspectbutton {
-moz-border-end-width: 1px;
box-shadow: 1px 0 0 hsla(210,16%,76%,.15), -1px 0 0 hsla(210,16%,76%,.15) inset;
-moz-margin-end: 6px;
list-style-image: url("chrome://browser/skin/devtools/inspect-button.png");
-moz-image-region: rect(0px 16px 16px 0px);
}
#highlighter-nodeinfobar-inspectbutton:-moz-locale-dir(rtl) {
box-shadow: -1px 0 0 hsla(210,16%,76%,.15), 1px 0 0 hsla(210,16%,76%,.15) inset;
}
#highlighter-nodeinfobar-inspectbutton:active:hover,
#highlighter-nodeinfobar-container:not([locked]) > #highlighter-nodeinfobar > #highlighter-nodeinfobar-inspectbutton {
-moz-image-region: rect(0px 32px 16px 16px);
}
#highlighter-nodeinfobar-menu {
-moz-border-start-width: 1px;
box-shadow: -1px 0 0 hsla(210,16%,76%,.15), 1px 0 0 hsla(210,16%,76%,.15) inset;
-moz-margin-start: 6px;
}
#highlighter-nodeinfobar-menu:-moz-locale-dir(rtl) {
box-shadow: 1px 0 0 hsla(210,16%,76%,.15), -1px 0 0 hsla(210,16%,76%,.15) inset;
}
#highlighter-nodeinfobar-menu > .toolbarbutton-menu-dropmarker {
-moz-appearance: none !important;
list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
-moz-box-align: center;
-moz-margin-start: -1px;
}
/* Highlighter - Node Infobar - box & arrow */
.highlighter-nodeinfobar-arrow {
width: 14px;
height: 14px;

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View File

@ -158,6 +158,7 @@ browser.jar:
skin/classic/browser/devtools/itemArrow-rtl.png (devtools/itemArrow-rtl.png)
skin/classic/browser/devtools/itemArrow-ltr.png (devtools/itemArrow-ltr.png)
skin/classic/browser/devtools/inspect-button.png (devtools/inspect-button.png)
skin/classic/browser/devtools/dropmarker.png (devtools/dropmarker.png)
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/sync-throbber.png
skin/classic/browser/sync-16.png
@ -331,6 +332,7 @@ browser.jar:
skin/classic/aero/browser/devtools/itemArrow-rtl.png (devtools/itemArrow-rtl.png)
skin/classic/aero/browser/devtools/itemArrow-ltr.png (devtools/itemArrow-ltr.png)
skin/classic/aero/browser/devtools/inspect-button.png (devtools/inspect-button.png)
skin/classic/aero/browser/devtools/dropmarker.png (devtools/dropmarker.png)
#ifdef MOZ_SERVICES_SYNC
skin/classic/aero/browser/sync-throbber.png
skin/classic/aero/browser/sync-16.png

View File

@ -8936,6 +8936,7 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
// success!
NS_ENSURE_TRUE(domReturn, NS_OK);
domReturn.swap(*aReturn);
if (aDoJSFixups) {

View File

@ -60,6 +60,7 @@
#include "nsString.h"
#include "nsToolkit.h"
#include "WinUtils.h"
#include "nsPIDOMWindow.h"
using namespace mozilla::widget;