Change tracking is one of the most important features in collaborative editing tools, such as Microsoft Word, Wikipeda or Google Docs. In this tutorial, you will learn how to use google-diff-match-patch and jQuery to view difference between two versions and accept or reject change.

Demo Page
Source Code
Introduction
First, let's have a look at the final example of our change tracking system.

This application will compare new version text with old version and show result in the Diff Viewer. When you hover your mouse on the difference, deletion or insertion, the "Accept Change" context menu will appear. If you click it, the old version text will be modified according to the difference.
The diff operation is implemented via google-diff-match-patch library with a little hack. Change applied via jQuery DOM manipulation.
What is google-diff-match-patch
google-diff-match-patch is Diff, Match and Patch libraries for Plain Text. It provides:
The Diff Match and Patch libraries offer robust algorithms to perform the operations required for synchronizing plain text.
- Diff:
- Compare two blocks of plain text and efficiently return a list of differences.
- Diff Demo
- Match:
- Given a search string, find its best fuzzy match in a block of plain text. Weighted for both accuracy and location.
- Match Demo
- Patch:
- Apply a list of patches onto plain text. Use best-effort to apply patch even when the underlying text doesn't match.
- Patch Demo
Currently available in Java, JavaScript, C++, C#, Lua and Python. Regardless of language, each library features the same API and the same functionality. All versions also have comprehensive test harnesses.
In this tutorial, we will only use its Diff API and we won't dig into the algorithm but how to use this wonderful api to implement our own changes tracking editor.
Why not use patch library shipped with google-diff-match-patch?
The function I want to implement is similar to Microsoft Word's "Track Changes". The change is accepted one by one in any order. Unfortunately, we cannot use the patch library shipped with google-diff-match-patch. The reason is because patches in google-diff-match-patch are kind of package things, you can only apply all patches at one time. This is, if you want to change the second difference, the first one must be applied at first.
Therefore, there is no way to add ":)" without change "Hello" to "hi" at first. So we need another way to accept change one by one in any order.
Step 1 Make google-diff-match-patch generate prettier html code and ready to apply change
Let's play a little bit with the Diff Demo and try it with two simple texts:
Version 1. Hello, World!
Version 2. Hi, World:)
The html code generated is:

After checked the source code, we can know that difference can be INSERT, DELETE or EQUAL and the function we interested is diff_prettyHtml(). As you can see from the above output, this function generates html code for the diff result. The EQUAL texts will be placed in a <span> tag. And in HTML, there are <del> and <ins> tags perfectly to present delete and insert texts.
However, the html code is not pretty enough for us, so we need to provide another one, so called "prettierHtml()".
diff_match_patch.prototype.diff_prettierHtml = function(diffs) {
var html = [];
var i = 0;
for (var x = 0; x < diffs.length; x++) {
var op = diffs[x][0]; // Operation (insert, delete, equal)
var data = diffs[x][1]; // Text of change.
var text = data;
switch (op) {
case DIFF_INSERT:
html[x] = '' + text + '';
break;
case DIFF_DELETE:
html[x] = '' + text + '';
break;
case DIFF_EQUAL:
html[x] = '' + text + '';
break;
}
if (op !== DIFF_DELETE) {
i += data.length;
}
}
return html.join('');
};
This function is basically copied from diff_prettyHtml(). I made two changes:
1. Do not escape special character, such as new line, less than, or bigger than.
2. Remove dirty inline style and title for each difference (not necessary).
The modified code will generate following html code:

Step 2 Calculate differences
This is done by google-diff-match-patch, but we would like to render result html code by our own function.
function calcDiffs() {
var dmp = new diff_match_patch();
var differences = dmp.diff_main($("#text1").val(), $("#text2").val());
var ds = dmp.diff_prettierHtml(differences);
$("#viewer").html(ds);
}
Step 3 Register Accept Change context menu
Thanks to google-diff-match-patch, all the modifications are placed either in <del> or <ins> tag, so we just binding mouseover event to all <del> and <ins> element. In addition, since those elements come and go frequently, we need to binding them with jQuery live() function.
function registerContextMenu(){
$('del, ins').live('mouseover', function(event) {
current= $(this);
$(".highlight").removeClass("highlight");
current.addClass("highlight");
var top= event.pageY +5;
$('#contextmenu_holder').css( {
top :top + 'px',
left : event.pageX + 'px'
}).show();
});
}
Step 4Accept Change
Now have a second look at the diff output html code, changes can be applied by its tag name. Continune with Hello World example, if we want to accept deletion of "ello", we just remove <del>ello</del>from DOM tree. Similarly, if the insertion can be implement via replace <ins> tag with <span>.
function registerAcceptChange(){
$('#accept).click(function () {
if (current.is('del')) {
current.remove();
}
if (current.is('ins')) {
current.replaceWith('' + current.html() + '');
}
resetText();
$('#contextmenu_holder').hide();
return false;
});
}
Of course, the text version 1 need to be recalculated after any change applied. The calculation process is also interesting, we need to join text between <span> and <del> tag.
function resetText() {
var fulltext = "";
$("#viewer").children().each(function() {
if (!$(this).is('ins')) {
fulltext = fulltext + $(this).html();
}
});
$("#text1").val(fulltext)
}
Step 5Pull all together
This is done by google-diff-match-patch, but we would like to render result html code by our own function.
$(function() {
calcDiffs();
registerContextMenu();
registerAcceptChange();
//hide context menu when click anywhere
$(document).click(function() {
$('#contextmenu_holder').hide();
$(".highlight").removeClass("highlight");
});
//caculate difference when text change
$('textarea').change(function() {
calcDiffs();
});
});
Conclusion
I hope this tutorial explained clearly how to use google-diff-match-patch and jQuery to implement text change tracking system. The functions we implemented can be further extended with undo/redo.
At last, I want to thank all the open source community. With their excellent jobs, it is possible to implement complicated function with just a few lines of codes.