Zum Hauptinhalt springen

Remote-Speicherung

Bei jeder Änderung den gesamten Zustand des Editors zu senden, ist ineffizient.
Für diesen Fall stellt der Editor eine API zur Datenreplikation in Echtzeit bereit.

Installation​

npm install @dineug/erd-editor

Der Replikations-Store liegt unter dem Unterpfad @dineug/erd-editor/engine.js, nicht im Paketstamm.
Dieser Einstiegspunkt greift nicht auf das DOM zu, daher läuft er in einem Web Worker oder an jeder anderen Stelle außerhalb des Hauptthreads.
Ein Import des Paketstamms benötigt dagegen ein Dokument: Seit 5.0.0 definiert er kein Element, aber seine Auswertung erzeugt beide Elementklassen. Vor 5.0.0 registrierte er das Custom Element <erd-editor>.

Verwendung​

type ReplicationStore = {
readonly value: string;
readonly runtimeValue: string;
on: (
listeners: Partial<{ change: (change: ReplicationChange) => void }>
) => Unsubscribe;
setInitialValue: (value: string) => void;
dispatch: (actions: Array<AnyAction> | AnyAction) => void;
dispatchSync: (actions: Array<AnyAction> | AnyAction) => void;
destroy: () => void;
};

type ReplicationChange = {
value: string;
changed: boolean;
};

type InjectEngineContext = {
toWidth: (text: string) => number;
};

type CreateReplicationStore = (
context: InjectEngineContext
) => ReplicationStore;

// example
import { createReplicationStore } from '@dineug/erd-editor/engine.js';

const replicationStore = createReplicationStore({
toWidth: text => text.length * 10,
});

Einen laufenden Editor replizieren​

Die Aktionen stammen aus dem gemeinsamen Store eines laufenden Editors.
Siehe Gemeinsame Bearbeitung.

import { createReplicationStore } from '@dineug/erd-editor/engine.js';

const replicationStore = createReplicationStore({ toWidth });
replicationStore.setInitialValue(editor.runtimeValue);

replicationStore.on({
change: ({ value, changed }) => {
if (changed) save(value);
},
});

const sharedStore = editor.getSharedStore();
sharedStore.subscribe(actions => {
replicationStore.dispatch(actions);
});

Nur die Änderung überschreitet die Grenze, nie das ganze Dokument.
Das Replikat wendet sie an und serialisiert das Ergebnis auf seiner eigenen Seite.
Das Ereignis change übergibt Ihnen dieses Ergebnis als value, und changed zeigt Ihnen an, wann sich das Schreiben lohnt.

Seit 4.0.0 initialisieren Sie das Replikat wie oben mit dem runtimeValue des Editors, nicht mit der gespeicherten Datei oder dem value des Editors.
In der Datei fehlen die seit dem Speichern vorgenommenen Änderungen, und in value fehlen die in der Sitzung entfernten Entitäten.
Ein Replikat, das ohne eine entfernte Tabelle initialisiert wurde, stellt diese ohne Namen und Spalten wieder her, wenn ein Editor das Entfernen rückgängig macht, und speichert sie so.
Seit 4.2.0 gilt dasselbe für ein Wort, einen Begriff oder eine Domäne, die von einem Blatt der Registerkarte Wörterbuch entfernt wurden.
Macht ein Editor das Entfernen rückgängig, listet ein Replikat, das ohne die Zeile initialisiert wurde, sie wieder leer auf, und da value eine leere Zeile weglässt, speichert das Replikat das Dokument ohne sie.
Bei einer Domäne bleiben außerdem die Spalten und Begriffe, die mit ihr verknüpft waren, in diesem Replikat nicht verknüpft, da es die Verknüpfungen nie gehalten hat und das Rückgängigmachen sie nicht sendet.

