mirror of
				https://github.com/cudr/slate-collaborative.git
				synced 2025-06-13 12:54:04 +00:00 
			
		
		
		
	feat: success show cursor position
This commit is contained in:
		
							parent
							
								
									2a4d64b074
								
							
						
					
					
						commit
						4efc8db60e
					
				| @ -40,10 +40,18 @@ class Connection { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private saveDoc = throttle(pathname => { |   private saveDoc = throttle(pathname => { | ||||||
|  |     try { | ||||||
|       if (this.options.onDocumentSave) { |       if (this.options.onDocumentSave) { | ||||||
|         const doc = this.docSet.getDoc(pathname) |         const doc = this.docSet.getDoc(pathname) | ||||||
| 
 | 
 | ||||||
|       this.options.onDocumentSave(pathname, toJS(doc)) |         const data = toJS(doc) | ||||||
|  | 
 | ||||||
|  |         delete data.cursors | ||||||
|  | 
 | ||||||
|  |         this.options.onDocumentSave(pathname, data) | ||||||
|  |       } | ||||||
|  |     } catch (e) { | ||||||
|  |       console.log(e) | ||||||
|     } |     } | ||||||
|   }, (this.options && this.options.saveTreshold) || 2000) |   }, (this.options && this.options.saveTreshold) || 2000) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,17 +1,17 @@ | |||||||
| import { Operation, SyncDoc } from '../model' | import { Operation, SyncDoc } from '../model' | ||||||
| 
 | 
 | ||||||
| export const addAnnotation = (doc: SyncDoc, op: Operation): SyncDoc => { | export const addAnnotation = (doc: SyncDoc, op: Operation): SyncDoc => { | ||||||
|   console.log('addAnnotation!!!', op) |   console.log('addAnnotation!!!', op.toJS()) | ||||||
|   return doc |   return doc | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const removeAnnotation = (doc: SyncDoc, op: Operation): SyncDoc => { | export const removeAnnotation = (doc: SyncDoc, op: Operation): SyncDoc => { | ||||||
|   console.log('removeAnnotation!!!', op) |   console.log('removeAnnotation!!!', op.toJS()) | ||||||
|   return doc |   return doc | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const setAnnotation = (doc: SyncDoc, op: Operation): SyncDoc => { | export const setAnnotation = (doc: SyncDoc, op: Operation): SyncDoc => { | ||||||
|   console.log('setAnnotation!!!', op) |   console.log('setAnnotation!!!', op.toJS()) | ||||||
|   return doc |   return doc | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -3,43 +3,19 @@ import { Operation, Operations, SyncDoc } from '../model' | |||||||
| import node from './node' | import node from './node' | ||||||
| import mark from './mark' | import mark from './mark' | ||||||
| import text from './text' | import text from './text' | ||||||
|  | import selection from './selection' | ||||||
| import annotation from './annotation' | import annotation from './annotation' | ||||||
| 
 | 
 | ||||||
| const setSelection = (doc, op, { id, selection }) => { | const setSelection = doc => doc | ||||||
|   console.log('selection', selection.toJSON()) | const setValue = doc => doc | ||||||
|   if (!doc.cursors) { |  | ||||||
|     doc.cursors = {} |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // console.log('setSelection', op.toJSON(), id)
 |  | ||||||
|   const operation = op.toJSON() |  | ||||||
| 
 |  | ||||||
|   if (!doc.cursors[id]) { |  | ||||||
|     doc.cursors[id] = { |  | ||||||
|       key: id, |  | ||||||
|       type: 'collaborative_selection' |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   const cursor = doc.cursors[id] |  | ||||||
|   const { focus, anchor } = operation.newProperties |  | ||||||
| 
 |  | ||||||
|   if (focus) cursor.focus = focus |  | ||||||
|   if (anchor) cursor.anchor = anchor |  | ||||||
| 
 |  | ||||||
|   return doc |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const setValue = (doc, op) => doc |  | ||||||
| 
 | 
 | ||||||
| const opType: any = { | const opType: any = { | ||||||
|   ...text, |   ...text, | ||||||
|   ...annotation, |   ...annotation, | ||||||
|   ...node, |   ...node, | ||||||
|   ...mark, |   ...mark, | ||||||
| 
 |   ...selection | ||||||
|   set_selection: setSelection, |   // set_value: setValue
 | ||||||
|   set_value: setValue |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const applyOperation = meta => ( | export const applyOperation = meta => ( | ||||||
| @ -49,7 +25,7 @@ export const applyOperation = meta => ( | |||||||
|   try { |   try { | ||||||
|     const applyOp = opType[op.type] |     const applyOp = opType[op.type] | ||||||
| 
 | 
 | ||||||
|     if (!applyOp) throw new TypeError('Invalid operation type!') |     if (!applyOp) throw new TypeError('Unsupported operation type!') | ||||||
| 
 | 
 | ||||||
|     return applyOp(doc, op, meta) |     return applyOp(doc, op, meta) | ||||||
|   } catch (e) { |   } catch (e) { | ||||||
|  | |||||||
							
								
								
									
										35
									
								
								packages/bridge/src/apply/selection.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								packages/bridge/src/apply/selection.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | import { toJS } from '../utils' | ||||||
|  | 
 | ||||||
|  | const setSelection = (doc, op, { id, selection, annotationType }) => { | ||||||
|  |   if (!doc.cursors) { | ||||||
|  |     doc.cursors = {} | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const operation = op.toJS() | ||||||
|  | 
 | ||||||
|  |   if (!doc.cursors[id]) { | ||||||
|  |     doc.cursors[id] = { | ||||||
|  |       key: id, | ||||||
|  |       type: annotationType, | ||||||
|  |       data: {} | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const cursor = doc.cursors[id] | ||||||
|  |   const { focus, anchor } = operation.newProperties | ||||||
|  | 
 | ||||||
|  |   if (focus) cursor.focus = focus | ||||||
|  |   if (anchor) cursor.anchor = anchor | ||||||
|  | 
 | ||||||
|  |   const cursorPath = (anchor && anchor.path) || (focus && focus.path) | ||||||
|  | 
 | ||||||
|  |   if (cursorPath) cursor.data.cursorPath = toJS(cursorPath) | ||||||
|  | 
 | ||||||
|  |   cursor.data.isBackward = selection.isBackward | ||||||
|  | 
 | ||||||
|  |   return doc | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export default { | ||||||
|  |   set_selection: setSelection | ||||||
|  | } | ||||||
| @ -87,29 +87,23 @@ class Connection { | |||||||
| 
 | 
 | ||||||
|   setCursors = cursors => { |   setCursors = cursors => { | ||||||
|     if (!cursors) return |     if (!cursors) return | ||||||
|     // console.log('setCursors', cursors)
 | 
 | ||||||
|     const { |     const { | ||||||
|       value: { annotations } |       value: { annotations } | ||||||
|     } = this.editor |     } = this.editor | ||||||
| 
 | 
 | ||||||
|     const keyMap = {} |     const keyMap = {} | ||||||
| 
 | 
 | ||||||
|  |     console.log('cursors', cursors) | ||||||
|  | 
 | ||||||
|     this.editor.withoutSaving(() => { |     this.editor.withoutSaving(() => { | ||||||
|       annotations.forEach(anno => { |       annotations.forEach(anno => { | ||||||
|         // if (cursors[anno.key]) {
 |  | ||||||
|         //   console.log('set cursor', anno, )
 |  | ||||||
|         //   this.editor.setAnnotation(anno, cursors[anno.key])
 |  | ||||||
|         //   keyMap[anno.key] = true
 |  | ||||||
|         // } else {
 |  | ||||||
|         //   this.editor.removeAnnotation(anno)
 |  | ||||||
|         // }
 |  | ||||||
| 
 |  | ||||||
|         this.editor.removeAnnotation(anno) |         this.editor.removeAnnotation(anno) | ||||||
|       }) |       }) | ||||||
| 
 | 
 | ||||||
|       Object.keys(cursors).forEach(key => { |       Object.keys(cursors).forEach(key => { | ||||||
|         if (key !== this.socket.id && !keyMap[key]) { |         if (key !== this.socket.id && !keyMap[key]) { | ||||||
|           this.editor.addAnnotation(cursors[key]) |           this.editor.addAnnotation(toJS(cursors[key])) | ||||||
|         } |         } | ||||||
|       }) |       }) | ||||||
|     }) |     }) | ||||||
| @ -121,11 +115,42 @@ class Connection { | |||||||
| 
 | 
 | ||||||
|     if (!doc) return |     if (!doc) return | ||||||
| 
 | 
 | ||||||
|     const changed = Automerge.change(doc, message, (d: any) => |     const selectionOps = operations.filter(op => op.type === 'set_selection') | ||||||
|       applySlateOps(d, operations, { | 
 | ||||||
|  |     console.log('hasSelectionOps', selectionOps.size) | ||||||
|  | 
 | ||||||
|  |     const { value } = this.editor | ||||||
|  | 
 | ||||||
|  |     const { selection } = value | ||||||
|  | 
 | ||||||
|  |     const meta = { | ||||||
|       id: this.socket.id, |       id: this.socket.id, | ||||||
|         selection: this.editor.value.selection |       selection, | ||||||
|       }) |       annotationType: 'collaborative_selection' | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const cursor = doc.cursors[meta.id] | ||||||
|  |     const cursorOffset = cursor && cursor.anchor && cursor.anchor.offset | ||||||
|  | 
 | ||||||
|  |     if (!selectionOps.size && selection.start.offset !== cursorOffset) { | ||||||
|  |       const opData = { | ||||||
|  |         type: 'set_selection', | ||||||
|  |         properties: {}, | ||||||
|  |         newProperties: { | ||||||
|  |           anchor: selection.start, | ||||||
|  |           focus: selection.end | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       const op = Operation.fromJSON(opData) | ||||||
|  | 
 | ||||||
|  |       operations = operations.push(op) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     console.log('operations', operations.toJSON()) | ||||||
|  | 
 | ||||||
|  |     const changed = Automerge.change(doc, message, (d: any) => | ||||||
|  |       applySlateOps(d, operations, meta) | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     this.docSet.setDoc(this.docId, changed) |     this.docSet.setDoc(this.docId, changed) | ||||||
|  | |||||||
| @ -15,23 +15,30 @@ const cursorStyleBase = { | |||||||
| } as any | } as any | ||||||
| 
 | 
 | ||||||
| const renderAnnotation = (props, editor, next) => { | const renderAnnotation = (props, editor, next) => { | ||||||
|   const { children, annotation, attributes } = props |   const { children, annotation, attributes, node } = props | ||||||
| 
 | 
 | ||||||
|   const isLeft = annotation.focus.offset >= annotation.anchor.offset |   const isBackward = annotation.data.get('isBackward') | ||||||
|  |   const cursorPath = annotation.data.get('cursorPath') | ||||||
| 
 | 
 | ||||||
|   console.log('isLeft', isLeft) |   const cursorStyles = { ...cursorStyleBase, left: isBackward ? '0%' : '100%' } | ||||||
| 
 | 
 | ||||||
|   const cursorStyles = { ...cursorStyleBase, left: isLeft ? '0%' : '100%' } |   const { document } = editor.value | ||||||
| 
 | 
 | ||||||
|   console.log('renderAnnotation', annotation.toJSON()) |   const targetNode = document.getNode(cursorPath) | ||||||
|  | 
 | ||||||
|  |   const isTarget = targetNode && targetNode.key === node.key | ||||||
|  | 
 | ||||||
|  |   const showCursor = isTarget | ||||||
| 
 | 
 | ||||||
|   switch (annotation.type) { |   switch (annotation.type) { | ||||||
|     case 'collaborative_selection': |     case 'collaborative_selection': | ||||||
|       return ( |       return ( | ||||||
|         <span {...attributes} style={wrapStyles}> |         <span {...attributes} style={wrapStyles}> | ||||||
|  |           {showCursor ? ( | ||||||
|             <span contentEditable={false} style={cursorStyles}> |             <span contentEditable={false} style={cursorStyles}> | ||||||
|               {annotation.key} |               {annotation.key} | ||||||
|             </span> |             </span> | ||||||
|  |           ) : null} | ||||||
|           {children} |           {children} | ||||||
|         </span> |         </span> | ||||||
|       ) |       ) | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user