TextDiff XPages control – For visual comparison of text
A few years back I stumbled across Google’s diff-match-patch project which provides some handy algorithms for text manipulation. At the time of discovery I was doing ‘classic’ notes development. Although I probably could have implemented something that worked in lotuscript with RichText or Mime, it wasn’t a priority at the time and I never bothered.
Since then, I have been doing mainly XPages, and now that I have been also doing a bit of XPages Control development. I was mainly interested in the ‘diff’ algorithm so I decided the time was right to turn the diff algorithm into a useful XPages control, which takes 2 input strings and displays a visual difference between them.
The diff-match-patch algorithm / project is licenced under Apache Licence 2.0 so it is the same licence as most OpenNTF projects.
Overview
Basically the control takes a ‘from’ and ‘to’ input, and displays the visual diff. I guess it is best to show the example!
Here is some From and To Input that we will use for our examples. I have bound these textareas to viewScope ‘fromText’ and ‘toText’ but they could be bound to whatever text field you like
So then we will use the text diff like so:
1 2 |
<gb:textDiff id="textDiff1" from="#{viewScope.fromText}" to="#{viewScope.toText}" disableTheme="true"> </gb:textDiff> |
Note the following picture is from my demo page so the actual output from the textdiff control is only what is inside the black box.
Algorithm parameters
For a good explanation of the algorithm parameters, I suggest you have a look at the google diff-match-patch webpage. But here is my best explanation!
- cleanup – whether to perform some sort of cleanup to produce some more human readable results. I find ‘semantic’ is a good option
- edit cost – only used for ‘efficiency’ cleanup
- Timeout – don’t spend longer than this amount of seconds
Here is an example of output after changing the ‘cleanup’ option to ‘semantic’. Note that it has lengthened the change from single words to a longer run of words
Styling
The control has style and styleClass properties for the insert, delete and equals operations. Basically the control outputs a bunch of ‘<span>’s for each chunk of the diff operation. These outputs are either an insertion, a deletion or ‘equals’, and they have associated ‘insertStyle’ and ‘insertStyleClass’ properties.
Themable
All the above properties are themable. You can use the ‘Text.Diff’ control type to set properties for all textdiff controls or you can come up with a new ThemeId that can be applied as needed.
Here is an example using the following theme properties with a custom ThemeId
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<control> <name>Text.Diff.Funky</name> <property> <name>style</name> <value>background-color: black;</value> </property> <property> <name>insertStyle</name> <value>color: aqua;</value> </property> <property> <name>equalStyle</name> <value>color: lime;</value> </property> <property> <name>deleteStyle</name> <value>color: pink;</value> </property> </control> |
Installation
You have 2 choices
- install my ‘Gregorbyte’ extension library
- scavenge the necessary files from my github repo and install to your nsf
Install my Gregorbyte Extension Library
Go and get the latest release which should be an update site zip file.
Install this to your domino designer, and also to your domino server using your favourite update site method.
To Scavenge the necessary files from my github repo
You’ll need to put these java files in your Java section of your NSF:
- /com.gregorbyte.xsp.controls/src/com/gregorbyte/xsp/component/UITextDiff.java
- /com.gregorbyte.xsp.controls/src/com/gregorbyte/xsp/renderkit/TextDiffRenderer.java
- /com.gregorbyte.xsp.controls/src/name/fraser/neil/plaintext/DiffMatchPatch.java
And this xsp-config (place in your WebContent/WEB-INF directory in you NSF using package explorer)
- /com.gregorbyte.xsp.controls/src/com/gregorbyte/xsp/config/gregorbyte-textdiff.xsp-config
and add this entry to your faces-config.xml
1 2 3 4 5 6 7 |
<render-kit> <renderer> <component-family>javax.faces.Output</component-family> <renderer-type>com.gregorbyte.TextDiff</renderer-type> <renderer-class>com.gregorbyte.xsp.renderkit.TextDiffRenderer</renderer-class> </renderer> </render-kit> |
Let me know if it works or doesn’t work in case I forgot something. I haven’t used this control heavily in production yet so there may be a bug here and there, please report it if so!
Can it do text diff with html content?
Hi Fredrik, If you want the result to keep it’s html formatting, it might be tricky due to tags overlapping. I might give it a try to see the results and report back later.
otherwise there are 2 options here
1. do a diff of the actual html, where you can actually see tags as part of the diff. In this case no changes are needed, just
2. do a diff of the ‘text’ only of the html, in this case, the control could pass the input through the ‘striptags’ html filter before performing the diff