Seit 5.1.0 kann @dineug/erd-editor-yjs Editoren auch über einen Yjs-Raum synchron halten.
Wird ein Replikat wie oben von einem Element gespeist, das an einen Raum gebunden ist, erhält es nur die Änderungen, die an diesem Element vorgenommen wurden, nie die, die der Raum hereinbringt: Diese erreichen das Element als die eines anderen Editors, und ein gemeinsamer Store gibt nichts weiter, was er empfangen hat.
Um das Dokument eines Raums zu speichern, speichern Sie den Wert von value des gebundenen Elements oder eines gebundenen Peer-Stores, wie unter Was der Raum enthält beschrieben.
Ein Yjs-Persistenz-Provider speichert den Raum selbst, der statt einer Datei einen Laufzeitwert und die seither vorgenommenen Änderungen enthält; siehe Grenzen.

InjectEngineContext​

toWidth​

Misst eine Zeichenkette in Pixeln.
Der Store hat kein DOM, kann Text also nicht selbst messen und berechnet die Spaltenbreiten jedes Mal mit dieser Funktion neu, wenn sich ein Name, ein Datentyp, ein Standardwert oder ein Kommentar ändert.
Seit 4.2.0 gehört dazu auch der logische Name einer Tabelle oder Spalte.
Die Domänenzelle einer Spalte, die den Namen der mit der Spalte verknüpften Domäne zeigt, misst er jedes Mal, wenn die Spalte mit einer Domäne verknüpft oder ihre Verknüpfung aufgehoben wird, und jedes Mal, wenn diese Domäne hinzugefügt, umbenannt oder entfernt wird.
Außerdem misst er jede Tabelle und jede Spalte erneut, sobald setInitialValue ein Dokument lädt.
Seit 4.0.0 werden die Breiten nur in runtimeValue gehalten, nie in value.
Daher ergibt ein Dokument, das diese Version gespeichert hat, beim Laden Byte für Byte wieder denselben Wert von value, wo auch immer es gespeichert wurde und wie auch immer Text dort gemessen wurde.

Messen Sie so wie der Editor – 400 12px im Font-Stack des Editors, gerundet, plus 2 px Innenabstand.
Andernfalls weichen die Breiten in runtimeValue von denen auf dem Bildschirm ab.

const TEXT_PADDING = 2;
const FONT =
"400 12px -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, " +
"'Helvetica Neue', 'Open Sans', system-ui, sans-serif, " +
"'Apple Color Emoji', 'Segoe UI Emoji'";

let context = null;

function getContext() {
if (context) return context;

try {
context = new OffscreenCanvas(0, 0).getContext('2d');
if (context) context.font = FONT;
} catch {
// no canvas available
}

return context;
}

function toWidth(text) {
const context = getContext();
const width = context ? context.measureText(text).width : text.length * 10;

return Math.round(width) + TEXT_PADDING;
}

const replicationStore = createReplicationStore({ toWidth });

text.length * 10 dient als Fallback, wenn kein Canvas verfügbar ist.
Er genügt für einen Store, dessen Dokument nur gespeichert und nie gerendert wird.

ReplicationStore​

value getter​

Serialisiert den aktuellen Zustand des Editors.
Gibt eine JSON-Zeichenkette zurück, die sich unverändert speichern lässt – kein geparstes Objekt.

const data = replicationStore.value;

Seit 4.0.0 ist value die Speicherform: das Dokument so, wie eine Datei es enthält, derselbe Text, den die Eigenschaft value des Elements zurückgibt.
Die Speicherform enthält nur die nicht entfernten Entitäten in fester Reihenfolge, ohne die entfernten, ohne die Stapelreihenfolge und ohne alles, was ein Ladevorgang erneut ermittelt, etwa die Breiten, die toWidth misst.
Seit 4.2.0 enthält sie außerdem die logischen Namen, die Angabe, ob jeder Name aus den Wörterbüchern abgeleitet wurde, die Domänenverknüpfungen sowie die Wörter, Begriffe und Domänen der Registerkarte Wörterbuch.
Seit 4.2.0 lässt sie außerdem jedes leere Textfeld einer Entität weg, jede Liste in doc und jede Collection, die nichts enthält, sowie collections selbst, wenn jede Collection leer ist.
Sie ist mit zwei Leerzeichen eingerückt, schreibt jede Wörterbuchzeile in eine eigene Textzeile und endet mit einem Zeilenumbruch, sodass dasselbe Dokument immer dieselben Bytes ergibt.
Zu ihrem Inhalt siehe Speicherform.

