Создайте поисковый интерфейс с виджетом поиска

Виджет поиска предоставляет настраиваемый интерфейс поиска для веб-приложений. Для его реализации требуется минимальное количество HTML и JavaScript, и он поддерживает такие распространенные функции, как фасетный поиск и пагинация. Вы также можете настроить интерфейс с помощью CSS и JavaScript.

Если вам нужна большая гибкость, используйте API запросов. См. раздел «Создание интерфейса поиска с помощью API запросов» .

Создайте интерфейс поиска.

Для создания интерфейса поиска необходимо выполнить следующие шаги:

  1. Настройте приложение для поиска.
  2. Сгенерируйте идентификатор клиента для приложения.
  3. Добавьте HTML-разметку для поля поиска и результатов.
  4. Загрузите виджет на страницу.
  5. Инициализируйте виджет.

Настройте приложение для поиска.

Для каждого поискового интерфейса требуется поисковое приложение, определенное в консоли администратора. Приложение предоставляет настройки запросов, такие как источники данных, фасеты и параметры качества поиска.

Для создания поискового приложения см. раздел «Создание пользовательского интерфейса поиска» .

Сгенерируйте идентификатор клиента для приложения.

В дополнение к шагам, описанным в разделе «Настройка доступа к API Cloud Search» , сгенерируйте идентификатор клиента для вашего веб-приложения.

Настройте проект

При настройке проекта:

  • Выберите тип веб-браузера .
  • Укажите URI источника вашего приложения.
  • Обратите внимание на идентификатор клиента. Для работы виджета секретный ключ клиента не требуется.

Для получения дополнительной информации см. OAuth 2.0 для клиентских веб-приложений .

Добавить HTML-разметку

Для работы виджета требуются следующие HTML-элементы:

  • Элемент input для поля поиска.
  • Элемент для привязки диалогового окна с подсказками.
  • Элемент для отображения результатов поиска.
  • (Необязательно) Элемент для управления фасетным отображением.

В этом фрагменте кода показаны элементы, идентифицированные по их атрибуту id :

serving/widget/public/with_css/index.html
<div id="search_bar">
  <div id="suggestions_anchor">
    <input type="text" id="search_input" placeholder="Search for...">
  </div>
</div>
<div id="facet_results"></div>
<div id="search_results"></div>

Загрузите виджет

Включите загрузчик, используя тег <script> :

serving/widget/public/with_css/index.html
<!-- Google API loader -->
<script src="https://apis.google.com/js/api.js?mods=enable_cloud_search_widget&onload=onLoad" async defer></script>

Предоставьте функцию обратного вызова onload . Когда загрузчик будет готов, вызовите gapi.load() для загрузки модуля API-клиента, входа в Google и модуля Cloud Search.

serving/widget/public/with_css/app.js
/**
* Load the cloud search widget & auth libraries. Runs after
* the initial gapi bootstrap library is ready.
*/
function onLoad() {
  gapi.load('client:auth2:cloudsearch-widget', initializeApp)
}

Инициализируйте виджет.

Инициализируйте клиентскую библиотеку с помощью gapi.client.init() или gapi.auth2.init() указав свой идентификатор клиента и область действия https://www.googleapis.com/auth/cloud_search.query . Используйте классы построителя для настройки и привязки виджета.

Пример инициализации:

serving/widget/public/with_css/app.js
/**
 * Initialize the app after loading the Google API client &
 * Cloud Search widget.
 */
function initializeApp() {
  // Load client ID & search app.
  loadConfiguration().then(function() {
    // Set API version to v1.
    gapi.config.update('cloudsearch.config/apiVersion', 'v1');

    // Build the result container and bind to DOM elements.
    var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
      .setSearchApplicationId(searchApplicationName)
      .setSearchResultsContainerElement(document.getElementById('search_results'))
      .setFacetResultsContainerElement(document.getElementById('facet_results'))
      .build();

    // Build the search box and bind to DOM elements.
    var searchBox = new gapi.cloudsearch.widget.searchbox.Builder()
      .setSearchApplicationId(searchApplicationName)
      .setInput(document.getElementById('search_input'))
      .setAnchor(document.getElementById('suggestions_anchor'))
      .setResultsContainer(resultsContainer)
      .build();
  }).then(function() {
    // Init API/oauth client w/client ID.
    return gapi.auth2.init({
        'clientId': clientId,
        'scope': 'https://www.googleapis.com/auth/cloud_search.query'
    });
  });
}

