@@ -151,6 +151,7 @@ function finishUpdateNote(note, _note, callback) {
151151 var values = {
152152 title : title ,
153153 content : body ,
154+ authorship : LZString . compressToBase64 ( JSON . stringify ( note . authorship ) ) ,
154155 lastchangeuserId : note . lastchangeuser ,
155156 lastchangeAt : Date . now ( )
156157 } ;
@@ -404,6 +405,13 @@ function startConnection(socket) {
404405 } , {
405406 model : models . User ,
406407 as : "lastchangeuser"
408+ } , {
409+ model : models . Author ,
410+ as : "authors" ,
411+ include : [ {
412+ model : models . User ,
413+ as : "user"
414+ } ]
407415 } ] ;
408416
409417 models . Note . findOne ( {
@@ -424,7 +432,19 @@ function startConnection(socket) {
424432 var body = LZString . decompressFromBase64 ( note . content ) ;
425433 var createtime = note . createdAt ;
426434 var updatetime = note . lastchangeAt ;
427- var server = new ot . EditorSocketIOServer ( body , [ ] , noteId , ifMayEdit ) ;
435+ var server = new ot . EditorSocketIOServer ( body , [ ] , noteId , ifMayEdit , operationCallback ) ;
436+
437+ var authors = { } ;
438+ for ( var i = 0 ; i < note . authors . length ; i ++ ) {
439+ var author = note . authors [ i ] ;
440+ var profile = models . User . parseProfile ( author . user . profile ) ;
441+ authors [ author . userId ] = {
442+ userid : author . userId ,
443+ color : author . color ,
444+ photo : profile . photo ,
445+ name : profile . name
446+ } ;
447+ }
428448
429449 notes [ noteId ] = {
430450 id : noteId ,
@@ -437,7 +457,9 @@ function startConnection(socket) {
437457 users : { } ,
438458 createtime : moment ( createtime ) . valueOf ( ) ,
439459 updatetime : moment ( updatetime ) . valueOf ( ) ,
440- server : server
460+ server : server ,
461+ authors : authors ,
462+ authorship : note . authorship ? JSON . parse ( LZString . decompressFromBase64 ( note . authorship ) ) : [ ]
441463 } ;
442464
443465 return finishConnection ( socket , notes [ noteId ] , users [ socket . id ] ) ;
@@ -581,6 +603,136 @@ function ifMayEdit(socket, callback) {
581603 return callback ( mayEdit ) ;
582604}
583605
606+ function operationCallback ( socket , operation ) {
607+ var noteId = socket . noteId ;
608+ if ( ! noteId || ! notes [ noteId ] ) return ;
609+ var note = notes [ noteId ] ;
610+ var userId = null ;
611+ // save authors
612+ if ( socket . request . user && socket . request . user . logged_in ) {
613+ var socketId = socket . id ;
614+ var user = users [ socketId ] ;
615+ userId = socket . request . user . id ;
616+ if ( ! note . authors [ userId ] ) {
617+ models . Author . create ( {
618+ noteId : noteId ,
619+ userId : userId ,
620+ color : users [ socketId ] . color
621+ } ) . then ( function ( author ) {
622+ note . authors [ author . userId ] = {
623+ userid : author . userId ,
624+ color : author . color ,
625+ photo : user . photo ,
626+ name : user . name
627+ } ;
628+ } ) . catch ( function ( err ) {
629+ return logger . error ( 'operation callback failed: ' + err ) ;
630+ } ) ;
631+ }
632+ }
633+ // save authorship
634+ var index = 0 ;
635+ var authorships = note . authorship ;
636+ var timestamp = Date . now ( ) ;
637+ for ( var i = 0 ; i < operation . length ; i ++ ) {
638+ var op = operation [ i ] ;
639+ if ( ot . TextOperation . isRetain ( op ) ) {
640+ index += op ;
641+ } else if ( ot . TextOperation . isInsert ( op ) ) {
642+ var opStart = index ;
643+ var opEnd = index + op . length ;
644+ var inserted = false ;
645+ // authorship format: [userId, startPos, endPos, createdAt, updatedAt]
646+ if ( authorships . length <= 0 ) authorships . push ( [ userId , opStart , opEnd , timestamp , timestamp ] ) ;
647+ else {
648+ for ( var j = 0 ; j < authorships . length ; j ++ ) {
649+ var authorship = authorships [ j ] ;
650+ if ( ! inserted ) {
651+ var nextAuthorship = authorships [ j + 1 ] || - 1 ;
652+ if ( nextAuthorship != - 1 && nextAuthorship [ 1 ] >= opEnd || j >= authorships . length - 1 ) {
653+ if ( authorship [ 1 ] < opStart && authorship [ 2 ] > opStart ) {
654+ // divide
655+ var postLength = authorship [ 2 ] - opStart ;
656+ authorship [ 2 ] = opStart ;
657+ authorship [ 4 ] = timestamp ;
658+ authorships . splice ( j + 1 , 0 , [ userId , opStart , opEnd , timestamp , timestamp ] ) ;
659+ authorships . splice ( j + 2 , 0 , [ authorship [ 0 ] , opEnd , opEnd + postLength , authorship [ 3 ] , timestamp ] ) ;
660+ j += 2 ;
661+ inserted = true ;
662+ } else if ( authorship [ 1 ] >= opStart ) {
663+ authorships . splice ( j , 0 , [ userId , opStart , opEnd , timestamp , timestamp ] ) ;
664+ j += 1 ;
665+ inserted = true ;
666+ } else if ( authorship [ 2 ] <= opStart ) {
667+ authorships . splice ( j + 1 , 0 , [ userId , opStart , opEnd , timestamp , timestamp ] ) ;
668+ j += 1 ;
669+ inserted = true ;
670+ }
671+ }
672+ }
673+ if ( authorship [ 1 ] >= opStart ) {
674+ authorship [ 1 ] += op . length ;
675+ authorship [ 2 ] += op . length ;
676+ }
677+ }
678+ }
679+ index += op . length ;
680+ } else if ( ot . TextOperation . isDelete ( op ) ) {
681+ var opStart = index ;
682+ var opEnd = index - op ;
683+ if ( operation . length == 1 ) {
684+ authorships = [ ] ;
685+ } else if ( authorships . length > 0 ) {
686+ for ( var j = 0 ; j < authorships . length ; j ++ ) {
687+ var authorship = authorships [ j ] ;
688+ if ( authorship [ 1 ] >= opStart && authorship [ 1 ] <= opEnd && authorship [ 2 ] >= opStart && authorship [ 2 ] <= opEnd ) {
689+ authorships . splice ( j , 1 ) ;
690+ j -= 1 ;
691+ } else if ( authorship [ 1 ] < opStart && authorship [ 1 ] < opEnd && authorship [ 2 ] > opStart && authorship [ 2 ] > opEnd ) {
692+ authorship [ 2 ] += op ;
693+ authorship [ 4 ] = timestamp ;
694+ } else if ( authorship [ 2 ] >= opStart && authorship [ 2 ] <= opEnd ) {
695+ authorship [ 2 ] = opStart ;
696+ authorship [ 4 ] = timestamp ;
697+ } else if ( authorship [ 1 ] >= opStart && authorship [ 1 ] <= opEnd ) {
698+ authorship [ 1 ] = opEnd ;
699+ authorship [ 4 ] = timestamp ;
700+ }
701+ if ( authorship [ 1 ] >= opEnd ) {
702+ authorship [ 1 ] += op ;
703+ authorship [ 2 ] += op ;
704+ }
705+ }
706+ }
707+ index += op ;
708+ }
709+ }
710+ // merge
711+ for ( var j = 0 ; j < authorships . length ; j ++ ) {
712+ var authorship = authorships [ j ] ;
713+ for ( var k = j + 1 ; k < authorships . length ; k ++ ) {
714+ var nextAuthorship = authorships [ k ] ;
715+ if ( nextAuthorship && authorship [ 0 ] === nextAuthorship [ 0 ] && authorship [ 2 ] === nextAuthorship [ 1 ] ) {
716+ var minTimestamp = Math . min ( authorship [ 3 ] , nextAuthorship [ 3 ] ) ;
717+ var maxTimestamp = Math . max ( authorship [ 3 ] , nextAuthorship [ 3 ] ) ;
718+ authorships . splice ( j , 1 , [ authorship [ 0 ] , authorship [ 1 ] , nextAuthorship [ 2 ] , minTimestamp , maxTimestamp ] ) ;
719+ authorships . splice ( k , 1 ) ;
720+ j -= 1 ;
721+ break ;
722+ }
723+ }
724+ }
725+ // clear
726+ for ( var j = 0 ; j < authorships . length ; j ++ ) {
727+ var authorship = authorships [ j ] ;
728+ if ( ! authorship [ 0 ] ) {
729+ authorships . splice ( j , 1 ) ;
730+ j -= 1 ;
731+ }
732+ }
733+ note . authorship = authorships ;
734+ }
735+
584736function connection ( socket ) {
585737 if ( config . maintenance ) return ;
586738 parseNoteIdFromSocket ( socket , function ( err , noteId ) {
0 commit comments