معرفی روشی جدید برای ایجاد تجربیات ویرایش وب سفارشی با استفاده از EditContext API

برای توسعه دهندگان همیشه کار ساده ای نبوده است که قابلیت های ویرایش پیشرفته را در برنامه های وب خود بگنجانند. پلتفرم وب با استفاده از عناصری مانند <input> و <textarea> یا با اعمال ویژگی contenteditable به عناصر، قابلیت ویرایش را برای هر دو متن ساده و اسناد HTML فراهم می کند. با این حال، قابلیت‌های اساسی این نوع عناصر اغلب برای آنچه توسعه‌دهندگان می‌خواهند در برنامه‌های خود به دست آورند، کافی نیست.

توسعه دهندگان اغلب به اجرای نمای ویرایشگر سفارشی خود پایان داده اند که عملکرد مورد نیاز کاربرانشان را پیاده سازی می کند. نمای ویرایشگر ممکن است با یک DOM پیچیده ساخته شود - یا حتی با یک عنصر <canvas> - اما از آنجایی که توسعه‌دهنده تنها راهی برای دریافت ورودی متنی نیاز به یک عنصر قابل ویرایش متمرکز دارد، همچنان باید یک عنصر contenteditable پنهان را در آن قرار دهد. صفحه آنها در جایی

نتیجه این است که در حالی که به نظر می‌رسد کاربر مستقیماً در حال ویرایش محتوا در نمای ویرایشگر سفارشی برنامه است، توسعه‌دهنده در واقع ورودی را با کنترل‌کننده‌های رویداد در عنصر پنهان دریافت می‌کند و سپس آن را در نمای ویرایشگر قابل مشاهده منعکس می‌کند. این می تواند منجر به مشکلاتی شود زیرا توسعه دهنده در نهایت با رفتار ویرایش پیش فرض مرورگر در عنصر contenteditable پنهان مبارزه می کند.

برای رسیدگی به این دسته از مشکلات، تیم مایکروسافت اج استاندارد EditContext را هدایت کرده است، یک API پلتفرم وب جدید که به توسعه دهندگان اجازه می دهد تا ورودی متن را مستقیماً بدون اینکه به رفتارهای ویرایش پیش فرض مرورگر مرتبط باشند، دریافت کنند.

یک مثال در دنیای واقعی

به عنوان مثال، زمانی که کاربران در Word Online همکاری می کنند. کاربران می توانند تغییرات و موقعیت مکان نماهای یکدیگر را ویرایش کنند و ببینند. با این حال، برای مثال، اگر یکی از همکاران از یک پنجره ویرایشگر روش ورودی (IME) برای نوشتن متن ژاپنی استفاده کند، ویرایشگر او تا زمانی که کاربر IME ترکیب خود را به پایان نرساند، برای نمایش تغییرات از سایر کاربران به‌روزرسانی نمی‌شود. این به این دلیل است که ایجاد تغییرات در ناحیه DOM در حال ویرایش در حالی که یک ترکیب IME فعال وجود دارد، می‌تواند باعث لغو زودهنگام ترکیب شود. برنامه باید منتظر بماند تا پنجره IME بسته شود تا نما را به‌روزرسانی کند، که ممکن است باعث تأخیر و اختلال در همکاری شود.

هنگام نوشتن متن مشکلی در همکاری در Word Online وجود دارد

برای ارائه یک تجربه بهتر برای توسعه دهنده و کاربر، توسعه دهندگان به راهی برای جدا کردن ورودی متن از نمای HTML DOM نیاز دارند. EditContext API راه حلی برای این مشکل است.

مبانی EditContext

با EditContext، می توانید متن و ورودی ترکیب را مستقیماً از طریق سطح API EditContext دریافت کنید، نه از طریق مشاهده تغییرات در 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 استفاده کنید.

مشتاقانه منتظر است

تیم مایکروسافت اج EditContext را از طریق همکاری با مهندسان کروم در کرومیوم پیاده‌سازی کرده است و با نسخه ۱۲۱ (ژانویه ۲۰۲۴) کروم و اج عرضه می‌شود. در حال حاضر، فقط در مرورگرهای مبتنی بر Chromium در دسترس است، اما می‌توانید موقعیت‌های Mozilla و WebKit را در EditContext API بخوانید.

ما می‌خواهیم ایجاد تجربه‌های ویرایش سفارشی قدرتمند در وب برای توسعه‌دهندگان وب آسان‌تر باشد، و ما معتقدیم که EditContext API با پرداختن به چالش‌های موجود و ارائه راه مستقیم‌تری برای مدیریت ورودی متن به این امر دست می‌یابد.

اگر می‌خواهید درباره API بیشتر بدانید، به اسناد MDN مراجعه کنید. برای ارسال بازخورد در مورد طراحی API، یک مشکل را در مخزن Github در EditContext API باز کنید. برای گزارش اشکالات مربوط به اجرای API، یک اشکال را در crbug.com ارسال کنید.