blob: 1d955478add035b84199e59b8fa4cacf8403356c [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">
<link rel="import" href="/core/ui_state.html">
<script>
'use strict';
/**
* @fileoverview FindController.
*/
tv.exportTo('tv.c', function() {
var Task = tv.b.Task;
function FindController() {
this.timeline_ = undefined;
this.filterText_ = '';
this.filterHits_ = new tv.c.Selection();
this.filterHitsDirty_ = true;
this.currentHitIndex_ = -1;
};
FindController.prototype = {
__proto__: Object.prototype,
get model() {
if (!this.timeline_)
return;
return this.timeline_.model;
},
get timeline() {
return this.timeline_;
},
set timeline(t) {
this.timeline_ = t;
this.filterHitsDirty_ = true;
},
get filterText() {
return this.filterText_;
},
set filterText(f) {
if (f == this.filterText_)
return;
this.filterText_ = f;
this.filterHitsDirty_ = true;
},
getFilterPromise_: function(filterText) {
if (!this.timeline_)
return;
var promise = Promise.resolve();
var filter = new tv.c.TitleOrCategoryFilter(filterText);
var filterHits = new tv.c.Selection();
var filterTask =
this.timeline.addAllObjectsMatchingFilterToSelectionAsTask(
filter, filterHits);
promise = Task.RunWhenIdle(filterTask);
promise.then(function() {
this.filterHitsDirty_ = false;
this.filterHits_ = filterHits;
this.timeline.setHighlightAndClearSelection(filterHits);
}.bind(this));
return promise;
},
clearFindSelections_: function() {
this.timeline.setHighlightAndClearSelection(new tv.c.Selection());
this.timeline.removeXNavStringMarker();
},
/**
* 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 = tv.c.UIState.fromUserFriendlyString(
this.model, this.timeline.viewport, 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.timeline.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.timeline)
return;
this.timeline.selection =
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>