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

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

اگر به انعطاف‌پذیری بیشتری نسبت به آنچه ویجت ارائه می‌دهد نیاز دارید، استفاده از Query API را در نظر بگیرید. برای اطلاعات بیشتر در مورد ایجاد رابط جستجو با Query API، به «ایجاد رابط جستجو با Query API» مراجعه کنید.

ساخت رابط جستجو

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

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

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

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

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

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

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

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

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

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

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

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

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

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

قطعه کد HTML زیر، کد HTML مربوط به یک ویجت جستجو را نشان می‌دهد که در آن عناصری که باید به آن متصل شوند، با ویژگی id خود شناسایی می‌شوند:

خدمت/ابزارک/عمومی/با_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>

ویجت را بارگذاری کنید

این ویجت به صورت پویا از طریق یک اسکریپت loader بارگذاری می‌شود. برای اضافه کردن loader، از تگ <script> همانطور که نشان داده شده است استفاده کنید:

خدمت/ابزارک/عمومی/با_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 در تگ script قرار دهید. این تابع زمانی فراخوانی می‌شود که لودر آماده باشد. وقتی لودر آماده شد، با فراخوانی gapi.load() به بارگذاری ویجت ادامه دهید تا ماژول‌های API client، Google Sign-in و Cloud Search بارگذاری شوند.

سرویس/ویجت/عمومی/با_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 خود استفاده کنید.

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

سرویس/ویجت/عمومی/با_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'
    });
  });
}

مثال بالا به دو متغیر برای پیکربندی اشاره دارد که به صورت زیر تعریف شده‌اند:

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

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

از ورود با گوگل برای نظارت بر وضعیت ورود کاربر و کاربرانی که در صورت نیاز وارد سیستم می‌شوند یا از سیستم خارج می‌شوند، استفاده کنید. برای مثال، مثال زیر وضعیت isSignedIn را برای نظارت بر تغییرات ورود به سیستم مشاهده می‌کند و از متد GoogleAuth.signIn() برای شروع ورود به سیستم از کلیک یک دکمه استفاده می‌کند:

سرویس/ویجت/عمومی/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();
};

برای جزئیات بیشتر، به ورود با گوگل مراجعه کنید.

ورود خودکار کاربران

شما می‌توانید با پیش‌مجاز کردن برنامه از طرف کاربران سازمان خود، تجربه ورود به سیستم را ساده‌تر کنید. این تکنیک همچنین در صورت استفاده از Cloud Identity Aware Proxy برای محافظت از برنامه مفید است.

برای اطلاعات بیشتر، به «استفاده از ورود به سیستم گوگل با برنامه‌های فناوری اطلاعات» مراجعه کنید.

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

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

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

استایل‌ها را با CSS لغو کنید

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

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

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

.cloudsearch_suggestion_container {
  font-size: 14px;
}

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

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

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

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

برای تزئین یک عنصر قبل از رندر کردن، یک آداپتور ایجاد و ثبت کنید که یکی از متدهای تزئین مانند decorateSuggestionElement یا decorateSearchResultElement.

برای مثال، آداپتورهای زیر یک کلاس سفارشی به عناصر پیشنهاد و نتیجه اضافه می‌کنند.

سرویس/ویجت/عمومی/با_تزئین_عنصر/برنامه.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 مربوطه استفاده کنید:

سرویس/ویجت/عمومی/با_تزئین_عنصر/برنامه.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 نشان می‌دهند.

سرویس/ویجت/عمومی/با_سفارش_عنصر/برنامه.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 مربوطه استفاده کنید:

سرویس/ویجت/عمومی/با_سفارش_عنصر/برنامه.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 قرار دهید.
  • شما نمی‌توانید سطل‌ها را به ترتیبی متفاوت از آنچه در پاسخ ظاهر می‌شوند، رندر کنید.

برای مثال، قطعه کد زیر، وجه‌ها را با استفاده از لینک‌ها به جای چک‌باکس‌ها رندر می‌کند.

خدمت/ابزارک/عمومی/با_سفارش_چهره/برنامه.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 جستجو را قبل از اجرا تغییر دهد.

برای مثال، آداپتور زیر درخواست‌ها را برای محدود کردن پرس‌وجوها به یک منبع انتخاب‌شده توسط کاربر، رهگیری می‌کند:

سرویس/ویجت/عمومی/با_درخواست_رهگیر/برنامه.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() استفاده کنید.

سرویس/ویجت/عمومی/با_درخواست_رهگیر/برنامه.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 زیر برای نمایش یک کادر انتخاب جهت فیلتر کردن بر اساس منابع استفاده می‌شود:

سرویس/ویجت/عمومی/با_درخواست_رهگیر/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>

کد زیر به تغییرات گوش می‌دهد، انتخاب را تنظیم می‌کند و در صورت لزوم، پرس‌وجو را دوباره اجرا می‌کند.

سرویس/ویجت/عمومی/با_درخواست_رهگیر/برنامه.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 را روی نسخه ترجیحی تنظیم کنید.

سرویس/ویجت/عمومی/پایه/برنامه.js
gapi.config.update('cloudsearch.config/apiVersion', 'v1');

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

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

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

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

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

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

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

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

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

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

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

  return request;