واجهة برمجة التطبيقات الخاصة بميزة "الإكمال التلقائي للأماكن"

المطوّرون في المنطقة الاقتصادية الأوروبية

تتيح لك واجهة برمجة التطبيقات Place Autocomplete Data API جلب توقعات الأماكن آليًا، وذلك لإنشاء تجارب إكمال تلقائي مخصّصة مع درجة تحكّم أدقّ من تلك المتاحة باستخدام أداة الإكمال التلقائي. سيوضّح لك هذا الدليل كيفية استخدام واجهة برمجة التطبيقات Place Autocomplete Data API لتقديم طلبات إكمال تلقائي استنادًا إلى طلبات المستخدمين.

يعرض المثال التالي عملية دمج مبسّطة لميزة "البحث أثناء الكتابة". أدخِل طلب البحث، مثل "بيتزا" أو "بوكي"، ثم انقر لاختيار النتيجة التي تريدها.

طلبات الإكمال التلقائي

يتلقّى طلب الإكمال التلقائي سلسلة إدخال لطلب بحث ويعرض قائمة بتوقّعات الأماكن. لإجراء طلب إكمال تلقائي، اتّصِل بـ fetchAutocompleteSuggestions() وأرسِل طلبًا يتضمّن السمات المطلوبة. تحتوي السمة input على السلسلة التي سيتم البحث عنها، وفي تطبيق نموذجي، يتم تعديل هذه القيمة أثناء كتابة المستخدم لطلب البحث. يجب أن يتضمّن الطلب sessionToken، الذي يُستخدَم لأغراض الفوترة.

تعرض المقتطفة التالية كيفية إنشاء نص الطلب وإضافة رمز مميز للجلسة، ثم استدعاء fetchAutocompleteSuggestions() للحصول على قائمة PlacePrediction.

// Add an initial request body.
let request = {
  input: "Tadi",
  locationRestriction: {
    west: -122.44,
    north: 37.8,
    east: -122.39,
    south: 37.78,
  },
  origin: { lat: 37.7893, lng: -122.4039 },
  includedPrimaryTypes: ["restaurant"],
  language: "en-US",
  region: "us",
};
// Create a session token.
const token = new AutocompleteSessionToken();

// Add the token to the request.
// @ts-ignore
request.sessionToken = token;

تقييد عبارات البحث المقترَحة من ميزة "الإكمال التلقائي"

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

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

استخدِم السمة origin لتحديد نقطة البداية التي سيتم منها احتساب المسافة الجيوديسية إلى الوجهة. في حال عدم إدخال هذه القيمة، لن يتم عرض المسافة.

استخدِم السمة includedPrimaryTypes لتحديد ما يصل إلى خمسة أنواع أماكن. في حال عدم تحديد أي أنواع، سيتم عرض الأماكن من جميع الأنواع.

الاطّلاع على مرجع واجهة برمجة التطبيقات

الحصول على تفاصيل المكان

لعرض عنصر Place من نتيجة توقّع مكان، عليك أولاً استدعاء toPlace()، ثم استدعاء fetchFields() على عنصر Place الناتج (يتم تضمين معرّف الجلسة من توقّع المكان تلقائيًا). يؤدي الاتصال بخدمة fetchFields() إلى إنهاء جلسة الإكمال التلقائي.

let place = suggestions[0].placePrediction.toPlace(); // Get first predicted place.

await place.fetchFields({
  fields: ["displayName", "formattedAddress"],
});

const placeInfo = document.getElementById("prediction");

placeInfo.textContent =
  "First predicted place: " +
  place.displayName +
  ": " +
  place.formattedAddress;

رموز الجلسات المميزة

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

لإنشاء رمز مميّز جديد للجلسة وإضافته إلى طلب، أنشئ مثيلاً من AutocompleteSessionToken، ثم اضبط السمة sessionToken للطلب لاستخدام الرموز المميّزة كما هو موضّح في المقتطف التالي:

// Create a session token.
const token = new AutocompleteSessionToken();

// Add the token to the request.
// @ts-ignore
request.sessionToken = token;

تنتهي الجلسة عند استدعاء fetchFields(). بعد إنشاء مثيل Place، لن تحتاج إلى تمرير رمز الجلسة إلى fetchFields() لأنّ ذلك يتم تلقائيًا.

await place.fetchFields({
  fields: ["displayName", "formattedAddress"],
});

