From e6fe3a1c642468ce1ab3ed5a11ed328a0dd8fb5f Mon Sep 17 00:00:00 2001 From: Tyler Lemburg <lemburg@unl.edu> Date: Fri, 31 Mar 2017 11:07:08 -0500 Subject: [PATCH] Updated Google Search API to version 2 Google is deprecating version 1 of their custom search element API sometime in April. While we don't generate actual elements using their code, we use their javascript libraries to call the search. This change updates the code for version 2, removing the deprecation warning and keeping things in compliance. Before working with this, read https://developers.google.com/custom-search/docs/element very carefully. The flow of the Google Search as it relates to UNL_Search is: 1) end-scripts.tpl.php is rendered with variables that include the custom search engine ID 2) This script, using search.js (or search.min.js), adds the google search javascript to the end of the page asynchronously. It also gives the callback for its loading as window.searchInit, which loads the UNLSearch.initialize function. 3) This sets up the various search capabilities, binds callbacks onto those actions, and has all the JS functions that we operate on in the search. I didn't need to use the <gsce> element as described in the docs, as we already have a text box to search, and I bind the results to the unl_results div (local_results if a site-search is executed). Lastly, this new code does not use the "Linked Search Engine" specification. Instead, the as_sitesearch parameter is passed into the Google API, or, if a specific Custom Search Engine is specified (cx parameter), that is used vs. our regular UNL one. --- www/index.php | 27 +---- www/js/search.js | 190 +++++++++++++++++------------- www/less/search-google.less | 30 ++++- www/templates/end-scripts.tpl.php | 12 +- 4 files changed, 155 insertions(+), 104 deletions(-) diff --git a/www/index.php b/www/index.php index 5cfd645..6975a62 100644 --- a/www/index.php +++ b/www/index.php @@ -1,5 +1,7 @@ <?php +$search_engine_id = '015236299699564929946:nk1siew10ie'; + $config_file = __DIR__ . '/../config.sample.php'; if (file_exists(__DIR__ . '/../config.inc.php')) { $config_file = __DIR__ . '/../config.inc.php'; @@ -101,10 +103,10 @@ if (isset($_GET['u']) && $scanned = UNL_Search::getScannedPage($_GET['u'])) { if (isset($_GET['cx'])) { // Use their custom search engine instead of the linked one. - $context = $_GET['cx']; + $search_engine_id = $_GET['cx']; } else { - // Auto-build a custom search engine - $context = array('crefUrl' => UNL_Search::getLinkedCSEUrl($_GET['u'])); + // send the site value as the context to search on + $context = $_GET['u']; } $localResults = renderTemplate('templates/google-results.tpl.php', array( @@ -116,7 +118,6 @@ if (isset($_GET['u']) && $scanned = UNL_Search::getScannedPage($_GET['u'])) { loadDefaultSections($page); } - $maincontent = ''; if (!$isEmbed) { $maincontent .= renderTemplate('templates/search-form.tpl.php', array('local_results' => $localResults)); @@ -130,25 +131,9 @@ $maincontent .= renderTemplate('templates/search-results.tpl.php', array( $initialQuery = json_encode(isset($_GET['q']) ? $_GET['q'] : ''); $context = json_encode($context); -$apiKey = UNL_Search::getJSAPIKey(); -$params = array( - 'autoload' => json_encode(array('modules' => array( - array( - 'name' => 'search', - 'version' => '1.0', - 'callback' => 'searchInit', - 'style' => '//www.google.com/cse/style/look/v2/default.css' - ), - ))), -); - -if (!empty($apiKey)) { - $params['key'] = $apiKey; -} - $maincontent .= renderTemplate('templates/end-scripts.tpl.php', array( 'localScriptUrl' => $localScriptUrl, - 'googleLoaderUrl' => 'https://www.google.com/jsapi?' . http_build_query($params), + 'googleLoaderUrl' => 'https://cse.google.com/cse.js?cx=' . $search_engine_id, 'initialQuery' => $initialQuery, 'localContext' => $context, )); diff --git a/www/js/search.js b/www/js/search.js index dabf7b3..6f70781 100644 --- a/www/js/search.js +++ b/www/js/search.js @@ -132,106 +132,111 @@ define(['jquery', 'analytics'], function ($, analytics) { $(this._renderTo).empty(); }; + // Google Search Wrapper Class + var GoogleSearcher = function(search_element, root_of_element) { + this.control = search_element; + this.control.root = root_of_element; + } + + GoogleSearcher.prototype.setSearchCompleteCallback = function(callback) { + this.complete_callback = callback; + } + + GoogleSearcher.prototype.setSearchStartingCallback = function(callback) { + this.starting_callback = callback; + } + + GoogleSearcher.prototype.execute = function(query) { + this.starting_callback(this.control, null, query); + this.control.execute(query); + this.complete_callback(this.control); + } + return { initialize: function(firstQ, localContext) { // query related var query = ''; var actCls = 'active'; - // CustomSearchControl instances and config - var unlSearch; - var localSearch; - var activeSearch; + // CustomSearchControl instances and config + var activeSearch; // this is the search that is currently shown + var unlGoogleSearch; + var localGoogleSearch; var directorySearch; - var drawOp = new google.search.DrawOptions(); var searchToggleLock = false; var trackQuery = function(q) { - var loc = window.location, - qs = loc.search.replace(/(?:(\?)|&)q=[^&]*(?:&|$)/, '$1'), - page = [ - loc.pathname, - qs || '?', - (qs && qs != '?') ? '&' : '', - 'q=', - encodeURIComponent(q) - ].join(''); - - analytics.callTrackPageview(page); - - if (window.history.pushState) { - window.history.pushState({query: q}, '', page); - } + var loc = window.location, + qs = loc.search.replace(/(?:(\?)|&)q=[^&]*(?:&|$)/, '$1'), + page = [ + loc.pathname, + qs || '?', + (qs && qs != '?') ? '&' : '', + 'q=', + encodeURIComponent(q) + ].join(''); + + analytics.callTrackPageview(page); + + if (window.history.pushState) { + window.history.pushState({query: q}, '', page); + } }; var queryComplete = function(control) { - var $root = $(control.root); + var $root = $(control.root); - // a11y patching - $('img.gs-image', $root).each(function() { - if (!this.alt) { - this.alt = $(this).closest('.gsc-table-result').find('.gs-title').first().text(); - } - }); - $('img.gcsc-branding-img-noclear', $root).attr('alt', 'Google™'); - - if (!searchToggleLock && control == localSearch && $('.gs-no-results-result', $root).length) { - $root.closest('.results-group').find('.result-tab li:last-child').click(); - return; + // a11y patching + $('img.gs-image', $root).each(function() { + if (!this.alt) { + this.alt = $(this).closest('.gsc-table-result').find('.gs-title').first().text(); } + }); + $('img.gcsc-branding-img-noclear', $root).attr('alt', 'Google™'); + + if (!searchToggleLock && localGoogleSearch && control == localGoogleSearch.control && $('.gs-no-results-result', $root).length) { + $root.closest('.results-group').find('.result-tab li:last-child').click(); + return; + } - $root.closest(resultSel).addClass(actCls); - $root.closest(googleSel).slideDown(); + $root.closest(resultSel).addClass(actCls); + $root.closest(googleSel).slideDown(); - searchToggleLock = false; + searchToggleLock = false; }; var fullQuery = function(q, track) { - if (track !== false) { - trackQuery(q); - } - try { - activeSearch.execute(q, undefined, {}); - } catch (e) { - queryComplete(activeSearch); - } - directorySearch.execute(q); - $(wrapperMain).fadeIn(); + if (track !== false) { + trackQuery(q); + } + try { + activeSearch.execute(q); + } catch (e) { + queryComplete(activeSearch.control); + } + directorySearch.execute(q); + $(wrapperMain).fadeIn(); }; var fullStop = function() { - activeSearch.cancelSearch(); - directorySearch.cancelSearch(); - $(resultSel).removeClass(actCls); - $(wrapperMain).fadeOut(); - setTimeout(function() { - activeSearch.clearAllResults(); - directorySearch.clearAllResults(); - }, transitionDelay); + //activeSearch.cancelSearch(): // TODO: implement this + directorySearch.cancelSearch(); + $(resultSel).removeClass(actCls); + $(wrapperMain).fadeOut(); + setTimeout(function() { + activeSearch.control.clearAllResults(); + directorySearch.clearAllResults(); + }, transitionDelay); }; var queryStart = function(control, searcher, q) { - $(control.root).closest(googleSel).slideUp(0); - if (q !== query) { - trackQuery(q); - directorySearch.execute(q); - } + $(control.root).closest(googleSel).slideUp(0); + if (q !== query) { + trackQuery(q); + directorySearch.execute(q); + } }; - drawOp.enableSearchResultsOnly(); - - unlSearch = activeSearch = new google.search.CustomSearchControl(unlContext); - unlSearch.setResultSetSize(google.search.Search.FILTERED_CSE_RESULTSET); - unlSearch.setSearchCompleteCallback(window, queryComplete); - unlSearch.setSearchStartingCallback(window, queryStart); - - if (localContext) { - localSearch = activeSearch = new google.search.CustomSearchControl(localContext); - localSearch.setResultSetSize('small'); - localSearch.setSearchCompleteCallback(window, queryComplete); - localSearch.setSearchStartingCallback(window, queryStart); - } - directorySearch = new Directory(directoryServer, dirResults); // Setup DOM on ready @@ -285,11 +290,39 @@ define(['jquery', 'analytics'], function ($, analytics) { } }; - // draw the Google search controls - unlSearch.draw(unlResults, drawOp); + var render_attrs = { + div: 'unl_results', + tag: 'searchresults-only', + attributes: { + enableImageSearch: false + } + } + // draw the Google search results stuff + google.search.cse.element.render(render_attrs); + // bind the search results element to this class + var searchElement = google.search.cse.element.getAllElements()['searchresults-only0']; + window.googleSearchElement = searchElement; + unlGoogleSearch = new GoogleSearcher(searchElement, $('#unl_results')); + unlGoogleSearch.setSearchStartingCallback(queryStart); + unlGoogleSearch.setSearchCompleteCallback(queryComplete); + activeSearch = unlGoogleSearch; if (localContext) { - localSearch.draw(localResults, drawOp); + var render_attrs_local = { + div: 'local_results', + tag: 'searchresults-only', + attributes: { + enableImageSearch: false, + as_sitesearch: localContext + } + } + google.search.cse.element.render(render_attrs_local); + var localSearchElement = google.search.cse.element.getAllElements()['searchresults-only1']; + window.localGoogleSearchElement = searchElement; + localGoogleSearch = new GoogleSearcher(localSearchElement, $('#local_results')); + localGoogleSearch.setSearchStartingCallback(queryStart); + localGoogleSearch.setSearchCompleteCallback(queryComplete); + activeSearch = localGoogleSearch; } // a11y patch Google search box @@ -311,13 +344,12 @@ define(['jquery', 'analytics'], function ($, analytics) { directorySearch.changeViewState(i); } else if ($par.is(wrapperWeb)) { searchToggleLock = true; - $(activeSearch.root).closest(googleSel).slideUp().trigger(evtStateChange, [i, 0 + !i]); + $(activeSearch.control.root).closest(googleSel).slideUp().trigger(evtStateChange, [i, 0 + !i]); if (i === 0) { - activeSearch = localSearch; + activeSearch = localGoogleSearch; } else { - activeSearch = unlSearch; + activeSearch = unlGoogleSearch; } - activeSearch.execute(query); } }); diff --git a/www/less/search-google.less b/www/less/search-google.less index 1c4e7eb..2af06ab 100644 --- a/www/less/search-google.less +++ b/www/less/search-google.less @@ -11,6 +11,29 @@ font-size: inherit; } +.gsc-thumbnail-inside { + padding-left: 0; + padding-right: 0; +} + +.gsc-control-cse .gs-snippet { + color: inherit; +} + +.gsc-thumbnail .gs-image-box { + padding-right: 0.5em; +} + +.gsc-url-top { + font-size: 80%; + padding-left: 0; + padding-right: 0; +} + +.gsc-control-cse { + padding: 0; +} + .gsc-result { .gsc-webResult & { @@ -21,6 +44,10 @@ .gs-title { height: 1.662em; } + + &.gsc-webResult:hover { + border: none; + } } .gs-result { @@ -29,7 +56,7 @@ text-decoration: none; } - a.gs-visibleUrl, .gs-visibleUrl { + a.gs-visibleUrl, .gs-visibleUrl, .gsc-url-top { color: @light-neutral; } } @@ -69,6 +96,7 @@ .gcsc-branding { margin-bottom: 1.3333em; + display: none; } td.gcsc-branding-text { diff --git a/www/templates/end-scripts.tpl.php b/www/templates/end-scripts.tpl.php index 63c71e6..81688c6 100644 --- a/www/templates/end-scripts.tpl.php +++ b/www/templates/end-scripts.tpl.php @@ -1,15 +1,21 @@ <script> require(['jquery', '<?php echo $localScriptUrl ?>'], function($, UNLSearch) { - var gSearchDefer = $.Deferred(); + var gSearchDefer = $.Deferred(); window.searchInit = function() { window.searchInit = $.noop; gSearchDefer.resolve(google); }; + window.__gcse = { + parsetags: 'explicit', + callback: window.searchInit + }; + $('<script>', { src: '<?php echo $googleLoaderUrl ?>', - asycn: 'async', - defer: 'defer' + async: 'async', + defer: 'defer', + type: 'text/javascript' }).appendTo($('body')); var $localCss = $('<link>', { -- GitLab