الانتقال إلى المحتوى الرئيسي

التحرير التعاوني

تحوّل الدالة getSharedStore() المحرر إلى عقدة في جلسة تعاونية.
فهي تُطلِق كل تغيير على شكل دفق من الإجراءات وتطبّق الإجراءات التي ترسلها المحررات الأخرى — وعليك أنت توفير وسيلة النقل بينها (WebSocket أو WebRTC أو أي وسيلة أخرى يمكنها نقل JSON).
وهي إحدى دوال ErdEditorElement، وتُستخدم مع التخزين البعيد عندما يلزم تخزين التغييرات المُمرَّرة أيضًا.
منذ الإصدار 5.1.0، لمشاركة مخطط عبر مستند Yjs وأي من مزوّديه بدلًا من توصيل وسيلة النقل بنفسك، اربط المحرر باستخدام @dineug/erd-editor-yjs؛ راجع Yjs.

interface ErdEditorElement extends HTMLElement {
// ...
getSharedStore: (
config?: SharedStoreConfig & {
mouseTracker?: boolean;
focusTracker?: boolean;
}
) => SharedStore;
}

type SharedStoreConfig = {
getNickname?: () => string;
};

type SharedStore = {
connection: () => void;
disconnect: () => void;
dispatch: (actions: Array<AnyAction> | AnyAction) => void;
dispatchSync: (actions: Array<AnyAction> | AnyAction) => void;
subscribe: (fn: (value: AnyAction[]) => void) => Unsubscribe;
flushStreamBuffers: () => void;
getLWW: () => SharedRegisters;
mergeLWW: (lww: SharedRegisters, version: number) => void;
getVersion: () => number;
forgetPeer: (editorId: string) => void;
reseed: (value: string, options: ReseedOptions) => void;
destroy: () => void;
};

// a JSON object whose shape is the editor's own: hand it on as it is
type SharedRegisters = Record<string, unknown> & {
readonly [registersBrand]: true;
};

type ReseedOptions = {
lww: SharedRegisters;
version: number;
keepScreen?: boolean; // default false
};

// example
const sharedStore = editor.getSharedStore();

لا يصدّر @dineug/erd-editor أيًّا من هذه الأنواع بالاسم. تصل شيفرة TypeScript إليها عبر ErdEditorElement، كما في ReturnType<ErdEditorElement['getSharedStore']>.

الإجراء كائن بسيط قابل للتحويل إلى سلسلة يصف تغييرًا واحدًا في المستند، لذا يجتاز JSON.stringify سليمًا في طريقه إلى وسيلة النقل.
وتصل الإجراءات في دفعات: تسلّمك الدالة subscribe مصفوفة، وتلك المصفوفة وحدة واحدة — مرّرها كاملة وأرسلها كاملة في الطرف الآخر.
تعامل مع الإجراء على أنه قيمة مبهمة ومرّره كما هو بدلًا من قراءته أو إعادة كتابته، لأن بيانات التتبع التي يحملها، مثل رقم النسخة، هي ما يُبقي المحررات متزامنة.

بعض ما يجري في المحرر يبقى في ذلك المحرر.
لا يُرسَل إحضار جدول أو ملاحظة أو مجموعة جداول إلى المقدمة، وهو ما يحدث أيضًا عند تحديد أحدها.
ولا تُرسَل كذلك اختيارات Statements وHeader وWrite logical names into empty comments (منذ الإصدار 4.2.0) وTables في علامة تبويب مخطط SQL، فهي تخص النافذة التي اختيرت فيها.
منذ الإصدار 4.1.0، يبقى المستكشف أيضًا في محرره: لا يُرسَل ما إذا كان مفتوحًا، ولا مقدار عرضه، ولا صفوفه المطوية، ولا الصف الذي عليه تركيز لوحة المفاتيح، ولا موضع التمرير في شجرته، ولا بحثه وخياراته.
ولا يُرسَل الإبراز الذي يضعه الانتقال إلى مفتاح خارجي على خط الربط الخاص بعلاقته.
منذ الإصدار 4.2.0، تبقى علامة تبويب القاموس أيضًا في محررها: لا يُرسَل أيُّ الأوراق هي المعروضة، ولا بحث كل ورقة وتحديدها وموضع التمرير فيها وعرض أعمدتها. أما تعديلاتها وعمليات الفرز فيها واستيراد ملفات CSV إليها فتُرسَل.
يُرسَل التمرير أو تغيير مستوى التكبير أو التبديل بين علامات التبويب، لكنه لا يحرّك أبدًا عرض مستخدم آخر أو علامة تبويبه. ويشمل ذلك التمرير الناتج عن الانتقال من المستكشف، والتبديل إلى علامة تبويب ERD عند فتح المستكشف من علامة تبويب أخرى، والتبديل بين علامات التبويب والتمرير الناتجين عن الانتقال من الورقة Checks في علامة تبويب القاموس إلى جدول أو عمود. أما الانتقال من تلك الورقة إلى كلمة أو مصطلح أو مجال فيبقى في علامة تبويب القاموس، لذا لا يُرسَل منه شيء.

منذ الإصدار 4.2.0، يُرسَل أيضًا تبديل عرض الأسماء، ويحدد قفله ما تفعله به المحررات الأخرى. ويكون القفل Name View مفعّلًا في المخطط الجديد وفي أي مستند سابق للإصدار 4.2.0.
ما دام القفل مفعّلًا، لا يظهر التبديل إلا في المحرر الذي أجراه: فهو لا يزال يُرسَل، لكن كل محرر آخر وكل نسخة متماثلة تُسقطه، لذا يمكن لكل مستخدم أن ينظر إلى عرض مختلف بينما يحتفظ value بالعرض المقفل.
وما دام القفل معطّلًا، يغيّر التبديل الذي يُجرى في محرر قادر على التحرير عرضَ الأسماء في كل المحررات والنسخ المتماثلة، ويكون آخر تبديل هو المعتمد، ويحفظه كلٌّ منها.
أما التبديل الذي يجريه محرر للقراءة فقط فيبقى دائمًا في ذلك المحرر، ولا يزال المحرر يتبع عمليات التبديل المشتركة التي تجريها المحررات الأخرى.