Jede Einstellung, deren Sperre eingeschaltet ist, wird mit dem Wert geschrieben, mit dem sie gesperrt wurde, jede andere Einstellung so, wie sie gerade steht.
Die Sperre Viewport umfasst den Ursprung der Ansicht und die Zoomstufe gemeinsam, und die Registerkarte, die Sprache des Codegenerators, beide Schreibweisen und der Begrenzertyp haben jeweils eine eigene Sperre.
Seit 4.2.0 hat auch die Namensansicht eine eigene Sperre, Name View, die in einem neuen Dokument eingeschaltet ist.
Die Sperren ersetzen das Feld ignoreSaveSettings des Dokuments, das seit 4.0.0 weder gelesen noch geschrieben wird.
Vor 4.0.0 war value das ganze Dokument, wie der Store es hielt, wobei die Scroll- und Zoom-Bits dieses Felds angewandt wurden.

runtimeValue getter​

Serialisiert seit 4.0.0 das Dokument so, wie das Replikat es hält, samt den entfernten Entitäten und allem, was ein Ladevorgang ermittelt.
Auch hier wird jede gesperrte Einstellung mit ihrem gesperrten Wert geschrieben.

const snapshot = replicationStore.runtimeValue;

Verwenden Sie diesen Wert, um einen Editor oder einen weiteren Store, der später beitritt, über dessen Methode setInitialValue zu initialisieren; siehe Gemeinsame Bearbeitung.
Ein Replikat hat weder getLWW noch getVersion und gibt daher mit runtimeValue keine Kollaborationsregister weiter: Ein daraus initialisierter Editor übernimmt sie von den laufenden Editoren, wie unter Einen Mitbearbeiter initialisieren beschrieben.
Speichern Sie ihn nie als Datei: Er enthält die entfernten Entitäten, und das veröffentlichte JSON Schema lehnt ihn ab.
Gerade diese entfernten Entitäten ermöglichen es, dass ein später gesendetes Rückgängigmachen einer Entfernung die Entität in dem damit initialisierten Store vollständig wiederherstellt.
Sie bleiben erhalten, bis das Dokument das nächste Mal aus seiner Datei geöffnet wird, deren Form sie nicht enthält.

setInitialValue​

Lädt den zuvor gespeicherten Zustand des Editors.

replicationStore.setInitialValue('json...');

Die Methode akzeptiert die Speicherform, einen Laufzeitwert oder ein Dokument, das eine frühere Version gespeichert hat, auch ein v2-Dokument.
Eine leere Zeichenkette oder alles, was keine Zeichenkette ist, lädt ein neues, leeres Dokument, statt einen Fehler auszulösen.
Ein Store, dem nie ein Wert übergeben wurde, beginnt mit demselben neuen Dokument.
Seit 4.0.0 sind in diesem Dokument alle Sperren eingeschaltet, sodass es in value die Ansicht, die Registerkarte, die Sprache des Codegenerators, die Schreibweisen und den Begrenzertyp behält, mit denen es begonnen hat, während die Editoren, die der Store repliziert, scrollen, zoomen, die Registerkarte wechseln oder diese Einstellungen ändern. In 3.10.0 speicherte es weder die Scrollposition noch den Zoom, und davor speicherte es beides.
Seit 4.2.0 behält es außerdem seine Namensansicht, Physical Names, während die Editoren ihre wechseln.
Ein gespeichertes Dokument behält die Sperren, die es angibt.
Ein Dokument, das keine angibt, was auf jedes vor 4.0.0 gespeicherte Dokument zutrifft, auch auf ein v2-Dokument, wird mit allen eingeschalteten Sperren geladen: mit dem Ursprung der Ansicht bei 0, 0, der Zoomstufe 1 und der Registerkarte ERD, gleich, was es gespeichert hat, sowie mit der Sprache des Codegenerators, den Schreibweisen und dem Begrenzertyp so, wie es sie gespeichert hat.
Ein vor 4.2.0 gespeichertes Dokument gibt keine Sperre Name View an und wird daher mit eingeschalteter Sperre und in der Ansicht Physical Names geladen, auch wenn es mit allen anderen Sperren im ausgeschalteten Zustand gespeichert wurde.
Seit 4.0.0 verwirft setInitialValue außerdem die Kollaborationsregister, die für das vorherige Dokument gehalten wurden, wie es die Methode setInitialValue des Elements tut.
Auch Text, der kein JSON ist, etwa eine Datei mit zurückgebliebenen Merge-Konfliktmarkierungen, löst keinen Fehler aus: Der Parse-Fehler wird nur in der Konsole protokolliert, das Dokument wird geleert, und die Einstellungen bleiben, wie sie waren.