أنشئ رمزًا مميزًا للجلسة التالية من خلال إنشاء مثيل جديد من AutocompleteSessionToken.

اقتراحات الرموز المميزة للجلسة:

  • استخدِم رموز الجلسات لجميع طلبات Place Autocomplete.
  • إنشاء رمز مميّز جديد لكل جلسة
  • مرِّر رمزًا مميزًا فريدًا للجلسة لكل جلسة جديدة. سيؤدي استخدام الرمز المميز نفسه لأكثر من جلسة واحدة إلى تحصيل رسوم كل طلب على حدة.

يمكنك اختياريًا حذف رمز الجلسة للإكمال التلقائي من الطلب. في حال عدم تضمين رمز الجلسة، يتم تحصيل رسوم كل طلب على حدة، ما يؤدي إلى تفعيل وحدة حفظ المخزون الإكمال التلقائي - لكل طلب. في حال إعادة استخدام رمز مميّز للجلسة، سيتم اعتبار الجلسة غير صالحة وسيتم تحصيل رسوم مقابل الطلبات كما لو لم يتم تقديم رمز مميّز للجلسة.

مثال

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

من منظور التطبيق، يكون تسلسل الأحداث على النحو التالي:

  1. يبدأ المستخدم في كتابة طلب بحث عن "باريس، فرنسا".
  2. عند رصد إدخال من المستخدم، ينشئ التطبيق رمزًا مميزًا جديدًا للجلسة، وهو "الرمز المميز أ".
  3. أثناء كتابة المستخدم، ترسل واجهة برمجة التطبيقات طلب إكمال تلقائي كل بضعة أحرف، وتعرض قائمة جديدة بالنتائج المحتملة لكل طلب:
    "م"
    "مصر"
    "مصر"
    "مصر"
  4. عندما يحدّد المستخدم خيارًا:
    • يتم تجميع جميع الطلبات الناتجة عن طلب البحث وإضافتها إلى الجلسة الممثّلة بالرمز المميز "أ"، وذلك كطلب واحد.
    • يتم احتساب اختيار المستخدِم كطلب تفاصيل مكان، ويتم إضافته إلى الجلسة الممثّلة بالرمز المميز "الرمز المميز أ".
  5. تنتهي الجلسة، ويتجاهل التطبيق الرمز المميّز "أ".
مزيد من المعلومات حول كيفية فوترة الجلسات

مثال على الرمز البرمجي الكامل

يحتوي هذا القسم على أمثلة كاملة توضّح كيفية استخدام Place Autocomplete Data API .

عبارات البحث المقترحة من ميزة "الإكمال التلقائي للأماكن"

يوضّح المثال التالي كيفية استدعاء fetchAutocompleteSuggestions() لإدخال "Tadi"، ثم استدعاء toPlace() على نتيجة التوقّع الأولى، يليه استدعاء fetchFields() للحصول على تفاصيل المكان.

TypeScript

/**
 * Demonstrates making a single request for Place predictions, then requests Place Details for the first result.
 */
async function init() {
    // @ts-ignore
    const { Place, AutocompleteSessionToken, AutocompleteSuggestion } = await google.maps.importLibrary("places") as google.maps.PlacesLibrary;

    // Add an initial request body.
    let request = {
        input: "Tadi",
        locationRestriction: { west: -122.44, north: 37.8, east: -122.39, south: 37.78 },
        origin: { lat: 37.7893, lng: -122.4039 },
        includedPrimaryTypes: ["restaurant"],
        language: "en-US",
        region: "us",
    };

    // Create a session token.
    const token = new AutocompleteSessionToken();
    // Add the token to the request.
    // @ts-ignore
    request.sessionToken = token;
    // Fetch autocomplete suggestions.
    const { suggestions } = await AutocompleteSuggestion.fetchAutocompleteSuggestions(request);

    const title = document.getElementById('title') as HTMLElement;
    title.appendChild(document.createTextNode('Query predictions for "' + request.input + '":'));

    for (let suggestion of suggestions) {
        const placePrediction = suggestion.placePrediction;

        // Create a new list element.
        const listItem = document.createElement('li');
        const resultsElement = document.getElementById("results") as HTMLElement;
        listItem.appendChild(document.createTextNode(placePrediction.text.toString()));
        resultsElement.appendChild(listItem);
    }

    let place = suggestions[0].placePrediction.toPlace(); // Get first predicted place.
    await place.fetchFields({
        fields: ['displayName', 'formattedAddress'],
    });

    const placeInfo = document.getElementById("prediction") as HTMLElement;
    placeInfo.textContent = 'First predicted place: ' + place.displayName + ': ' + place.formattedAddress;

}

