لم يكن من السهل دائمًا على المطوّرين دمج إمكانات التعديل المتقدّمة في تطبيقات الويب. توفّر منصة الويب إمكانية التعديل لكلّ من النصوص العادية ومستندات HTML باستخدام عناصر مثل <input>
و<textarea>
، أو من خلال تطبيق السمة contenteditable
على العناصر. ومع ذلك، غالبًا ما تكون الإمكانات الأساسية لأنواع العناصر هذه غير كافية لتحقيق ما يريده المطوّرون في تطبيقاتهم.
غالبًا ما ينتهي الأمر بالمطوّرين بتنفيذ طريقة عرض التعديل المخصّصة التي توفّر الوظائف التي يحتاجها المستخدمون. قد يتم إنشاء طريقة عرض المحرِّر باستخدام نموذج DOM معقّد، أو حتى باستخدام عنصر <canvas>
، ولكن بما أنّ الطريقة الوحيدة التي يمكن للمطوّر من خلالها تلقّي إدخال نصي تتطلّب عنصرًا قابلاً للتعديل ومركزًا على الشاشة، سيظلّ بحاجة إلى وضع عنصر contenteditable
مخفي على صفحته في مكان ما.
ونتيجةً لذلك، عندما يبدو أنّ المستخدم يعدّل المحتوى مباشرةً في طريقة عرض المحرِّر المخصّصة للتطبيق، يتلقّى المطوّر في الواقع الإدخال مع معالجات الأحداث في العنصر المخفي، ثم يعكسه في طريقة عرض المحرِّر المرئية. وقد يؤدي ذلك إلى حدوث مشاكل لأنّ المطوّر سيواجه سلوك التعديل التلقائي للمتصفّح في عنصر contenteditable
المخفي.
لحلّ هذه الفئة من المشاكل، سعى فريق Microsoft Edge إلى توحيد EditContext، وهي واجهة برمجة تطبيقات جديدة لمنصّة الويب تتيح للمطوّرين تلقّي إدخال نص مباشرةً بدون الارتباط بسلوكيات التعديل التلقائية للمتصفّح.
مثال من العالم الحقيقي
على سبيل المثال، عندما يتعاون المستخدمون في Word Online. يمكن للمستخدمين التعديل المشترَك والاطّلاع على تغييرات بعضهم وأماكن المؤشر. ومع ذلك، إذا كان أحد المتعاونين يستخدم نافذة محرر طريقة الإدخال (IME) لإنشاء نص ياباني، على سبيل المثال، لن يتم تعديل المحرّر الخاص به لعرض التغييرات التي أجراها المستخدمون الآخرون إلى أن ينتهي مستخدم IME من إنشاء النص. ويعود السبب في ذلك إلى أنّ إجراء تغييرات على منطقة نموذج DOM الذي يتم تعديله أثناء إنشاء تركيبة نشطة لنظام IME قد يؤدي إلى إلغاء التركيب قبل الأوان. يجب أن ينتظر التطبيق حتى يتم إغلاق نافذة IME لتعديل العرض، ما قد يؤدي إلى حدوث تأخيرات وتعيق التعاون.
لتوفير تجربة أفضل للمطوّرين وتجربة المستخدم، يحتاج المطوّرون إلى طريقة لفصل الإدخال النصي من طريقة عرض HTML DOM. وتعدّ واجهة برمجة التطبيقات EditContext API هي الحلّ لهذه المشكلة.
أساسيات EditContext
باستخدام EditContext، يمكنك تلقّي إدخال النص والتركيب مباشرةً من خلال واجهة برمجة التطبيقات EditContext API، بدلاً من مراقبة التغييرات في نموذج DOM. يتيح ذلك التحكّم بشكل أكبر في كيفية معالجة الإدخال، ويسمح حتى بإضافة إمكانية التعديل إلى عنصر <canvas>
.
يؤدي ربط مثيل EditContext بعنصر إلى جعله قابلاً للتعديل:
// This will be our editable element.
const element = document.querySelector('#editor-element');
// Creating the EditContext object.
const editContext = new EditContext();
// Associating the EditContext object with our DOM element.
// The element is now focusable and can receive text input.
element.editContext = editContext;
// In order to render the text typed by the user onto the
// page, as well as the user's selection, you'll need to
// receive the input in a textupdate event callback.
editContext.addEventListener('textupdate', event => {
element.textContent = editContext.text;
// For brevity, the code to render the selection
// isn't shown here.
renderSelection(event.selectionStart, event.selectionEnd);
});
مسؤوليات المؤلف
يسهّل استخدام واجهة برمجة التطبيقات EditContext API إتاحة طرق إدخال متقدّمة، مثل نوافذ تركيب أسلوب الإدخال (IME) وأدوات اختيار الرموز التعبيرية ومساحات إدخال أخرى لنظام التشغيل. لكي يكون كل ذلك ممكنًا في العنصر القابل للتعديل، تتطلّب واجهة برمجة التطبيقات EditContext API بعض المعلومات. بالإضافة إلى عرض النص وتحديده، هناك بعض الإجراءات الأخرى التي يجب تنفيذها عند استخدام واجهة برمجة التطبيقات EditContext API.
إدارة جانب منطقة قابلة للتعديل أو في حال تغيُّر اختيار المستخدم
استخدِم الطريقتَين updateControlBounds()
وupdateSelectionBounds()
لإعلام مثيل EditContext عند تغيُّر حجم المنطقة القابلة للتعديل أو اختيار المستخدم. يساعد ذلك المنصة في تحديد مكان عرض نوافذ أداة IME وغيرها من واجهة مستخدم التعديل الأخرى الخاصة بالنظام الأساسي.
// It's necessary to provide bounds information because EditContext
// is generic enough to work with any type of web editor, even
// <canvas>-based editors. The API doesn't make any assumptions as
// to how the editor is implemented or how the selection is rendered.
// Bounds are given in the client coordinate space.
const controlBound = editorElement.getBoundingClientRect();
const selection = document.getSelection();
const selectionBound = selection.getRangeAt(0).getBoundingClientRect();
editContext.updateControlBounds(controlBound);
editContext.updateSelectionBounds(selectionBound);
إدارة موضع واجهة مستخدم المحرِّر
انتظِر حدث characterboundsupdate
واطلب updateCharacterBounds()
استجابةً لمساعدة النظام الأساسي في تحديد مكان عرض نوافذ IME وواجهة مستخدم التعديل الأخرى الخاصة بالنظام الأساسي.
تطبيق التنسيق
استمِع إلى الحدث textformatupdate
وطبِّق التنسيق الذي يحدّده الحدث على عرض المحرّر. وتستخدم أدوات IME هذه الزخارف النصية عند إنشاء لغات معينة. على سبيل المثال، سيستخدم IME الياباني خطًا سفليًا لعرض الجزء الذي يتم إنشاؤه من النص.
التعامل مع سلوكيات تعديل النصوص المنسّقة
استمع إلى حدث beforeinput
للتعامل مع أي سلوكيات لتعديل النص المنسَّق تريد توفيرها، مثل مفاتيح الاختصار لتسليط الضوء على النص أو جعله مائلًا أو تطبيق تصحيح إملائي.
إدارة التغييرات في اختيارات المستخدم
عندما يتغيّر اختيار المستخدم بسبب إدخال لوحة المفاتيح أو الماوس، عليك إبلاغ مثيل EditContext بالتغيير. هذا الإجراء ضروري بسبب انطباق واجهة برمجة التطبيقات EditContext API على عدد كبير من حالات الاستخدام، بما في ذلك المحرّرون الذين يتم عرضهم باستخدام العنصر <canvas>
حيث لا يمكن للمتصفّح رصد تغييرات الاختيار تلقائيًا.
document.addEventListener('selectionchange', () => {
const selection = document.getSelection();
// EditContext doesn't handle caret navigation, so all the caret navigation/selection that happens
// in DOM space needs to be mapped to plain text space by the author and passed to EditContext.
// This example code assumes the editable area only contains text under a single node.
editContext.updateSelection(selection.anchorOffset, selection.focusOffset);
});
إذا كان العنصر الذي تستخدمه مع EditContext هو عنصر <canvas>
، ستحتاج أيضًا إلى تنفيذ سلوكَي التحديد والتنقّل باستخدام المؤشر، مثل التنقّل في النص باستخدام مفاتيح الأسهم. بالإضافة إلى ذلك، لا تعمل ميزة التدقيق الإملائي المضمّنة في المتصفّح إلا في العناصر غير <canvas>
.
EditContext في مقابل contenteditable
يُعدّ EditContext خيارًا رائعًا إذا كنت بصدد تنفيذ محرِّر مزوّد بميزات كاملة وتريد التحكّم بشكل كامل في كيفية معالجة إدخال النص، أو إذا كنت بصدد إضافة ميزات متقدّمة مثل التعديل المشترَك مع مستخدمين متعدّدين. ومع ذلك، نظرًا لجميع المتطلبات السابقة لاستخدام EditContext، إذا كان كل ما تحتاجه هو إتاحة تعديل النص البسيط، من المحتمل أن تظل بحاجة إلى استخدام عناصر <input>
أو <textarea>
أو السمة contenteditable
.
التطلّع إلى المستقبل
طبّق فريق Microsoft Edge سياسة EditContext في Chromium بالتعاون مع مهندسي Chrome. ويتم طرح الإصدار 121 (كانون الثاني/يناير 2024) من متصفّح Chrome وEdge. لا يتوفر في الوقت الحالي إلا في المتصفحات المستنِدة إلى Chromium، ولكن يمكنك الاطّلاع على مواضع Mozilla وWebKit's على واجهة برمجة التطبيقات EditContext API.
نريد أن نسهّل على مطوّري الويب إنشاء تجارب تعديل مخصّصة فعّالة على الويب، ونعتقد أنّ واجهة برمجة التطبيقات EditContext API تحقّق ذلك من خلال معالجة التحديات الحالية وتقديم طريقة أكثر مباشرة لمعالجة إدخال النصوص.
لمزيد من المعلومات عن واجهة برمجة التطبيقات، يمكنك الرجوع إلى مستندات MDN. لإرسال ملاحظات حول تصميم واجهة برمجة التطبيقات، افتح مشكلة في مستودع جيت هب الخاص بـ EditContext API. للإبلاغ عن أخطاء في تنفيذ واجهة برمجة التطبيقات، يُرجى إرسال خطأ على crbug.com.