Seit 4.0.0 führt das Laden keine Garbage Collection aus, sodass entfernte Entitäten in runtimeValue erhalten bleiben.
Vorher verwarf es die Entitäten, die nicht mehr in doc vorkamen und seit vier oder mehr Tagen nicht geändert worden waren.

Die Neuberechnungen beim Laden sind abgeschlossen, bevor setInitialValue zurückkehrt: die Schlüsselmarkierungen der Spalten, abgeleitet aus den Optionen jeder Spalte und aus den Beziehungen; jede Tabellen- und Spaltenbreite, erneut mit toWidth gemessen; die Punkte, an denen jede Verbindungslinie auf ihre Tabellen trifft; und bei jeder Beziehung das Kennzeichen, ob sie identifizierend ist, sowie das Symbol an ihrem Ende an der Elterntabelle.
Keine davon ist Teil von value, aber replicationStore.runtimeValue enthält sie bereits alle, wenn es direkt nach dem Aufruf gelesen wird.
Eine Aktion, die direkt nach dem Laden eintrifft, etwa ein erneut abgespieltes Scrollen, wird mit dem geladenen Dokument verglichen, sodass das Laden selbst nie als changed gemeldet wird.

Weder das Laden noch eine dieser Neuberechnungen löst das Ereignis change aus.
Lesen Sie replicationStore.value selbst, sobald setInitialValue zurückkehrt, wenn Sie das geladene Dokument in der Speicherform zurückschreiben möchten.

on@change​

Abonniert Änderungen am Zustand des Editors.

const unsubscribe = replicationStore.on({
change: ({ value, changed }) => {
if (changed) {
// save value...
}
},
});

Das Ereignis change wird um 200 ms entprellt, sodass eine schnelle Folge von Aktionen als eine einzige Benachrichtigung ankommt.
Es wird nur bei Aktionen ausgelöst, deren Art das Dokument ändern kann, sowie bei der Aktion settings.changeIgnoreSaveSettings, die ein älterer Editor möglicherweise noch sendet (siehe dispatch, dispatchSync).
Eine weitergeleitete Präsenzaktion oder editor.mergeLWW weckt es nie.
Rufen Sie die zurückgegebene Funktion auf, um das Abonnement zu beenden.

Seit 3.10.0 erhält der Listener einen Wert vom Typ ReplicationChange, den @dineug/erd-editor/engine.js neben ReplicationStore exportiert.
Vor 3.10.0 erhielt er nichts, und ein Listener, der das Argument ignoriert, funktioniert weiterhin.
value ist das serialisierte Dokument in der Speicherform, dieselbe Zeichenkette, die replicationStore.value in diesem Moment zurückgibt, sodass Sie es nicht erneut serialisieren müssen.
changed ist false, wenn die Aktionen seit dem vorherigen Ereignis change oder seit dem Laden den Wert von value Byte für Byte unverändert gelassen haben.

Eine Änderung, die eine Sperre aus value heraushält, löst trotzdem das Ereignis change aus, wobei changed auf false gesetzt ist; schreiben Sie daher nur, wenn changed den Wert true hat.
Das sind ein Scrollen oder Zoomen, während Viewport gesperrt ist, ein Wechsel der Registerkarte, während Canvas Type gesperrt ist, sowie eine Änderung der Sprache des Codegenerators, einer Schreibweise oder des Begrenzertyps, während die jeweils eigene Sperre eingeschaltet ist, was seit 5.1.0 nur noch ein Editor vor 5.1.0 sendet (siehe dispatch, dispatchSync).
Seit 4.2.0 gilt das auch für einen Wechsel der Namensansicht, während Name View gesperrt ist: Der Editor sendet ihn weiterhin, aber das Replikat verwirft ihn, wie es auch die anderen Editoren tun.
Ein Wechsel der Namensansicht in einem schreibgeschützten Editor wird auf dieselbe Weise verworfen, unabhängig vom Zustand der Sperre.
Das Ereignis change des Elements lässt eine solche Änderung aus, das Replikat meldet sie aber trotzdem.
In einem neuen Dokument und in einem vor 4.0.0 gespeicherten ist jede Sperre eingeschaltet, und Name View ist in jedem vor 4.2.0 gespeicherten Dokument gesperrt.
Ist Viewport entsperrt, ändert ein Scrollen oder Zoomen den Wert von value, ist Canvas Type entsperrt, gilt das auch für das Öffnen einer anderen Registerkarte des Editors, und ist Name View entsperrt, gilt es auch für einen Wechsel der Namensansicht aus einem Editor, der nicht schreibgeschützt ist.
Auch das Ein- oder Ausschalten einer Sperre ändert value.

Seit 4.0.0 vergleicht changed die Speicherform, die weder die entfernten Entitäten noch die Stapelreihenfolge enthält.
Daher führen eine Tabelle, die innerhalb eines einzigen Ereignisses change hinzugefügt und wieder entfernt wird, eine Änderung, die eine von einem anderen Mitbearbeiter entfernte Entität trifft, und ein weitergeleitetes Laden, das nur die Stapelreihenfolge ändert, ebenfalls alle zu changed mit dem Wert false.
Seit 4.2.0 gilt das auch für eine Zeile, die einem Blatt der Registerkarte Wörterbuch hinzugefügt und leer gelassen wird, da die Speicherform eine Zeile weglässt, die nichts enthält.

changed vergleicht nie mit Ihrer gespeicherten Datei, die sich bereits von value unterscheiden kann, sobald sie geladen ist: Das gilt für eine Datei, die eine frühere Version gespeichert hat, auch für eine v2-Datei, ebenso für eine Datei, die mit einer Byte-Order-Mark beginnt, und für eine von Hand bearbeitete.
Seit 4.2.0 gehört dazu auch eine Datei, die 4.0.0 oder 4.1.0 gespeichert hat, da value die leeren Textfelder ihrer Entitäten sowie die leeren Listen in doc und die leeren Collections weglässt, die eine solche Datei enthält.
Ein Byte-Vergleich mit einer solchen Datei würde sogar ein Scrollen, das eine Sperre heraushält, als Änderung zählen.
Das erste Ereignis change, bei dem changed auf true gesetzt ist, liefert eine solche Datei in der Speicherform zurück, sodass sie beim Schreiben einmalig umgeschrieben wird.
Eine Datei, die diese Version gespeichert hat, unterscheidet sich nicht, wo auch immer sie gespeichert wurde, wie unter toWidth erklärt.
Wird setInitialValue aufgerufen, während noch ein Ereignis change aussteht, und wird vor dessen Fälligkeit keine Aktion übergeben, trifft dieses Ereignis change trotzdem ein, mit dem geladenen value und mit changed auf false.

dispatch, dispatchSync​

Wendet Änderungen entfernter Editoren auf den replicationStore an.

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

dispatch verschiebt die Anwendung in einen Microtask, und dispatchSync wendet den Stapel sofort an.

Sie können den Stream eines gemeinsamen Stores ungefiltert übergeben.
Beide Methoden behalten nur die Aktionen, deren Art das Dokument ändern kann, sowie die beiden am Ende dieses Abschnitts beschriebenen, und verwerfen den Rest, sodass die Präsenz, die eine gemeinsame Sitzung überträgt – Mauszeiger, Fokus, Auswahl und Auswahlrahmen jedes Benutzers –, wirkungslos durchläuft.

Seit 3.10.0 gehören relationship.changeOnDelete und relationship.changeOnUpdate zu den behaltenen Aktionen, und relationship.add überträgt onDelete und onUpdate.
Ein Store aus einer früheren Version verwirft diese Aktionen und ignoriert diese Felder, sodass ihm die Aktionen ON DELETE und ON UPDATE einer Beziehung verloren gehen.

