Creare un'interfaccia di ricerca con il widget Ricerca

Il widget di ricerca offre un'interfaccia di ricerca personalizzabile per le applicazioni web. Il widget richiede solo una piccola quantità di HTML e JavaScript per implementare e abilitare funzionalità di ricerca comuni come facet e impaginazione. Tu puoi anche personalizzare parti dell'interfaccia con CSS e JavaScript.

Se hai bisogno di maggiore flessibilità rispetto a quella offerta dal widget, valuta l'utilizzo del l'API Query. Per informazioni sulla creazione di un'interfaccia di ricerca con l'API Query, Consulta la sezione Creazione di un'interfaccia di ricerca con l'API Query.

Crea un'interfaccia di ricerca

La creazione dell'interfaccia di ricerca richiede diversi passaggi:

  1. Configura un'applicazione di ricerca
  2. Genera un ID client per l'applicazione
  3. Aggiungi il markup HTML per la casella di ricerca e i risultati
  4. Carica il widget nella pagina
  5. Inizializzare il widget

Configura un'applicazione di ricerca

Ogni interfaccia di ricerca deve avere un'applicazione di ricerca definita nella sezione Console di amministrazione Google. L'applicazione di ricerca fornisce ulteriori le informazioni per la query, come origini dati, facet e la qualità della ricerca.

Per creare un'applicazione di ricerca, consulta: Crea un'esperienza di ricerca personalizzata.

Genera un ID client per l'applicazione

Oltre alla procedura per Configura l'accesso all'API Google Cloud Search. devi generare un ID client per l'applicazione web.

Configurare un progetto

Quando configuri il progetto:

  • Seleziona il tipo di client Browser web.
  • Fornisci l'URI di origine della tua app.
  • Nota relativa all'ID client creato. Avrai bisogno dell'ID client per completa i passaggi successivi. Il client secret non è obbligatorio per widget.

Per ulteriori informazioni, vedi OAuth 2.0 per applicazione web lato client.

Aggiungere il markup HTML

Il widget richiede una piccola porzione di codice HTML per funzionare. Tu devono fornire:

  • Un elemento input per la casella di ricerca.
  • Un elemento a cui ancorare il popup di suggerimento.
  • Un elemento che contenga i risultati di ricerca.
  • (Facoltativo) Fornisci un elemento che contenga i controlli dei facet.

Il seguente snippet HTML mostra il codice HTML di un widget di ricerca, in cui elementi da associare sono identificati tramite il relativo attributo 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>

Carica il widget

Il widget viene caricato in modo dinamico tramite uno script di caricamento. Per includere dal caricatore, utilizza il tag <script> come mostrato di seguito:

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>

Devi fornire un callback onload nel tag script. La funzione viene chiamata quando il caricatore è pronto. Quando il caricatore è pronto, continua a caricare il widget. chiamando gapi.load() per caricare il client API, Accedi con Google e i moduli 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)
}

La funzione initializeApp() viene richiamata dopo che tutti i moduli sono stati caricato.

Inizializzare il widget

Innanzitutto, inizializza la libreria client chiamando gapi.client.init() o gapi.auth2.init() con l'ID cliente generato e l'ambito https://www.googleapis.com/auth/cloud_search.query. Quindi, utilizza gapi.cloudsearch.widget.resultscontainer.Builder e gapi.cloudsearch.widget.searchbox.Builder classi per configurare il widget e associarlo agli elementi HTML.

Il seguente esempio mostra come inizializzare il widget:

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

L'esempio precedente fa riferimento a due variabili per la configurazione definita come:

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

Personalizzare l'esperienza di accesso

Per impostazione predefinita, il widget richiede agli utenti di accedere e autorizzare l'app nel momento in cui iniziano a digitare la query. Puoi utilizzare la modalità Accedi con Google per i siti web per offrire agli utenti un'esperienza di accesso più personalizzata.

Autorizza gli utenti direttamente

Utilizza la funzionalità Accedi con Google per monitorare lo stato di accesso della e accedere o uscire dagli utenti in base alle esigenze. Ad esempio, di esempio osserva la classe isSignedIn per monitorare le modifiche di accesso utilizza GoogleAuth.signIn() per avviare l'accesso da un pulsante clic:

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

Per maggiori dettagli, vedi Accedi con Google.

Consentire l'accesso automatico degli utenti

Puoi semplificare ulteriormente l'esperienza di accesso pre-autorizzando il per conto degli utenti della tua organizzazione. Questa tecnica è è utile anche se utilizzi Cloud Identity Aware Proxy per proteggere l'applicazione.

Per ulteriori informazioni, consulta l'articolo su come utilizzare Accedi con Google con app IT.

Personalizzare l'interfaccia

Puoi modificare l'aspetto dell'interfaccia di ricerca tramite una combinazione le seguenti tecniche:

  • Eseguire l'override degli stili con CSS
  • Decora gli elementi con un adattatore
  • Creare elementi personalizzati con un adattatore

Eseguire l'override degli stili con CSS

