This commit is contained in:
Ryan VanderMeulen 2013-01-25 09:59:09 -05:00
Родитель c8c186ac5c 7c23e6514e
Коммит 6b6ad4faae
29 изменённых файлов: 704 добавлений и 110 удалений

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

@ -18,6 +18,19 @@ input[type=button] {
overflow: auto;
}
/* UNDO */
#newtab-undo-container {
transition: opacity 100ms ease-out;
display: -moz-box;
-moz-box-align: center;
-moz-box-pack: center;
}
#newtab-undo-container[undo-disabled] {
opacity: 0;
pointer-events: none;
}
/* TOGGLE */
#newtab-toggle {
position: absolute;
@ -41,7 +54,10 @@ input[type=button] {
#newtab-margin-top {
min-height: 50px;
max-height: 80px;
display: -moz-box;
-moz-box-flex: 1;
-moz-box-align: center;
-moz-box-pack: center;
}
#newtab-margin-bottom {

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

@ -51,6 +51,7 @@ const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
#include dropTargetShim.js
#include dropPreview.js
#include updater.js
#include undo.js
// Everything is loaded. Initialize the New Tab Page.
gPage.init();

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

@ -20,7 +20,20 @@
<div id="newtab-scrollbox">
<div id="newtab-vertical-margin">
<div id="newtab-margin-top"/>
<div id="newtab-margin-top">
<div id="newtab-undo-container" undo-disabled="true">
<xul:label id="newtab-undo-label"
value="&newtab.undo.removedLabel;" />
<xul:button id="newtab-undo-button" tabindex="-1"
label="&newtab.undo.undoButton;"
class="newtab-undo-button" />
<xul:button id="newtab-undo-restore-button" tabindex="-1"
label="&newtab.undo.restoreButton;"
class="newtab-undo-button" />
<xul:toolbarbutton id="newtab-undo-close-button" tabindex="-1"
title="&newtab.undo.closeTooltip;" />
</div>
</div>
<div id="newtab-horizontal-margin">
<div class="newtab-side-margin"/>

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

