یک رابط جستجو با ویجت جستجو ایجاد کنید

ویجت جستجو یک رابط جستجوی قابل تنظیم برای برنامه های کاربردی وب فراهم می کند. ویجت فقط به مقدار کمی از HTML و جاوا اسکریپت برای پیاده سازی نیاز دارد و ویژگی های جستجوی رایج مانند وجوه و صفحه بندی را فعال می کند. همچنین می توانید بخش هایی از رابط را با CSS و جاوا اسکریپت سفارشی کنید.

اگر به انعطاف پذیری بیشتری نسبت به ویجت نیاز دارید، از Query API استفاده کنید. برای اطلاعات در مورد ایجاد رابط جستجو با Query API، به ایجاد رابط جستجو با Query API مراجعه کنید.

یک رابط جستجو بسازید

ساخت رابط جستجو به چندین مرحله نیاز دارد:

  1. یک برنامه جستجو را پیکربندی کنید
  2. شناسه مشتری برای برنامه ایجاد کنید
  3. نشانه گذاری HTML را برای کادر جستجو و نتایج اضافه کنید
  4. ویجت را در صفحه بارگیری کنید
  5. ویجت را راه اندازی کنید

یک برنامه جستجو را پیکربندی کنید

هر رابط جستجو باید یک برنامه جستجو تعریف شده در کنسول مدیریت داشته باشد. برنامه جستجو اطلاعات بیشتری را برای پرس و جو فراهم می کند، مانند منابع داده، جنبه ها و تنظیمات کیفیت جستجو.

برای ایجاد یک برنامه جستجو، به ایجاد تجربه جستجوی سفارشی مراجعه کنید.

شناسه مشتری برای برنامه ایجاد کنید

علاوه بر مراحل پیکربندی دسترسی به Google Cloud Search API ، همچنین باید شناسه مشتری برای برنامه وب ایجاد کنید.

یک پروژه را پیکربندی کنید

وقتی پروژه را پیکربندی می کنید:

  • نوع مشتری مرورگر وب را انتخاب کنید
  • URI مبدا برنامه خود را ارائه دهید.
  • یادداشت شناسه مشتری که ایجاد شده است. برای تکمیل مراحل بعدی به شناسه مشتری نیاز دارید. راز مشتری برای ویجت مورد نیاز نیست.

برای اطلاعات بیشتر، OAuth 2.0 را برای برنامه وب سمت مشتری ببینید.

اضافه کردن نشانه گذاری HTML

ویجت برای عملکرد به مقدار کمی HTML نیاز دارد. شما باید ارائه دهید:

  • یک عنصر input برای کادر جستجو.
  • عنصری برای لنگر انداختن پنجره بازشو.
  • عنصری که حاوی نتایج جستجو است.
  • (اختیاری) عنصری را برای کنترل جنبه‌ها ارائه دهید.

قطعه HTML زیر HTML را برای ویجت جستجو نشان می دهد، جایی که عناصری که باید محدود شوند با ویژگی 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 ارائه دهید. این تابع زمانی فراخوانی می شود که لودر آماده باشد. هنگامی که لودر آماده شد، با فراخوانی gapi.load() به بارگیری ویجت ادامه دهید تا ماژول های سرویس گیرنده API، Google Sign-in و 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)
}

تابع initializeApp() پس از بارگیری همه ماژول ها فراخوانی می شود.

ویجت را راه اندازی کنید

ابتدا کتابخانه سرویس گیرنده را با فراخوانی gapi.client.init() یا gapi.auth2.init() با شناسه مشتری تولید شده خود و محدوده https://www.googleapis.com/auth/cloud_search.query مقداردهی اولیه کنید. در مرحله بعد، از کلاس های gapi.cloudsearch.widget.resultscontainer.Builder و gapi.cloudsearch.widget.searchbox.Builder برای پیکربندی ویجت و اتصال آن به عناصر HTML خود استفاده کنید.

مثال زیر نحوه مقداردهی اولیه ویجت را نشان می دهد:

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 for Websites استفاده کنید تا تجربه ورود به سیستم مناسب‌تری را برای کاربران ارائه دهید.

به طور مستقیم به کاربران مجوز دهید

از Sign In With 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 با برنامه‌های فناوری اطلاعات را ببینید.

رابط کاربری را سفارشی کنید

شما می توانید ظاهر رابط جستجو را از طریق ترکیبی از تکنیک ها تغییر دهید:

  • با CSS استایل ها را نادیده بگیرید
  • عناصر را با آداپتور تزئین کنید
  • عناصر سفارشی را با آداپتور ایجاد کنید

با CSS استایل ها را نادیده بگیرید

ویجت جستجو با CSS خاص خود برای استایل دادن به عناصر پیشنهادی و نتیجه و همچنین کنترل های صفحه بندی ارائه می شود. در صورت نیاز می توانید این عناصر را تغییر دهید.

در طول بارگذاری، ویجت جستجو به صورت پویا شیوه نامه پیش فرض خود را بارگیری می کند. این امر پس از بارگیری شیوه نامه های برنامه رخ می دهد و اولویت قوانین را افزایش می دهد. برای اطمینان از ارجحیت سبک‌های خود بر سبک‌های پیش‌فرض، از انتخابگرهای اجدادی برای افزایش ویژگی‌های قوانین پیش‌فرض استفاده کنید.

به عنوان مثال، قانون زیر اگر در یک link ثابت یا برچسب style در سند بارگذاری شود، تأثیری ندارد.

.cloudsearch_suggestion_container {
  font-size: 14px;
}

در عوض، قانون را با شناسه یا کلاس کانتینر اجدادی که در صفحه اعلام شده است، واجد شرایط کنید.

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

برای فهرستی از کلاس‌های پشتیبانی و نمونه HTML تولید شده توسط ویجت، به مرجع کلاس‌های CSS پشتیبانی شده مراجعه کنید.

عناصر را با آداپتور تزئین کنید

برای تزئین یک عنصر قبل از رندر کردن، یک آداپتور ایجاد کنید و دوباره ثبت کنید که یکی از روش‌های تزئینی مانند 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');
}

برای ثبت آداپتور هنگام مقداردهی اولیه ویجت، از متد setAdapter() کلاس 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();

دکوراتورها ممکن است ویژگی های عنصر ظرف و همچنین هر عنصر فرزند را تغییر دهند. عناصر کودک ممکن است در طول دکوراسیون اضافه یا حذف شوند. با این حال، در صورت ایجاد تغییرات ساختاری در عناصر، به جای تزئین، عناصر را مستقیماً ایجاد کنید.

عناصر سفارشی را با آداپتور ایجاد کنید

برای ایجاد یک عنصر سفارشی برای یک پیشنهاد، محفظه جنبه یا نتیجه جستجو، آداپتوری ایجاد و ثبت کنید که به طور متناوب createSuggestionElement ، createFacetResultElement ، یا createSearchResultElement را پیاده سازی می کند.

آداپتورهای زیر ایجاد پیشنهادات سفارشی و عناصر نتایج جستجو را با استفاده از تگ‌های <template> HTML نشان می‌دهند.

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

برای ثبت نام آداپتور هنگام مقداردهی اولیه ویجت، از متد setAdapter() کلاس 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();

ایجاد عناصر وجه سفارشی با createFacetResultElement مشمول چندین محدودیت است:

  • شما باید کلاس CSS cloudsearch_facet_bucket_clickable را به عنصری که کاربران روی آن کلیک می کنند وصل کنید تا یک سطل را تغییر دهید.
  • شما باید هر سطل را در یک عنصر حاوی کلاس CSS 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 برای اصلاح درخواست‌های ارائه شده به 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;
}

برای ثبت آداپتور هنگام مقداردهی اولیه ویجت، از متد setAdapter() هنگام ساخت 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();

HTML زیر برای نمایش کادر انتخاب برای فیلتر کردن بر اساس منابع استفاده می شود:

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 در آداپتور، پاسخ جستجو را رهگیری کنید.

نسخه API را پین کنید

به طور پیش فرض ویجت از آخرین نسخه پایدار API استفاده می کند. برای قفل کردن یک نسخه خاص، پارامتر پیکربندی cloudsearch.config/apiVersion قبل از مقداردهی اولیه ویجت روی نسخه ترجیحی تنظیم کنید.

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

اگر تنظیم نشود یا روی مقدار نامعتبر تنظیم شود، نسخه API به طور پیش‌فرض روی 1.0 خواهد بود.

پین کردن نسخه ویجت

برای جلوگیری از تغییرات غیرمنتظره در رابط های جستجو، پارامتر پیکربندی cloudsearch.config/clientVersion را مطابق شکل تنظیم کنید:

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

اگر تنظیم نشود یا روی مقدار نامعتبر تنظیم شود، نسخه ویجت به طور پیش‌فرض روی 1.0 خواهد بود.

رابط جستجو را ایمن کنید

نتایج جستجو حاوی اطلاعات بسیار حساس است. بهترین شیوه ها را برای ایمن سازی برنامه های وب، به ویژه در برابر حملات کلیک جکینگ دنبال کنید.

برای اطلاعات بیشتر، پروژه راهنمای OWASP را ببینید

اشکال زدایی را فعال کنید

از interceptSearchRequest برای روشن کردن اشکال زدایی برای ویجت جستجو استفاده کنید. مثلا:

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

  return request;