public/js/share-codemirror-json.js
function applyToShareJS(cm, change) {

      // CodeMirror changes give a text replacement.

      var startPos = 0;  // Get character position from # of chars in each line.
      var i = 0;         // i goes through all lines.

      while (i < change.from.line) {
        startPos += cm.lineInfo(i).text.length + 1;   // Add 1 for '\n'
        i++;
      }

      startPos += change.from.ch;

      // sharejs json path to the location of the change
      var textPath = ['text', startPos];

      // array of operations that will be submitted
      var ops = [];

      // object to keep track of lines that were deleted
      var deletedLines = {};

      // get an updated document
      var doc = ctx.get();

      if (change.to.line == change.from.line && change.to.ch == change.from.ch) {
        // nothing was removed.
      } else {

        // change in lines (deleted lines)
        if(change.to.line !== change.from.line){
          for (i = change.to.line; i > change.from.line; i--) {

            if(doc.lines[i] !== undefined){
              ops.push({p:['lines', i], ld: doc.lines[i]});
              deletedLines[i] = true;
            }
          }
        }

        // change in text (deletion)
        ops.push({p:textPath, sd: change.removed.join('\n')});
      }

      if (change.text) {

        // change in text (insertion)
        ops.push({p:textPath, si: change.text.join('\n')});

        // new lines and pasting
        if ((change.from.line === change.to.line && change.text.length > 1) || change.origin === 'paste') {

          // figure out if there should also be an included line insertion
          // // if the change was just to add a new line character, do a replace
          // // on that line and then do an insert for the next
          if (change.text.join('\n') === '\n') {
            ops.push({p:['lines', change.from.line+1], li: {
              client: timestamps.client,
              timestamp: new Date ()
            }});
          } else {
            /*
             *  For the following values of change.origin, we know what we want to happen.
             *  - null - this is a programmatic insertion
             *  - paste, redo, undo - cm detected the indicated behavior
             *
             *  For others, they'll have to fall through and be handled accordingly.
             *  Not having this conditional here leads to things breaking...
             */
            if (change.origin && change.origin !== 'paste' && change.origin !== 'redo' && change.origin !== 'undo') {
              console.warn('not sure what to do in this case', change);
            } else {

              if (newTimestamp !== doc.lines[change.from.line].timestamp ||
                  timestamps.client !== doc.lines[change.from.line].client) {

                // replace (delete and insert) the line with updated values
                ops.push({p:['lines', change.from.line], ld: doc.lines[change.from.line], li: {
                  client: timestamps.client,
                  timestamp: new Date ()
                }});
              }

              for (i = 1; i < change.text.length; i++) {
                ops.push({p:['lines', change.from.line+1], li: {
                  client: timestamps.client,
                  timestamp: new Date ()
                }});
              }
            }
          }
        } else {
          // change in lines (replace + insertion)
          for (var changeTextIndex = 0; changeTextIndex < change.text.length; changeTextIndex++) {
            var lineChange = change.text[changeTextIndex];
            var lineIndex = change.from.line + changeTextIndex;

            if (doc.lines[lineIndex]) {

              // if this line was just deleted, we don't want to submit any
              // updates for it ... we have already updated the text appropriately,
              // updating this now will update the wrong line.

              var newTimestamp = new Date ();

              // the line metadata has changed (new author or new date)
              if (newTimestamp !== doc.lines[lineIndex].timestamp ||
                  timestamps.client !== doc.lines[lineIndex].client) {

                // replace (delete and insert) the line with updated values

                ops.push({p:['lines', lineIndex], ld: doc.lines[lineIndex], li: {
                  client: timestamps.client,
                  timestamp: newTimestamp
                }});
              }
            } else {
              // the line doesn't currently exist, so insert a new line
              ops.push({p:['lines', lineIndex], li: {
                client: timestamps.client,
                timestamp: new Date ()
              }});
            }
          }
        }
      }

      // submit the complete list of changes
      ctx.submitOp(ops);

      // call the function again on the next change, if there is one
      if (change.next) {
        applyToShareJS(cm, change.next);
      }
    }
