Arama widget'ıyla arama arayüzü oluşturma

Arama widget'ı, web uygulamaları için özelleştirilebilir bir arama arayüzü sağlar. Uygulamak için minimum düzeyde HTML ve JavaScript gerektirir ve yönler ile sayfalara ayırma gibi yaygın özellikleri destekler. Arayüzü CSS ve JavaScript ile de özelleştirebilirsiniz.

Daha fazla esnekliğe ihtiyacınız varsa Query API'yi kullanın. Query API ile arama arayüzü oluşturma başlıklı makaleyi inceleyin.

Arama arayüzü oluşturma

Arama arayüzünü oluşturmak için şu adımlar gerekir:

  1. Arama uygulaması yapılandırma
  2. Uygulama için bir istemci kimliği oluşturun.
  3. Arama kutusu ve sonuçları için HTML işaretlemesi ekleyin.
  4. Widget'ı sayfaya yükleyin.
  5. Widget'ı başlatın.

Arama uygulaması yapılandırma

Her arama arayüzü için Yönetici Konsolu'nda tanımlanmış bir arama uygulaması gerekir. Uygulama, veri kaynakları, özellikler ve arama kalitesi parametreleri gibi sorgu ayarları sağlar.

Arama uygulaması oluşturmak için Özel arama deneyimi oluşturma başlıklı makaleyi inceleyin.

Uygulama için istemci kimliği oluşturma

Cloud Search API'ye erişimi yapılandırma bölümündeki adımlara ek olarak web uygulamanız için bir istemci kimliği oluşturun.

Proje yapılandırma

Projeyi yapılandırırken:

  • Web tarayıcısı istemci türünü seçin.
  • Uygulamanızın kaynak URI'sini girin.
  • İstemci kimliğini not edin. Widget için istemci gizli anahtarı gerekmez.

Daha fazla bilgi için İstemci Tarafı Web Uygulaması için OAuth 2.0 başlıklı makaleyi inceleyin.

HTML biçimlendirmesi ekleme

Widget için şu HTML öğeleri gerekir:

  • Arama kutusu için bir input öğesi.
  • Öneri iletişim kutusunu sabitlemek için kullanılan bir öğe.
  • Arama sonuçları için bir öğe.
  • (İsteğe bağlı) Faset kontrolleri için bir öğe.

Bu snippet'te, id özellikleriyle tanımlanan öğeler gösterilmektedir:

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>

Widget'ı yükleme

Yükleyiciyi <script> etiketi kullanarak ekleyin:

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>

onloadGeri arama sağlayın. Yükleyici hazır olduğunda API istemcisini, Google ile Giriş'i ve Cloud Search modüllerini yüklemek için gapi.load() işlevini çağırın.

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

Widget'ı başlatma

İstemci kitaplığını gapi.client.init() veya gapi.auth2.init() ile istemci kimliğiniz ve https://www.googleapis.com/auth/cloud_search.query kapsamınızla başlatın. Widget'ı yapılandırmak ve bağlamak için oluşturucu sınıflarını kullanın.

Örnek başlatma:

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

Yapılandırma değişkenleri:

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

Oturum açma deneyimini özelleştirme

Kullanıcılar yazmaya başladığında widget, oturum açmalarını ister. Kişiselleştirilmiş bir deneyim için web sitelerinde Google ile oturum açma özelliğini kullanabilirsiniz.

Kullanıcıları doğrudan yetkilendirme

Oturum açma durumlarını izlemek ve yönetmek için Google ile oturum açma özelliğini kullanın. Bu örnekte, düğme tıklaması için GoogleAuth.signIn() kullanılmaktadır:

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

Kullanıcıların oturumunu otomatik olarak açma

Oturum açma sürecini kolaylaştırmak için kuruluşunuzdaki kullanıcılar adına uygulamaya önceden yetki verin. Bu özellik, Cloud Identity-Aware Proxy ile de kullanışlıdır. Google ile oturum açma özelliğini BT uygulamalarıyla kullanma başlıklı makaleyi inceleyin.

Arayüzü özelleştirme

Widget'ın görünümünü değiştirmek için:

  • CSS ile stilleri geçersiz kılma.
  • Adaptörle süsleme öğeleri.
  • Adaptörle özel öğeler oluşturma.

CSS ile stilleri geçersiz kılma

Widget kendi CSS'sini içerir. Bunu geçersiz kılmak için özgüllüğü artırmak üzere üst öğe seçicileri kullanın:

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

Desteklenen CSS sınıfları referansına bakın.

Öğeleri adaptörle süsleme

Oluşturma işleminden önce öğeleri değiştirmek için bir bağdaştırıcı oluşturup kaydedin. Bu örnekte özel bir CSS sınıfı ekleniyor:

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

İlk kullanıma hazırlama sırasında bağdaştırıcıyı kaydedin:

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

Adaptörle özel öğeler oluşturma

Özel kullanıcı arayüzü bileşenleri oluşturmak için createSuggestionElement, createFacetResultElement veya createSearchResultElement öğelerini uygulayın. Bu örnekte HTML <template> etiketleri kullanılmaktadır:

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

Adaptörü kaydedin:

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

Özel yön öğeleri aşağıdaki kurallara uymalıdır:

  • Tıklanabilir öğelere cloudsearch_facet_bucket_clickable ekleyin.
  • Her grubu cloudsearch_facet_bucket_container içine alın.
  • Yanıtın sıralamasını koruyun.

Örneğin, aşağıdaki snippet, onay kutuları yerine bağlantıları kullanarak yönleri oluşturur.

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

Arama davranışını özelleştirme

İstekleri bir bağdaştırıcıyla yakalayarak arama uygulaması ayarlarını geçersiz kılın. İstekleri yürütülmeden önce değiştirmek için interceptSearchRequest'yı uygulayın. Bu örnek, sorguları seçili bir kaynakla sınırlandırır:

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

Adaptörü kaydedin:

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

Kaynaklara göre filtreleme için bir seçim kutusu görüntülemek üzere aşağıdaki HTML kullanılır:

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>

Aşağıdaki kod, değişikliği dinler, seçimi ayarlar ve gerekirse sorguyu yeniden yürütür.

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

Ayrıca, bağdaştırıcıda interceptSearchResponse uygulayarak arama yanıtını engelleyebilirsiniz.

Sürümleri sabitleme

  • API sürümü: Başlatmadan önce cloudsearch.config/apiVersion olarak ayarlayın.
  • Widget sürümü: gapi.config.update('cloudsearch.config/clientVersion', 1.1) kullanın.

Ayarlanmamışsa her ikisi de varsayılan olarak 1,0 olur.

Örneğin, widget'ı 1.1 sürümüne sabitlemek için:

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

Arama arayüzünü güvenli hale getirme

Web uygulamaları için en iyi güvenlik uygulamalarını takip edin. Özellikle tıklama tuzağı saldırılarını önlemek için bu uygulamaları takip etmeniz önemlidir.

Hata ayıklamayı etkinleştirme

Hata ayıklamayı etkinleştirmek için interceptSearchRequest kullanın:

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