منذ الإصدار 5.1.0، يتبع تغيير لغة منشئ التعليمات البرمجية أو نمط تسمية الجداول أو نمط تسمية الأعمدة أو نوع علامات الاقتباس قفله الخاص (Language أو Table Name Case أو Column Name Case أو Bracket Type) بالطريقة نفسها، مع فرق واحد: ما دام القفل مفعّلًا، لا يُرسَل التغيير على الإطلاق.
يظهر فقط في المحرر الذي أجراه، وتتبعه علامتا تبويب منشئ التعليمات البرمجية ومخطط SQL فيه، ولا يراه أي محرر أو نسخة متماثلة أخرى. ويحتفظ value وruntimeValue بالقيمة المقفلة، لذا لا يراه كذلك المنضم الذي هُيّئ من أي محرر، ويمكن لكل مستخدم أن ينظر إلى لغة أو نمط تسمية أو نوع علامات اقتباس مختلف ما دام القفل مفعّلًا.
وما دام القفل معطّلًا، يُرسَل التغيير الذي يُجرى في محرر قادر على التحرير معلَّمًا بأنه مشترك (shared: true في حمولته). فيغيّر الإعداد في كل المحررات والنسخ المتماثلة، ويكون آخر تغيير هو المعتمد، ويحفظه كلٌّ منها. ويطبّق المحرر أو النسخة المتماثلة بالإصدار 5.1.0 التغيير المعلَّم أيًّا كان قفله هو، لذا يصل التغيير الذي يُجرى بعد إلغاء القفل مباشرة إلى كل مكان، حتى حيث يصل قبل إلغاء القفل.
قبل الإصدار 5.1.0 كان تغيير كهذا يصل إلى كل محرر ونسخة متماثلة سواء أكان قفله مفعّلًا أم لا، بينما كان الملف يحتفظ بالقيمة المقفلة.

منذ الإصدار 5.0.0 لا يرسل المحرر للقراءة فقط أي تغيير على الإطلاق. فالتمرير والتكبير وعلامة التبويب وعرض الأسماء وقاعدة البيانات ولغة منشئ التعليمات البرمجية وأنماط التسمية ونوع علامات الاقتباس وصفوف View Option التي يغيّرها قارئه تبقى على شاشته أيًّا كانت أقفالها؛ أما قبل الإصدار 5.0.0 فكانت عمليات التمرير والتكبير وتبديل علامات التبويب وقاعدة البيانات وإعدادات التعليمات البرمجية فيه تُرسَل كما في المحرر القابل للتحرير.
ولا يزال مخزنه يرسل ما ترسله أدوات التتبع الخاصة به من مؤشر القارئ وتركيزه وتحديده ومربع سحبه، ويجيب بالمسجّلات التي يطلبها المحرر المنضم، ويطبّق كل تغيير ترسله المحررات الأخرى. ويصل أي تغيير في قاعدة البيانات أو في أحد إعدادات منشئ التعليمات البرمجية أو في أحد صفوف View Option إلى مستنده، وإلى شاشته أيضًا ما لم يكن قارئه قد غيّر ذلك الإعداد فيها، ويظهر تبديل عرض الأسماء المشترك على شاشته في الحالتين. ومنذ الإصدار 5.1.0 لا يتلقى إعدادًا من إعدادات منشئ التعليمات البرمجية إلا إذا غُيّر ذلك الإعداد وقفله معطّل، أو حمله إلغاء قفل.
وعند تحوّل المحرر إلى وضع القراءة فقط يرسل أولًا ما لا يزال المخزن يحتجزه من سحب أو تمرير، كما تفعل flushStreamBuffers، فتحتفظ المحررات الأخرى بآخر ما جرى.

الأقفال مشتركة: آخر قفل لإعداد ما أو إلغاء قفله هو المعتمد في كل المحررات، ويحمل القفل قيم المحرر الذي فعّله، لذا يحفظ كل محرر وكل نسخة متماثلة القيمة نفسها.
لذلك يحفظ قفل Viewport عرض المحرر الذي فعّله، ويحفظ قفل Canvas Type آخر علامة تبويب كان عليها ذلك المحرر قبل علامة تبويب الإعدادات، حيث تُفعَّل الأقفال.
يضبط تعطيل قفل Language أو Table Name Case أو Column Name Case أو Bracket Type أو، منذ الإصدار 4.2.0، Name View ذلك الإعداد أيضًا في كل المحررات على القيمة الظاهرة في المحرر الذي عطّله، بما في ذلك تغييره الخاص الذي أجراه تحت القفل، فتواصل جميعها حفظ قيمة واحدة. ولا يحرّك تعطيل Viewport أو Canvas Type عرض أحد ولا علامة تبويبه.

يُرسَل تعديل السكربت Before tables أو After tables كاملًا عندما يفقد حقله التركيز. وتُحسم قيمة كل من السكربتين على حدة، لذا لا يكتب تعديل متعاون لأحدهما فوق الآخر أبدًا.

لا شيء مما يُفعل في وضع التدفق في علامة تبويب التصور المرئي يُعد تغييرًا في المستند، لذا لا يرسل المحرر الموجود في وضع التدفق أي تغييرات إلى المحررات الأخرى، وتظل التغييرات التي ترسلها تُطبَّق عليه أثناء وجوده فيه.
وثمة استثناءان. مغادرة وضع التدفق إلى علامة تبويب أخرى تبديل بين علامات التبويب، يُرسَل كأي تبديل آخر. ومنذ الإصدار 4.2.0، يُعد اختيار عنصر من قائمة عرض الأسماء في شريط وضع التدفق تبديلًا لعرض الأسماء، يُرسَل ويُطبَّق كالتبديل الذي يُجرى على لوحة الرسم.
ولا تُرسَل Previous table وNext table ومفاتيح التراجع والإعادة، التي تنتقل خطوةً خطوةً عبر ما عرضه وضع التدفق.
يؤدي زر الرابط الخارجي في البطاقة، ونتيجة البحث السريع المختارة بعد # أو @ أو :، وفتح المستكشف جميعها إلى مغادرة وضع التدفق إلى علامة تبويب ERD. ويُرسَل أيضًا التمرير الذي يُحدثه هناك زر البطاقة أو نتيجة البحث السريع.

محرران في صفحة واحدة​

يحلّ الربط هنا من subscribe إلى dispatch محل الشبكة، لكي ترى بنية الجلسة دون أن تعترضها وسيلة نقل.

import '@dineug/erd-editor/erd-editor.js';

const editor1 = document.createElement('erd-editor');
const editor2 = document.createElement('erd-editor');

const sharedStore1 = editor1.getSharedStore({
getNickname: () => 'editor1',
});
const sharedStore2 = editor2.getSharedStore({
getNickname: () => 'editor2',
});

sharedStore1.subscribe(actions => {
sharedStore2.dispatch(actions);
});

sharedStore2.subscribe(actions => {
sharedStore1.dispatch(actions);
});

يبدأ المحرران هنا من المستند الجديد الفارغ نفسه، لذا لا يحتاج أي منهما إلى تهيئة.
مع ثلاثة محررات أو أكثر، أرسل دفعات كل محرر إلى كل المحررات الأخرى: فالمحرر لا يمرّر أبدًا ما استقبله.

تهيئة متعاون​

يمرّر المخزن المشترك التغييرات لحظة حدوثها ولا يسلّم المنضم أبدًا المستند بحالته الراهنة، لذا يجب تزويد المحرر الذي ينضم إلى جلسة جارية بالمستند أولًا.
منذ الإصدار 4.0.0، هيّئه بالخاصية runtimeValue من محرر موجود بالفعل في الجلسة، لا بالخاصية value ولا بالملف المحفوظ.
تحتفظ الغرفة المربوطة باستخدام @dineug/erd-editor-yjs بالمستند نفسه بمجرد أن يكون عميل قد هيّأها، لذا يفتح كل محرر مربوط بها ذلك المستند دون تمرير runtimeValue.

