खोज विजेट के साथ खोज इंटरफ़ेस बनाना

सर्च विजेट, वेब ऐप्लिकेशन के लिए पसंद के मुताबिक खोज इंटरफ़ेस उपलब्ध कराता है. विजेट को लागू करने के लिए, सिर्फ़ कुछ एचटीएमएल और JavaScript की ज़रूरत होती है. साथ ही, ये पहलुओं और पेज पर नंबर डालने जैसी सामान्य खोज सुविधाओं को चालू करता है. सीएसएस और JavaScript की मदद से, इंटरफ़ेस के कुछ हिस्सों को अपनी पसंद के मुताबिक भी बनाया जा सकता है.

अगर आपको विजेट में दिए गए विकल्पों के अलावा और विकल्प चाहिए, तो Query API का इस्तेमाल करें. क्वेरी एपीआई की मदद से खोज इंटरफ़ेस बनाने के बारे में जानकारी पाने के लिए, क्वेरी एपीआई की मदद से खोज इंटरफ़ेस बनाना देखें.

सर्च इंटरफ़ेस बनाना

खोज इंटरफ़ेस बनाने के लिए, कई चरणों को पूरा करना ज़रूरी है:

  1. सर्च ऐप्लिकेशन कॉन्फ़िगर करना
  2. ऐप्लिकेशन के लिए क्लाइंट आईडी जनरेट करना
  3. खोज बॉक्स और नतीजों के लिए एचटीएमएल मार्कअप जोड़ना
  4. पेज पर विजेट लोड करना
  5. विजेट को शुरू करना

सर्च ऐप्लिकेशन कॉन्फ़िगर करना

हर खोज इंटरफ़ेस के लिए, Admin console में एक खोज ऐप्लिकेशन तय होना चाहिए. सर्च ऐप्लिकेशन, क्वेरी के लिए ज़्यादा जानकारी देता है, जैसे कि डेटा सोर्स, पहलू, और खोज क्वालिटी की सेटिंग.

सर्च ऐप्लिकेशन बनाने के लिए, पसंद के मुताबिक खोज अनुभव बनाना लेख पढ़ें.

ऐप्लिकेशन के लिए क्लाइंट आईडी जनरेट करना

Google Cloud Search API का ऐक्सेस कॉन्फ़िगर करना में बताए गए चरणों के अलावा, आपको वेब ऐप्लिकेशन के लिए क्लाइंट आईडी भी जनरेट करना होगा.

कोई प्रोजेक्ट कॉन्फ़िगर करना

प्रोजेक्ट कॉन्फ़िगर करने पर:

  • वेब ब्राउज़र क्लाइंट टाइप चुनें
  • अपने ऐप्लिकेशन का ऑरिजिन यूआरआई दें.
  • बनाए गए क्लाइंट आईडी का नोट. अगले चरण को पूरा करने के लिए, आपको Client-ID की ज़रूरत होगी. विजेट के लिए क्लाइंट सीक्रेट की ज़रूरत नहीं होती.

ज़्यादा जानकारी के लिए, क्लाइंट-साइड वेब ऐप्लिकेशन के लिए OAuth 2.0 लेख पढ़ें.

एचटीएमएल मार्कअप जोड़ना

विजेट के काम करने के लिए, थोड़ा एचटीएमएल होना ज़रूरी है. आपको यह जानकारी देनी होगी:

  • खोज बॉक्स के लिए input एलिमेंट.
  • सुझाव वाले पॉप-अप को ऐंकर करने के लिए एलिमेंट.
  • खोज के नतीजों को शामिल करने वाला एलिमेंट.
  • (ज़रूरी नहीं) फ़ेसेट कंट्रोल को शामिल करने के लिए कोई एलिमेंट दें.

यहां दिया गया एचटीएमएल स्निपेट, खोज विजेट के लिए एचटीएमएल दिखाता है. इसमें, बाउंड किए जाने वाले एलिमेंट की पहचान उनके 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>

विजेट लोड करना

