blob: 1d5ddaef15637a35fa0c432bb25b4ca9f7d36566 [file] [log] [blame]
Chris Craikb122baf2015-03-05 13:58:42 -08001<!DOCTYPE html>
2<!--
3Copyright (c) 2012 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="import" href="/base/task.html">
9<link rel="import" href="/core/filter.html">
10<link rel="import" href="/core/selection.html">
Chris Craikb122baf2015-03-05 13:58:42 -080011
12<script>
13'use strict';
14
15/**
16 * @fileoverview FindController.
17 */
18tv.exportTo('tv.c', function() {
19 var Task = tv.b.Task;
20
Chris Craik44c28202015-05-12 17:25:16 -070021 function FindController(selectionController) {
22 this.selectionController_ = selectionController;
Chris Craikb122baf2015-03-05 13:58:42 -080023 this.filterText_ = '';
24 this.filterHits_ = new tv.c.Selection();
25 this.filterHitsDirty_ = true;
26 this.currentHitIndex_ = -1;
27 };
28
29 FindController.prototype = {
30 __proto__: Object.prototype,
31
32 get model() {
Chris Craik44c28202015-05-12 17:25:16 -070033 return this.selectionController_.model;
Chris Craikb122baf2015-03-05 13:58:42 -080034 },
35
Chris Craik44c28202015-05-12 17:25:16 -070036 get selectionController() {
37 return this.selectionController_;
Chris Craikb122baf2015-03-05 13:58:42 -080038 },
39
40 get filterText() {
41 return this.filterText_;
42 },
43
44 set filterText(f) {
45 if (f == this.filterText_)
46 return;
47 this.filterText_ = f;
48 this.filterHitsDirty_ = true;
49 },
50
51 getFilterPromise_: function(filterText) {
Chris Craik44c28202015-05-12 17:25:16 -070052 if (!this.selectionController_)
Chris Craikb122baf2015-03-05 13:58:42 -080053 return;
54 var promise = Promise.resolve();
55
Chris Craik44c28202015-05-12 17:25:16 -070056
57 var sc = this.selectionController_;
58
Chris Craikb122baf2015-03-05 13:58:42 -080059 var filter = new tv.c.TitleOrCategoryFilter(filterText);
60 var filterHits = new tv.c.Selection();
Chris Craik44c28202015-05-12 17:25:16 -070061 var filterTask = sc.addAllEventsMatchingFilterToSelectionAsTask(
62 filter, filterHits);
Chris Craikb122baf2015-03-05 13:58:42 -080063 promise = Task.RunWhenIdle(filterTask);
64 promise.then(function() {
65 this.filterHitsDirty_ = false;
66 this.filterHits_ = filterHits;
Chris Craik44c28202015-05-12 17:25:16 -070067 sc.findTextChangedTo(filterHits);
Chris Craikb122baf2015-03-05 13:58:42 -080068 }.bind(this));
69 return promise;
70 },
71
72 clearFindSelections_: function() {
Chris Craik44c28202015-05-12 17:25:16 -070073 this.selectionController_.findTextCleared();
Chris Craikb122baf2015-03-05 13:58:42 -080074 },
75
76 /**
77 * Updates the filter hits based on the current filtering settings. Returns
78 * a promise which resolves when |filterHits| has been refreshed.
79 */
80 updateFilterHits: function() {
81 var promise = Promise.resolve();
82
83 if (!this.filterHitsDirty_)
84 return promise;
85
86 this.filterHits_ = new tv.c.Selection();
87 this.currentHitIndex_ = -1;
88
89 // Try constructing a UIState from the filterText.
90 // UIState.fromUserFriendlyString will throw an error only if the string
91 // is syntactically correct to a UI state string but with invalid values.
92 // It will return undefined if there is no syntactic match.
93 var stateFromString;
94 try {
Chris Craik44c28202015-05-12 17:25:16 -070095 stateFromString = this.selectionController_.uiStateFromString(
96 this.filterText);
Chris Craikb122baf2015-03-05 13:58:42 -080097 } catch (e) {
98 var overlay = new tv.b.ui.Overlay();
99 overlay.textContent = e.message;
100 overlay.title = 'UI State Navigation Error';
101 overlay.visible = true;
102 return promise;
103 }
104
105 if (stateFromString !== undefined) {
Chris Craik44c28202015-05-12 17:25:16 -0700106 this.selectionController_.navToPosition(stateFromString, true);
Chris Craikb122baf2015-03-05 13:58:42 -0800107 } else {
108 // filterText is not a navString here -- proceed with find and filter.
109 if (this.filterText.length === 0)
110 this.clearFindSelections_();
111 else
112 promise = this.getFilterPromise_(this.filterText);
113 }
114 return promise;
115 },
116
117 /**
118 * Returns the most recent filter hits as a tv.c.Selection. Call
119 * |updateFilterHits| to ensure this is up to date after the filter
120 * settings have been changed.
121 */
122 get filterHits() {
123 return this.filterHits_;
124 },
125
126 get currentHitIndex() {
127 return this.currentHitIndex_;
128 },
129
130 find_: function(dir) {
131 var firstHit = this.currentHitIndex_ === -1;
132 if (firstHit && dir < 0)
133 this.currentHitIndex_ = 0;
134
135 var N = this.filterHits.length;
136 this.currentHitIndex_ = (this.currentHitIndex_ + dir + N) % N;
137
Chris Craik44c28202015-05-12 17:25:16 -0700138 if (!this.selectionController_)
Chris Craikb122baf2015-03-05 13:58:42 -0800139 return;
140
Chris Craik44c28202015-05-12 17:25:16 -0700141 this.selectionController_.findFocusChangedTo(
142 this.filterHits.subSelection(this.currentHitIndex_, 1));
Chris Craikb122baf2015-03-05 13:58:42 -0800143 },
144
145 findNext: function() {
146 this.find_(1);
147 },
148
149 findPrevious: function() {
150 this.find_(-1);
151 },
152
153 reset: function() {
154 this.filterText_ = '';
155 this.filterHitsDirty_ = true;
156 }
157 };
158
159 return {
160 FindController: FindController
161 };
162});
163</script>