Il widget Ricerca è dotato di un proprio CSS per lo stile dei suggerimenti e degli elementi dei risultati nonché i controlli di impaginazione. Puoi modificare lo stile di questi elementi in base alle tue esigenze.

Durante il caricamento, il widget di ricerca carica in modo dinamico il foglio di stile predefinito. Ciò si verifica dopo aver caricato i fogli di stile dell'applicazione, aumentando la priorità delle regole. Per fare in modo che i tuoi stili abbiano la precedenza su quelli predefiniti, Utilizzare i selettori predecessore per aumentare la specificità delle regole predefinite.

Ad esempio, la seguente regola non ha effetto se viene caricata in un ambiente Tag link o style nel documento.

.cloudsearch_suggestion_container {
  font-size: 14px;
}

Qualifica invece la regola con l'ID o la classe del container predecessore dichiarate nella pagina.

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

Per un elenco delle classi di supporto e degli esempi di codice HTML generati dal widget, vedi la sezione Riferimento per le classi CSS supportate.

Decora gli elementi con un adattatore

Per decorare un elemento prima del rendering, crea e reimposta un che implementa uno dei metodi di decorazione come decorateSuggestionElement oppure decorateSearchResultElement.

Ad esempio, i seguenti adattatori aggiungono una classe personalizzata al suggerimento elementi dei risultati.

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

Per registrare l'adattatore durante l'inizializzazione del widget, usa setAdapter() della rispettiva classe Builder:

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

I decoratori possono modificare gli attributi dell'elemento contenitore, così come qualsiasi elementi secondari. Gli elementi secondari possono essere aggiunti o rimossi durante la decorazione. Tuttavia, se apporti modifiche strutturali agli elementi, valuta la possibilità di creare il elementi in modo diretto, invece di decorare.

Creare elementi personalizzati con un adattatore

Per creare un elemento personalizzato per un suggerimento, un contenitore di facet o un risultato di ricerca: crea e registra un adattatore che implementa createSuggestionElement, createFacetResultElement, oppure createSearchResultElement in modo reattivo.

I seguenti adattatori illustrano la creazione di suggerimenti personalizzati e risultati di ricerca utilizzando i 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;
}

Per registrare l'adattatore durante l'inizializzazione del widget, usa setAdapter() della rispettiva classe Builder:

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

Creazione di elementi facet personalizzati con createFacetResultElement è soggetto a diverse restrizioni:

  • Devi collegare la classe CSS cloudsearch_facet_bucket_clickable al su cui gli utenti fanno clic per attivare/disattivare un bucket.
  • Devi racchiudere ogni bucket in un elemento contenitore con il CSS classe cloudsearch_facet_bucket_container.
  • Non puoi eseguire il rendering dei bucket in un ordine diverso da quello in cui appaiono nella risposta.

Ad esempio, il seguente snippet esegue il rendering dei facet utilizzando i link di caselle di controllo.

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

Personalizza il comportamento di ricerca

Le impostazioni dell'applicazione di ricerca rappresentano il valore predefinito configurazione per un'interfaccia di ricerca e sono statici. Per implementare le creatività dinamiche, filtri o facet, ad esempio consentire agli utenti di attivare/disattivare le origini dati, puoi sostituisce le impostazioni dell'applicazione di ricerca intercettando la richiesta di ricerca con un adattatore.

Implementa un adattatore con interceptSearchRequest per modificare le richieste fatte API Search prima dell'esecuzione.

Ad esempio, il seguente adattatore intercetta le richieste per limitare le query a un'origine selezionata dall'utente:

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

Per registrare l'adattatore durante l'inizializzazione del widget, usa il setAdapter() quando crei l'elemento ResultsContainer

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

Il seguente codice HTML viene utilizzato per visualizzare una casella di selezione a cui applicare un filtro in base a fonti:

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>

Il seguente codice rimane in ascolto della modifica, imposta la selezione e ed esegue nuovamente la query, se necessario.

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

Puoi anche intercettare la risposta di ricerca implementando interceptSearchResponse nell'adattatore.

Blocca la versione API

Per impostazione predefinita, il widget utilizza l'ultima versione stabile dell'API. Per bloccare specifica una versione, imposta il parametro di configurazione cloudsearch.config/apiVersion alla versione preferita prima di inizializzare il widget.

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

Se non viene configurata o viene impostata un valore non valido, la versione dell'API sarà 1.0 per impostazione predefinita.

Fissa la versione del widget

Per evitare modifiche impreviste alle interfacce di ricerca, imposta il valore Parametro di configurazione cloudsearch.config/clientVersion come mostrato:

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

Se non viene configurata o viene impostata un valore non valido, la versione del widget sarà 1.0 per impostazione predefinita.

Proteggi l'interfaccia di ricerca

I risultati di ricerca contengono informazioni molto sensibili. Segui le best practice per proteggere le applicazioni web, in particolare attacchi clickjacking.

Per ulteriori informazioni, vedi OWASP Guide Project.

Attiva debug

Utilizza interceptSearchRequest per attivare il debug per il widget di ricerca. Ad esempio:

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

  return request;