init();

JavaScript

/**
 * Demonstrates making a single request for Place predictions, then requests Place Details for the first result.
 */
async function init() {
  // @ts-ignore
  const { Place, AutocompleteSessionToken, AutocompleteSuggestion } =
    await google.maps.importLibrary("places");
  // Add an initial request body.
  let request = {
    input: "Tadi",
    locationRestriction: {
      west: -122.44,
      north: 37.8,
      east: -122.39,
      south: 37.78,
    },
    origin: { lat: 37.7893, lng: -122.4039 },
    includedPrimaryTypes: ["restaurant"],
    language: "en-US",
    region: "us",
  };
  // Create a session token.
  const token = new AutocompleteSessionToken();

  // Add the token to the request.
  // @ts-ignore
  request.sessionToken = token;

  // Fetch autocomplete suggestions.
  const { suggestions } =
    await AutocompleteSuggestion.fetchAutocompleteSuggestions(request);
  const title = document.getElementById("title");

  title.appendChild(
    document.createTextNode('Query predictions for "' + request.input + '":'),
  );

  for (let suggestion of suggestions) {
    const placePrediction = suggestion.placePrediction;
    // Create a new list element.
    const listItem = document.createElement("li");
    const resultsElement = document.getElementById("results");

    listItem.appendChild(
      document.createTextNode(placePrediction.text.toString()),
    );
    resultsElement.appendChild(listItem);
  }

  let place = suggestions[0].placePrediction.toPlace(); // Get first predicted place.

  await place.fetchFields({
    fields: ["displayName", "formattedAddress"],
  });

  const placeInfo = document.getElementById("prediction");

  placeInfo.textContent =
    "First predicted place: " +
    place.displayName +
    ": " +
    place.formattedAddress;
}

init();

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#map {
  height: 100%;
}

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

HTML

<html>
  <head>
    <title>Place Autocomplete Data API Predictions</title>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="title"></div>
    <ul id="results"></ul>
    <p><span id="prediction"></span></p>
    <img
      class="powered-by-google"
      src="https://storage.googleapis.com/geo-devrel-public-buckets/powered_by_google_on_white.png"
      alt="Powered by Google"
    />

    <!-- prettier-ignore -->
    <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
        ({key: "AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg", v: "weekly"});</script>
  </body>
</html>

تجربة عيّنة

الإكمال التلقائي للأماكن مع ميزة "البحث أثناء الكتابة" باستخدام الجلسات

يوضّح هذا المثال المفاهيم التالية:

  • الاتصال fetchAutocompleteSuggestions() استنادًا إلى طلبات البحث التي يقدّمها المستخدمون وعرض قائمة بالأماكن المتوقّعة استجابةً لذلك
  • استخدام رموز الجلسات المميزة لتجميع طلب بحث مستخدم مع طلب "تفاصيل المكان" النهائي
  • استرداد تفاصيل المكان المحدّد وعرض علامة.
  • استخدام ميزة "تضمين عناصر التحكّم" لتضمين عناصر واجهة المستخدم في العنصر gmp-map

TypeScript

const mapElement = document.querySelector('gmp-map') as google.maps.MapElement;
let innerMap: google.maps.Map;
let marker: google.maps.marker.AdvancedMarkerElement;
let titleElement = document.querySelector('.title') as HTMLElement;
let resultsContainerElement = document.querySelector('.results') as HTMLElement;
let inputElement = document.querySelector('input') as HTMLInputElement;
let tokenStatusElement = document.querySelector('.token-status') as HTMLElement;
let newestRequestId = 0;
let tokenCount = 0;

// Create an initial request body.
const request: google.maps.places.AutocompleteRequest = {
    input: '',
    includedPrimaryTypes: [
        'restaurant',
        'cafe',
        'museum',
        'park',
        'botanical_garden',
    ],
}

async function init() {
    await google.maps.importLibrary('maps');
    innerMap = mapElement.innerMap;
    innerMap.setOptions({
        mapTypeControl: false,
    });

    // Update request center and bounds when the map bounds change.
    google.maps.event.addListener(innerMap, 'bounds_changed', async () => {
        request.locationRestriction = innerMap.getBounds();
        request.origin = innerMap.getCenter();
    });

    inputElement.addEventListener('input', makeAutocompleteRequest);
}

