requestAutocomplete

أخذ أموالي، وليس وقتي

مقدمة

أحبّ الويب. بوجهٍ عام، أعتقد أنّ هذه فكرة جيدة. ولهذا السبب، أشارك في الكثير من المناقشات حول الويب مقارنةً بالتطبيقات الأصلية. لا يستغرق الأمر وقتًا طويلاً حتى يبدأ الشخص الآخر في الحديث عن سهولة الدفع من خلال الأنظمة الأصلية. ردّي المعتاد هو إلقاء قنبلة دخانية والخروج من الغرفة ضاحكًا بشكل مجنون، لأنّه ليس من الجدل الذي يمكنني الفوز به. يمكن أن تصل نسبة التخلّي عن سلة التسوّق على الموقع الإلكتروني المتوافق مع الأجهزة الجوّالة إلى%97. تخيل ذلك في العالم الواقعي. تخيل أنّ% 97 من الأشخاص في سوبرماركت لديهم سلة مليئة بالأشياء التي يريدونها، ويقلبون سلّتهم ويغادرون. في الوقت الحالي، يحدّد بعض هؤلاء الأشخاص أسعارًا مرتفعة للمنتجات بدون أن ينوي أحدهم شراؤها، ولكنّ تجربة المستخدم المروعة في الشراء على الويب تساهم بشكل كبير في ذلك. نحن نفرض على المستخدمين ضريبة على صحتهم العقلية. تذكَّر تجربة دفع ممتعة مررت بها على الويب، خاصةً على الأجهزة الجوّالة. هل هذا متجر تطبيقات؟ أو على الأقل نظام مغلق مشابه يتضمّن معلومات الدفع هذه مشكلة. وتتطلّب هذه الشروط من المواقع الإلكترونية الالتزام بمقدّم خدمة دفع معيّن يجب أن يكون لدى المستخدم حساب لديه وأن يكون مسجّلاً الدخول إليه، أو الالتزام بمنصّة تتطلّب من المستخدمين تسجيل الدخول إلى مقدّم خدمة دفع معيّن، مثل متاجر التطبيقات التي تتطلّب منك إنشاء الرموز البرمجية لهذه المنصة فقط. وفي حال عدم تنفيذ أحد هذين الإجراءَين، سيضطر المستخدم إلى النقر على الشاشة أو لوحة المفاتيح إلى أن يُزيل الجلد من أصابعه أو يتخلّى عن المحاولة. علينا حلّ هذه المشكلة.

requestAutocomplete

في عالم WebGL وWebRTC وغيرها من واجهات برمجة التطبيقات المميّزة للويب التي تبدأ بـ "Web"، تبدو requestAutocomplete غير مميّزة. ومع ذلك، فهو بطل خارق يرتدي ملابس بيج. واجهة برمجة تطبيقات صغيرة ومملة يمكنها أن تقضي على مصاص دماء الوقت في عمليات الدفع على الويب.

بدلاً من أن يعتمد الموقع الإلكتروني على مقدّم خدمة دفع معيّن، يطلب تفاصيل الدفع من المتصفّح الذي يخزّنها نيابةً عن المستخدم. إنّ إصدار requestAutocomplete() في Chrome مدمج أيضًا مع "محفظة Google" للمستخدمين في الولايات المتحدة فقط (حاليًا). جرِّب هذه الميزة على موقعنا الإلكتروني التجريبي.

form.requestAutocomplete

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

button.addEventListener('click', function(event) {
  form.requestAutocomplete();
  event.preventDefault();
});

// TODO: listen for autocomplete events on the form

قبل الاطّلاع على الأحداث، علينا التأكّد من أنّ المتصفّح يفهم حقول النموذج…

متطلبات النموذج

في الأيام التي كان فيها الإنترنت بالأبيض والأسود، اعتمدت الإصدارة 5 من Internet Explorer سمة جديدة، وهي autocomplete، على عناصر إدخال النماذج. يمكن ضبطه على "إيقاف" لإيقاف المتصفّح عن تقديم اقتراحات، وهذا كلّ ما في الأمر. تم توسيع نطاق واجهة برمجة التطبيقات هذه حتى تتمكّن من تحديد المحتوى المتوقّع للحقل بدون تعديل السمة "name"، وهذا ما يستخدمه requestAutocomplete لربط حقول النماذج ببيانات المستخدمين.

<input name="fullname" autocomplete="name">

من حيث المواصفات، لا تقتصر requestAutocomplete على عمليات الدفع، ولكن يُرجى العِلم أنّ عملية التنفيذ الحالية في Chrome تقتصر على عمليات الدفع إلى حدٍ كبير. من المتوقّع أن يتمكّن المتصفّحون في المستقبل من التعامل مع أنواع أخرى من البيانات، مثل تفاصيل تسجيل الدخول وأداة إنشاء كلمات المرور ومعلومات جواز السفر وحتى تحميل صورة رمزية.

