טקסט ועריכה
עריכה היא יכולת של המנוע, לא הרכבה ביישום
החולשה הקלאסית של פתרונות מבוססי canvas היא הנחת input של HTML מעל ה-canvas כשצריך להקליד. מכאן נגררת שרשרת בעיות: סמן שזז ממקומו, חלון מועמדים של IME שסוטה, גלילה לא מסונכרנת ונגישות שבורה.
doper מתייחס לעריכה כיכולת מדרג ראשון של הליבה: סמן, בחירה, בחירה בגרירה, בחירת מילה בלחיצה כפולה, ניווט במקלדת, הרכבת IME, מיקום חלון המועמדים, לוח גזירים, ביטול/ביצוע חוזר, מצב קריאה בלבד וסיסמה — כולם ממומשים במנוע. היישום אינו יוצר, אינו ממקם ואינו מסנכרן שום פקד קלט של HTML.
שימוש ברכיבים המוכנים
import { TextField, TextArea } from "@dopejs/pingo";
TextField({
value: order.note,
revision: order.revision,
semanticLabel: "הערה להזמנה",
inputMode: "text",
onTransaction: (transaction) => order.apply(transaction),
});
TextArea({ value: description, revision, rows: 4 });שימוש בפרימיטיב
createElement("editableText", {
value,
revision,
multiline: false,
readOnly: false,
password: false,
maxGraphemes: 200,
inputMode: "email",
onTransaction: (transaction) => apply(transaction),
onSubmit: () => moveToNextCell(),
});או באמצעות בקר מקומי:
import { useTextEditingController } from "@dopejs/pingo";
const editor = useTextEditingController({ value: cell.value });
createElement("editableText", { controller: editor });גשר הקלט והנסיגה
התהליכון הראשי מתחבר לשירות קלט הטקסט של מערכת ההפעלה לפי סדר עדיפות:
- EditContext — נקשר ל-canvas, מקבל טקסט, בחירה והרכבה, ומספק לשיטת הקלט את control, selection וגבולות התווים.
- מתווך קלט שהמנוע מנהל — כאשר EditContext אינו זמין, המארח מחזיק
textareaנסתר יחיד גלובלי שמטפל באופן מאוחד ב-beforeinput, בהרכבה, במקלדת הרכה ובלוח הגזירים.
השני הוא מימוש נסיגה ברמת הפלטפורמה ולא מודל רכיבים מסוג EmbedDOM: ב-Scene אין DOM המתאים אחד לאחד לכל צומת עריכה. שני הנתיבים עוברים את אותה מערכת בדיקות חוזה התנהגותי.
טרנזקציות עריכה עם גרסאות
בעלות המצב מפורשת: המעטפת מחזיקה בנתונים העסקיים, והליבה מחזיקה במצב הרגעי של הפעלת העריכה הפעילה.
קלט ← הליבה בודקת את base_revision ← מיישמת ומציירת מחדש מיד ← פולטת בכיוון ההפוך EditTransaction עם גרסה
↓
היישום מאשר, או שולח ערך מתוקן עם גרסה חדשהטרנזקציה שפג תוקפה לעולם לא תדרוס מצב חדש יותר. כלומר כל הקשה אינה מחייבת מחזור בנייה מלא של TSX, ועם זאת הנתונים המבוקרים והוולידציה העסקית ממשיכים להתקיים.
מודל מיקומי הטקסט
ממשקי הקלט של הרשת עובדים בהיסטים של UTF-16, מחרוזות Rust הן UTF-8, וגבולות הגרפמות, אשכולות העיצוב והגליפים הנראים שונים זה מזה. לכן המנוע מתחזק מיפוי מפורש:
היסט UTF-16 ↔ סקלר Unicode ↔ גרפמה ↔ אשכול עיצוב ↔ גליף / שורהבגבול הפרוטוקול נעשה שימוש אחיד ב-UTF-16 כדי להתיישר עם EditContext ועם InputEvent. מחיקה, תזוזה ובחירה לעולם אינן חוצות גרפמה, רצף משולב, אמוג׳י עם ZWJ או אשכול עיצוב — על כך שומרות בדיקות תכונה ומטריצת מקבעי הרכבה (תווים משולבים, אמוג׳י ZWJ, כתיבה מימין לשמאל, מועמדי CJK מרובי מקטעים).
סיסמאות ופרטיות
טקסט של סיסמה אינו נכנס להקלטה ולהרצה חוזרת, ליומנים, לטקסט גלוי בכלי הפיתוח או לערכי נגישות; יעד מסוג סיסמה גם אינו כותב ללוח הגזירים. הליבה פולטת רק גליפים ממוסכים, ולכן הטקסט הגלוי אינו מגיע כלל ל-DisplayList. יש לכך בדיקות אוטומטיות, ואפשר גם לבדוק את ה-DOM בעצמך ב-Playground המפורסם.
גבולות ידועים
- ניווט חזותי בטקסט דו-כיווני יסופק יחד עם התמיכה בטקסט דו-כיווני; כרגע זו דחייה מפורשת.
- סכימת טקסט עשיר, יישוב התנגשויות בעריכה משותפת, נוסחאות ופקודות Markdown שייכים לשכבות שמעל, אך הם יכולים להיבנות על אותן טרנזקציות עריכה ועל אותו ממשק בחירה.