async function makeAutocompleteRequest(inputEvent) {
    // To avoid race conditions, store the request ID and compare after the request.
    const requestId = ++newestRequestId;

    const { AutocompleteSuggestion } = (await google.maps.importLibrary(
        'places'
    )) as google.maps.PlacesLibrary;

    if (!inputEvent.target?.value) {
        titleElement.textContent = '';
        resultsContainerElement.replaceChildren();
        return;
    }

    // Add the latest char sequence to the request.
    request.input = (inputEvent.target as HTMLInputElement).value;

    // Fetch autocomplete suggestions and show them in a list.
    const { suggestions } =
        await AutocompleteSuggestion.fetchAutocompleteSuggestions(request);

    // If the request has been superseded by a newer request, do not render the output.
    if (requestId !== newestRequestId) return;

    titleElement.innerText = `Place predictions for "${request.input}"`;

    // Clear the list first.
    resultsContainerElement.replaceChildren();

    for (const suggestion of suggestions) {
        const placePrediction = suggestion.placePrediction;

        if (!placePrediction) {
            continue;
        }

        // Create a link for the place, add an event handler to fetch the place.
        // We are using a button element to take advantage of its a11y capabilities.
        const placeButton = document.createElement('button');
        placeButton.addEventListener('click', () => {
            onPlaceSelected(placePrediction.toPlace());
        });
        placeButton.textContent = placePrediction.text.toString();
        placeButton.classList.add('place-button');

        // Create a new list item element.
        const li = document.createElement('li');
        li.appendChild(placeButton);
        resultsContainerElement.appendChild(li);
    }
}

// Event handler for clicking on a suggested place.
async function onPlaceSelected(place: google.maps.places.Place) {
    const { AdvancedMarkerElement } = (await google.maps.importLibrary(
        'marker'
    )) as google.maps.MarkerLibrary;

    await place.fetchFields({
        fields: ['displayName', 'formattedAddress', 'location'],
    });

    resultsContainerElement.textContent = `${place.displayName}: ${place.formattedAddress}`;
    titleElement.textContent = 'Selected Place:';
    inputElement.value = '';

    await refreshToken();

    // Remove the previous marker, if it exists.
    if (marker) {
        marker.remove();
    }

    // Create a new marker.
    marker = new AdvancedMarkerElement({
        map: innerMap,
        position: place.location,
        title: place.displayName,
    })

    // Center the map on the selected place.
    if (place.location) {
        innerMap.setCenter(place.location);
        innerMap.setZoom(15);
    }
}

// Helper function to refresh the session token.
async function refreshToken() {
    const { AutocompleteSessionToken } = (await google.maps.importLibrary(
        'places'
    )) as google.maps.PlacesLibrary;

    // Increment the token counter.
    tokenCount++;

    // Create a new session token and add it to the request.
    request.sessionToken = new AutocompleteSessionToken();
    tokenStatusElement.textContent = `Session token count: ${tokenCount}`;
}

init();

JavaScript

