ขอแนะนำวิธีใหม่ในการสร้างประสบการณ์การแก้ไขเว็บแบบกำหนดเองโดยใช้ EditContext API

การที่นักพัฒนาซอฟต์แวร์รวมความสามารถในการแก้ไขขั้นสูงไว้ในเว็บแอปพลิเคชันของตนจึงไม่ใช่เรื่องง่ายเสมอไป แพลตฟอร์มเว็บช่วยให้แก้ไขได้ทั้งเอกสารข้อความธรรมดาและ HTML โดยใช้องค์ประกอบ เช่น <input> และ <textarea> หรือใช้แอตทริบิวต์ contenteditable กับองค์ประกอบ อย่างไรก็ตาม ความสามารถพื้นฐานขององค์ประกอบประเภทเหล่านี้มักไม่เพียงพอต่อสิ่งที่นักพัฒนาแอปต้องการบรรลุในแอป

นักพัฒนาแอปมักจะใช้มุมมองเครื่องมือแก้ไขที่กําหนดเองซึ่งใช้ฟังก์ชันการทํางานตามที่ผู้ใช้ต้องการ มุมมองเครื่องมือแก้ไขอาจสร้างขึ้นด้วย DOM ที่ซับซ้อน หรือแม้แต่องค์ประกอบ <canvas> แต่เนื่องจากวิธีเดียวที่นักพัฒนาแอปจะได้รับอินพุตข้อความคือต้องโฟกัสองค์ประกอบที่แก้ไขได้ นักพัฒนาแอปจึงยังคงต้องวางองค์ประกอบ contenteditable ที่ซ่อนอยู่ในหน้าเว็บ

ผลที่ได้คือขณะที่ผู้ใช้กำลังแก้ไขเนื้อหาในมุมมองเครื่องมือแก้ไขที่กำหนดเองของแอปโดยตรง แต่นักพัฒนาซอฟต์แวร์ได้รับอินพุตที่มีตัวแฮนเดิลเหตุการณ์ในองค์ประกอบที่ซ่อนอยู่ แล้วมิเรอร์ข้อมูลเข้าสู่มุมมองเครื่องมือแก้ไขที่มองเห็นได้ ซึ่งอาจทำให้เกิดปัญหาเนื่องจากนักพัฒนาซอฟต์แวร์ต้องต่อสู้กับลักษณะการแก้ไขเริ่มต้นของเบราว์เซอร์ในองค์ประกอบ contenteditable ที่ซ่อนอยู่

ทีม Microsoft Edge ได้ขับเคลื่อนมาตรฐานของ EditContext ซึ่งเป็น API แพลตฟอร์มเว็บใหม่ที่ช่วยให้นักพัฒนาแอปรับอินพุตข้อความได้โดยตรงโดยไม่ต้องเชื่อมโยงกับลักษณะการแก้ไขเริ่มต้นของเบราว์เซอร์ เพื่อแก้ไขปัญหาประเภทนี้

ตัวอย่างการใช้งานจริง

ตัวอย่างเช่น เมื่อผู้ใช้ทำงานร่วมกันใน Word ออนไลน์ ผู้ใช้จะแก้ไขร่วมกันและดูการเปลี่ยนแปลงและตำแหน่งเคอร์เซอร์ของกันและกันได้ อย่างไรก็ตาม หากผู้ทำงานร่วมกันคนหนึ่งใช้หน้าต่าง Input Method Editor (IME) เพื่อเขียนข้อความภาษาญี่ปุ่น เช่น เครื่องมือแก้ไขของผู้ทำงานร่วมกันจะไม่ได้รับการอัปเดตเพื่อแสดงการเปลี่ยนแปลงจากผู้ใช้คนอื่นจนกว่าผู้ใช้ IME จะเขียนข้อความเสร็จ ทั้งนี้เนื่องจากการเปลี่ยนแปลงพื้นที่ของ DOM ที่แก้ไขอยู่ขณะมีองค์ประกอบ IME ที่ทำงานอยู่ อาจทำให้การแต่งเพลงถูกยกเลิกก่อนกำหนด แอปพลิเคชันต้องรอจนกว่าหน้าต่าง IME จะปิดเพื่ออัปเดตมุมมอง ซึ่งอาจทำให้เกิดความล่าช้าและขัดขวางการทำงานร่วมกัน

พบปัญหาในการทำงานร่วมกันใน Word Online ขณะเขียนข้อความ

นักพัฒนาแอปต้องมีวิธีแยกอินพุตข้อความออกจากมุมมอง 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 และ UI การแก้ไขอื่นๆ สำหรับแพลตฟอร์มใด

// 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);

การจัดการตำแหน่งของ UI เครื่องมือแก้ไข

คอยฟังเหตุการณ์ characterboundsupdate และเรียก updateCharacterBounds() เพื่อตอบสนองและช่วยให้แพลตฟอร์มตัดสินใจว่าจะแสดงหน้าต่าง IME และ UI การแก้ไขอื่นๆ สำหรับแพลตฟอร์มใด

การใช้การจัดรูปแบบ

ฟังหาเหตุการณ์ textformatupdate แล้วใช้การจัดรูปแบบที่เหตุการณ์ระบุกับมุมมองเครื่องมือแก้ไข IME จะใช้การตกแต่งข้อความเหล่านี้เมื่อเขียนภาษาบางภาษา ตัวอย่างเช่น IME ภาษาญี่ปุ่นจะใช้เส้นใต้เพื่อแสดงว่าข้อความส่วนใดกำลังเขียนอยู่

ภาพหน้าจอของหน้าต่างตัวแก้ไขวิธีการป้อนข้อมูลที่ใช้ป้อนอักขระภาษาญี่ปุ่น

การจัดการลักษณะการแก้ไข Rich Text

ฟังเหตุการณ์ beforeinput เพื่อจัดการลักษณะการแก้ไข Rich Text ที่คุณต้องการรองรับ เช่น แป้นลัดสำหรับข้อความตัวหนาหรือตัวเอียง หรือใช้การแก้ไขการตรวจตัวสะกด

การจัดการการเปลี่ยนแปลงในรายการที่ผู้ใช้เลือก

เมื่อการเลือกของผู้ใช้เปลี่ยนแปลงเนื่องจากการป้อนข้อมูลด้วยแป้นพิมพ์หรือเมาส์ คุณจะต้องแจ้งอินสแตนซ์ EditContext เกี่ยวกับการเปลี่ยนแปลง ซึ่งเป็นสิ่งจำเป็นเนื่องจากความเกี่ยวข้องของ EditContext API กับ Use Case จำนวนมาก ซึ่งรวมถึงเครื่องมือแก้ไขที่แสดงผลด้วยองค์ประกอบ <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 ใน EditContext API

เราต้องการให้นักพัฒนาเว็บสร้างประสบการณ์การแก้ไขที่กำหนดเองที่มีประสิทธิภาพบนเว็บได้ง่ายยิ่งขึ้น และเราเชื่อว่า EditContext API สามารถบรรลุเป้าหมายนี้ด้วยการรับมือกับความท้าทายที่มีอยู่และนําเสนอวิธีจัดการการป้อนข้อความที่ตรงยิ่งขึ้น

หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับ API โปรดดูเอกสารประกอบ MDN หากต้องการส่งความคิดเห็นเกี่ยวกับการออกแบบ API ให้เปิดปัญหาในที่เก็บ GitHub ของ EditContext API หากต้องการรายงานข้อบกพร่องเกี่ยวกับการติดตั้งใช้งาน API ให้ส่งข้อบกพร่องที่ crbug.com