आईएमई-सेफ़ एंटर-टू-सबमिट

वेब की सुविधाएं: कीबोर्ड इवेंट

कई चैट इंटरफ़ेस में, उपयोगकर्ता के <textarea> में Enter दबाने पर मैसेज सबमिट हो जाता है.

यह सुविधा, सीधे लैटिन कीबोर्ड इनपुट (जैसे, अंग्रेज़ी) से टाइप करने वाले उपयोगकर्ताओं के लिए काम करती है. हालांकि, जैपनीज़, चाइनीज़ या कोरियन जैसी भाषाओं में टेक्स्ट लिखने के लिए, इनपुट पद्धति संपादक (आईएमई) से टाइप करने वाले उपयोगकर्ताओं के लिए यह सुविधा काम नहीं करती.

इन मामलों में, Enter/Return बटन का इस्तेमाल, मौजूदा वर्ण के कन्वर्ज़न कैंडिडेट की पुष्टि करने के लिए किया जाता है. अगर कस्टम JavaScript, Enter पर keydown को सुनता है और तुरंत सबमिट करता है, तो उपयोगकर्ता का मैसेज तब भेजा जाता है, जब वह वर्णों को बदल रहा होता है. इससे अधूरे, फ़्रैगमेंट किए गए या गलत मैसेज भेजे जाते हैं.

कंपोज़िशन-ऐक्टिव चेक, Enter पर काम करने वाले किसी भी कस्टम keydown हैंडलर पर लागू होता है. यह सिर्फ़ कई लाइनों वाले <textarea> फ़ील्ड पर लागू नहीं होता. सिंगल-लाइन <input> फ़ील्ड, जिनमें Enter को हैंडल करने की सुविधा होती है, जैसे कि खोज और ढूंढने वाले बार, इनलाइन नाम बदलने वाले फ़ील्ड, मॉडल डायलॉग फ़ील्ड, और कमांड पैलेट. इनमें आईएमई की पुष्टि करने वाला वही Enter कीडाउन मिलता है जो <textarea> को मिलता है. इसमें isComposing को true पर सेट किया जाता है. किसी <input> से <form> को नेटिव तौर पर इंप्लिसिट सबमिट करने के लिए, किसी कस्टम Enter हैंडलर की ज़रूरत नहीं होती. ऐसा इसलिए, क्योंकि जब आईएमई, Enter कीस्ट्रोक का इस्तेमाल करता है, तो ब्राउज़र इंप्लिसिट सबमिशन को रोक देते हैं.

लागू करने की रणनीति

कस्टम एंटर-टू-सबमिट वाले <textarea> या <input> के लिए, कॉन्टेंट सबमिट करने से पहले KeyboardEvent की नेटिव isComposing प्रॉपर्टी देखें. event.preventDefault() को भी कॉल करें: Enter की डिफ़ॉल्ट कार्रवाई, <textarea> में एक न्यूलाइन डालती है. साथ ही, <form> के अंदर <input> में, यह ब्राउज़र के इंप्लिसिट सबमिशन को ट्रिगर करती है, जो दूसरी बार सबमिट करेगा.

<form id="chat-form">
  <label for="chat-input" class="visually-hidden">Message</label>
  <textarea id="chat-input" placeholder="Type a message..."></textarea>
  <button type="submit" id="send-button">Send</button>
</form>
const textarea = document.getElementById('chat-input');
const form = document.getElementById('chat-form');

textarea.addEventListener('keydown', (event) => {
  if (event.key === 'Enter' && !event.shiftKey) {
    // Prevent the default action (newline in a textarea, implicit form submission in an input)
    event.preventDefault();

    // If the user is composing text, return early.
    if (event.isComposing) {
      return;
    }

    form.requestSubmit();
  }
});

एक लाइन वाले <input> के लिए, !event.shiftKey शर्त के बिना उसी हैंडलर का इस्तेमाल करें. यह शर्त सिर्फ़ इसलिए मौजूद है, क्योंकि Shift+Enter, <textarea> में एक नई लाइन जोड़ता है.

सुलभता और टेस्टिंग

  1. सबमिट करने के लिए साफ़ तौर पर बटन: हमेशा <button type="submit"> एलिमेंट शामिल करें. कीबोर्ड शॉर्टकट, मददगार होते हैं. इन्हें फ़ॉर्म सबमिट करने के नेटिव पाथ की जगह इस्तेमाल नहीं किया जाना चाहिए.
  2. ऐक्सेस किए जा सकने वाले इनपुट: पक्का करें कि सभी <input> और <textarea> एलिमेंट, प्रोग्राम के हिसाब से <label> से जुड़े हों. इसके लिए, मैच होने वाले id और for एट्रिब्यूट का इस्तेमाल करें.

फ़ॉलबैक रणनीतियां

Safari के हाल ही के वर्शन में, इवेंट के क्रम से जुड़ी एक समस्या (WebKit गड़बड़ी 165004) की वजह से, compositionend को पुष्टि करने वाले Enter keydown से पहले स्क्रिप्ट हैंडलर को डिलीवर किया गया. भले ही, इसके पीछे के इवेंट को उल्टे क्रम में भेजा गया था. जब तक keydown हैंडलर चला, तब तक event.isComposing को false पर रीसेट कर दिया गया था. इसका मतलब है कि सिर्फ़ स्टैंडर्ड जांच से, समय से पहले सबमिट होने से नहीं रोका जा सकता.

अगर आपको Safari के पुराने वर्शन और अन्य प्लैटफ़ॉर्म पर, क्रॉस-ब्राउज़र के साथ काम करने की सुविधा चाहिए, तो इनमें से कोई एक फ़ॉलबैक रणनीति अपनाएं:

event.isComposing को event.keyCode === 229 की जांच के साथ जोड़कर, Safari के गलत क्रम में पुष्टि करने वाले Enter कीडाउन को आसानी से पकड़ा जा सकता है. यह event.key === 'Enter' गेट के अंदर नेस्ट किया गया है. इसलिए, यह मोबाइल वर्चुअल कीबोर्ड से सुरक्षित है. ये कीबोर्ड, सामान्य वर्ण लेआउट एंट्री के लिए 229 का इस्तेमाल कर सकते हैं.

textarea.addEventListener('keydown', (event) => {
  if (event.key === 'Enter' && !event.shiftKey) {
    event.preventDefault();

    // Block submission if composing natively or if keyCode is 229
    if (event.isComposing || event.keyCode === 229) {
      return;
    }

    form.requestSubmit();
  }
});

दूसरी रणनीति: event.timeStamp विंडो का इस्तेमाल करना (विकल्प)

ऐसे कोड बेस के लिए जो keyCode जैसे बंद किए जा चुके एपीआई के इस्तेमाल पर पूरी तरह से पाबंदी लगाते हैं या अगर टारगेट किए गए खास एनवायरमेंट में 229 की जांच से जुड़ी समस्याएं पहले से मौजूद हैं, तो ब्राउज़र से रिपोर्ट किए गए इवेंट के डिस्पैच टाइमस्टैंप को ट्रैक किया जा सकता है.

Safari, पुष्टि करने वाले Enter कीडाउन इवेंट को compositionend इवेंट के बहुत करीब भेजता है. आम तौर पर, यह 5 मि॰से॰ के अंदर होता है. कभी-कभी हैंडलर डिलीवरी ऑर्डर के इनवर्ज़न की वजह से, कीडाउन टाइमस्टैंप थोड़ा पहले होता है. इसलिए, समय के अंतर की जांच करना काफ़ी भरोसेमंद होता है. साथ ही, सामान्य स्थितियों में मोबाइल वर्चुअल कीबोर्ड पर फ़ॉल्स-पॉज़िटिव ट्रिगर होने की संभावना नहीं होती.

let lastCompositionEndAt = null;

textarea.addEventListener('compositionend', (event) => {
  // IMPORTANT: Always use event.timeStamp, not Date.now() or performance.now().
  // Handler-time measurements are vulnerable to drift when the main thread is blocked.
  lastCompositionEndAt = event.timeStamp;
});

textarea.addEventListener('keydown', (event) => {
  if (event.key === 'Enter' && !event.shiftKey) {
    event.preventDefault();

    if (event.isComposing) {
      return;
    }

    // Block submission if the event occurs within a 50ms window of composition ending.
    // Math.abs handles Safari's inverted event delivery timing bug.
    if (
      lastCompositionEndAt !== null &&
      Math.abs(event.timeStamp - lastCompositionEndAt) < 50
    ) {
      return;
    }

    form.requestSubmit();
  }
});