Bug 892229 - Ctrl+F / Cmd+F should search/filter requests. r=vporof

This commit is contained in:
Aaron Graham 2015-04-06 15:11:00 -04:00
parent 3fdedeb219
commit 0d2a06ebc0
5 changed files with 132 additions and 19 deletions

View File

@ -60,6 +60,7 @@ const GENERIC_VARIABLES_VIEW_SETTINGS = {
eval: () => {}
};
const NETWORK_ANALYSIS_PIE_CHART_DIAMETER = 200; // px
const FREETEXT_FILTER_SEARCH_DELAY = 200; // ms
/**
* Object defining the network monitor view components.
@ -350,6 +351,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
this._splitter = $("#network-inspector-view-splitter");
this._summary = $("#requests-menu-network-summary-label");
this._summary.setAttribute("value", L10N.getStr("networkMenu.empty"));
this.userInputTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
Prefs.filters.forEach(type => this.filterOn(type));
this.sortContents(this._byTiming);
@ -380,6 +382,13 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
this.cloneSelectedRequestEvent = this.cloneSelectedRequest.bind(this);
this.toggleRawHeadersEvent = this.toggleRawHeaders.bind(this);
this.requestsFreetextFilterEvent = this.requestsFreetextFilterEvent.bind(this);
this.reFilterRequests = this.reFilterRequests.bind(this);
this.freetextFilterBox = $("#requests-menu-filter-freetext-text");
this.freetextFilterBox.addEventListener("input", this.requestsFreetextFilterEvent, false);
this.freetextFilterBox.addEventListener("command", this.requestsFreetextFilterEvent, false);
$("#toolbar-labels").addEventListener("click", this.requestsMenuSortEvent, false);
$("#requests-menu-footer").addEventListener("click", this.requestsMenuFilterEvent, false);
$("#requests-menu-clear-button").addEventListener("click", this.reqeustsMenuClearEvent, false);
@ -440,6 +449,9 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
$("#toolbar-labels").removeEventListener("click", this.requestsMenuSortEvent, false);
$("#requests-menu-footer").removeEventListener("click", this.requestsMenuFilterEvent, false);
$("#requests-menu-clear-button").removeEventListener("click", this.reqeustsMenuClearEvent, false);
this.freetextFilterBox.removeEventListener("input", this.requestsFreetextFilterEvent, false);
this.freetextFilterBox.removeEventListener("command", this.requestsFreetextFilterEvent, false);
this.userInputTimer.cancel();
$("#network-request-popup").removeEventListener("popupshowing", this._onContextShowing, false);
$("#request-menu-context-newtab").removeEventListener("command", this._onContextNewTabCommand, false);
$("#request-menu-context-copy-url").removeEventListener("command", this._onContextCopyUrlCommand, false);
@ -670,6 +682,31 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
}
},
/**
* Handles the timeout on the freetext filter textbox
*/
requestsFreetextFilterEvent: function() {
this.userInputTimer.cancel();
this._currentFreetextFilter = this.freetextFilterBox.value || "";
if (this._currentFreetextFilter.length === 0) {
this.freetextFilterBox.removeAttribute("filled");
} else {
this.freetextFilterBox.setAttribute("filled", true);
}
this.userInputTimer.initWithCallback(this.reFilterRequests, FREETEXT_FILTER_SEARCH_DELAY, Ci.nsITimer.TYPE_ONE_SHOT);
},
/**
* Refreshes the view contents with the newly selected filters
*/
reFilterRequests: function() {
this.filterContents(this._filterPredicate);
this.refreshSummary();
this.refreshZebra();
},
/**
* Filters all network requests in this container by a specified type.
*
@ -700,9 +737,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
this._disableFilter(aType);
}
this.filterContents(this._filterPredicate);
this.refreshSummary();
this.refreshZebra();
this.reFilterRequests();
},
/**
@ -771,18 +806,14 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
*/
get _filterPredicate() {
let filterPredicates = this._allFilterPredicates;
let currentFreetextFilter = this._currentFreetextFilter;
if (this._activeFilters.length === 1) {
// The simplest case: only one filter active.
return filterPredicates[this._activeFilters[0]].bind(this);
} else {
// Multiple filters active.
return requestItem => {
return this._activeFilters.some(filterName => {
return filterPredicates[filterName].call(this, requestItem);
});
};
}
return requestItem => {
return this._activeFilters.some(filterName => {
return filterPredicates[filterName].call(this, requestItem) &&
filterPredicates["freetext"].call(this, requestItem, currentFreetextFilter);
});
};
},
/**
@ -798,7 +829,8 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
images: this.isImage,
media: this.isMedia,
flash: this.isFlash,
other: this.isOther
other: this.isOther,
freetext: this.isFreetextMatch
}),
/**
@ -957,6 +989,9 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
!this.isHtml(e) && !this.isCss(e) && !this.isJs(e) && !this.isXHR(e) &&
!this.isFont(e) && !this.isImage(e) && !this.isMedia(e) && !this.isFlash(e),
isFreetextMatch: function({ attachment: { url } }, text) //no text is a positive match
!text || url.contains(text),
/**
* Predicates used when sorting items.
*
@ -1865,7 +1900,8 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
_updateQueue: [],
_updateTimeout: null,
_resizeTimeout: null,
_activeFilters: ["all"]
_activeFilters: ["all"],
_currentFreetextFilter: ""
});
/**

View File

@ -47,6 +47,18 @@
</menupopup>
</popupset>
<commandset>
<command id="freeTextFilterCommand"
oncommand="NetMonitorView.RequestsMenu.freetextFilterBox.focus()"/>
</commandset>
<keyset>
<key id="freeTextFilterKey"
key="&netmonitorUI.footer.filterFreetext.key;"
modifiers="accel"
command="freeTextFilterCommand"/>
</keyset>
<deck id="body" class="theme-sidebar" flex="1">
<vbox id="network-inspector-view" flex="1">
@ -752,6 +764,14 @@
data-key="other"
label="&netmonitorUI.footer.filterOther;">
</button>
<spacer id="requests-menu-spacer-textbox"
class="requests-menu-footer-spacer"
flex="0"/>
<textbox id="requests-menu-filter-freetext-text"
class="requests-menu-footer-textbox devtools-searchinput"
type="search"
required="true"
placeholder="&netmonitorUI.footer.filterFreetext.label;"/>
<spacer id="requests-menu-spacer"
class="requests-menu-footer-spacer"
flex="100"/>

View File

@ -5,9 +5,9 @@
* Test if filtering items in the network table works correctly.
*/
const BASIC_REQUESTS = [
{ url: "sjs_content-type-test-server.sjs?fmt=html&res=undefined" },
{ url: "sjs_content-type-test-server.sjs?fmt=css" },
{ url: "sjs_content-type-test-server.sjs?fmt=js" },
{ url: "sjs_content-type-test-server.sjs?fmt=html&res=undefined&text=sample" },
{ url: "sjs_content-type-test-server.sjs?fmt=css&text=sample" },
{ url: "sjs_content-type-test-server.sjs?fmt=js&text=sample" },
];
const REQUESTS_WITH_MEDIA = BASIC_REQUESTS.concat([
@ -23,6 +23,15 @@ const REQUESTS_WITH_MEDIA_AND_FLASH = REQUESTS_WITH_MEDIA.concat([
function test() {
initNetMonitor(FILTERING_URL).then(([aTab, aDebuggee, aMonitor]) => {
function setFreetextFilter(value) {
// Set the text and manually call all callbacks synchronously to avoid the timeout
RequestsMenu.freetextFilterBox.value = value;
RequestsMenu.requestsFreetextFilterEvent();
RequestsMenu.userInputTimer.cancel();
RequestsMenu.reFilterRequests();
}
info("Starting test... ");
let { $, NetMonitorView } = aMonitor.panelWin;
@ -96,16 +105,37 @@ function test() {
testFilterButtons(aMonitor, "all");
return testContents([1, 1, 1, 1, 1, 1, 1, 1]);
})
.then(() => {
// Text in filter box that matches nothing should hide all.
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
setFreetextFilter("foobar");
return testContents([0, 0, 0, 0, 0, 0, 0, 0]);
})
.then(() => {
// Text in filter box that matches should filter out everything else.
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
setFreetextFilter("sample");
return testContents([1, 1, 1, 0, 0, 0, 0, 0]);
})
// ...then combine multiple filters together.
.then(() => {
// Enable filtering for html and css; should show request of both type.
setFreetextFilter("");
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
testFilterButtonsCustom(aMonitor, [0, 1, 1, 0, 0, 0, 0, 0, 0, 0]);
return testContents([1, 1, 0, 0, 0, 0, 0, 0]);
})
.then(() => {
// Html and css filter enabled and text filter should show just the html and css match.
// Should not show both the items that match the button plus the items that match the text.
setFreetextFilter("sample");
return testContents([1, 1, 0, 0, 0, 0, 0, 0]);
})
.then(() => {
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-flash-button"));
setFreetextFilter("");
testFilterButtonsCustom(aMonitor, [0, 1, 1, 0, 0, 0, 0, 0, 1, 0]);
return testContents([1, 1, 0, 0, 0, 0, 0, 1]);
})

View File

@ -124,6 +124,11 @@
- in the network details footer for the "Other" filtering button. -->
<!ENTITY netmonitorUI.footer.filterOther "Other">
<!-- LOCALIZATION NOTE (netmonitorUI.footer.filterFreetext): This is the label displayed
- in the network details footer for the url filtering textbox. -->
<!ENTITY netmonitorUI.footer.filterFreetext.label "Filter URLs">
<!ENTITY netmonitorUI.footer.filterFreetext.key "F">
<!-- LOCALIZATION NOTE (netmonitorUI.footer.clear): This is the label displayed
- in the network details footer for the "Clear" button. -->
<!ENTITY netmonitorUI.footer.clear "Clear">

View File

@ -697,6 +697,28 @@ label.requests-menu-status-code {
font-weight: 600;
}
#requests-menu-filter-freetext-text {
transition-property: max-width, -moz-padding-end, -moz-padding-start;
transition-duration: 250ms;
transition-timing-function: ease;
}
#requests-menu-filter-freetext-text:not([focused]):not([filled]) > .textbox-input-box {
overflow: hidden;
}
#requests-menu-filter-freetext-text:not([focused]):not([filled]) {
max-width: 20px !important;
-moz-padding-end: 5px;
-moz-padding-start: 22px;
background-position: 8px center, top left, top left;
}
#requests-menu-filter-freetext-text[focused],
#requests-menu-filter-freetext-text[filled] {
max-width: 200px !important;
}
/* Performance analysis buttons */
#requests-menu-network-summary-button {