Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(689)

Side by Side Diff: Source/devtools/front_end/FilterController.js

Issue 33143002: DevTools: Unify filtering UI (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /**
32 * @interface
33 * @extends {WebInspector.EventTarget}
34 */
35 WebInspector.Filter = function()
36 {
37 }
38
39 WebInspector.Filter.Events = {
40 FilterChanged: "FilterChanged"
41 }
42
43 WebInspector.Filter.prototype = {
44 /**
45 * @return {boolean}
46 */
47 isActive: function() { },
48
49 /**
50 * @return {Element}
51 */
52 element: function() { }
53 }
54
55 /**
56 * @constructor
57 * @implements {WebInspector.Filter}
58 * @extends {WebInspector.Object}
59 */
60 WebInspector.TextFilter = function()
61 {
62 this._filterElement = document.createElement("div");
63 this._filterElement.className = "text-filter";
64
65 this._filterInputElement = this._filterElement.createChild("input", "search- replace toolbar-replace-control");
66 this._filterInputElement.placeholder = WebInspector.UIString("Filter");
67 this._filterInputElement.id = "filter-input-field";
68 this._filterInputElement.addEventListener("mousedown", this._onFilterFieldMa nualFocus.bind(this), false); // when the search field is manually selected
69 this._filterInputElement.addEventListener("input", this._onInput.bind(this), false);
70 }
71
72 WebInspector.TextFilter.prototype = {
73 /**
74 * @return {boolean}
75 */
76 isActive: function()
77 {
78 return !!this._filterInputElement.value;
79 },
80
81 /**
82 * @return {Element}
83 */
84 element: function()
85 {
86 return this._filterElement;
87 },
88
89 /**
90 * @return {string}
91 */
92 value: function()
93 {
94 return this._filterInputElement.value;
95 },
96
97 /**
98 * @param {string} value
99 */
100 setValue: function(value)
101 {
102 this._filterInputElement.value = value;
103 this.dispatchEventToListeners(WebInspector.Filter.Events.FilterChanged, null);
104 },
105
106 /**
107 * @return {RegExp}
108 */
109 regex: function()
110 {
111 var filterQuery = this._filterInputElement.value;
112 return filterQuery ? createPlainTextSearchRegex(filterQuery, "i") : null ;
113 },
114
115 /**
116 * @param {Event} event
117 */
118 _onFilterFieldManualFocus: function(event)
119 {
120 WebInspector.setCurrentFocusElement(event.target);
121 },
122
123 /**
124 * @param {WebInspector.Event} event
125 */
126 _onInput: function(event)
127 {
128 this.dispatchEventToListeners(WebInspector.Filter.Events.FilterChanged, null);
129 },
130
131 __proto__: WebInspector.Object.prototype
132 }
133
134 /**
135 * @constructor
136 * @implements {WebInspector.Filter}
137 * @extends {WebInspector.Object}
138 * @param {Array.<{name: string, label: string}>} types
139 */
140 WebInspector.TypesFilter = function(types)
pfeldman 2013/10/22 15:15:01 NamedBitSetFilter
141 {
142 this._filtersElement = document.createElement("div");
143 this._filtersElement.className = "types-filter status-bar-item";
144 this._filtersElement.title = WebInspector.UIString("Use %s Click to select m ultiple types.", WebInspector.KeyboardShortcut.shortcutToString("", WebInspector .KeyboardShortcut.Modifiers.CtrlOrMeta));
145
146 this._types = types;
147 this._allowedTypes = {};
148 this._typeFilterElements = {};
149 this._addTypeFilter(WebInspector.TypesFilter.ALL_TYPES, WebInspector.UIStrin g("All"));
150
151 this._filtersElement.createChild("div", "types-filter-divider");
152
153 for (var i = 0; i < types.length; ++i) {
pfeldman 2013/10/22 15:15:01 {}
154 this._addTypeFilter(types[i].name, types[i].label);
155 }
156 this._toggleTypeFilter(WebInspector.TypesFilter.ALL_TYPES, false);
157 }
158
159 WebInspector.TypesFilter.ALL_TYPES = "all";
160
161 WebInspector.TypesFilter.prototype = {
162 /**
163 * @return {boolean}
164 */
165 isActive: function()
166 {
167 return !this._allowedTypes[WebInspector.TypesFilter.ALL_TYPES];
168 },
169
170 /**
171 * @return {Element}
172 */
173 element: function()
174 {
175 return this._filtersElement;
176 },
177
178 /**
179 * @param {string} typeName
180 * @return {boolean}
181 */
182 accept: function(typeName)
183 {
184 return !!this._allowedTypes[WebInspector.TypesFilter.ALL_TYPES] || !!thi s._allowedTypes[typeName];
185 },
186
187 /**
188 * @return {Array.<string>}
189 */
190 filteredOutTypes: function()
191 {
192 if (this._allowedTypes[WebInspector.TypesFilter.ALL_TYPES])
193 return [];
194 var result = [];
195 for (var i = 0; i < this._types.length; ++i) {
196 var name = this._types[i].name;
197 if (!this._allowedTypes[name])
198 result.push(name);
199 }
200 return result;
201 },
202
203 /**
204 * @param {Array.<string>} filteredOutTypes
205 */
206 setFilteredOutTypes: function(filteredOutTypes)
207 {
208 this._allowedTypes = {};
209 if (filteredOutTypes.length === 0) {
210 this._allowedTypes[WebInspector.TypesFilter.ALL_TYPES] = true;
211 } else {
212 for (var i = 0; i < this._types.length; ++i) {
213 var name = this._types[i].name;
214 this._allowedTypes[name] = true;
215 }
216 for (var i = 0; i < filteredOutTypes.length; ++i)
217 delete this._allowedTypes[filteredOutTypes[i]];
218 }
219 for (var typeName in this._typeFilterElements)
220 this._typeFilterElements[typeName].enableStyleClass("selected", this ._allowedTypes[typeName]);
221 this.dispatchEventToListeners(WebInspector.Filter.Events.FilterChanged, null);
222 },
223
224 /**
225 * @return {Array.<string>}
226 */
227 acceptedTypes: function()
228 {
229 if (this._allowedTypes[WebInspector.TypesFilter.ALL_TYPES])
230 return [WebInspector.TypesFilter.ALL_TYPES];
231 var result = [];
232 for (var i = 0; i < this._types.length; ++i) {
233 var name = this._types[i].name;
234 if (this._allowedTypes[name])
235 result.push(name);
236 }
237 return result;
238 },
239
240 /**
241 * @param {Array.<string>} acceptedTypes
242 */
243 setAcceptedTypes: function(acceptedTypes)
244 {
245 this._allowedTypes = {};
246 for (var i = 0; i < acceptedTypes.length; ++i)
247 this._allowedTypes[acceptedTypes[i]] = true;
248 for (var typeName in this._typeFilterElements)
249 this._typeFilterElements[typeName].enableStyleClass("selected", this ._allowedTypes[typeName]);
250 this.dispatchEventToListeners(WebInspector.Filter.Events.FilterChanged, null);
251 },
252
253 /**
254 * @param {string} typeName
255 * @param {string} label
256 */
257 _addTypeFilter: function(typeName, label)
258 {
259 var typeFilterElement = this._filtersElement.createChild("li", typeName) ;
260 typeFilterElement.typeName = typeName;
261 typeFilterElement.createTextChild(label);
262 typeFilterElement.addEventListener("click", this._onTypeFilterClicked.bi nd(this), false);
263 this._typeFilterElements[typeName] = typeFilterElement;
264 },
265
266 /**
267 * @param {!Event} e
268 */
269 _onTypeFilterClicked: function(e)
270 {
271 var toggle;
272 if (WebInspector.isMac())
273 toggle = e.metaKey && !e.ctrlKey && !e.altKey && !e.shiftKey;
274 else
275 toggle = e.ctrlKey && !e.metaKey && !e.altKey && !e.shiftKey;
276 this._toggleTypeFilter(e.target.typeName, toggle);
277 },
278
279 /**
280 * @param {string} typeName
281 * @param {boolean} allowMultiSelect
282 */
283 _toggleTypeFilter: function(typeName, allowMultiSelect)
284 {
285 if (allowMultiSelect && typeName !== WebInspector.TypesFilter.ALL_TYPES)
286 this._typeFilterElements[WebInspector.TypesFilter.ALL_TYPES].removeS tyleClass("selected");
287 else {
288 for (var key in this._typeFilterElements)
289 this._typeFilterElements[key].removeStyleClass("selected");
290 }
291
292 var filterElement = this._typeFilterElements[typeName];
293 filterElement.enableStyleClass("selected", !filterElement.hasStyleClass( "selected"));
294
295 this._allowedTypes = {};
296 for (var key in this._typeFilterElements) {
297 if (this._typeFilterElements[key].hasStyleClass("selected"))
298 this._allowedTypes[key] = true;
299 }
300 this.dispatchEventToListeners(WebInspector.Filter.Events.FilterChanged, null);
301 },
302
303 __proto__: WebInspector.Object.prototype
304 }
305
306 /**
307 * @constructor
308 * @implements {WebInspector.Filter}
309 * @extends {WebInspector.Object}
310 * @param {Array.<{value: *, label: string, title: string}>} options
311 */
312 WebInspector.ComboBoxFilter = function(options)
313 {
314 this._filterElement = document.createElement("div");
315 this._filterElement.className = "combobox-filter";
316
317 this._options = options;
318 this._filterComboBox = new WebInspector.StatusBarComboBox(this._filterChange d.bind(this));
319 for (var i = 0; i < options.length; ++i) {
320 var filterOption = options[i];
321 var option = document.createElement("option");
322 option.text = filterOption.label;
323 option.title = filterOption.title;
324 this._filterComboBox.addOption(option);
325 this._filterComboBox.element.title = this._filterComboBox.selectedOption ().title;
326 }
327 this._filterElement.appendChild(this._filterComboBox.element);
328 }
329
330 WebInspector.ComboBoxFilter.prototype = {
331 /**
332 * @return {boolean}
333 */
334 isActive: function()
335 {
336 return this._filterComboBox.selectedIndex() !== 0;
337 },
338
339 /**
340 * @return {Element}
341 */
342 element: function()
343 {
344 return this._filterElement;
345 },
346
347 /**
348 * @param {string} typeName
349 * @return {*}
350 */
351 value: function(typeName)
352 {
353 var option = this._options[this._filterComboBox.selectedIndex()];
354 return option.value;
355 },
356
357 /**
358 * @param {Event} event
359 */
360 _filterChanged: function(event)
361 {
362 var option = this._options[this._filterComboBox.selectedIndex()];
363 this._filterComboBox.element.title = option.title;
364 this.dispatchEventToListeners(WebInspector.Filter.Events.FilterChanged, null);
365 },
366
367 __proto__: WebInspector.Object.prototype
368 }
369
370 /**
371 * @constructor
372 * @implements {WebInspector.Filter}
373 * @extends {WebInspector.Object}
374 * @param {boolean} activeWhenChecked
375 */
376 WebInspector.CheckboxFilter = function(className, title, activeWhenChecked)
377 {
378 this._className = className;
379 this._filterElement = document.createElement("div");
380 this._filterElement.classList.add("checkbox-filter", "checkbox-filter-" + th is._className);
381 this._activeWhenChecked = activeWhenChecked;
382 this._createCheckbox(title);
383 }
384
385 WebInspector.CheckboxFilter.prototype = {
386 /**
387 * @return {boolean}
388 */
389 isActive: function()
390 {
391 return this._activeWhenChecked === this._checkElement.checked;
392 },
393
394 /**
395 * @return {Element}
396 */
397 element: function()
398 {
399 return this._filterElement;
400 },
401
402 /**
403 * @return {boolean}
404 */
405 checked: function()
406 {
407 return this._checkElement.checked;
408 },
409
410 /**
411 * @param {boolean} checked
412 */
413 setChecked: function(checked)
414 {
415 this._checkElement.checked = checked;
416 this._checkElement.enableStyleClass("checkbox-filter-checkbox-checked", this._checkElement.checked);
417 this.dispatchEventToListeners(WebInspector.Filter.Events.FilterChanged, null);
418 },
419
420 _createCheckbox: function(title)
421 {
422 var label = this._filterElement.createChild("label");
423 var checkBorder = label.createChild("div", "checkbox-filter-checkbox");
424 this._checkElement = checkBorder.createChild("div", "checkbox-filter-che ckbox-check checkbox-filter-checkbox-checked");
425 this._checkElement.type = "checkbox";
426 this._checkElement.checked = true;
427 this._filterElement.addEventListener("click", listener.bind(this), false );
428
429 function listener(event)
430 {
431 this.setChecked(!this._checkElement.checked);
432 }
433
434 var typeElement = label.createChild("span", "type");
435 typeElement.textContent = title;
436 },
437
438 __proto__: WebInspector.Object.prototype
439 }
440
441 /**
442 * @constructor
443 * @extends {WebInspector.Object}
444 */
445 WebInspector.FilterController = function()
pfeldman 2013/10/22 15:15:01 Make it the first class in file.
446 {
447 this._filtersShown = false;
448 this._element = document.createElement("div");
449 this._element.className = "hbox";
450
451 this._filterButton = new WebInspector.StatusBarButton(WebInspector.UIString( "Filter"), "filters-toggle", 3);
452 this._filterButton.element.addEventListener("mousedown", this._handleFilterB uttonClick.bind(this), false);
453
454 this._filters = [];
455 }
456
457 WebInspector.FilterController.Events = {
458 FiltersToggled: "FiltersToggled"
459 }
460
461 WebInspector.FilterController.FilterControllerState = {
462 Inactive : "inactive",
463 Active : "active",
464 Shown : "shown"
465 };
466
467 WebInspector.FilterController.prototype = {
468 /**
469 * @return {Element}
470 */
471 filterButton: function()
472 {
473 return this._filterButton.element;
474 },
475
476 /**
477 * @return {Element}
478 */
479 filtersElement: function()
480 {
481 return this._element;
482 },
483
484 /**
485 * @return {boolean}
486 */
487 filtersToggled: function()
488 {
489 return this._filtersShown;
490 },
491
492 /**
493 * @param {WebInspector.Filter} filter
494 */
495 addFilter: function(filter)
496 {
497 this._filters.push(filter);
498 this._element.appendChild(filter.element());
499 filter.addEventListener(WebInspector.Filter.Events.FilterChanged, this._ filterChanged, this);
500 this._updateFilterButton();
501 },
502
503 /**
504 * @param {WebInspector.Event} event
505 */
506 _filterChanged: function(event)
507 {
508 this._updateFilterButton();
509 },
510
511 /**
512 * @return {string}
513 */
514 _filterControllerState: function()
515 {
516 if (this._filtersShown)
517 return WebInspector.FilterController.FilterControllerState.Shown;
518 var isActive = false;
519 for (var i = 0; i < this._filters.length; ++i) {
520 if (this._filters[i].isActive())
521 return WebInspector.FilterController.FilterControllerState.Activ e;
522 }
523 return WebInspector.FilterController.FilterControllerState.Inactive;
524 },
525
526 _updateFilterButton: function()
527 {
528 this._filterButton.state = this._filterControllerState();
529 },
530
531 /**
532 * @param {Event} event
533 */
534 _handleFilterButtonClick: function(event)
535 {
536 this._filtersShown = !this._filtersShown;
537 this._updateFilterButton();
538 this.dispatchEventToListeners(WebInspector.FilterController.Events.Filte rsToggled, this._filtersShown);
539 },
540
541 __proto__: WebInspector.Object.prototype
542 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698