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

تنظيم صفحاتك في مجموعات يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.

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

إذا كنت بحاجة إلى مرونة أكبر من الأداة، يمكنك استخدام واجهة برمجة تطبيقات طلبات البحث. للحصول على معلومات عن إنشاء واجهة بحث باستخدام واجهة برمجة تطبيقات طلبات البحث، يُرجى الرجوع إلى إنشاء واجهة بحث باستخدام واجهة برمجة تطبيقات طلبات البحث.

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

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

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

ضبط تطبيق بحث

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

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

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

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

ضبط مشروع

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

  • اختيار نوع العميل متصفِّح ويب
  • أدخل معرّف الموارد المنتظم (URI) المصدر لتطبيقك.
  • ملاحظة عن معرِّف العميل الذي تم إنشاؤه وستحتاج إلى معرِّف العميل لإكمال الخطوات التالية. سر العميل ليس مطلوبًا للأداة.

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

إضافة ترميز HTML

وتتطلب الأداة قدرًا صغيرًا من HTML لتعمل. عليك تقديم:

  • عنصر input لمربّع البحث.
  • عنصر لإحداء النافذة المنبثقة للاقتراح.
  • عنصر يحتوي على نتائج البحث.
  • (خطوة اختيارية) أدخِل عنصرًا يحتوي على عناصر التحكّم في الواجهات.

يعرض مقتطف HTML التالي رمز HTML لأداة بحث، حيث يتم تحديد العناصر المطلوب ربطها من خلال سمة id:

العرض/التطبيقات المصغّرة/متاحة للجميع/مع_css/الفهرسة.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> كما هو موضّح في ما يلي:

العرض/التطبيقات المصغّرة/متاحة للجميع/مع_css/الفهرسة.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() لتحميل برنامج واجهة برمجة التطبيقات وتسجيل الدخول بحساب Google ووحدات 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 للمواقع الإلكترونية لتقديم تجربة تسجيل دخول أكثر تخصيصًا للمستخدمين.

تفويض المستخدمين مباشرةً

استخدِم ميزة تسجيل الدخول باستخدام حساب Google لمراقبة حالة تسجيل دخول المستخدمين والمستخدمين الذين يسجّلون الدخول أو الخروج. على سبيل المثال، يلاحظ المثال التالي حالة isSignedIn لمراقبة تغييرات تسجيل الدخول ويستخدم طريقة GoogleAuth.signIn() لبدء تسجيل الدخول من خلال النقر على الزر:

العرض/التطبيقات المصغّرة/متاحة للجميع/مع_تسجيل الدخول/التطبيقات.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 لحماية التطبيق.

لمزيد من المعلومات، يمكنك الاطّلاع على استخدام تسجيل الدخول بحساب Google مع تطبيقات تكنولوجيا المعلومات.

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

يمكنك تغيير مظهر واجهة البحث من خلال مجموعة من الأساليب:

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

إلغاء الأنماط باستخدام CSS

تأتي أداة البحث مع خدمة CSS الخاصة بها لاختيار تصميم الاقتراحات والنتائج، بالإضافة إلى عناصر التحكّم في التقسيم على صفحات. ويمكنك إعادة تصميم هذه العناصر حسب الحاجة.

أثناء التحميل، تُحمّل أداة البحث ورقة الأنماط التلقائية بشكل ديناميكي. ويحدث ذلك بعد تحميل أوراق أنماط التطبيق، ما يؤدي إلى رفع أولوية القواعد. للتأكّد من أنّ أنماطك تحظى بالأولوية على الأنماط التلقائية، استخدِم أدوات اختيار الأصل لزيادة دقة قواعدها التلقائية.

على سبيل المثال، لا يكون للقاعدة التالية أي تأثير في حال تحميلها في علامة link أو style ثابتة في المستند.

.cloudsearch_suggestion_container {
  font-size: 14px;
}

بدلاً من ذلك، يجب تأهيل القاعدة باستخدام رقم تعريف أو فئة حاوية الأصل.

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

للحصول على قائمة بفئات الدعم ومثال HTML الذي أنشأته الأداة، راجِع مرجع فئات CSS المتوافقة.

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

لتزيين عنصر قبل العرض، أنشِئ محوّلًا ينفّذ إحدى طرق التزيين وأدرجه مجددًا، مثل decorateSuggestionElement أو decorateSearchResultElement..

على سبيل المثال، تضيف المحوّلات التالية فئة مخصّصة إلى عناصر الاقتراح والنتيجة.

العرض/التطبيقات المصغّرة/متاحة للجميع/مع_decoated_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 المناسبة:

العرض/التطبيقات المصغّرة/متاحة للجميع/مع_decoated_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 بشكلٍ مجيب بشكل مؤقت وتسجيله.

توضّح المحوّلات التالية إنشاء عناصر مخصّصة للاقتراحات ونتائج البحث باستخدام علامات HTML <template>.

العرض/التطبيقات المصغّرة/متاحة للجميع/مع_مخصّصة/عنصر التطبيق.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 لتعديل الطلبات التي تم إجراؤها في واجهة برمجة تطبيقات البحث قبل التنفيذ.

على سبيل المثال، يعترض المحوِّل التالي الطلبات لقصر طلبات البحث على مصدر يختاره المستخدم:

العرض/التطبيقات المصغّرة/متاحة للجميع/مع_طلب_اعتراض/تطبيق.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.

العرض/التطبيقات المصغّرة/متاحة للجميع/مع_طلب_اعتراض/تطبيق.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 التالي لعرض مربّع اختيار للفلترة حسب المصادر:

العرض/التطبيقات المصغّرة/متاحة للجميع/مع_طلب_اعتراض/فهرس.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 في المحوّل.

تثبيت إصدار واجهة برمجة التطبيقات

ويتم استخدام أحدث إصدار ثابت من واجهة برمجة التطبيقات تلقائيًا. ولقفل إصدار معيّن من الإعدادات، عليك ضبط معلَمة الضبط cloudsearch.config/apiVersion على الإصدار المفضّل قبل إعداد الأداة.

العرض/التطبيقات المصغّرة/متاحة للجميع/الأساسية/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.

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

استخدام interceptSearchRequest لتفعيل تصحيح الأخطاء لأداة البحث مثلاً:

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

  return request;