Seit 4.0.0 gehören außerdem table.changeGroup, sieben der acht Aktionen unter tableGroup (tableGroup.add, tableGroup.move, tableGroup.moveTo, tableGroup.remove, tableGroup.resize, tableGroup.changeName und tableGroup.changeColor, alle außer der Änderung der Stapelreihenfolge tableGroup.changeZIndex), relationship.changeColumns, settings.changeLockSettings und settings.changeDDLScript zu den behaltenen Aktionen.
settings.changeRelationshipOptimization existiert nicht mehr, daher verwerfen beide Methoden diese Aktion.
Ein Store aus einer früheren Version verwirft die neuen Aktionen, sodass ihm Tabellengruppen, die Sperren, die Skripte von Schema SQL und die Spalten verloren gehen, die der Dialog Spalten zuordnen einer bestehenden Beziehung zuweist.
Betreiben Sie das Replikat mit derselben Version wie die Editoren oder einer neueren.

Version 4.1.0 fügt keinen Aktionstyp hinzu und lässt @dineug/erd-editor/engine.js unverändert, sodass ein Replikat der Version 4.0.0 jede Änderung behält, die ein Editor der Version 4.1.0 sendet, genau wie ein Replikat der Version 4.1.0.
Seit 4.1.0 benennen Replace und Replace All in Suchen und Ersetzen auch Indizes und Tabellengruppen um, und zwar über die Aktionen index.changeName und tableGroup.changeName, die ein Replikat der Version 4.0.0 bereits behält.
Der eigene Zustand des Explorers wird nie gesendet, und ein Registerkartenwechsel oder ein Scrollen, das er auslöst, kommt an wie jeder andere Registerkartenwechsel und jedes andere Scrollen; siehe Gemeinsame Bearbeitung.

Seit 4.2.0 gehören zu den behaltenen Aktionen außerdem table.changeLogicalName, table.changeNameDerived, column.changeLogicalName, column.changeDomain, column.changeNameDerived, settings.changeNameViewMode sowie dictionary.add, dictionary.update und dictionary.remove, die jede Änderung, jede Sortierung und jeden CSV-Import auf den Blättern der Registerkarte Wörterbuch übertragen.
Von den Wechseln der Namensansicht wendet ein Replikat nur diejenigen an, die ein nicht schreibgeschützter Editor vornimmt, während Name View entsperrt ist, und verwirft den Rest (siehe on@change).
Ein Store aus einer früheren Version verwirft alle diese Aktionen, sodass ihm die logischen Namen, die Domänenverknüpfungen, die Angabe, ob jeder Name aus den Wörterbüchern stammt, die Wörter, Begriffe und Domänen sowie die Namensansicht verloren gehen.
Ein Editor einer Version vor 4.2.0 in der Sitzung kann einem Replikat der Version 4.2.0 trotzdem einiges davon wieder nehmen.
Ein Import von Schema SQL, GraphQL, DBML oder AML in diesem Editor, nicht aber ein Import and Add, leert die Wörter, Begriffe und Domänen des Replikats.
Macht er ein Laden, einen Import oder clear() rückgängig, lädt er seine eigene Kopie des Dokuments in das Replikat, ohne logische Namen, Domänenverknüpfungen oder Wörterbücher; siehe Gemischte Versionen.
@dineug/erd-editor/engine.js exportiert wie zuvor createReplicationStore, ReplicationStore und ReplicationChange, und createReplicationStore nimmt denselben Kontext an.

5.1.0 fügt keinen Aktionstyp hinzu und ändert keinen Export von @dineug/erd-editor/engine.js, daher behält ein Replikat ab 4.2.0 weiterhin jede Änderung, die ein Editor der Version 5.1.0 sendet.
Seit 5.1.0 entscheidet das Replikat über zeitgleich vorgenommene Bearbeitungen so wie die Editoren der Version 5.1.0; siehe Gleichzeitige Bearbeitungen.
Es führt eine Version für die Position einer Tabelle, für Position und Größe einer Notiz und einer Tabellengruppe sowie für den Ursprung der Ansicht und die Zoomstufe.
Ein Editor der Version 5.1.0 sendet ein Ziehen, ein Verschieben der Ansicht oder einen Zoom als den Punkt, an dem es endet, über table.moveTo, memo.moveTo, tableGroup.moveTo, settings.scrollTo und settings.changeZoomLevel, und das Replikat übernimmt jede dieser Aktionen sowie jede Aktion memo.resize und tableGroup.resize nur, wenn deren Version nicht unter der liegt, die es hält.
Verschieben daher zwei dieser Editoren zeitgleich dieselbe Tabelle, Notiz oder Tabellengruppe oder ändern deren Größe, speichert das Replikat sie an dem Punkt und in der Größe, die jeder von ihnen zeigt, in welcher Reihenfolge es sie auch hört, und ein Ziehen, Verschieben der Ansicht oder Zoomen, das der Transport doppelt zustellt, bewegt nichts doppelt.
Ist Viewport entsperrt, speichert das Replikat den Ursprung und die Zoomstufe jeweils aus dem Schreibvorgang, dessen Version die größte ist, dort, wo der Editor stand, der ihn vorgenommen hat.
Ein Zoom verschiebt auch den Ursprung, daher können ein Verschieben der Ansicht und ein Zoom, die zwei Editoren zeitgleich vornehmen, als Ursprung des einen Editors mit der Zoomstufe des anderen gespeichert werden.
Vor 5.1.0 addierte das Replikat die Schritte der Verschiebungen und Zooms jedes Editors zu einer einzigen Ansicht.

Die Abstände, die ein Editor vor 5.1.0 für ein Ziehen, ein Verschieben der Ansicht oder einen Zoom sendet (table.move, memo.move, tableGroup.move, settings.streamScrollTo und settings.streamZoomLevel), werden weiterhin zu dem addiert, was das Replikat hält, außerhalb der Versionen.
Eine Farbänderung kommt weiterhin ohne Version an: Das Replikat versieht sie, wie jeder Editor, mit einer eigenen Version und behält die Farbe, die es zuletzt gehört hat, daher können zwei Farbänderungen derselben Tabelle, Notiz oder Tabellengruppe, die zeitgleich vorgenommen werden, anders gespeichert werden, als ein Editor sie zeigt.
Ein Replikat vor 5.1.0 wendet die Punkte und Größen in der Reihenfolge an, in der sie eintreffen, daher kann es eine Tabelle an einer anderen Stelle speichern, als die Editoren der Version 5.1.0 sie zeigen.
Halten Sie jeden Editor der Sitzung und das Replikat auf 5.1.0 oder neuer, damit zeitgleich vorgenommene Bearbeitungen gleich enden, abgesehen von den Ausnahmen, die Gleichzeitige Bearbeitungen nennt.

Seit 5.1.0 sendet ein Editor eine Änderung der Sprache des Codegenerators, einer Schreibweise oder des Begrenzertyps nur, solange die Sperre dieser Einstellung ausgeschaltet ist, mit shared: true in ihrer Payload markiert, und das Replikat wendet jede markierte an, wie die Editoren; siehe Gemeinsame Bearbeitung.
Eine unmarkierte, die ein Editor vor 5.1.0 unabhängig von der Sperre sendet, wendet das Replikat nur an, solange diese Einstellung auf seiner Seite entsperrt ist, und verwirft sie, solange die Einstellung gesperrt ist (siehe on@change).

Seit 4.0.0 wenden beide Methoden außerdem die Aktion editor.mergeLWW an, die die Kollaborationsregister überträgt, mit denen ein Editor antwortet, wenn ein anderer der Sitzung beitritt, sodass das Replikat gleichzeitige Änderungen so abgleicht wie die Editoren.
Sie ändert kein Byte von value und löst kein Ereignis change aus.
Die Aktion settings.changeIgnoreSaveSettings, die ein vor 4.0.0 veröffentlichter Editor möglicherweise noch sendet, wird behalten, ändert aber nichts: Sie löst das Ereignis change aus, wobei changed auf false gesetzt ist.

destroy​

Zerstört die replicationStore-Instanz vollständig.

replicationStore.destroy();

Danach löst der Store kein Ereignis change mehr aus und ignoriert weitere Dispatch-Aufrufe.
Das Dokument bleibt auf seinem letzten Wert stehen, statt einen Fehler auszulösen.
Erstellen Sie einen neuen Store, um neu zu beginnen.