विजेट को लोडर स्क्रिप्ट की मदद से डाइनैमिक तरीके से लोड किया जाता है. लोडर को शामिल करने के लिए, <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>

आपको स्क्रिप्ट टैग में onload कॉलबैक देना होगा. लोडर के तैयार होने पर, फ़ंक्शन को कॉल किया जाता है. जब लोडर तैयार हो जाए, तो एपीआई क्लाइंट, Google साइन-इन, और Cloud Search मॉड्यूल को लोड करने के लिए, gapi.load() को कॉल करके विजेट लोड करना जारी रखें.

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

सभी मॉड्यूल लोड होने के बाद, initializeApp() फ़ंक्शन को कॉल किया जाता है.

विजेट को शुरू करना

सबसे पहले, जनरेट किए गए क्लाइंट आईडी और https://www.googleapis.com/auth/cloud_search.query स्कोप के साथ gapi.client.init() या gapi.auth2.init() को कॉल करके, क्लाइंट लाइब्रेरी को शुरू करें. इसके बाद, विजेट को कॉन्फ़िगर करने और उसे अपने एचटीएमएल एलिमेंट से जोड़ने के लिए, gapi.cloudsearch.widget.resultscontainer.Builder और gapi.cloudsearch.widget.searchbox.Builder क्लास का इस्तेमाल करें.

नीचे दिए गए उदाहरण में, विजेट को शुरू करने का तरीका बताया गया है:

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

ऊपर दिए गए उदाहरण में, कॉन्फ़िगरेशन के लिए दो वैरिएबल के बारे में बताया गया है. इनके बारे में यहां बताया गया है:

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

साइन इन करने के अनुभव को पसंद के मुताबिक बनाना

डिफ़ॉल्ट रूप से, विजेट पर क्वेरी टाइप करने पर, उपयोगकर्ताओं को साइन इन करने और ऐप्लिकेशन को अनुमति देने के लिए कहा जाता है. उपयोगकर्ताओं को साइन इन करने का बेहतर अनुभव देने के लिए, वेबसाइटों के लिए Google Sign-in का इस्तेमाल किया जा सकता है.

उपयोगकर्ताओं को सीधे अनुमति देना

उपयोगकर्ता के साइन-इन स्टेटस को मॉनिटर करने और ज़रूरत के हिसाब से उपयोगकर्ताओं को साइन-इन या साइन-आउट करने के लिए, Google से साइन इन करें सुविधा का इस्तेमाल करें. उदाहरण के लिए, यहां दिए गए उदाहरण में, साइन इन करने के तरीके में हुए बदलावों को मॉनिटर करने के लिए isSignedIn स्टेटस को देखा गया है. साथ ही, बटन पर क्लिक करके साइन इन करने की प्रोसेस शुरू करने के लिए, GoogleAuth.signIn() तरीके का इस्तेमाल किया गया है:

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

ज़्यादा जानकारी के लिए, 'Google से साइन इन करें' लेख पढ़ें.

उपयोगकर्ताओं को अपने-आप साइन इन करना

अपने संगठन के उपयोगकर्ताओं की ओर से ऐप्लिकेशन को पहले से अनुमति देकर, साइन इन करने की प्रोसेस को और आसान बनाया जा सकता है. ऐप्लिकेशन को सुरक्षित रखने के लिए, Cloud Identity-Aware Proxy का इस्तेमाल करने पर भी यह तकनीक काम की होती है.

ज़्यादा जानकारी के लिए, आईटी ऐप्लिकेशन के साथ Google साइन इन का इस्तेमाल करना देखें.

इंटरफ़ेस को पसंद के मुताबिक बनाना

कई तरीकों का इस्तेमाल करके, खोज इंटरफ़ेस के दिखने का तरीका बदला जा सकता है:

  • सीएसएस की मदद से स्टाइल बदलना
  • अडैप्टर की मदद से एलिमेंट को सजाना
  • अडैप्टर की मदद से कस्टम एलिमेंट बनाना

सीएसएस का इस्तेमाल करके स्टाइल बदलना

खोज विजेट में, सुझाव और नतीजों के एलिमेंट को स्टाइल करने के लिए अपनी सीएसएस होती है. साथ ही, पेजेशन कंट्रोल भी होते हैं. ज़रूरत के हिसाब से, इन एलिमेंट को फिर से स्टाइल किया जा सकता है.

लोड होने के दौरान, सर्च विजेट अपनी डिफ़ॉल्ट स्टाइलशीट को डाइनैमिक तौर पर लोड करता है. ऐसा, ऐप्लिकेशन स्टाइलशीट लोड होने के बाद होता है. इससे नियमों की प्राथमिकता बढ़ जाती है. यह पक्का करने के लिए कि आपकी स्टाइल, डिफ़ॉल्ट स्टाइल से ज़्यादा प्राथमिकता पाएं, डिफ़ॉल्ट नियमों को ज़्यादा सटीक बनाने के लिए, पैरंट सेलेक्टर्स का इस्तेमाल करें.

उदाहरण के लिए, अगर दस्तावेज़ में स्टैटिक link या style टैग में लोड किया जाता है, तो नीचे दिए गए नियम का कोई असर नहीं पड़ता.

.cloudsearch_suggestion_container {
  font-size: 14px;
}

इसके बजाय, पेज में बताए गए पैरंट कंटेनर के आईडी या क्लास के साथ नियम को मंज़ूरी दें.

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

विजेट की मदद से जनरेट की गई सहायता क्लास और एचटीएमएल के उदाहरण की सूची के लिए, काम करने वाली सीएसएस क्लास रेफ़रंस देखें.

एलिमेंट को अडैप्टर से सजाएं

रेंडर करने से पहले एलिमेंट को सजाने के लिए, एक ऐसा अडैप्टर बनाएं और उसे फिर से सेट करें जो सजावट के किसी एक तरीके को लागू करता हो. जैसे, decorateSuggestionElement या decorateSearchResultElement.

उदाहरण के लिए, नीचे दिए गए अडैप्टर, सुझाव और नतीजे के एलिमेंट में एक कस्टम क्लास जोड़ते हैं.

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

विजेट को शुरू करते समय अडैप्टर को रजिस्टर करने के लिए, Builder क्लास के setAdapter() तरीके का इस्तेमाल करें:

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

डेकोरेटर, कंटेनर एलिमेंट के साथ-साथ किसी भी चाइल्ड एलिमेंट के एट्रिब्यूट में बदलाव कर सकते हैं. सजावट के दौरान, चाइल्ड एलिमेंट जोड़े या हटाए जा सकते हैं. हालांकि, अगर एलिमेंट के स्ट्रक्चर में बदलाव किए जा रहे हैं, तो उन्हें सजाने के बजाय सीधे तौर पर बनाएं.

अडैप्टर की मदद से कस्टम एलिमेंट बनाना

सुझाव, फ़ेसेट कंटेनर या खोज के नतीजे के लिए कस्टम एलिमेंट बनाने के लिए, ऐसा अडैप्टर बनाएं और रजिस्टर करें जो createSuggestionElement, createFacetResultElement या createSearchResultElement को लागू करता हो.

नीचे दिए गए अडैप्टर, एचटीएमएल <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;
}

विजेट को शुरू करते समय अडैप्टर को फिर से रजिस्टर करने के लिए, इससे जुड़ी Builder क्लास के setAdapter() तरीके का इस्तेमाल करें:

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

createFacetResultElement के साथ कस्टम फ़ेसेट एलिमेंट बनाने पर, कई पाबंदियां लागू होती हैं:

  • आपको उस एलिमेंट में सीएसएस क्लास cloudsearch_facet_bucket_clickable अटैच करना होगा जिस पर क्लिक करके उपयोगकर्ता, बकेट को टॉगल करते हैं.
  • आपको हर बकेट को सीएसएस क्लास cloudsearch_facet_bucket_container वाले एलिमेंट में रैप करना होगा.
  • बकेट को उस क्रम में रेंडर नहीं किया जा सकता जिस क्रम में वे रिस्पॉन्स में दिखती हैं.

उदाहरण के लिए, यहां दिया गया स्निपेट, चेक बॉक्स के बजाय लिंक का इस्तेमाल करके फ़ेसेट रेंडर करता है.

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

खोज के तरीके को पसंद के मुताबिक बनाना

सर्च ऐप्लिकेशन की सेटिंग, खोज इंटरफ़ेस के लिए डिफ़ॉल्ट कॉन्फ़िगरेशन दिखाती हैं और ये स्टैटिक होती हैं. डाइनैमिक फ़िल्टर या पहलू लागू करने के लिए, जैसे कि उपयोगकर्ताओं को डेटा सोर्स को टॉगल करने की अनुमति देना. इसके लिए, अडैप्टर का इस्तेमाल करके खोज के अनुरोध को इंटरसेप्ट करके, खोज ऐप्लिकेशन की सेटिंग बदली जा सकती हैं.

interceptSearchRequest के तरीके के साथ अडैप्टर लागू करें, ताकि search API को किए गए अनुरोधों को लागू करने से पहले उनमें बदलाव किया जा सके.

उदाहरण के लिए, यह अडैप्टर, उपयोगकर्ता के चुने गए सोर्स पर क्वेरी को सीमित करने के अनुरोधों को इंटरसेप्ट करता है:

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

विजेट को शुरू करते समय अडैप्टर को रजिस्टर करने के लिए, ResultsContainer बनाते समय 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();

स्रोतों के हिसाब से फ़िल्टर करने के लिए, एक बॉक्स दिखाने के लिए इस एचटीएमएल का इस्तेमाल किया जाता है:

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>

नीचे दिया गया कोड, बदलाव को सुनता है, चुने गए विकल्प को सेट करता है, और ज़रूरत पड़ने पर क्वेरी को फिर से चलाता है.

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

अडैप्टर में interceptSearchResponse लागू करके भी, खोज के जवाब को रोका जा सकता है.

एपीआई वर्शन को पिन करना

डिफ़ॉल्ट रूप से, विजेट एपीआई के सबसे नए वर्शन का इस्तेमाल करता है. किसी खास वर्शन को लॉक करने के लिए, विजेट को शुरू करने से पहले cloudsearch.config/apiVersion कॉन्फ़िगरेशन पैरामीटर को पसंदीदा वर्शन पर सेट करें.

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

अगर एपीआई वर्शन की वैल्यू सेट नहीं की गई है या अमान्य वैल्यू पर सेट है, तो यह डिफ़ॉल्ट रूप से 1.0 पर सेट हो जाएगा.

विजेट का वर्शन पिन करें

खोज इंटरफ़ेस में अनचाहे बदलावों से बचने के लिए, cloudsearch.config/clientVersion कॉन्फ़िगरेशन पैरामीटर को इस तरह सेट करें:

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

अगर इस एट्रिब्यूट की वैल्यू सेट नहीं की जाती है या अमान्य वैल्यू पर सेट की जाती है, तो विजेट का वर्शन डिफ़ॉल्ट रूप से 1.0 पर सेट हो जाएगा.

सर्च इंटरफ़ेस को सुरक्षित बनाएं

खोज के नतीजों में बेहद संवेदनशील जानकारी शामिल है. वेब ऐप्लिकेशन को सुरक्षित रखने के लिए, सबसे सही तरीके अपनाएं. खास तौर पर, क्लिक जैकिंग अटैक से सुरक्षित रखने के लिए.

ज़्यादा जानकारी के लिए, OWASP गाइड प्रोजेक्ट देखें

डीबग करने की सुविधा चालू करना

Search विजेट के लिए डीबग करने की सुविधा चालू करने के लिए, interceptSearchRequest का इस्तेमाल करें. उदाहरण के लिए:

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

  return request;