Migrating web search api to custom search api on templates-sdk

am: 843649b

* commit '843649bab10d2e6b8c9791132de7b6217dabed59':
  Migrating web search api to custom search api on templates-sdk

Change-Id: I7f85542e8fd0534ac492e848c7b3070dc056cb43
This commit is contained in:
Amanda Kassay 2016-03-31 16:46:46 +00:00 committed by android-build-merger
commit e774264f51
2 changed files with 295 additions and 138 deletions

View File

@ -732,7 +732,7 @@ a.back-link {
text-align:center; text-align:center;
width: 50%; width: 50%;
} }
.training-nav-top a.prev-page-link { .training-nav-top a.prev-page-link {
padding-left: 15px; padding-left: 15px;
text-align: left; text-align: left;
@ -840,7 +840,7 @@ a.back-link {
margin: 0 0 6px; margin: 0 0 6px;
line-height: 16px; line-height: 16px;
} }
/* Class colors */ /* Class colors */
ol.class-list li:nth-child(10n+1) .title { ol.class-list li:nth-child(10n+1) .title {
background: #00bcd4; background: #00bcd4;
@ -872,7 +872,7 @@ a.back-link {
ol.class-list li:nth-child(10n+10) .title { ol.class-list li:nth-child(10n+10) .title {
background: #7e57c2; background: #7e57c2;
} }
@media (max-width: 719px) { @media (max-width: 719px) {
ol.class-list ol, ol.class-list ol,
ol.class-list .description { ol.class-list .description {
@ -6376,7 +6376,7 @@ div.jd-descr > .resource-widget[data-section=distribute\/tools] .section-card-me
.dac-button.dac-raised.dac-primary, .landing-secondary, .button { .dac-button.dac-raised.dac-primary, .landing-secondary, .button {
background-color: #039bef; } background-color: #039bef; }
.dac-button.dac-raised.dac-primary:hover, .landing-secondary:hover, .button:hover { .dac-button.dac-raised.dac-primary:hover, .landing-secondary:hover, .button:hover {
background-color: #0288d1; background-color: #0288d1;
color:#fff; } color:#fff; }
.dac-button.dac-raised.dac-primary:active, .landing-secondary:active, .button:active { .dac-button.dac-raised.dac-primary:active, .landing-secondary:active, .button:active {
background-color: #0277bd; background-color: #0277bd;
@ -8874,4 +8874,85 @@ $spritesheet: width height image $spritesheet-sprites;
.dac-hero-cta.mprev { .dac-hero-cta.mprev {
white-space:nowrap; white-space:nowrap;
} }
} }
/** Custom search API styles */
.dac-custom-search {
background: #fff;
margin: 0 -10px;
padding: 20px 10px;
z-index: 1;
}
.dac-custom-search-section-title {
color: #505050;
}
.dac-custom-search-entry {
margin-bottom: 36px;
margin-top: 24px;
}
.dac-custom-search-image {
background-size: cover;
height: 112px;
}
@media (max-width: 719px) {
.dac-custom-search-image {
display: none;
}
}
.dac-custom-search-title {
color: #333;
font-size: 14px;
font-weight: 700;
line-height: 24px;
margin: 0;
padding: 0;
}
.dac-custom-search-title a {
color: inherit;
}
.dac-custom-search-section {
color: #999;
font-size: 16px;
font-variant: small-caps;
font-weight: 700;
margin: -5px 0 0 0;
}
.dac-custom-search-snippet {
color: #666;
margin: 0;
}
.dac-custom-search-link {
font-weight: 500;
word-wrap: break-word;
width: 100%;
}
.dac-custom-search-load-more {
background: none;
border: none;
color: #333;
cursor: pointer;
display: block;
font-size: 14px;
font-weight: 700;
margin: 75px auto;
outline: none;
padding: 10px;
}
.dac-custom-search-load-more:hover {
opacity: 0.7;
}
.dac-custom-search-no-results {
color: #999;
}

View File

@ -2548,12 +2548,13 @@ function search_focus_changed(obj, focused)
function submit_search() { function submit_search() {
var query = document.getElementById('search_autocomplete').value; var query = document.getElementById('search_autocomplete').value;
location.hash = 'q=' + query; location.hash = 'q=' + query;
loadSearchResults(); searchControl.query = query;
searchControl.init();
searchControl.trackSearchRequest(query);
$("#searchResults").slideDown('slow', setStickyTop); $("#searchResults").slideDown('slow', setStickyTop);
return false; return false;
} }
function hideResults() { function hideResults() {
$("#searchResults").slideUp('fast', setStickyTop); $("#searchResults").slideUp('fast', setStickyTop);
$("#search-close").addClass("hide"); $("#search-close").addClass("hide");
@ -2562,119 +2563,248 @@ function hideResults() {
$("#search_autocomplete").val("").blur(); $("#search_autocomplete").val("").blur();
// reset the ajax search callback to nothing, so results don't appear unless ENTER // reset the ajax search callback to nothing, so results don't appear unless ENTER
searchControl.setSearchStartingCallback(this, function(control, searcher, query) {}); searchControl.reset();
// forcefully regain key-up event control (previously jacked by search api)
$("#search_autocomplete").keyup(function(event) {
return search_changed(event, false, toRoot);
});
return false; return false;
} }
/* ########################################################## */ /* ########################################################## */
/* ################ CUSTOM SEARCH ENGINE ################## */ /* ################ CUSTOM SEARCH ENGINE ################## */
/* ########################################################## */ /* ########################################################## */
var searchControl = null;
var dacsearch = dacsearch || {};
var searchControl; /**
google.load('search', '1', {"callback" : function() { * The custom search engine API.
searchControl = new google.search.SearchControl(); * @constructor
} }); */
dacsearch.CustomSearchEngine = function() {
/**
* The last response from Google CSE.
* @private {Object}
*/
this.resultQuery_ = {};
function loadSearchResults() { /** @private {?Element} */
document.getElementById("search_autocomplete").style.color = "#000"; this.searchResultEl_ = null;
searchControl = new google.search.SearchControl(); /** @private {?Element} */
this.searchInputEl_ = null;
// use our existing search form and use tabs when multiple searchers are used /** @private {string} */
drawOptions = new google.search.DrawOptions(); this.query = '';
drawOptions.setDrawMode(google.search.SearchControl.DRAW_MODE_TABBED); };
drawOptions.setInput(document.getElementById("search_autocomplete"));
// configure search result options /**
searchOptions = new google.search.SearcherOptions(); * Initializes DAC's Google custom search engine.
searchOptions.setExpandMode(GSearchControl.EXPAND_MODE_OPEN); * @export
*/
dacsearch.CustomSearchEngine.prototype.init = function() {
this.searchResultEl_ = $('#leftSearchControl');
this.searchResultEl_.empty();
this.searchInputEl_ = $('#search_autocomplete');
this.searchInputEl_.focus().val(this.query);
this.getResults_();
this.bindEvents_();
};
// configure each of the searchers, for each tab
devSiteSearcher = new google.search.WebSearch();
devSiteSearcher.setUserDefinedLabel("All");
devSiteSearcher.setSiteRestriction("001482626316274216503:zu90b7s047u");
designSearcher = new google.search.WebSearch(); /**
designSearcher.setUserDefinedLabel("Design"); * Binds the keyup event to the search input.
designSearcher.setSiteRestriction("http://developer.android.com/design/"); * @private
*/
dacsearch.CustomSearchEngine.prototype.bindEvents_ = function() {
this.searchInputEl_.keyup(this.debounce_(function(e) {
var code = e.which;
if (code != 13) {
this.query = this.searchInputEl_.val();
location.hash = 'q=' + encodeURI(this.query);
this.searchResultEl_.empty();
this.getResults_();
}
}.bind(this), 250));
};
trainingSearcher = new google.search.WebSearch();
trainingSearcher.setUserDefinedLabel("Training");
trainingSearcher.setSiteRestriction("http://developer.android.com/training/");
guidesSearcher = new google.search.WebSearch(); /**
guidesSearcher.setUserDefinedLabel("Guides"); * Resets the search control.
guidesSearcher.setSiteRestriction("http://developer.android.com/guide/"); */
dacsearch.CustomSearchEngine.prototype.reset = function() {
this.query = '';
this.searchInputEl_.off('keyup');
this.searchResultEl_.empty();
this.updateResultTitle_();
};
referenceSearcher = new google.search.WebSearch();
referenceSearcher.setUserDefinedLabel("Reference");
referenceSearcher.setSiteRestriction("http://developer.android.com/reference/");
googleSearcher = new google.search.WebSearch(); /**
googleSearcher.setUserDefinedLabel("Google Services"); * Updates the search query text at the top of the results.
googleSearcher.setSiteRestriction("http://developer.android.com/google/"); * @private
*/
dacsearch.CustomSearchEngine.prototype.updateResultTitle_ = function() {
$("#searchTitle").html("Results for <em>" + this.query + "</em>");
};
blogSearcher = new google.search.WebSearch();
blogSearcher.setUserDefinedLabel("Blog");
blogSearcher.setSiteRestriction("http://android-developers.blogspot.com");
// add each searcher to the search control /**
searchControl.addSearcher(devSiteSearcher, searchOptions); * Makes the CSE api call and gets the results.
searchControl.addSearcher(designSearcher, searchOptions); * @param {number=} opt_start The optional start index.
searchControl.addSearcher(trainingSearcher, searchOptions); * @private
searchControl.addSearcher(guidesSearcher, searchOptions); */
searchControl.addSearcher(referenceSearcher, searchOptions); dacsearch.CustomSearchEngine.prototype.getResults_ = function(opt_start) {
searchControl.addSearcher(googleSearcher, searchOptions); var lang = getLangPref();
searchControl.addSearcher(blogSearcher, searchOptions); // Fix zh-cn to be zh-CN.
lang = lang.replace(/-\w+/, function(m) { return m.toUpperCase(); });
var cseUrl = 'https://content.googleapis.com/customsearch/v1?';
var searchParams = {
cx: '000521750095050289010:zpcpi1ea4s8',
key: 'AIzaSyCFhbGnjW06dYwvRCU8h_zjdpS4PYYbEe8',
q: this.query,
start: opt_start || 1,
num: 6,
hl: lang,
fields: 'queries,items(pagemap,link,title,htmlSnippet,formattedUrl)'
};
// configure result options $.get(cseUrl + $.param(searchParams), function(data) {
searchControl.setResultSetSize(google.search.Search.LARGE_RESULTSET); this.resultQuery_ = data;
searchControl.setLinkTarget(google.search.Search.LINK_TARGET_SELF); this.renderResults_(data);
searchControl.setTimeoutInterval(google.search.SearchControl.TIMEOUT_SHORT); this.updateResultTitle_(this.query);
searchControl.setNoResultsString(google.search.SearchControl.NO_RESULTS_DEFAULT_STRING); }.bind(this));
};
// upon ajax search, refresh the url and search title
searchControl.setSearchStartingCallback(this, function(control, searcher, query) {
updateResultTitle(query);
var query = document.getElementById('search_autocomplete').value;
location.hash = 'q=' + query;
});
// once search results load, set up click listeners /**
searchControl.setSearchCompleteCallback(this, function(control, searcher, query) { * Renders the results.
addResultClickListeners(); * @private
}); */
dacsearch.CustomSearchEngine.prototype.renderResults_ = function(results) {
var el = this.searchResultEl_;
// draw the search results box if (!results.items) {
searchControl.draw(document.getElementById("leftSearchControl"), drawOptions); el.append($('<div>').text('No results'));
return;
}
// get query and execute the search for (var i = 0; i < results.items.length; i++) {
searchControl.execute(decodeURI(getQuery(location.hash))); var item = results.items[i];
var hasImage = item.pagemap && item.pagemap.cse_thumbnail;
var sectionMatch = item.link.match(/developer\.android\.com\/(\w*)/);
var section = (sectionMatch && sectionMatch[1]) || 'blog';
document.getElementById("search_autocomplete").focus(); var entry = $('<div>').addClass('dac-custom-search-entry cols');
addTabListeners();
} if (hasImage) {
// End of loadSearchResults var image = item.pagemap.cse_thumbnail[0];
entry.append($('<div>').addClass('col-1of6')
.append($('<div>').addClass('dac-custom-search-image').css(
'background-image', 'url(' + image.src + ')')));
}
var linkTitleEl = $('<a>').text(item.title).attr('href', item.link);
linkTitleEl.click(function(e) {
ga('send', 'event', 'Google Custom Search',
'clicked: ' + linkTitleEl.attr('href'),
'query: ' + $("#search_autocomplete").val().toLowerCase());
});
var linkUrlEl = $('<a>').addClass('dac-custom-search-link').text(
item.formattedUrl).attr('href', item.link);
linkUrlEl.click(function(e) {
ga('send', 'event', 'Google Custom Search',
'clicked: ' + linkUrlEl.attr('href'),
'query: ' + $("#search_autocomplete").val().toLowerCase());
});
entry.append($('<div>').addClass(hasImage ? 'col-5of6' : 'col-6of6')
.append($('<p>').addClass('dac-custom-search-section').text(section))
.append(
linkTitleEl.wrap('<h2>').parent().addClass('dac-custom-search-title'))
.append($('<p>').addClass('dac-custom-search-snippet')
.html(item.htmlSnippet.replace(/<br>/g, ''))).append(linkUrlEl));
el.append(entry);
}
if ($('#dac-custom-search-load-more')) {
$('#dac-custom-search-load-more').remove();
}
if (results.queries.nextPage) {
var loadMoreButton = $('<button id="dac-custom-search-load-more">')
.addClass('dac-custom-search-load-more')
.text('Load more')
.click(function() {
this.loadMoreResults_();
}.bind(this));
el.append(loadMoreButton);
}
};
/**
* Loads more results.
* @private
*/
dacsearch.CustomSearchEngine.prototype.loadMoreResults_ = function() {
this.query = this.resultQuery_.queries.request[0].searchTerms;
var start = this.resultQuery_.queries.nextPage[0].startIndex;
var loadMoreButton = this.searchResultEl_.find(
'#dac-custom-search-load-more');
loadMoreButton.text('Loading more...');
this.getResults_(start);
this.trackSearchRequest(this.query + ' startIndex = ' + start);
};
/**
* Tracks a search request.
* @param {string} query The query for the request,
* includes start index if loading more results.
*/
dacsearch.CustomSearchEngine.prototype.trackSearchRequest = function(query) {
ga('send', 'event', 'Google Custom Search Submit', 'submit search query',
'query: ' + query);
};
/**
* Returns a function, that, as long as it continues to be invoked, will not
* be triggered. The function will be called after it stops being called for
* N milliseconds.
* @param {Function} func The function to debounce.
* @param {number} wait The number of milliseconds to wait before calling the function.
* @private
*/
dacsearch.CustomSearchEngine.prototype.debounce_ = function(func, wait) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
func.apply(context, args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
google.setOnLoadCallback(function(){ google.setOnLoadCallback(function(){
searchControl = new dacsearch.CustomSearchEngine();
if (location.hash.indexOf("q=") == -1) { if (location.hash.indexOf("q=") == -1) {
// if there's no query in the url, don't search and make sure results are hidden // if there's no query in the url, don't search and make sure results are hidden
$('#searchResults').hide(); $('#searchResults').hide();
return; return;
} else { } else {
// first time loading search results for this page // first time loading search results for this page
searchControl.query = decodeURI(location.hash.split('q=')[1]);
searchControl.init();
searchControl.trackSearchRequest(searchControl.query);
$('#searchResults').slideDown('slow', setStickyTop); $('#searchResults').slideDown('slow', setStickyTop);
$("#search-close").removeClass("hide"); $("#search-close").removeClass("hide");
loadSearchResults();
} }
}, true); }, true);
@ -2703,7 +2833,7 @@ $(window).hashchange( function(){
// If the hash isn't a search query or there's an error in the query, // If the hash isn't a search query or there's an error in the query,
// then adjust the scroll position to account for sticky header, then exit. // then adjust the scroll position to account for sticky header, then exit.
if ((location.hash.indexOf("q=") == -1) || (query == "undefined")) { if ((location.hash.indexOf("q=") == -1) || (searchControl.query == "undefined")) {
// If the results pane is open, close it. // If the results pane is open, close it.
if (!$("#searchResults").is(":hidden")) { if (!$("#searchResults").is(":hidden")) {
hideResults(); hideResults();
@ -2712,65 +2842,11 @@ $(window).hashchange( function(){
return; return;
} }
// Otherwise, we have a search to do
var query = decodeURI(getQuery(location.hash));
searchControl.execute(query);
$('#searchResults').slideDown('slow', setStickyTop); $('#searchResults').slideDown('slow', setStickyTop);
$("#search_autocomplete").focus(); $("#search_autocomplete").focus();
$("#search-close").removeClass("hide"); $("#search-close").removeClass("hide");
updateResultTitle(query);
}); });
function updateResultTitle(query) {
$("#searchTitle").html("Results for <em>" + escapeHTML(query) + "</em>");
}
// forcefully regain key-up event control (previously jacked by search api)
$("#search_autocomplete").keyup(function(event) {
return search_changed(event, false, toRoot);
});
// add event listeners to each tab so we can track the browser history
function addTabListeners() {
var tabHeaders = $(".gsc-tabHeader");
for (var i = 0; i < tabHeaders.length; i++) {
$(tabHeaders[i]).attr("id",i).click(function() {
/*
// make a copy of the page numbers for the search left pane
setTimeout(function() {
// remove any residual page numbers
$('#searchResults .gsc-tabsArea .gsc-cursor-box.gs-bidi-start-align').remove();
// move the page numbers to the left position; make a clone,
// because the element is drawn to the DOM only once
// and because we're going to remove it (previous line),
// we need it to be available to move again as the user navigates
$('#searchResults .gsc-webResult .gsc-cursor-box.gs-bidi-start-align:visible')
.clone().appendTo('#searchResults .gsc-tabsArea');
}, 200);
*/
});
}
setTimeout(function(){$(tabHeaders[0]).click()},200);
}
// add analytics tracking events to each result link
function addResultClickListeners() {
$("#searchResults a.gs-title").each(function(index, link) {
// When user clicks enter for Google search results, track it
$(link).click(function() {
ga('send', 'event', 'Google Click', 'clicked: ' + $(this).attr('href'),
'query: ' + $("#search_autocomplete").val().toLowerCase());
});
});
}
function getQuery(hash) {
var queryParts = hash.split('=');
return queryParts[1];
}
/* returns the given string with all HTML brackets converted to entities /* returns the given string with all HTML brackets converted to entities
TODO: move this to the site's JS library */ TODO: move this to the site's JS library */
function escapeHTML(string) { function escapeHTML(string) {