Suchoberfläche mit dem Such-Widget erstellen

Mit dem Such-Widget steht Ihnen eine anpassbare Suchoberfläche für Webanwendungen zur Verfügung. Für das Widget wird nur wenig HTML- und JavaScript-Code benötigt, um gängige Suchfunktionen zu implementieren und zu aktivieren, z. B. Facetten und Paginierung. Sie können mit CSS und JavaScript auch Teile der Benutzeroberfläche anpassen.

Wenn Sie mehr Flexibilität benötigen als vom Widget angeboten, sollten Sie die Query API verwenden. Weitere Informationen zum Erstellen einer Suchoberfläche mit der Query API

Suchoberfläche erstellen

So erstellen Sie eine Suchoberfläche:

  1. Suchanwendung konfigurieren
  2. Client-ID für die Anwendung generieren
  3. Dem Suchfeld und den Suchergebnissen HTML-Markup hinzufügen
  4. Widget auf die Seite laden
  5. Widget initialisieren

Suchanwendung konfigurieren

Für jede Suchoberfläche muss in der Admin-Konsole eine Suchanwendung definiert werden. Die Suchanwendung enthält zusätzliche Informationen für die Abfrage, z. B. Datenquellen, Facetten und Einstellungen für die Suchqualität.

Informationen zum Erstellen einer Suchanwendung finden Sie im Hilfeartikel Benutzerdefinierte Suche erstellen.

Client-ID für die Anwendung generieren

Zusätzlich zu den Schritten in der Anleitung zum Konfigurieren des Zugriffs auf die Google Cloud Search API müssen Sie auch eine Client-ID für die Webanwendung generieren.

Projekt konfigurieren

Bei der Konfiguration eines Projekts sollten Sie Folgendes tun:

  • Wählen Sie als Clienttyp Webbrowser aus.
  • Geben Sie den Origin-URI Ihrer App an.
  • Notieren Sie sich die erstellte Client-ID. Sie benötigen diese für die nächsten Schritte. Der Clientschlüssel ist für das Widget nicht erforderlich.

Weitere Informationen

HTML-Markup hinzufügen

Damit das Widget funktioniert, ist etwas HTML-Code erforderlich. Sie müssen Folgendes angeben:

  • Ein input-Element für das Suchfeld.
  • Ein Element, um das Pop-up für Vorschläge zu verankern.
  • Ein Element, in dem die Suchergebnisse enthalten sind.
  • Optional: Ein Element, das die Steuerelemente für Facets enthält

Im folgenden Snippet sehen Sie den HTML-Code für ein Such-Widget, wobei die zu bindenden Elemente durch ihr Attribut id identifiziert werden:

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 laden

Das Widget wird über ein Lader-Skript dynamisch geladen. Verwenden Sie das Tag <script> folgendermaßen, um den Lader einzubinden:

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>

Im Skript-Tag müssen Sie einen onload-Funktionsaufruf bereitstellen. Die Funktion wird aufgerufen, wenn der Lader bereit ist. Fahren Sie dann mit dem Laden des Widgets fort, indem Sie gapi.load() aufrufen. So werden der API-Client für Google Log-in und für Cloud Search geladen.

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

Die Funktion initializeApp() wird aufgerufen, nachdem alle Module geladen wurden.

Widget initialisieren

Initialisieren Sie zuerst die Clientbibliothek, indem Sie gapi.client.init() oder gapi.auth2.init() mit Ihrer generierten Client-ID und dem Bereich https://www.googleapis.com/auth/cloud_search.query aufrufen. Verwenden Sie als Nächstes die Klassen gapi.cloudsearch.widget.resultscontainer.Builder und gapi.cloudsearch.widget.searchbox.Builder, um das Widget zu konfigurieren und an Ihre HTML-Elemente zu binden.

Im folgenden Beispiel sehen Sie, wie das Widget initialisiert wird:

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

Im obigen Beispiel wird für die Konfiguration auf zwei Variablen verwiesen, die folgendermaßen definiert sind:

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

Anmeldung anpassen

Standardmäßig werden Nutzer vom Widget aufgefordert, sich anzumelden und die App zu autorisieren, sobald sie mit der Eingabe einer Abfrage beginnen. Mithilfe von Google Log-in für Websites können Sie Ihren Nutzern eine individuellere Anmeldung anbieten.

Nutzer direkt autorisieren

Verwenden Sie Über Google anmelden, um den Anmeldestatus eines Nutzers zu überwachen und diesen bei Bedarf an- oder abzumelden. Im folgenden Beispiel wird beispielsweise der Status isSignedIn beobachtet, um Änderungen bei der Anmeldung zu überwachen. Die Anmeldung wird über die Methode GoogleAuth.signIn() gestartet, wenn auf eine Schaltfläche geklickt wird:

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

Weitere Informationen finden Sie unter Über Google anmelden.

Nutzer automatisch anmelden

Sie können die Anmeldung weiter optimieren, indem Sie die Anwendung für die Nutzer in Ihrer Organisation vorab autorisieren. Diese Technik ist auch nützlich, wenn Sie Cloud Identity-Aware Proxy verwenden, um die Anwendung zu schützen.

Weitere Informationen finden Sie im Artikel Google Log-in mit IT-Apps verwenden.

Benutzeroberfläche anpassen

Sie können das Erscheinungsbild der Suchoberfläche durch eine Kombination verschiedener Vorgänge ändern:

  • Stile mit CSS überschreiben
  • Elemente mit einem Adapter dekorieren
  • Benutzerdefinierte Elemente mit einem Adapter erstellen

Stile mit CSS überschreiben

Das Such-Widget hat ein eigenes CSS, um Vorschlags- und Ergebniselemente sowie die Steuerelemente für die Paginierung zu formatieren. Sie können diese Elemente nach Bedarf umgestalten.

Während des Ladevorgangs wird auch das Stylesheet des Such-Widgets dynamisch geladen. Dies geschieht nach dem Laden von Anwendungs-Stylesheets, wodurch die Priorität der Regeln erhöht wird. Wenn Sie dafür sorgen möchten, dass Ihre eigenen Stile Vorrang vor den Standardstilen haben, verwenden Sie Ancestor-Selektoren, um die Standardregeln spezifischer zu gestalten.

Die folgende Regel hat beispielsweise keine Auswirkungen, wenn sie in einen statischen link- oder style-Tag im Dokument geladen wird:

.cloudsearch_suggestion_container {
  font-size: 14px;
}

Qualifizieren Sie die Regel stattdessen mit der ID oder der Klasse des auf der Seite deklarierten übergeordneten Containers.

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

Weitere Informationen zu den unterstützen CSS-Klassen und Beispiel-HTML, die vom Widget erstellt wurden

Elemente mit einem Adapter dekorieren

Wenn Sie ein Element vor dem Rendern dekorieren möchten, erstellen und registrieren Sie einen Adapter, der eine der Dekorationsmethoden wie decorateSuggestionElement oder decorateSearchResultElement. implementiert.

Durch die folgenden Adapter werden den Elementen für Vorschläge und Ergebnisse beispielsweise eine benutzerdefinierte Klasse hinzugefügt.

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

Wenn Sie den Adapter bei der Initialisierung des Widgets registrieren möchten, verwenden Sie die Methode setAdapter() der jeweiligen Builder-Klasse:

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

Mit einem Decorator können die Attribute des Containerelements sowie alle untergeordneten Elemente geändert werden. Untergeordnete Elemente können während der Dekoration hinzugefügt oder entfernt werden. Wenn Sie jedoch strukturelle Änderungen an den Elementen vornehmen, sollten Sie die Elemente direkt erstellen, anstatt sie zu dekorieren.

Benutzerdefinierte Elemente mit einem Adapter erstellen

Wenn Sie ein benutzerdefiniertes Element für einen Vorschlag, einen Facettencontainer oder ein Suchergebnis erstellen möchten, erstellen und registrieren Sie einen Adapter, der createSuggestionElement, createFacetResultElement oder createSearchResultElement implementiert.

Die folgenden Adapter veranschaulichen, wie benutzerdefinierte Vorschlags- und Suchergebniselemente mithilfe von <template>-HTML-Tags erstellt werden.

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

Wenn Sie den Adapter bei der Initialisierung des Widgets registrieren möchten, verwenden Sie die Methode setAdapter() der jeweiligen Builder-Klasse:

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

Für das Erstellen benutzerdefinierter Facetten-Elemente mit createFacetResultElement gibt es mehrere Einschränkungen:

  • Die CSS-Klasse cloudsearch_facet_bucket_clickable muss an das Element angehängt werden, auf das Nutzer klicken, um zwischen Buckets durchzuwechseln.
  • Jeder Bucket muss sich in einem Element befinden. Verwenden Sie hierzu die CCS-Klasse cloudsearch_facet_bucket_container.
  • Buckets können nur in der Reihenfolge gerendert werden, die die Antwort vorgibt.

Im folgenden Snippet werden Facetten beispielsweise mithilfe von Links anstelle von Kästchen dargestellt.

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

Suchverhalten anpassen

Die Einstellungen der Suchanwendung stellen die Standardkonfiguration für eine Suchoberfläche dar und sind statisch. Wenn dynamische Filter oder Facetten implementiert werden sollen, z. B. um Nutzern den Wechsel zwischen Datenquellen zu ermöglichen, können Sie die Einstellungen der Suchanwendung überschreiben. Dazu fangen Sie die Suchanfrage mit einem Adapter ab.

Implementieren Sie einen Adapter mit der Methode interceptSearchRequest, um Anfragen an die Such-API vor der Ausführung zu ändern.

Der folgende Adapter fängt beispielsweise Anforderungen ab, um Abfragen auf eine vom Nutzer ausgewählte Quelle zu beschränken:

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

Wenn Sie den Adapter bei der Initialisierung des Widgets registrieren möchten, verwenden Sie beim Erstellen des ResultsContainer die Methode setAdapter().

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

Der folgende HTML-Code wird verwendet, um ein Auswahlfeld zum Filtern nach Quellen anzuzeigen:

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>

Mit dem folgenden Code soll die Änderung erkannt, die Auswahl getroffen und die Abfrage falls nötig neu ausgeführt werden.

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

Sie können die Suchantwort auch abfangen, indem Sie interceptSearchResponse im Adapter implementieren.

API-Version anpinnen

Standardmäßig verwendet das Widget die neueste stabile Version der API. Soll eine bestimmte Version verwendet werden, legen Sie den Konfigurationsparameter cloudsearch.config/apiVersion auf die bevorzugte Version fest, bevor Sie das Widget initialisieren.

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

Wenn die API-Version nicht festgelegt oder auf einen ungültigen Wert gesetzt ist, wird standardmäßig „1.0“ verwendet.

Widgetversion anpinnen

Um unerwartete Änderungen an Suchoberflächen zu vermeiden, legen Sie den Konfigurationsparameter cloudsearch.config/clientVersion wie unten gezeigt fest:

gapi.config.update('cloudsearch.config/clientVersion', 1.1);

Wenn die Widget-Version nicht festgelegt oder auf einen ungültigen Wert gesetzt ist, wird standardmäßig „1.0“ verwendet.

Suchoberfläche schützen

Die Suchergebnisse enthalten vertrauliche Informationen. Befolgen Sie die Best Practices, um Webanwendungen zu schützen, insbesondere vor Clickjacking-Angriffen.

Weitere Informationen vom Open Web Application Security Project

Debug aktivieren

Verwenden Sie interceptSearchRequest, um die Fehlerbehebung für das Such-Widget zu aktivieren. Beispiel:

  if (!request.requestOptions) {
  // Make sure requestOptions is populated
  request.requestOptions = {};
  }
  // Enable debugging
  request.requestOptions.debugOptions = {enableDebugging: true}

  return request;