editor2.setInitialValue(editor1.runtimeValue);

const sharedStore2 = editor2.getSharedStore();

لا تزال قيمة وقت التشغيل تحتفظ بما أُزيل منذ فتح المستند، لذا عندما يتراجع محرر آخر لاحقًا عن إزالة، يعيد المنضم الجدول باسمه وأعمدته.
الخاصية value هي الصيغة التي يحملها الملف، دون الكيانات المُزالة، لذا فإن المنضم الذي يُهيَّأ منها، أو من الملف، سيعيد بدلًا من ذلك جدولًا فارغًا بلا اسم.
منذ الإصدار 4.2.0، ينطبق الأمر نفسه على الكلمة أو المصطلح أو المجال المُزال من إحدى أوراق القاموس: فحين يتراجع محرر آخر عن الإزالة، يُدرج المنضم الذي هُيّئ من runtimeValue الصف من جديد كاملًا، أما المنضم الذي هُيّئ من value فيُدرج صفًا فارغًا، يستبعده بعد ذلك value الخاص به.
واصل كتابة value إلى التخزين: فالخاصية runtimeValue مخصصة فقط لتهيئة محرر آخر أو عرض ثانٍ أو replicationStore.
تهيّئ المحررات في VS Code وObsidian وبيئة تطوير JetBrains وتطبيق الويب بهذه الطريقة عرضًا ثانيًا لمستند مفتوح.

لا يُمرَّر استدعاء الدالة setInitialValue، لذا لا تغيّر تهيئة المنضم شيئًا لدى المحررات الأخرى.
منذ الإصدار 4.0.0، تتخلص الدالة أيضًا من مسجّلات التعاون في المحرر، وهي التي تحسم التعديلات المتزامنة. وإذا سبق أن اشترك أحد في المخزن المشترك للمحرر، يطلب المخزن من المحررات الأخرى مسجّلاتها مجددًا، كما في أول استدعاء للدالة subscribe، لكي يحسم المحرر المُعاد تحميله في منتصف الجلسة التعديلات كما تحسمها المحررات الأخرى.
أما إسناد قيمة إلى value فيُبقي على المسجّلات، لكنه بخلاف setInitialValue يُمرَّر: فبمجرد أن يصبح للمحرر مخزن مشترك، يحمّل كل محرر في الجلسة المستند المُسنَد، لذا لا تهيّئ منضمًا بهذه الطريقة أبدًا.

لا تحتوي value ولا runtimeValue على المسجّلات ولا على رقم النسخة الذي بلغته ساعة المحرر، لذا يأخذهما المنضم المهيّأ من runtimeValue وحدها من الجواب الذي ترسله المحررات في الجلسة عند أول اشتراك له.
إلى أن يصل ذلك الجواب، قد يحمل تعديل يجريه المنضم رقم نسخة أدنى مما تحتفظ به المحررات الأخرى، فترفضه وهو يبقى على المنضم، وتُطبَّق كتابة أقدم لا تزال في طريقها فوق الكتابة الأحدث التي تحملها التهيئة. وحيث لا يجيب أي محرر قيد التشغيل، كما حين يحتفظ خادم أو مخزن مستندات بمستند الجلسة، لا يحصل المنضم عليهما أبدًا.
منذ الإصدار 5.1.0 سلّمهما مع القيمة. في محرر موجود في الجلسة، استدع flushStreamBuffers() ليخرج أولًا ما لا يزال يحتجزه من سحب أو تغيير لون، ثم اقرأ runtimeValue ودالتي getLWW() وgetVersion() الخاصتين بمخزنه في اللحظة نفسها. يحمّل المنضم القيمة بالدالة setInitialValue، ثم يأخذ الباقي بالدالة mergeLWW في مخزنه، بهذا الترتيب، لأن كل استدعاء للدالة setInitialValue يتخلص من المسجّلات. فيحمل تعديله التالي رقم نسخة يتجاوز كل رقم تحمله التهيئة، فيُطبَّق دون جواب ينتظره. وفي مخزن موجود بالفعل، تنجز الدالة reseed الأمرين في استدعاء واحد.

// on an editor already in the session
sharedStore1.flushStreamBuffers();
const seed = {
value: editor1.runtimeValue,
lww: sharedStore1.getLWW(),
version: sharedStore1.getVersion(),
};

// on the joiner
editor2.setInitialValue(seed.value);
const sharedStore2 = editor2.getSharedStore();
sharedStore2.mergeLWW(seed.lww, seed.version);

التهيئة المحفوظة بهذه الطريقة لفتح المنضمين اللاحقين تضم الثلاثة معًا. وهي ليست ملفًا: تظل value هي ما يُكتب إلى التخزين.
لا يسلّم replicationStore أي مسجّلات، لذا يظل المنضم المهيّأ من runtimeValue الخاصة به يأخذها من جواب المحررات.

التعديلات المتزامنة​

يحتفظ كل محرر وكل نسخة متماثلة، لكل اسم ولكل حقل آخر تقريبًا، برقم نسخة الكتابة التي ضبطته: هذه هي مسجّلات التعاون الخاصة به. ولا تُطبَّق الكتابة إلا إذا لم يكن رقم نسختها أدنى من الرقم المحفوظ، لذا تنتهي المحررات التي تسمع التغييرات نفسها بترتيبات مختلفة إلى المستند نفسه.
منذ الإصدار 5.1.0 يحمل كل رقم نسخة، تحت عدّاده، خانة خاصة بالمحرر الكاتب مأخوذة من معرّفه. لذلك تنمو الأرقام بخطوات قدرها 4,194,304 وتتجاوز عددًا صحيحًا من 32 بتًا عندما يبلغ العدّاد 512. يحملها JSON.stringify وJSON.parse سليمة، لكن على وسيط تمرير أو مخزن يحللها بلغة أخرى أن يحتفظ بها أعدادًا من 64 بتًا، لا أعدادًا صحيحة من 32 بتًا أبدًا.

منذ الإصدار 5.1.0 ينتهي محرران يغيّران اسمًا أو حقلًا واحدًا في اللحظة نفسها، باستثناء ما يرد أدناه، إلى القيمة نفسها في كل محرر ونسخة متماثلة: فكل منهما، وهو يكتب عند عدّاد واحد، يختم رقم نسخة مختلفًا عن الآخر، ويفوز الأكبر منهما في كل مكان. قبل الإصدار 5.1.0 كان يمكن أن يختم الاثنان رقم نسخة واحدًا، فيحتفظ كل محرر بما سمعه أخيرًا، لذا كان يمكن أن ينتهيا إلى نتيجتين مختلفتين. يتشارك محرران الخانة نفسها باحتمال 1 من 4,194,304 لكل زوج، وعندئذ يتعادلان كما في السابق.

