Merge latest green b2g-inbound changeset and mozilla-central
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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",
|
||||
|
@ -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"/>
|
||||
|
@ -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;
|
||||
|
@ -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")) {
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
});
|
@ -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++;
|
||||
|
@ -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",
|
||||
|
@ -9,7 +9,7 @@ EXTRA_COMPONENTS += [
|
||||
'PlacesProtocolHandler.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
EXTRA_PP_JS_MODULES += [
|
||||
'PlacesUIUtils.jsm',
|
||||
]
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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();
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -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);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
|
@ -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]
|
||||
|
@ -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.");
|
||||
}
|
||||
|
||||
|
@ -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).");
|
||||
|
@ -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;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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.");
|
||||
|
||||
|
@ -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.");
|
||||
|
||||
|
@ -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.");
|
||||
|
@ -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.");
|
||||
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.");
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.");
|
||||
});
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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.");
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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() {
|
||||
|
@ -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.");
|
||||
|
@ -162,6 +162,7 @@ registerCleanupFunction(function() {
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gEditor = null;
|
||||
gSources = null;
|
||||
gFrames = null;
|
||||
gClassicFrames = null;
|
||||
});
|
||||
|
@ -291,6 +291,8 @@ registerCleanupFunction(function() {
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gL10N = null;
|
||||
gEditor = null;
|
||||
gVars = null;
|
||||
gWatch = null;
|
||||
});
|
||||
|
@ -97,6 +97,8 @@ registerCleanupFunction(function() {
|
||||
gDebuggee = null;
|
||||
gPanel = null;
|
||||
gDebugger = null;
|
||||
gL10N = null;
|
||||
gEditor = null;
|
||||
gVars = null;
|
||||
gWatch = null;
|
||||
});
|
||||
|
@ -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.");
|
||||
|
@ -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,
|
||||
|
@ -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.");
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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 }
|
||||
})
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
253
browser/devtools/shared/widgets/SimpleListWidget.jsm
Normal 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: ""
|
||||
};
|
@ -2078,7 +2078,6 @@ Scope.prototype = {
|
||||
_enumItems: null,
|
||||
_nonEnumItems: null,
|
||||
_fetched: false,
|
||||
_retrieved: false,
|
||||
_committed: false,
|
||||
_isLocked: false,
|
||||
_isExpanded: false,
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -13,6 +13,13 @@
|
||||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
/* SimpleListWidget */
|
||||
|
||||
.simple-list-widget-container {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* SideMenuWidget */
|
||||
|
||||
.side-menu-widget-container {
|
||||
|
@ -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));
|
||||
},
|
||||
|
||||
};
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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"
|
||||
|
@ -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");
|
||||
|
||||
|
BIN
browser/modules/test/image.png
Normal file
After Width: | Height: | Size: 55 KiB |
@ -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>
|
||||
|
@ -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
|
||||
});
|
||||
};
|
||||
|
||||
|
Before Width: | Height: | Size: 961 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 584 B |
Before Width: | Height: | Size: 1.6 KiB |
@ -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;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB |
@ -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%;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 441 B |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 214 B |
Before Width: | Height: | Size: 380 B |
Before Width: | Height: | Size: 477 B |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB |
@ -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;
|
||||
|
@ -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)
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 961 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 584 B |