Loading tools/droiddoc/templates-sdk/assets/css/default.css +86 −5 Original line number Original line Diff line number Diff line Loading @@ -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; } tools/droiddoc/templates-sdk/assets/js/docs.js +223 −147 Original line number Original line Diff line number Diff line Loading @@ -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"); Loading @@ -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); Loading Loading @@ -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(); Loading @@ -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) { Loading Loading
tools/droiddoc/templates-sdk/assets/css/default.css +86 −5 Original line number Original line Diff line number Diff line Loading @@ -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; }
tools/droiddoc/templates-sdk/assets/js/docs.js +223 −147 Original line number Original line Diff line number Diff line Loading @@ -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"); Loading @@ -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); Loading Loading @@ -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(); Loading @@ -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) { Loading