function applyToShareJS(cm, change) {

      // CodeMirror changes give a text replacement.

      var startPos = 0;  // Get character position from # of chars in each line.
      var i = 0;         // i goes through all lines.

      while (i < change.from.line) {
        startPos += cm.lineInfo(i).text.length + 1;   // Add 1 for '\n'
        i++;
      }

      startPos += change.from.ch;

      // sharejs json path to the location of the change
      var textPath = ['text', startPos];

      // array of operations that will be submitted
      var ops = [];

      // object to keep track of lines that were deleted
      var deletedLines = {};

      // get an updated document
      var doc = ctx.get();

      if (change.to.line == change.from.line && change.to.ch == change.from.ch) {
        // nothing was removed.
      } else {

        // change in lines (deleted lines)
        if(change.to.line !== change.from.line){
          for (i = change.to.line; i > change.from.line; i--) {

            if(doc.lines[i] !== undefined){
              ops.push({p:['lines', i], ld: doc.lines[i]});
              deletedLines[i] = true;
            }
          }
        }

        // change in text (deletion)
        ops.push({p:textPath, sd: change.removed.join('\n')});
      }

      if (change.text) {

        // change in text (insertion)
        ops.push({p:textPath, si: change.text.join('\n')});

        // new lines and pasting
        if ((change.from.line === change.to.line && change.text.length > 1) || change.origin === 'paste') {

          // figure out if there should also be an included line insertion
          // // if the change was just to add a new line character, do a replace
          // // on that line and then do an insert for the next
          if (change.text.join('\n') === '\n') {
            ops.push({p:['lines', change.from.line+1], li: {
              client: timestamps.client,
              timestamp: new Date ()
            }});
          } else {
            /*
             *  For the following values of change.origin, we know what we want to happen.
             *  - null - this is a programmatic insertion
             *  - paste, redo, undo - cm detected the indicated behavior
             *
             *  For others, they'll have to fall through and be handled accordingly.
             *  Not having this conditional here leads to things breaking...
             */
            if (change.origin && change.origin !== 'paste' && change.origin !== 'redo' && change.origin !== 'undo') {
              console.warn('not sure what to do in this case', change);
            } else {

              if (newTimestamp !== doc.lines[change.from.line].timestamp ||
                  timestamps.client !== doc.lines[change.from.line].client) {

                // replace (delete and insert) the line with updated values
                ops.push({p:['lines', change.from.line], ld: doc.lines[change.from.line], li: {
                  client: timestamps.client,
                  timestamp: new Date ()
                }});
              }

              for (i = 1; i < change.text.length; i++) {
                ops.push({p:['lines', change.from.line+1], li: {
                  client: timestamps.client,
                  timestamp: new Date ()
                }});
              }
            }
          }
        } else {
          // change in lines (replace + insertion)
          for (var changeTextIndex = 0; changeTextIndex < change.text.length; changeTextIndex++) {
            var lineChange = change.text[changeTextIndex];
            var lineIndex = change.from.line + changeTextIndex;

            if (doc.lines[lineIndex]) {

              // if this line was just deleted, we don't want to submit any
              // updates for it ... we have already updated the text appropriately,
              // updating this now will update the wrong line.

              var newTimestamp = new Date ();

              // the line metadata has changed (new author or new date)
              if (newTimestamp !== doc.lines[lineIndex].timestamp ||
                  timestamps.client !== doc.lines[lineIndex].client) {

                // replace (delete and insert) the line with updated values

                ops.push({p:['lines', lineIndex], ld: doc.lines[lineIndex], li: {
                  client: timestamps.client,
                  timestamp: newTimestamp
                }});
              }
            } else {
              // the line doesn't currently exist, so insert a new line
              ops.push({p:['lines', lineIndex], li: {
                client: timestamps.client,
                timestamp: new Date ()
              }});
            }
          }
        }
      }

      // submit the complete list of changes
      ctx.submitOp(ops);

      // call the function again on the next change, if there is one
      if (change.next) {
        applyToShareJS(cm, change.next);
      }
    }