Переменные конфигурации:

serving/widget/public/with_css/app.js
/**
* Client ID from OAuth credentials.
*/
var clientId = "...apps.googleusercontent.com";

/**
* Full resource name of the search application, such as
* "searchapplications/<your-id>".
*/
var searchApplicationName = "searchapplications/...";

Настройте процесс входа в систему.

Виджет предлагает пользователям войти в систему, когда они начинают печатать. Для персонализации можно использовать функцию входа через Google для веб-сайтов .

Авторизуйте пользователей напрямую

Используйте функцию «Вход через Google» для отслеживания и управления состоянием авторизации. В этом примере используется GoogleAuth.signIn() при нажатии кнопки:

serving/widget/public/with_signin/app.js
// Handle sign-in/sign-out.
let auth = gapi.auth2.getAuthInstance();

// Watch for sign in status changes to update the UI appropriately.
let onSignInChanged = (isSignedIn) => {
  // Update UI to switch between signed in/out states
  // ...
}
auth.isSignedIn.listen(onSignInChanged);
onSignInChanged(auth.isSignedIn.get()); // Trigger with current status.

// Connect sign-in/sign-out buttons.
document.getElementById("sign-in").onclick = function(e) {
  auth.signIn();
};
document.getElementById("sign-out").onclick = function(e) {
  auth.signOut();
};

Автоматический вход пользователей

Предварительно авторизуйте приложение для пользователей вашей организации, чтобы упростить вход в систему. Это также полезно при использовании Cloud Identity Aware Proxy . См. раздел «Использование входа через Google с ИТ-приложениями» .

Настройте интерфейс

Вы можете изменить внешний вид виджета следующим образом:

  • Переопределение стилей с помощью CSS.
  • Декоративные элементы с помощью адаптера.
  • Создание пользовательских элементов с помощью адаптера.

Переопределяйте стили с помощью CSS

Виджет включает в себя собственные CSS-стили. Для их переопределения используйте селекторы предков для повышения специфичности:

#suggestions_anchor .cloudsearch_suggestion_container {
  font-size: 14px;
}

См. справочник поддерживаемых классов CSS .

Декоративные элементы с помощью адаптера

Создайте и зарегистрируйте адаптер для изменения элементов перед их рендерингом. В этом примере добавляется пользовательский CSS-класс:

serving/widget/public/with_decorated_element/app.js
/**
 * Search box adapter that decorates suggestion elements by
 * adding a custom CSS class.
 */
function SearchBoxAdapter() {}
SearchBoxAdapter.prototype.decorateSuggestionElement = function(element) {
  element.classList.add('my-suggestion');
}

/**
 * Results container adapter that decorates suggestion elements by
 * adding a custom CSS class.
 */
function ResultsContainerAdapter() {}
ResultsContainerAdapter.prototype.decorateSearchResultElement = function(element) {
  element.classList.add('my-result');
}

Зарегистрируйте адаптер во время инициализации:

serving/widget/public/with_decorated_element/app.js
// Build the result container and bind to DOM elements.
var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
  .setAdapter(new ResultsContainerAdapter())
  // ...
  .build();

// Build the search box and bind to DOM elements.
var searchBox = new gapi.cloudsearch.widget.searchbox.Builder()
  .setAdapter(new SearchBoxAdapter())
  // ...
  .build();

Создавайте пользовательские элементы с помощью адаптера.

Реализуйте createSuggestionElement , createFacetResultElement или createSearchResultElement для создания пользовательских компонентов интерфейса. В этом примере используются HTML-теги <template> :

serving/widget/public/with_custom_element/app.js
/**
 * Search box adapter that overrides creation of suggestion elements.
 */
