Bug 1309192 - Implement search filter in Net Panel Toolbar r=jsnajdr

MozReview-Commit-ID: FjVo69jmE7e

--HG--
extra : rebase_source : 384206ee66824fe75d84232c7960280295909649
This commit is contained in:
Ricky Chien 2016-10-20 13:58:35 +08:00
Родитель f0150be625
Коммит 0bae861b5c
16 изменённых файлов: 107 добавлений и 95 удалений

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

@ -4,8 +4,9 @@
"use strict";
const {
TOGGLE_FILTER,
ENABLE_FILTER_ONLY,
TOGGLE_FILTER_TYPE,
ENABLE_FILTER_TYPE_ONLY,
SET_FILTER_TEXT,
} = require("../constants");
/**
@ -15,9 +16,9 @@ const {
*
* @param {string} filter - A filter type is going to be updated
*/
function toggleFilter(filter) {
function toggleFilterType(filter) {
return {
type: TOGGLE_FILTER,
type: TOGGLE_FILTER_TYPE,
filter,
};
}
@ -30,14 +31,27 @@ function toggleFilter(filter) {
*
* @param {string} filter - A filter type is going to be updated
*/
function enableFilterOnly(filter) {
function enableFilterTypeOnly(filter) {
return {
type: ENABLE_FILTER_ONLY,
type: ENABLE_FILTER_TYPE_ONLY,
filter,
};
}
/**
* Set filter text.
*
* @param {string} url - A filter text is going to be set
*/
function setFilterText(url) {
return {
type: SET_FILTER_TEXT,
url,
};
}
module.exports = {
toggleFilter,
enableFilterOnly,
toggleFilterType,
enableFilterTypeOnly,
setFilterText,
};

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

@ -42,7 +42,7 @@ module.exports = connect(
if (evt.type === "keydown" && (evt.key !== "" || evt.key !== "Enter")) {
return;
}
dispatch(Actions.toggleFilter(evt.target.dataset.key));
dispatch(Actions.toggleFilterType(evt.target.dataset.key));
},
})
)(FilterButtons);

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

@ -5,5 +5,6 @@
DevToolsModules(
'filter-buttons.js',
'search-box.js',
'toggle-button.js',
)

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