const mapElement = document.querySelector('gmp-map');
let innerMap;
let marker;
let titleElement = document.querySelector('.title');
let resultsContainerElement = document.querySelector('.results');
let inputElement = document.querySelector('input');
let tokenStatusElement = document.querySelector('.token-status');
let newestRequestId = 0;
let tokenCount = 0;
// Create an initial request body.
const request = {
    input: '',
    includedPrimaryTypes: [
        'restaurant',
        'cafe',
        'museum',
        'park',
        'botanical_garden',
    ],
};
async function init() {
    await google.maps.importLibrary('maps');
    innerMap = mapElement.innerMap;
    innerMap.setOptions({
        mapTypeControl: false,
    });
    // Update request center and bounds when the map bounds change.
    google.maps.event.addListener(innerMap, 'bounds_changed', async () => {
        request.locationRestriction = innerMap.getBounds();
        request.origin = innerMap.getCenter();
    });
    inputElement.addEventListener('input', makeAutocompleteRequest);
}
async function makeAutocompleteRequest(inputEvent) {
    // To avoid race conditions, store the request ID and compare after the request.
    const requestId = ++newestRequestId;
    const { AutocompleteSuggestion } = (await google.maps.importLibrary('places'));
    if (!inputEvent.target?.value) {
        titleElement.textContent = '';
        resultsContainerElement.replaceChildren();
        return;
    }
    // Add the latest char sequence to the request.
    request.input = inputEvent.target.value;
    // Fetch autocomplete suggestions and show them in a list.
    const { suggestions } = await AutocompleteSuggestion.fetchAutocompleteSuggestions(request);
    // If the request has been superseded by a newer request, do not render the output.
    if (requestId !== newestRequestId)
        return;
    titleElement.innerText = `Place predictions for "${request.input}"`;
    // Clear the list first.
    resultsContainerElement.replaceChildren();
    for (const suggestion of suggestions) {
        const placePrediction = suggestion.placePrediction;
        if (!placePrediction) {
            continue;
        }
        // Create a link for the place, add an event handler to fetch the place.
        // We are using a button element to take advantage of its a11y capabilities.
        const placeButton = document.createElement('button');
        placeButton.addEventListener('click', () => {
            onPlaceSelected(placePrediction.toPlace());
        });
        placeButton.textContent = placePrediction.text.toString();
        placeButton.classList.add('place-button');
        // Create a new list item element.
        const li = document.createElement('li');
        li.appendChild(placeButton);
        resultsContainerElement.appendChild(li);
    }
}
// Event handler for clicking on a suggested place.
async function onPlaceSelected(place) {
    const { AdvancedMarkerElement } = (await google.maps.importLibrary('marker'));
    await place.fetchFields({
        fields: ['displayName', 'formattedAddress', 'location'],
    });
    resultsContainerElement.textContent = `${place.displayName}: ${place.formattedAddress}`;
    titleElement.textContent = 'Selected Place:';
    inputElement.value = '';
    await refreshToken();
    // Remove the previous marker, if it exists.
    if (marker) {
        marker.remove();
    }
    // Create a new marker.
    marker = new AdvancedMarkerElement({
        map: innerMap,
        position: place.location,
        title: place.displayName,
    });
    // Center the map on the selected place.
    if (place.location) {
        innerMap.setCenter(place.location);
        innerMap.setZoom(15);
    }
}
// Helper function to refresh the session token.
async function refreshToken() {
    const { AutocompleteSessionToken } = (await google.maps.importLibrary('places'));
    // Increment the token counter.
    tokenCount++;
    // Create a new session token and add it to the request.
    request.sessionToken = new AutocompleteSessionToken();
    tokenStatusElement.textContent = `Session token count: ${tokenCount}`;
}
init();

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#map {
  height: 100%;
}

/* 
 * Optional: Makes the sample page fill the window. 
 */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

.place-button {
  height: 3rem;
  width: 100%;
  background-color: transparent;
  text-align: left;
  border: none;
  cursor: pointer;
}

.place-button:focus-visible {
  outline: 2px solid #0056b3;
  border-radius: 2px;
}

.input {
  width: 300px;
  font-size: small;
  margin-bottom: 1rem;
}

/* Styles for the floating panel */
.controls {
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
  font-family: sans-serif;
  font-size: small;
  margin: 12px;
  padding: 1rem;
}

.title {
  font-weight: bold;
  margin-top: 1rem;
  margin-bottom: 0.5rem;
}

.results {
  list-style-type: none;
  margin: 0;
  padding: 0;
}

.results li:not(:last-child) {
  border-bottom: 1px solid #ddd;
}

.results li:hover {
  background-color: #eee;
}

HTML

<html>
    <head>
        <title>Place Autocomplete Data API Session</title>

        <link rel="stylesheet" type="text/css" href="./style.css" />
        <script type="module" src="./index.js"></script>
        <!-- prettier-ignore -->
        <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
        ({key: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "weekly"});</script>
    </head>
    <body>
        <gmp-map center="37.7893, -122.4039" zoom="12" map-id="DEMO_MAP_ID">
            <div
                class="controls"
                slot="control-inline-start-block-start"
            >
                <input
                    type="text"
                    class="input"
                    placeholder="Search for a place..."
                    autocomplete="off"
                /><!-- Turn off the input's own autocomplete (not supported by all browsers).-->
                <div class="token-status"></div>
                <div class="title"></div>
                <ol class="results"></ol>
            </div>
        </gmp-map>
    </body>
</html>

تجربة عيّنة