function SearchBoxAdapter() {}
SearchBoxAdapter.prototype.createSuggestionElement = function(suggestion) {
  let template = document.querySelector('#suggestion_template');
  let fragment = document.importNode(template.content, true);
  fragment.querySelector('.suggested_query').textContent = suggestion.suggestedQuery;
  return fragment.firstElementChild;
}

/**
 * Results container adapter that overrides creation of result elements.
 */
function ResultsContainerAdapter() {}
ResultsContainerAdapter.prototype.createSearchResultElement = function(result) {
  let template = document.querySelector('#result_template');
  let fragment = document.importNode(template.content, true);
  fragment.querySelector('.title').textContent = result.title;
  fragment.querySelector('.title').href = result.url;
  let snippetText = result.snippet != null ?
    result.snippet.snippet : '';
  fragment.querySelector('.query_snippet').innerHTML = snippetText;
  return fragment.firstElementChild;
}

Зарегистрируйте адаптер:

serving/widget/public/with_custom_element/app.js
// Build the result container and bind to DOM elements.
var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
  .setAdapter(new ResultsContainerAdapter())
  // ...
  .build();

// Build the search box and bind to DOM elements.
var searchBox = new gapi.cloudsearch.widget.searchbox.Builder()
  .setAdapter(new SearchBoxAdapter())
  // ...
  .build();

Пользовательские элементы фасетной фильтрации должны соответствовать следующим правилам:

  • Прикрепите атрибут cloudsearch_facet_bucket_clickable к кликабельным элементам.
  • Оберните каждый сегмент в контейнер cloudsearch_facet_bucket_container .
  • Сохраните порядок ячеек в ответе.

Например, следующий фрагмент кода отображает фасеты с помощью ссылок вместо флажков.

serving/widget/public/with_custom_facet/app.js
/**
 * Results container adapter that intercepts requests to dynamically
 * change which sources are enabled based on user selection.
 */
function ResultsContainerAdapter() {
  this.selectedSource = null;
}

ResultsContainerAdapter.prototype.createFacetResultElement = function(result) {
  // container for the facet
  var container = document.createElement('div');

  // Add a label describing the facet (operator/property)
  var label = document.createElement('div')
  label.classList.add('facet_label');
  label.textContent = result.operatorName;
  container.appendChild(label);

  // Add each bucket
  for(var i in result.buckets) {
    var bucket = document.createElement('div');
    bucket.classList.add('cloudsearch_facet_bucket_container');

    // Extract & render value from structured value
    // Note: implementation of renderValue() not shown
    var bucketValue = this.renderValue(result.buckets[i].value)
    var link = document.createElement('a');
    link.classList.add('cloudsearch_facet_bucket_clickable');
    link.textContent = bucketValue;
    bucket.appendChild(link);
    container.appendChild(bucket);
  }
  return container;
}

// Renders a value for user display
ResultsContainerAdapter.prototype.renderValue = function(value) {
  // ...
}

Настройка поведения поиска

Переопределяйте настройки поискового приложения, перехватывая запросы с помощью адаптера. Реализуйте interceptSearchRequest для изменения запросов перед их выполнением. В этом примере запросы ограничиваются выбранным источником:

serving/widget/public/with_request_interceptor/app.js
/**
 * Results container adapter that intercepts requests to dynamically
 * change which sources are enabled based on user selection.
 */
function ResultsContainerAdapter() {
  this.selectedSource = null;
}
ResultsContainerAdapter.prototype.interceptSearchRequest = function(request) {
  if (!this.selectedSource || this.selectedSource == 'ALL') {
    // Everything selected, fall back to sources defined in the search
    // application.
    request.dataSourceRestrictions = null;
  } else {
    // Restrict to a single selected source.
    request.dataSourceRestrictions = [
      {
        source: {
          predefinedSource: this.selectedSource
        }
      }
    ];
  }
  return request;
}

Зарегистрируйте адаптер:

serving/widget/public/with_request_interceptor/app.js
var resultsContainerAdapter = new ResultsContainerAdapter();
// Build the result container and bind to DOM elements.
var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
  .setAdapter(resultsContainerAdapter)
  // ...
  .build();

Следующий HTML-код используется для отображения выпадающего списка для фильтрации по источникам:

serving/widget/public/with_request_interceptor/index.html
<div>
  <span>Source</span>
  <select id="sources">
    <option value="ALL">All</option>
    <option value="GOOGLE_GMAIL">Gmail</option>
    <option value="GOOGLE_DRIVE">Drive</option>
    <option value="GOOGLE_SITES">Sites</option>
    <option value="GOOGLE_GROUPS">Groups</option>
    <option value="GOOGLE_CALENDAR">Calendar</option>
    <option value="GOOGLE_KEEP">Keep</option>
  </select>
</div>

Приведенный ниже код отслеживает изменения, устанавливает выбранный параметр и при необходимости повторно выполняет запрос.

serving/widget/public/with_request_interceptor/app.js
// Handle source selection
document.getElementById('sources').onchange = (e) => {
  resultsContainerAdapter.selectedSource = e.target.value;
  let request = resultsContainer.getCurrentRequest();
  if (request.query) {
    // Re-execute if there's a valid query. The source selection
    // will be applied in the interceptor.
    resultsContainer.resetState();
    resultsContainer.executeRequest(request);
  }
}

Также можно перехватывать ответы поисковых запросов, реализовав интерфейс interceptSearchResponse в адаптере.

Версии для закрепления

  • Версия API : Установите значение в cloudsearch.config/apiVersion перед инициализацией.
  • Версия виджета : Используйте gapi.config.update('cloudsearch.config/clientVersion', 1.1) .

Оба параметра по умолчанию равны 1,0, если не заданы.

Например, чтобы закрепить виджет за версией 1.1:

serving/widget/public/basic/app.js
gapi.config.update('cloudsearch.config/apiVersion', 'v1');

Защитите интерфейс поиска

Применяйте лучшие практики обеспечения безопасности веб-приложений, особенно для предотвращения кликджекинга .

Включить отладку

Используйте interceptSearchRequest для включения отладки:

if (!request.requestOptions) {
  request.requestOptions = {};
}
request.requestOptions.debugOptions = {enableDebugging: true};
return request;
,

Виджет поиска предоставляет настраиваемый интерфейс поиска для веб-приложений. Для его реализации требуется минимальное количество HTML и JavaScript, и он поддерживает такие распространенные функции, как фасетный поиск и пагинация. Вы также можете настроить интерфейс с помощью CSS и JavaScript.

Если вам нужна большая гибкость, используйте API запросов. См. раздел «Создание интерфейса поиска с помощью API запросов» .

Создайте интерфейс поиска.

Для создания интерфейса поиска необходимо выполнить следующие шаги:

  1. Настройте приложение для поиска.
  2. Сгенерируйте идентификатор клиента для приложения.
  3. Добавьте HTML-разметку для поля поиска и результатов.
  4. Загрузите виджет на страницу.
  5. Инициализируйте виджет.

Настройте приложение для поиска.

Для каждого поискового интерфейса требуется поисковое приложение, определенное в консоли администратора. Приложение предоставляет настройки запросов, такие как источники данных, фасеты и параметры качества поиска.

Для создания поискового приложения см. раздел «Создание пользовательского интерфейса поиска» .

Сгенерируйте идентификатор клиента для приложения.

В дополнение к шагам, описанным в разделе «Настройка доступа к API Cloud Search» , сгенерируйте идентификатор клиента для вашего веб-приложения.

Настройте проект

При настройке проекта:

  • Выберите тип веб-браузера .
  • Укажите URI источника вашего приложения.
  • Обратите внимание на идентификатор клиента. Для работы виджета секретный ключ клиента не требуется.

Для получения дополнительной информации см. OAuth 2.0 для клиентских веб-приложений .

Добавить HTML-разметку

Для работы виджета требуются следующие HTML-элементы:

  • Элемент input для поля поиска.
  • Элемент для привязки диалогового окна с подсказками.
  • Элемент для отображения результатов поиска.
  • (Необязательно) Элемент для управления фасетным отображением.

В этом фрагменте кода показаны элементы, идентифицированные по их атрибуту id :

serving/widget/public/with_css/index.html
<div id="search_bar">
  <div id="suggestions_anchor">
    <input type="text" id="search_input" placeholder="Search for...">
  </div>
</div>
<div id="facet_results"></div>
<div id="search_results"></div>

Загрузите виджет

Включите загрузчик, используя тег <script> :

serving/widget/public/with_css/index.html
<!-- Google API loader -->
<script src="https://apis.google.com/js/api.js?mods=enable_cloud_search_widget&onload=onLoad" async defer></script>

Предоставьте функцию обратного вызова onload . Когда загрузчик будет готов, вызовите gapi.load() для загрузки модуля API-клиента, входа в Google и модуля Cloud Search.

serving/widget/public/with_css/app.js
/**
* Load the cloud search widget & auth libraries. Runs after
* the initial gapi bootstrap library is ready.
*/
function onLoad() {
  gapi.load('client:auth2:cloudsearch-widget', initializeApp)
}

Инициализируйте виджет.

Инициализируйте клиентскую библиотеку с помощью gapi.client.init() или gapi.auth2.init() указав свой идентификатор клиента и область действия https://www.googleapis.com/auth/cloud_search.query . Используйте классы построителя для настройки и привязки виджета.

Пример инициализации:

serving/widget/public/with_css/app.js
/**
 * Initialize the app after loading the Google API client &
 * Cloud Search widget.
 */
function initializeApp() {
  // Load client ID & search app.
  loadConfiguration().then(function() {
    // Set API version to v1.
    gapi.config.update('cloudsearch.config/apiVersion', 'v1');

    // Build the result container and bind to DOM elements.
    var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
      .setSearchApplicationId(searchApplicationName)
      .setSearchResultsContainerElement(document.getElementById('search_results'))
      .setFacetResultsContainerElement(document.getElementById('facet_results'))
      .build();

    // Build the search box and bind to DOM elements.
    var searchBox = new gapi.cloudsearch.widget.searchbox.Builder()
      .setSearchApplicationId(searchApplicationName)
      .setInput(document.getElementById('search_input'))
      .setAnchor(document.getElementById('suggestions_anchor'))
      .setResultsContainer(resultsContainer)
      .build();
  }).then(function() {
    // Init API/oauth client w/client ID.
    return gapi.auth2.init({
        'clientId': clientId,
        'scope': 'https://www.googleapis.com/auth/cloud_search.query'
    });
  });
}

Переменные конфигурации:

serving/widget/public/with_css/app.js
/**
* Client ID from OAuth credentials.
*/
var clientId = "...apps.googleusercontent.com";

/**
* Full resource name of the search application, such as
* "searchapplications/<your-id>".
*/
var searchApplicationName = "searchapplications/...";

Настройте процесс входа в систему.

Виджет предлагает пользователям войти в систему, когда они начинают печатать. Для персонализации можно использовать функцию входа через Google для веб-сайтов .

Авторизуйте пользователей напрямую

Используйте функцию «Вход через Google» для отслеживания и управления состоянием авторизации. В этом примере используется GoogleAuth.signIn() при нажатии кнопки:

serving/widget/public/with_signin/app.js
// Handle sign-in/sign-out.
let auth = gapi.auth2.getAuthInstance();

// Watch for sign in status changes to update the UI appropriately.
let onSignInChanged = (isSignedIn) => {
  // Update UI to switch between signed in/out states
  // ...
}
auth.isSignedIn.listen(onSignInChanged);
onSignInChanged(auth.isSignedIn.get()); // Trigger with current status.

// Connect sign-in/sign-out buttons.
document.getElementById("sign-in").onclick = function(e) {
  auth.signIn();
};
document.getElementById("sign-out").onclick = function(e) {
  auth.signOut();
};

Автоматический вход пользователей

Предварительно авторизуйте приложение для пользователей вашей организации, чтобы упростить вход в систему. Это также полезно при использовании Cloud Identity Aware Proxy . См. раздел «Использование входа через Google с ИТ-приложениями» .

Настройте интерфейс

Вы можете изменить внешний вид виджета следующим образом:

  • Переопределение стилей с помощью CSS.
  • Декоративные элементы с помощью адаптера.
  • Создание пользовательских элементов с помощью адаптера.

Переопределяйте стили с помощью CSS

Виджет включает в себя собственные CSS-стили. Для их переопределения используйте селекторы предков для повышения специфичности:

#suggestions_anchor .cloudsearch_suggestion_container {
  font-size: 14px;
}

См. справочник поддерживаемых классов CSS .

Декоративные элементы с помощью адаптера

Создайте и зарегистрируйте адаптер для изменения элементов перед их рендерингом. В этом примере добавляется пользовательский CSS-класс:

serving/widget/public/with_decorated_element/app.js
/**
 * Search box adapter that decorates suggestion elements by
 * adding a custom CSS class.
 */
function SearchBoxAdapter() {}
SearchBoxAdapter.prototype.decorateSuggestionElement = function(element) {
  element.classList.add('my-suggestion');
}

/**
 * Results container adapter that decorates suggestion elements by
 * adding a custom CSS class.
 */
function ResultsContainerAdapter() {}
ResultsContainerAdapter.prototype.decorateSearchResultElement = function(element) {
  element.classList.add('my-result');
}

Зарегистрируйте адаптер во время инициализации:

serving/widget/public/with_decorated_element/app.js
// Build the result container and bind to DOM elements.
var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
  .setAdapter(new ResultsContainerAdapter())
  // ...
  .build();

// Build the search box and bind to DOM elements.
var searchBox = new gapi.cloudsearch.widget.searchbox.Builder()
  .setAdapter(new SearchBoxAdapter())
  // ...
  .build();

Создавайте пользовательские элементы с помощью адаптера.

Реализуйте createSuggestionElement , createFacetResultElement или createSearchResultElement для создания пользовательских компонентов интерфейса. В этом примере используются HTML-теги <template> :

serving/widget/public/with_custom_element/app.js
/**
 * Search box adapter that overrides creation of suggestion elements.
 */
function SearchBoxAdapter() {}
SearchBoxAdapter.prototype.createSuggestionElement = function(suggestion) {
  let template = document.querySelector('#suggestion_template');
  let fragment = document.importNode(template.content, true);
  fragment.querySelector('.suggested_query').textContent = suggestion.suggestedQuery;
  return fragment.firstElementChild;
}

/**
 * Results container adapter that overrides creation of result elements.
 */
function ResultsContainerAdapter() {}
ResultsContainerAdapter.prototype.createSearchResultElement = function(result) {
  let template = document.querySelector('#result_template');
  let fragment = document.importNode(template.content, true);
  fragment.querySelector('.title').textContent = result.title;
  fragment.querySelector('.title').href = result.url;
  let snippetText = result.snippet != null ?
    result.snippet.snippet : '';
  fragment.querySelector('.query_snippet').innerHTML = snippetText;
  return fragment.firstElementChild;
}

Зарегистрируйте адаптер:

serving/widget/public/with_custom_element/app.js
// Build the result container and bind to DOM elements.
var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
  .setAdapter(new ResultsContainerAdapter())
  // ...
  .build();

// Build the search box and bind to DOM elements.
var searchBox = new gapi.cloudsearch.widget.searchbox.Builder()
  .setAdapter(new SearchBoxAdapter())
  // ...
  .build();

Пользовательские элементы фасетной фильтрации должны соответствовать следующим правилам:

  • Прикрепите атрибут cloudsearch_facet_bucket_clickable к кликабельным элементам.
  • Оберните каждый сегмент в контейнер cloudsearch_facet_bucket_container .
  • Сохраните порядок ячеек в ответе.

Например, следующий фрагмент кода отображает фасеты с помощью ссылок вместо флажков.

serving/widget/public/with_custom_facet/app.js
/**
 * Results container adapter that intercepts requests to dynamically
 * change which sources are enabled based on user selection.
 */
function ResultsContainerAdapter() {
  this.selectedSource = null;
}

