| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * EventsView displays a filtered list of all events sharing a source, and | 6 * EventsView displays a filtered list of all events sharing a source, and |
| 7 * a details pane for the selected sources. | 7 * a details pane for the selected sources. |
| 8 * | 8 * |
| 9 * +----------------------++----------------+ | 9 * +----------------------++----------------+ |
| 10 * | filter box || | | 10 * | filter box || | |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 var nextSourceRow = this.sourceIdToRowMap_[nextSourceId]; | 171 var nextSourceRow = this.sourceIdToRowMap_[nextSourceId]; |
| 172 sourceRow.moveBefore(nextSourceRow); | 172 sourceRow.moveBefore(nextSourceRow); |
| 173 } | 173 } |
| 174 } | 174 } |
| 175 }, | 175 }, |
| 176 | 176 |
| 177 setFilter_: function(filterText) { | 177 setFilter_: function(filterText) { |
| 178 var lastComparisonFunction = this.comparisonFunction_; | 178 var lastComparisonFunction = this.comparisonFunction_; |
| 179 var lastDoSortBackwards = this.doSortBackwards_; | 179 var lastDoSortBackwards = this.doSortBackwards_; |
| 180 | 180 |
| 181 this.pickSortFunction_(filterText); | 181 var filterParser = new SourceFilterParser(filterText); |
| 182 this.currentFilter_ = filterParser.filter; |
| 183 |
| 184 this.pickSortFunction_(filterParser.sort); |
| 182 | 185 |
| 183 if (lastComparisonFunction != this.comparisonFunction_ || | 186 if (lastComparisonFunction != this.comparisonFunction_ || |
| 184 lastDoSortBackwards != this.doSortBackwards_) { | 187 lastDoSortBackwards != this.doSortBackwards_) { |
| 185 this.sort_(); | 188 this.sort_(); |
| 186 } | 189 } |
| 187 | 190 |
| 188 var oldFilter = this.currentFilter_; | |
| 189 this.currentFilter_ = createFilter_(filterText); | |
| 190 | |
| 191 // No need to filter again if filters match. | |
| 192 if (oldFilter && | |
| 193 JSON.stringify(oldFilter) == JSON.stringify(this.currentFilter_)) { | |
| 194 return; | |
| 195 } | |
| 196 | |
| 197 // Iterate through all of the rows and see if they match the filter. | 191 // Iterate through all of the rows and see if they match the filter. |
| 198 for (var id in this.sourceIdToRowMap_) { | 192 for (var id in this.sourceIdToRowMap_) { |
| 199 var entry = this.sourceIdToRowMap_[id]; | 193 var entry = this.sourceIdToRowMap_[id]; |
| 200 entry.setIsMatchedByFilter(entry.matchesFilter(this.currentFilter_)); | 194 entry.setIsMatchedByFilter(this.currentFilter_(entry.getSourceEntry())); |
| 201 } | 195 } |
| 202 }, | 196 }, |
| 203 | 197 |
| 204 /** | 198 /** |
| 205 * Parse any "sort:" directives, and update |comparisonFunction_| and | 199 * Given a "sort" object with "method" and "backwards" keys, looks up and |
| 206 * |doSortBackwards_| as needed. Note only the last valid sort directive | 200 * sets |comparisonFunction_| and |doSortBackwards_|. If the ID does not |
| 207 * is used. | 201 * correspond to a sort function, defaults to sorting by ID. |
| 208 */ | 202 */ |
| 209 pickSortFunction_: function(filterText) { | 203 pickSortFunction_: function(sort) { |
| 210 this.comparisonFunction_ = compareSourceId_; | 204 this.doSortBackwards_ = sort.backwards; |
| 211 this.doSortBackwards_ = false; | 205 this.comparisonFunction_ = COMPARISON_FUNCTION_TABLE[sort.method]; |
| 212 | 206 if (!this.comparisonFunction_) { |
| 213 var filterList = parseFilter_(filterText); | 207 this.doSortBackwards_ = false; |
| 214 for (var i = 0; i < filterList.length; ++i) { | 208 this.comparisonFunction_ = compareSourceId_; |
| 215 var sort = parseSortDirective_(filterList[i].parsed); | |
| 216 if (sort != null) { | |
| 217 this.comparisonFunction_ = sort.comparisonFunction; | |
| 218 this.doSortBackwards_ = sort.backwards; | |
| 219 } | |
| 220 } | 209 } |
| 221 }, | 210 }, |
| 222 | 211 |
| 223 /** | 212 /** |
| 224 * Repositions |sourceRow|'s in the table using an insertion sort. | 213 * Repositions |sourceRow|'s in the table using an insertion sort. |
| 225 * Significantly faster than sorting the entire table again, when only | 214 * Significantly faster than sorting the entire table again, when only |
| 226 * one entry has changed. | 215 * one entry has changed. |
| 227 */ | 216 */ |
| 228 insertionSort_: function(sourceRow) { | 217 insertionSort_: function(sourceRow) { |
| 229 // SourceRow that should be after |sourceRow|, if it needs | 218 // SourceRow that should be after |sourceRow|, if it needs |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 398 scrollToSourceId: function(sourceId) { | 387 scrollToSourceId: function(sourceId) { |
| 399 this.detailsView_.scrollToSourceId(sourceId); | 388 this.detailsView_.scrollToSourceId(sourceId); |
| 400 }, | 389 }, |
| 401 | 390 |
| 402 /** | 391 /** |
| 403 * If already using the specified sort method, flips direction. Otherwise, | 392 * If already using the specified sort method, flips direction. Otherwise, |
| 404 * removes pre-existing sort parameter before adding the new one. | 393 * removes pre-existing sort parameter before adding the new one. |
| 405 */ | 394 */ |
| 406 toggleSortMethod_: function(sortMethod) { | 395 toggleSortMethod_: function(sortMethod) { |
| 407 // Get old filter text and remove old sort directives, if any. | 396 // Get old filter text and remove old sort directives, if any. |
| 408 var filterList = parseFilter_(this.getFilterText_()); | 397 var filterParser = new SourceFilterParser(this.getFilterText_()); |
| 409 var filterText = ''; | 398 var filterText = filterParser.filterTextWithoutSort; |
| 410 for (var i = 0; i < filterList.length; ++i) { | 399 |
| 411 if (parseSortDirective_(filterList[i].parsed) == null) | 400 filterText = 'sort:' + sortMethod + ' ' + filterText; |
| 412 filterText += filterList[i].original; | |
| 413 } | |
| 414 | 401 |
| 415 // If already using specified sortMethod, sort backwards. | 402 // If already using specified sortMethod, sort backwards. |
| 416 if (!this.doSortBackwards_ && | 403 if (!this.doSortBackwards_ && |
| 417 COMPARISON_FUNCTION_TABLE[sortMethod] == this.comparisonFunction_) { | 404 COMPARISON_FUNCTION_TABLE[sortMethod] == this.comparisonFunction_) { |
| 418 sortMethod = '-' + sortMethod; | 405 filterText = '-' + filterText; |
| 419 } | 406 } |
| 420 | 407 |
| 421 filterText = 'sort:' + sortMethod + ' ' + filterText; | |
| 422 this.setFilterText_(filterText.trim()); | 408 this.setFilterText_(filterText.trim()); |
| 423 }, | 409 }, |
| 424 | 410 |
| 425 sortById_: function(event) { | 411 sortById_: function(event) { |
| 426 this.toggleSortMethod_('id'); | 412 this.toggleSortMethod_('id'); |
| 427 }, | 413 }, |
| 428 | 414 |
| 429 sortBySourceType_: function(event) { | 415 sortBySourceType_: function(event) { |
| 430 this.toggleSortMethod_('source'); | 416 this.toggleSortMethod_('source'); |
| 431 }, | 417 }, |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 | 559 |
| 574 function compareSourceType_(source1, source2) { | 560 function compareSourceType_(source1, source2) { |
| 575 var source1Text = source1.getSourceTypeString(); | 561 var source1Text = source1.getSourceTypeString(); |
| 576 var source2Text = source2.getSourceTypeString(); | 562 var source2Text = source2.getSourceTypeString(); |
| 577 var compareResult = source1Text.localeCompare(source2Text); | 563 var compareResult = source1Text.localeCompare(source2Text); |
| 578 if (compareResult != 0) | 564 if (compareResult != 0) |
| 579 return compareResult; | 565 return compareResult; |
| 580 return compareSourceId_(source1, source2); | 566 return compareSourceId_(source1, source2); |
| 581 } | 567 } |
| 582 | 568 |
| 583 /** | |
| 584 * Parses a single "sort:" directive, and returns a dictionary containing | |
| 585 * the sort function and direction. Returns null on failure, including | |
| 586 * the case when no such sort function exists. | |
| 587 */ | |
| 588 | |
| 589 function parseSortDirective_(filterElement) { | |
| 590 var match = /^sort:(-?)(.*)$/.exec(filterElement); | |
| 591 if (!match || !COMPARISON_FUNCTION_TABLE[match[2]]) | |
| 592 return null; | |
| 593 return { | |
| 594 comparisonFunction: COMPARISON_FUNCTION_TABLE[match[2]], | |
| 595 backwards: (match[1] == '-'), | |
| 596 }; | |
| 597 } | |
| 598 | |
| 599 /** | |
| 600 * Parses an "is:" directive, and updates |filter| accordingly. | |
| 601 * | |
| 602 * Returns true on success, and false if |filterElement| is not an "is:" | |
| 603 * directive. | |
| 604 */ | |
| 605 function parseRestrictDirective_(filterElement, filter) { | |
| 606 var match = /^is:(-?)(.*)$/.exec(filterElement); | |
| 607 if (!match) | |
| 608 return false; | |
| 609 if (match[2] == 'active') { | |
| 610 if (match[1] == '-') { | |
| 611 filter.isInactive = true; | |
| 612 } else { | |
| 613 filter.isActive = true; | |
| 614 } | |
| 615 return true; | |
| 616 } | |
| 617 if (match[2] == 'error') { | |
| 618 if (match[1] == '-') { | |
| 619 filter.isNotError = true; | |
| 620 } else { | |
| 621 filter.isError = true; | |
| 622 } | |
| 623 return true; | |
| 624 } | |
| 625 return false; | |
| 626 } | |
| 627 | |
| 628 /** | |
| 629 * Parses all directives that take arbitrary strings as input, | |
| 630 * and updates |filter| accordingly. Directives of these types | |
| 631 * are stored as lists. | |
| 632 * | |
| 633 * Returns true on success, and false if |filterElement| is not a | |
| 634 * recognized directive. | |
| 635 */ | |
| 636 function parseStringDirective_(filterElement, filter) { | |
| 637 var directives = ['type', 'id']; | |
| 638 for (var i = 0; i < directives.length; ++i) { | |
| 639 var directive = directives[i]; | |
| 640 var match = RegExp('^' + directive + ':(.*)$').exec(filterElement); | |
| 641 if (!match) | |
| 642 continue; | |
| 643 | |
| 644 // Split parameters around commas and remove empty elements. | |
| 645 var parameters = match[1].split(','); | |
| 646 parameters = parameters.filter(function(string) { | |
| 647 return string.length > 0; | |
| 648 }); | |
| 649 | |
| 650 // If there's already a matching filter, take the intersection. | |
| 651 // This behavior primarily exists for tests. It is not correct | |
| 652 // when one of the 'type' filters is a partial match. | |
| 653 if (filter[directive]) { | |
| 654 parameters = parameters.filter(function(string) { | |
| 655 return filter[directive].indexOf(string) != -1; | |
| 656 }); | |
| 657 } | |
| 658 | |
| 659 filter[directive] = parameters; | |
| 660 return true; | |
| 661 } | |
| 662 return false; | |
| 663 } | |
| 664 | |
| 665 /** | |
| 666 * Takes in the text of a filter and returns a list of {parsed, original} | |
| 667 * pairs that correspond to substrings of the filter before and after | |
| 668 * filtering. This function is used both to parse filters and to remove | |
| 669 * the sort rule from a filter. Extra whitespace other than a single | |
| 670 * character after each element is ignored. Parsed strings are all | |
| 671 * lowercase. | |
| 672 */ | |
| 673 function parseFilter_(filterText) { | |
| 674 filterText = filterText.toLowerCase(); | |
| 675 | |
| 676 // Assemble a list of quoted and unquoted strings in the filter. | |
| 677 var filterList = []; | |
| 678 var position = 0; | |
| 679 while (position < filterText.length) { | |
| 680 var inQuote = false; | |
| 681 var filterElement = ''; | |
| 682 var startPosition = position; | |
| 683 while (position < filterText.length) { | |
| 684 var nextCharacter = filterText[position]; | |
| 685 ++position; | |
| 686 if (nextCharacter == '\\' && | |
| 687 position < filterText.length) { | |
| 688 // If there's a backslash, skip the backslash and add the next | |
| 689 // character to the element. | |
| 690 filterElement += filterText[position]; | |
| 691 ++position; | |
| 692 continue; | |
| 693 } else if (nextCharacter == '"') { | |
| 694 // If there's an unescaped quote character, toggle |inQuote| without | |
| 695 // modifying the element. | |
| 696 inQuote = !inQuote; | |
| 697 } else if (!inQuote && /\s/.test(nextCharacter)) { | |
| 698 // If not in a quote and have a whitespace character, that's the | |
| 699 // end of the element. | |
| 700 break; | |
| 701 } else { | |
| 702 // Otherwise, add the next character to the element. | |
| 703 filterElement += nextCharacter; | |
| 704 } | |
| 705 } | |
| 706 | |
| 707 if (filterElement.length > 0) { | |
| 708 var filter = { | |
| 709 parsed: filterElement, | |
| 710 original: filterText.substring(startPosition, position), | |
| 711 }; | |
| 712 filterList.push(filter); | |
| 713 } | |
| 714 } | |
| 715 return filterList; | |
| 716 } | |
| 717 | |
| 718 /** | |
| 719 * Converts |filterText| into an object representing the filter. | |
| 720 */ | |
| 721 function createFilter_(filterText) { | |
| 722 var filter = {}; | |
| 723 var filterList = parseFilter_(filterText); | |
| 724 | |
| 725 for (var i = 0; i < filterList.length; ++i) { | |
| 726 if (parseSortDirective_(filterList[i].parsed) || | |
| 727 parseRestrictDirective_(filterList[i].parsed, filter) || | |
| 728 parseStringDirective_(filterList[i].parsed, filter)) { | |
| 729 continue; | |
| 730 } | |
| 731 if (filter.textFilters == undefined) | |
| 732 filter.textFilters = []; | |
| 733 filter.textFilters.push(filterList[i].parsed); | |
| 734 } | |
| 735 return filter; | |
| 736 } | |
| 737 | |
| 738 return EventsView; | 569 return EventsView; |
| 739 })(); | 570 })(); |
| OLD | NEW |