Commit e6fe3a1c authored by Tyler R Lemburg's avatar Tyler R Lemburg
Browse files

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.
parent d5034a09
<?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,
));
......
......@@ -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);
}
});
......
......@@ -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 {
......
<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>', {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment