Skip to content

Instantly share code, notes, and snippets.

@marcocerna
Last active September 25, 2015 23:31
Show Gist options
  • Save marcocerna/f272de020d605ca5e900 to your computer and use it in GitHub Desktop.
Save marcocerna/f272de020d605ca5e900 to your computer and use it in GitHub Desktop.
Base for TVE
{
"resultList": [
{
"trioObject": {
"category": [
{
"categoryId": "tivo:ca.413855",
"label": "Reality",
"type": "category"
},
{
"categoryId": "tivo:ca.413896",
"image": [
],
"label": "Interests",
"type": "category"
}
],
"collectionId": "tivo:cl.2017587",
"collectionType": "series",
"credit": [
],
"description": "Strangers, cut off from the outside world, coexist in an isolated house.",
"episodic": true,
"internalRating": [
{
"ratingTypeId": "tivo:rt.6",
"ratingValueId": "tivo:rv.4",
"type": "internalRating"
}
],
"rating": [
{
"type": "typedTvRating",
"value": "14"
},
{
"type": "typedCanadaRating",
"value": "pg"
}
],
"title": "Big Brother",
"tvRating": "14",
"type": "collection"
},
"childCategories": [
{
"categoryId": "tivo:ca.413855",
"name": "Reality"
}
]
},
{
"trioObject": {
"category": [
{
"categoryId": "tivo:ca.413855",
"label": "Reality",
"type": "category"
},
{
"categoryId": "tivo:ca.413896",
"image": [
],
"label": "Interests",
"type": "category"
}
],
"collectionId": "tivo:cl.2017587",
"collectionType": "series",
"credit": [
],
"description": "Strangers, cut off from the outside world, coexist in an isolated house.",
"episodic": true,
"internalRating": [
{
"ratingTypeId": "tivo:rt.6",
"ratingValueId": "tivo:rv.4",
"type": "internalRating"
}
],
"rating": [
{
"type": "typedTvRating",
"value": "14"
},
{
"type": "typedCanadaRating",
"value": "pg"
}
],
"title": "Big Brother",
"tvRating": "14",
"type": "collection"
},
"childCategories": [
{
"categoryId": "tivo:ca.413855",
"name": "Reality"
}
]
},
{
"trioObject": {
"category": [
{
"categoryId": "tivo:ca.413855",
"label": "Reality",
"type": "category"
},
{
"categoryId": "tivo:ca.413896",
"image": [
],
"label": "Interests",
"type": "category"
}
],
"collectionId": "tivo:cl.2017587",
"collectionType": "series",
"credit": [
],
"description": "Strangers, cut off from the outside world, coexist in an isolated house.",
"episodic": true,
"internalRating": [
{
"ratingTypeId": "tivo:rt.6",
"ratingValueId": "tivo:rv.4",
"type": "internalRating"
}
],
"rating": [
{
"type": "typedTvRating",
"value": "14"
},
{
"type": "typedCanadaRating",
"value": "pg"
}
],
"title": "Big Brother",
"tvRating": "14",
"type": "collection"
},
"childCategories": [
{
"categoryId": "tivo:ca.413855",
"name": "Reality"
}
]
}
]
}
<!DOCTYPE html>
<html>
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/processing.js/1.4.1/processing-api.min.js"></script>
<meta name="description" content="Slider Info/Panel Demo" />
<meta charset="utf-8">
<meta content="070aa09f-9afd-440d-a854-d2bdb4c93f25" name="_csrf">
<meta content="X-CSRF-TOKEN" name="_csrf_header">
<title>Hydra Search Bar Demo</title>
<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro' rel='stylesheet' type='text/css'>
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/normalize/2.1.3/normalize.css">
<link rel='stylesheet' type="text/css" href="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/css/vendor/qtip2/jquery.qtip.css">
<link rel="stylesheet" type="text/css" href="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/vendor/ezmark/css/ezmark.css">
<link rel='stylesheet' type="text/css" href="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/css/vendor/jquery-ui/jquery-ui.css">
<link rel="stylesheet" type="text/css" href="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/css/common.css">
<link rel="stylesheet" type="text/css" href="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/tivo/css/theme.css">
<link rel="stylesheet" type="text/css" href="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/hydra/css/core.css">
<link rel="stylesheet" type="text/css" href="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/hydra/css/app.css">
<link rel="stylesheet" type="text/css" href="searchbar.css">
<!-- here's a sample how to make a template -->
<script id="feed-template" type="text/html">
<li><div class="img-container"><img src=""/></div>
</li>
</script>
<!-- stub out appManager -->
<script type="text/javascript">
window.appManager = {
initializeNewDomContent: function(){}
}
</script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.js"></script>
<script type="text/javascript" src="http://cdn.jsdelivr.net/underscorejs/1.4.4/underscore.js"></script>
<script type="text/javascript" src="http://cdn.jsdelivr.net/backbonejs/1.0.0/backbone.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/vendor/class.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/vendor/mustache/mustache.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/vendor/jquery.mustache/jquery.mustache.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/vendor/moment/moment.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/vendor/jquery.highlighter.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/utils/tve-app.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/managers/template_manager.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/managers/i18n_manager.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com//assets/tve/common/i18n/messages_en.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com//assets/tve/tivo/i18n/messages_en_US_tivo.js"></script>
<script type="text/javascript">i18n.setLocale("en_US_tivo");</script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/actions/always_available_action.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/actions/guest_check_panel.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/actions/watch_now_action.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/actions/get_onepass_action.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/widgets/button_stack.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/widgets/actions_button_list.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/widgets/content_detail_panel.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/widgets/content_image.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/widgets/image_with_fallback.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/widgets/content_details.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/widgets/branding_partner_list.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/widgets/feed_list.js"></script>
<script type="text/javascript" src="http://tve-ws-stdev-tivo.elasticbeanstalk.com/assets/tve/common/js/widgets/view_toggle.js"></script>
<script type="text/javascript" src="https://tve-web.s3.amazonaws.com/jquery.scrollintoview.js"></script>
<script type="text/javascript" src="http://ricostacruz.com/jquery.transit/jquery.transit.js"></script>
<script type="text/javascript" src="searchbar.js"></script>
<script type="text/javascript">
debug=console;
TVE_mso='tivo';
TVE_dynamicImageBaseUrl = 'http://i-stg.tivo.com/images-staging/';
TVE_channelLogoBaseUrl = 'http://i.tivo.com/images-static/logos/';
TVE_staticImageBaseUrl = 'http://i.tivo.com/images-static/';
TVE_imageBaseURL = '/assets/tve/tivo/img';
</script>
</head>
<body>
<div id="main-content">
<div class="demo-container">
<h1>Hydra Search Bar Demo</h1>
<div class="top-info-bar">
<ul class="links">
<li>Fake Link 1</li>
<li>Fake Link 2</li>
<li>Fake Link 3</li>
</ul>
<div class="js-search-container search-container">
<div class="search-input-wrapper primary-background">
<input class="js-search-input input-secondary transparent-background" type="text" autocomplete="on"/>
<span class="search-input-icon image-search"></span>
</div>
<div class="js-search-button search-button-wrapper">
<span class="search-button-icon image-search"></span>
<span class="search-button-label">Search</span>
</div>
</div>
</div>
</div>
</div>
/*Search input*/
.search-input-wrapper {
border-radius: 4px;
display: none;
margin: 4px 5px 0 0;
width: 250px; /*Wider than input to hold the search/cancel icon*/
}
.search-input-wrapper .ui-autocomplete-input {
/*This should be common to all input fields*/
border: medium none;
height: 2.25em;
margin: 0;
padding: 5px 0 5px 5px;
/*This is unique to this input*/
display: inline-block;
width: 215px;
}
.search-input-icon {
display: none;
margin: 0px;
}
/*Search button*/
.search-button-icon {
cursor: pointer;
margin-bottom: 5px;
}
.search-button-wrapper {
display: inline-block;
margin-top: 5px;
}
.search-button-label {
float: right;
padding: 3px 8px;
}
/*Search animation*/
.search-bar-open .search-input-icon {
display: inline-block;
}
.search-animation-running .search-input-icon {
display: none;
}
.search-animation-running .search-button-wrapper,
.search-bar-open .search-button-wrapper {
display: none;
}
/*Containers*/
.search-container {
float: right;
}
.links {
float: right;
padding: 8px 0;
}
.demo-container {
border: 3px solid white;
height: 120px;
margin: 20px;
padding: 20px;
width: 700px;
}
var templateHtml = '<li><a data-destination="{{contentUrl}}" class="js-link"><div class="search-result-container"><div class="search-result-text-content"><div class="js-title content-title link-secondary menu-link"></div> <div class="js-episode-title episode-title text-primary"></div><div class="js-tv-rating text-secondary hide-final-separator"></div><div class="js-star-rating"></div><div class="js-genre-list text-secondary hide-final-separator"></div></div></div></a></li>';
var titleHtml = '<span class="ellipses-truncated-text">{{title}}</span><span>{{movieYear}}</span>';
$(document).ready(function() {
$.widget("tivo.searchbar", {
options: {
dataUrl: TVE.util.tveAppPath + '/search/suggestions',
maxResults: 20,
placeholderText: 'Shows, people, channels',
searchInputSelector: '.js-search-input',
searchButtonSelector: '.js-search-button'
},
_init: function() {
var self = this;
var opts = this.options;
var $searchContainer = $(this.element);
var $searchInput = $(opts.searchInputSelector, $searchContainer);
$searchInput.autocomplete({
minLength: 2,
appendTo: '.js-search-container',
source: $.proxy(self._autoCompleteSource, self),
position: {
my : "right top",
at: "right bottom"
},
select: function(event, ui) {
if (ui.item.contentUrl) {
appManager.navigate(ui.item.contentUrl, {trigger: true});
}
},
open: function(event, ui) {
var $autocomplete = $('.ui-autocomplete', $searchContainer);
appManager.initializeNewDomContent($autocomplete);
}
});
// Override default render item method with our custom one.
var autoComplete = $searchInput.data("uiAutocomplete");
if (autoComplete) {
autoComplete._renderItem = self._renderAutoCompleteItem;
}
this._addSearchbarToggle();
$searchInput.val(opts.placeholderText);
$searchInput.keydown(function() {
if ($searchInput.val() === opts.placeholderText) {
$searchInput.val('');
}
});
},
_addSearchbarToggle: function() {
var opts = this.options;
var $searchContainer = $(this.element);
var $searchInput = $(opts.searchInputSelector, $searchContainer);
var $searchInputWrapper = $('.search-input-wrapper');
var $searchButton = $(opts.searchButtonSelector, $searchContainer);
var focusoutEventInProgress = false;
$searchButton.on('click', function() {
var isSearchbarHidden = $searchInputWrapper.css('display') === 'none';
if (!focusoutEventInProgress && isSearchbarHidden) {
$searchContainer.addClass('search-animation-running');
$searchInputWrapper.animate({width:'toggle'}, function() {
$searchInputWrapper.css('display', 'inline-block');
$searchInput.focus().val(opts.placeholderText);
$searchContainer.removeClass('search-animation-running').addClass('search-bar-open');
})
}
})
$searchContainer.on('focusout', function() {
focusoutEventInProgress = true;
$searchContainer.addClass('search-animation-running');
$searchInputWrapper.animate({width:'toggle'}, function() {
$searchInput.val(opts.placeholderText);
$searchContainer.removeClass('search-animation-running search-bar-open');
});
// While searchbar is open, clicking the search button triggers focusout and click events.
// In that case, focusout closes the searchbar, and click immediately reopens it.
// To prevent this, added a timeout so that click event immediately following focusout gets ignored.
setTimeout(function() {
focusoutEventInProgress = false;
}, 100);
})
},
_autoCompleteSource: function(request, responseCallback) {
var dataPromise = $.get(this.options.dataUrl, {
keyword: request.term,
count: this.options.maxResults
});
dataPromise.done(function(data) {
var resultList = data.resultList || [];
responseCallback(resultList.length ? resultList : ["N"]);
});
dataPromise.error(function(jqXHR, status, exception) {
debug.warn("Error on /search/suggestions: " + status);
responseCallback( ["N"] );
});
},
_renderAutoCompleteItem: function(ul, item) {
var searchTerm = $(this.options.searchInputSelector).val();
var html;
var $autocompleteItem;
if (item.value !== undefined && item.value === "N") {
// If no search results, add this html.
html = Templates.render('search-list-no-results', i18n.allMsgs());
$autocompleteItem = $(html).appendTo(ul);
} else if (item.trioObject.personId) {
// If personId exists, we have a person result. Use this html template and apply the personPanel
// widget.
item.contentUrl = '#person/' + item.trioObject.personId;
html = Templates.render('search-list-person-result');
$autocompleteItem = $(html).appendTo(ul);
$autocompleteItem.personPanel({
personId: item.trioObject.personId,
highlightText: searchTerm,
highlightClass: 'bold-text',
roleDisplayLimit: 2,
personPageLinkSelector: '.js-person-link'
});
} else {
// For all other results, use this code. This will be removed, as more search results come back
// as domain models.
if (item.trioObject.type === 'channel') {
item.contentUrl = '#guide/' + item.trioObject.channelNumber;
html = Templates.render('search-list-channel-result', item, item.trioObject);
} else {
item.contentUrl = '#info/' + item.trioObject.collectionId;
html = Templates.render('search-list-results', item);
}
$autocompleteItem = $(html).appendTo(ul);
$autocompleteItem.find('.js-image-data').contentImage({
collectionId: item.trioObject.collectionId,
collectionType: item.trioObject.collectionType,
categories: item.childCategories
});
$autocompleteItem.find('.js-title').contentTitle({
contentDetails: item.trioObject
});
// It seems that most of the time, movies come back as 'collection', but occasionally they come back as
// 'content'. I *think* it might be when text is matched inside its description rather than by title.
if (item.trioObject.type === 'content' && item.trioObject.collectionType !== 'movie') {
$autocompleteItem.find('.js-episode-title').episodeTitle({
contentDetails: item.trioObject
});
}
if (item.trioObject.collectionType === 'movie') {
$autocompleteItem.find('.js-star-rating').starRating({
starRating: item.trioObject.starRating
});
} else {
$autocompleteItem.find('.js-tv-rating').contentTvRating({
tvRating: item.trioObject.tvRating
});
}
$autocompleteItem.find('.js-genre-list').contentGenreList({
genreListModel: item.trioObject.category,
maxCategories: 1
});
$autocompleteItem.find('.js-channel-logo').channelLogo({
channelLogoUrl: item.channelLogoUrl
});
$autocompleteItem.find('.js-channel').contentChannel({
channelInfo: item.trioObject
});
// Highlight the search keyword. This should only apply to the title text.
$autocompleteItem.find('.js-title .ellipses-truncated-text,.menu-link').highlight(searchTerm, 'bold-text');
}
return $autocompleteItem;
}
});
Templates.add('search-list-results', templateHtml);
Templates.add('content-details-title', titleHtml);
$('.js-search-container').searchbar({dataUrl: 'data.json'});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment