إنشاء واجهة بحث باستخدام أداة البحث

توفّر أداة البحث المصغّرة واجهة بحث قابلة للتخصيص لتطبيقات الويب. يتطلّب الحد الأدنى من HTML وJavaScript للتنفيذ ويتوافق مع الميزات الشائعة، مثل الأوجه والتقسيم على صفحات. يمكنك أيضًا تخصيص الواجهة باستخدام CSS وJavaScript.

إذا كنت بحاجة إلى مزيد من المرونة، استخدِم Query API. اطّلِع على إنشاء واجهة بحث باستخدام Query API.

إنشاء واجهة بحث

يتطلّب إنشاء واجهة البحث اتّباع الخطوات التالية:

  1. إعداد تطبيق بحث
  2. أنشئ معرّف عميل للتطبيق.
  3. أضِف ترميز HTML لمربّع البحث والنتائج.
  4. حمِّل الأداة على الصفحة.
  5. إعداد التطبيق المصغّر

إعداد تطبيق بحث

تتطلّب كل واجهة بحث تطبيق بحث محدّدًا في "وحدة تحكّم المشرف". يوفر التطبيق إعدادات طلب البحث، مثل مصادر البيانات والواجهات ومعلمات جودة البحث.

لإنشاء تطبيق بحث، يُرجى الاطّلاع على مقالة إنشاء تجربة بحث مخصّصة.

إنشاء معرّف عميل للتطبيق

بالإضافة إلى الخطوات الواردة في إعداد إذن الوصول إلى Cloud Search API، عليك إنشاء معرّف عميل لتطبيق الويب.

إعداد مشروع

عند ضبط إعدادات المشروع:

لمزيد من المعلومات، يُرجى الاطّلاع على بروتوكول OAuth 2.0 لتطبيقات الويب من جهة العميل.

إضافة ترميز HTML

تتطلّب الأداة عناصر HTML التالية:

  • عنصر 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 معاودة الاتصال عندما يكون المحمّل جاهزًا، استدعِ الدالة gapi.load() لتحميل وحدة العميل لواجهة برمجة التطبيقات ووحدة &quot;تسجيل الدخول باستخدام Google&quot; ووحدة 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)
}

إعداد التطبيق المصغّر

ابدأ مكتبة العميل باستخدام gapi.client.init() أو gapi.auth2.init() مع معرّف العميل ونطاق https://www.googleapis.com/auth/cloud_search.query. استخدِم فئات أداة الإنشاء لضبط التطبيق المصغّر وربطه.

مثال على عملية الإعداد:

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 للمواقع الإلكترونية للحصول على تجربة مخصّصة.

منح الأذونات للمستخدمين مباشرةً

استخدِم ميزة تسجيل الدخول باستخدام حساب Google لمراقبة حالات تسجيل الدخول وإدارتها. يستخدم هذا المثال 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();
};

تسجيل دخول المستخدمين تلقائيًا

يمكنك منح التطبيق إذنًا مسبقًا للمستخدمين في مؤسستك من أجل تبسيط عملية تسجيل الدخول. ويفيد ذلك أيضًا مع Cloud Identity Aware Proxy. اطّلِع على استخدام ميزة &quot;تسجيل الدخول باستخدام حساب Google&quot; مع تطبيقات تكنولوجيا المعلومات.

تخصيص الواجهة

يمكنك تغيير مظهر التطبيق المصغّر من خلال:

  • تجاوز الأنماط باستخدام CSS
  • تزيين العناصر باستخدام محوّل
  • إنشاء عناصر مخصّصة باستخدام أداة ربط

تجاوز الأنماط باستخدام CSS

يتضمّن التطبيق المصغّر ملف CSS خاصًا به. لتجاوزها، استخدِم محدّدات العناصر الأصلية لزيادة التحديد:

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

راجِع مرجع فئات CSS المتوافقة.

تزيين العناصر باستخدام محوّل

أنشئ مسهِّلاً وسجِّله لتعديل العناصر قبل عرضها. يضيف هذا المثال فئة CSS مخصّصة:

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

تسجيل المحوّل أثناء عملية الإعداد:

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

سجِّل المحوّل باتّباع الخطوات التالية:

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

يجب أن تتّبع عناصر التصنيف حسب الأوجه المخصّصة القواعد التالية:

  • أضِف 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 لتعديل الطلبات قبل تنفيذها. يقصر هذا المثال طلبات البحث على مصدر محدّد:

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

سجِّل المحوّل باتّباع الخطوات التالية:

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 في المحوّل.

تثبيت الإصدارات

  • إصدار واجهة برمجة التطبيقات: اضبط القيمة cloudsearch.config/apiVersion قبل بدء عملية التهيئة.
  • إصدار التطبيق المصغّر: استخدِم gapi.config.update('cloudsearch.config/clientVersion', 1.1).

يتم ضبط القيمة التلقائية لكليهما على 1.0 في حال عدم ضبطهما.

على سبيل المثال، لتثبيت الأداة على الإصدار 1.1، اتّبِع الخطوات التالية:

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

تأمين واجهة البحث

اتّبِع أفضل ممارسات الأمان لتطبيقات الويب، خاصةً لمنع اختطاف النقرات.

تفعيل تصحيح الأخطاء

استخدِم interceptSearchRequest لتفعيل تصحيح الأخطاء:

if (!request.requestOptions) {
  request.requestOptions = {};
}
request.requestOptions.debugOptions = {enableDebugging: true};
return request;