ResultsContainerAdapter.prototype.createFacetResultElement = function(result) {
  // container for the facet
  var container = document.createElement('div');

  // Add a label describing the facet (operator/property)
  var label = document.createElement('div')
  label.classList.add('facet_label');
  label.textContent = result.operatorName;
  container.appendChild(label);

  // Add each bucket
  for(var i in result.buckets) {
    var bucket = document.createElement('div');
    bucket.classList.add('cloudsearch_facet_bucket_container');

    // Extract & render value from structured value
    // Note: implementation of renderValue() not shown
    var bucketValue = this.renderValue(result.buckets[i].value)
    var link = document.createElement('a');
    link.classList.add('cloudsearch_facet_bucket_clickable');
    link.textContent = bucketValue;
    bucket.appendChild(link);
    container.appendChild(bucket);
  }
  return container;
}

// Renders a value for user display
ResultsContainerAdapter.prototype.renderValue = function(value) {
  // ...
}

Настройка поведения поиска

Переопределяйте настройки поискового приложения, перехватывая запросы с помощью адаптера. Реализуйте interceptSearchRequest для изменения запросов перед их выполнением. В этом примере запросы ограничиваются выбранным источником:

serving/widget/public/with_request_interceptor/app.js
/**
 * Results container adapter that intercepts requests to dynamically
 * change which sources are enabled based on user selection.
 */
function ResultsContainerAdapter() {
  this.selectedSource = null;
}
ResultsContainerAdapter.prototype.interceptSearchRequest = function(request) {
  if (!this.selectedSource || this.selectedSource == 'ALL') {
    // Everything selected, fall back to sources defined in the search
    // application.
    request.dataSourceRestrictions = null;
  } else {
    // Restrict to a single selected source.
    request.dataSourceRestrictions = [
      {
        source: {
          predefinedSource: this.selectedSource
        }
      }
    ];
  }
  return request;
}

Зарегистрируйте адаптер:

serving/widget/public/with_request_interceptor/app.js
var resultsContainerAdapter = new ResultsContainerAdapter();
// Build the result container and bind to DOM elements.
var resultsContainer = new gapi.cloudsearch.widget.resultscontainer.Builder()
  .setAdapter(resultsContainerAdapter)
  // ...
  .build();

Следующий HTML-код используется для отображения выпадающего списка для фильтрации по источникам:

serving/widget/public/with_request_interceptor/index.html
<div>
  <span>Source</span>
  <select id="sources">
    <option value="ALL">All</option>
    <option value="GOOGLE_GMAIL">Gmail</option>
    <option value="GOOGLE_DRIVE">Drive</option>
    <option value="GOOGLE_SITES">Sites</option>
    <option value="GOOGLE_GROUPS">Groups</option>
    <option value="GOOGLE_CALENDAR">Calendar</option>
    <option value="GOOGLE_KEEP">Keep</option>
  </select>
</div>

Приведенный ниже код отслеживает изменения, устанавливает выбранный параметр и при необходимости повторно выполняет запрос.

serving/widget/public/with_request_interceptor/app.js
// Handle source selection
document.getElementById('sources').onchange = (e) => {
  resultsContainerAdapter.selectedSource = e.target.value;
  let request = resultsContainer.getCurrentRequest();
  if (request.query) {
    // Re-execute if there's a valid query. The source selection
    // will be applied in the interceptor.
    resultsContainer.resetState();
    resultsContainer.executeRequest(request);
  }
}

Также можно перехватывать ответы поисковых запросов, реализовав интерфейс interceptSearchResponse в адаптере.

Версии для закрепления

  • Версия API : Установите значение в cloudsearch.config/apiVersion перед инициализацией.
  • Версия виджета : Используйте gapi.config.update('cloudsearch.config/clientVersion', 1.1) .

Оба параметра по умолчанию равны 1,0, если не заданы.

Например, чтобы закрепить виджет за версией 1.1:

serving/widget/public/basic/app.js
gapi.config.update('cloudsearch.config/apiVersion', 'v1');

Защитите интерфейс поиска

Применяйте лучшие практики обеспечения безопасности веб-приложений, особенно для предотвращения кликджекинга .

Включить отладку

Используйте interceptSearchRequest для включения отладки:

if (!request.requestOptions) {
  request.requestOptions = {};
}
request.requestOptions.debugOptions = {enableDebugging: true};
return request;