منذ الإصدار 5.1.0 تُمنح أرقام النسخ بالطريقة نفسها لموضع الجدول، وموضع الملاحظة أو مجموعة الجداول وحجمها، ولأصل العرض ومستوى تكبيره، ويخرج ما يحرّكها على شكل الموضع الذي ينتهي إليه:

  • السحب على شكل table.moveTo أو memo.moveTo أو tableGroup.moveTo واحد لكل كيان جرى نقله، في دفعة واحدة، لذا يحمل سحب المجموعة نقاط جداولها مع نقطة المجموعة؛
  • التراجع عن سحب أو إعادته على شكل النقطة التي يضع عندها كل كيان؛
  • تحريك العرض على شكل settings.scrollTo، وتغيير مستوى التكبير على شكل settings.changeZoomLevel؛
  • تغيير حجم ملاحظة أو مجموعة جداول على شكل موضعها وحجمها معًا.

لذلك ينتهي مستخدمان ينقلان جدولًا أو ملاحظة أو مجموعة جداول واحدة، أو ينقلانها ويغيّران حجمها، في اللحظة نفسها، إلى أن تكون عند نقطة واحدة وبحجم واحد في كل محرر ونسخة متماثلة. وتذهب النقطة إلى الكتابة ذات رقم النسخة الأكبر، بالمحورين معًا. ولا يكتب النقل حجمًا، لذا يحتفظ تغيير الحجم بحجمه حتى حيث يأخذ نقلٌ أُجري في الوقت نفسه النقطة.
قبل الإصدار 5.1.0 كان السحب يخرج على شكل المسافة المقطوعة، لذا كان سحبان لجدول واحد يتراكمان، وكان نقل وتغيير حجم لملاحظة واحدة أو مجموعة جداول واحدة يتمّان في الوقت نفسه قد ينتهيان إلى نتيجتين مختلفتين.
السحب الذي يقل عن 20 بكسل، ولا يترك إدخالًا في سجل التراجع، يُرسَل كأي سحب آخر، لذا يمكنه، بوصفه نقطة، أن يتجاوز سحبًا للكيان نفسه أجراه مستخدم آخر في اللحظة نفسها. ودفعة السحب أو تحريك العرض أو التكبير التي تسلّمها وسيلة النقل مرتين لا تحرّك شيئًا مرتين.

تغيير اللون استثناء. يخرج بلا رقم نسخة، ويختمه كل محرر ونسخة متماثلة برقمه الخاص ويحتفظ باللون الذي سمعه أخيرًا، لذا قد ينتهي مستخدمان يغيّران لون جدول أو ملاحظة أو مجموعة جداول واحدة في اللحظة نفسها إلى لونين مختلفين.
وثمة تغييرات قليلة لا تحمل رقم نسخة على الإطلاق، لذا يطبّقها كل محرر ونسخة متماثلة بالترتيب الذي يسمعها به، وقد ينتهي تغييران منها يجريان في اللحظة نفسها إلى نتيجتين مختلفتين أيضًا: نقل عمود داخل جدوله أو فهرسه (column.move وindexColumn.move)، وتغيير قاعدة البيانات، أو صف View Option، أو أحد الإعدادات Relationship DataType Sync وMaximum comment width وColumn Order في علامة تبويب الإعدادات.
قد تظهر الكيانات التي يضيفها مستخدمان في اللحظة نفسها، مثل جدولين أو عمودين في جدول واحد، بترتيب مختلف في كل محرر ونسخة متماثلة أيضًا، ويحفظ value كل منها ترتيبه الخاص.

كل ما سبق صحيح بين المحررات والنسخ المتماثلة بالإصدار 5.1.0 أو أحدث؛ وما يغيّره وجود إصدار أقدم موضّح في الجمع بين إصدارات مختلفة.

الجمع بين إصدارات مختلفة​

لا يطبّق المحرر إلا أنواع الإجراءات التي يعرفها إصداره، لذا في الجلسة التي تجمع بين إصدارات مختلفة تفوت المحررات الأقدم كل ما يُنقل عبر نوع أحدث.

منذ الإصدار 3.10.0، يُنقل تغيير ON DELETE أو ON UPDATE لعلاقة ما عبر أحد نوعين جديدين من الإجراءات، هما relationship.changeOnDelete وrelationship.changeOnUpdate، ويمكن أن يحمل relationship.add كليهما. ولا يحتاج وسيط تمرير ينقل الإجراءات كما هي إلى أي شيء جديد من أجلها.
يتجاهل المحرر الصادر قبل الإصدار 3.10.0 أنواع الإجراءات والحقول تلك: فلا يعرف أبدًا ON DELETE أو ON UPDATE لعلاقة ما، والمستند المحفوظ منه لا يحتوي على أي منهما. والعلاقة التي يضيفها محرر أقدم تصل دونهما، لذا يبدأ كلاهما بالقيمة Not set.

ويُنقل كل تغيير آخر يرسله محرر بالإصدار 3.10.0 عبر أنواع إجراءات تعرفها المحررات الأقدم بالفعل.
يرسل Replace All في البحث والاستبدال تعديلاته في دفعة واحدة من إجراءات إعادة التسمية والتعليق والملاحظة نفسها التي يرسلها التعديل اليدوي. ويُنقل خيارا العرض Alternate Key وReferential Actions عبر الإجراء الموجود مسبقًا settings.changeShow.

منذ الإصدار 4.0.0، تُنقل هذه التغييرات عبر أنواع إجراءات جديدة، ولا يحتاج وسيط تمرير ينقل الإجراءات كما هي إلى أي شيء جديد من أجلها:

  • إضافة مجموعة جداول أو نقلها أو تغيير حجمها أو إعادة تسميتها أو تغيير لونها أو إزالتها: tableGroup.add وtableGroup.move وtableGroup.moveTo وtableGroup.resize وtableGroup.changeName وtableGroup.changeColor وtableGroup.remove؛ وانضمام جدول إلى مجموعة أو مغادرته لها: table.changeGroup؛
  • النقر على Save في تعيين الأعمدة لعلاقة موجودة، وهو ما يضبط قائمتي أعمدتها كلتيهما في آن واحد: relationship.changeColumns؛
  • تفعيل قفل أو تعطيله: settings.changeLockSettings؛
  • تعديل السكربت Before tables أو After tables في علامة تبويب مخطط SQL: settings.changeDDLScript.

ويُنقل خيارا العرض Table Groups وMemos عبر الإجراء الموجود مسبقًا settings.changeShow.
لم يعد يُرسَل settings.changeIgnoreSaveSettings، الذي كان يرسله مفتاحا التبديل Save Scroll Information وSave Zoom Information قبل أن تحل الأقفال محلهما، وأُزيل settings.changeRelationshipOptimization. ولا يغيّر المحرر بالإصدار 4.0.0 شيئًا إذا استقبل أيًا منهما.

يتجاهل المحرر الصادر قبل الإصدار 4.0.0 أنواع الإجراءات الجديدة: فلا يرى أبدًا أي مجموعة جداول ولا الجداول التي تضمها، مع أن سحب المجموعة لا يزال يحرّك جداولها لديه، لأن السحب يرسل أيضًا نقلًا لكل جدول من تلك الجداول.
ويُبقي على الأعمدة القديمة للعلاقة بعد النقر على Save في تعيين الأعمدة، وعندما يُزال لديه عمود من ذلك التعيين القديم، تختفي العلاقة من كل المحررات. وليس لديه أقفال ولا سكربتات.
والمستند المحفوظ من محرر كهذا لا يحتوي على أي من ذلك، ويفتحه المحرر بالإصدار 4.0.0 وجميع الأقفال مفعّلة.
احرص على أن يكون كل محرر في الجلسة، وأي replicationStore يخزّن مستندها، على الإصدار 4.0.0 أو أحدث.

لا يرسل المحرر بالإصدار 4.1.0 أي نوع إجراء جديد، لذا تتشارك المحررات والنسخ المتماثلة بالإصدارين 4.0.0 و4.1.0 الجلسة نفسها دون أن يفوتها شيء.
وتبحث ميزة البحث والاستبدال فيه أيضًا في أسماء الفهارس وأسماء مجموعات الجداول، ويعيد Replace وReplace All تسميتها عبر الإجراءين index.changeName وtableGroup.changeName اللذين يطبّقهما المحرر بالإصدار 4.0.0 بالفعل.

منذ الإصدار 4.2.0، تُنقل هذه التغييرات عبر أنواع إجراءات جديدة، ولا يحتاج وسيط تمرير ينقل الإجراءات كما هي إلى أي شيء جديد من أجلها:

  • الاسم المنطقي لجدول أو عمود: table.changeLogicalName وcolumn.changeLogicalName؛ وما إذا كان اسمه مشتقًا من القواميس: table.changeNameDerived وcolumn.changeNameDerived؛
  • ربط عمود بمجال أو فك ربطه بالمجال: column.changeDomain؛
  • إضافة كلمة أو مصطلح أو مجال في علامة تبويب القاموس أو تغييره (بما في ذلك موضعه في الورقة، كما يضبطه الفرز) أو إزالته: dictionary.add وdictionary.update وdictionary.remove؛
  • تبديل عرض الأسماء: settings.changeNameViewMode.

ويُنقل القفل Name View عبر الإجراء الموجود مسبقًا settings.changeLockSettings، وخيار العرض Domain عبر settings.changeShow، ونقل Logical Name أو Domain في ترتيب الأعمدة عبر settings.changeColumnOrder.
ويحمل الإجراءان editor.clear وeditor.loadJson في استيراد مخطط SQL أو GraphQL أو DBML أو AML عبر Import الحقل keepDictionaries: true، الذي يُبقي على الكلمات والمصطلحات والمجالات في كل المحررات. وكذلك يحمله الإجراءان في استدعاء setSchemaSQL أو setSchemaGraphQL أو setSchemaDBML أو setSchemaAML بوضع الاستبدال.
ويُنقل الاسم المادي الذي تشتقه القواميس عبر table.changeName أو column.changeName، ونوع البيانات الذي يمنحه المجال لأعمدته عبر column.changeDataType، وهي الإجراءات التي يرسلها التعديل اليدوي.

يتجاهل المحرر الصادر قبل الإصدار 4.2.0 أنواع الإجراءات الجديدة: فليس لديه أسماء منطقية ولا روابط مجالات ولا قواميس ولا عرض أسماء. ولا يغيّر قفل Name View أو إلغاء قفله شيئًا لديه، ولا نقل Logical Name أو Domain في ترتيب الأعمدة، ولا نقل عنصر آخر إلى موضع أيٍّ منهما. ولا قفل Canvas Type الذي يفعّله محرر انتقل إلى علامة تبويب الإعدادات من علامة تبويب القاموس: فالمحرر الأقدم لا يعرف علامة التبويب تلك، لذا يُبقي Canvas Type غير مقفل. ولا يزال يعرض الأسماء المادية التي تشتقها القواميس وأنواع البيانات التي تمنحها المجالات.
ولا تعرف تعديلاته الخاصة شيئًا عن الأسماء المنطقية أو المجالات أو القواميس، مما يترك الآثار التالية على المحررات الأحدث:

  • يبقى اسم الجدول أو العمود الذي يعيد تسميته يدويًا معلَّمًا على أنه مشتق، لذا قد يشتق الاسم المنطقي الذي يُكتب له لاحقًا في محرر أحدث الاسمَ من جديد فوق الاسم الذي كتبه.
  • نوع البيانات الذي يمنحه لعمود مرتبط بمجال يُبقي على الربط، لذا تُدرج الورقة Checks الفحص Domain type mismatch، ويمنح التغيير التالي لنوع المجال العمودَ نوعَ المجال من جديد.
  • لا تحصل أعمدة المفتاح الخارجي في العلاقة التي يضيفها على اسم منطقي ولا مجال من مفتاحها.
  • يصل الجدول الذي يلصقه أو يكرره بلا أسماء منطقية ولا روابط مجالات.
  • لا يرسل استيراد مخطط SQL أو GraphQL أو DBML أو AML فيه الحقل keepDictionaries، لذا يُفرغ الكلمات والمصطلحات والمجالات في كل المحررات.
  • يحمّل تراجعه عن تحميل أو استيراد أو عن clear() نسخته الخاصة من المستند في كل المحررات، وليس في تلك النسخة أسماء منطقية ولا روابط مجالات ولا قواميس.
  • تعيد تلك النسخة، والمستند الذي يحمّله استيراد مخطط SQL أو GraphQL أو DBML أو AML فيه، القفلَ Name View في كل المحررات أيضًا إلى الحال التي وجده عليها ذلك المحرر الأقدم. ثم يحفظ كل محرر العرض Physical Names بوصفه عرض الأسماء، ويعرضه أيضًا إذا كان القفل معطّلًا.

والمستند المحفوظ من محرر كهذا لا يحتوي على أسماء منطقية ولا روابط مجالات ولا قواميس ولا عرض أسماء، لذا يفتحه المحرر بالإصدار 4.2.0 على العرض Physical Names. لكن المحرر الأقدم يحفظ القفل Name View على الحال التي وجده عليها، لذا يبقى المستند الذي أُلغي قفله في محرر بالإصدار 4.2.0 غير مقفل.
احرص على أن يكون كل محرر في الجلسة، وأي replicationStore يخزّن مستندها، على الإصدار 4.2.0 أو أحدث.

لا يرسل المحرر بالإصدار 5.1.0 أي نوع إجراء جديد، لذا لا تزال المحررات والنسخ المتماثلة السابقة للإصدار 5.1.0 تتشارك الجلسة معه، ولا يحتاج وسيط تمرير ينقل الإجراءات كما هي إلى أي شيء جديد. لكن ما تصفه التعديلات المتزامنة لا يصح إلا بين المحررات والنسخ المتماثلة بالإصدار 5.1.0:

  • تُنقل عمليات سحب محرر بالإصدار 5.1.0 على شكل نقاط عبر table.moveTo وmemo.moveTo وtableGroup.moveTo، وتطبّقها المحررات الأقدم بالفعل، وتُنقل عمليات تحريك العرض والتكبير فيه على شكل نقاط عبر settings.scrollTo وsettings.changeZoomLevel، اللتين لا يطبّقهما، كأي تحريك للعرض وتكبير، أي محرر آخر وإنما تأخذهما النسخ المتماثلة فقط. ويطبّق المحرر الأقدم كل نقطة من السحب بالترتيب الذي تصل به، خارج أي مسجّل، وتفعل النسخة المتماثلة الأقدم الأمر نفسه مع كل نقطة من سحب أو تحريك للعرض أو تكبير، لذا قد تنتهي نقطتان أُرسلتا في وقت واحد لكيان واحد، أو للعرض، إلى نتيجتين مختلفتين هناك.
  • لا يزال سحب المحرر الأقدم يُنقل على شكل المسافة المقطوعة، التي يجمعها كل محرر ونسخة متماثلة خارج مسجّلاتها، ويُنقل تحريكه للعرض أو تكبيره على شكل مسافة أيضًا، تجمعها كل نسخة متماثلة بالطريقة نفسها. وقد تنتهي مسافة ونقطة لكيان واحد أُجريتا في الوقت نفسه إلى نتيجتين مختلفتين في المحررات والنسخ المتماثلة التي تسمعهما بترتيبين مختلفين، وتُجمع المسافة التي تسلّمها وسيلة النقل مرتين مرتين.
  • خارج الاستثناءات التي تسميها التعديلات المتزامنة، تفوز كتابة محرر بالإصدار 5.1.0 لاسم أو حقل أُجريت في اللحظة نفسها التي كتب فيها محرر أقدم الاسم أو الحقل نفسه دائمًا تقريبًا، بالجواب نفسه في كل محرر ونسخة متماثلة. ولا يزال يمكن لمحررين أقدمين أن ينتهيا إلى نتيجتين مختلفتين على حقل واحد كُتب في وقت واحد.
  • لا يرسل محرر بالإصدار 5.1.0 تغيير لغة منشئ التعليمات البرمجية أو نمط التسمية أو نوع علامات الاقتباس إلا ما دام قفله معطّلًا، مع العلامة shared: true، التي يتجاهلها المحرر الأقدم فيطبّق التغيير كما في السابق. ولا يزال المحرر الأقدم يرسل التغيير الذي يجريه تحت القفل، بلا علامة: فيُسقطه المحرر أو النسخة المتماثلة بالإصدار 5.1.0 ما دام ذلك الإعداد مقفلًا لديه، وتطبّقه المحررات الأقدم. فتتبع المحررات الأقدم تحت القفل اختيارات بعضها بعضًا بينما تحتفظ المحررات بالإصدار 5.1.0 باختياراتها الخاصة، ويحتفظ الملف بالقيمة المقفلة في الحالتين. ويحمل إلغاء القفل الذي يجريه أي من الإصدارين قيمة من ألغاه إلى كل محرر ونسخة متماثلة.
  • التحميل الذي يستبدل المستند، مثل value المُسنَدة أو clear() أو استيراد يستبدل المستند، ينهي رسم العلاقة في كل محرر بالإصدار 5.1.0، في المحرر الذي أجراه وفي كل محرر يستقبله. أما المحرر الأقدم فيُبقي رسمها مفعّلًا خلاله.

احرص على أن يكون كل محرر في الجلسة، وأي replicationStore يخزّن مستندها، على الإصدار 5.1.0 أو أحدث، لتنتهي التعديلات التي تتم في اللحظة نفسها إلى النتيجة نفسها في كل مكان، باستثناء ما تسميه التعديلات المتزامنة؛ ويظل الإصدار 4.2.0 أو أحدث هو ما يُبقي على الأسماء المنطقية والقواميس. ويُعد خادم MCP السابق للإصدار 1.2.0 محررًا سابقًا للإصدار 5.1.0 هنا، ولا يمكن ربط محرر سابق للإصدار 5.1.0 بغرفة Yjs على الإطلاق.

SharedStoreConfig​

getNickname​

تضبط الاسم المستعار الذي يظهر بجوار مؤشر الماوس الخاص بهذا المستخدم في المحررات الأخرى.
يرى المستخدمون الآخرون user عندما يكون الاسم المستعار مفقودًا أو فارغًا.

editor.getSharedStore({
getNickname: () => 'nickname...',
});

mouseTracker​

يبث مؤشر الماوس الخاص بهذا المستخدم إلى المحررات الأخرى. القيمة الافتراضية true.
تظهر المؤشرات التي يرسلها المستخدمون الآخرون دائمًا على لوحة رسم ERD.

editor.getSharedStore({ mouseTracker: false });

focusTracker​

يبث ما يعمل عليه هذا المستخدم. القيمة الافتراضية true.
يُرسَل إلى المحررات الأخرى ويُرسم فيها كل من الجدول والخلية اللذين عليهما تركيزك، والجداول والملاحظات ومجموعات الجداول التي حددتها، والمربع الذي تسحبه على لوحة الرسم.
يحصل كل مستخدم على لون خاص به لكي تميّز بين المستخدمين: إطار حول الجدول الذي عليه التركيز، وخط سفلي تحت الخلية التي عليها التركيز، وحلقة حول الجداول والملاحظات ومجموعات الجداول المحددة، ومستطيل متقطع لمربع السحب.
منذ الإصدار 4.2.0، يمكن لكل مستخدم أن ينظر إلى عرض أسماء مختلف ما دام قفله مفعّلًا، أو بعد تبديل يجريه محرر للقراءة فقط لنفسه. والخلية التي عليها التركيز ولا يرسمها عرضك يُرسم خطها السفلي تحت الخلية التي يرسمها مكانها: فالاسم والاسم المنطقي يحل كلٌّ منهما محل الآخر، كما يفعل نوع البيانات والمجال.
تُرسم معلومات الحضور الواردة من المستخدمين الآخرين دائمًا على لوحة الرسم لديك، سواء أكان هذا الخيار مفعّلًا أم لا.
في وضع التدفق في علامة تبويب التصور المرئي، يُرسم تركيز المستخدمين الآخرين وتحديدهم على بطاقات الجداول، أما مربعات السحب الخاصة بهم فلا تُرسم. ولا تزال الجداول التي تحددها هناك تُرسَل؛ أما المربع الذي تسحبه هناك فلا يُرسَل.

editor.getSharedStore({ focusTracker: false });

عطّل كلا المتتبعين لاستخدام المخزن المشترك كوسيط تمرير بسيط لا ينشر أي معلومات حضور خاصة به.
ولا تزال معلومات الحضور التي ترسلها المحررات الأخرى تُستقبل وتُرسم.
وهذا ما تفعله المحررات في VS Code وObsidian وبيئة تطوير JetBrains وGoogle Drive.

editor.getSharedStore({ mouseTracker: false, focusTracker: false });

يُنقل المؤشر والتركيز والتحديد ومربع السحب عبر الدفق نفسه الذي تمر عبره تغييرات المستند، لكنها عابرة.
فهي لا تدخل أبدًا في المستند ولا في سجل التراجع ولا في editor.value، لذا يمكن لوسيلة النقل أن تُسقطها، ويتجاهلها أي replicationStore.

SharedStore​

connection, disconnect​

تضبط هاتان الدالتان حالة الاتصال الحالية.
أثناء قطع الاتصال، تُحفظ التغييرات في مخزن مؤقت داخلي.
تُطلَق التغييرات المخزنة مؤقتًا إلى المشتركين بمجرد أن يصبح الإرسال ممكنًا مجددًا.
الحالة الافتراضية هي حالة الاتصال (connection).

sharedStore.connection();
sharedStore.disconnect();

dispatch, dispatchSync​

تطبّق التغييرات الواردة من مثيلات المحرر الأخرى على مثيل المحرر الحالي.
عندما تحمل دفعة طلب محرر آخر للمسجّلات، كما يرسله أول اشتراك لمنضم، يجيب المخزن عبر مشتركيه بمسجّلاته ورقم نسخته، ما لم يكن لا يحتفظ بأي مسجّلات.
منذ الإصدار 5.1.0 يرسل أولًا كل دفعة دفق لا يزال يحتجزها، كما تفعل flushStreamBuffers، لكي يقوم كل رقم نسخة يحمله جوابه على كتابة أُرسلت إلى الآخرين. لذلك يجعل وصول منضم كل محرر في الجلسة يرسل في وقت واحد ما لا يزال يحتجزه من سحب أو تحريك للعرض أو تكبير أو تغيير لون أو تغيير حجم ملاحظة.

sharedStore.dispatch(actions); // async
sharedStore.dispatchSync(actions); // sync

subscribe​

تشترك في تغييرات المحرر.
لا يخرج شيء من المحرر حتى يوجد مشترك واحد على الأقل، وتُحفظ التغييرات التي تحدث قبل ذلك في مخزن مؤقت.
ويطلب أول اشتراك أيضًا من المحررات الأخرى مسجّلات التعاون الخاصة بها، وهي التي تحسم التعديلات المتزامنة، لكي يحسمها المنضم المتأخر بالطريقة نفسها.
لكنه لا يجلب المستند، لذا هيّئ المنضم المتأخر أولًا؛ ومنذ الإصدار 5.1.0 يمكن أن تحمل التهيئة المسجّلات أيضًا.
منذ الإصدار 4.0.0، يطلب المخزن ذلك مجددًا في كل مرة تحمّل فيها الدالة setInitialValue، أو منذ الإصدار 5.1.0 الدالة reseed، مستندًا في محرره بعد ذلك الاشتراك الأول.

const unsubscribe = sharedStore.subscribe(actions => {
// send...
});

flushStreamBuffers​

ترسل دفعات الدفق التي لا يزال هذا المخزن يحتجزها، الآن، بدلًا من إرسالها بعد انقضاء فترة هدوئها.
منذ الإصدار 3.9.2، تعمل على المخزن الناتج عن getSharedStore؛ وفي الإصدار 3.9.1 تكون الدالة موجودة في النوع لكنها لا تفعل شيئًا.
يتم كل من نقل جدول أو ملاحظة أو مجموعة جداول، وتغيير لون أي منها، وتغيير حجم ملاحظة، وتمرير العرض أو تغيير مستوى تكبيره، على شكل دفق من التغييرات الصغيرة. ولا ينطبق ذلك على تغيير حجم مجموعة جداول: فهو يُرسَل مرة واحدة، عند انتهاء السحب.
يجمع المخزن كل دفق في دفعة واحدة ويحتجزها حتى يهدأ الدفق لمدة 200 مللي ثانية، على مرحلتين. يمر تغيير اللون أو تغيير حجم الملاحظة بالمرحلتين، فيخرج بعد نحو 400 مللي ثانية من آخر تغيير، كما كان كل دفق قبل الإصدار 5.1.0. ومنذ الإصدار 5.1.0 يخرج السحب أو تحريك العرض أو التكبير بعد المرحلة الأولى، أي بعد نحو 200 مللي ثانية من آخر خطوة فيه، على شكل الموضع الذي ينتهي إليه (راجع التعديلات المتزامنة).
ينهي الاستدعاء ذلك الانتظار في المرحلتين كلتيهما. وما دام المخزن متصلًا، يستلم المشترك الدفعة قبل أن يعود الاستدعاء. ولا يرسل الاستدعاء شيئًا إذا لم يكن هناك شيء محتجز.
تُسقط الدالة destroy، سواء أكانت دالة المخزن نفسه أم دالة المحرر، أي دفعة لا تزال محتجزة، لذا استدع هذه الدالة أولًا عندما تتخلى عن مخزن ويجب أن تحتفظ المحررات الأخرى بآخر تغيير، كما عند إغلاق علامة تبويب.

sharedStore.flushStreamBuffers();
sharedStore.destroy();

getLWW​

منذ الإصدار 5.1.0، تعيد نسخة من مسجّلات التعاون الخاصة بالمحرر (راجع التعديلات المتزامنة).
تُصنع النسخة عبر JSON، فهي كائن بسيط جاهز لتمريره إلى JSON.stringify، وتغيير يطرأ عليها يترك مسجّلات المخزن كما كانت.
سلّمها كما هي إلى mergeLWW أو reseed في مخزن آخر. وشكلها خاص بالمحرر نفسه، لذا لا تقرأ أي حقل منها.
اقرأها مع getVersion ومع runtimeValue الخاصة بالمحرر في اللحظة نفسها لتهيئة منضم.

const lww = sharedStore.getLWW();

mergeLWW​

منذ الإصدار 5.1.0، تضم المسجّلات التي سلّمها مخزن آخر عبر getLWW إلى مسجّلات هذا المخزن، محتفظة بالرقم الأكبر لكل منها، وتضم version إلى ساعة المحرر، التي تحتفظ بالأكبر بين رقمها الخاص والرقم المعطى.
لا تغيّر شيئًا في المستند: لا بايتًا من value أو runtimeValue، ولا إدخالًا في سجل التراجع، ولا حدث change. هي ترفع فقط أرقام النسخ التي يجب أن تتجاوزها أي كتابة لاحقة، فتُرفض بعدها أي كتابة أقدم من المسجّلات المعطاة، ويحمل التعديل التالي للمحرر رقم نسخة يتجاوز version.
لا ترسل شيئًا ولا تجيب عن شيء. وهي تضم مباشرة ما يحصل عليه أول اشتراك لمنضم من جواب المحررات الأخرى.
استدعها بعد setInitialValue لا قبلها أبدًا: فكل استدعاء للدالة setInitialValue وكل reseed يتخلص من المسجّلات المحتفظ بها، ومعها ما أخذه mergeLWW قبله.

sharedStore.mergeLWW(lww, version);

getVersion​

منذ الإصدار 5.1.0، تعيد أعلى رقم نسخة ضمّته ساعة المحرر: أكبر أرقام نسخ التغييرات التي أجراها أو تلقاها، وطلبات المسجّلات والأجوبة التي يتبادلها الانضمام، وكل version أُعطي للدالة mergeLWW أو reseed.
لا تحرّكه المؤشرات ولا التركيز ولا التحديدات ولا مربعات السحب، سواء أكانت خاصة به أم بمحرر آخر.
سلّمه مع getLWW()، المقروءة في اللحظة نفسها، إلى mergeLWW أو reseed لدى منضم. وهو رقم نسخة مثل تلك التي تحملها إجراءاته.

const version = sharedStore.getVersion();

forgetPeer​

منذ الإصدار 5.1.0، تزيل فورًا المؤشر والتركيز والتحديد ومربع السحب التي أرسلها المحرر ذو المعرّف المعطى، وانتهاء الصلاحية الذي كان ينتظره كل منها. ويبقى ما أرسله كل محرر آخر.
المعرّف هو meta.editorId الذي يحمله كل إجراء يرسله المخزن المشترك لذلك المحرر. والمعرّف الذي لا يحتفظ المحرر بشيء عنه لا يغيّر شيئًا.
استدعها عندما تعلم وسيلة النقل لديك أن نظيرًا غادر. وإلا يبقى ما أرسله النظير مرسومًا حتى تنتهي صلاحيته: مؤشره بعد 30 ثانية من آخر مؤشر استُقبل، وتركيزه وتحديده بعد 90 ثانية منه، ومربع سحبه بعد 3 ثوانٍ.

sharedStore.forgetPeer(editorId);

reseed​

منذ الإصدار 5.1.0، تفتح مستند الجلسة في المحرر مجددًا، كما تفعل إعادة الانضمام. ويستدعيها ربط Yjs لفتح مستند الغرفة عندما يرتبط بغرفة سبقت تهيئتها، ومجددًا عند كل إعادة انضمام، مع إبقاء ما على الشاشة بعد أن انضم إلى الغرفة.
تحمّل value كما تفعل setInitialValue، وتأخذ lww وversion كما تفعل mergeLWW، فيحتفظ المخزن عندئذ بالمسجّلات المعطاة بالضبط، وتحتفظ ساعته بالأكبر بين رقمها الخاص وversion. وهي تفرغ أيضًا سجل التراجع، وبخلاف setInitialValue تتخلص من التحديد والتركيز، لأنهما قد يسميان ما لم تعد القيمة تحتويه.
باستثناء اشتقاق الاسم المنطقي أدناه، لا تُنشئ إدخالًا في سجل التراجع، ولا تُطلق حدث change، ولا ترسل أي تغيير. وبمجرد أن يكون للمخزن مشترك، ترسل طلب المسجّلات الذي يرسله كل تحميل كهذا، وقد تُسقطه وسيلة نقل سلّمت المسجّلات بالفعل، وترسل، مع تشغيل focusTracker، التحديد والتركيز بعد مسحهما.
وكما تفعل setInitialValue، تعمل أثناء ضبط readonly، وتتخلص من عرض التدفق، وتنهي رسم العلاقة، وتغلق محررات الملاحظة واسم مجموعة الجداول والخلايا، محتفظة بما كُتب فيها أو متخلصة منه بالطريقة نفسها؛ أما الاسم الذي تشتقه خلية اسم منطقي تُغلَق مما كتبه قارئها فتعديل عادي: يُرسَل، ويمكن التراجع عنه، ويُطلَق على شكل حدث change.

من دون keepScreen تعرض الشاشة ما تحتويه القيمة، كما بعد setInitialValue. ومع keepScreen: true تُعاد شاشة القارئ فوق المستند المحمَّل، على تلك الشاشة وحدها:

  • موضع التمرير ومستوى التكبير، بعد أن يكون العنصر قد عرضهما؛ أما ما لم يُعرَض قط، أو حُمّل وهو مخفي ولم يظهر بعدها، فيُفتح حيث تضعه القيمة، كما يحدث لمنضم متأخر؛
  • علامة التبويب، إذا نقلها التحميل، وفي علامة تبويب الإعدادات أيضًا علامة التبويب التي جاء منها القارئ، وهي التي يسميها قفل Canvas Type الذي يُفعَّل هناك؛
  • عرض الأسماء وكل إعداد من إعدادات منشئ التعليمات البرمجية أظهره القارئ بنفسه تحت قفله، لكن فقط إذا كان ذلك القفل مفعّلًا قبل التحميل ولا يزال مفعّلًا بعده، ويحمل القيمة المقفلة نفسها. فإذا ألغى نظير القفل وغيّر الإعداد وقفله من جديد بقيمة أخرى في الأثناء، يُفتح المحرر على القيمة المقفلة الجديدة، وحيث يكون القفل معطّلًا قبل التحميل أو بعده يعرض القيمة المحمَّلة؛
  • كل إعداد غيّره قارئ للقراءة فقط على شاشته، أيًّا كانت الأقفال.

لا يُرسَل شيء من ذلك، وتظل value وruntimeValue تعرضان المستند المحمَّل. ويحل إلغاء قفل لاحق يجريه نظير محل إعداد التعليمات البرمجية الذي أُبقي عليه بهذه الطريقة، كما يفعل أي إلغاء قفل.
ويجعل التمرير أو التكبير التالي الذي يجريه القارئ والمحرر قادر على التحرير موضعَ التمرير ومستوى التكبير المُبقى عليهما جزءًا من المستند من جديد، ويخرج مسبوقًا بموضع الشاشة الحالي، لذا تأخذ النسخ المتماثلة ذلك التكبير أيضًا.

تترك إعادة التهيئة ما يحتجزه المخزن كما هو. فالسحب أو تحريك العرض أو التكبير الذي لا يزال محتجزًا يخرج بعدها، مقروءًا من المستند المعاد تهيئته؛ وتغيير اللون أو تغيير حجم الملاحظة يخرج كما أُجري، مع أن المحرر لم يعد يعرضه؛ وما احتجزته disconnect() يخرج عند connection().
لذا استدع flushStreamBuffers أولًا، وأرسل ما تطلقه، وأعد التهيئة بقيمة تحتويه. لا تُعِد التهيئة أبدًا أثناء قطع الاتصال.

sharedStore.reseed(seed.value, {
lww: seed.lww,
version: seed.version,
keepScreen: true,
});

destroy​

تدمّر مثيل sharedStore بالكامل.
ولا يتأثر المحرر نفسه، لذا يظل المستند قابلًا للتحرير بعد مغادرة الجلسة.
يتوقف متتبعا الماوس والتركيز بمجرد تدمير آخر sharedStore سلّمه المحرر.
وتُسقط معه أي دفعة دفق لا يزال المخزن يحتجزها؛ استدع flushStreamBuffers أولًا لإرسالها.
لا تزال المؤشرات والتركيز والتحديدات ومربعات السحب التي أرسلتها المحررات الأخرى مرسومة حتى تنتهي صلاحيتها؛ ومنذ الإصدار 5.1.0 تزيل forgetPeer ما يخص محررًا واحدًا فورًا.

sharedStore.destroy();