في Chrome حاليًا، يتعرّف requestAutocomplete على ما يلي:

الدفع

  • بريد إلكتروني
  • cc-name - الاسم كما يظهر على البطاقة
  • cc-number - رقم البطاقة
  • cc-exp-month - شهر انتهاء صلاحية البطاقة بتنسيق من رقمَين
  • cc-exp-year - سنة انتهاء صلاحية البطاقة بالتنسيق أربعة أرقام
  • cc-csc - رمز أمان البطاقة المكوّن من 3 أو 4 أرقام
<input type="email" autocomplete="email" name="email">
<input type="text" autocomplete="cc-name" name="card-name">
<input type="text" autocomplete="cc-number" name="card-num">
<input type="text" autocomplete="cc-exp-month" name="card-exp-month">
<input type="text" autocomplete="cc-exp-year" name="card-exp-year">
<input type="text" autocomplete="cc-csc" name="card-csc">

إنّ سمات "الاسم" التي استخدمتها أعلاه هي أمثلة فقط، وليس من الضروري استخدام قيم معيّنة. إذا كنت ستعيد استخدام هذا النموذج للمستخدمين الذين لا يستخدمون requestAutocomplete، وهو الخيار المثالي، عليك إضافة التصنيفات والتنسيق والتحقّق الأساسي من HTML5.

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

رسالة وحدة تحكّم مفصّلة.
رسالة وحدة التحكّم التفصيلية

العنوان

  • الاسم: الاسم الكامل إنّ استخدام الاسم الكامل كحقل واحد أفضل بكثير من استخدام حقول متعددة. تُظهر الحقول المتعددة، مثل الاسم الأول واسم العائلة، انحيازًا غربيًا وقد لا تكون منطقية للثقافات الأخرى، كما أنّه من الأسهل الكتابة في حقل واحد.

  • ‫tel: رقم الهاتف الكامل بما في ذلك رمز البلد، ويمكن تقسيمه بدلاً من ذلك إلى

    • رمز-البلد-الهاتف، على سبيل المثال ‎+44
    • tel-national - the rest
  • street-address: عنوان كامل يتضمّن مكوّنات مفصولة بفواصل، ويمكن تقسيمه إلى

    • address-line1
    • address-line2 - قد يكون فارغًا
  • المنطقة المحلية - المدينة/البلدة

  • المنطقة: رمز الولاية أو المقاطعة أو الكانتون

  • الرمز البريدي - الرمز البريدي، الرمز البريدي، الرمز البريدي

  • بلد

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

<input type="text" autocomplete="billing name" required name="billing-name">
<input type="tel" autocomplete="billing tel" required name="billling-tel">
<input type="text" autocomplete="billing address-line1" required name="billing-address1">
<input type="text" autocomplete="billing address-line2" required name="billing-address2">
<input type="text" autocomplete="billing locality" required name="billing-locality">
<input type="text" autocomplete="billing region" required name="billing-region">
<input type="text" autocomplete="billing postal-code" required name="billing-postal-code">
<select autocomplete="billing country" required name="billing-country">
  <option value="US">United States</option>
  …
</select>

<input type="text" autocomplete="shipping name" name="shipping-name">
…

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

متى يجب استدعاء requestAutocomplete؟

من الأفضل عرض مربّع حوار requestAutocomplete بدلاً من تحميل الصفحة التي تعرض نموذج الدفع. إذا سارت الأمور على ما يرام، لن يظهر النموذج للمستخدم على الإطلاق.

مسار الدفعات

من الأنماط الشائعة أن تتضمّن صفحة سلة التسوق زر "الدفع" الذي ينقلك إلى نموذج تفاصيل الدفع. في هذه الحالة، تريد تحميل نموذج الفوترة في صفحة سلة التسوّق، ولكن إخفائه عن المستخدم، ثمّ استدعاء requestAutocomplete عليه عندما ينقر المستخدم على الزر "الدفع". تذكَّر أنّه عليك عرض صفحة سلة التسوّق من خلال طبقة المقابس الآمنة لتجنُّب ظهور تحذير Skeletor. في البداية، علينا إخفاء زر الدفع لكي لا يتمكّن المستخدم من النقر عليه إلى أن نصبح جاهزين، ولكننا نريد إجراء ذلك فقط للمستخدمين الذين لديهم JavaScript. في عنوان صفحتك:

<script>document.documentElement.className += ' js';</script>

في ملف CSS:

.js #checkout-button,
#checkout-form.for-autocomplete {
  display: none;
}

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

<form id="checkout-form" class="for-autocomplete" action="/checkout" method="post">
  …fields for payment, billing address &amp; shipping if relevant…
</form>

يمكن الآن لبرنامج JavaScript بدء إعداد كل شيء:

function enhanceForm() {
  var button = document.getElementById('checkout-button');
  var form = document.getElementById('checkout-form');

  // show the checkout button
  button.style.display = 'block';

  // exit early if there's no requestAutocomplete support
  if (!form.requestAutocomplete) {
    // be sure to show the checkout button so users can
    // access the basic payment form!
    return;
  }

  button.addEventListener('click', function(event) {
    form.requestAutocomplete();
    event.preventDefault();
  });

  // TODO: listen for autocomplete events on the form
}

يمكنك الاتصال برقم enhanceForm على صفحة سلة التسوّق، في وقت ما بعد نموذج الدفع وزر الدفع. ستوفّر المتصفّحات المتوافقة مع requestAutocomplete تجربة سريعة جديدة، بينما ستعود المتصفّحات الأخرى إلى طريقة الدفع العادية. للحصول على نقاط إضافية، يمكنك تحميل نموذج HTML عبر XHR كجزء من enhanceForm. وهذا يعني أنّه يمكنك تحميل النموذج فقط في المتصفّحات المتوافقة مع requestAutocomplete، ولن تحتاج إلى إضافة النموذج إلى كل صفحة يمكنك من خلالها طلب enhanceForm. هذه هي طريقة عمل الموقع التجريبي.

لقد استدعيت requestAutocomplete، ماذا بعد؟

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

form.addEventListener('autocomplete', function() {
  // hurrah! You got all the data you needed
});

form.addEventListener('autocompleteerror', function(event) {
  if (event.reason == 'invalid') {
    // the form was populated, but it failed html5 validation
    // eg, the data didn't match one of your pattern attributes
  }
  else if (event.reason == 'cancel') {
    // the user aborted the process
  }
  else if (event.reason == 'disabled') {
    // the browser supports requestAutocomplete, but it's not
    // available at this time. Eg, it wasn't called from an
    // interaction event or the page is insecure
  }
});

إذا سارت الأمور على ما يرام، يمكنك إجراء ما تريده بالبيانات، وأبسط إجراء يمكنك اتّخاذه هو إرسال النموذج. يمكن للخادم بعد ذلك التحقّق من صحة البيانات وعرض صفحة تأكيد على المستخدم تتضمّن تكلفة التسليم. إذا كانت البيانات غير صالحة، يمكنك عرض النموذج وتمييز الحقول التي يحتاج المستخدم إلى تعديلها. بدلاً من ذلك، يمكنك إرسال النموذج والسماح لعملية التحقّق العادية من جهة الخادم بتنفيذ الخطوات. إذا ألغى المستخدم العملية، ليس عليك اتّخاذ أي إجراء. إذا كانت الميزة غير مفعّلة، أرسِل المستخدم إلى النموذج العادي. وبالتالي، في معظم الحالات، سيكون جمهورك مشابهًا لـ…

form.addEventListener('autocomplete', function() {
  form.submit();
});

form.addEventListener('autocompleteerror', function(event) {
  if (event.reason == 'invalid') {
    form.submit();
  }
  else if (event.reason != 'cancel') {
    window.location = '/checkout-page/';
  }
});

أين يخزّن المتصفّح بياناتي؟

لا تحدّد المواصفة مكان تخزين البيانات، ما يتيح للمتصفحات ابتكار ميزات جديدة. إذا كنت مسجِّلاً الدخول إلى Chrome، سيظهر لك خيار تخزين التفاصيل في "محفظة Google"، ما يتيح الوصول إليها على الأجهزة الأخرى التي سجّلت الدخول إليها. إذا حفظت تفاصيلك في "محفظة Google"، لن يتعامل requestAutocomplete مع رقم بطاقتك الحقيقي، ما يزيد من مستوى الأمان. إذا لم تكن مسجِّلاً الدخول إلى Chrome أو اخترت عدم استخدام "محفظة Google"، يتم تخزين بياناتك اختياريًا على الجهاز في المتصفّح لإعادة استخدامها. هذه هي الحالة الآن، ولكن في المستقبل قد يعتمد Chrome والمتصفّحات الأخرى مقدّمي خدمات دفع إضافيين.

تسهيل الدفع

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

جولة إضافية: التعامل مع النماذج المتعدّدة الصفحات

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

checkoutButton.addEventListener('click', function() {
  requestUserData({
    billing: true,
    shipping: true
  }, function(response) {
    if (response.err == 'cancel') {
      // exit silently
      return;
    }
    if (response.err) {
      // fall back to normal form
      window.location.href = '/normal-checkout-form/';
      return;
    }

    // the rest is just made-up pseudo code as an example
    postToServer(data.shipping).then(function() {
      return postToServer(data.billing);
    }).then(function() {
      return postToServer(data.cc);
    }).catch(function() {
      // handle error
    });
  });
});