@ -39,8 +39,11 @@ let gPage = {
this._updateAttributes(enabled);
// Initialize the whole page if we haven't done that, yet.
if (enabled)
if (enabled) {
this._init();
} else {
gUndoDialog.hide();
}
},
/**

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

@ -84,6 +84,7 @@ Site.prototype = {
*/
block: function Site_block() {
if (!gBlockedLinks.isBlocked(this._link)) {
gUndoDialog.show(this);
gBlockedLinks.block(this._link);
gUpdater.updateGrid();
}

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

@ -0,0 +1,116 @@
#ifdef 0
/* 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/. */
#endif
/**
* Dialog allowing to undo the removal of single site or to completely restore
* the grid's original state.
*/
let gUndoDialog = {
/**
* The undo dialog's timeout in miliseconds.
*/
HIDE_TIMEOUT_MS: 15000,
/**
* Contains undo information.
*/
_undoData: null,
/**
* Initializes the undo dialog.
*/
init: function UndoDialog_init() {
this._undoContainer = document.getElementById("newtab-undo-container");
this._undoContainer.addEventListener("click", this, false);
this._undoButton = document.getElementById("newtab-undo-button");
this._undoCloseButton = document.getElementById("newtab-undo-close-button");
this._undoRestoreButton = document.getElementById("newtab-undo-restore-button");
},
/**
* Shows the undo dialog.
* @param aSite The site that just got removed.
*/
show: function UndoDialog_show(aSite) {
if (this._undoData)
clearTimeout(this._undoData.timeout);
this._undoData = {
index: aSite.cell.index,
wasPinned: aSite.isPinned(),
blockedLink: aSite.link,
timeout: setTimeout(this.hide.bind(this), this.HIDE_TIMEOUT_MS)
};
this._undoContainer.removeAttribute("undo-disabled");
this._undoButton.removeAttribute("tabindex");
this._undoCloseButton.removeAttribute("tabindex");
this._undoRestoreButton.removeAttribute("tabindex");
},
/**
* Hides the undo dialog.
*/
hide: function UndoDialog_hide() {
if (!this._undoData)
return;
clearTimeout(this._undoData.timeout);
this._undoData = null;
this._undoContainer.setAttribute("undo-disabled", "true");
this._undoButton.setAttribute("tabindex", "-1");
this._undoCloseButton.setAttribute("tabindex", "-1");
this._undoRestoreButton.setAttribute("tabindex", "-1");
},
/**
* The undo dialog event handler.
* @param aEvent The event to handle.
*/
handleEvent: function UndoDialog_handleEvent(aEvent) {
switch (aEvent.target.id) {
case "newtab-undo-button":
this._undo();
break;
case "newtab-undo-restore-button":
this._undoAll();
break;
case "newtab-undo-close-button":
this.hide();
break;
}
},
/**
* Undo the last blocked site.
*/
_undo: function UndoDialog_undo() {
if (!this._undoData)
return;
let {index, wasPinned, blockedLink} = this._undoData;
gBlockedLinks.unblock(blockedLink);
if (wasPinned) {
gPinnedLinks.pin(blockedLink, index);
}
gUpdater.updateGrid();
this.hide();
},
/**
* Undo all blocked sites.
*/
_undoAll: function UndoDialog_undoAll() {
NewTabUtils.undoAll(function() {
gUpdater.updateGrid();
this.hide();
}.bind(this));
}
};
gUndoDialog.init();

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

@ -19,6 +19,7 @@ _BROWSER_FILES = \
browser_newtab_focus.js \
browser_newtab_reset.js \
browser_newtab_tabsync.js \
browser_newtab_undo.js \
browser_newtab_unpin.js \
browser_newtab_bug721442.js \
browser_newtab_bug722273.js \

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

@ -0,0 +1,49 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*
* These tests make sure that the undo dialog works as expected.
*/
function runTests() {
// remove unpinned sites and undo it
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("5");
yield addNewTabPageTab();
checkGrid("5p,0,1,2,3,4,6,7,8");
yield blockCell(4);
yield blockCell(4);
checkGrid("5p,0,1,2,6,7,8");
yield undo();
checkGrid("5p,0,1,2,4,6,7,8");
// now remove a pinned site and undo it
yield blockCell(0);
checkGrid("0,1,2,4,6,7,8");
yield undo();
checkGrid("5p,0,1,2,4,6,7,8");
// remove a site and restore all
yield blockCell(1);
checkGrid("5p,1,2,4,6,7,8");
yield undoAll();
checkGrid("5p,0,1,2,3,4,6,7,8");
}
function undo() {
let cw = getContentWindow();
let target = cw.document.getElementById("newtab-undo-button");
EventUtils.synthesizeMouseAtCenter(target, {}, cw);
whenPagesUpdated();
}
function undoAll() {
let cw = getContentWindow();
let target = cw.document.getElementById("newtab-undo-restore-button");
EventUtils.synthesizeMouseAtCenter(target, {}, cw);
whenPagesUpdated();
}

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

@ -12,9 +12,11 @@ relativesrcdir = @relativesrcdir@
include $(DEPTH)/config/autoconf.mk
MOCHITEST_BROWSER_FILES = \
browser_cmd_addon.js \
browser_cmd_calllog.js \
browser_cmd_calllog_chrome.js \
browser_dbg_cmd_break.html \
browser_dbg_cmd_break.js \
browser_cmd_addon.js \
browser_cmd_commands.js \
browser_cmd_cookie.js \
browser_cmd_integrate.js \
@ -67,13 +69,9 @@ ifneq ($(OS_ARCH),WINNT)
MOCHITEST_BROWSER_FILES += \
browser_dbg_cmd.html \
browser_dbg_cmd.js \
browser_cmd_calllog.js \
browser_cmd_calllog_chrome.js \
$(NULL)
else
$(filter disabled-temporarily--bug-820221, browser_dbg_cmd.js)
$(filter disabled-temporarily--bug-817304, browser_cmd_calllog.js)
$(filter disabled-temporarily--bug-819017, browser_cmd_calllog_chrome.js)
endif
include $(topsrcdir)/config/rules.mk

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

@ -70,6 +70,32 @@ function testVariablesView()
testThirdLevelContents();
testIntegrity(arr, obj);
let fooScope = gVariablesView.addScope("foo");
let anonymousVar = fooScope.addVar();
let anonymousScope = gVariablesView.addScope();
let barVar = anonymousScope.addVar("bar");
is(fooScope.header, true,
"A named scope should have a header visible.");
is(fooScope.target.hasAttribute("non-header"), false,
"The non-header attribute should not be applied to scopes with headers.");
is(anonymousScope.header, false,
"An anonymous scope should have a header visible.");
is(anonymousScope.target.hasAttribute("non-header"), true,
"The non-header attribute should not be applied to scopes without headers.");
is(barVar.header, true,
"A named variable should have a header visible.");
is(barVar.target.hasAttribute("non-header"), false,
"The non-header attribute should not be applied to variables with headers.");
is(anonymousVar.header, false,
"An anonymous variable should have a header visible.");
is(anonymousVar.target.hasAttribute("non-header"), true,
"The non-header attribute should not be applied to variables without headers.");
gVariablesView.clearHierarchy();
is (gVariablesView._prevHierarchy.size, 0,
"The previous hierarchy should have been cleared.");
@ -103,18 +129,18 @@ function testHeader() {
gScope.showHeader();
gVariable.showHeader();
is(gScope.header, true,
"The scope title header should now be visible");
is(gVariable.header, true,
"The variable title header should now be visible");
is(gScope.header, false,
"The scope title header should still not be visible");
is(gVariable.header, false,
"The variable title header should still not be visible");
gScope.hideHeader();
gVariable.hideHeader();
is(gScope.header, false,
"The scope title header should now be hidden");
"The scope title header should now still be hidden");
is(gVariable.header, false,
"The variable title header should now be hidden");
"The variable title header should now still be hidden");
}
function testFirstLevelContents() {

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

@ -341,6 +341,28 @@ let gDevToolsBrowser = {
gDevToolsBrowser._updateMenuCheckbox, false);
},
/**
* Add a <key> to <keyset id="devtoolsKeyset">.
* Appending a <key> element is not always enough. The <keyset> needs
* to be detached and reattached to make sure the <key> is taken into
* account (see bug 832984).
*
* @param {XULDocument} doc
* The document to which keys are to be added
* @param {XULElement} or {DocumentFragment} keys
* Keys to add
*/
attachKeybindingsToBrowser: function DT_attachKeybindingsToBrowser(doc, keys) {
let devtoolsKeyset = doc.getElementById("devtoolsKeyset");
if (!devtoolsKeyset) {
devtoolsKeyset = doc.createElement("keyset");
devtoolsKeyset.setAttribute("id", "devtoolsKeyset");
}
devtoolsKeyset.appendChild(keys);
let mainKeyset = doc.getElementById("mainKeyset");
mainKeyset.parentNode.insertBefore(devtoolsKeyset, mainKeyset);
},
/**
* Add the menuitem for a tool to all open browser windows.
*
@ -366,7 +388,7 @@ let gDevToolsBrowser = {
doc.getElementById("mainCommandSet").appendChild(elements.cmd);
if (elements.key) {
doc.getElementById("mainKeyset").appendChild(elements.key);
this.attachKeybindingsToBrowser(doc, elements.keys);
}
doc.getElementById("mainBroadcasterSet").appendChild(elements.bc);
@ -420,8 +442,7 @@ let gDevToolsBrowser = {
let mcs = doc.getElementById("mainCommandSet");
mcs.appendChild(fragCommands);
let mks = doc.getElementById("mainKeyset");
mks.appendChild(fragKeys);
this.attachKeybindingsToBrowser(doc, fragKeys);
let mbs = doc.getElementById("mainBroadcasterSet");
mbs.appendChild(fragBroadcasters);

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

@ -122,10 +122,10 @@ LayoutView.prototype = {
this.inspector.selection.reason != "highlighter") {
this.cssLogic.highlight(this.inspector.selection.node);
this.undim();
this.update();
} else {
this.dim();
}
this.update();
},
/**

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

@ -784,6 +784,9 @@ function MarkupContainer(aMarkupView, aNode)
}.bind(this), false);
if (this.editor.closeElt) {
this.editor.closeElt.addEventListener("mousedown", function(evt) {
this.markup.navigate(this);
}.bind(this), false);
this.codeBox.appendChild(this.editor.closeElt);
}

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

@ -699,8 +699,9 @@ var Scratchpad = {
// Check to see if the first line is a mode-line comment.
let line = content.split("\n")[0];
let modeline = self._scanModeLine(line);
let chrome = Services.prefs.getBoolPref(DEVTOOLS_CHROME_ENABLED);
if (modeline["-sp-context"] === "browser") {
if (chrome && modeline["-sp-context"] === "browser") {
self.setBrowserContext();
}

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

@ -8,18 +8,14 @@ Cu.import("resource://gre/modules/FileUtils.jsm", tempScope);
let NetUtil = tempScope.NetUtil;
let FileUtils = tempScope.FileUtils;
// Reference to the Scratchpad object.
let gScratchpad;
// Reference to the temporary nsIFile we will work with.
let gFile;
let gScratchpad; // Reference to the Scratchpad object.
let gFile; // Reference to the temporary nsIFile we will work with.
let DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled";
// The temporary file content.
let gFileContent = "function main() { return 0; }";
const SCRATCHPAD_CONTEXT_CONTENT = 1;
const SCRATCHPAD_CONTEXT_BROWSER = 2;
function test() {
waitForExplicitFinish();
@ -72,11 +68,25 @@ function runTests() {
function fileImported(status, content) {
ok(Components.isSuccessCode(status), "File was imported successfully");
is(gScratchpad.executionContext, SCRATCHPAD_CONTEXT_BROWSER);
gFile.remove(false);
gFile = null;
gScratchpad = null;
finish();
// Since devtools.chrome.enabled is off, Scratchpad should still be in
// the content context.
is(gScratchpad.executionContext, gScratchpadWindow.SCRATCHPAD_CONTEXT_CONTENT);
// Set the pref and try again.
Services.prefs.setBoolPref(DEVTOOLS_CHROME_ENABLED, true);
gScratchpad.importFromFile(gFile.QueryInterface(Ci.nsILocalFile), true, function(status, content) {
ok(Components.isSuccessCode(status), "File was imported successfully");
is(gScratchpad.executionContext, gScratchpadWindow.SCRATCHPAD_CONTEXT_BROWSER);
gFile.remove(false);
gFile = null;
gScratchpad = null;
finish();
});
}
registerCleanupFunction(function () {
Services.prefs.clearUserPref(DEVTOOLS_CHROME_ENABLED);
});

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

@ -34,6 +34,10 @@ XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
.QueryInterface(Components.interfaces.nsIPrefBranch2);
});
XPCOMUtils.defineLazyGetter(this, "toolboxStrings", function () {
return Services.strings.createBundle("chrome://browser/locale/devtools/toolbox.properties");
});
/**
* A collection of utilities to help working with commands
*/
@ -163,9 +167,12 @@ this.DeveloperToolbar = function DeveloperToolbar(aChromeWindow, aToolbarElement
this._pendingShowCallback = undefined;
this._pendingHide = false;
this._errorsCount = {};
this._warningsCount = {};
this._errorListeners = {};
this._errorCounterButton = this._doc
.getElementById("developer-toolbar-toolbox-button");
this._errorCounterButton._defaultTooltipText =
this._errorCounterButton.getAttribute("tooltiptext");
try {
CmdCommands.refreshAutoCommands(aChromeWindow);
@ -397,6 +404,7 @@ DeveloperToolbar.prototype._initErrorsCount = function DT__initErrorsCount(aTab)
this._errorListeners[tabId] = listener;
this._errorsCount[tabId] = 0;
this._warningsCount[tabId] = 0;
let messages = listener.getCachedMessages();
messages.forEach(this._onPageError.bind(this, tabId));
@ -415,7 +423,7 @@ DeveloperToolbar.prototype._initErrorsCount = function DT__initErrorsCount(aTab)
DeveloperToolbar.prototype._stopErrorsCount = function DT__stopErrorsCount(aTab)
{
let tabId = aTab.linkedPanel;
if (!(tabId in this._errorsCount)) {
if (!(tabId in this._errorsCount) || !(tabId in this._warningsCount)) {
this._updateErrorsCount();
return;
}
@ -423,6 +431,7 @@ DeveloperToolbar.prototype._stopErrorsCount = function DT__stopErrorsCount(aTab)
this._errorListeners[tabId].destroy();
delete this._errorListeners[tabId];
delete this._errorsCount[tabId];
delete this._warningsCount[tabId];
this._updateErrorsCount();
};
@ -550,13 +559,15 @@ DeveloperToolbar.prototype._onPageError =
function DT__onPageError(aTabId, aPageError)
{
if (aPageError.category == "CSS Parser" ||
aPageError.category == "CSS Loader" ||
(aPageError.flags & aPageError.warningFlag) ||
(aPageError.flags & aPageError.strictFlag)) {
return; // just a CSS or JS warning
aPageError.category == "CSS Loader") {
return;
}
if ((aPageError.flags & aPageError.warningFlag) ||
(aPageError.flags & aPageError.strictFlag)) {
this._warningsCount[aTabId]++;
} else {
this._errorsCount[aTabId]++;
}
this._errorsCount[aTabId]++;
this._updateErrorsCount(aTabId);
};
@ -579,8 +590,9 @@ function DT__onPageBeforeUnload(aEvent)
Array.prototype.some.call(tabs, function(aTab) {
if (aTab.linkedBrowser.contentWindow === window) {
let tabId = aTab.linkedPanel;
if (tabId in this._errorsCount) {
if (tabId in this._errorsCount || tabId in this._warningsCount) {
this._errorsCount[tabId] = 0;
this._warningsCount[tabId] = 0;
this._updateErrorsCount(tabId);
}
return true;
@ -607,11 +619,15 @@ function DT__updateErrorsCount(aChangedTabId)
}
let errors = this._errorsCount[tabId];
let warnings = this._warningsCount[tabId];
let btn = this._errorCounterButton;
if (errors) {
this._errorCounterButton.setAttribute("error-count", errors);
let tooltiptext = toolboxStrings.formatStringFromName("toolboxDockButtons.errorsCount.tooltip", [errors, warnings], 2);
btn.setAttribute("error-count", errors);
btn.setAttribute("tooltiptext", tooltiptext);
} else {
this._errorCounterButton.removeAttribute("error-count");
btn.removeAttribute("error-count");
btn.setAttribute("tooltiptext", btn._defaultTooltipText);
}
};
@ -625,8 +641,9 @@ DeveloperToolbar.prototype.resetErrorsCount =
function DT_resetErrorsCount(aTab)
{
let tabId = aTab.linkedPanel;
if (tabId in this._errorsCount) {
if (tabId in this._errorsCount || tabId in this._warningsCount) {
this._errorsCount[tabId] = 0;
this._warningsCount[tabId] = 0;
this._updateErrorsCount(tabId);
}
};

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

@ -698,7 +698,7 @@ Scope.prototype = {
* Shows the scope's title header.
*/
showHeader: function S_showHeader() {
if (this._isHeaderVisible) {
if (this._isHeaderVisible || !this._nameString) {
return;
}
this._target.removeAttribute("non-header");
@ -788,6 +788,18 @@ Scope.prototype = {
*/
set twisty(aFlag) aFlag ? this.showArrow() : this.hideArrow(),
/**
* Gets the expand lock state.
* @return boolean
*/
get locked() this._locked,
/**
* Sets the expand lock state.
* @param boolean aFlag
*/
set locked(aFlag) this._locked = aFlag,
/**
* Adds an event listener for a certain event on this scope's title.
* @param string aName
@ -1386,7 +1398,9 @@ create({ constructor: Variable, proto: Scope.prototype }, {
get setter() this._initialDescriptor.set,
/**
* Sets the specific grip for this variable.
* Sets the specific grip for this variable (applies the text content and
* class name to the value label).
*
* The grip should contain the value or the type & class, as defined in the
* remote debugger protocol. For convenience, undefined and null are
* both considered types.
@ -1401,23 +1415,18 @@ create({ constructor: Variable, proto: Scope.prototype }, {
* - { type: "object", class: "Object" }
*/
_setGrip: function V__setGrip(aGrip) {
// Don't allow displaying grip information if there's no name available.
if (!this._nameString) {
return;
}
if (aGrip === undefined) {
aGrip = { type: "undefined" };
}
if (aGrip === null) {
aGrip = { type: "null" };
}
this._applyGrip(aGrip);
},
/**
* Applies the necessary text content and class name to a value node based
* on a grip.
*
* @param any aGrip
* @see Variable._setGrip
*/
_applyGrip: function V__applyGrip(aGrip) {
let prevGrip = this._valueGrip;
if (prevGrip) {
this._valueLabel.classList.remove(VariablesView.getClass(prevGrip));
@ -1441,11 +1450,16 @@ create({ constructor: Variable, proto: Scope.prototype }, {
_init: function V__init(aName, aDescriptor) {
this._idString = generateId(this._nameString = aName);
this._displayScope(aName, "variable");
this._displayVariable();
this._customizeVariable();
this._prepareTooltip();
this._setAttributes();
this._addEventListeners();
// Don't allow displaying variable information there's no name available.
if (this._nameString) {
this._displayVariable();
this._customizeVariable();
this._prepareTooltip();
this._setAttributes();
this._addEventListeners();
}
this._onInit(this.ownerView._store.size < LAZY_APPEND_BATCH);
},
@ -1530,18 +1544,16 @@ create({ constructor: Variable, proto: Scope.prototype }, {
let document = this.document;
let tooltip = document.createElement("tooltip");
tooltip.id = "tooltip-" + this.id;
tooltip.id = "tooltip-" + this._idString;
let configurableLabel = document.createElement("label");
configurableLabel.setAttribute("value", "configurable");
let enumerableLabel = document.createElement("label");
enumerableLabel.setAttribute("value", "enumerable");
let writableLabel = document.createElement("label");
configurableLabel.setAttribute("value", "configurable");
enumerableLabel.setAttribute("value", "enumerable");
writableLabel.setAttribute("value", "writable");
tooltip.setAttribute("orient", "horizontal")
tooltip.setAttribute("orient", "horizontal");
tooltip.appendChild(configurableLabel);
tooltip.appendChild(enumerableLabel);
tooltip.appendChild(writableLabel);
@ -1847,11 +1859,16 @@ create({ constructor: Property, proto: Variable.prototype }, {
_init: function P__init(aName, aDescriptor) {
this._idString = generateId(this._nameString = aName);
this._displayScope(aName, "property");
this._displayVariable();
this._customizeVariable();
this._prepareTooltip();
this._setAttributes();
this._addEventListeners();
// Don't allow displaying property information there's no name available.
if (this._nameString) {
this._displayVariable();
this._customizeVariable();
this._prepareTooltip();
this._setAttributes();
this._addEventListeners();
}
this._onInit(this.ownerView._store.size < LAZY_APPEND_BATCH);
},
@ -1990,9 +2007,9 @@ VariablesView.isPrimitive = function VV_isPrimitive(aDescriptor) {
return true;
}
// For convenience, undefined and null are both considered types.
// For convenience, undefined, null and long strings are considered primitives.
let type = grip.type;
if (type == "undefined" || type == "null") {
if (type == "undefined" || type == "null" || type == "longString") {
return true;
}
@ -2087,6 +2104,8 @@ VariablesView.getString = function VV_getString(aGrip, aConciseFlag) {
return "undefined";
case "null":
return "null";
case "longString":
return "\"" + aGrip.initial + "\"";
default:
if (!aConciseFlag) {
return "[" + aGrip.type + " " + aGrip.class + "]";

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

@ -20,8 +20,11 @@
<p>Hello world! Test for errors count in the Web Console button (developer
toolbar).</p>
<p style="color: foobarBug762996css"><button>click me</button></p>
<script type="text/javascript">
<script type="text/javascript;version=1.8">
"use strict";
let testObj = {};
document.querySelector("button").onclick = function() {
let test = testObj.fooBug788445 + "warning";
window.foobarBug762996click();
};
</script>

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

@ -21,6 +21,8 @@ function test() {
let toolbar = document.getElementById("Tools:DevToolbar");
let tab1, tab2;
Services.prefs.setBoolPref("javascript.options.strict", true);
function openToolbar(browser, tab) {
tab1 = tab;
ignoreAllUncaughtExceptions(false);
@ -40,13 +42,46 @@ function test() {
return count ? count : "0";
}
function getTooltipValues() {
let matches = webconsole.getAttribute("tooltiptext")
.match(/(\d+) errors, (\d+) warnings/);
return matches ? [matches[1], matches[2]] : [0, 0];
}
function waitForButtonUpdate(aOptions)
{
aOptions.validator = function() {
let errors = getErrorsCount();
let tooltip = getTooltipValues();
let result = errors == aOptions.errors &&
tooltip[1] == aOptions.warnings;
if (result) {
is(errors, tooltip[0], "button error-count is the same as in the tooltip");
}
return result;
};
let originalFailure = aOptions.failure;
aOptions.failure = function() {
let tooltip = getTooltipValues();
info("expected " + aOptions.errors + " errors, " +
aOptions.warnings + " warnings");
info("got " + tooltip[0] + " errors, " + tooltip[1] + " warnings");
originalFailure();
};
waitForValue(aOptions);
}
function onOpenToolbar() {
ok(DeveloperToolbar.visible, "DeveloperToolbar is visible");
waitForValue({
waitForButtonUpdate({
name: "web console button shows page errors",
validator: getErrorsCount,
value: 3,
errors: 3,
warnings: 0,
success: addErrors,
failure: finish,
});
@ -57,13 +92,15 @@ function test() {
waitForFocus(function() {
let button = content.document.querySelector("button");
EventUtils.synthesizeMouse(button, 2, 2, {}, content);
executeSoon(function() {
EventUtils.synthesizeMouse(button, 3, 2, {}, content);
});
}, content);
waitForValue({
waitForButtonUpdate({
name: "button shows one more error after click in page",
validator: getErrorsCount,
value: 4,
errors: 4,
warnings: 1,
success: function() {
ignoreAllUncaughtExceptions();
addTab(TEST_URI, onOpenSecondTab);
@ -78,10 +115,10 @@ function test() {
ignoreAllUncaughtExceptions(false);
expectUncaughtException();
waitForValue({
waitForButtonUpdate({
name: "button shows correct number of errors after new tab is open",
validator: getErrorsCount,
value: 3,
errors: 3,
warnings: 0,
success: switchToTab1,
failure: finish,
});
@ -89,10 +126,10 @@ function test() {
function switchToTab1() {
gBrowser.selectedTab = tab1;
waitForValue({
waitForButtonUpdate({
name: "button shows the page errors from tab 1",
validator: getErrorsCount,
value: 4,
errors: 4,
warnings: 1,
success: function() {
openWebConsole(tab1, onWebConsoleOpen);
},
@ -128,12 +165,12 @@ function test() {
}
function checkConsoleOutput(hud) {
let errors = ["foobarBug762996a", "foobarBug762996b", "foobarBug762996load",
"foobarBug762996click", "foobarBug762996consoleLog",
"foobarBug762996css"];
errors.forEach(function(error) {
isnot(hud.outputNode.textContent.indexOf(error), -1,
error + " found in the Web Console output");
let msgs = ["foobarBug762996a", "foobarBug762996b", "foobarBug762996load",
"foobarBug762996click", "foobarBug762996consoleLog",
"foobarBug762996css", "fooBug788445"];
msgs.forEach(function(msg) {
isnot(hud.outputNode.textContent.indexOf(msg), -1,
msg + " found in the Web Console output");
});
hud.jsterm.clearOutput();
@ -145,10 +182,10 @@ function test() {
let button = content.document.querySelector("button");
EventUtils.synthesizeMouse(button, 2, 2, {}, content);
waitForValue({
waitForButtonUpdate({
name: "button shows one more error after another click in page",
validator: getErrorsCount,
value: 5,
errors: 5,
warnings: 1, // warnings are not repeated by the js engine
success: function() {
waitForValue(waitForNewError);
},
@ -173,6 +210,8 @@ function test() {
is(hud.outputNode.textContent.indexOf("foobarBug762996click"), -1,
"clear console button worked");
is(getErrorsCount(), 0, "page errors counter has been reset");
let tooltip = getTooltipValues();
is(tooltip[1], 0, "page warnings counter has been reset");
doPageReload(hud);
}
@ -187,10 +226,10 @@ function test() {
ignoreAllUncaughtExceptions();
content.location.reload();
waitForValue({
waitForButtonUpdate({
name: "the Web Console button count has been reset after page reload",
validator: getErrorsCount,
value: 3,
errors: 3,
warnings: 0,
success: function() {
waitForValue(waitForConsoleOutputAfterReload);
},
@ -218,6 +257,7 @@ function test() {
gDevTools.closeToolbox(target1);
gBrowser.removeTab(tab1);
gBrowser.removeTab(tab2);
Services.prefs.clearUserPref("javascript.options.strict");
finish();
}

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

@ -194,7 +194,9 @@ TiltVisualizer.prototype = {
this._browserTab = null;
if (this.inspector) {
this.inspector.selection.off("new-node", this.onNewNodeFromInspector);
if (this.inspector.selection) {
this.inspector.selection.off("new-node", this.onNewNodeFromInspector);
}
this.inspector = null;
}

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

@ -1,3 +1,4 @@
toolboxDockButtons.bottom.tooltip=Dock to bottom of browser window
toolboxDockButtons.side.tooltip=Dock to side of browser window
toolboxDockButtons.window.tooltip=Show in separate window
toolboxDockButtons.bottom.tooltip=Dock to bottom of browser window
toolboxDockButtons.side.tooltip=Dock to side of browser window
toolboxDockButtons.window.tooltip=Show in separate window
toolboxDockButtons.errorsCount.tooltip=%S errors, %S warnings.\nClick to toggle developer tools.

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

@ -4,3 +4,7 @@
<!-- These strings are used in the about:newtab page -->
<!ENTITY newtab.pageTitle "New Tab">
<!ENTITY newtab.undo.removedLabel "Thumbnail removed.">
<!ENTITY newtab.undo.undoButton "Undo.">
<!ENTITY newtab.undo.restoreButton "Restore All.">
<!ENTITY newtab.undo.closeTooltip "Hide">

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

@ -196,12 +196,20 @@ LinksStorage.prototype = {
string);
},
/**
* Removes the storage value for a given key.
* @param aKey The storage key (a string).
*/
remove: function Storage_remove(aKey) {
Services.prefs.clearUserPref(this._prefs[aKey]);
},
/**
* Clears the storage and removes all values.
*/
clear: function Storage_clear() {
for each (let pref in this._prefs) {
Services.prefs.clearUserPref(pref);
for (let key in this._prefs) {
this.remove(key);
}
}
};
@ -813,6 +821,18 @@ this.NewTabUtils = {
}, true);
},
/**
* Undoes all sites that have been removed from the grid and keep the pinned
* tabs.
* @param aCallback the callback method.
*/
undoAll: function NewTabUtils_undoAll(aCallback) {
Storage.remove("blockedLinks");
Links.resetCache();
BlockedLinks.resetCache();
Links.populateCache(aCallback, true);
},
links: Links,
allPages: AllPages,
linkChecker: LinkChecker,

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

@ -4,6 +4,7 @@
:root {
-moz-appearance: none;
font-size: 75%;
background-color: transparent;
}
@ -15,6 +16,59 @@
background-attachment: fixed;
}
/* UNDO */
#newtab-undo-container {
padding: 4px 3px;
border: 1px solid;
border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
background-color: rgba(255,255,255,.4);
color: #525e69;
}
#newtab-undo-label {
margin-top: 0;
margin-bottom: 0;
}
.newtab-undo-button {
-moz-appearance: none;
color: rgb(221,72,20);
cursor: pointer;
padding: 0;
margin: 0 4px;
border: 0;
background: transparent;
text-decoration: none;
min-width: 0;
}
.newtab-undo-button:hover {
text-decoration: underline;
}
.newtab-undo-button:-moz-focusring {
outline: 1px dotted;
}
#newtab-undo-close-button {
padding: 0;
border: none;
list-style-image: url("moz-icon://stock/gtk-close?size=menu");
-moz-user-focus: normal;
}
#newtab-undo-close-button > .toolbarbutton-icon {
margin: -4px;
}
#newtab-undo-close-button > .toolbarbutton-text {
display: none;
}
#newtab-undo-close-button:-moz-focusring {
outline: 1px dotted;
}
/* TOGGLE */
#newtab-toggle {
width: 16px;
@ -89,7 +143,6 @@
padding: 0 8px;
background-color: rgba(248,249,251,.95);
color: #1f364c;
font-size: 12px;
line-height: 24px;
}

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

@ -4,6 +4,7 @@
:root {
-moz-appearance: none;
font-size: 75%;
background-color: transparent;
}
@ -15,6 +16,64 @@
background-attachment: fixed;
}
/* UNDO */
#newtab-undo-container {
padding: 4px 3px;
border: 1px solid;
border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
background-color: rgba(255,255,255,.4);
color: #525e69;
}
#newtab-undo-label {
margin-top: 0;
margin-bottom: 0;
}
.newtab-undo-button {
-moz-appearance: none;
color: rgb(20,79,174);
cursor: pointer;
padding: 0;
margin: 0 4px;
border: 0;
background: transparent;
text-decoration: none;
min-width: 0;
}
.newtab-undo-button:hover {
text-decoration: underline;
}
.newtab-undo-button:-moz-focusring {
outline: 1px dotted;
}
#newtab-undo-close-button {
padding: 0;
border: none;
list-style-image: url("chrome://global/skin/icons/close.png");
-moz-image-region: rect(0, 16px, 16px, 0);
-moz-user-focus: normal;
}
#newtab-undo-close-button:hover {
-moz-image-region: rect(0, 32px, 16px, 16px);
}
#newtab-undo-close-button:hover:active {
-moz-image-region: rect(0, 48px, 16px, 32px);
}
#newtab-undo-close-button > .toolbarbutton-text {
display: none;
}
#newtab-undo-close-button:-moz-focusring {
outline: 1px dotted;
}
/* TOGGLE */
#newtab-toggle {
width: 16px;
@ -96,7 +155,6 @@
padding: 0 8px;
background-color: rgba(248,249,251,.95);
color: #1f364c;
font-size: 12px;
line-height: 24px;
}

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

@ -4,6 +4,7 @@
:root {
-moz-appearance: none;
font-size: 75%;
background-color: transparent;
}
@ -15,6 +16,70 @@
background-attachment: fixed;
}
/* UNDO */
#newtab-undo-container {
padding: 4px 3px;
border: 1px solid;
border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
background-color: rgba(255,255,255,.4);
color: #525e69;
}
#newtab-undo-label {
margin-top: 0;
margin-bottom: 0;
}
.newtab-undo-button {
-moz-appearance: none;
color: -moz-nativehyperlinktext;
color: rgb(0,102,204);
cursor: pointer;
padding: 0;
margin: 0 4px;
border: 0;
background: transparent;
text-decoration: none;
min-width: 0;
}
.newtab-undo-button:hover {
text-decoration: underline;
}
.newtab-undo-button:-moz-focusring {
outline: 1px dotted;
}
.newtab-undo-button > .button-box {
padding: 0;
}
#newtab-undo-close-button {
-moz-appearance: none;
padding: 0;
border: none;
list-style-image: url("chrome://global/skin/icons/close.png");
-moz-image-region: rect(0, 16px, 16px, 0);
-moz-user-focus: normal;
}
#newtab-undo-close-button:hover {
-moz-image-region: rect(0, 32px, 16px, 16px);
}
#newtab-undo-close-button:hover:active {
-moz-image-region: rect(0, 48px, 16px, 32px);
}
#newtab-undo-close-button > .toolbarbutton-text {
display: none;
}
#newtab-undo-close-button:-moz-focusring {
outline: 1px dotted;
}
/* TOGGLE */
#newtab-toggle {
width: 16px;
@ -89,7 +154,6 @@
padding: 0 8px;
background-color: rgba(248,249,251,.95);
color: #1f364c;
font-size: 12px;
line-height: 24px;
}

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

@ -1512,8 +1512,27 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDocument)
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(nsDocument,
nsNodeUtils::LastRelease(this))
NS_IMETHODIMP_(nsrefcnt)
nsDocument::Release()
{
NS_PRECONDITION(0 != mRefCnt, "dup release");
NS_ASSERT_OWNINGTHREAD_AND_NOT_CCTHREAD(nsDocument);
nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(nsDocument)::Upcast(this);
nsrefcnt count = mRefCnt.decr(base);
NS_LOG_RELEASE(this, count, "nsDocument");
if (count == 0) {
if (mStackRefCnt && !mNeedsReleaseAfterStackRefCntRelease) {
mNeedsReleaseAfterStackRefCntRelease = true;
NS_ADDREF_THIS();
return mRefCnt.get();
}
NS_ASSERT_OWNINGTHREAD(nsDocument);
mRefCnt.stabilizeForDeletion();
nsNodeUtils::LastRelease(this);
return 0;
}
return count;
}
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDocument)
if (Element::CanSkip(tmp, aRemovingAllowed)) {
@ -6707,6 +6726,8 @@ nsIDocument::CreateEvent(const nsAString& aEventType, ErrorResult& rv) const
void
nsDocument::FlushPendingNotifications(mozFlushType aType)
{
nsDocumentOnStack dos(this);
// We need to flush the sink for non-HTML documents (because the XML
// parser still does insertion with deferred notifications). We
// also need to flush the sink if this is a layout-related flush, to

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

@ -93,6 +93,7 @@ class nsHTMLCSSStyleSheet;
class nsDOMNavigationTiming;
class nsWindowSizes;
class nsHtml5TreeOpExecutor;
class nsDocumentOnStack;
namespace mozilla {
namespace dom {
@ -1020,6 +1021,20 @@ public:
protected:
friend class nsNodeUtils;
friend class nsDocumentOnStack;
void IncreaseStackRefCnt()
{
++mStackRefCnt;
}
void DecreaseStackRefCnt()
{
if (--mStackRefCnt == 0 && mNeedsReleaseAfterStackRefCntRelease) {
mNeedsReleaseAfterStackRefCntRelease = false;
NS_RELEASE_THIS();
}
}
// Returns true if a request for DOM full-screen is currently enabled in
// this document. This returns true if there are no windowed plugins in this
@ -1379,12 +1394,30 @@ private:
bool mAutoSize, mAllowZoom, mValidScaleFloat, mValidMaxScale, mScaleStrEmpty, mWidthStrEmpty;
uint32_t mViewportWidth, mViewportHeight;
nsrefcnt mStackRefCnt;
bool mNeedsReleaseAfterStackRefCntRelease;
#ifdef DEBUG
protected:
bool mWillReparent;
#endif
};
class nsDocumentOnStack
{
public:
nsDocumentOnStack(nsDocument* aDoc) : mDoc(aDoc)
{
mDoc->IncreaseStackRefCnt();
}
~nsDocumentOnStack()
{
mDoc->DecreaseStackRefCnt();
}
private:
nsDocument* mDoc;
};
#define NS_DOCUMENT_INTERFACE_TABLE_BEGIN(_class) \
NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class) \
NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsIDOMDocument, nsDocument) \

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

@ -15,7 +15,7 @@
///////////////////////////////////////////////////////////////////////////////
var EXPORTED_SYMBOLS = [ "SourceMapConsumer", "SourceMapGenerator", "SourceNode" ];
this.EXPORTED_SYMBOLS = [ "SourceMapConsumer", "SourceMapGenerator", "SourceNode" ];
Components.utils.import('resource://gre/modules/devtools/Require.jsm');
/* -*- Mode: js; js-indent-level: 2; -*- */