Home | History | Annotate | Download | only in src
      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
      3 // found in the LICENSE file.
      4 
      5 'use strict';
      6 
      7 /**
      8  * @fileoverview FindControl and FindController.
      9  */
     10 base.require('timeline_track_view');
     11 base.require('filter');
     12 base.require('overlay');
     13 base.exportTo('tracing', function() {
     14 
     15   /**
     16    * FindControl
     17    * @constructor
     18    * @extends {tracing.ui.Overlay}
     19    */
     20   var FindControl = tracing.ui.define('div');
     21 
     22   FindControl.prototype = {
     23     __proto__: tracing.ui.Overlay.prototype,
     24 
     25     decorate: function() {
     26       tracing.ui.Overlay.prototype.decorate.call(this);
     27 
     28       this.className = 'find-control';
     29 
     30       this.hitCountEl_ = document.createElement('div');
     31       this.hitCountEl_.className = 'hit-count-label';
     32       this.hitCountEl_.textContent = '1 of 7';
     33 
     34       var findPreviousBn = document.createElement('div');
     35       findPreviousBn.className = 'button find-previous';
     36       findPreviousBn.textContent = '\u2190';
     37       findPreviousBn.addEventListener('click', function() {
     38         this.controller.findPrevious();
     39         this.updateHitCountEl_();
     40       }.bind(this));
     41 
     42       var findNextBn = document.createElement('div');
     43       findNextBn.className = 'button find-next';
     44       findNextBn.textContent = '\u2192';
     45       findNextBn.addEventListener('click', function() {
     46         this.controller.findNext();
     47         this.updateHitCountEl_();
     48       }.bind(this));
     49 
     50       // Filter input element.
     51       this.filterEl_ = document.createElement('input');
     52       this.filterEl_.type = 'input';
     53 
     54       this.filterEl_.addEventListener('input', function(e) {
     55         this.controller.filterText = this.filterEl_.value;
     56         this.updateHitCountEl_();
     57       }.bind(this));
     58 
     59       this.filterEl_.addEventListener('keydown', function(e) {
     60         if (e.keyCode == 13) {
     61           findNextBn.click();
     62         } else if (e.keyCode == 27) {
     63           this.filterEl_.blur();
     64           this.updateHitCountEl_();
     65         }
     66       }.bind(this));
     67 
     68       this.filterEl_.addEventListener('blur', function(e) {
     69         this.updateHitCountEl_();
     70       }.bind(this));
     71 
     72       this.filterEl_.addEventListener('focus', function(e) {
     73         this.updateHitCountEl_();
     74       }.bind(this));
     75 
     76       // Attach everything.
     77       this.appendChild(this.filterEl_);
     78 
     79       this.appendChild(findPreviousBn);
     80       this.appendChild(findNextBn);
     81       this.appendChild(this.hitCountEl_);
     82 
     83       this.updateHitCountEl_();
     84     },
     85 
     86     get controller() {
     87       return this.controller_;
     88     },
     89 
     90     set controller(c) {
     91       this.controller_ = c;
     92       this.updateHitCountEl_();
     93     },
     94 
     95     focus: function() {
     96       this.filterEl_.selectionStart = 0;
     97       this.filterEl_.selectionEnd = this.filterEl_.value.length;
     98       this.filterEl_.focus();
     99     },
    100 
    101     updateHitCountEl_: function() {
    102       if (!this.controller || document.activeElement != this.filterEl_) {
    103         this.hitCountEl_.textContent = '';
    104         return;
    105       }
    106       var i = this.controller.currentHitIndex;
    107       var n = this.controller.filterHits.length;
    108       if (n == 0)
    109         this.hitCountEl_.textContent = '0 of 0';
    110       else
    111         this.hitCountEl_.textContent = (i + 1) + ' of ' + n;
    112     }
    113   };
    114 
    115   function FindController() {
    116     this.timeline_ = undefined;
    117     this.model_ = undefined;
    118     this.filterText_ = '';
    119     this.filterHits_ = new tracing.Selection();
    120     this.filterHitsDirty_ = true;
    121     this.currentHitIndex_ = 0;
    122   };
    123 
    124   FindController.prototype = {
    125     __proto__: Object.prototype,
    126 
    127     get timeline() {
    128       return this.timeline_;
    129     },
    130 
    131     set timeline(t) {
    132       this.timeline_ = t;
    133       this.filterHitsDirty_ = true;
    134     },
    135 
    136     get filterText() {
    137       return this.filterText_;
    138     },
    139 
    140     set filterText(f) {
    141       if (f == this.filterText_)
    142         return;
    143       this.filterText_ = f;
    144       this.filterHitsDirty_ = true;
    145       this.findNext();
    146     },
    147 
    148     get filterHits() {
    149       if (this.filterHitsDirty_) {
    150         this.filterHitsDirty_ = false;
    151         if (this.timeline_) {
    152           var filter = new tracing.TitleFilter(this.filterText);
    153           this.filterHits_.clear();
    154           this.timeline.addAllObjectsMatchingFilterToSelection(
    155               filter, this.filterHits_);
    156           this.currentHitIndex_ = this.filterHits_.length - 1;
    157         } else {
    158           this.filterHits_.clear();
    159           this.currentHitIndex_ = 0;
    160         }
    161       }
    162       return this.filterHits_;
    163     },
    164 
    165     get currentHitIndex() {
    166       return this.currentHitIndex_;
    167     },
    168 
    169     find_: function(dir) {
    170       if (!this.timeline)
    171         return;
    172 
    173       var N = this.filterHits.length;
    174       this.currentHitIndex_ = this.currentHitIndex_ + dir;
    175 
    176       if (this.currentHitIndex_ < 0) this.currentHitIndex_ = N - 1;
    177       if (this.currentHitIndex_ >= N) this.currentHitIndex_ = 0;
    178 
    179       if (this.currentHitIndex_ < 0 || this.currentHitIndex_ >= N) {
    180         this.timeline.selection = new tracing.Selection();
    181         return;
    182       }
    183 
    184       // We allow the zoom level to change on the first hit level. But, when
    185       // then cycling through subsequent changes, restrict it to panning.
    186       var zoomAllowed = this.currentHitIndex_ == 0;
    187       var subSelection = this.filterHits.subSelection(this.currentHitIndex_);
    188       this.timeline.setSelectionAndMakeVisible(subSelection, zoomAllowed);
    189     },
    190 
    191     findNext: function() {
    192       this.find_(1);
    193     },
    194 
    195     findPrevious: function() {
    196       this.find_(-1);
    197     }
    198   };
    199 
    200   return {
    201     FindControl: FindControl,
    202     FindController: FindController
    203   };
    204 });
    205