Suchoberfläche mit dem Such-Widget erstellen

Das Such-Widget bietet eine anpassbare Suchoberfläche für Webanwendungen. Für das Widget ist nur eine geringe Menge von HTML und JavaScript erforderlich, um gängige Suchfunktionen wie Facetten und Paginierung zu implementieren und zu aktivieren. Sie können auch Teile der Benutzeroberfläche mit CSS und JavaScript anpassen.

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

Suchoberfläche erstellen

Das Erstellen der Suchoberfläche erfordert mehrere Schritte:

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

Suchanwendung konfigurieren

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

Weitere Informationen zum Erstellen einer Suchanwendung finden Sie unter Benutzerdefinierte Suche erstellen.

Client-ID für die Anwendung generieren

Zusätzlich zu den Schritten unter Zugriff auf die Google Cloud Search API konfigurieren musst du auch eine Client-ID für die Webanwendung generieren.

Projekt konfigurieren

Beachten Sie beim Konfigurieren des Projekts Folgendes:

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

Weitere Informationen finden Sie unter OAuth 2.0 für clientseitige Webanwendung.

HTML-Markup hinzufügen

Damit das Widget funktioniert, ist eine geringe Menge an HTML-Code erforderlich. Sie müssen Folgendes angeben:

  • Ein input-Element für das Suchfeld.
  • Ein Element, in dem das Vorschlags-Pop-up verankert wird.
  • Ein -Element, das die Suchergebnisse enthalten soll.
  • Optional: Geben Sie ein Element für die Facet-Steuerelemente an.

Das folgende HTML-Snippet zeigt den HTML-Code für ein Such-Widget, wobei die zu bindenden Elemente durch ihr Attribut id gekennzeichnet werden:

ausliefern/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 Ladeprogramm dynamisch geladen. Verwenden Sie das Tag <script> wie unten gezeigt, um das Ladeprogramm einzuschließen:

ausliefern/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>

Sie müssen einen onload-Callback im Skript-Tag angeben. Die Funktion wird aufgerufen, wenn der Lader bereit ist. Wenn das Ladeprogramm bereit ist, laden Sie das Widget weiter. Rufen Sie dazu gapi.load() auf, um den API-Client, Google Log-in und Cloud Search-Module zu laden.

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. Rufen Sie dazu gapi.client.init() oder gapi.auth2.init() mit Ihrer generierten Client-ID und dem Bereich https://www.googleapis.com/auth/cloud_search.query auf. Mit den Klassen gapi.cloudsearch.widget.resultscontainer.Builder und gapi.cloudsearch.widget.searchbox.Builder können Sie das Widget konfigurieren und an Ihre HTML-Elemente binden.

Das folgende Beispiel zeigt, 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 Beispiel oben werden zwei Variablen zur Konfiguration verwendet:

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 dazu aufgefordert, sich anzumelden und die App zu autorisieren, wenn sie mit der Eingabe einer Abfrage beginnen. Sie können Google Log-in für Websites verwenden, um Nutzern eine individuellere Anmeldung zu bieten.

Nutzer direkt autorisieren

Mit Über Google anmelden kannst du den Anmeldestatus des Nutzers beobachten und bei Bedarf die Nutzer anmelden bzw. abmelden. Im folgenden Beispiel wird der Status isSignedIn beobachtet, um Anmeldeänderungen zu beobachten. Mit der Methode GoogleAuth.signIn() wird die Anmeldung über einen Klick auf eine Schaltfläche initiiert:

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 findest du unter Über Google anmelden.

Nutzer automatisch anmelden

Sie können die Anmeldung weiter optimieren, indem Sie die Anwendung im Namen von Nutzern in Ihrer Organisation autorisieren. Diese Methode ist auch nützlich, wenn Sie die Anwendung mit Cloud Identity-Aware Proxy schützen.

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

Oberfläche anpassen

Sie können die Darstellung der Suchoberfläche durch eine Kombination von Methoden ä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, mit dem sich Vorschlags- und Ergebniselemente sowie die Paginierungssteuerung gestalten lassen. Sie können diese Elemente nach Bedarf umgestalten.

Während des Ladevorgangs lädt das Such-Widget das standardmäßige Stylesheet dynamisch. Dies geschieht nach dem Laden der Anwendungs-Stylesheets, wobei die Priorität der Regeln erhöht wird. Verwenden Sie Ancestor-Selektoren, um die Spezifität der Standardregeln zu erhöhen und sicherzustellen, dass Ihre eigenen Stile Vorrang vor den Standardstilen haben.

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

.cloudsearch_suggestion_container {
  font-size: 14px;
}

Qualifizieren Sie die Regel stattdessen mit der ID oder Klasse des Ancestor-Containers, der auf der Seite deklariert wird.

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

Eine Liste der vom Widget erstellten Supportklassen und Beispiel-HTML finden Sie in der Referenz zu unterstützten CSS-Klassen.

Elemente mit einem Adapter dekorieren

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

Mit den folgenden Adaptern wird beispielsweise den Vorschlägen und Ergebniselementen 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');
}

Verwenden Sie die Methode setAdapter() der entsprechenden Builder-Klasse, um den Adapter beim Initialisieren des Widgets zu registrieren:

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

decoder kann die Attribute des Containerelements und aller untergeordneten Elemente ändern. Untergeordnete Elemente können während der Dekoration hinzugefügt oder entfernt werden. Wenn Sie strukturelle Änderungen an den Elementen vornehmen, sollten Sie sie stattdessen direkt erstellen, statt sie zu dekorieren.

Benutzerdefinierte Elemente mit einem Adapter erstellen

Wenn Sie ein benutzerdefiniertes Element für einen Vorschlag, einen Facet-Container oder ein Suchergebnis erstellen möchten, müssen Sie einen Adapter erstellen und registrieren, mit dem createSuggestionElement, createFacetResultElement oder createSearchResultElement implementiert wird.

Die folgenden Adapter veranschaulichen, wie benutzerdefinierte Vorschlags- und Suchergebniselemente mithilfe von HTML-<template>-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 entsprechenden 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();

Das Erstellen benutzerdefinierter Facet-Elemente mit createFacetResultElement unterliegt mehreren Einschränkungen:

  • Sie müssen die CSS-Klasse cloudsearch_facet_bucket_clickable an das Element anhängen, auf das die Nutzer klicken, um einen Bucket umzuschalten.
  • Jeder Bucket muss in einem Element mit der CSS-Klasse cloudsearch_facet_bucket_container zusammengefasst werden.
  • Sie können die Buckets nur in der Antwort rendern.

Im folgenden Snippet werden beispielsweise Attribute mithilfe von Links anstelle von Kästchen gerendert.

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 Sie dynamische Filter oder Attribute implementieren möchten (z. B. dass Nutzer Datenquellen wechseln dürfen), können Sie die Einstellungen der Suchanwendung überschreiben, indem Sie die Suchanfrage mit einem Adapter abfangen.

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

Mit dem folgenden Adapter werden Anfragen beispielsweise abgefangen, um Abfragen auf eine vom Nutzer ausgewählte Quelle zu beschränken:

Serving/Widget/öffentlich/mit_Anfrage_Abfangen/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 beim Initialisieren des Widgets registrieren möchten, verwenden Sie beim Erstellen von ResultsContainer die Methode setAdapter().

Serving/Widget/öffentlich/mit_Anfrage_Abfangen/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();

Mit dem folgenden HTML-Code wird ein Auswahlfeld zum Filtern nach Quellen angezeigt:

Serving/Widget/öffentlich/mit_Anfrage_Abfangen/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 wird die Änderung erfasst, eine Auswahl getroffen und die Abfrage gegebenenfalls noch einmal ausgeführt.

Serving/Widget/öffentlich/mit_Anfrage_Abfangen/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

Das Widget verwendet standardmäßig die neueste stabile Version der API. Wenn Sie eine bestimmte Version sperren möchten, legen Sie vor dem Initialisieren des Widgets den Konfigurationsparameter cloudsearch.config/apiVersion auf die bevorzugte Version fest.

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

Die API-Version ist standardmäßig auf 1.0 gesetzt, wenn sie nicht konfiguriert oder ein ungültiger Wert festgelegt ist.

Widget-Version anpinnen

Wenn Sie unerwartete Änderungen an Suchoberflächen vermeiden möchten, legen Sie den Konfigurationsparameter cloudsearch.config/clientVersion so fest:

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

Wenn kein Wert festgelegt oder ein ungültiger Wert festgelegt ist, wird standardmäßig die Widget-Version verwendet.

Suchoberfläche schützen

Suchergebnisse enthalten hochsensible Informationen. Halten Sie sich an die Best Practices zum Schutz von Webanwendungen, insbesondere vor Clickjacking-Angriffen.

Weitere Informationen finden Sie im OWASP Guide Project.

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