Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e774264f authored by Amanda Kassay's avatar Amanda Kassay Committed by android-build-merger
Browse files

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

am: 843649ba

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

Change-Id: I7f85542e8fd0534ac492e848c7b3070dc056cb43
parents 4f9a67db 843649ba
Loading
Loading
Loading
Loading
+86 −5
Original line number Original line Diff line number Diff line
@@ -8875,3 +8875,84 @@ $spritesheet: width height image $spritesheet-sprites;
  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;
}
+223 −147
Original line number Original line Diff line number Diff line
@@ -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() {
function loadSearchResults() {
  /**
  document.getElementById("search_autocomplete").style.color = "#000";
   * The last response from Google CSE.

   * @private {Object}
  searchControl = new google.search.SearchControl();
   */

  this.resultQuery_ = {};
  // use our existing search form and use tabs when multiple searchers are used

  drawOptions = new google.search.DrawOptions();
  /** @private {?Element} */
  drawOptions.setDrawMode(google.search.SearchControl.DRAW_MODE_TABBED);
  this.searchResultEl_ = null;
  drawOptions.setInput(document.getElementById("search_autocomplete"));


  /** @private {?Element} */
  // configure search result options
  this.searchInputEl_ = null;
  searchOptions = new google.search.SearcherOptions();

  searchOptions.setExpandMode(GSearchControl.EXPAND_MODE_OPEN);
  /** @private {string} */

  this.query = '';
  // configure each of the searchers, for each tab
};
  devSiteSearcher = new google.search.WebSearch();

  devSiteSearcher.setUserDefinedLabel("All");
/**
  devSiteSearcher.setSiteRestriction("001482626316274216503:zu90b7s047u");
 * Initializes DAC's Google custom search engine.

 * @export
  designSearcher = new google.search.WebSearch();
 */
  designSearcher.setUserDefinedLabel("Design");
dacsearch.CustomSearchEngine.prototype.init = function() {
  designSearcher.setSiteRestriction("http://developer.android.com/design/");
  this.searchResultEl_ = $('#leftSearchControl');

  this.searchResultEl_.empty();
  trainingSearcher = new google.search.WebSearch();
  this.searchInputEl_ = $('#search_autocomplete');
  trainingSearcher.setUserDefinedLabel("Training");
  this.searchInputEl_.focus().val(this.query);
  trainingSearcher.setSiteRestriction("http://developer.android.com/training/");
  this.getResults_();

  this.bindEvents_();
  guidesSearcher = new google.search.WebSearch();
};
  guidesSearcher.setUserDefinedLabel("Guides");

  guidesSearcher.setSiteRestriction("http://developer.android.com/guide/");


/**
  referenceSearcher = new google.search.WebSearch();
 * Binds the keyup event to the search input.
  referenceSearcher.setUserDefinedLabel("Reference");
 * @private
  referenceSearcher.setSiteRestriction("http://developer.android.com/reference/");
 */

dacsearch.CustomSearchEngine.prototype.bindEvents_ = function() {
  googleSearcher = new google.search.WebSearch();
  this.searchInputEl_.keyup(this.debounce_(function(e) {
  googleSearcher.setUserDefinedLabel("Google Services");
    var code = e.which;
  googleSearcher.setSiteRestriction("http://developer.android.com/google/");
    if (code != 13) {

      this.query = this.searchInputEl_.val();
  blogSearcher = new google.search.WebSearch();
      location.hash = 'q=' + encodeURI(this.query);
  blogSearcher.setUserDefinedLabel("Blog");
      this.searchResultEl_.empty();
  blogSearcher.setSiteRestriction("http://android-developers.blogspot.com");
      this.getResults_();

    }
  // add each searcher to the search control
  }.bind(this), 250));
  searchControl.addSearcher(devSiteSearcher, searchOptions);
};
  searchControl.addSearcher(designSearcher, searchOptions);

  searchControl.addSearcher(trainingSearcher, searchOptions);

  searchControl.addSearcher(guidesSearcher, searchOptions);
/**
  searchControl.addSearcher(referenceSearcher, searchOptions);
 * Resets the search control.
  searchControl.addSearcher(googleSearcher, searchOptions);
 */
  searchControl.addSearcher(blogSearcher, searchOptions);
dacsearch.CustomSearchEngine.prototype.reset = function() {

  this.query = '';
  // configure result options
  this.searchInputEl_.off('keyup');
  searchControl.setResultSetSize(google.search.Search.LARGE_RESULTSET);
  this.searchResultEl_.empty();
  searchControl.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
  this.updateResultTitle_();
  searchControl.setTimeoutInterval(google.search.SearchControl.TIMEOUT_SHORT);
};
  searchControl.setNoResultsString(google.search.SearchControl.NO_RESULTS_DEFAULT_STRING);



  // upon ajax search, refresh the url and search title
/**
  searchControl.setSearchStartingCallback(this, function(control, searcher, query) {
 * Updates the search query text at the top of the results.
    updateResultTitle(query);
 * @private
    var query = document.getElementById('search_autocomplete').value;
 */
    location.hash = 'q=' + query;
dacsearch.CustomSearchEngine.prototype.updateResultTitle_ = function() {
  $("#searchTitle").html("Results for <em>" + this.query + "</em>");
};


/**
 * Makes the CSE api call and gets the results.
 * @param {number=} opt_start The optional start index.
 * @private
 */
dacsearch.CustomSearchEngine.prototype.getResults_ = function(opt_start) {
  var lang = getLangPref();
  // 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)'
  };

  $.get(cseUrl + $.param(searchParams), function(data) {
    this.resultQuery_ = data;
    this.renderResults_(data);
    this.updateResultTitle_(this.query);
  }.bind(this));
};


/**
 * Renders the results.
 * @private
 */
dacsearch.CustomSearchEngine.prototype.renderResults_ = function(results) {
  var el = this.searchResultEl_;

  if (!results.items) {
    el.append($('<div>').text('No results'));
    return;
  }

  for (var i = 0; i < results.items.length; i++) {
    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';

    var entry = $('<div>').addClass('dac-custom-search-entry cols');

    if (hasImage) {
      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());
    });
    });


  // once search results load, set up click listeners
    var linkUrlEl = $('<a>').addClass('dac-custom-search-link').text(
  searchControl.setSearchCompleteCallback(this, function(control, searcher, query) {
        item.formattedUrl).attr('href', item.link);
    addResultClickListeners();
    linkUrlEl.click(function(e) {
      ga('send', 'event', 'Google Custom Search',
          'clicked: ' + linkUrlEl.attr('href'),
          'query: ' + $("#search_autocomplete").val().toLowerCase());
    });
    });


  // draw the search results box
  searchControl.draw(document.getElementById("leftSearchControl"), drawOptions);


  // get query and execute the search
    entry.append($('<div>').addClass(hasImage ? 'col-5of6' : 'col-6of6')
  searchControl.execute(decodeURI(getQuery(location.hash)));
      .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));


  document.getElementById("search_autocomplete").focus();
    el.append(loadMoreButton);
  addTabListeners();
  }
  }
// End of loadSearchResults
};


/**
 * 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) {