@ -0,0 +1,24 @@
/* 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 { connect } = require("devtools/client/shared/vendor/react-redux");
const SearchBox = require("devtools/client/shared/components/search-box");
const { L10N } = require("../l10n");
const Actions = require("../actions/index");
const { FREETEXT_FILTER_SEARCH_DELAY } = require("../constants");
module.exports = connect(
(state) => ({
delay: FREETEXT_FILTER_SEARCH_DELAY,
keyShortcut: L10N.getStr("netmonitor.toolbar.filterFreetext.key"),
placeholder: L10N.getStr("netmonitor.toolbar.filterFreetext.label"),
type: "filter",
}),
(dispatch) => ({
onChange: (url) => {
dispatch(Actions.setFilterText(url));
},
})
)(SearchBox);

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

@ -3,12 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const general = {
FREETEXT_FILTER_SEARCH_DELAY: 200,
};
const actionTypes = {
TOGGLE_FILTER: "TOGGLE_FILTER",
ENABLE_FILTER_ONLY: "ENABLE_FILTER_ONLY",
TOGGLE_FILTER_TYPE: "TOGGLE_FILTER_TYPE",
ENABLE_FILTER_TYPE_ONLY: "ENABLE_FILTER_TYPE_ONLY",
TOGGLE_SIDEBAR: "TOGGLE_SIDEBAR",
SHOW_SIDEBAR: "SHOW_SIDEBAR",
DISABLE_TOGGLE_BUTTON: "DISABLE_TOGGLE_BUTTON",
SET_FILTER_TEXT: "SET_FILTER_TEXT",
};
module.exports = actionTypes;
module.exports = Object.assign({}, general, actionTypes);

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

@ -299,7 +299,7 @@ var NetMonitorController = {
request = NetMonitorView.RequestsMenu.getItemForPredicate(predicate);
if (!request) {
// Reset filters so that the request is visible.
gStore.dispatch(Actions.toggleFilter("all"));
gStore.dispatch(Actions.toggleFilterType("all"));
request = NetMonitorView.RequestsMenu.getItemForPredicate(predicate);
}

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

@ -31,11 +31,10 @@
<toolbarbutton id="requests-menu-network-summary-button"
class="devtools-toolbarbutton icon-and-text"
data-localization="tooltiptext=netmonitor.toolbar.perf"/>
<textbox id="requests-menu-filter-freetext-text"
class="devtools-filterinput"
type="search"
required="true"
data-localization="placeholder=netmonitor.toolbar.filterFreetext.label"/>
<html:div xmlns="http://www.w3.org/1999/xhtml"
id="react-details-pane-toggle-hook"/>
<html:div xmlns="http://www.w3.org/1999/xhtml"
id="react-search-box-hook"/>
<html:div xmlns="http://www.w3.org/1999/xhtml"
id="react-details-pane-toggle-hook"/>
</hbox>

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

@ -9,8 +9,6 @@ const promise = require("promise");
const EventEmitter = require("devtools/shared/event-emitter");
const { Task } = require("devtools/shared/task");
const { localizeMarkup } = require("devtools/shared/l10n");
const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
const {L10N} = require("./l10n");
function NetMonitorPanel(iframeWindow, toolbox) {
this.panelWin = iframeWindow;
@ -23,15 +21,6 @@ function NetMonitorPanel(iframeWindow, toolbox) {
this._controller._toolbox = this._toolbox;
EventEmitter.decorate(this);
this.shortcuts = new KeyShortcuts({
window: this.panelDoc.defaultView,
});
let key = L10N.getStr("netmonitor.toolbar.filterFreetext.key");
this.shortcuts.on(key, (name, event) => {
event.preventDefault();
this._view.RequestsMenu.freetextFilterBox.focus();
});
}
exports.NetMonitorPanel = NetMonitorPanel;
@ -79,8 +68,6 @@ NetMonitorPanel.prototype = {
let deferred = promise.defer();
this._destroying = deferred.promise;
this.shortcuts.destroy();
yield this._controller.shutdownNetMonitor();
this.emit("destroyed");

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

@ -5,11 +5,12 @@
const I = require("devtools/client/shared/vendor/immutable");
const {
TOGGLE_FILTER,
ENABLE_FILTER_ONLY,
TOGGLE_FILTER_TYPE,
ENABLE_FILTER_TYPE_ONLY,
SET_FILTER_TEXT,
} = require("../constants");
const FiltersTypes = I.Record({
const FilterTypes = I.Record({
all: false,
html: false,
css: false,
@ -24,10 +25,11 @@ const FiltersTypes = I.Record({
});
const Filters = I.Record({
types: new FiltersTypes({ all: true }),
types: new FilterTypes({ all: true }),
url: "",
});
function toggleFilter(state, action) {
function toggleFilterType(state, action) {
let { filter } = action;
let newState;
@ -36,7 +38,7 @@ function toggleFilter(state, action) {
return state;
}
if (filter === "all") {
return new FiltersTypes({ all: true });
return new FilterTypes({ all: true });
}
newState = state.withMutations(types => {
@ -45,13 +47,13 @@ function toggleFilter(state, action) {
});
if (!newState.includes(true)) {
newState = new FiltersTypes({ all: true });
newState = new FilterTypes({ all: true });
}
return newState;
}
function enableFilterOnly(state, action) {
function enableFilterTypeOnly(state, action) {
let { filter } = action;
// Ignore unknown filter type
@ -59,18 +61,17 @@ function enableFilterOnly(state, action) {
return state;
}
return new FiltersTypes({ [filter]: true });
return new FilterTypes({ [filter]: true });
}
function filters(state = new Filters(), action) {
let types;
switch (action.type) {
case TOGGLE_FILTER:
types = toggleFilter(state.types, action);
return state.set("types", types);
case ENABLE_FILTER_ONLY:
types = enableFilterOnly(state.types, action);
return state.set("types", types);
case TOGGLE_FILTER_TYPE:
return state.set("types", toggleFilterType(state.types, action));
case ENABLE_FILTER_TYPE_ONLY:
return state.set("types", enableFilterTypeOnly(state.types, action));
case SET_FILTER_TEXT:
return state.set("url", action.url);
default:
return state;
}

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

@ -2,7 +2,7 @@
NetMonitorController, NetMonitorView */
"use strict";
/* eslint-disable mozilla/reject-some-requires */
const { Cc, Ci, Cu } = require("chrome");
const { Cu } = require("chrome");
const Services = require("Services");
const {Task} = require("devtools/shared/task");
const {DeferredTask} = Cu.import("resource://gre/modules/DeferredTask.jsm", {});
@ -70,8 +70,7 @@ const REQUESTS_WATERFALL_BACKGROUND_TICKS_OPACITY_MIN = 32;
const REQUESTS_WATERFALL_BACKGROUND_TICKS_OPACITY_ADD = 32;
const REQUESTS_WATERFALL_DOMCONTENTLOADED_TICKS_COLOR_RGBA = [255, 0, 0, 128];
const REQUESTS_WATERFALL_LOAD_TICKS_COLOR_RGBA = [0, 0, 255, 128];
// ms
const FREETEXT_FILTER_SEARCH_DELAY = 200;
// Constants for formatting bytes.
const BYTES_IN_KB = 1024;
const BYTES_IN_MB = Math.pow(BYTES_IN_KB, 2);
@ -134,8 +133,6 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
this._splitter = $("#network-inspector-view-splitter");
this._summary = $("#requests-menu-network-summary-button");
this._summary.setAttribute("label", L10N.getStr("networkMenu.empty"));
this.userInputTimer = Cc["@mozilla.org/timer;1"]
.createInstance(Ci.nsITimer);
// Create a tooltip for the newly appended network request item.
this.tooltip = new HTMLTooltip(NetMonitorController._toolbox.doc, { type: "arrow" });
@ -174,16 +171,8 @@ 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);
$("#toolbar-labels").addEventListener("keydown",
@ -195,18 +184,20 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
this.unsubscribeStore = store.subscribe(storeWatcher(
null,
() => store.getState().filters.types,
(newTypes) => {
this._activeFilters = newTypes
() => store.getState().filters,
(newFilters) => {
this._activeFilters = newFilters.types
.toSeq()
.filter((checked, key) => checked)
.keySeq()
.toArray();
this._currentFreetextFilter = newFilters.url;
this.reFilterRequests();
}
));
Prefs.filters.forEach(type => store.dispatch(Actions.toggleFilter(type)));
Prefs.filters.forEach(type =>
store.dispatch(Actions.toggleFilterType(type)));
window.once("connected", this._onConnect.bind(this));
},
@ -268,12 +259,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
this.requestsMenuSortEvent, false);
$("#toolbar-labels").removeEventListener("keydown",
this.requestsMenuSortKeyboardEvent, false);
this.freetextFilterBox.removeEventListener("input",
this.requestsFreetextFilterEvent, false);
this.freetextFilterBox.removeEventListener("command",
this.requestsFreetextFilterEvent, false);
this.userInputTimer.cancel();
this._flushRequestsTask.disarm();
$("#requests-menu-reload-notice-button").removeEventListener("command",
@ -615,23 +601,6 @@ 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
*/

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

@ -29,14 +29,12 @@ const REQUESTS_WITH_MEDIA_AND_FLASH_AND_WS = REQUESTS_WITH_MEDIA_AND_FLASH.conca
]);
add_task(function* () {
let Actions = require("devtools/client/netmonitor/actions/index");
let { monitor } = yield initNetMonitor(FILTERING_URL);
let { gStore } = monitor.panelWin;
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();
gStore.dispatch(Actions.setFilterText(value));
}
info("Starting test... ");

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

@ -28,7 +28,7 @@ add_task(function* () {
info("Checking the image thumbnail when all items are sorted.");
checkImageThumbnail();
gStore.dispatch(Actions.toggleFilter("images"));
gStore.dispatch(Actions.toggleFilterType("images"));
info("Checking the image thumbnail when only images are shown.");
checkImageThumbnail();

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

@ -32,7 +32,7 @@ add_task(function* () {
// Predicate used to modify the frontend when setting the new pref value,
// before trying to validate the changes.
modifyFrontend: ($, value) => value.forEach(e =>
getStore().dispatch(Actions.toggleFilter(e)))
getStore().dispatch(Actions.toggleFilterType(e)))
},
networkDetailsWidth: {
newValue: ~~(Math.random() * 200 + 100),

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

@ -6,6 +6,7 @@ const ReactDOM = require("devtools/client/shared/vendor/react-dom");
const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
const FilterButtons = createFactory(require("./components/filter-buttons"));
const ToggleButton = createFactory(require("./components/toggle-button"));
const SearchBox = createFactory(require("./components/search-box"));
const { L10N } = require("./l10n");
// Shortcuts
@ -28,6 +29,7 @@ ToolbarView.prototype = {
this._clearContainerNode = $("#react-clear-button-hook");
this._filterContainerNode = $("#react-filter-buttons-hook");
this._toggleContainerNode = $("#react-details-pane-toggle-hook");
this._searchContainerNode = $("#react-search-box-hook");
// clear button
ReactDOM.render(button({
@ -45,6 +47,13 @@ ToolbarView.prototype = {
FilterButtons()
), this._filterContainerNode);
// search box
ReactDOM.render(Provider(
{ store },
SearchBox()
), this._searchContainerNode);
// details pane toggle button
ReactDOM.render(Provider(
{ store },
ToggleButton()
@ -60,7 +69,9 @@ ToolbarView.prototype = {
ReactDOM.unmountComponentAtNode(this._clearContainerNode);
ReactDOM.unmountComponentAtNode(this._filterContainerNode);
ReactDOM.unmountComponentAtNode(this._toggleContainerNode);
ReactDOM.unmountComponentAtNode(this._searchContainerNode);
}
};
exports.ToolbarView = ToolbarView;

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

@ -44,7 +44,10 @@ module.exports = createClass({
},
componentWillUnmount() {
this.shortcuts.destroy();
if (this.shortcuts) {
this.shortcuts.destroy();
}
// Clean up an existing timeout.
if (this.searchTimeout) {
clearTimeout(this.searchTimeout);

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

@ -47,7 +47,7 @@ add_task(function* () {
"The correct request is definitely selected");
// Filter out the HTML request.
panel.panelWin.gStore.dispatch(Actions.toggleFilter("js"));
panel.panelWin.gStore.dispatch(Actions.toggleFilterType("js"));
yield toolbox.selectTool("webconsole");
is(toolbox.currentToolId, "webconsole", "Web console was selected");