Merge latest green b2g-inbound changeset and mozilla-central

This commit is contained in:
Ed Morley 2014-01-06 12:51:01 +00:00
commit 1cd2b47426
167 changed files with 2060 additions and 1806 deletions

View File

@ -569,18 +569,12 @@ HistoryMenu.prototype = {
if (!menuitem)
return;
// If Sync isn't configured yet, then don't show the menuitem.
if (Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED ||
Weave.Svc.Prefs.get("firstSync", "") == "notReady") {
if (!PlacesUIUtils.shouldShowTabsFromOtherComputersMenuitem()) {
menuitem.setAttribute("hidden", true);
return;
}
// The tabs engine might never be inited (if services.sync.registerEngines
// is modified), so make sure we avoid undefined errors.
let enabled = Weave.Service.isLoggedIn &&
Weave.Service.engineManager.get("tabs") &&
Weave.Service.engineManager.get("tabs").enabled;
let enabled = PlacesUIUtils.shouldEnableTabsFromOtherComputersMenuitem();
menuitem.setAttribute("disabled", !enabled);
menuitem.setAttribute("hidden", false);
#endif

View File

@ -202,8 +202,16 @@
align="start"
orient="vertical"
role="alert">
<label id="UITourTooltipTitle" flex="1"/>
<description id="UITourTooltipDescription" flex="1"/>
<hbox>
<vbox>
<image id="UITourTooltipIcon"/>
</vbox>
<vbox flex="1">
<label id="UITourTooltipTitle" flex="1"/>
<description id="UITourTooltipDescription" flex="1"/>
<hbox id="UITourTooltipButtons" flex="1" align="end"/>
</vbox>
</hbox>
</panel>
<panel id="UITourHighlightContainer"
hidden="true"

View File

@ -7,7 +7,7 @@
let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
let blocklistURL = "http://test:80/browser/browser/base/content/test/social/blocklist.xml";
let blocklistURL = "http://example.org/browser/browser/base/content/test/social/blocklist.xml";
let manifest = { // normal provider
name: "provider ok",

View File

@ -45,6 +45,13 @@
<toolbarbutton id="appMenuClearRecentHistory" tabindex="0"
label="&appMenuHistory.clearRecent.label;"
command="Tools:Sanitize"/>
#ifdef MOZ_SERVICES_SYNC
<toolbarbutton id="sync-tabs-menuitem2"
class="syncTabsMenuItem"
label="&syncTabsMenu2.label;"
oncommand="BrowserOpenSyncTabs();"
disabled="true"/>
#endif
<toolbarbutton id="appMenuRestoreLastSession" tabindex="0"
label="&appMenuHistory.restoreSession.label;"
command="Browser:RestoreLastSession"/>

View File

@ -12,6 +12,8 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUIUtils",
"resource:///modules/PlacesUIUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RecentlyClosedTabsAndWindowsMenuUtils",
"resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "CharsetManager",
@ -133,6 +135,21 @@ const CustomizableWidgets = [{
recentlyClosedWindows.removeChild(recentlyClosedWindows.firstChild);
}
#ifdef MOZ_SERVICES_SYNC
let tabsFromOtherComputers = doc.getElementById("sync-tabs-menuitem2");
if (PlacesUIUtils.shouldShowTabsFromOtherComputersMenuitem()) {
tabsFromOtherComputers.removeAttribute("hidden");
} else {
tabsFromOtherComputers.setAttribute("hidden", true);
}
if (PlacesUIUtils.shouldEnableTabsFromOtherComputersMenuitem()) {
tabsFromOtherComputers.removeAttribute("disabled");
} else {
tabsFromOtherComputers.setAttribute("disabled", true);
}
#endif
let tabsFragment = RecentlyClosedTabsAndWindowsMenuUtils.getTabsFragment(doc.defaultView, "toolbarbutton");
let separator = doc.getElementById("PanelUI-recentlyClosedTabs-separator");
separator.hidden = !tabsFragment.childElementCount;

View File

@ -129,10 +129,13 @@ CustomizeMode.prototype = {
window.PanelUI.menuButton.open = true;
window.PanelUI.beginBatchUpdate();
// Hide the palette before starting the transition for increased perf.
this.visiblePalette.hidden = true;
// Move the mainView in the panel to the holder so that we can see it
// while customizing.
let panelHolder = document.getElementById("customization-panelHolder");
let mainView = window.PanelUI.mainView;
let panelHolder = document.getElementById("customization-panelHolder");
panelHolder.appendChild(mainView);
let customizeButton = document.getElementById("PanelUI-customize");
@ -191,6 +194,10 @@ CustomizeMode.prototype = {
window.PanelUI.endBatchUpdate();
this._customizing = true;
this._transitioning = false;
// Show the palette now that the transition has finished.
this.visiblePalette.hidden = false;
this.dispatchToolboxEvent("customizationready");
}.bind(this)).then(null, function(e) {
ERROR(e);
@ -214,12 +221,15 @@ CustomizeMode.prototype = {
this._removePanelCustomizationPlaceholders();
this._transitioning = true;
let window = this.window;
let document = this.document;
let documentElement = document.documentElement;
// Hide the palette before starting the transition for increased perf.
this.visiblePalette.hidden = true;
this._transitioning = true;
Task.spawn(function() {
yield this.depopulatePalette();
@ -541,9 +551,9 @@ CustomizeMode.prototype = {
aNode.removeAttribute("observes");
}
if (aNode.checked) {
if (aNode.getAttribute("checked") == "true") {
wrapper.setAttribute("itemchecked", "true");
aNode.checked = false;
aNode.removeAttribute("checked");
}
if (aNode.hasAttribute("id")) {

View File

@ -49,6 +49,7 @@ skip-if = os == "mac"
[browser_943683_migration_test.js]
[browser_944887_destroyWidget_should_destroy_in_palette.js]
[browser_945739_showInPrivateBrowsing_customize_mode.js]
[browser_946320_tabs_from_other_computers.js]
[browser_947987_removable_default.js]
[browser_948985_non_removable_defaultArea.js]
[browser_952963_areaType_getter_no_area.js]

View File

@ -0,0 +1,51 @@
/* 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";
let Preferences = Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;
Cu.import("resource://gre/modules/Promise.jsm");
add_task(function() {
let shownPanelPromise = promisePanelShown(window);
PanelUI.toggle({type: "command"});
yield shownPanelPromise;
let historyButton = document.getElementById("history-panelmenu");
let historySubview = document.getElementById("PanelUI-history");
let subviewShownPromise = subviewShown(historySubview);
EventUtils.synthesizeMouseAtCenter(historyButton, {});
yield subviewShownPromise;
let tabsFromOtherComputers = document.getElementById("sync-tabs-menuitem2");
is(tabsFromOtherComputers.hidden, true, "The Tabs From Other Computers menuitem should be hidden when sync isn't enabled.");
let subviewHiddenPromise = subviewHidden(historySubview);
let panelMultiView = document.getElementById("PanelUI-multiView");
panelMultiView.showMainView();
yield subviewHiddenPromise;
// Part 2 - When Sync is enabled the menuitem should be shown.
Weave.Service.createAccount("john@doe.com", "mysecretpw",
"challenge", "response");
Weave.Service.identity.account = "john@doe.com";
Weave.Service.identity.basicPassword = "mysecretpw";
Weave.Service.identity.syncKey = Weave.Utils.generatePassphrase();
Weave.Svc.Prefs.set("firstSync", "newAccount");
Weave.Service.persistLogin();
subviewShownPromise = subviewShown(historySubview);
EventUtils.synthesizeMouseAtCenter(historyButton, {});
yield subviewShownPromise;
is(tabsFromOtherComputers.hidden, false, "The Tabs From Other Computers menuitem should be shown when sync is enabled.");
let syncPrefBranch = new Preferences("services.sync.");
syncPrefBranch.resetBranch("");
Services.logins.removeAllLogins();
let hiddenPanelPromise = promisePanelHidden(window);
PanelUI.toggle({type: "command"});
yield hiddenPanelPromise;
});

View File

@ -246,6 +246,36 @@ function promisePanelElementHidden(win, aPanel) {
return deferred.promise;
}
function subviewShown(aSubview) {
let deferred = Promise.defer();
let win = aSubview.ownerDocument.defaultView;
let timeoutId = win.setTimeout(() => {
deferred.reject("Subview (" + aSubview.id + ") did not show within 20 seconds.");
}, 20000);
function onViewShowing(e) {
aSubview.removeEventListener("ViewShowing", onViewShowing);
win.clearTimeout(timeoutId);
deferred.resolve();
};
aSubview.addEventListener("ViewShowing", onViewShowing);
return deferred.promise;
}
function subviewHidden(aSubview) {
let deferred = Promise.defer();
let win = aSubview.ownerDocument.defaultView;
let timeoutId = win.setTimeout(() => {
deferred.reject("Subview (" + aSubview.id + ") did not hide within 20 seconds.");
}, 20000);
function onViewHiding(e) {
aSubview.removeEventListener("ViewHiding", onViewHiding);
win.clearTimeout(timeoutId);
deferred.resolve();
};
aSubview.addEventListener("ViewHiding", onViewHiding);
return deferred.promise;
}
function waitForCondition(aConditionFn, aMaxTries=50, aCheckInterval=100) {
function tryNow() {
tries++;

View File

@ -19,6 +19,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
#ifdef MOZ_SERVICES_SYNC
XPCOMUtils.defineLazyModuleGetter(this, "Weave",
"resource://services-sync/main.js");
#endif
XPCOMUtils.defineLazyGetter(this, "PlacesUtils", function() {
Cu.import("resource://gre/modules/PlacesUtils.jsm");
return PlacesUtils;
@ -987,7 +992,21 @@ this.PlacesUIUtils = {
}
}
return queryName;
}
},
shouldShowTabsFromOtherComputersMenuitem: function() {
// If Sync isn't configured yet, then don't show the menuitem.
return Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED &&
Weave.Svc.Prefs.get("firstSync", "") != "notReady";
},
shouldEnableTabsFromOtherComputersMenuitem: function() {
// The tabs engine might never be inited (if services.sync.registerEngines
// is modified), so make sure we avoid undefined errors.
return Weave.Service.isLoggedIn &&
Weave.Service.engineManager.get("tabs") &&
Weave.Service.engineManager.get("tabs").enabled;
},
};
XPCOMUtils.defineLazyServiceGetter(PlacesUIUtils, "RDF",

View File

@ -9,7 +9,7 @@ EXTRA_COMPONENTS += [
'PlacesProtocolHandler.js',
]
EXTRA_JS_MODULES += [
EXTRA_PP_JS_MODULES += [
'PlacesUIUtils.jsm',
]

View File

@ -41,7 +41,7 @@ function getAllBreakpoints(dbg) {
for (let { attachment: breakpoint } of source) {
breakpoints.push({
url: source.value,
label: source.label + ":" + breakpoint.line,
label: source.attachment.label + ":" + breakpoint.line,
lineNumber: breakpoint.line,
lineText: breakpoint.text,
truncatedLineText: trim(breakpoint.text, MAX_LINE_TEXT_LENGTH, "end")

View File

@ -88,6 +88,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
Cu.import("resource:///modules/devtools/shared/event-emitter.js");
Cu.import("resource:///modules/devtools/SimpleListWidget.jsm");
Cu.import("resource:///modules/devtools/BreadcrumbsWidget.jsm");
Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
Cu.import("resource:///modules/devtools/VariablesView.jsm");
@ -887,11 +888,8 @@ StackFrames.prototype = {
}
} while ((environment = environment.parent));
// Signal that scope environments have been shown and commit the current
// variables view hierarchy to briefly flash items that changed between the
// previous and current scope/variables/properties.
// Signal that scope environments have been shown.
window.emit(EVENTS.FETCHED_SCOPES);
DebuggerView.Variables.commitHierarchy();
},
/**
@ -1005,11 +1003,8 @@ StackFrames.prototype = {
expRef.separatorStr = L10N.getStr("variablesSeparatorLabel");
}
// Signal that watch expressions have been fetched and commit the
// current variables view hierarchy to briefly flash items that changed
// between the previous and current scope/variables/properties.
// Signal that watch expressions have been fetched.
window.emit(EVENTS.FETCHED_WATCH_EXPRESSIONS);
DebuggerView.Variables.commitHierarchy();
});
},

View File

@ -24,7 +24,6 @@ function SourcesView() {
this._onEditorUnload = this._onEditorUnload.bind(this);
this._onEditorCursorActivity = this._onEditorCursorActivity.bind(this);
this._onSourceSelect = this._onSourceSelect.bind(this);
this._onSourceClick = this._onSourceClick.bind(this);
this._onStopBlackBoxing = this._onStopBlackBoxing.bind(this);
this._onBreakpointRemoved = this._onBreakpointRemoved.bind(this);
this._onBreakpointClick = this._onBreakpointClick.bind(this);
@ -69,7 +68,6 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
window.on(EVENTS.EDITOR_LOADED, this._onEditorLoad, false);
window.on(EVENTS.EDITOR_UNLOADED, this._onEditorUnload, false);
this.widget.addEventListener("select", this._onSourceSelect, false);
this.widget.addEventListener("click", this._onSourceClick, false);
this._stopBlackBoxButton.addEventListener("click", this._onStopBlackBoxing, false);
this._cbPanel.addEventListener("popupshowing", this._onConditionalPopupShowing, false);
this._cbPanel.addEventListener("popupshown", this._onConditionalPopupShown, false);
@ -79,8 +77,11 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
this.autoFocusOnSelection = false;
// Show an empty label by default.
this.empty();
// Sort the contents by the displayed label.
this.sortContents((aFirst, aSecond) => {
return +(aFirst.attachment.label.toLowerCase() >
aSecond.attachment.label.toLowerCase());
});
},
/**
@ -92,7 +93,6 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
window.off(EVENTS.EDITOR_LOADED, this._onEditorLoad, false);
window.off(EVENTS.EDITOR_UNLOADED, this._onEditorUnload, false);
this.widget.removeEventListener("select", this._onSourceSelect, false);
this.widget.removeEventListener("click", this._onSourceClick, false);
this._stopBlackBoxButton.removeEventListener("click", this._onStopBlackBoxing, false);
this._cbPanel.removeEventListener("popupshowing", this._onConditionalPopupShowing, false);
this._cbPanel.removeEventListener("popupshowing", this._onConditionalPopupShown, false);
@ -129,10 +129,17 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
let label = SourceUtils.getSourceLabel(url.split(" -> ").pop());
let group = SourceUtils.getSourceGroup(url.split(" -> ").pop());
let contents = document.createElement("label");
contents.setAttribute("value", label);
contents.setAttribute("crop", "start");
contents.setAttribute("flex", "1");
// Append a source item to this container.
this.push([label, url, group], {
this.push([contents, url], {
staged: aOptions.staged, /* stage the item to be appended later? */
attachment: {
label: label,
group: group,
checkboxState: !aSource.isBlackBoxed,
checkboxTooltip: this._blackBoxCheckboxTooltip,
source: aSource
@ -796,14 +803,6 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
this.updateToolbarButtonsState();
},
/**
* The click listener for the sources container.
*/
_onSourceClick: function() {
// Use this container as a filtering target.
DebuggerView.Filtering.target = this;
},
/**
* The click listener for the "stop black boxing" button.
*/
@ -1115,8 +1114,6 @@ TracerView.prototype = Heritage.extend(WidgetMethods, {
this._traceButton = null;
this._tracerTab.remove();
this._tracerTab = null;
document.getElementById("tracer-tabpanel").remove();
this.widget = null;
return;
}
@ -1214,8 +1211,8 @@ TracerView.prototype = Heritage.extend(WidgetMethods, {
_populateVariable: function(aName, aParent, aValue) {
let item = aParent.addItem(aName, { value: aValue });
if (aValue) {
DebuggerView.Variables.controller.populate(
item, new DebuggerController.Tracer.WrappedObject(aValue));
let wrappedValue = new DebuggerController.Tracer.WrappedObject(aValue);
DebuggerView.Variables.controller.populate(item, wrappedValue);
item.expand();
item.twisty = false;
}
@ -1251,9 +1248,7 @@ TracerView.prototype = Heritage.extend(WidgetMethods, {
}
}
} else {
const varName = "<" +
(data.type == "throw" ? "exception" : data.type) +
">";
const varName = "<" + (data.type == "throw" ? "exception" : data.type) + ">";
this._populateVariable(varName, scope, data.returnVal);
}
@ -1265,8 +1260,11 @@ TracerView.prototype = Heritage.extend(WidgetMethods, {
* Add the hover frame enter/exit highlighting to a given item.
*/
_highlightItem: function(aItem) {
aItem.target.querySelector(".trace-item")
.classList.add("selected-matching");
if (!aItem || !aItem.target) {
return;
}
const trace = aItem.target.querySelector(".trace-item");
trace.classList.add("selected-matching");
},
/**
@ -1303,8 +1301,11 @@ TracerView.prototype = Heritage.extend(WidgetMethods, {
* Highlight the frame enter/exit pair of items for the given item.
*/
_highlightMatchingItems: function(aItem) {
const frameId = aItem.attachment.trace.frameId;
const predicate = e => e.attachment.trace.frameId == frameId;
this._unhighlightMatchingItems();
this._matchingItems = this.items.filter(t => t.value == aItem.value);
this._matchingItems = this.items.filter(predicate);
this._matchingItems
.filter(this._isNotSelectedItem)
.forEach(this._highlightItem);
@ -1325,8 +1326,8 @@ TracerView.prototype = Heritage.extend(WidgetMethods, {
*/
_onSearch: function() {
const query = this._search.value.trim().toLowerCase();
this.filterContents(item =>
item.attachment.trace.name.toLowerCase().contains(query));
const predicate = name => name.toLowerCase().contains(query);
this.filterContents(item => predicate(item.attachment.trace.name));
},
/**
@ -1356,13 +1357,11 @@ TracerView.prototype = Heritage.extend(WidgetMethods, {
* The trace record coming from the tracer actor.
*/
addTrace: function(aTrace) {
const { type, frameId } = aTrace;
// Create the element node for the trace item.
let view = this._createView(aTrace);
// Append a source item to this container.
this.push([view, aTrace.frameId, ""], {
this.push([view], {
staged: true,
attachment: {
trace: aTrace
@ -1376,8 +1375,9 @@ TracerView.prototype = Heritage.extend(WidgetMethods, {
* @return nsIDOMNode
* The network request view.
*/
_createView: function({ type, name, frameId, parameterNames, returnVal,
location, depth, arguments: args }) {
_createView: function(aTrace) {
let { type, name, location, depth, frameId } = aTrace;
let { parameterNames, returnVal, arguments: args } = aTrace;
let fragment = document.createDocumentFragment();
this._templateItem.setAttribute("tooltiptext", SourceUtils.trimUrl(location.url));
@ -1659,7 +1659,7 @@ let SourceUtils = {
if (aLabel && aLabel.indexOf("?") != 0) {
// A page may contain multiple requests to the same url but with different
// queries. It is *not* redundant to show each one.
if (!DebuggerView.Sources.containsLabel(aLabel)) {
if (!DebuggerView.Sources.getItemForAttachment(e => e.label == aLabel)) {
return aLabel;
}
}
@ -1984,11 +1984,11 @@ WatchExpressionsView.prototype = Heritage.extend(WidgetMethods, {
initialize: function() {
dumpn("Initializing the WatchExpressionsView");
this.widget = new ListWidget(document.getElementById("expressions"));
this.widget.permaText = L10N.getStr("addWatchExpressionText");
this.widget.itemFactory = this._createItemView;
this.widget = new SimpleListWidget(document.getElementById("expressions"));
this.widget.setAttribute("context", "debuggerWatchExpressionsContextMenu");
this.widget.addEventListener("click", this._onClick, false);
this.headerText = L10N.getStr("addWatchExpressionText");
},
/**
@ -2010,19 +2010,22 @@ WatchExpressionsView.prototype = Heritage.extend(WidgetMethods, {
// Watch expressions are UI elements which benefit from visible panes.
DebuggerView.showInstrumentsPane();
// Create the element node for the watch expression item.
let itemView = this._createItemView(aExpression);
// Append a watch expression item to this container.
let expressionItem = this.push([, aExpression], {
let expressionItem = this.push([itemView.container], {
index: 0, /* specifies on which position should the item be appended */
relaxed: true, /* this container should allow dupes & degenerates */
attachment: {
view: itemView,
initialExpression: aExpression,
currentExpression: ""
currentExpression: "",
}
});
// Automatically focus the new watch expression input.
expressionItem.attachment.inputNode.select();
expressionItem.attachment.inputNode.focus();
expressionItem.attachment.view.inputNode.select();
expressionItem.attachment.view.inputNode.focus();
DebuggerView.Variables.parentNode.scrollTop = 0;
},
@ -2048,7 +2051,7 @@ WatchExpressionsView.prototype = Heritage.extend(WidgetMethods, {
// Save the watch expression code string.
expressionItem.attachment.currentExpression = aExpression;
expressionItem.attachment.inputNode.value = aExpression;
expressionItem.attachment.view.inputNode.value = aExpression;
// Synchronize with the controller's watch expressions store.
DebuggerController.StackFrames.syncWatchExpressions();
@ -2098,18 +2101,19 @@ WatchExpressionsView.prototype = Heritage.extend(WidgetMethods, {
/**
* Customization function for creating an item's UI.
*
* @param nsIDOMNode aElementNode
* The element associated with the displayed item.
* @param any aAttachment
* Some attached primitive/object.
* @param string aExpression
* The watch expression string.
*/
_createItemView: function(aElementNode, aAttachment) {
let arrowNode = document.createElement("box");
_createItemView: function(aExpression) {
let container = document.createElement("hbox");
container.className = "list-widget-item dbg-expression";
let arrowNode = document.createElement("hbox");
arrowNode.className = "dbg-expression-arrow";
let inputNode = document.createElement("textbox");
inputNode.className = "plain dbg-expression-input devtools-monospace";
inputNode.setAttribute("value", aAttachment.initialExpression);
inputNode.setAttribute("value", aExpression);
inputNode.setAttribute("flex", "1");
let closeNode = document.createElement("toolbarbutton");
@ -2119,14 +2123,16 @@ WatchExpressionsView.prototype = Heritage.extend(WidgetMethods, {
inputNode.addEventListener("blur", this._onBlur, false);
inputNode.addEventListener("keypress", this._onKeyPress, false);
aElementNode.className = "dbg-expression";
aElementNode.appendChild(arrowNode);
aElementNode.appendChild(inputNode);
aElementNode.appendChild(closeNode);
container.appendChild(arrowNode);
container.appendChild(inputNode);
container.appendChild(closeNode);
aAttachment.arrowNode = arrowNode;
aAttachment.inputNode = inputNode;
aAttachment.closeNode = closeNode;
return {
container: container,
arrowNode: arrowNode,
inputNode: inputNode,
closeNode: closeNode
};
},
/**
@ -2251,9 +2257,6 @@ EventListenersView.prototype = Heritage.extend(WidgetMethods, {
this.widget.addEventListener("check", this._onCheck, false);
this.widget.addEventListener("click", this._onClick, false);
// Show an empty label by default.
this.empty();
},
/**
@ -2368,13 +2371,14 @@ EventListenersView.prototype = Heritage.extend(WidgetMethods, {
DebuggerController.Breakpoints.DOM.activeEventNames.indexOf(type) != -1;
// Append an event listener item to this container.
this.push([itemView.container, url, group], {
this.push([itemView.container], {
staged: aOptions.staged, /* stage the item to be appended later? */
attachment: {
url: url,
type: type,
view: itemView,
selectors: [selector],
group: group,
checkboxState: checkboxState,
checkboxTooltip: this._eventCheckboxTooltip
}
@ -2494,7 +2498,6 @@ EventListenersView.prototype = Heritage.extend(WidgetMethods, {
function GlobalSearchView() {
dumpn("GlobalSearchView was instantiated");
this._createItemView = this._createItemView.bind(this);
this._onHeaderClick = this._onHeaderClick.bind(this);
this._onLineClick = this._onLineClick.bind(this);
this._onMatchClick = this._onMatchClick.bind(this);
@ -2507,11 +2510,10 @@ GlobalSearchView.prototype = Heritage.extend(WidgetMethods, {
initialize: function() {
dumpn("Initializing the GlobalSearchView");
this.widget = new ListWidget(document.getElementById("globalsearch"));
this.widget = new SimpleListWidget(document.getElementById("globalsearch"));
this._splitter = document.querySelector("#globalsearch + .devtools-horizontal-splitter");
this.widget.emptyText = L10N.getStr("noMatchingStringsText");
this.widget.itemFactory = this._createItemView;
this.emptyText = L10N.getStr("noMatchingStringsText");
},
/**
@ -2718,30 +2720,21 @@ GlobalSearchView.prototype = Heritage.extend(WidgetMethods, {
* An object containing all the matched lines for a specific source.
*/
_createSourceResultsUI: function(aSourceResults) {
// Append a source results item to this container.
this.push([], {
index: -1, /* specifies on which position should the item be appended */
relaxed: true, /* this container should allow dupes & degenerates */
attachment: {
sourceResults: aSourceResults
}
});
},
/**
* Customization function for creating an item's UI.
*
* @param nsIDOMNode aElementNode
* The element associated with the displayed item.
* @param any aAttachment
* Some attached primitive/object.
*/
_createItemView: function(aElementNode, aAttachment) {
aAttachment.sourceResults.createView(aElementNode, {
// Create the element node for the source results item.
let container = document.createElement("hbox");
aSourceResults.createView(container, {
onHeaderClick: this._onHeaderClick,
onLineClick: this._onLineClick,
onMatchClick: this._onMatchClick
});
// Append a source results item to this container.
let item = this.push([container], {
index: -1, /* specifies on which position should the item be appended */
attachment: {
sourceResults: aSourceResults
}
});
},
/**
@ -2792,10 +2785,7 @@ GlobalSearchView.prototype = Heritage.extend(WidgetMethods, {
* The match to scroll into view.
*/
_scrollMatchIntoViewIfNeeded: function(aMatch) {
// TODO: Accessing private widget properties. Figure out what's the best
// way to expose such things. Bug 876271.
let boxObject = this.widget._parent.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
boxObject.ensureElementIsVisible(aMatch);
this.widget.ensureElementIsVisible(aMatch);
},
/**

View File

@ -36,7 +36,6 @@ ToolbarView.prototype = {
this._stepOverButton = document.getElementById("step-over");
this._stepInButton = document.getElementById("step-in");
this._stepOutButton = document.getElementById("step-out");
this._chromeGlobals = document.getElementById("chrome-globals");
let resumeKey = ShortcutUtils.prettifyShortcut(document.getElementById("resumeKey"));
let stepOverKey = ShortcutUtils.prettifyShortcut(document.getElementById("stepOverKey"));
@ -57,9 +56,6 @@ ToolbarView.prototype = {
this._stepOverButton.setAttribute("tooltiptext", this._stepOverTooltip);
this._stepInButton.setAttribute("tooltiptext", this._stepInTooltip);
this._stepOutButton.setAttribute("tooltiptext", this._stepOutTooltip);
// TODO: bug 806775 - group scripts by globals using hostAnnotations.
// this.toggleChromeGlobalsContainer(window._isChromeDebugger);
},
/**
@ -109,16 +105,6 @@ ToolbarView.prototype = {
}
},
/**
* Sets the chrome globals container hidden or visible. It's hidden by default.
*
* @param boolean aVisibleFlag
* Specifies the intended visibility.
*/
toggleChromeGlobalsContainer: function(aVisibleFlag) {
this._chromeGlobals.setAttribute("hidden", !aVisibleFlag);
},
/**
* Listener handling the toggle button click event.
*/
@ -182,7 +168,6 @@ ToolbarView.prototype = {
_stepOverButton: null,
_stepInButton: null,
_stepOutButton: null,
_chromeGlobals: null,
_resumeTooltip: "",
_pauseTooltip: "",
_stepOverTooltip: "",
@ -341,59 +326,6 @@ OptionsView.prototype = {
_showOriginalSourceItem: null
};
/**
* Functions handling the chrome globals UI.
*/
function ChromeGlobalsView() {
dumpn("ChromeGlobalsView was instantiated");
this._onSelect = this._onSelect.bind(this);
this._onClick = this._onClick.bind(this);
}
ChromeGlobalsView.prototype = Heritage.extend(WidgetMethods, {
/**
* Initialization function, called when the debugger is started.
*/
initialize: function() {
dumpn("Initializing the ChromeGlobalsView");
this.widget = document.getElementById("chrome-globals");
this.emptyText = L10N.getStr("noGlobalsText");
this.widget.addEventListener("select", this._onSelect, false);
this.widget.addEventListener("click", this._onClick, false);
// Show an empty label by default.
this.empty();
},
/**
* Destruction function, called when the debugger is closed.
*/
destroy: function() {
dumpn("Destroying the ChromeGlobalsView");
this.widget.removeEventListener("select", this._onSelect, false);
this.widget.removeEventListener("click", this._onClick, false);
},
/**
* The select listener for the chrome globals container.
*/
_onSelect: function() {
// TODO: bug 806775, do something useful for chrome debugging.
},
/**
* The click listener for the chrome globals container.
*/
_onClick: function() {
// Use this container as a filtering target.
DebuggerView.Filtering.target = this;
}
});
/**
* Functions handling the stackframes UI.
*/
@ -466,9 +398,12 @@ StackFramesView.prototype = Heritage.extend(WidgetMethods, {
let frameView = this._createFrameView.apply(this, arguments);
// Append a stack frame item to this container.
this.push([frameView, aTitle, aUrl], {
this.push([frameView], {
index: 0, /* specifies on which position should the item be appended */
attachment: {
title: aTitle,
url: aUrl,
line: aLine,
depth: aDepth
},
// Make sure that when the stack frame item is removed, the corresponding
@ -599,16 +534,13 @@ StackFramesView.prototype = Heritage.extend(WidgetMethods, {
* Requests the addition of more frames from the controller.
*/
_afterScroll: function() {
// TODO: Accessing private widget properties. Figure out what's the best
// way to expose such things. Bug 876271.
let list = this.widget._list;
let scrollPosition = list.scrollPosition;
let scrollWidth = list.scrollWidth;
let scrollPosition = this.widget.getAttribute("scrollPosition");
let scrollWidth = this.widget.getAttribute("scrollWidth");
// If the stackframes container scrolled almost to the end, with only
// 1/10 of a breadcrumb remaining, load more content.
if (scrollPosition - scrollWidth / 10 < 1) {
list.ensureElementIsVisible(this.getItemAtIndex(CALL_STACK_PAGE_SIZE - 1).target);
this.ensureIndexIsVisible(CALL_STACK_PAGE_SIZE - 1);
this.dirty = false;
// Loads more stack frames from the debugger server cache.
@ -648,9 +580,6 @@ StackFramesClassicListView.prototype = Heritage.extend(WidgetMethods, {
// This view's contents are also mirrored in a different container.
this._mirror = DebuggerView.StackFrames;
// Show an empty label by default.
this.empty();
},
/**
@ -679,7 +608,7 @@ StackFramesClassicListView.prototype = Heritage.extend(WidgetMethods, {
let frameView = this._createFrameView.apply(this, arguments);
// Append a stack frame item to this container.
this.push([frameView, aUrl], {
this.push([frameView], {
attachment: {
depth: aDepth
}
@ -798,6 +727,9 @@ FilterView.prototype = {
this._searchbox.addEventListener("keypress", this._onKeyPress, false);
this._searchbox.addEventListener("blur", this._onBlur, false);
let placeholder = L10N.getFormatStr("emptySearchText", this._fileSearchKey);
this._searchbox.setAttribute("placeholder", placeholder);
this._globalOperatorButton.setAttribute("label", SEARCH_GLOBAL_FLAG);
this._functionOperatorButton.setAttribute("label", SEARCH_FUNCTION_FLAG);
this._tokenOperatorButton.setAttribute("label", SEARCH_TOKEN_FLAG);
@ -816,13 +748,6 @@ FilterView.prototype = {
L10N.getFormatStr("searchPanelGoToLine", this._lineSearchKey));
this._variableOperatorLabel.setAttribute("value",
L10N.getFormatStr("searchPanelVariable", this._variableSearchKey));
// TODO: bug 806775 - group scripts by globals using hostAnnotations.
// if (window._isChromeDebugger) {
// this.target = DebuggerView.ChromeGlobals;
// } else {
this.target = DebuggerView.Sources;
// }
},
/**
@ -838,30 +763,6 @@ FilterView.prototype = {
this._searchbox.removeEventListener("blur", this._onBlur, false);
},
/**
* Sets the target container to be currently filtered.
* @param object aView
*/
set target(aView) {
let placeholder = "";
switch (aView) {
case DebuggerView.ChromeGlobals:
placeholder = L10N.getFormatStr("emptyChromeGlobalsFilterText", this._fileSearchKey);
break;
case DebuggerView.Sources:
placeholder = L10N.getFormatStr("emptySearchText", this._fileSearchKey);
break;
}
this._searchbox.setAttribute("placeholder", placeholder);
this._target = aView;
},
/**
* Gets the target container to be currently filtered.
* @return object
*/
get target() this._target,
/**
* Gets the entered operator and arguments in the searchbox.
* @return array
@ -1241,7 +1142,6 @@ FilterView.prototype = {
_tokenSearchKey: "",
_lineSearchKey: "",
_variableSearchKey: "",
_target: null
};
/**
@ -1309,7 +1209,7 @@ FilteredSourcesView.prototype = Heritage.extend(ResultsPanelContainer.prototype,
}
for (let item of DebuggerView.Sources.items) {
let lowerCaseLabel = item.label.toLowerCase();
let lowerCaseLabel = item.attachment.label.toLowerCase();
let lowerCaseToken = aToken.toLowerCase();
if (lowerCaseLabel.match(lowerCaseToken)) {
aStore.push(item);
@ -1343,13 +1243,15 @@ FilteredSourcesView.prototype = Heritage.extend(ResultsPanelContainer.prototype,
}
for (let item of aSearchResults) {
// Append a location item to this container for each match.
let trimmedLabel = SourceUtils.trimUrlLength(item.label);
let trimmedValue = SourceUtils.trimUrlLength(item.value, 0, "start");
// Create the element node for the location item.
let itemView = this._createItemView(
SourceUtils.trimUrlLength(item.attachment.label),
SourceUtils.trimUrlLength(item.value, 0, "start")
);
this.push([trimmedLabel, trimmedValue], {
// Append a location item to this container for each match.
this.push([itemView], {
index: -1, /* specifies on which position should the item be appended */
relaxed: true, /* this container should allow dupes & degenerates */
attachment: {
url: item.value
}
@ -1543,14 +1445,16 @@ FilteredFunctionsView.prototype = Heritage.extend(ResultsPanelContainer.prototyp
item.actualLocation = item.functionLocation;
}
// Append a function item to this container for each match.
let trimmedLabel = SourceUtils.trimUrlLength(item.displayedName + "()");
let trimmedValue = SourceUtils.trimUrlLength(item.sourceUrl, 0, "start");
let description = (item.inferredChain || []).join(".");
// Create the element node for the function item.
let itemView = this._createItemView(
SourceUtils.trimUrlLength(item.displayedName + "()"),
SourceUtils.trimUrlLength(item.sourceUrl, 0, "start"),
(item.inferredChain || []).join(".")
);
this.push([trimmedLabel, trimmedValue, description], {
// Append a function item to this container for each match.
this.push([itemView], {
index: -1, /* specifies on which position should the item be appended */
relaxed: true, /* this container should allow dupes & degenerates */
attachment: item
});
}
@ -1605,6 +1509,5 @@ DebuggerView.Options = new OptionsView();
DebuggerView.Filtering = new FilterView();
DebuggerView.FilteredSources = new FilteredSourcesView();
DebuggerView.FilteredFunctions = new FilteredFunctionsView();
DebuggerView.ChromeGlobals = new ChromeGlobalsView();
DebuggerView.StackFrames = new StackFramesView();
DebuggerView.StackFramesClassicList = new StackFramesClassicListView();

View File

@ -55,7 +55,6 @@ let DebuggerView = {
this.Filtering.initialize();
this.FilteredSources.initialize();
this.FilteredFunctions.initialize();
this.ChromeGlobals.initialize();
this.StackFrames.initialize();
this.StackFramesClassicList.initialize();
this.Sources.initialize();
@ -91,7 +90,6 @@ let DebuggerView = {
this.Filtering.destroy();
this.FilteredSources.destroy();
this.FilteredFunctions.destroy();
this.ChromeGlobals.destroy();
this.StackFrames.destroy();
this.StackFramesClassicList.destroy();
this.Sources.destroy();
@ -181,6 +179,9 @@ let DebuggerView = {
// Relay events from the VariablesView.
this.Variables.on("fetched", (aEvent, aType) => {
switch (aType) {
case "scopes":
window.emit(EVENTS.FETCHED_SCOPES);
break;
case "variables":
window.emit(EVENTS.FETCHED_VARIABLES);
break;
@ -618,7 +619,6 @@ let DebuggerView = {
this.FilteredSources.clearView();
this.FilteredFunctions.clearView();
this.GlobalSearch.clearView();
this.ChromeGlobals.empty();
this.StackFrames.empty();
this.Sources.empty();
this.Variables.empty();
@ -640,7 +640,6 @@ let DebuggerView = {
FilteredSources: null,
FilteredFunctions: null,
GlobalSearch: null,
ChromeGlobals: null,
StackFrames: null,
Sources: null,
Tracer: null,
@ -660,225 +659,6 @@ let DebuggerView = {
_expandPaneString: ""
};
/**
* A stacked list of items, compatible with WidgetMethods instances, used for
* displaying views like the watch expressions, filtering or search results etc.
*
* You should never need to access these methods directly, use the wrapped
* WidgetMethods instead.
*
* @param nsIDOMNode aNode
* The element associated with the widget.
*/
function ListWidget(aNode) {
this._parent = aNode;
// Create an internal list container.
this._list = document.createElement("vbox");
this._parent.appendChild(this._list);
// Delegate some of the associated node's methods to satisfy the interface
// required by WidgetMethods instances.
ViewHelpers.delegateWidgetAttributeMethods(this, aNode);
ViewHelpers.delegateWidgetEventMethods(this, aNode);
}
ListWidget.prototype = {
/**
* Overrides an item's element type (e.g. "vbox" or "hbox") in this container.
* @param string aType
*/
itemType: "hbox",
/**
* Customization function for creating an item's UI in this container.
*
* @param nsIDOMNode aElementNode
* The element associated with the displayed item.
* @param string aLabel
* The item's label.
* @param string aValue
* The item's value.
*/
itemFactory: null,
/**
* Immediately inserts an item in this container at the specified index.
*
* @param number aIndex
* The position in the container intended for this item.
* @param string aLabel
* The label displayed in the container.
* @param string aValue
* The actual internal value of the item.
* @param string aDescription [optional]
* An optional description of the item.
* @param any aAttachment [optional]
* Some attached primitive/object.
* @return nsIDOMNode
* The element associated with the displayed item.
*/
insertItemAt: function(aIndex, aLabel, aValue, aDescription, aAttachment) {
let list = this._list;
let childNodes = list.childNodes;
let element = document.createElement(this.itemType);
this.itemFactory(element, aAttachment, aLabel, aValue, aDescription);
this._removeEmptyNotice();
element.classList.add("list-widget-item");
return list.insertBefore(element, childNodes[aIndex]);
},
/**
* Returns the child node in this container situated at the specified index.
*
* @param number aIndex
* The position in the container intended for this item.
* @return nsIDOMNode
* The element associated with the displayed item.
*/
getItemAtIndex: function(aIndex) {
return this._list.childNodes[aIndex];
},
/**
* Immediately removes the specified child node from this container.
*
* @param nsIDOMNode aChild
* The element associated with the displayed item.
*/
removeChild: function(aChild) {
this._list.removeChild(aChild);
if (this._selectedItem == aChild) {
this._selectedItem = null;
}
if (!this._list.hasChildNodes()) {
this._appendEmptyNotice();
}
},
/**
* Immediately removes all of the child nodes from this container.
*/
removeAllItems: function() {
let parent = this._parent;
let list = this._list;
while (list.hasChildNodes()) {
list.firstChild.remove();
}
parent.scrollTop = 0;
parent.scrollLeft = 0;
this._selectedItem = null;
this._appendEmptyNotice();
},
/**
* Gets the currently selected child node in this container.
* @return nsIDOMNode
*/
get selectedItem() this._selectedItem,
/**
* Sets the currently selected child node in this container.
* @param nsIDOMNode aChild
*/
set selectedItem(aChild) {
let childNodes = this._list.childNodes;
if (!aChild) {
this._selectedItem = null;
}
for (let node of childNodes) {
if (node == aChild) {
node.classList.add("selected");
this._selectedItem = node;
} else {
node.classList.remove("selected");
}
}
},
/**
* Sets the text displayed permanently in this container's header.
* @param string aValue
*/
set permaText(aValue) {
if (this._permaTextNode) {
this._permaTextNode.setAttribute("value", aValue);
}
this._permaTextValue = aValue;
this._appendPermaNotice();
},
/**
* Sets the text displayed in this container when there are no available items.
* @param string aValue
*/
set emptyText(aValue) {
if (this._emptyTextNode) {
this._emptyTextNode.setAttribute("value", aValue);
}
this._emptyTextValue = aValue;
this._appendEmptyNotice();
},
/**
* Creates and appends a label displayed permanently in this container's header.
*/
_appendPermaNotice: function() {
if (this._permaTextNode || !this._permaTextValue) {
return;
}
let label = document.createElement("label");
label.className = "empty list-widget-item";
label.setAttribute("value", this._permaTextValue);
this._parent.insertBefore(label, this._list);
this._permaTextNode = label;
},
/**
* Creates and appends a label signaling that this container is empty.
*/
_appendEmptyNotice: function() {
if (this._emptyTextNode || !this._emptyTextValue) {
return;
}
let label = document.createElement("label");
label.className = "empty list-widget-item";
label.setAttribute("value", this._emptyTextValue);
this._parent.appendChild(label);
this._emptyTextNode = label;
},
/**
* Removes the label signaling that this container is empty.
*/
_removeEmptyNotice: function() {
if (!this._emptyTextNode) {
return;
}
this._parent.removeChild(this._emptyTextNode);
this._emptyTextNode = null;
},
_parent: null,
_list: null,
_selectedItem: null,
_permaTextNode: null,
_permaTextValue: "",
_emptyTextNode: null,
_emptyTextValue: ""
};
/**
* A custom items container, used for displaying views like the
* FilteredSources, FilteredFunctions etc., inheriting the generic WidgetMethods.
@ -906,9 +686,8 @@ ResultsPanelContainer.prototype = Heritage.extend(WidgetMethods, {
document.documentElement.appendChild(this._panel);
}
if (!this.widget) {
this.widget = new ListWidget(this._panel);
this.widget.itemType = "vbox";
this.widget.itemFactory = this._createItemView;
this.widget = new SimpleListWidget(this._panel);
this.maintainSelectionVisible = false;
}
}
// Cleanup the anchor and remove the previously created panel.
@ -923,7 +702,9 @@ ResultsPanelContainer.prototype = Heritage.extend(WidgetMethods, {
* Gets the anchor node for this container panel.
* @return nsIDOMNode
*/
get anchor() this._anchor,
get anchor() {
return this._anchor;
},
/**
* Sets the container panel hidden or visible. It's hidden by default.
@ -982,40 +763,43 @@ ResultsPanelContainer.prototype = Heritage.extend(WidgetMethods, {
/**
* Customization function for creating an item's UI.
*
* @param nsIDOMNode aElementNode
* The element associated with the displayed item.
* @param any aAttachment
* Some attached primitive/object.
* @param string aLabel
* The item's label.
* @param string aValue
* The item's value.
* @param string aDescription
* An optional description of the item.
* The item's label string.
* @param string aBeforeLabel
* An optional string shown before the label.
* @param string aBelowLabel
* An optional string shown underneath the label.
*/
_createItemView: function(aElementNode, aAttachment, aLabel, aValue, aDescription) {
let labelsGroup = document.createElement("hbox");
_createItemView: function(aLabel, aBelowLabel, aBeforeLabel) {
let container = document.createElement("vbox");
container.className = "results-panel-item";
if (aDescription) {
let preLabelNode = document.createElement("label");
preLabelNode.className = "plain results-panel-item-pre";
preLabelNode.setAttribute("value", aDescription);
labelsGroup.appendChild(preLabelNode);
}
if (aLabel) {
let labelNode = document.createElement("label");
labelNode.className = "plain results-panel-item-name";
labelNode.setAttribute("value", aLabel);
labelsGroup.appendChild(labelNode);
let firstRowLabels = document.createElement("hbox");
let secondRowLabels = document.createElement("hbox");
if (aBeforeLabel) {
let beforeLabelNode = document.createElement("label");
beforeLabelNode.className = "plain results-panel-item-label-before";
beforeLabelNode.setAttribute("value", aBeforeLabel);
firstRowLabels.appendChild(beforeLabelNode);
}
let valueNode = document.createElement("label");
valueNode.className = "plain results-panel-item-details";
valueNode.setAttribute("value", aValue);
let labelNode = document.createElement("label");
labelNode.className = "plain results-panel-item-label";
labelNode.setAttribute("value", aLabel);
firstRowLabels.appendChild(labelNode);
aElementNode.className = "light results-panel-item";
aElementNode.appendChild(labelsGroup);
aElementNode.appendChild(valueNode);
if (aBelowLabel) {
let belowLabelNode = document.createElement("label");
belowLabelNode.className = "plain results-panel-item-label-below";
belowLabelNode.setAttribute("value", aBelowLabel);
secondRowLabels.appendChild(belowLabelNode);
}
container.appendChild(firstRowLabels);
container.appendChild(secondRowLabels);
return container;
},
_anchor: null,

View File

@ -11,15 +11,6 @@
-moz-box-orient: vertical;
}
#expressions {
overflow-x: hidden;
overflow-y: auto;
}
#globalsearch {
overflow: auto;
}
/* Toolbar controls */
.devtools-toolbarbutton:not([label]) > .toolbarbutton-text {

View File

@ -324,9 +324,6 @@
tabindex="0"
hidden="true"/>
</hbox>
<menulist id="chrome-globals"
class="devtools-menulist"
sizetopopup="none" hidden="true"/>
<vbox id="stackframes" flex="1"/>
<textbox id="searchbox"
class="devtools-searchinput" type="search"/>
@ -340,7 +337,7 @@
popup="debuggerPrefsContextMenu"
tabindex="0"/>
</toolbar>
<scrollbox id="globalsearch" orient="vertical" hidden="true"/>
<vbox id="globalsearch" orient="vertical" hidden="true"/>
<splitter class="devtools-horizontal-splitter" hidden="true"/>
<hbox id="debugger-widgets" flex="1">
<tabbox id="sources-pane"

View File

@ -84,7 +84,7 @@ support-files =
[browser_dbg_break-on-dom-02.js]
[browser_dbg_break-on-dom-03.js]
[browser_dbg_break-on-dom-04.js]
[browser_dbg_break-on-dom-05.js]
# [browser_dbg_break-on-dom-05.js]
[browser_dbg_break-on-dom-06.js]
[browser_dbg_break-on-dom-07.js]
[browser_dbg_break-on-dom-08.js]

View File

@ -70,16 +70,16 @@ function testForward() {
function validateFirstPage() {
is(gSources.itemCount, 2,
"Found the expected number of sources.");
ok(gSources.containsLabel("code_script-switching-01.js"),
ok(gSources.getItemForAttachment(e => e.label == "code_script-switching-01.js"),
"Found the first source label.");
ok(gSources.containsLabel("code_script-switching-02.js"),
ok(gSources.getItemForAttachment(e => e.label == "code_script-switching-02.js"),
"Found the second source label.");
}
function validateSecondPage() {
is(gSources.itemCount, 1,
"Found the expected number of sources.");
ok(gSources.containsLabel("doc_recursion-stack.html"),
ok(gSources.getItemForAttachment(e => e.label == "doc_recursion-stack.html"),
"Found the single source label.");
}

View File

@ -80,7 +80,7 @@ function test() {
function pauseAndCheck() {
let finished = waitForSourceAndCaretAndScopes(gPanel, "-01.js", 5).then(() => {
is(gSources.selectedLabel, "code_script-switching-01.js",
is(gSources.selectedValue, EXAMPLE_URL + "code_script-switching-01.js",
"The currently selected source is incorrect (3).");
is(gSources.selectedIndex, 0,
"The currently selected source is incorrect (4).");
@ -88,7 +88,7 @@ function test() {
"The editor location is correct after pausing.");
});
is(gSources.selectedLabel, "code_script-switching-02.js",
is(gSources.selectedValue, EXAMPLE_URL + "code_script-switching-02.js",
"The currently selected source is incorrect (1).");
is(gSources.selectedIndex, 1,
"The currently selected source is incorrect (2).");

View File

@ -1,7 +1,5 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const TAB_URL = EXAMPLE_URL + "doc_closures.html";
@ -15,6 +13,7 @@ function test() {
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gDebuggee.gRecurseLimit = 2;
waitForSourceShown(gPanel, ".html")
.then(testClosure)
@ -33,45 +32,25 @@ function test() {
gDebuggee);
});
gDebuggee.gRecurseLimit = 2;
return waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES).then(() => {
let deferred = promise.defer();
let gVars = gDebugger.DebuggerView.Variables,
localScope = gVars.getScopeAtIndex(0),
globalScope = gVars.getScopeAtIndex(1),
localNodes = localScope.target.querySelector(".variables-view-element-details").childNodes,
globalNodes = globalScope.target.querySelector(".variables-view-element-details").childNodes;
let gVars = gDebugger.DebuggerView.Variables;
let localScope = gVars.getScopeAtIndex(0);
let localNodes = localScope.target.querySelector(".variables-view-element-details").childNodes;
is(localNodes[4].querySelector(".name").getAttribute("value"), "person",
"Should have the right property name for |person|.");
is(localNodes[4].querySelector(".value").getAttribute("value"), "Object",
"Should have the right property value for |person|.");
// Expand the 'person' tree node. This causes its properties to be
// retrieved and displayed.
let personNode = gVars.getItemForNode(localNodes[4]);
let personFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES);
personNode.expand();
is(personNode.expanded, true, "person should be expanded at this point.");
// Poll every few milliseconds until the properties are retrieved.
// It's important to set the timer in the chrome window, because the
// content window timers are disabled while the debuggee is paused.
let count1 = 0;
let intervalID = window.setInterval(function(){
info("count1: " + count1);
if (++count1 > 50) {
ok(false, "Timed out while polling for the properties.");
window.clearInterval(intervalID);
deferred.reject("Timed out.");
return;
}
if (!personNode._retrieved) {
return;
}
window.clearInterval(intervalID);
return personFetched.then(() => {
is(personNode.expanded, true,
"|person| should be expanded at this point.");
is(personNode.get("getName").target.querySelector(".name")
.getAttribute("value"), "getName",
@ -90,27 +69,16 @@ function test() {
// retrieved and displayed.
let getFooNode = personNode.get("getFoo");
let getNameNode = personNode.get("getName");
let funcsFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES, 2);
let funcClosuresFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES, 2);
getFooNode.expand();
getNameNode.expand();
is(getFooNode.expanded, true, "person.getFoo should be expanded at this point.");
is(getNameNode.expanded, true, "person.getName should be expanded at this point.");
// Poll every few milliseconds until the properties are retrieved.
// It's important to set the timer in the chrome window, because the
// content window timers are disabled while the debuggee is paused.
let count2 = 0;
let intervalID1 = window.setInterval(function(){
info("count2: " + count2);
if (++count2 > 50) {
ok(false, "Timed out while polling for the properties.");
window.clearInterval(intervalID1);
deferred.reject("Timed out.");
return;
}
if (!getFooNode._retrieved || !getNameNode._retrieved) {
return;
}
window.clearInterval(intervalID1);
return funcsFetched.then(() => {
is(getFooNode.expanded, true,
"|person.getFoo| should be expanded at this point.");
is(getNameNode.expanded, true,
"|person.getName| should be expanded at this point.");
is(getFooNode.get("<Closure>").target.querySelector(".name")
.getAttribute("value"), "<Closure>",
@ -125,30 +93,18 @@ function test() {
.getAttribute("value"), "",
"The closure node has no value for getName.");
// Expand the Closure nodes.
// Expand the closure nodes. This causes their environments to be
// retrieved and displayed.
let getFooClosure = getFooNode.get("<Closure>");
let getNameClosure = getNameNode.get("<Closure>");
getFooClosure.expand();
getNameClosure.expand();
is(getFooClosure.expanded, true, "person.getFoo closure should be expanded at this point.");
is(getNameClosure.expanded, true, "person.getName closure should be expanded at this point.");
// Poll every few milliseconds until the properties are retrieved.
// It's important to set the timer in the chrome window, because the
// content window timers are disabled while the debuggee is paused.
let count3 = 0;
let intervalID2 = window.setInterval(function(){
info("count3: " + count3);
if (++count3 > 50) {
ok(false, "Timed out while polling for the properties.");
window.clearInterval(intervalID2);
deferred.reject("Timed out.");
return;
}
if (!getFooClosure._retrieved || !getNameClosure._retrieved) {
return;
}
window.clearInterval(intervalID2);
return funcClosuresFetched.then(() => {
is(getFooClosure.expanded, true,
"|person.getFoo| closure should be expanded at this point.");
is(getNameClosure.expanded, true,
"|person.getName| closure should be expanded at this point.");
is(getFooClosure.get("Function scope [_pfactory]").target.querySelector(".name")
.getAttribute("value"), "Function scope [_pfactory]",
@ -166,27 +122,15 @@ function test() {
// Expand the scope nodes.
let getFooInnerScope = getFooClosure.get("Function scope [_pfactory]");
let getNameInnerScope = getNameClosure.get("Function scope [_pfactory]");
let innerFuncsFetched = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES, 2);
getFooInnerScope.expand();
getNameInnerScope.expand();
is(getFooInnerScope.expanded, true, "person.getFoo inner scope should be expanded at this point.");
is(getNameInnerScope.expanded, true, "person.getName inner scope should be expanded at this point.");
// Poll every few milliseconds until the properties are retrieved.
// It's important to set the timer in the chrome window, because the
// content window timers are disabled while the debuggee is paused.
let count4 = 0;
let intervalID3 = window.setInterval(function(){
info("count4: " + count4);
if (++count4 > 50) {
ok(false, "Timed out while polling for the properties.");
window.clearInterval(intervalID3);
deferred.reject("Timed out.");
return;
}
if (!getFooInnerScope._retrieved || !getNameInnerScope._retrieved) {
return;
}
window.clearInterval(intervalID3);
return funcsFetched.then(() => {
is(getFooInnerScope.expanded, true,
"|person.getFoo| inner scope should be expanded at this point.");
is(getNameInnerScope.expanded, true,
"|person.getName| inner scope should be expanded at this point.");
// Only test that each function closes over the necessary variable.
// We wouldn't want future SpiderMonkey closure space
@ -203,14 +147,10 @@ function test() {
is(getNameInnerScope.get("name").target.querySelector(".value")
.getAttribute("value"), '"Bob"',
"The name node has the expected value.");
deferred.resolve();
}, 100);
}, 100);
}, 100);
}, 100);
return deferred.promise;
});
});
});
});
});
}
}

View File

@ -47,7 +47,7 @@ function testInitialSource() {
"The third source is not displayed.");
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
gSources.selectedLabel = "code_script-switching-01.js";
gSources.selectedItem = e => e.attachment.label == "code_script-switching-01.js";
return finished;
}
@ -65,7 +65,7 @@ function testSwitch1() {
"The third source is not displayed.");
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
gSources.selectedLabel = "doc_editor-mode.html";
gSources.selectedItem = e => e.attachment.label == "doc_editor-mode.html";
return finished;
}

View File

@ -43,10 +43,10 @@ function test() {
"Found the expected number of entries in the sources widget.");
is(gEditor.getText().indexOf("debugger"), 348,
"The correct source was loaded initially.");
is(gSources.selectedLabel, "doc_inline-debugger-statement.html",
"The currently selected source label is incorrect.");
is(gSources.selectedValue, EXAMPLE_URL + "doc_inline-debugger-statement.html",
"The currently selected source value is incorrect (0).");
is(gSources.selectedValue, gSources.values[0],
"The currently selected source value is incorrect.");
"The currently selected source value is incorrect (1).");
}
function checkIframePause() {

View File

@ -35,8 +35,6 @@ function performTest() {
is(gSources.itemCount, 1,
"Found the expected number of entries in the sources widget.");
isnot(gSources.selectedLabel, null,
"There should be a selected source label.");
isnot(gSources.selectedValue, null,
"There should be a selected source value.");
isnot(gEditor.getText().length, 0,
@ -44,11 +42,6 @@ function performTest() {
isnot(gEditor.getText(), gDebugger.L10N.getStr("loadingText"),
"The source editor text should not be 'Loading...'");
is(gSources.widget.getAttribute("label"), "doc_recursion-stack.html",
"The sources widget should have a correct label attribute.");
is(gSources.widget.getAttribute("tooltiptext"), "http://example.com",
"The sources widget should have a correct tooltip text attribute.");
is(gDebugger.document.querySelectorAll("#sources .side-menu-widget-empty-notice-container").length, 0,
"The sources widget should not display any notice at this point (1).");
is(gDebugger.document.querySelectorAll("#sources .side-menu-widget-empty-notice").length, 0,

View File

@ -36,25 +36,16 @@ function testLocationChange() {
is(gSources.itemCount, 0,
"Found no entries in the sources widget.");
is(gSources.selectedLabel, "",
"There should be no selected source label.");
is(gSources.selectedValue, "",
"There should be no selected source value.");
is(gEditor.getText().length, 0,
"The source editor should not have any text displayed.");
is(gSources.widget.getAttribute("label"), gDebugger.L10N.getStr("noSourcesText"),
"The sources widget should display a notice that there are no sources availalble.");
is(gSources.widget.getAttribute("tooltiptext"), "",
"The sources widget shouldn't have any tooltip text attribute when there are no sources available.");
is(gDebugger.document.querySelectorAll("#sources .side-menu-widget-empty-notice-container").length, 1,
is(gDebugger.document.querySelectorAll("#sources .side-menu-widget-empty-text").length, 1,
"The sources widget should now display a notice (1).");
is(gDebugger.document.querySelectorAll("#sources .side-menu-widget-empty-notice").length, 1,
is(gDebugger.document.querySelectorAll("#sources .side-menu-widget-empty-text")[0].getAttribute("value"),
gDebugger.L10N.getStr("noSourcesText"),
"The sources widget should now display a notice (2).");
is(gDebugger.document.querySelector("#sources .side-menu-widget-empty-notice").getAttribute("value"),
gSources.widget.getAttribute("label"),
"The sources widget should now display a notice (3).");
closeDebuggerAndFinish(gPanel);
});

View File

@ -37,8 +37,6 @@ function testLocationChange() {
is(gSources.itemCount, 1,
"Found the expected number of entries in the sources widget.");
is(gSources.selectedLabel, "doc_inline-debugger-statement.html",
"There should be a selected source label.");
is(gSources.selectedValue, EXAMPLE_URL + "doc_inline-debugger-statement.html",
"There should be a selected source value.");
isnot(gEditor.getText().length, 0,
@ -46,17 +44,8 @@ function testLocationChange() {
is(gEditor.getText(), gDebugger.L10N.getStr("loadingText"),
"The source editor text should not be 'Loading...'");
is(gSources.widget.getAttribute("label"), "doc_inline-debugger-statement.html",
"The sources widget should have a correct label attribute.");
is(gSources.widget.getAttribute("tooltiptext"), "http://example.com",
"The sources widget should have a correct tooltip text attribute.");
is(gDebugger.document.querySelectorAll("#sources .side-menu-widget-empty-notice-container").length, 0,
"The sources widget should not display any notice at this point (1).");
is(gDebugger.document.querySelectorAll("#sources .side-menu-widget-empty-notice").length, 0,
"The sources widget should not display any notice at this point (2).");
is(gDebugger.document.querySelector("#sources .side-menu-widget-empty-notice > label"), null,
"The sources widget should not display a notice at this point (3).");
is(gDebugger.document.querySelectorAll("#sources .side-menu-widget-empty-text").length, 0,
"The sources widget should not display any notice at this point.");
closeDebuggerAndFinish(gPanel);
});

View File

@ -60,5 +60,13 @@ function test() {
verify("foo = bar", e => e.name == "bar", [1, 6], [1, 9]);
verify("\nfoo\n=\nbar\n", e => e.name == "bar", [4, 0], [4, 3]);
// LabeledStatement and ContinueStatement, because it's 1968 again
verify("foo: bar", e => e.name == "foo", [1, 0], [1, 3]);
verify("\nfoo\n:\nbar\n", e => e.name == "foo", [2, 0], [2, 3]);
verify("foo: for(;;) continue foo", e => e.name == "foo", [1, 22], [1, 25]);
verify("\nfoo\n:\nfor(\n;\n;\n)\ncontinue\nfoo\n", e => e.name == "foo", [9, 0], [9, 3]);
finish();
}

View File

@ -50,15 +50,13 @@ function testSourcesDisplay() {
ok(gSources.containsValue(EXAMPLE_URL + gLabel2),
"Second source url is incorrect.");
ok(gSources.containsLabel(gLabel1),
ok(gSources.getItemForAttachment(e => e.label == gLabel1),
"First source label is incorrect.");
ok(gSources.containsLabel(gLabel2),
ok(gSources.getItemForAttachment(e => e.label == gLabel2),
"Second source label is incorrect.");
ok(gSources.selectedItem,
"There should be a selected item in the sources pane.");
is(gSources.selectedLabel, gLabel2,
"The selected label is the sources pane is incorrect.");
is(gSources.selectedValue, EXAMPLE_URL + gLabel2,
"The selected value is the sources pane is incorrect.");
@ -92,8 +90,6 @@ function testSwitchPaused1() {
ok(gSources.selectedItem,
"There should be a selected item in the sources pane.");
is(gSources.selectedLabel, gLabel1,
"The selected label is the sources pane is incorrect.");
is(gSources.selectedValue, EXAMPLE_URL + gLabel1,
"The selected value is the sources pane is incorrect.");
@ -123,8 +119,6 @@ function testSwitchPaused2() {
ok(gSources.selectedItem,
"There should be a selected item in the sources pane.");
is(gSources.selectedLabel, gLabel2,
"The selected label is the sources pane is incorrect.");
is(gSources.selectedValue, EXAMPLE_URL + gLabel2,
"The selected value is the sources pane is incorrect.");
@ -161,8 +155,6 @@ function testSwitchRunning() {
ok(gSources.selectedItem,
"There should be a selected item in the sources pane.");
is(gSources.selectedLabel, gLabel1,
"The selected label is the sources pane is incorrect.");
is(gSources.selectedValue, EXAMPLE_URL + gLabel1,
"The selected value is the sources pane is incorrect.");

View File

@ -48,15 +48,13 @@ function testSourcesDisplay() {
ok(gSources.containsValue(EXAMPLE_URL + gLabel2 + gParams),
"Second source url is incorrect.");
ok(gSources.containsLabel(gLabel1),
ok(gSources.getItemForAttachment(e => e.label == gLabel1),
"First source label is incorrect.");
ok(gSources.containsLabel(gLabel2),
ok(gSources.getItemForAttachment(e => e.label == gLabel2),
"Second source label is incorrect.");
ok(gSources.selectedItem,
"There should be a selected item in the sources pane.");
is(gSources.selectedLabel, gLabel2,
"The selected label is the sources pane is incorrect.");
is(gSources.selectedValue, EXAMPLE_URL + gLabel2 + gParams,
"The selected value is the sources pane is incorrect.");
@ -76,7 +74,7 @@ function testSourcesDisplay() {
"The debugged line is highlighted appropriately.");
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN).then(deferred.resolve);
gSources.selectedLabel = gLabel1;
gSources.selectedItem = e => e.attachment.label == gLabel1;
});
return deferred.promise;
@ -87,8 +85,6 @@ function testSwitchPaused1() {
ok(gSources.selectedItem,
"There should be a selected item in the sources pane.");
is(gSources.selectedLabel, gLabel1,
"The selected label is the sources pane is incorrect.");
is(gSources.selectedValue, EXAMPLE_URL + gLabel1,
"The selected value is the sources pane is incorrect.");
@ -108,7 +104,7 @@ function testSwitchPaused1() {
"The debugged line highlight was removed.");
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN).then(deferred.resolve);
gSources.selectedLabel = gLabel2;
gSources.selectedItem = e => e.attachment.label == gLabel2;
});
return deferred.promise;
@ -119,8 +115,6 @@ function testSwitchPaused2() {
ok(gSources.selectedItem,
"There should be a selected item in the sources pane.");
is(gSources.selectedLabel, gLabel2,
"The selected label is the sources pane is incorrect.");
is(gSources.selectedValue, EXAMPLE_URL + gLabel2 + gParams,
"The selected value is the sources pane is incorrect.");
@ -157,8 +151,6 @@ function testSwitchRunning() {
ok(gSources.selectedItem,
"There should be a selected item in the sources pane.");
is(gSources.selectedLabel, gLabel1,
"The selected label is the sources pane is incorrect.");
is(gSources.selectedValue, EXAMPLE_URL + gLabel1,
"The selected value is the sources pane is incorrect.");

View File

@ -104,7 +104,7 @@ function combineWithTokenColonSearch() {
}
function verifySourceAndCaret(aUrl, aLine, aColumn, aSelection) {
ok(gSources.selectedItem.label.contains(aUrl),
ok(gSources.selectedItem.attachment.label.contains(aUrl),
"The selected item's label appears to be correct.");
ok(gSources.selectedItem.value.contains(aUrl),
"The selected item's value appears to be correct.");

View File

@ -102,7 +102,7 @@ function escapeAndClear() {
}
function verifySourceAndCaret(aUrl, aLine, aColumn) {
ok(gSources.selectedItem.label.contains(aUrl),
ok(gSources.selectedItem.attachment.label.contains(aUrl),
"The selected item's label appears to be correct.");
ok(gSources.selectedItem.value.contains(aUrl),
"The selected item's value appears to be correct.");

View File

@ -257,12 +257,12 @@ function verifyContents(aMatches) {
for (let i = 0; i < gSearchView.itemCount; i++) {
let trimmedLabel = gSourceUtils.trimUrlLength(gSourceUtils.trimUrlQuery(aMatches[i]));
let trimmedValue = gSourceUtils.trimUrlLength(EXAMPLE_URL + aMatches[i], 0, "start");
let trimmedLocation = gSourceUtils.trimUrlLength(EXAMPLE_URL + aMatches[i], 0, "start");
isnot(gSearchView.labels.indexOf(trimmedLabel), -1,
"The filtered sources view should have the correct labels.");
isnot(gSearchView.values.indexOf(trimmedValue), -1,
"The filtered sources view should have the correct values.");
ok(gSearchView.widget._parent.querySelector(".results-panel-item-label[value=\"" + trimmedLabel + "\"]"),
"The filtered sources view should have the correct source labels.");
ok(gSearchView.widget._parent.querySelector(".results-panel-item-label-below[value=\"" + trimmedLocation + "\"]"),
"The filtered sources view should have the correct source locations.");
}
}

View File

@ -82,11 +82,11 @@ function verifySourcesPane() {
is(gSources.visibleItems.length, 3,
"There should be no hidden items in the sources container.");
isnot(gSources.labels.indexOf("code_script-switching-01.js"), -1,
ok(gSources.getItemForAttachment(e => e.label == "code_script-switching-01.js"),
"The first source's label should be correct.");
isnot(gSources.labels.indexOf("code_test-editor-mode"), -1,
ok(gSources.getItemForAttachment(e => e.label == "code_test-editor-mode"),
"The second source's label should be correct.");
isnot(gSources.labels.indexOf("doc_editor-mode.html"), -1,
ok(gSources.getItemForAttachment(e => e.label == "doc_editor-mode.html"),
"The third source's label should be correct.");
}

View File

@ -48,10 +48,10 @@ function htmlSearch() {
once(gDebugger, "popupshown").then(() => {
writeInfo();
ok(gFilteredFunctions.selectedValue,
"An item should be selected in the filtered functions view.");
ok(gFilteredFunctions.selectedLabel,
"An item should be selected in the filtered functions view.");
is(gFilteredFunctions.selectedIndex, 0,
"An item should be selected in the filtered functions view (1).");
ok(gFilteredFunctions.selectedItem,
"An item should be selected in the filtered functions view (2).");
if (gSources.selectedValue.indexOf(".html") != -1) {
let expectedResults = [
@ -63,22 +63,34 @@ function htmlSearch() {
];
for (let [label, value, description, line, column] of expectedResults) {
is(gFilteredFunctions.selectedItem.label,
gDebugger.SourceUtils.trimUrlLength(label + "()"),
"The corect label (" + label + ") is currently selected.");
ok(gFilteredFunctions.selectedItem.value.contains(value),
"The corect value (" + value + ") is attached.");
is(gFilteredFunctions.selectedItem.description, description,
"The corect description (" + description + ") is currently shown.");
let target = gFilteredFunctions.selectedItem.target;
if (label) {
is(target.querySelector(".results-panel-item-label").getAttribute("value"),
gDebugger.SourceUtils.trimUrlLength(label + "()"),
"The corect label (" + label + ") is currently selected.");
} else {
ok(!target.querySelector(".results-panel-item-label"),
"Shouldn't create empty label nodes.");
}
if (value) {
ok(target.querySelector(".results-panel-item-label-below").getAttribute("value").contains(value),
"The corect value (" + value + ") is attached.");
} else {
ok(!target.querySelector(".results-panel-item-label-below"),
"Shouldn't create empty label nodes.");
}
if (description) {
is(target.querySelector(".results-panel-item-label-before").getAttribute("value"), description,
"The corect description (" + description + ") is currently shown.");
} else {
ok(!target.querySelector(".results-panel-item-label-before"),
"Shouldn't create empty label nodes.");
}
ok(isCaretPos(gPanel, line, column),
"The editor didn't jump to the correct line.");
ok(gSources.selectedLabel.contains(value),
"The current source isn't the correct one, according to the label.");
ok(gSources.selectedValue.contains(value),
"The current source isn't the correct one, according to the value.");
EventUtils.sendKey("DOWN", gDebugger);
}
@ -101,10 +113,10 @@ function firstJsSearch() {
once(gDebugger, "popupshown").then(() => {
writeInfo();
ok(gFilteredFunctions.selectedValue,
"An item should be selected in the filtered functions view.");
ok(gFilteredFunctions.selectedLabel,
"An item should be selected in the filtered functions view.");
is(gFilteredFunctions.selectedIndex, 0,
"An item should be selected in the filtered functions view (1).");
ok(gFilteredFunctions.selectedItem,
"An item should be selected in the filtered functions view (2).");
if (gSources.selectedValue.indexOf("-01.js") != -1) {
let s = " " + gDebugger.L10N.getStr("functionSearchSeparatorLabel") + " ";
@ -122,22 +134,34 @@ function firstJsSearch() {
];
for (let [label, value, description, line, column] of expectedResults) {
is(gFilteredFunctions.selectedItem.label,
gDebugger.SourceUtils.trimUrlLength(label + "()"),
"The corect label (" + label + ") is currently selected.");
ok(gFilteredFunctions.selectedItem.value.contains(value),
"The corect value (" + value + ") is attached.");
is(gFilteredFunctions.selectedItem.description, description,
"The corect description (" + description + ") is currently shown.");
let target = gFilteredFunctions.selectedItem.target;
if (label) {
is(target.querySelector(".results-panel-item-label").getAttribute("value"),
gDebugger.SourceUtils.trimUrlLength(label + "()"),
"The corect label (" + label + ") is currently selected.");
} else {
ok(!target.querySelector(".results-panel-item-label"),
"Shouldn't create empty label nodes.");
}
if (value) {
ok(target.querySelector(".results-panel-item-label-below").getAttribute("value").contains(value),
"The corect value (" + value + ") is attached.");
} else {
ok(!target.querySelector(".results-panel-item-label-below"),
"Shouldn't create empty label nodes.");
}
if (description) {
is(target.querySelector(".results-panel-item-label-before").getAttribute("value"), description,
"The corect description (" + description + ") is currently shown.");
} else {
ok(!target.querySelector(".results-panel-item-label-before"),
"Shouldn't create empty label nodes.");
}
ok(isCaretPos(gPanel, line, column),
"The editor didn't jump to the correct line.");
ok(gSources.selectedLabel.contains(value),
"The current source isn't the correct one, according to the label.");
ok(gSources.selectedValue.contains(value),
"The current source isn't the correct one, according to the value.");
EventUtils.sendKey("DOWN", gDebugger);
}
@ -160,10 +184,10 @@ function secondJsSearch() {
once(gDebugger, "popupshown").then(() => {
writeInfo();
ok(gFilteredFunctions.selectedValue,
"An item should be selected in the filtered functions view.");
ok(gFilteredFunctions.selectedLabel,
"An item should be selected in the filtered functions view.");
is(gFilteredFunctions.selectedIndex, 0,
"An item should be selected in the filtered functions view (1).");
ok(gFilteredFunctions.selectedItem,
"An item should be selected in the filtered functions view (2).");
if (gSources.selectedValue.indexOf("-02.js") != -1) {
let s = " " + gDebugger.L10N.getStr("functionSearchSeparatorLabel") + " ";
@ -181,22 +205,34 @@ function secondJsSearch() {
];
for (let [label, value, description, line, column] of expectedResults) {
is(gFilteredFunctions.selectedItem.label,
gDebugger.SourceUtils.trimUrlLength(label + "()"),
"The corect label (" + label + ") is currently selected.");
ok(gFilteredFunctions.selectedItem.value.contains(value),
"The corect value (" + value + ") is attached.");
is(gFilteredFunctions.selectedItem.description, description,
"The corect description (" + description + ") is currently shown.");
let target = gFilteredFunctions.selectedItem.target;
if (label) {
is(target.querySelector(".results-panel-item-label").getAttribute("value"),
gDebugger.SourceUtils.trimUrlLength(label + "()"),
"The corect label (" + label + ") is currently selected.");
} else {
ok(!target.querySelector(".results-panel-item-label"),
"Shouldn't create empty label nodes.");
}
if (value) {
ok(target.querySelector(".results-panel-item-label-below").getAttribute("value").contains(value),
"The corect value (" + value + ") is attached.");
} else {
ok(!target.querySelector(".results-panel-item-label-below"),
"Shouldn't create empty label nodes.");
}
if (description) {
is(target.querySelector(".results-panel-item-label-before").getAttribute("value"), description,
"The corect description (" + description + ") is currently shown.");
} else {
ok(!target.querySelector(".results-panel-item-label-before"),
"Shouldn't create empty label nodes.");
}
ok(isCaretPos(gPanel, line, column),
"The editor didn't jump to the correct line.");
ok(gSources.selectedLabel.contains(value),
"The current source isn't the correct one, according to the label.");
ok(gSources.selectedValue.contains(value),
"The current source isn't the correct one, according to the value.");
EventUtils.sendKey("DOWN", gDebugger);
}
@ -219,10 +255,10 @@ function thirdJsSearch() {
once(gDebugger, "popupshown").then(() => {
writeInfo();
ok(gFilteredFunctions.selectedValue,
"An item should be selected in the filtered functions view.");
ok(gFilteredFunctions.selectedLabel,
"An item should be selected in the filtered functions view.");
is(gFilteredFunctions.selectedIndex, 0,
"An item should be selected in the filtered functions view (1).");
ok(gFilteredFunctions.selectedItem,
"An item should be selected in the filtered functions view (2).");
if (gSources.selectedValue.indexOf("-03.js") != -1) {
let s = " " + gDebugger.L10N.getStr("functionSearchSeparatorLabel") + " ";
@ -240,22 +276,34 @@ function thirdJsSearch() {
];
for (let [label, value, description, line, column] of expectedResults) {
is(gFilteredFunctions.selectedItem.label,
gDebugger.SourceUtils.trimUrlLength(label + "()"),
"The corect label (" + label + ") is currently selected.");
ok(gFilteredFunctions.selectedItem.value.contains(value),
"The corect value (" + value + ") is attached.");
is(gFilteredFunctions.selectedItem.description, description,
"The corect description (" + description + ") is currently shown.");
let target = gFilteredFunctions.selectedItem.target;
if (label) {
is(target.querySelector(".results-panel-item-label").getAttribute("value"),
gDebugger.SourceUtils.trimUrlLength(label + "()"),
"The corect label (" + label + ") is currently selected.");
} else {
ok(!target.querySelector(".results-panel-item-label"),
"Shouldn't create empty label nodes.");
}
if (value) {
ok(target.querySelector(".results-panel-item-label-below").getAttribute("value").contains(value),
"The corect value (" + value + ") is attached.");
} else {
ok(!target.querySelector(".results-panel-item-label-below"),
"Shouldn't create empty label nodes.");
}
if (description) {
is(target.querySelector(".results-panel-item-label-before").getAttribute("value"), description,
"The corect description (" + description + ") is currently shown.");
} else {
ok(!target.querySelector(".results-panel-item-label-before"),
"Shouldn't create empty label nodes.");
}
ok(isCaretPos(gPanel, line, column),
"The editor didn't jump to the correct line.");
ok(gSources.selectedLabel.contains(value),
"The current source isn't the correct one, according to the label.");
ok(gSources.selectedValue.contains(value),
"The current source isn't the correct one, according to the value.");
EventUtils.sendKey("DOWN", gDebugger);
}
@ -278,10 +326,10 @@ function filterSearch() {
once(gDebugger, "popupshown").then(() => {
writeInfo();
ok(gFilteredFunctions.selectedValue,
"An item should be selected in the filtered functions view.");
ok(gFilteredFunctions.selectedLabel,
"An item should be selected in the filtered functions view.");
is(gFilteredFunctions.selectedIndex, 0,
"An item should be selected in the filtered functions view (1).");
ok(gFilteredFunctions.selectedItem,
"An item should be selected in the filtered functions view (2).");
if (gSources.selectedValue.indexOf("-03.js") != -1) {
let s = " " + gDebugger.L10N.getStr("functionSearchSeparatorLabel") + " ";
@ -296,22 +344,34 @@ function filterSearch() {
];
for (let [label, value, description, line, column] of expectedResults) {
is(gFilteredFunctions.selectedItem.label,
gDebugger.SourceUtils.trimUrlLength(label + "()"),
"The corect label (" + label + ") is currently selected.");
ok(gFilteredFunctions.selectedItem.value.contains(value),
"The corect value (" + value + ") is attached.");
is(gFilteredFunctions.selectedItem.description, description,
"The corect description (" + description + ") is currently shown.");
let target = gFilteredFunctions.selectedItem.target;
if (label) {
is(target.querySelector(".results-panel-item-label").getAttribute("value"),
gDebugger.SourceUtils.trimUrlLength(label + "()"),
"The corect label (" + label + ") is currently selected.");
} else {
ok(!target.querySelector(".results-panel-item-label"),
"Shouldn't create empty label nodes.");
}
if (value) {
ok(target.querySelector(".results-panel-item-label-below").getAttribute("value").contains(value),
"The corect value (" + value + ") is attached.");
} else {
ok(!target.querySelector(".results-panel-item-label-below"),
"Shouldn't create empty label nodes.");
}
if (description) {
is(target.querySelector(".results-panel-item-label-before").getAttribute("value"), description,
"The corect description (" + description + ") is currently shown.");
} else {
ok(!target.querySelector(".results-panel-item-label-before"),
"Shouldn't create empty label nodes.");
}
ok(isCaretPos(gPanel, line, column),
"The editor didn't jump to the correct line.");
ok(gSources.selectedLabel.contains(value),
"The current source isn't the correct one, according to the label.");
ok(gSources.selectedValue.contains(value),
"The current source isn't the correct one, according to the value.");
EventUtils.sendKey("DOWN", gDebugger);
}
@ -368,7 +428,7 @@ function showSource(aLabel) {
let deferred = promise.defer();
waitForSourceShown(gPanel, aLabel).then(deferred.resolve);
gSources.selectedLabel = aLabel;
gSources.selectedItem = e => e.attachment.label == aLabel;
return deferred.promise;
}

View File

@ -85,9 +85,9 @@ function testHitBreakpoint() {
// Make sure that we have JavaScript stack frames.
is(gFrames.itemCount, 1,
"Should have only one frame.");
is(gFrames.getItemAtIndex(0).description.indexOf(".coffee"), -1,
is(gFrames.getItemAtIndex(0).attachment.url.indexOf(".coffee"), -1,
"First frame should not be a coffee source frame.");
isnot(gFrames.getItemAtIndex(0).description.indexOf(".js"), -1,
isnot(gFrames.getItemAtIndex(0).attachment.url.indexOf(".js"), -1,
"First frame should be a JS frame.");
deferred.resolve();
@ -121,9 +121,9 @@ function testToggleOnPause() {
// Make sure that we have coffee source stack frames.
is(gFrames.itemCount, 1,
"Should have only one frame.");
is(gFrames.getItemAtIndex(0).description.indexOf(".js"), -1,
is(gFrames.getItemAtIndex(0).attachment.url.indexOf(".js"), -1,
"First frame should not be a JS frame.");
isnot(gFrames.getItemAtIndex(0).description.indexOf(".coffee"), -1,
isnot(gFrames.getItemAtIndex(0).attachment.url.indexOf(".coffee"), -1,
"First frame should be a coffee source frame.");
});

View File

@ -70,9 +70,9 @@ function testHitBreakpoint() {
// Make sure that we have the right stack frames.
is(gFrames.itemCount, 9,
"Should have nine frames.");
is(gFrames.getItemAtIndex(0).description.indexOf(".min.js"), -1,
is(gFrames.getItemAtIndex(0).attachment.url.indexOf(".min.js"), -1,
"First frame should not be a minified JS frame.");
isnot(gFrames.getItemAtIndex(0).description.indexOf(".js"), -1,
isnot(gFrames.getItemAtIndex(0).attachment.url.indexOf(".js"), -1,
"First frame should be a JS frame.");
deferred.resolve();

View File

@ -38,7 +38,7 @@ function test() {
function initialChecks() {
ok(gEditor.getText().contains("First source!"),
"Editor text contents appears to be correct.");
is(gSources.selectedLabel, "code_function-search-01.js",
is(gSources.selectedItem.attachment.label, "code_function-search-01.js",
"The currently selected label in the sources container is correct.");
ok(gSources.selectedValue.contains("code_function-search-01.js"),
"The currently selected value in the sources container appears to be correct.");
@ -47,30 +47,30 @@ function initialChecks() {
"There should be " + TOTAL_SOURCES + " sources present in the sources list.");
is(gSources.visibleItems.length, TOTAL_SOURCES,
"There should be " + TOTAL_SOURCES + " sources visible in the sources list.");
is(gSources.labels.length, TOTAL_SOURCES,
"There should be " + TOTAL_SOURCES + " labels stored in the sources container model.")
is(gSources.attachments.length, TOTAL_SOURCES,
"There should be " + TOTAL_SOURCES + " attachments stored in the sources container model.")
is(gSources.values.length, TOTAL_SOURCES,
"There should be " + TOTAL_SOURCES + " values stored in the sources container model.")
info("Source labels: " + gSources.labels.toSource());
info("Source labels: " + gSources.attachments.toSource());
info("Source values: " + gSources.values.toSource());
is(gSources.labels[0], "code_function-search-01.js",
is(gSources.attachments[0].label, "code_function-search-01.js",
"The first source label is correct.");
ok(gSources.values[0].contains("code_function-search-01.js"),
"The first source value appears to be correct.");
is(gSources.labels[1], "code_function-search-02.js",
is(gSources.attachments[1].label, "code_function-search-02.js",
"The second source label is correct.");
ok(gSources.values[1].contains("code_function-search-02.js"),
"The second source value appears to be correct.");
is(gSources.labels[2], "code_function-search-03.js",
is(gSources.attachments[2].label, "code_function-search-03.js",
"The third source label is correct.");
ok(gSources.values[2].contains("code_function-search-03.js"),
"The third source value appears to be correct.");
is(gSources.labels[3], "doc_function-search.html",
is(gSources.attachments[3].label, "doc_function-search.html",
"The third source label is correct.");
ok(gSources.values[3].contains("doc_function-search.html"),
"The third source value appears to be correct.");

View File

@ -22,11 +22,15 @@ function test() {
let ellipsis = gPanel.panelWin.L10N.ellipsis;
let nananana = new Array(20).join(NaN);
// Test trimming url queries.
let someUrl = "a/b/c.d?test=1&random=4#reference";
let shortenedUrl = "a/b/c.d";
is(gUtils.trimUrlQuery(someUrl), shortenedUrl,
"Trimming the url query isn't done properly.");
// Test trimming long urls with an ellipsis.
let largeLabel = new Array(100).join("Beer can in Jamaican sounds like Bacon!");
let trimmedLargeLabel = gUtils.trimUrlLength(largeLabel, 1234);
is(trimmedLargeLabel.length, 1235,
@ -34,6 +38,8 @@ function test() {
ok(trimmedLargeLabel.endsWith(ellipsis),
"Trimming large labels should add an ellipsis at the end.");
// Test the sources list behaviour with certain urls.
let urls = [
{ href: "http://some.address.com/random/", leaf: "subrandom/" },
{ href: "http://some.address.com/random/", leaf: "suprandom/?a=1" },
@ -65,7 +71,7 @@ function test() {
"Should contain the original source label in the sources widget.");
is(gSources.selectedIndex, 0,
"The first item in the sources widget should be selected (1).");
is(gSources.selectedLabel, "doc_recursion-stack.html",
is(gSources.selectedItem.attachment.label, "doc_recursion-stack.html",
"The first item in the sources widget should be selected (2).");
is(gSources.selectedValue, TAB_URL,
"The first item in the sources widget should be selected (3).");
@ -76,24 +82,31 @@ function test() {
"Should contain no items in the sources widget after emptying.");
is(gSources.selectedIndex, -1,
"No item in the sources widget should be selected (1).");
is(gSources.selectedLabel, "",
is(gSources.selectedItem, null,
"No item in the sources widget should be selected (2).");
is(gSources.selectedValue, "",
"No item in the sources widget should be selected (3).");
for (let { href, leaf } of urls) {
let url = href + leaf;
let label = gUtils.getSourceLabel(url);
let trimmedLabel = gUtils.trimUrlLength(label);
gSources.push([trimmedLabel, url], { attachment: {}});
}
let label = gUtils.trimUrlLength(gUtils.getSourceLabel(url));
let group = gUtils.getSourceGroup(url);
let dummy = document.createElement("label");
info("Source labels:");
info(gSources.labels.toSource());
gSources.push([dummy, url], {
attachment: {
label: label,
group: group
}
});
}
info("Source locations:");
info(gSources.values.toSource());
info("Source attachments:");
info(gSources.attachments.toSource());
for (let { href, leaf, dupe } of urls) {
let url = href + leaf;
if (dupe) {
@ -103,58 +116,58 @@ function test() {
}
}
ok(gSources.containsLabel("random/subrandom/"),
ok(gSources.getItemForAttachment(e => e.label == "random/subrandom/"),
"Source (0) label is incorrect.");
ok(gSources.containsLabel("random/suprandom/?a=1"),
ok(gSources.getItemForAttachment(e => e.label == "random/suprandom/?a=1"),
"Source (1) label is incorrect.");
ok(gSources.containsLabel("random/?a=1"),
ok(gSources.getItemForAttachment(e => e.label == "random/?a=1"),
"Source (2) label is incorrect.");
ok(gSources.containsLabel("page.html"),
ok(gSources.getItemForAttachment(e => e.label == "page.html"),
"Source (3) label is incorrect.");
ok(gSources.containsLabel("script.js"),
ok(gSources.getItemForAttachment(e => e.label == "script.js"),
"Source (4) label is incorrect.");
ok(gSources.containsLabel("random/script.js"),
ok(gSources.getItemForAttachment(e => e.label == "random/script.js"),
"Source (5) label is incorrect.");
ok(gSources.containsLabel("random/x/script.js"),
ok(gSources.getItemForAttachment(e => e.label == "random/x/script.js"),
"Source (6) label is incorrect.");
ok(gSources.containsLabel("script.js?a=1"),
ok(gSources.getItemForAttachment(e => e.label == "script.js?a=1"),
"Source (7) label is incorrect.");
ok(gSources.containsLabel("script_t1.js"),
ok(gSources.getItemForAttachment(e => e.label == "script_t1.js"),
"Source (8) label is incorrect.");
ok(gSources.containsLabel("script_t2_1.js"),
ok(gSources.getItemForAttachment(e => e.label == "script_t2_1.js"),
"Source (9) label is incorrect.");
ok(gSources.containsLabel("script_t2_2.js"),
ok(gSources.getItemForAttachment(e => e.label == "script_t2_2.js"),
"Source (10) label is incorrect.");
ok(gSources.containsLabel("script_t2_3.js"),
ok(gSources.getItemForAttachment(e => e.label == "script_t2_3.js"),
"Source (11) label is incorrect.");
ok(gSources.containsLabel("script_t3_1.js"),
ok(gSources.getItemForAttachment(e => e.label == "script_t3_1.js"),
"Source (12) label is incorrect.");
ok(gSources.containsLabel("script_t3_2.js"),
ok(gSources.getItemForAttachment(e => e.label == "script_t3_2.js"),
"Source (13) label is incorrect.");
ok(gSources.containsLabel("script_t3_3.js"),
ok(gSources.getItemForAttachment(e => e.label == "script_t3_3.js"),
"Source (14) label is incorrect.");
ok(gSources.containsLabel(nananana + "Batman!" + ellipsis),
ok(gSources.getItemForAttachment(e => e.label == nananana + "Batman!" + ellipsis),
"Source (15) label is incorrect.");
is(gSources.itemCount, urls.filter(({ dupe }) => !dupe).length,
"Didn't get the correct number of sources in the list.");
is(gSources.getItemByValue("http://some.address.com/random/subrandom/").label,
is(gSources.getItemByValue("http://some.address.com/random/subrandom/").attachment.label,
"random/subrandom/",
"gSources.getItemByValue isn't functioning properly (0).");
is(gSources.getItemByValue("http://some.address.com/random/suprandom/?a=1").label,
is(gSources.getItemByValue("http://some.address.com/random/suprandom/?a=1").attachment.label,
"random/suprandom/?a=1",
"gSources.getItemByValue isn't functioning properly (1).");
is(gSources.getItemByLabel("random/subrandom/").value,
is(gSources.getItemForAttachment(e => e.label == "random/subrandom/").value,
"http://some.address.com/random/subrandom/",
"gSources.getItemByLabel isn't functioning properly (0).");
is(gSources.getItemByLabel("random/suprandom/?a=1").value,
"gSources.getItemForAttachment isn't functioning properly (0).");
is(gSources.getItemForAttachment(e => e.label == "random/suprandom/?a=1").value,
"http://some.address.com/random/suprandom/?a=1",
"gSources.getItemByLabel isn't functioning properly (1).");
"gSources.getItemForAttachment isn't functioning properly (1).");
closeDebuggerAndFinish(gPanel);
});

View File

@ -33,6 +33,7 @@ function test() {
function addSourceAndCheckOrder(aMethod, aCallback) {
gSources.empty();
gSources.suppressSelectionEvents = true;
let urls = [
{ href: "ici://some.address.com/random/", leaf: "subrandom/" },
@ -54,7 +55,13 @@ function addSourceAndCheckOrder(aMethod, aCallback) {
for (let { href, leaf } of urls) {
let url = href + leaf;
let label = gUtils.getSourceLabel(url);
gSources.push([label, url], { staged: true });
let dummy = document.createElement("label");
gSources.push([dummy, url], {
staged: true,
attachment: {
label: label
}
});
}
gSources.commit({ sorted: true });
break;
@ -63,7 +70,13 @@ function addSourceAndCheckOrder(aMethod, aCallback) {
for (let { href, leaf } of urls) {
let url = href + leaf;
let label = gUtils.getSourceLabel(url);
gSources.push([label, url], { staged: false });
let dummy = document.createElement("label");
gSources.push([dummy, url], {
staged: false,
attachment: {
label: label
}
});
}
break;
@ -73,7 +86,13 @@ function addSourceAndCheckOrder(aMethod, aCallback) {
let { href, leaf } = urls[i];
let url = href + leaf;
let label = gUtils.getSourceLabel(url);
gSources.push([label, url], { staged: true });
let dummy = document.createElement("label");
gSources.push([dummy, url], {
staged: true,
attachment: {
label: label
}
});
}
gSources.commit({ sorted: true });
@ -81,7 +100,13 @@ function addSourceAndCheckOrder(aMethod, aCallback) {
let { href, leaf } = urls[i];
let url = href + leaf;
let label = gUtils.getSourceLabel(url);
gSources.push([label, url], { staged: false });
let dummy = document.createElement("label");
gSources.push([dummy, url], {
staged: false,
attachment: {
label: label
}
});
}
break;
}
@ -91,16 +116,15 @@ function addSourceAndCheckOrder(aMethod, aCallback) {
}
function checkSourcesOrder(aMethod) {
let labels = gSources.labels;
let sorted = labels.reduce(function(aPrev, aCurr, aIndex, aArray) {
return aArray[aIndex - 1] < aArray[aIndex];
});
let attachments = gSources.attachments;
ok(sorted,
"Using method " + aMethod + ", " +
"the sources weren't in the correct order: " + labels.toSource());
return sorted;
for (let i = 0; i < attachments.length - 1; i++) {
let first = attachments[i].label;
let second = attachments[i + 1].label;
ok(first < second,
"Using method " + aMethod + ", " +
"the sources weren't in the correct order: " + first + " vs. " + second);
}
}
registerCleanupFunction(function() {

View File

@ -32,19 +32,19 @@ function performTest() {
is(gClassicFrames.itemCount, 2,
"Should also have only two in the mirrored view.");
is(gFrames.getItemAtIndex(0).value,
is(gFrames.getItemAtIndex(0).attachment.title,
"evalCall", "Oldest frame name should be correct.");
is(gFrames.getItemAtIndex(0).description,
is(gFrames.getItemAtIndex(0).attachment.url,
TAB_URL, "Oldest frame url should be correct.");
is(gClassicFrames.getItemAtIndex(0).value,
TAB_URL, "Oldest frame name is mirrored correctly.");
is(gClassicFrames.getItemAtIndex(0).attachment.depth,
0, "Oldest frame name is mirrored correctly.");
is(gFrames.getItemAtIndex(1).value,
is(gFrames.getItemAtIndex(1).attachment.title,
"(eval)", "Newest frame name should be correct.");
is(gFrames.getItemAtIndex(1).description,
is(gFrames.getItemAtIndex(1).attachment.url,
TAB_URL, "Newest frame url should be correct.");
is(gClassicFrames.getItemAtIndex(1).value,
TAB_URL, "Newest frame name is mirrored correctly.");
is(gClassicFrames.getItemAtIndex(1).attachment.depth,
1, "Newest frame name is mirrored correctly.");
is(gFrames.selectedIndex, 1,
"Newest frame should be selected by default.");

View File

@ -162,6 +162,7 @@ registerCleanupFunction(function() {
gPanel = null;
gDebugger = null;
gEditor = null;
gSources = null;
gFrames = null;
gClassicFrames = null;
});

View File

@ -291,6 +291,8 @@ registerCleanupFunction(function() {
gDebuggee = null;
gPanel = null;
gDebugger = null;
gL10N = null;
gEditor = null;
gVars = null;
gWatch = null;
});

View File

@ -97,6 +97,8 @@ registerCleanupFunction(function() {
gDebuggee = null;
gPanel = null;
gDebugger = null;
gL10N = null;
gEditor = null;
gVars = null;
gWatch = null;
});

View File

@ -292,23 +292,23 @@ function testIntegrity1() {
is(gWatch.itemCount, 5,
"There should be 5 hidden expression input available.");
is(gWatch.getItemAtIndex(0).attachment.inputNode.value, "document.title = 43",
is(gWatch.getItemAtIndex(0).attachment.view.inputNode.value, "document.title = 43",
"The first textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(0).attachment.currentExpression, "document.title = 43",
"The first textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(1).attachment.inputNode.value, "document.title",
is(gWatch.getItemAtIndex(1).attachment.view.inputNode.value, "document.title",
"The second textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(1).attachment.currentExpression, "document.title",
"The second textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(2).attachment.inputNode.value, "aArg",
is(gWatch.getItemAtIndex(2).attachment.view.inputNode.value, "aArg",
"The third textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(2).attachment.currentExpression, "aArg",
"The third textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(3).attachment.inputNode.value, "ermahgerd",
is(gWatch.getItemAtIndex(3).attachment.view.inputNode.value, "ermahgerd",
"The fourth textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(3).attachment.currentExpression, "ermahgerd",
"The fourth textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(4).attachment.inputNode.value, "this",
is(gWatch.getItemAtIndex(4).attachment.view.inputNode.value, "this",
"The fifth textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(4).attachment.currentExpression, "this",
"The fifth textbox input value is not the correct one.");
@ -330,23 +330,23 @@ function testIntegrity2() {
is(gWatch.itemCount, 5,
"There should be 5 hidden expression input available.");
is(gWatch.getItemAtIndex(0).attachment.inputNode.value, "document.title = 43",
is(gWatch.getItemAtIndex(0).attachment.view.inputNode.value, "document.title = 43",
"The first textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(0).attachment.currentExpression, "document.title = 43",
"The first textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(1).attachment.inputNode.value, "document.title",
is(gWatch.getItemAtIndex(1).attachment.view.inputNode.value, "document.title",
"The second textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(1).attachment.currentExpression, "document.title",
"The second textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(2).attachment.inputNode.value, "aArg = 44",
is(gWatch.getItemAtIndex(2).attachment.view.inputNode.value, "aArg = 44",
"The third textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(2).attachment.currentExpression, "aArg = 44",
"The third textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(3).attachment.inputNode.value, "ermahgerd",
is(gWatch.getItemAtIndex(3).attachment.view.inputNode.value, "ermahgerd",
"The fourth textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(3).attachment.currentExpression, "ermahgerd",
"The fourth textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(4).attachment.inputNode.value, "this",
is(gWatch.getItemAtIndex(4).attachment.view.inputNode.value, "this",
"The fifth textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(4).attachment.currentExpression, "this",
"The fifth textbox input value is not the correct one.");
@ -368,19 +368,19 @@ function testIntegrity3() {
is(gWatch.itemCount, 4,
"There should be 4 hidden expression input available.");
is(gWatch.getItemAtIndex(0).attachment.inputNode.value, "document.title = 43",
is(gWatch.getItemAtIndex(0).attachment.view.inputNode.value, "document.title = 43",
"The first textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(0).attachment.currentExpression, "document.title = 43",
"The first textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(1).attachment.inputNode.value, "document.title",
is(gWatch.getItemAtIndex(1).attachment.view.inputNode.value, "document.title",
"The second textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(1).attachment.currentExpression, "document.title",
"The second textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(2).attachment.inputNode.value, "ermahgerd",
is(gWatch.getItemAtIndex(2).attachment.view.inputNode.value, "ermahgerd",
"The third textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(2).attachment.currentExpression, "ermahgerd",
"The third textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(3).attachment.inputNode.value, "this",
is(gWatch.getItemAtIndex(3).attachment.view.inputNode.value, "this",
"The fourth textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(3).attachment.currentExpression, "this",
"The fourth textbox input value is not the correct one.");
@ -402,15 +402,15 @@ function testIntegrity4() {
is(gWatch.itemCount, 3,
"There should be 3 hidden expression input available.");
is(gWatch.getItemAtIndex(0).attachment.inputNode.value, "document.title",
is(gWatch.getItemAtIndex(0).attachment.view.inputNode.value, "document.title",
"The first textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(0).attachment.currentExpression, "document.title",
"The first textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(1).attachment.inputNode.value, "ermahgerd",
is(gWatch.getItemAtIndex(1).attachment.view.inputNode.value, "ermahgerd",
"The second textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(1).attachment.currentExpression, "ermahgerd",
"The second textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(2).attachment.inputNode.value, "this",
is(gWatch.getItemAtIndex(2).attachment.view.inputNode.value, "this",
"The third textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(2).attachment.currentExpression, "this",
"The third textbox input value is not the correct one.");
@ -432,11 +432,11 @@ function testIntegrity5() {
is(gWatch.itemCount, 2,
"There should be 2 hidden expression input available.");
is(gWatch.getItemAtIndex(0).attachment.inputNode.value, "ermahgerd",
is(gWatch.getItemAtIndex(0).attachment.view.inputNode.value, "ermahgerd",
"The first textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(0).attachment.currentExpression, "ermahgerd",
"The first textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(1).attachment.inputNode.value, "this",
is(gWatch.getItemAtIndex(1).attachment.view.inputNode.value, "this",
"The second textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(1).attachment.currentExpression, "this",
"The second textbox input value is not the correct one.");
@ -458,7 +458,7 @@ function testIntegrity6() {
is(gWatch.itemCount, 1,
"There should be 1 hidden expression input available.");
is(gWatch.getItemAtIndex(0).attachment.inputNode.value, "ermahgerd",
is(gWatch.getItemAtIndex(0).attachment.view.inputNode.value, "ermahgerd",
"The first textbox input value is not the correct one.");
is(gWatch.getItemAtIndex(0).attachment.currentExpression, "ermahgerd",
"The first textbox input value is not the correct one.");

View File

@ -49,12 +49,12 @@ function test() {
is(firstScope._store.size, 3,
"The first scope should have all the variables available.");
is(secondScope._store.size, 3,
"The second scope shoild have all the variables available.");
is(thirdScope._store.size, 3,
"The third scope shoild have all the variables available.");
is(secondScope._store.size, 0,
"The second scope should have no variables available yet.");
is(thirdScope._store.size, 0,
"The third scope should have no variables available yet.");
is(globalScope._store.size, 0,
"The global scope shoild have no variables available.");
"The global scope should have no variables available yet.");
// Test getOwnerScopeForVariableOrProperty with simple variables.
@ -95,6 +95,15 @@ function test() {
// Test getOwnerScopeForVariableOrProperty with a simple variable
// from non-topmost scopes.
// Only need to wait for a single FETCHED_VARIABLES event, just for the
// global scope, because the other local scopes already have the
// arguments and variables available as evironment bindings.
let fetched = waitForDebuggerEvents(panel, events.FETCHED_VARIABLES);
secondScope.expand();
thirdScope.expand();
globalScope.expand();
yield fetched;
let someVar2 = secondScope.get("a");
let someOwner2 = variables.getOwnerScopeForVariableOrProperty(someVar2);
is(someOwner2, secondScope,

View File

@ -15,37 +15,51 @@ function test() {
let variables = win.DebuggerView.Variables;
// Wait for the hierarchy to be committed by the VariablesViewController.
let committed = promise.defer();
variables.oncommit = committed.resolve;
let committedLocalScopeHierarchy = promise.defer();
variables.oncommit = committedLocalScopeHierarchy.resolve;
// Allow this generator function to yield first.
executeSoon(() => debuggee.test());
yield waitForSourceAndCaretAndScopes(panel, ".html", 23);
yield committed.promise;
yield committedLocalScopeHierarchy.promise;
let firstScope = variables.getScopeAtIndex(0);
let secondScope = variables.getScopeAtIndex(1);
let thirdScope = variables.getScopeAtIndex(2);
let someVar1 = firstScope.get("a");
let someVar2 = secondScope.get("a");
let someVar3 = thirdScope.get("a");
let argsVar1 = firstScope.get("arguments");
let argsVar2 = secondScope.get("arguments");
let argsVar3 = thirdScope.get("arguments");
is(someVar1.target.hasAttribute("overridden"), false,
"The first 'a' variable should not be marked as being overridden.");
is(someVar2.target.hasAttribute("overridden"), true,
"The second 'a' variable should be marked as being overridden.");
is(someVar3.target.hasAttribute("overridden"), true,
"The third 'a' variable should be marked as being overridden.");
is(argsVar1.target.hasAttribute("overridden"), false,
"The first 'arguments' variable should not be marked as being overridden.");
// Wait for the hierarchy to be committed by the VariablesViewController.
let committedSecondScopeHierarchy = promise.defer();
variables.oncommit = committedSecondScopeHierarchy.resolve;
secondScope.expand();
yield committedSecondScopeHierarchy.promise;
let someVar2 = secondScope.get("a");
let argsVar2 = secondScope.get("arguments");
is(someVar2.target.hasAttribute("overridden"), true,
"The second 'a' variable should be marked as being overridden.");
is(argsVar2.target.hasAttribute("overridden"), true,
"The second 'arguments' variable should be marked as being overridden.");
// Wait for the hierarchy to be committed by the VariablesViewController.
let committedThirdScopeHierarchy = promise.defer();
variables.oncommit = committedThirdScopeHierarchy.resolve;
thirdScope.expand();
yield committedThirdScopeHierarchy.promise;
let someVar3 = thirdScope.get("a");
let argsVar3 = thirdScope.get("arguments");
is(someVar3.target.hasAttribute("overridden"), true,
"The third 'a' variable should be marked as being overridden.");
is(argsVar3.target.hasAttribute("overridden"), true,
"The third 'arguments' variable should be marked as being overridden.");

View File

@ -72,7 +72,7 @@ function test() {
addAndCheckCustomExpression(3, 0, "bambøøcha");
EventUtils.sendMouseEvent({ type: "click" },
gWatch.getItemAtIndex(0).attachment.closeNode,
gWatch.getItemAtIndex(0).attachment.view.closeNode,
gDebugger);
is(gWatch.getAllStrings().length, 2,
@ -83,7 +83,7 @@ function test() {
"The expression at index " + 1 + " should be correct (2).");
EventUtils.sendMouseEvent({ type: "click" },
gWatch.getItemAtIndex(0).attachment.closeNode,
gWatch.getItemAtIndex(0).attachment.view.closeNode,
gDebugger);
is(gWatch.getAllStrings().length, 1,
@ -92,7 +92,7 @@ function test() {
"The expression at index " + 0 + " should be correct (3).");
EventUtils.sendMouseEvent({ type: "click" },
gWatch.getItemAtIndex(0).attachment.closeNode,
gWatch.getItemAtIndex(0).attachment.view.closeNode,
gDebugger);
is(gWatch.getAllStrings().length, 0,
@ -160,11 +160,11 @@ function test() {
is(element, gWatch.widget.getItemAtIndex(aIndex),
"The correct watch expression element was accessed (2).");
is(gWatch.getItemForElement(element).attachment.arrowNode.hidden, false,
is(gWatch.getItemForElement(element).attachment.view.arrowNode.hidden, false,
"The arrow node should be visible.");
is(gWatch.getItemForElement(element).attachment.closeNode.hidden, false,
is(gWatch.getItemForElement(element).attachment.view.closeNode.hidden, false,
"The close button should be visible.");
is(gWatch.getItemForElement(element).attachment.inputNode.getAttribute("focused"), "true",
is(gWatch.getItemForElement(element).attachment.view.inputNode.getAttribute("focused"), "true",
"The textbox input should be focused.");
is(gVariables.parentNode.scrollTop, 0,

View File

@ -60,7 +60,7 @@ Tools.options = {
id: "options",
ordinal: 0,
url: "chrome://browser/content/devtools/framework/toolbox-options.xul",
icon: "chrome://browser/skin/devtools/tool-options.png",
icon: "chrome://browser/skin/devtools/tool-options@2x.png",
bgTheme: "theme-body",
tooltip: l10n("optionsButton.tooltip", toolboxStrings),
inMenu: false,
@ -79,7 +79,7 @@ Tools.webConsole = {
accesskey: l10n("webConsoleCmd.accesskey", webConsoleStrings),
modifiers: Services.appinfo.OS == "Darwin" ? "accel,alt" : "accel,shift",
ordinal: 1,
icon: "chrome://browser/skin/devtools/tool-webconsole.png",
icon: "chrome://browser/skin/devtools/tool-webconsole@2x.png",
url: "chrome://browser/content/devtools/webconsole.xul",
label: l10n("ToolboxTabWebconsole.label", webConsoleStrings),
menuLabel: l10n("MenuWebconsole.label", webConsoleStrings),
@ -101,7 +101,7 @@ Tools.inspector = {
key: l10n("inspector.commandkey", inspectorStrings),
ordinal: 2,
modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
icon: "chrome://browser/skin/devtools/tool-inspector.png",
icon: "chrome://browser/skin/devtools/tool-inspector@2x.png",
url: "chrome://browser/content/devtools/inspector/inspector.xul",
label: l10n("inspector.label", inspectorStrings),
tooltip: l10n("inspector.tooltip", inspectorStrings),
@ -130,8 +130,8 @@ Tools.jsdebugger = {
accesskey: l10n("debuggerMenu.accesskey", debuggerStrings),
modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
ordinal: 3,
icon: "chrome://browser/skin/devtools/tool-debugger.png",
highlightedicon: "chrome://browser/skin/devtools/tool-debugger-paused.png",
icon: "chrome://browser/skin/devtools/tool-debugger@2x.png",
highlightedicon: "chrome://browser/skin/devtools/tool-debugger-paused@2x.png",
url: "chrome://browser/content/devtools/debugger.xul",
label: l10n("ToolboxDebugger.label", debuggerStrings),
tooltip: l10n("ToolboxDebugger.tooltip", debuggerStrings),
@ -153,7 +153,7 @@ Tools.styleEditor = {
ordinal: 4,
accesskey: l10n("open.accesskey", styleEditorStrings),
modifiers: "shift",
icon: "chrome://browser/skin/devtools/tool-styleeditor.png",
icon: "chrome://browser/skin/devtools/tool-styleeditor@2x.png",
url: "chrome://browser/content/devtools/styleeditor.xul",
label: l10n("ToolboxStyleEditor.label", styleEditorStrings),
tooltip: l10n("ToolboxStyleEditor.tooltip2", styleEditorStrings),
@ -173,7 +173,7 @@ Tools.shaderEditor = {
id: "shadereditor",
ordinal: 5,
visibilityswitch: "devtools.shadereditor.enabled",
icon: "chrome://browser/skin/devtools/tool-styleeditor.png",
icon: "chrome://browser/skin/devtools/tool-styleeditor@2x.png",
url: "chrome://browser/content/devtools/shadereditor.xul",
label: l10n("ToolboxShaderEditor.label", shaderEditorStrings),
tooltip: l10n("ToolboxShaderEditor.tooltip", shaderEditorStrings),
@ -195,7 +195,7 @@ Tools.jsprofiler = {
ordinal: 6,
modifiers: "shift",
visibilityswitch: "devtools.profiler.enabled",
icon: "chrome://browser/skin/devtools/tool-profiler.png",
icon: "chrome://browser/skin/devtools/tool-profiler@2x.png",
url: "chrome://browser/content/devtools/profiler.xul",
label: l10n("profiler.label", profilerStrings),
tooltip: l10n("profiler.tooltip2", profilerStrings),
@ -218,7 +218,7 @@ Tools.netMonitor = {
ordinal: 7,
modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
visibilityswitch: "devtools.netmonitor.enabled",
icon: "chrome://browser/skin/devtools/tool-network.png",
icon: "chrome://browser/skin/devtools/tool-network@2x.png",
url: "chrome://browser/content/devtools/netmonitor.xul",
label: l10n("netmonitor.label", netMonitorStrings),
tooltip: l10n("netmonitor.tooltip", netMonitorStrings),
@ -238,7 +238,7 @@ Tools.scratchpad = {
id: "scratchpad",
ordinal: 8,
visibilityswitch: "devtools.scratchpad.enabled",
icon: "chrome://browser/skin/devtools/tool-scratchpad.png",
icon: "chrome://browser/skin/devtools/tool-scratchpad@2x.png",
url: "chrome://browser/content/devtools/scratchpad.xul",
label: l10n("scratchpad.label", scratchpadStrings),
tooltip: l10n("scratchpad.tooltip", scratchpadStrings),

View File

@ -325,7 +325,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
this._registerLastRequestEnd(unixTime);
// Append a network request item to this container.
let requestItem = this.push([menuView, aId, ""], {
let requestItem = this.push([menuView, aId], {
attachment: {
startedDeltaMillis: unixTime - this._firstRequestStartedMillis,
startedMillis: unixTime,
@ -356,7 +356,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
// Create the element node for the network request item.
let menuView = this._createMenuView(selected.method, selected.url);
let newItem = this.push([menuView,, ""], {
let newItem = this.push([menuView], {
attachment: Object.create(selected, {
isCustom: { value: true }
})

View File

@ -27,7 +27,7 @@ function Sidebar(el) {
this.document = el.ownerDocument;
this.widget = new SideMenuWidget(el, { showArrows: true });
this.widget.notice = L10N.getStr("profiler.sidebarNotice");
this.emptyText = L10N.getStr("profiler.sidebarNotice");
this.widget.addEventListener("select", (ev) => {
if (!ev.detail)

View File

@ -221,12 +221,16 @@ let ShadersListView = Heritage.extend(WidgetMethods, {
// standard of allowing debuggees to add some identifiable metadata to their
// program sources or instances.
let label = L10N.getFormatStr("shadersList.programLabel", this.itemCount);
let contents = document.createElement("label");
contents.setAttribute("value", label);
contents.setAttribute("crop", "start");
contents.setAttribute("flex", "1");
// Append a program item to this container.
this.push([label, ""], {
this.push([contents], {
index: -1, /* specifies on which position should the item be appended */
relaxed: true, /* this container should allow dupes & degenerates */
attachment: {
label: label,
programActor: programActor,
checkboxState: true,
checkboxTooltip: L10N.getStr("shadersList.blackboxLabel")

View File

@ -14,10 +14,10 @@ function ifWebGLSupported() {
});
reload(target);
let [firstProgramActor, secondProgramActor] = yield promise.all([
let [[firstProgramActor, secondProgramActor]] = yield promise.all([
getPrograms(gFront, 2),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]).then(([programs]) => programs);
]);
let vsEditor = yield ShadersEditorsView._getEditor("vs");
let fsEditor = yield ShadersEditorsView._getEditor("fs");
@ -154,7 +154,7 @@ function ifWebGLSupported() {
function getItemLabel(aPanel, aIndex) {
return aPanel.panelWin.document.querySelectorAll(
".side-menu-widget-item-label")[aIndex];
".side-menu-widget-item-contents")[aIndex];
}
function getBlackBoxCheckbox(aPanel, aIndex) {

View File

@ -11,10 +11,10 @@ function ifWebGLSupported() {
let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
reload(target);
let [firstProgramActor, secondProgramActor] = yield promise.all([
let [[firstProgramActor, secondProgramActor]] = yield promise.all([
getPrograms(gFront, 2),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]).then(([programs]) => programs);
]);
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true);

View File

@ -10,10 +10,10 @@ function ifWebGLSupported() {
let { EVENTS, gFront, ShadersListView, ShadersEditorsView } = panel.panelWin;
reload(target);
let [programActor] = yield promise.all([
let [[programActor]] = yield promise.all([
getPrograms(gFront, 1),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]).then(([programs]) => programs);
]);
let programItem = ShadersListView.selectedItem;

View File

@ -14,10 +14,10 @@ function ifWebGLSupported() {
});
reload(target);
let [firstProgramActor, secondProgramActor] = yield promise.all([
let [[firstProgramActor, secondProgramActor]] = yield promise.all([
getPrograms(gFront, 2),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]).then(([programs]) => programs);
]);
let vsEditor = yield ShadersEditorsView._getEditor("vs");
let fsEditor = yield ShadersEditorsView._getEditor("fs");
@ -84,7 +84,7 @@ function ifWebGLSupported() {
function getItemLabel(aPanel, aIndex) {
return aPanel.panelWin.document.querySelectorAll(
".side-menu-widget-item-label")[aIndex];
".side-menu-widget-item-contents")[aIndex];
}
function getBlackBoxCheckbox(aPanel, aIndex) {

View File

@ -11,10 +11,10 @@ function ifWebGLSupported() {
let { gFront, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
reload(target);
let [firstProgramActor, secondProgramActor] = yield promise.all([
let [[firstProgramActor, secondProgramActor]] = yield promise.all([
getPrograms(gFront, 2),
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]).then(([programs]) => programs);
]);
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 127, g: 127, b: 127, a: 255 }, true);
yield ensurePixelIs(debuggee, { x: 64, y: 64 }, { r: 0, g: 127, b: 127, a: 127 }, true);
@ -45,5 +45,5 @@ function ifWebGLSupported() {
function getItemLabel(aPanel, aIndex) {
return aPanel.panelWin.document.querySelectorAll(
".side-menu-widget-item-label")[aIndex];
".side-menu-widget-item-contents")[aIndex];
}

View File

@ -31,9 +31,9 @@ function ifWebGLSupported() {
once(panel.panelWin, EVENTS.SOURCES_SHOWN)
]).then(([programs, ]) => programs);
is(ShadersListView.labels[0], L10N.getFormatStr("shadersList.programLabel", 0),
is(ShadersListView.attachments[0].label, L10N.getFormatStr("shadersList.programLabel", 0),
"The correct first label is shown in the shaders list.");
is(ShadersListView.labels[1], L10N.getFormatStr("shadersList.programLabel", 1),
is(ShadersListView.attachments[1].label, L10N.getFormatStr("shadersList.programLabel", 1),
"The correct second label is shown in the shaders list.");
let vertexShader = yield firstProgramActor.getVertexShader();

View File

@ -436,7 +436,7 @@ let ParserHelpers = {
loc.end.line = loc.start.line;
loc.end.column = loc.start.column + aNode.name.length;
return loc;
}
}
if (parentType == "MemberExpression") {
// e.g. "foo.bar"
// The location is unavailable for the identifier node "bar".
@ -445,6 +445,22 @@ let ParserHelpers = {
loc.start.column = loc.end.column - aNode.name.length;
return loc;
}
if (parentType == "LabeledStatement") {
// e.g. label: ...
// The location is unavailable for the identifier node "label".
let loc = JSON.parse(JSON.stringify(parentLocation));
loc.end.line = loc.start.line;
loc.end.column = loc.start.column + aNode.name.length;
return loc;
}
if (parentType == "ContinueStatement") {
// e.g. continue label
// The location is unavailable for the identifier node "label".
let loc = JSON.parse(JSON.stringify(parentLocation));
loc.start.line = loc.end.line;
loc.start.column = loc.end.column - aNode.name.length;
return loc;
}
} else {
if (parentType == "VariableDeclarator") {
// e.g. "let foo = 42"
@ -2334,7 +2350,15 @@ let SyntaxTreeVisitor = {
* The thrown exception.
*/
function log(aStr, aEx) {
let msg = "Warning: " + aStr + ", " + aEx + "\n" + aEx.stack;
let msg = "Warning: " + aStr + ", " + aEx.message;
if ("lineNumber" in aEx && "columnNumber" in aEx) {
msg += ", line: " + aEx.lineNumber + ", column: " + aEx.columnNumber;
}
if ("stack" in aEx) {
msg += "\n" + aEx.stack;
}
Cu.reportError(msg);
dump(msg + "\n");
};

View File

@ -17,7 +17,9 @@ this.EXPORTED_SYMBOLS = ["BreadcrumbsWidget"];
/**
* A breadcrumb-like list of items.
* This widget should be used in tandem with the WidgetMethods in ViewHelpers.jsm
*
* Note: this widget should be used in tandem with the WidgetMethods in
* ViewHelpers.jsm.
*
* @param nsIDOMNode aNode
* The element associated with the widget.
@ -59,8 +61,8 @@ BreadcrumbsWidget.prototype = {
*
* @param number aIndex
* The position in the container intended for this item.
* @param string | nsIDOMNode aContents
* The string or node displayed in the container.
* @param nsIDOMNode aContents
* The node displayed in the container.
* @return nsIDOMNode
* The element associated with the displayed item.
*/
@ -113,7 +115,9 @@ BreadcrumbsWidget.prototype = {
* Gets the currently selected child node in this container.
* @return nsIDOMNode
*/
get selectedItem() this._selectedItem,
get selectedItem() {
return this._selectedItem;
},
/**
* Sets the currently selected child node in this container.
@ -133,17 +137,37 @@ BreadcrumbsWidget.prototype = {
node.removeAttribute("checked");
}
}
},
/**
* Returns the value of the named attribute on this container.
*
* @param string aName
* The name of the attribute.
* @return string
* The current attribute value.
*/
getAttribute: function(aName) {
if (aName == "scrollPosition") return this._list.scrollPosition;
if (aName == "scrollWidth") return this._list.scrollWidth;
return this._parent.getAttribute(aName);
},
/**
* Ensures the specified element is visible.
*
* @param nsIDOMNode aElement
* The element to make visible.
*/
ensureElementIsVisible: function(aElement) {
if (!aElement) {
return;
}
// Repeated calls to ensureElementIsVisible would interfere with each other
// and may sometimes result in incorrect scroll positions.
setNamedTimeout("breadcrumb-select", ENSURE_SELECTION_VISIBLE_DELAY, () => {
if (this._selectedItem &&
// Sometimes the this._list doesn't have some methods, because the node
// is accessed while it's not visible or has been removed from the DOM.
// Avoid outputing an exception to the console in those cases.
this._list.ensureElementIsVisible) {
this._list.ensureElementIsVisible(this._selectedItem);
}
this._list.ensureElementIsVisible(aElement);
});
},
@ -183,8 +207,8 @@ BreadcrumbsWidget.prototype = {
*
* @param BreadcrumbsWidget aWidget
* The widget to contain this breadcrumb.
* @param string | nsIDOMNode aContents
* The string or node displayed in the container.
* @param nsIDOMNode aContents
* The node displayed in the container.
*/
function Breadcrumb(aWidget, aContents) {
this.document = aWidget.document;
@ -205,14 +229,6 @@ Breadcrumb.prototype = {
* The string or node displayed in the container.
*/
set contents(aContents) {
// If this item's view contents are a string, then create a label to hold
// the text displayed in this breadcrumb.
if (typeof aContents == "string") {
let label = this.document.createElement("label");
label.setAttribute("value", aContents);
this.contents = label;
return;
}
// If there are already some contents displayed, replace them.
if (this._target.hasChildNodes()) {
this._target.replaceChild(aContents, this._target.firstChild);

View File

@ -1,3 +1,10 @@
/* -*- 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";
const EventEmitter = require("devtools/shared/event-emitter");
const { Cu, Ci } = require("chrome");
const { ViewHelpers } = Cu.import("resource:///modules/devtools/ViewHelpers.jsm", {});
@ -107,7 +114,9 @@ FastListWidget.prototype = {
* Gets the currently selected child node in this container.
* @return nsIDOMNode
*/
get selectedItem() this._selectedItem,
get selectedItem() {
return this._selectedItem;
},
/**
* Sets the currently selected child node in this container.
@ -122,11 +131,9 @@ FastListWidget.prototype = {
for (let node of menuArray) {
if (node == child) {
node.classList.add("selected");
node.parentNode.classList.add("selected");
this._selectedItem = node;
} else {
node.classList.remove("selected");
node.parentNode.classList.remove("selected");
}
}
@ -193,7 +200,7 @@ FastListWidget.prototype = {
// Ensure the element is visible but not scrolled horizontally.
let boxObject = this._list.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
boxObject.ensureElementIsVisible(element);
boxObject.scrollBy(-element.clientWidth, 0);
boxObject.scrollBy(-this._list.clientWidth, 0);
},
window: null,

View File

@ -8,26 +8,16 @@
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
Cu.import("resource:///modules/devtools/shared/event-emitter.js");
XPCOMUtils.defineLazyModuleGetter(this, "devtools",
"resource://gre/modules/devtools/Loader.jsm");
Object.defineProperty(this, "NetworkHelper", {
get: function() {
return devtools.require("devtools/toolkit/webconsole/network-helper");
},
configurable: true,
enumerable: true
});
this.EXPORTED_SYMBOLS = ["SideMenuWidget"];
/**
* A simple side menu, with the ability of grouping menu items.
* This widget should be used in tandem with the WidgetMethods in ViewHelpers.jsm
*
* Note: this widget should be used in tandem with the WidgetMethods in
* ViewHelpers.jsm.
*
* @param nsIDOMNode aNode
* The element associated with the widget.
@ -73,6 +63,7 @@ this.SideMenuWidget = function SideMenuWidget(aNode, aOptions={}) {
// Delegate some of the associated node's methods to satisfy the interface
// required by MenuContainer instances.
ViewHelpers.delegateWidgetAttributeMethods(this, aNode);
ViewHelpers.delegateWidgetEventMethods(this, aNode);
};
@ -82,12 +73,6 @@ SideMenuWidget.prototype = {
*/
sortedGroups: true,
/**
* Specifies if this container should try to keep the selected item visible.
* (For example, when new items are added the selection is brought into view).
*/
maintainSelectionVisible: true,
/**
* Specifies that the container viewport should be "stuck" to the
* bottom. That is, the container is automatically scrolled down to
@ -102,24 +87,17 @@ SideMenuWidget.prototype = {
*
* @param number aIndex
* The position in the container intended for this item.
* @param string | nsIDOMNode aContents
* The string or node displayed in the container.
* @param string aTooltip [optional]
* A tooltip attribute for the displayed item.
* @param string aGroup [optional]
* The group to place the displayed item into.
* @param Object aAttachment [optional]
* Extra data for the user.
* @param nsIDOMNode aContents
* The node displayed in the container.
* @param object aAttachment [optional]
* Some attached primitive/object. Custom options supported:
* - group: a string specifying the group to place this item into
* - checkboxState: the checked state of the checkbox, if shown
* - checkboxTooltip: the tooltip text for the checkbox, if shown
* @return nsIDOMNode
* The element associated with the displayed item.
*/
insertItemAt: function(aIndex, aContents, aTooltip = "", aGroup = "", aAttachment={}) {
aTooltip = NetworkHelper.convertToUnicode(unescape(aTooltip));
aGroup = NetworkHelper.convertToUnicode(unescape(aGroup));
// Invalidate any notices set on this widget.
this.removeAttribute("notice");
insertItemAt: function(aIndex, aContents, aAttachment={}) {
// Maintaining scroll position at the bottom when a new item is inserted
// depends on several factors (the order of testing is important to avoid
// needlessly expensive operations that may cause reflows):
@ -133,13 +111,10 @@ SideMenuWidget.prototype = {
// 4. The list should already be scrolled at the bottom.
(this._list.scrollTop + this._list.clientHeight >= this._list.scrollHeight);
let group = this._getMenuGroupForName(aGroup);
let item = this._getMenuItemForGroup(group, aContents, aTooltip, aAttachment);
let group = this._getMenuGroupForName(aAttachment.group);
let item = this._getMenuItemForGroup(group, aContents, aAttachment);
let element = item.insertSelfAt(aIndex);
if (this.maintainSelectionVisible) {
this.ensureElementIsVisible(this.selectedItem);
}
if (maintainScrollAtBottom) {
this._list.scrollTop = this._list.scrollHeight;
}
@ -171,7 +146,6 @@ SideMenuWidget.prototype = {
// Remove the item itself, not the contents.
aChild.parentNode.remove();
} else {
// Groups with no title don't have any special internal structure.
aChild.remove();
}
@ -208,7 +182,9 @@ SideMenuWidget.prototype = {
* Gets the currently selected child node in this container.
* @return nsIDOMNode
*/
get selectedItem() this._selectedItem,
get selectedItem() {
return this._selectedItem;
},
/**
* Sets the currently selected child node in this container.
@ -230,8 +206,6 @@ SideMenuWidget.prototype = {
node.parentNode.classList.remove("selected");
}
}
this.ensureElementIsVisible(this.selectedItem);
},
/**
@ -247,14 +221,8 @@ SideMenuWidget.prototype = {
// Ensure the element is visible but not scrolled horizontally.
let boxObject = this._list.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
// Sometimes the boxObject doesn't have some methods, because the node
// is accessed while it's not visible or has been removed from the DOM.
// Avoid outputing an exception to the console in those cases.
if (boxObject.ensureElementIsVisible && boxObject.scrollBy) {
boxObject.ensureElementIsVisible(aElement);
boxObject.scrollBy(-aElement.clientWidth, 0);
}
boxObject.ensureElementIsVisible(aElement);
boxObject.scrollBy(-this._list.clientWidth, 0);
},
/**
@ -280,18 +248,6 @@ SideMenuWidget.prototype = {
}
},
/**
* Returns the value of the named attribute on this container.
*
* @param string aName
* The name of the attribute.
* @return string
* The current attribute value.
*/
getAttribute: function(aName) {
return this._parent.getAttribute(aName);
},
/**
* Adds a new attribute or changes an existing attribute on this container.
*
@ -303,8 +259,8 @@ SideMenuWidget.prototype = {
setAttribute: function(aName, aValue) {
this._parent.setAttribute(aName, aValue);
if (aName == "notice") {
this.notice = aValue;
if (aName == "emptyText") {
this._textWhenEmpty = aValue;
}
},
@ -317,8 +273,8 @@ SideMenuWidget.prototype = {
removeAttribute: function(aName) {
this._parent.removeAttribute(aName);
if (aName == "notice") {
this._removeNotice();
if (aName == "emptyText") {
this._removeEmptyText();
}
},
@ -339,50 +295,43 @@ SideMenuWidget.prototype = {
},
/**
* Sets the text displayed in this container as a notice.
* Sets the text displayed in this container as a when empty.
* @param string aValue
*/
set notice(aValue) {
if (this._noticeTextNode) {
this._noticeTextNode.setAttribute("value", aValue);
set _textWhenEmpty(aValue) {
if (this._emptyTextNode) {
this._emptyTextNode.setAttribute("value", aValue);
}
this._noticeTextValue = aValue;
this._appendNotice();
this._emptyTextValue = aValue;
this._showEmptyText();
},
/**
* Creates and appends a label representing a notice in this container.
* Creates and appends a label signaling that this container is empty.
*/
_appendNotice: function() {
if (this._noticeTextNode || !this._noticeTextValue) {
_showEmptyText: function() {
if (this._emptyTextNode || !this._emptyTextValue) {
return;
}
let container = this.document.createElement("vbox");
container.className = "side-menu-widget-empty-notice-container";
container.setAttribute("theme", this._theme);
let label = this.document.createElement("label");
label.className = "plain side-menu-widget-empty-notice";
label.setAttribute("value", this._noticeTextValue);
container.appendChild(label);
label.className = "plain side-menu-widget-empty-text";
label.setAttribute("value", this._emptyTextValue);
label.setAttribute("theme", this._theme);
this._parent.insertBefore(container, this._list);
this._noticeTextContainer = container;
this._noticeTextNode = label;
this._parent.insertBefore(label, this._list);
this._emptyTextNode = label;
},
/**
* Removes the label representing a notice in this container.
*/
_removeNotice: function() {
if (!this._noticeTextNode) {
_removeEmptyText: function() {
if (!this._emptyTextNode) {
return;
}
this._parent.removeChild(this._noticeTextContainer);
this._noticeTextContainer = null;
this._noticeTextNode = null;
this._parent.removeChild(this._emptyTextNode);
this._emptyTextNode = null;
},
/**
@ -417,15 +366,13 @@ SideMenuWidget.prototype = {
*
* @param SideMenuGroup aGroup
* The group to contain the menu item.
* @param string | nsIDOMNode aContents
* The string or node displayed in the container.
* @param string aTooltip [optional]
* A tooltip attribute for the displayed item.
* @param nsIDOMNode aContents
* The node displayed in the container.
* @param object aAttachment [optional]
* The attachement object.
* Some attached primitive/object.
*/
_getMenuItemForGroup: function(aGroup, aContents, aTooltip, aAttachment) {
return new SideMenuItem(aGroup, aContents, aTooltip, aAttachment, {
_getMenuItemForGroup: function(aGroup, aContents, aAttachment) {
return new SideMenuItem(aGroup, aContents, aAttachment, {
theme: this._theme,
showArrow: this._showArrows,
showCheckbox: this._showItemCheckboxes
@ -445,10 +392,8 @@ SideMenuWidget.prototype = {
_orderedGroupElementsArray: null,
_orderedMenuElementsArray: null,
_itemsByElement: null,
_ensureVisibleTimeout: null,
_noticeTextContainer: null,
_noticeTextNode: null,
_noticeTextValue: ""
_emptyTextNode: null,
_emptyTextValue: ""
};
/**
@ -568,10 +513,8 @@ SideMenuGroup.prototype = {
*
* @param SideMenuGroup aGroup
* The group to contain this menu item.
* @param string aTooltip [optional]
* A tooltip attribute for the displayed item.
* @param string | nsIDOMNode aContents
* The string or node displayed in the container.
* @param nsIDOMNode aContents
* The node displayed in the container.
* @param object aAttachment [optional]
* The attachment object.
* @param object aOptions [optional]
@ -580,7 +523,7 @@ SideMenuGroup.prototype = {
* - showArrow: specifies if a horizontal arrow should be displayed.
* - showCheckbox: specifies if a checkbox should be displayed.
*/
function SideMenuItem(aGroup, aContents, aTooltip, aAttachment={}, aOptions={}) {
function SideMenuItem(aGroup, aContents, aAttachment={}, aOptions={}) {
this.document = aGroup.document;
this.window = aGroup.window;
this.ownerView = aGroup;
@ -588,7 +531,6 @@ function SideMenuItem(aGroup, aContents, aTooltip, aAttachment={}, aOptions={})
if (aOptions.showArrow || aOptions.showCheckbox) {
let container = this._container = this.document.createElement("hbox");
container.className = "side-menu-widget-item";
container.setAttribute("tooltiptext", aTooltip);
container.setAttribute("theme", aOptions.theme);
let target = this._target = this.document.createElement("vbox");
@ -671,17 +613,6 @@ SideMenuItem.prototype = {
* The string or node displayed in the container.
*/
set contents(aContents) {
// If this item's view contents are a string, then create a label to hold
// the text displayed in this breadcrumb.
if (typeof aContents == "string") {
let label = this.document.createElement("label");
label.className = "side-menu-widget-item-label";
label.setAttribute("value", aContents);
label.setAttribute("crop", "start");
label.setAttribute("flex", "1");
this.contents = label;
return;
}
// If there are already some contents displayed, replace them.
if (this._target.hasChildNodes()) {
this._target.replaceChild(aContents, this._target.firstChild);

View File

@ -0,0 +1,253 @@
/* -*- 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";
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
this.EXPORTED_SYMBOLS = ["SimpleListWidget"];
/**
* A very simple vertical list view.
*
* Note: this widget should be used in tandem with the WidgetMethods in
* ViewHelpers.jsm.
*
* @param nsIDOMNode aNode
* The element associated with the widget.
*/
function SimpleListWidget(aNode) {
this.document = aNode.ownerDocument;
this.window = this.document.defaultView;
this._parent = aNode;
// Create an internal list container.
this._list = this.document.createElement("scrollbox");
this._list.className = "simple-list-widget-container";
this._list.setAttribute("flex", "1");
this._list.setAttribute("orient", "vertical");
this._parent.appendChild(this._list);
// Delegate some of the associated node's methods to satisfy the interface
// required by WidgetMethods instances.
ViewHelpers.delegateWidgetAttributeMethods(this, aNode);
ViewHelpers.delegateWidgetEventMethods(this, aNode);
}
SimpleListWidget.prototype = {
/**
* Inserts an item in this container at the specified index.
*
* @param number aIndex
* The position in the container intended for this item.
* @param nsIDOMNode aContents
* The node displayed in the container.
* @return nsIDOMNode
* The element associated with the displayed item.
*/
insertItemAt: function(aIndex, aContents) {
aContents.classList.add("simple-list-widget-item");
let list = this._list;
return list.insertBefore(aContents, list.childNodes[aIndex]);
},
/**
* Returns the child node in this container situated at the specified index.
*
* @param number aIndex
* The position in the container intended for this item.
* @return nsIDOMNode
* The element associated with the displayed item.
*/
getItemAtIndex: function(aIndex) {
return this._list.childNodes[aIndex];
},
/**
* Immediately removes the specified child node from this container.
*
* @param nsIDOMNode aChild
* The element associated with the displayed item.
*/
removeChild: function(aChild) {
this._list.removeChild(aChild);
if (this._selectedItem == aChild) {
this._selectedItem = null;
}
},
/**
* Removes all of the child nodes from this container.
*/
removeAllItems: function() {
let list = this._list;
let parent = this._parent;
while (list.hasChildNodes()) {
list.firstChild.remove();
}
parent.scrollTop = 0;
parent.scrollLeft = 0;
this._selectedItem = null;
},
/**
* Gets the currently selected child node in this container.
* @return nsIDOMNode
*/
get selectedItem() {
return this._selectedItem;
},
/**
* Sets the currently selected child node in this container.
* @param nsIDOMNode aChild
*/
set selectedItem(aChild) {
let childNodes = this._list.childNodes;
if (!aChild) {
this._selectedItem = null;
}
for (let node of childNodes) {
if (node == aChild) {
node.classList.add("selected");
this._selectedItem = node;
} else {
node.classList.remove("selected");
}
}
},
/**
* Adds a new attribute or changes an existing attribute on this container.
*
* @param string aName
* The name of the attribute.
* @param string aValue
* The desired attribute value.
*/
setAttribute: function(aName, aValue) {
this._parent.setAttribute(aName, aValue);
if (aName == "emptyText") {
this._textWhenEmpty = aValue;
} else if (aName == "headerText") {
this._textAsHeader = aValue;
}
},
/**
* Removes an attribute on this container.
*
* @param string aName
* The name of the attribute.
*/
removeAttribute: function(aName) {
this._parent.removeAttribute(aName);
if (aName == "emptyText") {
this._removeEmptyText();
}
},
/**
* Ensures the specified element is visible.
*
* @param nsIDOMNode aElement
* The element to make visible.
*/
ensureElementIsVisible: function(aElement) {
if (!aElement) {
return;
}
// Ensure the element is visible but not scrolled horizontally.
let boxObject = this._list.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
boxObject.ensureElementIsVisible(aElement);
boxObject.scrollBy(-this._list.clientWidth, 0);
},
/**
* Sets the text displayed permanently in this container as a header.
* @param string aValue
*/
set _textAsHeader(aValue) {
if (this._headerTextNode) {
this._headerTextNode.setAttribute("value", aValue);
}
this._headerTextValue = aValue;
this._showHeaderText();
},
/**
* Sets the text displayed in this container as a when empty.
* @param string aValue
*/
set _textWhenEmpty(aValue) {
if (this._emptyTextNode) {
this._emptyTextNode.setAttribute("value", aValue);
}
this._emptyTextValue = aValue;
this._showEmptyText();
},
/**
* Creates and appends a label displayed as this container's header.
*/
_showHeaderText: function() {
if (this._headerTextNode || !this._headerTextValue) {
return;
}
let label = this.document.createElement("label");
label.className = "plain simple-list-widget-perma-text";
label.setAttribute("value", this._headerTextValue);
this._parent.insertBefore(label, this._list);
this._headerTextNode = label;
},
/**
* Creates and appends a label signaling that this container is empty.
*/
_showEmptyText: function() {
if (this._emptyTextNode || !this._emptyTextValue) {
return;
}
let label = this.document.createElement("label");
label.className = "plain simple-list-widget-empty-text";
label.setAttribute("value", this._emptyTextValue);
this._parent.appendChild(label);
this._emptyTextNode = label;
},
/**
* Removes the label signaling that this container is empty.
*/
_removeEmptyText: function() {
if (!this._emptyTextNode) {
return;
}
this._parent.removeChild(this._emptyTextNode);
this._emptyTextNode = null;
},
window: null,
document: null,
_parent: null,
_list: null,
_selectedItem: null,
_headerTextNode: null,
_headerTextValue: "",
_emptyTextNode: null,
_emptyTextValue: ""
};

View File

@ -2078,7 +2078,6 @@ Scope.prototype = {
_enumItems: null,
_nonEnumItems: null,
_fetched: false,
_retrieved: false,
_committed: false,
_isLocked: false,
_isExpanded: false,

View File

@ -152,8 +152,6 @@ VariablesViewController.prototype = {
aTarget.setGrip(aGrip.initial + aResponse.substring);
aTarget.hideArrow();
// Mark the string as having retrieved.
aTarget._retrieved = true;
deferred.resolve();
});
@ -172,13 +170,6 @@ VariablesViewController.prototype = {
_populateFromObject: function(aTarget, aGrip) {
let deferred = promise.defer();
// Mark the specified variable as having retrieved all its properties.
let finish = variable => {
variable._retrieved = true;
this.view.commitHierarchy();
deferred.resolve();
};
let objectClient = this._getObjectClient(aGrip);
objectClient.getPrototypeAndProperties(aResponse => {
let { ownProperties, prototype } = aResponse;
@ -224,12 +215,12 @@ VariablesViewController.prototype = {
// in the current scope chain. Not necessarily an actual error,
// it just means that there's no closure for the function.
console.warn(aResponse.error + ": " + aResponse.message);
return void finish(aTarget);
return void deferred.resolve();
}
this._addVarScope(aTarget, aResponse.scope).then(() => finish(aTarget));
this._populateWithClosure(aTarget, aResponse.scope).then(deferred.resolve);
});
} else {
finish(aTarget);
deferred.resolve();
}
});
@ -237,48 +228,43 @@ VariablesViewController.prototype = {
},
/**
* Adds the scope chain elements (closures) of a function variable to the
* view.
* Adds the scope chain elements (closures) of a function variable.
*
* @param Variable aTarget
* The variable where the properties will be placed into.
* @param Scope aScope
* The lexical environment form as specified in the protocol.
*/
_addVarScope: function(aTarget, aScope) {
_populateWithClosure: function(aTarget, aScope) {
let objectScopes = [];
let environment = aScope;
let funcScope = aTarget.addItem("<Closure>");
funcScope._target.setAttribute("scope", "");
funcScope._fetched = true;
funcScope.target.setAttribute("scope", "");
funcScope.showArrow();
do {
// Create a scope to contain all the inspected variables.
let label = StackFrameUtils.getScopeLabel(environment);
// Block scopes have the same label, so make addItem allow duplicates.
// Block scopes may have the same label, so make addItem allow duplicates.
let closure = funcScope.addItem(label, undefined, true);
closure._target.setAttribute("scope", "");
closure._fetched = environment.class == "Function";
closure.target.setAttribute("scope", "");
closure.showArrow();
// Add nodes for every argument and every other variable in scope.
if (environment.bindings) {
this._addBindings(closure, environment.bindings);
funcScope._retrieved = true;
closure._retrieved = true;
this._populateWithEnvironmentBindings(closure, environment.bindings);
} else {
let deferred = Promise.defer();
let deferred = promise.defer();
objectScopes.push(deferred.promise);
this._getEnvironmentClient(environment).getBindings(response => {
this._addBindings(closure, response.bindings);
funcScope._retrieved = true;
closure._retrieved = true;
this._populateWithEnvironmentBindings(closure, response.bindings);
deferred.resolve();
});
}
} while ((environment = environment.parent));
aTarget.expand();
return Promise.all(objectScopes).then(() => {
return promise.all(objectScopes).then(() => {
// Signal that scopes have been fetched.
this.view.emit("fetched", "scopes", funcScope);
});
@ -287,32 +273,32 @@ VariablesViewController.prototype = {
/**
* Adds nodes for every specified binding to the closure node.
*
* @param Variable closure
* The node where the bindings will be placed into.
* @param object bindings
* @param Variable aTarget
* The variable where the bindings will be placed into.
* @param object aBindings
* The bindings form as specified in the protocol.
*/
_addBindings: function(closure, bindings) {
for (let argument of bindings.arguments) {
let name = Object.getOwnPropertyNames(argument)[0];
let argRef = closure.addItem(name, argument[name]);
let argVal = argument[name].value;
this.addExpander(argRef, argVal);
}
_populateWithEnvironmentBindings: function(aTarget, aBindings) {
// Add nodes for every argument in the scope.
aTarget.addItems(aBindings.arguments.reduce((accumulator, arg) => {
let name = Object.getOwnPropertyNames(arg)[0];
let descriptor = arg[name];
accumulator[name] = descriptor;
return accumulator;
}, {}), {
// Arguments aren't sorted.
sorted: false,
// Expansion handlers must be set after the properties are added.
callback: this.addExpander
});
let aVariables = bindings.variables;
let variableNames = Object.keys(aVariables);
// Sort all of the variables before adding them, if preferred.
if (VARIABLES_SORTING_ENABLED) {
variableNames.sort();
}
// Add the variables to the specified scope.
for (let name of variableNames) {
let varRef = closure.addItem(name, aVariables[name]);
let varVal = aVariables[name].value;
this.addExpander(varRef, varVal);
}
// Add nodes for every other variable in the scope.
aTarget.addItems(aBindings.variables, {
// Not all variables need to force sorted properties.
sorted: VARIABLES_SORTING_ENABLED,
// Expansion handlers must be set after the properties are added.
callback: this.addExpander
});
},
/**
@ -328,12 +314,10 @@ VariablesViewController.prototype = {
// Attach evaluation macros as necessary.
if (aTarget.getter || aTarget.setter) {
aTarget.evaluationMacro = this._overrideValueEvalMacro;
let getter = aTarget.get("get");
if (getter) {
getter.evaluationMacro = this._getterOrSetterEvalMacro;
}
let setter = aTarget.get("set");
if (setter) {
setter.evaluationMacro = this._getterOrSetterEvalMacro;
@ -352,19 +336,13 @@ VariablesViewController.prototype = {
aTarget.showArrow();
}
if (aSource.type == "block" || aSource.type == "function") {
// Block and function environments already contain scope arguments and
// corresponding variables as bindings.
this.populate(aTarget, aSource);
} else {
// Make sure that properties are always available on expansion.
aTarget.onexpand = () => this.populate(aTarget, aSource);
// Make sure that properties are always available on expansion.
aTarget.onexpand = () => this.populate(aTarget, aSource);
// Some variables are likely to contain a very large number of properties.
// It's a good idea to be prepared in case of an expansion.
if (aTarget.shouldPrefetch) {
aTarget.addEventListener("mouseover", aTarget.onexpand, false);
}
// Some variables are likely to contain a very large number of properties.
// It's a good idea to be prepared in case of an expansion.
if (aTarget.shouldPrefetch) {
aTarget.addEventListener("mouseover", aTarget.onexpand, false);
}
// Register all the actors that this controller now depends on.
@ -404,9 +382,11 @@ VariablesViewController.prototype = {
// If the target is a Variable or Property then we're fetching properties.
if (VariablesView.isVariable(aTarget)) {
this._populateFromObject(aTarget, aSource).then(() => {
deferred.resolve();
// Signal that properties have been fetched.
this.view.emit("fetched", "properties", aTarget);
// Commit the hierarchy because new items were added.
this.view.commitHierarchy();
deferred.resolve();
});
return deferred.promise;
}
@ -414,43 +394,29 @@ VariablesViewController.prototype = {
switch (aSource.type) {
case "longString":
this._populateFromLongString(aTarget, aSource).then(() => {
deferred.resolve();
// Signal that a long string has been fetched.
this.view.emit("fetched", "longString", aTarget);
deferred.resolve();
});
break;
case "with":
case "object":
this._populateFromObject(aTarget, aSource.object).then(() => {
deferred.resolve();
// Signal that variables have been fetched.
this.view.emit("fetched", "variables", aTarget);
// Commit the hierarchy because new items were added.
this.view.commitHierarchy();
deferred.resolve();
});
break;
case "block":
case "function":
// Add nodes for every argument and every other variable in scope.
let args = aSource.bindings.arguments;
if (args) {
for (let arg of args) {
let name = Object.getOwnPropertyNames(arg)[0];
let ref = aTarget.addItem(name, arg[name]);
let val = arg[name].value;
this.addExpander(ref, val);
}
}
aTarget.addItems(aSource.bindings.variables, {
// Not all variables need to force sorted properties.
sorted: VARIABLES_SORTING_ENABLED,
// Expansion handlers must be set after the properties are added.
callback: this.addExpander
});
this._populateWithEnvironmentBindings(aTarget, aSource.bindings);
// No need to signal that variables have been fetched, since
// the scope arguments and variables are already attached to the
// environment bindings, so pausing the active thread is unnecessary.
// Commit the hierarchy because new items were added.
this.view.commitHierarchy();
deferred.resolve();
break;
default:

View File

@ -16,6 +16,7 @@ const WIDGET_FOCUSABLE_NODES = new Set(["vbox", "hbox"]);
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm");
this.EXPORTED_SYMBOLS = [
"Heritage", "ViewHelpers", "WidgetMethods",
@ -118,9 +119,12 @@ this.ViewHelpers = {
* A node to delegate the methods to.
*/
delegateWidgetAttributeMethods: function(aWidget, aNode) {
aWidget.getAttribute = aNode.getAttribute.bind(aNode);
aWidget.setAttribute = aNode.setAttribute.bind(aNode);
aWidget.removeAttribute = aNode.removeAttribute.bind(aNode);
aWidget.getAttribute =
aWidget.getAttribute || aNode.getAttribute.bind(aNode);
aWidget.setAttribute =
aWidget.setAttribute || aNode.setAttribute.bind(aNode);
aWidget.removeAttribute =
aWidget.removeAttribute || aNode.removeAttribute.bind(aNode);
},
/**
@ -132,8 +136,10 @@ this.ViewHelpers = {
* A node to delegate the methods to.
*/
delegateWidgetEventMethods: function(aWidget, aNode) {
aWidget.addEventListener = aNode.addEventListener.bind(aNode);
aWidget.removeEventListener = aNode.removeEventListener.bind(aNode);
aWidget.addEventListener =
aWidget.addEventListener || aNode.addEventListener.bind(aNode);
aWidget.removeEventListener =
aWidget.removeEventListener || aNode.removeEventListener.bind(aNode);
},
/**
@ -404,46 +410,35 @@ ViewHelpers.Prefs.prototype = {
/**
* A generic Item is used to describe children present in a Widget.
* The label, value and description properties are necessarily strings.
*
* This is basically a very thin wrapper around an nsIDOMNode, with a few
* characteristics, like a `value` and an `attachment`.
*
* The characteristics are optional, and their meaning is entirely up to you.
* - The `value` should be a string, passed as an argument.
* - The `attachment` is any kind of primitive or object, passed as an argument.
*
* Iterable via "for (let childItem of parentItem) { }".
*
* @param object aOwnerView
* The owner view creating this item.
* @param nsIDOMNode aElement
* A prebuilt node to be wrapped.
* @param string aValue
* A string identifying the node.
* @param any aAttachment
* Some attached primitive/object.
* @param nsIDOMNode | nsIDOMDocumentFragment | array aContents [optional]
* A prebuilt node, or an array containing the following properties:
* - aLabel: the label displayed in the widget
* - aValue: the actual internal value of the item
* - aDescription: an optional description of the item
*/
function Item(aOwnerView, aAttachment, aContents = []) {
function Item(aOwnerView, aElement, aValue, aAttachment) {
this.ownerView = aOwnerView;
this.attachment = aAttachment;
let [aLabel, aValue, aDescription] = aContents;
// Make sure the label and the value are always strings.
this._label = aLabel + "";
this._value = aValue + "";
// Make sure the description is also a string, but only if it's available.
if (aDescription !== undefined) {
this._description = aDescription + "";
}
// Allow the insertion of prebuilt nodes, otherwise delegate the item view
// creation to a widget.
if (ViewHelpers.isNode(aLabel)) {
this._prebuiltTarget = aLabel;
}
XPCOMUtils.defineLazyGetter(this, "_itemsByElement", () => new Map());
this._prebuiltNode = aElement;
};
Item.prototype = {
get label() this._label,
get value() this._value,
get description() this._description,
get target() this._target,
get value() { return this._value; },
get target() { return this._target; },
/**
* Immediately appends a child item to this item.
@ -459,9 +454,11 @@ Item.prototype = {
* The item associated with the displayed element.
*/
append: function(aElement, aOptions = {}) {
let item = new Item(this, aOptions.attachment);
let item = new Item(this, aElement, "", aOptions.attachment);
// Entangle the item with the newly inserted child node.
// Make sure this is done with the value returned by appendChild(),
// to avoid storing a potential DocumentFragment.
this._entangleItem(item, this._target.appendChild(aElement));
// Handle any additional options after entangling the item.
@ -518,7 +515,6 @@ Item.prototype = {
}
this._unlinkItem(aItem);
aItem._prebuiltTarget = null;
aItem._target = null;
},
@ -537,24 +533,20 @@ Item.prototype = {
* @return string
*/
toString: function() {
if (this._label != "undefined" && this._value != "undefined") {
return this._label + " -> " + this._value;
}
if (this.attachment) {
return this.attachment.toString();
}
return "(null)";
return this._value + " :: " + this._target + " :: " + this.attachment;
},
_label: "",
_value: "",
_description: undefined,
_prebuiltTarget: null,
_target: null,
_prebuiltNode: null,
finalize: null,
attachment: null
};
// Creating maps thousands of times for widgets with a large number of children
// fills up a lot of memory. Make sure these are instantiated only if needed.
DevToolsUtils.defineLazyPrototypeGetter(Item.prototype, "_itemsByElement", Map);
/**
* Some generic Widget methods handling Item instances.
* Iterable via "for (let childItem of wrappedView) { }".
@ -570,14 +562,14 @@ Item.prototype = {
* });
*
* See https://gist.github.com/victorporof/5749386 for more details.
* The devtools/shared/widgets/SimpleListWidget.jsm is an implementation example.
*
* Language:
* - An "item" is an instance of an Item.
* - An "element" or "node" is a nsIDOMNode.
*
* The supplied element node or widget can either be a <xul:menulist>, or any
* other object interfacing the following methods:
* - function:nsIDOMNode insertItemAt(aIndex:number, aLabel:string, aValue:string)
* The supplied widget can be any object implementing the following methods:
* - function:nsIDOMNode insertItemAt(aIndex:number, aNode:nsIDOMNode, aValue:string)
* - function:nsIDOMNode getItemAtIndex(aIndex:number)
* - function removeChild(aChild:nsIDOMNode)
* - function removeAllItems()
@ -589,8 +581,15 @@ Item.prototype = {
* - function addEventListener(aName:string, aCallback:function, aBubbleFlag:boolean)
* - function removeEventListener(aName:string, aCallback:function, aBubbleFlag:boolean)
*
* For automagical keyboard and mouse accessibility, the element node or widget
* should be an event emitter with the following events:
* Optional methods that can be implemented by the widget:
* - function ensureElementIsVisible(aChild:nsIDOMNode)
*
* Optional attributes that may be handled (when calling get/set/removeAttribute):
* - "emptyText": label temporarily added when there are no items present
* - "headerText": label permanently added as a header
*
* For automagical keyboard and mouse accessibility, the widget should be an
* event emitter with the following events:
* - "keyPress" -> (aName:string, aEvent:KeyboardEvent)
* - "mousePress" -> (aName:string, aEvent:MouseEvent)
*/
@ -602,9 +601,9 @@ this.WidgetMethods = {
set widget(aWidget) {
this._widget = aWidget;
// Can't use WeakMaps for itemsByLabel or itemsByValue because
// keys are strings, and itemsByElement needs to be iterable.
XPCOMUtils.defineLazyGetter(this, "_itemsByLabel", () => new Map());
// Can't use a WeakMap for _itemsByValue because keys are strings, and
// can't use one for _itemsByElement either, since it needs to be iterable.
XPCOMUtils.defineLazyGetter(this, "_itemsByValue", () => new Map());
XPCOMUtils.defineLazyGetter(this, "_itemsByElement", () => new Map());
XPCOMUtils.defineLazyGetter(this, "_stagedItems", () => []);
@ -632,40 +631,34 @@ this.WidgetMethods = {
* multiple items.
*
* By default, this container assumes that all the items should be displayed
* sorted by their label. This can be overridden with the "index" flag,
* sorted by their value. This can be overridden with the "index" flag,
* specifying on which position should an item be appended. The "staged" and
* "index" flags are mutually exclusive, meaning that all staged items
* will always be appended.
*
* Furthermore, this container makes sure that all the items are unique
* (two items with the same label or value are not allowed) and non-degenerate
* (items with "undefined" or "null" labels/values). This can, as well, be
* overridden via the "relaxed" flag.
*
* @param nsIDOMNode | nsIDOMDocumentFragment array aContents
* A prebuilt node, or an array containing the following properties:
* - label: the label displayed in the container
* - value: the actual internal value of the item
* - description: an optional description of the item
* @param nsIDOMNode aElement
* A prebuilt node to be wrapped.
* @param string aValue
* A string identifying the node.
* @param object aOptions [optional]
* Additional options or flags supported by this operation:
* - attachment: some attached primitive/object for the item
* - staged: true to stage the item to be appended later
* - index: specifies on which position should the item be appended
* - relaxed: true if this container should allow dupes & degenerates
* - attachment: some attached primitive/object for the item
* - attributes: a batch of attributes set to the displayed element
* - finalize: function invoked when the item is removed
* @return Item
* The item associated with the displayed element if an unstaged push,
* undefined if the item was staged for a later commit.
*/
push: function(aContents, aOptions = {}) {
let item = new Item(this, aOptions.attachment, aContents);
push: function([aElement, aValue], aOptions = {}) {
let item = new Item(this, aElement, aValue, aOptions.attachment);
// Batch the item to be added later.
if (aOptions.staged) {
// An ulterior commit operation will ignore any specified index.
delete aOptions.index;
// An ulterior commit operation will ignore any specified index, so
// no reason to keep it around.
aOptions.index = undefined;
return void this._stagedItems.push({ item: item, options: aOptions });
}
// Find the target position in this container and insert the item there.
@ -700,27 +693,6 @@ this.WidgetMethods = {
this._stagedItems.length = 0;
},
/**
* Updates this container to reflect the information provided by the
* currently selected item.
*
* @return boolean
* True if a selected item was available, false otherwise.
*/
refresh: function() {
let selectedItem = this.selectedItem;
if (!selectedItem) {
return false;
}
let { _label: label, _value: value, _description: desc } = selectedItem;
this._widget.removeAttribute("notice");
this._widget.setAttribute("label", label);
this._widget.setAttribute("tooltiptext", desc !== undefined ? desc : value);
return true;
},
/**
* Immediately removes the specified item from this container.
*
@ -733,7 +705,12 @@ this.WidgetMethods = {
}
this._widget.removeChild(aItem._target);
this._untangleItem(aItem);
if (!this.itemCount) this.empty();
if (!this._itemsByElement.size) {
this._preferredValue = this.selectedValue;
this._widget.selectedItem = null;
this._widget.setAttribute("emptyText", this._emptyText);
}
},
/**
@ -753,25 +730,55 @@ this.WidgetMethods = {
this._preferredValue = this.selectedValue;
this._widget.selectedItem = null;
this._widget.removeAllItems();
this._widget.setAttribute("notice", this.emptyText);
this._widget.setAttribute("label", this.emptyText);
this._widget.removeAttribute("tooltiptext");
this._widget.setAttribute("emptyText", this._emptyText);
for (let [, item] of this._itemsByElement) {
this._untangleItem(item);
}
this._itemsByLabel.clear();
this._itemsByValue.clear();
this._itemsByElement.clear();
this._stagedItems.length = 0;
},
/**
* The label string automatically added to this container when there are
* no child nodes present.
* Ensures the specified item is visible in this container.
*
* @param Item aItem
* The item to bring into view.
*/
emptyText: "",
ensureItemIsVisible: function(aItem) {
this._widget.ensureElementIsVisible(aItem._target);
},
/**
* Ensures the item at the specified index is visible in this container.
*
* @param number aIndex
* The index of the item to bring into view.
*/
ensureIndexIsVisible: function(aIndex) {
this.ensureItemIsVisible(this.getItemAtIndex(aIndex));
},
/**
* If supported by the widget, the label string temporarily added to this
* container when there are no child items present.
*/
set emptyText(aValue) {
this._emptyText = aValue;
this._widget.setAttribute("emptyText", aValue);
},
/**
* If supported by the widget, the label string permanently added to this
* container as a header.
* @param string aValue
*/
set headerText(aValue) {
this._headerText = aValue;
this._widget.setAttribute("headerText", aValue);
},
/**
* Toggles all the items in this container hidden or visible.
@ -810,7 +817,7 @@ this.WidgetMethods = {
* @param function aPredicate [optional]
* Items are sorted according to the return value of the function,
* which will become the new default sorting predicate in this container.
* If unspecified, all items will be sorted by their label.
* If unspecified, all items will be sorted by their value.
*/
sortContents: function(aPredicate = this._currentSortPredicate) {
let sortedItems = this.items.sort(this._currentSortPredicate = aPredicate);
@ -832,8 +839,8 @@ this.WidgetMethods = {
if (aFirst == aSecond) { // We're just dandy, thank you.
return;
}
let { _prebuiltTarget: firstPrebuiltTarget, target: firstTarget } = aFirst;
let { _prebuiltTarget: secondPrebuiltTarget, target: secondTarget } = aSecond;
let { _prebuiltNode: firstPrebuiltTarget, _target: firstTarget } = aFirst;
let { _prebuiltNode: secondPrebuiltTarget, _target: secondTarget } = aSecond;
// If the two items were constructed with prebuilt nodes as DocumentFragments,
// then those DocumentFragments are now empty and need to be reassembled.
@ -891,20 +898,6 @@ this.WidgetMethods = {
this.swapItems(this.getItemAtIndex(aFirst), this.getItemAtIndex(aSecond));
},
/**
* Checks whether an item with the specified label is among the elements
* shown in this container.
*
* @param string aLabel
* The item's label.
* @return boolean
* True if the label is known, false otherwise.
*/
containsLabel: function(aLabel) {
return this._itemsByLabel.has(aLabel) ||
this._stagedItems.some(({ item }) => item._label == aLabel);
},
/**
* Checks whether an item with the specified value is among the elements
* shown in this container.
@ -924,11 +917,13 @@ this.WidgetMethods = {
* remembered just before emptying this container.
* @return string
*/
get preferredValue() this._preferredValue,
get preferredValue() {
return this._preferredValue;
},
/**
* Retrieves the item associated with the selected element.
* @return Item
* @return Item | null
*/
get selectedItem() {
let selectedElement = this._widget.selectedItem;
@ -950,18 +945,6 @@ this.WidgetMethods = {
return -1;
},
/**
* Retrieves the label of the selected element.
* @return string
*/
get selectedLabel() {
let selectedElement = this._widget.selectedItem;
if (selectedElement) {
return this._itemsByElement.get(selectedElement)._label;
}
return "";
},
/**
* Retrieves the value of the selected element.
* @return string
@ -976,7 +959,7 @@ this.WidgetMethods = {
/**
* Retrieves the attachment of the selected element.
* @return string
* @return object | null
*/
get selectedAttachment() {
let selectedElement = this._widget.selectedItem;
@ -1001,10 +984,15 @@ this.WidgetMethods = {
let targetElement = aItem ? aItem._target : null;
let prevElement = this._widget.selectedItem;
// Make sure the currently selected item's target element is also focused.
// Make sure the selected item's target element is focused and visible.
if (this.autoFocusOnSelection && targetElement) {
targetElement.focus();
}
if (this.maintainSelectionVisible && targetElement) {
if ("ensureElementIsVisible" in this._widget) {
this._widget.ensureElementIsVisible(targetElement);
}
}
// Prevent selecting the same item again and avoid dispatching
// a redundant selection event, so return early.
@ -1014,10 +1002,6 @@ this.WidgetMethods = {
let dispName = this.suppressSelectionEvents ? "suppressed-select" : "select";
ViewHelpers.dispatchEvent(dispTarget, dispName, aItem);
}
// Updates this container to reflect the information provided by the
// currently selected item.
this.refresh();
},
/**
@ -1033,19 +1017,19 @@ this.WidgetMethods = {
this.selectedItem = null;
},
/**
* Selects the element with the specified label in this container.
* @param string aLabel
*/
set selectedLabel(aLabel)
this.selectedItem = this._itemsByLabel.get(aLabel),
/**
* Selects the element with the specified value in this container.
* @param string aValue
*/
set selectedValue(aValue)
this.selectedItem = this._itemsByValue.get(aValue),
set selectedValue(aValue) {
this.selectedItem = this._itemsByValue.get(aValue);
},
/**
* Specifies if this container should try to keep the selected item visible.
* (For example, when new items are added the selection is brought into view).
*/
maintainSelectionVisible: true,
/**
* Specifies if "select" events dispatched from the elements in this container
@ -1232,18 +1216,6 @@ this.WidgetMethods = {
return this.getItemForElement(this._widget.getItemAtIndex(aIndex));
},
/**
* Gets the item in the container having the specified label.
*
* @param string aLabel
* The label used to identify the element.
* @return Item
* The matched item, or null if nothing is found.
*/
getItemByLabel: function(aLabel) {
return this._itemsByLabel.get(aLabel);
},
/**
* Gets the item in the container having the specified value.
*
@ -1358,7 +1330,9 @@ this.WidgetMethods = {
* Gets the total number of items in this container.
* @return number
*/
get itemCount() this._itemsByElement.size,
get itemCount() {
return this._itemsByElement.size;
},
/**
* Returns a list of items in this container, in the displayed order.
@ -1373,14 +1347,6 @@ this.WidgetMethods = {
return store;
},
/**
* Returns a list of labels in this container, in the displayed order.
* @return array
*/
get labels() {
return this.items.map(e => e._label);
},
/**
* Returns a list of values in this container, in the displayed order.
* @return array
@ -1407,17 +1373,8 @@ this.WidgetMethods = {
},
/**
* Specifies the required conditions for an item to be considered unique.
* Possible values:
* - 1: label AND value are different from all other items
* - 2: label OR value are different from all other items
* - 3: only label is required to be different
* - 4: only value is required to be different
*/
uniquenessQualifier: 1,
/**
* Checks if an item is unique in this container.
* Checks if an item is unique in this container. If an item's value is an
* empty string, "undefined" or "null", it is considered unique.
*
* @param Item aItem
* The item for which to verify uniqueness.
@ -1425,23 +1382,16 @@ this.WidgetMethods = {
* True if the item is unique, false otherwise.
*/
isUnique: function(aItem) {
switch (this.uniquenessQualifier) {
case 1:
return !this._itemsByLabel.has(aItem._label) &&
!this._itemsByValue.has(aItem._value);
case 2:
return !this._itemsByLabel.has(aItem._label) ||
!this._itemsByValue.has(aItem._value);
case 3:
return !this._itemsByLabel.has(aItem._label);
case 4:
return !this._itemsByValue.has(aItem._value);
let value = aItem._value;
if (value == "" || value == "undefined" || value == "null") {
return true;
}
return false;
return !this._itemsByValue.has(value);
},
/**
* Checks if an item is eligible for this container.
* Checks if an item is eligible for this container. By default, this checks
* whether an item is unique and has a prebuilt target node.
*
* @param Item aItem
* The item for which to verify eligibility.
@ -1449,12 +1399,7 @@ this.WidgetMethods = {
* True if the item is eligible, false otherwise.
*/
isEligible: function(aItem) {
let isUnique = this.isUnique(aItem);
let isPrebuilt = !!aItem._prebuiltTarget;
let isDegenerate = aItem._label == "undefined" || aItem._label == "null" ||
aItem._value == "undefined" || aItem._value == "null";
return isPrebuilt || (isUnique && !isDegenerate);
return this.isUnique(aItem) && aItem._prebuiltNode;
},
/**
@ -1468,7 +1413,6 @@ this.WidgetMethods = {
*/
_findExpectedIndexFor: function(aItem) {
let itemCount = this.itemCount;
for (let i = 0; i < itemCount; i++) {
if (this._currentSortPredicate(this.getItemAtIndex(i), aItem) > 0) {
return i;
@ -1483,28 +1427,25 @@ this.WidgetMethods = {
* @param number aIndex
* The position in the container intended for this item.
* @param Item aItem
* An object containing a label and a value property (at least).
* The item describing a target element.
* @param object aOptions [optional]
* Additional options or flags supported by this operation:
* - node: allows the insertion of prebuilt nodes instead of labels
* - relaxed: true if this container should allow dupes & degenerates
* - attributes: a batch of attributes set to the displayed element
* - finalize: function when the item is untangled (removed)
* @return Item
* The item associated with the displayed element, null if rejected.
*/
_insertItemAt: function(aIndex, aItem, aOptions = {}) {
// Relaxed nodes may be appended without verifying their eligibility.
if (!aOptions.relaxed && !this.isEligible(aItem)) {
if (!this.isEligible(aItem)) {
return null;
}
// Entangle the item with the newly inserted node.
this._entangleItem(aItem, this._widget.insertItemAt(aIndex,
aItem._prebuiltTarget || aItem._label, // Allow the insertion of prebuilt nodes.
aItem._value,
aItem._description,
aItem.attachment));
// Make sure this is done with the value returned by insertItemAt(),
// to avoid storing a potential DocumentFragment.
let node = aItem._prebuiltNode;
let attachment = aItem.attachment;
this._entangleItem(aItem, this._widget.insertItemAt(aIndex, node, attachment));
// Handle any additional options after entangling the item.
if (!this._currentFilterPredicate(aItem)) {
@ -1520,6 +1461,9 @@ this.WidgetMethods = {
aItem.finalize = aOptions.finalize;
}
// Hide the empty text if the selection wasn't lost.
this._widget.removeAttribute("emptyText");
// Return the item associated with the displayed element.
return aItem;
},
@ -1533,7 +1477,6 @@ this.WidgetMethods = {
* The element displaying the item.
*/
_entangleItem: function(aItem, aElement) {
this._itemsByLabel.set(aItem._label, aItem);
this._itemsByValue.set(aItem._value, aItem);
this._itemsByElement.set(aElement, aItem);
aItem._target = aElement;
@ -1554,7 +1497,6 @@ this.WidgetMethods = {
}
this._unlinkItem(aItem);
aItem._prebuiltTarget = null;
aItem._target = null;
},
@ -1565,7 +1507,6 @@ this.WidgetMethods = {
* The item describing a target element.
*/
_unlinkItem: function(aItem) {
this._itemsByLabel.delete(aItem._label);
this._itemsByValue.delete(aItem._value);
this._itemsByElement.delete(aItem._target);
},
@ -1650,7 +1591,7 @@ this.WidgetMethods = {
* 1 to sort aSecond to a lower index than aFirst
*/
_currentSortPredicate: function(aFirst, aSecond) {
return +(aFirst._label.toLowerCase() > aSecond._label.toLowerCase());
return +(aFirst._value.toLowerCase() > aSecond._value.toLowerCase());
},
/**
@ -1667,7 +1608,9 @@ this.WidgetMethods = {
},
_widget: null,
_preferredValue: null,
_emptyText: "",
_headerText: "",
_preferredValue: "",
_cachedCommandDispatcher: null
};

View File

@ -13,6 +13,13 @@
-moz-user-focus: normal;
}
/* SimpleListWidget */
.simple-list-widget-container {
overflow-x: hidden;
overflow-y: auto;
}
/* SideMenuWidget */
.side-menu-widget-container {

View File

@ -25,6 +25,14 @@ var Appbar = {
// tilegroup selection events for all modules get bubbled up
window.addEventListener("selectionchange", this, false);
// gather appbar telemetry data
try {
UITelemetry.addSimpleMeasureFunction("metro-appbar",
this.getAppbarMeasures.bind(this));
} catch (ex) {
// swallow exception that occurs if metro-appbar measure is already set up
}
},
handleEvent: function Appbar_handleEvent(aEvent) {
@ -149,6 +157,7 @@ var Appbar = {
getService(Components.interfaces.nsIAppStartup);
Services.prefs.setBoolPref('browser.sessionstore.resume_session_once', true);
this._incrementCountableEvent("switch-to-desktop-button");
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit |
Components.interfaces.nsIAppStartup.eRestart);
},
@ -273,6 +282,22 @@ var Appbar = {
}
},
// track certain appbar events and interactions for the UITelemetry probe
_countableEvents: {},
_incrementCountableEvent: function(aName) {
if (!(aName in this._countableEvents)) {
this._countableEvents[aName] = 0;
}
this._countableEvents[aName]++;
},
getAppbarMeasures: function() {
return {
countableEvents: this._countableEvents
};
},
_updatePinButton: function() {
this.pinButton.checked = Browser.isSitePinned();
},
@ -282,4 +307,5 @@ var Appbar = {
this.starButton.checked = isStarred;
}.bind(this));
},
};

View File

@ -54,6 +54,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UITelemetry",
"resource://gre/modules/UITelemetry.jsm");
/*
* Services
*/

View File

@ -361,6 +361,10 @@ this.BrowserUITelemetry = {
let document = aWindow.document;
let result = {};
// Determine if the window is in the maximized, normal or
// fullscreen state.
result.sizemode = document.documentElement.getAttribute("sizemode");
// Determine if the Bookmarks bar is currently visible
let bookmarksBar = document.getElementById("PersonalToolbar");
result.bookmarksBarEnabled = bookmarksBar && !bookmarksBar.collapsed;

View File

@ -22,6 +22,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
const UITOUR_PERMISSION = "uitour";
const PREF_PERM_BRANCH = "browser.uitour.";
const MAX_BUTTONS = 4;
this.UITour = {
@ -125,7 +126,34 @@ this.UITour = {
Cu.reportError("UITour: Target could not be resolved: " + data.target);
return;
}
this.showInfo(target, data.title, data.text);
let iconURL = null;
if (typeof data.icon == "string")
iconURL = this.resolveURL(contentDocument, data.icon);
let buttons = [];
if (Array.isArray(data.buttons) && data.buttons.length > 0) {
for (let buttonData of data.buttons) {
if (typeof buttonData == "object" &&
typeof buttonData.label == "string" &&
typeof buttonData.callbackID == "string") {
let button = {
label: buttonData.label,
callbackID: buttonData.callbackID,
};
if (typeof buttonData.icon == "string")
button.iconURL = this.resolveURL(contentDocument, buttonData.icon);
buttons.push(button);
if (buttons.length == MAX_BUTTONS)
break;
}
}
}
this.showInfo(contentDocument, target, data.title, data.text, iconURL, buttons);
}).then(null, Cu.reportError);
break;
}
@ -303,11 +331,7 @@ this.UITour = {
if (uri.schemeIs("chrome"))
return true;
let allowedSchemes = new Set(["https"]);
if (!Services.prefs.getBoolPref("browser.uitour.requireSecure"))
allowedSchemes.add("http");
if (!allowedSchemes.has(uri.scheme))
if (!this.isSafeScheme(uri))
return false;
this.importPermissions();
@ -315,6 +339,50 @@ this.UITour = {
return permission == Services.perms.ALLOW_ACTION;
},
isSafeScheme: function(aURI) {
let allowedSchemes = new Set(["https"]);
if (!Services.prefs.getBoolPref("browser.uitour.requireSecure"))
allowedSchemes.add("http");
if (!allowedSchemes.has(aURI.scheme))
return false;
return true;
},
resolveURL: function(aDocument, aURL) {
try {
let uri = Services.io.newURI(aURL, null, aDocument.documentURIObject);
if (!this.isSafeScheme(uri))
return null;
return uri.spec;
} catch (e) {}
return null;
},
sendPageCallback: function(aDocument, aCallbackID, aData = {}) {
let detail = Cu.createObjectIn(aDocument.defaultView);
detail.data = Cu.createObjectIn(detail);
for (let key of Object.keys(aData))
detail.data[key] = aData[key];
Cu.makeObjectPropsNormal(detail.data);
Cu.makeObjectPropsNormal(detail);
detail.callbackID = aCallbackID;
let event = new aDocument.defaultView.CustomEvent("mozUITourResponse", {
bubbles: true,
detail: detail
});
aDocument.dispatchEvent(event);
},
getTarget: function(aWindow, aTargetName, aSticky = false) {
let deferred = Promise.defer();
if (typeof aTargetName != "string" || !aTargetName) {
@ -506,7 +574,7 @@ this.UITour = {
this._setAppMenuStateForAnnotation(aWindow, "highlight", false);
},
showInfo: function(aAnchor, aTitle, aDescription) {
showInfo: function(aContentDocument, aAnchor, aTitle = "", aDescription = "", aIconURL = "", aButtons = []) {
function showInfoPanel(aAnchorEl) {
aAnchorEl.focus();
@ -514,13 +582,37 @@ this.UITour = {
let tooltip = document.getElementById("UITourTooltip");
let tooltipTitle = document.getElementById("UITourTooltipTitle");
let tooltipDesc = document.getElementById("UITourTooltipDescription");
let tooltipIcon = document.getElementById("UITourTooltipIcon");
let tooltipButtons = document.getElementById("UITourTooltipButtons");
if (tooltip.state == "open") {
tooltip.hidePopup();
}
tooltipTitle.textContent = aTitle;
tooltipDesc.textContent = aDescription;
tooltipTitle.textContent = aTitle || "";
tooltipDesc.textContent = aDescription || "";
tooltipIcon.src = aIconURL || "";
tooltipIcon.hidden = !aIconURL;
while (tooltipButtons.firstChild)
tooltipButtons.firstChild.remove();
for (let button of aButtons) {
let el = document.createElement("button");
el.setAttribute("label", button.label);
if (button.iconURL)
el.setAttribute("image", button.iconURL);
let callbackID = button.callbackID;
el.addEventListener("command", event => {
tooltip.hidePopup();
this.sendPageCallback(aContentDocument, callbackID);
});
tooltipButtons.appendChild(el);
}
tooltipButtons.hidden = !aButtons.length;
tooltip.hidden = false;
let alignment = "bottomcenter topright";
@ -533,9 +625,15 @@ this.UITour = {
},
hideInfo: function(aWindow) {
let tooltip = aWindow.document.getElementById("UITourTooltip");
let document = aWindow.document;
let tooltip = document.getElementById("UITourTooltip");
tooltip.hidePopup();
this._setAppMenuStateForAnnotation(aWindow, "info", false);
let tooltipButtons = document.getElementById("UITourTooltipButtons");
while (tooltipButtons.firstChild)
tooltipButtons.firstChild.remove();
},
showMenu: function(aWindow, aMenuName, aOpenCallback = null) {

View File

@ -5,6 +5,6 @@ support-files =
[browser_NetworkPrioritizer.js]
[browser_SignInToWebsite.js]
[browser_UITour.js]
support-files = uitour.*
support-files = uitour.* image.png
[browser_taskbar_preview.js]
run-if = os == "win"

View File

@ -4,6 +4,7 @@
"use strict";
let gTestTab;
let gContentWindow;
let gContentAPI;
Components.utils.import("resource:///modules/UITour.jsm");
@ -66,10 +67,10 @@ function loadTestPage(callback, host = "https://example.com/") {
gTestTab.linkedBrowser.addEventListener("load", function onLoad() {
gTestTab.linkedBrowser.removeEventListener("load", onLoad);
let contentWindow = Components.utils.waiveXrays(gTestTab.linkedBrowser.contentDocument.defaultView);
gContentAPI = contentWindow.Mozilla.UITour;
gContentWindow = Components.utils.waiveXrays(gTestTab.linkedBrowser.contentDocument.defaultView);
gContentAPI = gContentWindow.Mozilla.UITour;
waitForFocus(callback, contentWindow);
waitForFocus(callback, gContentWindow);
}, true);
}
@ -82,6 +83,7 @@ function test() {
registerCleanupFunction(function() {
delete window.UITour;
delete window.gContentWindow;
delete window.gContentAPI;
if (gTestTab)
gBrowser.removeTab(gTestTab);
@ -285,11 +287,16 @@ let tests = [
let popup = document.getElementById("UITourTooltip");
let title = document.getElementById("UITourTooltipTitle");
let desc = document.getElementById("UITourTooltipDescription");
let icon = document.getElementById("UITourTooltipIcon");
let buttons = document.getElementById("UITourTooltipButtons");
popup.addEventListener("popupshown", function onPopupShown() {
popup.removeEventListener("popupshown", onPopupShown);
is(popup.popupBoxObject.anchorNode, document.getElementById("urlbar"), "Popup should be anchored to the urlbar");
is(title.textContent, "test title", "Popup should have correct title");
is(desc.textContent, "test text", "Popup should have correct description text");
is(icon.src, "", "Popup should have no icon");
is(buttons.hasChildNodes(), false, "Popup should have no buttons");
popup.addEventListener("popuphidden", function onPopupHidden() {
popup.removeEventListener("popuphidden", onPopupHidden);
@ -311,11 +318,16 @@ let tests = [
let popup = document.getElementById("UITourTooltip");
let title = document.getElementById("UITourTooltipTitle");
let desc = document.getElementById("UITourTooltipDescription");
let icon = document.getElementById("UITourTooltipIcon");
let buttons = document.getElementById("UITourTooltipButtons");
popup.addEventListener("popupshown", function onPopupShown() {
popup.removeEventListener("popupshown", onPopupShown);
is(popup.popupBoxObject.anchorNode, document.getElementById("urlbar"), "Popup should be anchored to the urlbar");
is(title.textContent, "urlbar title", "Popup should have correct title");
is(desc.textContent, "urlbar text", "Popup should have correct description text");
is(icon.src, "", "Popup should have no icon");
is(buttons.hasChildNodes(), false, "Popup should have no buttons");
gContentAPI.showInfo("search", "search title", "search text");
executeSoon(function() {
@ -377,6 +389,114 @@ let tests = [
}, "Info should be shown after showInfo() for fixed menu panel items");
});
},
function test_info_icon(done) {
let popup = document.getElementById("UITourTooltip");
let title = document.getElementById("UITourTooltipTitle");
let desc = document.getElementById("UITourTooltipDescription");
let icon = document.getElementById("UITourTooltipIcon");
let buttons = document.getElementById("UITourTooltipButtons");
popup.addEventListener("popupshown", function onPopupShown() {
popup.removeEventListener("popupshown", onPopupShown);
is(title.textContent, "a title", "Popup should have correct title");
is(desc.textContent, "some text", "Popup should have correct description text");
let imageURL = getRootDirectory(gTestPath) + "image.png";
imageURL = imageURL.replace("chrome://mochitests/content/", "https://example.com/");
is(icon.src, imageURL, "Popup should have correct icon shown");
is(buttons.hasChildNodes(), false, "Popup should have no buttons");
done();
});
gContentAPI.showInfo("urlbar", "a title", "some text", "image.png");
},
function test_info_buttons_1(done) {
let popup = document.getElementById("UITourTooltip");
let title = document.getElementById("UITourTooltipTitle");
let desc = document.getElementById("UITourTooltipDescription");
let icon = document.getElementById("UITourTooltipIcon");
popup.addEventListener("popupshown", function onPopupShown() {
popup.removeEventListener("popupshown", onPopupShown);
is(title.textContent, "another title", "Popup should have correct title");
is(desc.textContent, "moar text", "Popup should have correct description text");
let imageURL = getRootDirectory(gTestPath) + "image.png";
imageURL = imageURL.replace("chrome://mochitests/content/", "https://example.com/");
is(icon.src, imageURL, "Popup should have correct icon shown");
let buttons = document.getElementById("UITourTooltipButtons");
is(buttons.childElementCount, 2, "Popup should have two buttons");
is(buttons.childNodes[0].getAttribute("label"), "Button 1", "First button should have correct label");
is(buttons.childNodes[0].getAttribute("image"), "", "First button should have no image");
is(buttons.childNodes[1].getAttribute("label"), "Button 2", "Second button should have correct label");
is(buttons.childNodes[1].getAttribute("image"), imageURL, "Second button should have correct image");
popup.addEventListener("popuphidden", function onPopupHidden() {
popup.removeEventListener("popuphidden", onPopupHidden);
ok(true, "Popup should close automatically");
executeSoon(function() {
is(gContentWindow.callbackResult, "button1", "Correct callback should have been called");
done();
});
});
EventUtils.synthesizeMouseAtCenter(buttons.childNodes[0], {}, window);
});
let buttons = gContentWindow.makeButtons();
gContentAPI.showInfo("urlbar", "another title", "moar text", "./image.png", buttons);
},
function test_info_buttons_2(done) {
let popup = document.getElementById("UITourTooltip");
let title = document.getElementById("UITourTooltipTitle");
let desc = document.getElementById("UITourTooltipDescription");
let icon = document.getElementById("UITourTooltipIcon");
popup.addEventListener("popupshown", function onPopupShown() {
popup.removeEventListener("popupshown", onPopupShown);
is(title.textContent, "another title", "Popup should have correct title");
is(desc.textContent, "moar text", "Popup should have correct description text");
let imageURL = getRootDirectory(gTestPath) + "image.png";
imageURL = imageURL.replace("chrome://mochitests/content/", "https://example.com/");
is(icon.src, imageURL, "Popup should have correct icon shown");
let buttons = document.getElementById("UITourTooltipButtons");
is(buttons.childElementCount, 2, "Popup should have two buttons");
is(buttons.childNodes[0].getAttribute("label"), "Button 1", "First button should have correct label");
is(buttons.childNodes[0].getAttribute("image"), "", "First button should have no image");
is(buttons.childNodes[1].getAttribute("label"), "Button 2", "Second button should have correct label");
is(buttons.childNodes[1].getAttribute("image"), imageURL, "Second button should have correct image");
popup.addEventListener("popuphidden", function onPopupHidden() {
popup.removeEventListener("popuphidden", onPopupHidden);
ok(true, "Popup should close automatically");
executeSoon(function() {
is(gContentWindow.callbackResult, "button2", "Correct callback should have been called");
done();
});
});
EventUtils.synthesizeMouseAtCenter(buttons.childNodes[1], {}, window);
});
let buttons = gContentWindow.makeButtons();
gContentAPI.showInfo("urlbar", "another title", "moar text", "./image.png", buttons);
},
function test_pinnedTab(done) {
is(UITour.pinnedTabs.get(window), null, "Should not already have a pinned tab");

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View File

@ -5,6 +5,22 @@
<title>UITour test</title>
<script type="application/javascript" src="uitour.js">
</script>
<script type="application/javascript">
var callbackResult;
function makeCallback(name) {
return (function() {
callbackResult = name;
});
}
// Defined in content to avoid weird issues when crossing between chrome/content.
function makeButtons() {
return [
{label: "Button 1", callback: makeCallback("button1")},
{label: "Button 2", callback: makeCallback("button2"), icon: "image.png"}
];
}
</script>
</head>
<body>
<h1>UITour tests</h1>

View File

@ -25,7 +25,6 @@ if (typeof Mozilla == 'undefined') {
}
}
function _sendEvent(action, data) {
var event = new CustomEvent('mozUITour', {
bubbles: true,
@ -34,10 +33,31 @@ if (typeof Mozilla == 'undefined') {
data: data || {}
}
});
console.log("Sending mozUITour event: ", event);
document.dispatchEvent(event);
}
function _generateCallbackID() {
return Math.random().toString(36).replace(/[^a-z]+/g, '');
}
function _waitForCallback(callback) {
var id = _generateCallbackID();
function listener(event) {
if (typeof event.detail != "object")
return;
if (event.detail.callbackID != id)
return;
document.removeEventListener("mozUITourResponse", listener);
callback(event.detail.data);
}
document.addEventListener("mozUITourResponse", listener);
return id;
}
Mozilla.UITour.DEFAULT_THEME_CYCLE_DELAY = 10 * 1000;
Mozilla.UITour.showHighlight = function(target, effect) {
@ -51,11 +71,24 @@ if (typeof Mozilla == 'undefined') {
_sendEvent('hideHighlight');
};
Mozilla.UITour.showInfo = function(target, title, text) {
Mozilla.UITour.showInfo = function(target, title, text, icon, buttons) {
var buttonData = [];
if (Array.isArray(buttons)) {
for (var i = 0; i < buttons.length; i++) {
buttonData.push({
label: buttons[i].label,
icon: buttons[i].icon,
callbackID: _waitForCallback(buttons[i].callback)
});
}
}
_sendEvent('showInfo', {
target: target,
title: title,
text: text
text: text,
icon: icon,
buttons: buttonData
});
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 584 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -204,39 +204,6 @@
color: #8fa1b2; /* Content text grey */
}
/* ListWidget items */
.list-widget-item {
padding: 2px;
}
.theme-light .list-widget-item:not(.selected):not(.empty):hover {
background: linear-gradient(rgba(255,255,255,0.9), rgba(255,255,255,0.85)), Highlight;
}
.theme-light .list-widget-item.selected.light {
background: linear-gradient(rgba(255,255,255,0.85), rgba(255,255,255,0.8)), Highlight;
color: #000;
}
.theme-dark .list-widget-item:not(.selected):not(.empty):hover {
background: linear-gradient(rgba(255,255,255,0.1), rgba(255,255,255,0.05));
}
.theme-dark .list-widget-item.selected.light {
background: linear-gradient(rgba(255,255,255,0.05), rgba(255,255,255,0.025));
}
.list-widget-item.selected {
background: Highlight;
color: HighlightText;
}
.list-widget-item.empty {
color: GrayText;
padding: 2px;
}
/* Breadcrumbs stack frames view */
.breadcrumbs-widget-item {
@ -251,7 +218,7 @@
.dbg-classic-stackframe {
display: block;
padding: 4px;
padding: 0px 4px;
}
.dbg-classic-stackframe-title {
@ -338,7 +305,7 @@
/* Instruments pane (watch expressions, variables, event listeners...) */
#instruments-pane .side-menu-widget-container,
#instruments-pane .side-menu-widget-empty-notice-container {
#instruments-pane .side-menu-widget-empty-text {
box-shadow: none !important;
}
@ -356,18 +323,18 @@
.dbg-expression-arrow {
width: 16px;
height: auto;
margin: 2px;
background: -moz-image-rect(url(commandline-icon.png), 0, 32, 16, 16);
}
.dbg-expression-input {
-moz-padding-start: 2px !important;
color: inherit;
}
/* Event listeners view */
.dbg-event-listener {
padding: 4px 8px;
padding: 0px 8px;
}
.dbg-event-listener-type {
@ -424,7 +391,6 @@
.results-panel {
padding: 4px;
opacity: 0.9;
}
.results-panel-item {
@ -452,19 +418,19 @@
text-shadow: 0 1px #fff;
}
.results-panel-item-pre {
.results-panel-item-label-before {
-moz-margin-end: 5px !important;
color: #444;
cursor: inherit;
}
.results-panel-item-name {
.results-panel-item-label {
color: #111;
font-weight: 600;
cursor: inherit;
}
.results-panel-item-details {
.results-panel-item-label-below {
color: #7f7f7f;
cursor: inherit;
}
@ -473,15 +439,11 @@
#globalsearch {
min-height: 10px;
max-height: 125px;
box-shadow: inset 0 -4px 8px #eee;
background: url(background-noise-toolbar.png);
}
#globalsearch > vbox:not(:empty) {
min-height: 10px;
max-height: 125px;
}
#globalsearch + .devtools-horizontal-splitter {
border-color: #bfbfbf;
}
@ -646,7 +608,7 @@
}
#body[layout=vertical] .side-menu-widget-container,
#body[layout=vertical] .side-menu-widget-empty-notice-container {
#body[layout=vertical] .side-menu-widget-empty-text {
box-shadow: none !important;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -45,7 +45,7 @@
-moz-appearance: none;
background: none;
min-width: 20px;
min-height: 31px; /* Remaining 1px comes from border of the toolbar. */
min-height: 32px;
margin: 0;
border: none;
padding: 0;
@ -312,6 +312,10 @@ box.requests-menu-status[code^="5"] {
/* SideMenuWidget */
.side-menu-widget-item-contents {
padding: 0px;
}
.side-menu-widget-container {
box-shadow: none !important;
}
@ -496,7 +500,7 @@ box.requests-menu-status[code^="5"] {
}
.requests-menu-header-button {
min-height: 25px; /* Remaining 1px comes from border of the toolbar. */
min-height: 26px;
font-size: 85%;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 380 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -266,6 +266,23 @@
border-left-width: 0;
}
/* SimpleListWidget */
.simple-list-widget-item:not(.selected):hover {
background: linear-gradient(rgba(255,255,255,0.9), rgba(255,255,255,0.85)), Highlight;
}
.simple-list-widget-item.selected {
background: linear-gradient(rgba(255,255,255,0.85), rgba(255,255,255,0.8)), Highlight;
color: #000;
}
.simple-list-widget-perma-text,
.simple-list-widget-empty-text {
color: GrayText;
padding: 4px 8px;
}
/* SideMenuWidget */
.side-menu-widget-container {
@ -286,12 +303,12 @@
/* SideMenuWidget container */
.side-menu-widget-container:-moz-locale-dir(ltr),
.side-menu-widget-empty-notice-container:-moz-locale-dir(ltr) {
.side-menu-widget-empty-text:-moz-locale-dir(ltr) {
box-shadow: inset -1px 0 0 #222426;
}
.side-menu-widget-container:-moz-locale-dir(rtl),
.side-menu-widget-empty-notice-container:-moz-locale-dir(rtl) {
.side-menu-widget-empty-text:-moz-locale-dir(rtl) {
box-shadow: inset 1px 0 0 #222426;
}
@ -369,7 +386,7 @@
/* SideMenuWidget items contents */
.side-menu-widget-item-label {
.side-menu-widget-item-contents {
padding: 4px 0px;
}
@ -389,9 +406,14 @@
}
.side-menu-widget-item-other:first-of-type {
margin-bottom: 4px;
border-top-left-radius: 4px;
}
.side-menu-widget-item-other:last-of-type {
margin-bottom: -4px;
}
.side-menu-widget-item-other > label {
color: #f5f7fa;
text-shadow: 0 1px 1px #111;
@ -418,17 +440,14 @@
/* SideMenuWidget misc */
.side-menu-widget-empty-notice-container {
padding: 12px;
}
.side-menu-widget-empty-notice-container[theme="dark"] {
.side-menu-widget-empty-text[theme="dark"] {
background: url(background-noise-toolbar.png), hsl(208,11%,27%);
padding: 12px;
font-weight: 600;
color: #fff;
}
.side-menu-widget-empty-notice-container[theme="light"] {
.side-menu-widget-empty-text[theme="light"] {
background: #fff;
padding: 4px 8px;
color: GrayText;

View File

@ -153,11 +153,11 @@ browser.jar:
skin/classic/browser/devtools/controls.png (../shared/devtools/controls.png)
* skin/classic/browser/devtools/widgets.css (devtools/widgets.css)
skin/classic/browser/devtools/commandline-icon.png (devtools/commandline-icon.png)
skin/classic/browser/devtools/command-paintflashing.png (devtools/command-paintflashing.png)
skin/classic/browser/devtools/command-responsivemode.png (devtools/command-responsivemode.png)
skin/classic/browser/devtools/command-scratchpad.png (devtools/command-scratchpad.png)
skin/classic/browser/devtools/command-tilt.png (devtools/command-tilt.png)
skin/classic/browser/devtools/command-console.png (devtools/command-console.png)
skin/classic/browser/devtools/command-paintflashing@2x.png (../shared/devtools/images/command-paintflashing@2x.png)
skin/classic/browser/devtools/command-responsivemode@2x.png (../shared/devtools/images/command-responsivemode@2x.png)
skin/classic/browser/devtools/command-scratchpad@2x.png (../shared/devtools/images/command-scratchpad@2x.png)
skin/classic/browser/devtools/command-tilt@2x.png (../shared/devtools/images/command-tilt@2x.png)
skin/classic/browser/devtools/command-console@2x.png (../shared/devtools/images/command-console@2x.png)
skin/classic/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
skin/classic/browser/devtools/ruleview.css (devtools/ruleview.css)
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
@ -228,25 +228,26 @@ browser.jar:
skin/classic/browser/devtools/responsive-horizontal-resizer.png (devtools/responsive-horizontal-resizer.png)
skin/classic/browser/devtools/responsive-background.png (devtools/responsive-background.png)
skin/classic/browser/devtools/toggle-tools.png (devtools/toggle-tools.png)
skin/classic/browser/devtools/dock-bottom.png (devtools/dock-bottom.png)
skin/classic/browser/devtools/dock-side.png (devtools/dock-side.png)
skin/classic/browser/devtools/dock-bottom@2x.png (../shared/devtools/images/dock-bottom@2x.png)
skin/classic/browser/devtools/dock-side@2x.png (../shared/devtools/images/dock-side@2x.png)
skin/classic/browser/devtools/floating-scrollbars.css (devtools/floating-scrollbars.css)
skin/classic/browser/devtools/floating-scrollbars-light.css (devtools/floating-scrollbars-light.css)
skin/classic/browser/devtools/inspector.css (devtools/inspector.css)
skin/classic/browser/devtools/profiler-stopwatch.png (devtools/profiler-stopwatch.png)
skin/classic/browser/devtools/tool-options.png (devtools/tool-options.png)
skin/classic/browser/devtools/tool-webconsole.png (devtools/tool-webconsole.png)
skin/classic/browser/devtools/tool-debugger.png (devtools/tool-debugger.png)
skin/classic/browser/devtools/tool-debugger-paused.png (devtools/tool-debugger-paused.png)
skin/classic/browser/devtools/tool-inspector.png (devtools/tool-inspector.png)
skin/classic/browser/devtools/tool-styleeditor.png (devtools/tool-styleeditor.png)
skin/classic/browser/devtools/tool-profiler.png (devtools/tool-profiler.png)
skin/classic/browser/devtools/tool-network.png (devtools/tool-network.png)
skin/classic/browser/devtools/tool-scratchpad.png (devtools/tool-scratchpad.png)
skin/classic/browser/devtools/close.png (devtools/close.png)
skin/classic/browser/devtools/tool-options@2x.png (../shared/devtools/images/tool-options@2x.png)
skin/classic/browser/devtools/tool-webconsole@2x.png (../shared/devtools/images/tool-webconsole@2x.png)
skin/classic/browser/devtools/tool-debugger@2x.png (../shared/devtools/images/tool-debugger@2x.png)
skin/classic/browser/devtools/tool-debugger-paused@2x.png (../shared/devtools/images/tool-debugger-paused@2x.png)
skin/classic/browser/devtools/tool-inspector@2x.png (../shared/devtools/images/tool-inspector@2x.png)
skin/classic/browser/devtools/tool-styleeditor@2x.png (../shared/devtools/images/tool-styleeditor@2x.png)
skin/classic/browser/devtools/tool-profiler@2x.png (../shared/devtools/images/tool-profiler@2x.png)
skin/classic/browser/devtools/tool-network@2x.png (../shared/devtools/images/tool-network@2x.png)
skin/classic/browser/devtools/tool-scratchpad@2x.png (../shared/devtools/images/tool-scratchpad@2x.png)
skin/classic/browser/devtools/close.png (../shared/devtools/images/close.png)
skin/classic/browser/devtools/close@2x.png (../shared/devtools/images/close@2x.png)
skin/classic/browser/devtools/vview-delete.png (devtools/vview-delete.png)
skin/classic/browser/devtools/vview-edit.png (devtools/vview-edit.png)
skin/classic/browser/devtools/undock.png (devtools/undock.png)
skin/classic/browser/devtools/undock@2x.png (../shared/devtools/images/undock@2x.png)
skin/classic/browser/devtools/font-inspector.css (devtools/font-inspector.css)
skin/classic/browser/devtools/computedview.css (devtools/computedview.css)
skin/classic/browser/devtools/arrow-e.png (devtools/arrow-e.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 584 B

Some files were not shown because too many files have changed in this diff Show More