@cocreate/crdt 1.3.14 → 1.3.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,321 +0,0 @@
1
- import * as Y from 'yjs'
2
- import { WebsocketProvider } from 'y-websocket'
3
- import { fetchUpdates, storeState, IndexeddbPersistence } from 'y-indexeddb'
4
- import crud from '@cocreate/crud-client';
5
- import CoCreateCursors from '@cocreate/cursors'
6
- import { logger } from '@cocreate/utils'
7
-
8
- let console = logger('off');
9
-
10
- class CoCreateCrdt {
11
- constructor(org, ydoc) {
12
- this.doc = ydoc;
13
- this.orgName = org;
14
- this.docs = {};
15
- this._awarenessListener = null;
16
- this.character = '_';
17
- this.listenAwereness = function(){}
18
- }
19
-
20
- createDoc(id) {
21
- if (!id || id == "") {
22
- return null;
23
- }
24
-
25
- let newInfo = this.parseType(id)
26
-
27
- const newId = newInfo.id;
28
-
29
- if (this.docs[newId]) {
30
- if (!this.docs[newId].types.some((type) => type === id)) {
31
- // register event
32
- this.docs[newId].types.push(id);
33
- this.registerUpdateEvent(this.docs[newId], id)
34
-
35
- }
36
- return false;
37
- }
38
-
39
- const yDoc = this.doc
40
-
41
- const url_socket = this.__getSocketUrl();
42
-
43
- var socketProvider = new WebsocketProvider(url_socket, newId, yDoc);
44
-
45
- let indexeddbProvider = null;
46
- if (newInfo.document_id != "null") {
47
- indexeddbProvider = new IndexeddbPersistence(newId, this.doc)
48
- indexeddbProvider.whenSynced.then(() => {
49
- console.log('loaded data from indexed db')
50
- })
51
- }
52
-
53
- let awareness = socketProvider.awareness;
54
-
55
- this._cursors = new Map();
56
-
57
- this._awarenessListener = event => {
58
- const f = clientId => {
59
- // if (clientId !== this.doc.clientID) {
60
- this.updateRemoteSelection(yDoc, id, yDoc.getText(id), this._cursors, clientId, awareness)
61
- // }
62
- }
63
- event.added.forEach(f)
64
- event.removed.forEach(f)
65
- event.updated.forEach(f)
66
- }
67
-
68
- awareness.on('change', this._awarenessListener);
69
-
70
- this.docs[newId] = {
71
- id: newId,
72
- doc: yDoc,
73
- socket: socketProvider,
74
- awareness: awareness,
75
- types: [id],
76
- indexeddb: indexeddbProvider
77
- }
78
- this.registerUpdateEvent(this.docs[newId], id)
79
-
80
- return true;
81
- }
82
-
83
- registerUpdateEvent(docObject, id) {
84
- const yDoc = docObject.doc;
85
- const shardType = yDoc.getText(id)
86
- let _this = this;
87
-
88
- shardType.observe((event) => {
89
- _this.__setTypeObserveEvent(event, id);
90
- })
91
- }
92
-
93
- __getSocketUrl() {
94
- console.log("get_socket url")
95
- let w_location = window.location || window.parent.location;
96
- let w_protocol = w_location.protocol;
97
- let w_host = w_location.host;
98
- if (w_location.protocol === "about:") {
99
- w_protocol = w_location.protocol;
100
- w_host = document.referrer;
101
- }
102
- let protocol = w_protocol === 'http:' ? 'ws' : 'wss';
103
-
104
- let url_socket = `${protocol}://${w_host}:8080/`;
105
- if (window.config && window.config.host) {
106
- if (window.config.host.includes("://")) {
107
- url_socket = `${window.config.host}/`;
108
- } else {
109
- url_socket = `${protocol}://${window.config.host}/`;
110
- }
111
- }
112
-
113
- console.log(url_socket)
114
- url_socket += "crdt/";
115
-
116
- return url_socket;
117
-
118
- }
119
-
120
- __setTypeObserveEvent(event, id) {
121
- console.log('set crdt event .', event.delta)
122
- if (!id) return;
123
-
124
- const eventDelta = event.delta;
125
-
126
- if (eventDelta.length == 0) {
127
- return;
128
- }
129
- const info = JSON.parse(atob(id));
130
- let is_save_value = false
131
-
132
- // let is_crud = eventDelta.attributes && eventDelta.attributes.crud === false ? false : true;
133
-
134
- const wholestring = event.target.toString()
135
- const store_event = new CustomEvent('store-content-db', {
136
- detail: wholestring
137
- })
138
-
139
- const update_event = new CustomEvent('cocreate-crdt-update', {
140
- detail: {eventDelta,...info},
141
- })
142
-
143
- window.dispatchEvent(update_event);
144
- }
145
-
146
- //send Position Custom
147
- sendPosition(collection, document_id, name, from, to) {
148
- let id = this.generateID(config.organization_Id, collection, document_id, name);
149
- const info = this.parseType(id)
150
- const type = this.getType(id);
151
- console.log("Type ",type)
152
- if (!type) {
153
- return;
154
- }
155
- if (from != null && to != null){
156
- var anchor = Y.createRelativePositionFromTypeIndex(type, from)
157
- var head = Y.createRelativePositionFromTypeIndex(type, to)
158
-
159
- console.log("Sending Cursor ",{
160
- anchor,
161
- head
162
- },{'to':to,'from':from,'info.id':info.id})
163
-
164
- this.docs[info.id].socket.awareness.setLocalStateField('cursor', {
165
- anchor,
166
- head
167
- })
168
- }
169
- else {
170
- this.docs[info.id].socket.awareness.setLocalStateField('cursor', null);
171
- }
172
-
173
- }
174
-
175
- updateRemoteSelection (y, cm, type, cursors, clientId, awareness) {
176
- console.log("CHANGE ---- DOCID ",this.doc.clientID,' OTHER CLIENTEID ',clientId)
177
- // ToDo: blocks character inserts
178
- if(clientId !== this.doc.clientID){
179
-
180
- const m = cursors.get(clientId)
181
- if (m !== undefined) {
182
- m.caret.clear()
183
- if (m.sel !== null) {
184
- m.sel.clear()
185
- }
186
- cursors.delete(clientId)
187
- }
188
-
189
- // redraw caret and selection for clientId
190
- const aw = awareness.getStates().get(clientId);
191
-
192
- if (aw === undefined) {
193
- this.removeCursor(clientId)
194
- return
195
- }
196
- const user = aw.user || {}
197
- if (user.color == null) {
198
- user.color = '#ffa500'
199
- }
200
- if (user.name == null) {
201
- user.name = `User: ${clientId}`
202
- }
203
- const cursor = aw.cursor
204
- if (cursor == null || cursor.anchor == null || cursor.head == null) {
205
- this.removeCursor(clientId)
206
- return
207
- }
208
-
209
- const anchor = Y.createAbsolutePositionFromRelativePosition(Y.createRelativePositionFromJSON(cursor.anchor), y)
210
- const head = Y.createAbsolutePositionFromRelativePosition(Y.createRelativePositionFromJSON(cursor.head), y)
211
- // const anchor = cursor.anchor
212
- // const head = cursor.head
213
-
214
- if (anchor !== null && head !== null ) {
215
-
216
- let from = anchor.index
217
- let to = head.index
218
-
219
- let info = this.parseType(cursor.anchor['tname']);
220
-
221
- let id_mirror = info.document_id + info.name+'--mirror-div';
222
- let json = {};
223
-
224
- let selector = '[collection="'+info.collection+'"][document_id="'+info.document_id+'"][name="'+info.name+'"]'
225
- selector += ':not(.codemirror):not(.quill):not(.monaco)';
226
-
227
- let elements = document.querySelectorAll(selector);
228
-
229
- let that = this; // does it matter the position this is placed
230
- elements.forEach(function (element, index, array) {
231
- json = {
232
- element:element,
233
- selector:selector,
234
- startPosition:from,
235
- endPositon:to,
236
- clientId : clientId,
237
- user:{
238
- 'color':user.color,
239
- 'name':user.name
240
- },
241
- }
242
-
243
- CoCreateCursors.draw_cursor(json);
244
- //sent custom position
245
- that.listenAwereness.apply(this,[json]);
246
- });
247
- }
248
- }
249
- }
250
-
251
- listen(json){
252
- this.listenAwereness.apply(this,[json])
253
- }
254
-
255
- removeCursor(clientId){
256
- let elements = document.querySelectorAll('[id*="socket_'+clientId+'"]');
257
- elements.forEach(function (element, index, array) {
258
- element.parentNode.removeChild(element);
259
- })
260
-
261
- let sel_elements = document.querySelectorAll('[id*="sel-'+clientId+'"]');
262
- sel_elements.forEach(function (sel_element, index, array) {
263
- sel_element.parentNode.removeChild(sel_element);
264
- })
265
- }
266
-
267
- deleteDoc(id) {
268
- const info = this.parseType(id)
269
- if (this.docs[info.id]) {
270
- delete this.docs[info.id];
271
- }
272
- }
273
-
274
- destroyObserver(id) {
275
- const info = this.parseType(id)
276
- this.docs[info.id].doc.getText(id).unobserve((event) => {});
277
-
278
- this.docs[info.id].socket.awareness.off('change', this._awarenessListener);
279
- }
280
-
281
- getType(id){
282
- const info = this.parseType(id)
283
- if (!this.docs[info.id]) {
284
- return null;
285
- }
286
- return this.docs[info.id].doc.getText(id);
287
- }
288
-
289
- parseType(id) {
290
- let data = JSON.parse(atob(id));
291
-
292
- let newId = {org: data.org, collection: data.collection, document_id: data.document_id}
293
- return {
294
- id: btoa(JSON.stringify(newId)),
295
- collection: data.collection,
296
- document_id: data.document_id,
297
- name: data.name
298
- }
299
- }
300
-
301
- generateDoc(collection, document_id) {
302
- let docId = {collection: collection, document_id: document_id}
303
- return {
304
- docId: btoa(JSON.stringify(id)),
305
- collection: collection,
306
- document_id: document_id
307
- }
308
- }
309
-
310
- generateName(name) {
311
- const nameId = {name}
312
- return btoa(JSON.stringify(nameId));
313
- }
314
-
315
- generateID(org, collection, document_id, name) {
316
- const info = {org, collection, document_id, name}
317
- return btoa(JSON.stringify(info));
318
- }
319
- }
320
-
321
- export default CoCreateCrdt;
@@ -1,225 +0,0 @@
1
- import CoCreateCrdt from "./core.js"
2
- import * as Y from 'yjs'
3
- import crud from '@cocreate/crud-client';
4
-
5
-
6
- class CoCreateCRDTClass extends CoCreateCrdt
7
- {
8
- constructor(org, doc) {
9
- super(org, doc)
10
- }
11
-
12
- /*
13
- crdt.init({
14
- collection: "module",
15
- document_id: "",
16
- name: "",
17
- element: dom_object,
18
- metadata: "xxxx"
19
- })
20
- */
21
- init(info) {
22
- try {
23
- this.__validateKeysJson(info, ['collection', 'document_id', 'name']);
24
-
25
- const id = this.__getYDocId(info['collection'], info['document_id'], info['name'])
26
-
27
- if (!id) return;
28
- const status = this.createDoc(id, info.element)
29
- // console.log("InitCrdt")
30
- } catch(e) {
31
- console.log('Invalid param', e);
32
- }
33
- }
34
-
35
- /*. init data function
36
- crdt.replaceText({
37
- collection: "module",
38
- document_id: "",
39
- name: "",
40
- value: "",
41
- updateCrud: true | false,
42
- element: dom_object,
43
- metadata: "xxxx"
44
- })
45
- */
46
-
47
- replaceText(info){
48
- if (!info) return;
49
-
50
- const id = this.__getYDocId(info.collection, info.document_id, info.name)
51
- if (!id) return;
52
-
53
- if (info.updateCrud != false) info.updateCrud = true;
54
-
55
- if (this.getType(id) ) {
56
- let oldData = this.getType(id).toString();
57
- let textValue = info.value.toString();
58
- if (oldData && oldData.length > 0) {
59
- this.deleteData(id, 0, Math.max(oldData.length, textValue.length));
60
- }
61
- this.insertData(id, 0, textValue);
62
- }
63
- if (info.crud != false) {
64
- crud.updateDocument({
65
- collection: info.collection,
66
- document_id: info.document_id,
67
- data: {[info.name]: info.value},
68
- element: info.element,
69
- metadata:info.metadata,
70
- namespace: info.namespace,
71
- room: info.room,
72
- broadcast: info.broadcast,
73
- upsert: info.upsert,
74
- broadcast_sender: info.broadcast_sender
75
- })
76
- }
77
- }
78
-
79
- /*
80
- crdt.insertText({
81
- collection: 'module_activities',
82
- document_id: '5e4802ce3ed96d38e71fc7e5',
83
- name: 'name',
84
- value: 'T',
85
- position: '8',
86
- attributes: {bold: true}
87
- })
88
- */
89
- insertText(info) {
90
- try {
91
- this.__validateKeysJson(info,['collection','document_id','name','value','position']);
92
- let id = this.__getYDocId(info['collection'], info['document_id'], info['name'])
93
- if (id) {
94
-
95
- this.insertData(id, info['position'], info['value'].toString(), info['attributes']);
96
-
97
- let wholestring = this.getType(id).toString();
98
-
99
- console.log(wholestring)
100
-
101
- if (info.crud != false) {
102
- crud.updateDocument({
103
- collection: info.collection,
104
- document_id: info.document_id,
105
- data: {
106
- [info.name]: wholestring
107
- },
108
- metadata: 'yjs-change'
109
- })
110
- }
111
- }
112
- }
113
- catch (e) {
114
- console.error(e);
115
- }
116
- }
117
-
118
-
119
- /*
120
- crdt.deleteText({
121
- collection: 'module_activities',
122
- document_id: '5e4802ce3ed96d38e71fc7e5',
123
- name: 'name',
124
- position: '8',
125
- length: 2,
126
- })
127
- */
128
- deleteText(info) {
129
- try{
130
- this.__validateKeysJson(info,['collection','document_id','name', 'position','length']);
131
- let id = this.__getYDocId(info['collection'], info['document_id'], info['name'])
132
- if (id) {
133
- this.deleteData(id, info['position'], info['length']);
134
-
135
- let wholestring = this.getType(id).toString();
136
-
137
- console.log(wholestring)
138
-
139
- if (info.crud != false) {
140
- crud.updateDocument({
141
- collection: info.collection,
142
- document_id: info.document_id,
143
- data: {
144
- [info.name]: wholestring
145
- },
146
- metadata: 'yjs-change'
147
- })
148
- }
149
- }
150
- }
151
- catch (e) {
152
- console.error(e);
153
- }
154
- }
155
-
156
-
157
- /*
158
- crdt.getText({
159
- collection: 'module_activities',
160
- document_id: '5e4802ce3ed96d38e71fc7e5',
161
- name: 'name'
162
- })
163
- */
164
- getText(info) {
165
- try{
166
- this.__validateKeysJson(info,['collection','document_id','name']);
167
- let id = this.__getYDocId(info['collection'], info['document_id'], info['name'])
168
- if (id) {
169
- return this.getWholeString(id);
170
- } else {
171
- return "";
172
- }
173
- }
174
- catch (e) {
175
- console.error(e);
176
- return "";
177
- }
178
- }
179
-
180
-
181
- /*
182
- crdt.getPosition(function(data))
183
- crdt.getPosition(function(data){console.log(" EScuchando ahora ",data)})
184
- */
185
- getPosition(callback){
186
- if(typeof miFuncion === 'function')
187
- this.changeListenAwereness(callback);
188
- else
189
- console.error('Callback should be a function')
190
- }
191
-
192
- __getYDocId(collection, document_id, name) {
193
- if (!crud.checkAttrValue(collection) ||
194
- !crud.checkAttrValue(document_id) ||
195
- !crud.checkAttrValue(name))
196
- {
197
- return null;
198
- }
199
- return this.generateID(config.organization_Id, collection, document_id, name);
200
- }
201
-
202
- __validateKeysJson(json,rules){
203
- let keys_json = Object.keys(json);
204
- keys_json.forEach(key=>{
205
- const index = rules.indexOf(key);
206
- if(index != -1)
207
- rules.splice(index, 1);
208
- });
209
- if( rules.length )
210
- throw "Requires the following "+ rules.toString();
211
- }
212
- }
213
-
214
- let CoCreateCrdt = null;
215
- if (!window.CoCreateCrdt) {
216
- const crdtDoc = new Y.Doc();
217
- CoCreateCrdt = new CoCreateCRDTClass(config.organization_Id, crdtDoc);
218
- window.Y = Y;
219
- window.CoCreateCrdt = CoCreateCrdt;
220
- } else {
221
- CoCreateCrdt = window.CoCreateCrdt;
222
- }
223
-
224
- export default CoCreateCrdt;
225
-