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

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

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

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

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

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

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

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

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

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

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

إعداد مشروع

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

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

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

استخدام ميزة تسجيل الدخول باستخدام حساب 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 لحماية التطبيق.

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

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

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

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

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

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

أثناء التحميل، تُحمِّل أداة "بحث Google" ورقة الأنماط التلقائية ديناميكيًا. ويحدث ذلك بعد تحميل أوراق أنماط التطبيق، ما يزيد من أولوية القواعد. لضمان أن تكون للأنماط الخاصة بك الأولوية على الأنماط التلقائية، استخدام محددات الأصل لزيادة خصوصية القواعد الافتراضية.

على سبيل المثال، ليس للقاعدة التالية أي تأثير إذا تم تحميلها في ملف العلامة 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 بشكل متكرر.

توضح المحوّلات التالية إنشاء اقتراح مخصص ونتائج بحث عناصر باستخدام علامات HTML <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;
}

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

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

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

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

تستخدم الأداة بشكل تلقائي أحدث إصدار ثابت من واجهة برمجة التطبيقات. للقفل في إصدار معيّن، اضبط معلَمة الإعداد 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 في حال ترك السياسة بدون ضبط أو ضبطها على قيمة غير صالحة.

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

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

لمزيد من المعلومات، يُرجى الاطّلاع على مشروع دليل OWASP.

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

استخدام interceptSearchRequest لتفعيل تصحيح الأخطاء في تطبيق "بحث Google" المصغّر على سبيل المثال:

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

  return request;