Membuat antarmuka penelusuran dengan widget penelusuran

Widget penelusuran memberikan antarmuka penelusuran yang dapat disesuaikan untuk aplikasi web. Widget ini memerlukan HTML dan JavaScript minimal untuk diterapkan dan mendukung fitur umum seperti faset dan penomoran halaman. Anda juga dapat menyesuaikan antarmuka dengan CSS dan JavaScript.

Jika Anda membutuhkan lebih banyak fleksibilitas, gunakan Query API. Lihat Membuat antarmuka penelusuran dengan Query API.

Membuat antarmuka penelusuran

Membuat antarmuka penelusuran memerlukan langkah-langkah berikut:

  1. Mengonfigurasi aplikasi penelusuran.
  2. Buat ID klien untuk aplikasi.
  3. Tambahkan markup HTML untuk kotak dan hasil penelusuran.
  4. Muat widget di halaman.
  5. Lakukan inisialisasi widget.

Mengonfigurasi aplikasi penelusuran

Setiap antarmuka penelusuran memerlukan aplikasi penelusuran yang ditentukan di konsol Admin. Aplikasi ini menyediakan setelan kueri, seperti sumber data, faset, dan parameter kualitas penelusuran.

Untuk membuat aplikasi penelusuran, lihat Membuat pengalaman penelusuran khusus.

Membuat ID klien untuk aplikasi

Selain langkah-langkah dalam Mengonfigurasi akses ke Cloud Search API, buat ID klien untuk aplikasi web Anda.

Mengonfigurasi project

Saat mengonfigurasi project:

  • Pilih jenis klien Browser web.
  • Berikan URI asal aplikasi Anda.
  • Catat ID klien. Widget tidak memerlukan rahasia klien.

Untuk mengetahui informasi selengkapnya, lihat OAuth 2.0 untuk Aplikasi Web Sisi Klien.

Menambahkan markup HTML

Widget memerlukan elemen HTML berikut:

  • Elemen input untuk kotak penelusuran.
  • Elemen untuk mengaitkan dialog saran.
  • Elemen untuk hasil penelusuran.
  • (Opsional) Elemen untuk kontrol faset.

Cuplikan ini menampilkan elemen yang diidentifikasi oleh atribut 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>

Memuat widget

Sertakan pemuat menggunakan tag <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>

Berikan callback onload. Saat pemuat siap, panggil gapi.load() untuk memuat klien API, Login dengan Google, dan modul 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)
}

Menginisialisasi widget

Lakukan inisialisasi library klien menggunakan gapi.client.init() atau gapi.auth2.init() dengan ID klien dan cakupan https://www.googleapis.com/auth/cloud_search.query. Gunakan class builder untuk mengonfigurasi dan mengikat widget.

Contoh inisialisasi:

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'
    });
  });
}

Variabel konfigurasi:

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/...";

Menyesuaikan pengalaman login

Widget akan meminta pengguna untuk login saat mereka mulai mengetik. Anda dapat menggunakan Login dengan Google untuk Situs untuk mendapatkan pengalaman yang disesuaikan.

Mengotorisasi pengguna secara langsung

Gunakan Login dengan Google untuk memantau dan mengelola status login. Contoh ini menggunakan GoogleAuth.signIn() saat tombol diklik:

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

Membuat pengguna login secara otomatis

Otorisasi aplikasi terlebih dahulu untuk pengguna di organisasi Anda guna menyederhanakan login. Fitur ini juga berguna dengan Cloud Identity Aware Proxy. Lihat Menggunakan Login dengan Google dengan Aplikasi IT.

Menyesuaikan antarmuka

Anda dapat mengubah tampilan widget dengan:

  • Mengganti gaya dengan CSS.
  • Mendekorasi elemen dengan adaptor.
  • Membuat elemen kustom dengan adaptor.

Mengganti gaya dengan CSS

Widget ini menyertakan CSS-nya sendiri. Untuk menggantinya, gunakan pemilih ancestor untuk meningkatkan kekhususan:

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

Lihat referensi Class CSS yang didukung.

Mendekorasi elemen dengan adaptor

Buat dan daftarkan adaptor untuk mengubah elemen sebelum merender. Contoh ini menambahkan class CSS kustom:

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');
}

Daftarkan adaptor selama inisialisasi:

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();

Membuat elemen kustom dengan adaptor

Implementasikan createSuggestionElement, createFacetResultElement, atau createSearchResultElement untuk membuat komponen UI kustom. Contoh ini menggunakan tag 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;
}

Daftarkan adaptor:

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();

Elemen facet kustom harus mengikuti aturan berikut:

  • Lampirkan cloudsearch_facet_bucket_clickable ke elemen yang dapat diklik.
  • Bungkus setiap bucket dalam cloudsearch_facet_bucket_container.
  • Pertahankan urutan bucket dari respons.

Misalnya, cuplikan berikut merender faset menggunakan link, bukan kotak centang.

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) {
  // ...
}

Menyesuaikan perilaku penelusuran

Ganti setelan aplikasi penelusuran dengan menghalangi permintaan menggunakan adaptor. Terapkan interceptSearchRequest untuk mengubah permintaan sebelum dieksekusi. Contoh ini membatasi kueri ke sumber yang dipilih:

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;
}

Daftarkan adaptor:

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 berikut digunakan untuk menampilkan kotak centang guna memfilter berdasarkan sumber:

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>

Kode berikut mendeteksi perubahan, menetapkan pilihan, dan mengeksekusi ulang kueri jika diperlukan.

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);
  }
}

Anda juga dapat menghalangi respons penelusuran dengan menerapkan interceptSearchResponse di adaptor.

Menyematkan versi

  • API version: Tetapkan cloudsearch.config/apiVersion sebelum melakukan inisialisasi.
  • Versi widget: Gunakan gapi.config.update('cloudsearch.config/clientVersion', 1.1).

Keduanya ditetapkan secara default ke 1.0 jika tidak ditetapkan.

Misalnya, untuk menyematkan widget ke versi 1.1:

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

Mengamankan antarmuka penelusuran

Ikuti praktik terbaik keamanan untuk aplikasi web, terutama untuk mencegah clickjacking.

Mengaktifkan proses debug

Gunakan interceptSearchRequest untuk mengaktifkan proses debug:

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