function applyToShareJS ( cm , change ) { // CodeMirror changes give a text replacement. var startPos = 0 ; // Get character position from # of chars in each line. var i = 0 ; // i goes through all lines. while ( i < change . from . line ) { startPos += cm . lineInfo ( i ) . text . length + 1 ; // Add 1 for '\n' i ++ ; } startPos += change . from . ch ; // sharejs json path to the location of the change var textPath = [ 'text' , startPos ] ; // array of operations that will be submitted var ops = [ ] ; // object to keep track of lines that were deleted var deletedLines = { } ; // get an updated document var doc = ctx . get ( ) ; if ( change . to . line == change . from . line && change . to . ch == change . from . ch ) { // nothing was removed. } else { // change in lines (deleted lines) if ( change . to . line !== change . from . line ) { for ( i = change . to . line ; i > change . from . line ; i -- ) { if ( doc . lines [ i ] !== undefined ) { ops . push ( { p : [ 'lines' , i ] , ld : doc . lines [ i ] } ) ; deletedLines [ i ] = true ; } } } // change in text (deletion) ops . push ( { p : textPath , sd : change . removed . join ( '\n' ) } ) ; } if ( change . text ) { // change in text (insertion) ops . push ( { p : textPath , si : change . text . join ( '\n' ) } ) ; // new lines and pasting if ( ( change . from . line === change . to . line && change . text . length > 1 ) || change . origin === 'paste' ) { // figure out if there should also be an included line insertion // // if the change was just to add a new line character, do a replace // // on that line and then do an insert for the next if ( change . text . join ( '\n' ) === '\n' ) { ops . push ( { p : [ 'lines' , change . from . line + 1 ] , li : { client : timestamps . client , timestamp : new Date ( ) } } ) ; } else { /*
             *  For the following values of change.origin, we know what we want to happen.
             *  - null - this is a programmatic insertion
             *  - paste, redo, undo - cm detected the indicated behavior
             *
             *  For others, they'll have to fall through and be handled accordingly.
             *  Not having this conditional here leads to things breaking...
             */ if ( change . origin && change . origin !== 'paste' && change . origin !== 'redo' && change . origin !== 'undo' ) { console . warn ( 'not sure what to do in this case' , change ) ; } else { if ( newTimestamp !== doc . lines [ change . from . line ] . timestamp || timestamps . client !== doc . lines [ change . from . line ] . client ) { // replace (delete and insert) the line with updated values ops . push ( { p : [ 'lines' , change . from . line ] , ld : doc . lines [ change . from . line ] , li : { client : timestamps . client , timestamp : new Date ( ) } } ) ; } for ( i = 1 ; i < change . text . length ; i ++ ) { ops . push ( { p : [ 'lines' , change . from . line + 1 ] , li : { client : timestamps . client , timestamp : new Date ( ) } } ) ; } } } } else { // change in lines (replace + insertion) for ( var changeTextIndex = 0 ; changeTextIndex < change . text . length ; changeTextIndex ++ ) { var lineChange = change . text [ changeTextIndex ] ; var lineIndex = change . from . line + changeTextIndex ; if ( doc . lines [ lineIndex ] ) { // if this line was just deleted, we don't want to submit any // updates for it ... we have already updated the text appropriately, // updating this now will update the wrong line. var newTimestamp = new Date ( ) ; // the line metadata has changed (new author or new date) if ( newTimestamp !== doc . lines [ lineIndex ] . timestamp || timestamps . client !== doc . lines [ lineIndex ] . client ) { // replace (delete and insert) the line with updated values ops . push ( { p : [ 'lines' , lineIndex ] , ld : doc . lines [ lineIndex ] , li : { client : timestamps . client , timestamp : newTimestamp } } ) ; } } else { // the line doesn't currently exist, so insert a new line ops . push ( { p : [ 'lines' , lineIndex ] , li : { client : timestamps . client , timestamp : new Date ( ) } } ) ; } } } } // submit the complete list of changes ctx . submitOp ( ops ) ; // call the function again on the next change, if there is one if ( change . next ) { applyToShareJS ( cm , change . next ) ; } }
Convert a CodeMirror change into an op understood by share.js
Convert a CodeMirror change into an op understood by share . js