blob: 1d5ddaef15637a35fa0c432bb25b4ca9f7d36566 [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright (c) 2012 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="/base/task.html">
<link rel="import" href="/core/filter.html">
<link rel="import" href="/core/selection.html">
<script>
'use strict';
/**
* @fileoverview FindController.
*/
tv.exportTo('tv.c', function() {
var Task = tv.b.Task;
function FindController(selectionController) {
this.selectionController_ = selectionController;
this.filterText_ = '';
this.filterHits_ = new tv.c.Selection();
this.filterHitsDirty_ = true;
this.currentHitIndex_ = -1;
};
FindController.prototype = {
__proto__: Object.prototype,
get model() {
return this.selectionController_.model;
},
get selectionController() {
return this.selectionController_;
},
get filterText() {
return this.filterText_;
},
set filterText(f) {
if (f == this.filterText_)
return;
this.filterText_ = f;
this.filterHitsDirty_ = true;
},
getFilterPromise_: function(filterText) {
if (!this.selectionController_)
return;
var promise = Promise.resolve();
var sc = this.selectionController_;
var filter = new tv.c.TitleOrCategoryFilter(filterText);
var filterHits = new tv.c.Selection();
var filterTask = sc.addAllEventsMatchingFilterToSelectionAsTask(
filter, filterHits);
promise = Task.RunWhenIdle(filterTask);
promise.then(function() {
this.filterHitsDirty_ = false;
this.filterHits_ = filterHits;
sc.findTextChangedTo(filterHits);
}.bind(this));
return promise;
},
clearFindSelections_: function() {
this.selectionController_.findTextCleared();
},
/**
* Updates the filter hits based on the current filtering settings. Returns
* a promise which resolves when |filterHits| has been refreshed.
*/
updateFilterHits: function() {
var promise = Promise.resolve();
if (!this.filterHitsDirty_)
return promise;
this.filterHits_ = new tv.c.Selection();
this.currentHitIndex_ = -1;
// Try constructing a UIState from the filterText.
// UIState.fromUserFriendlyString will throw an error only if the string
// is syntactically correct to a UI state string but with invalid values.
// It will return undefined if there is no syntactic match.
var stateFromString;
try {
stateFromString = this.selectionController_.uiStateFromString(
this.filterText);
} catch (e) {
var overlay = new tv.b.ui.Overlay();
overlay.textContent = e.message;
overlay.title = 'UI State Navigation Error';
overlay.visible = true;
return promise;
}
if (stateFromString !== undefined) {
this.selectionController_.navToPosition(stateFromString, true);
} else {
// filterText is not a navString here -- proceed with find and filter.
if (this.filterText.length === 0)
this.clearFindSelections_();
else
promise = this.getFilterPromise_(this.filterText);
}
return promise;
},
/**
* Returns the most recent filter hits as a tv.c.Selection. Call
* |updateFilterHits| to ensure this is up to date after the filter
* settings have been changed.
*/
get filterHits() {
return this.filterHits_;
},
get currentHitIndex() {
return this.currentHitIndex_;
},
find_: function(dir) {
var firstHit = this.currentHitIndex_ === -1;
if (firstHit && dir < 0)
this.currentHitIndex_ = 0;
var N = this.filterHits.length;
this.currentHitIndex_ = (this.currentHitIndex_ + dir + N) % N;
if (!this.selectionController_)
return;
this.selectionController_.findFocusChangedTo(
this.filterHits.subSelection(this.currentHitIndex_, 1));
},
findNext: function() {
this.find_(1);
},
findPrevious: function() {
this.find_(-1);
},
reset: function() {
this.filterText_ = '';
this.filterHitsDirty_ = true;
}
};
return {
FindController: FindController
};
});
</script>