| /* |
| This is part of jsdifflib v1.0. <http://github.com/cemerick/jsdifflib> |
| |
| Copyright 2007 - 2011 Chas Emerick <cemerick@snowtide.com>. All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without modification, are |
| permitted provided that the following conditions are met: |
| |
| 1. Redistributions of source code must retain the above copyright notice, this list of |
| conditions and the following disclaimer. |
| |
| 2. Redistributions in binary form must reproduce the above copyright notice, this list |
| of conditions and the following disclaimer in the documentation and/or other materials |
| provided with the distribution. |
| |
| THIS SOFTWARE IS PROVIDED BY Chas Emerick ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
| FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Chas Emerick OR |
| CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| The views and conclusions contained in the software and documentation are those of the |
| authors and should not be interpreted as representing official policies, either expressed |
| or implied, of Chas Emerick. |
| */ |
| diffview = { |
| /** |
| * Builds and returns a visual diff view. The single parameter, `params', should contain |
| * the following values: |
| * |
| * - baseTextLines: the array of strings that was used as the base text input to SequenceMatcher |
| * - newTextLines: the array of strings that was used as the new text input to SequenceMatcher |
| * - opcodes: the array of arrays returned by SequenceMatcher.get_opcodes() |
| * - baseTextName: the title to be displayed above the base text listing in the diff view; defaults |
| * to "Base Text" |
| * - newTextName: the title to be displayed above the new text listing in the diff view; defaults |
| * to "New Text" |
| * - contextSize: the number of lines of context to show around differences; by default, all lines |
| * are shown |
| * - viewType: if 0, a side-by-side diff view is generated (default); if 1, an inline diff view is |
| * generated |
| */ |
| buildView: function (params) { |
| var baseTextLines = params.baseTextLines; |
| var newTextLines = params.newTextLines; |
| var opcodes = params.opcodes; |
| var contextSize = params.contextSize; |
| var inline = (params.viewType == 0 || params.viewType == 1) ? params.viewType : 0; |
| |
| if (baseTextLines == null) |
| throw "Cannot build diff view; baseTextLines is not defined."; |
| if (newTextLines == null) |
| throw "Cannot build diff view; newTextLines is not defined."; |
| if (!opcodes) |
| throw "Canno build diff view; opcodes is not defined."; |
| |
| function celt (name, clazz) { |
| var e = document.createElement(name); |
| e.className = clazz; |
| return e; |
| } |
| |
| function telt (name, text) { |
| var e = document.createElement(name); |
| e.appendChild(document.createTextNode(text)); |
| return e; |
| } |
| |
| function ctelt (name, clazz, text) { |
| var e = document.createElement(name); |
| e.className = clazz; |
| e.appendChild(document.createTextNode(text)); |
| return e; |
| } |
| |
| var tdata = []; |
| |
| var rows = []; |
| var node2; |
| |
| /** |
| * Adds two cells to the given row; if the given row corresponds to a real |
| * line number (based on the line index tidx and the endpoint of the |
| * range in question tend), then the cells will contain the line number |
| * and the line of text from textLines at position tidx (with the class of |
| * the second cell set to the name of the change represented), and tidx + 1 will |
| * be returned. Otherwise, tidx is returned, and two empty cells are added |
| * to the given row. |
| */ |
| function addCells (row, tidx, tend, textLines, change) { |
| if (tidx < tend) { |
| row.appendChild(ctelt("td", change, textLines[tidx].replace(/\t/g, "\u00a0\u00a0\u00a0\u00a0"))); |
| return tidx + 1; |
| } else { |
| row.appendChild(celt("td", "empty")); |
| return tidx; |
| } |
| } |
| |
| function addCellsInline (row, tidx, tidx2, textLines, change) { |
| row.appendChild(ctelt("td", change, textLines[tidx != null ? tidx : tidx2].replace(/\t/g, "\u00a0\u00a0\u00a0\u00a0"))); |
| } |
| |
| for (var idx = 0; idx < opcodes.length; idx++) { |
| code = opcodes[idx]; |
| change = code[0]; |
| var b = code[1]; |
| var be = code[2]; |
| var n = code[3]; |
| var ne = code[4]; |
| var rowcnt = Math.max(be - b, ne - n); |
| var toprows = []; |
| var botrows = []; |
| for (var i = 0; i < rowcnt; i++) { |
| // jump ahead if we've alredy provided leading context or if this is the first range |
| if (contextSize && opcodes.length > 1 && ((idx > 0 && i == contextSize) || (idx == 0 && i == 0)) && change=="equal") { |
| var jump = rowcnt - ((idx == 0 ? 1 : 2) * contextSize); |
| if (jump > 1) { |
| toprows.push(node = celt("tr", "row")); |
| |
| b += jump; |
| n += jump; |
| i += jump - 1; |
| if (!inline) node.appendChild(ctelt("td", "skip span6", "")); |
| node.appendChild(ctelt("td", "skip span6", "")); |
| |
| // skip last lines if they're all equal |
| if (idx + 1 == opcodes.length) { |
| break; |
| } else { |
| continue; |
| } |
| } |
| } |
| |
| toprows.push(node = celt("tr", "row")); |
| if (inline) { |
| if (change == "insert") { |
| addCellsInline(node, null, n++, newTextLines, change + " span6"); |
| } else if (change == "replace") { |
| botrows.push(node2 = celt("tr", "row")); |
| if (b < be) addCellsInline(node, b++, null, baseTextLines, "delete span6"); |
| if (n < ne) addCellsInline(node2, null, n++, newTextLines, "insert span6"); |
| } else if (change == "delete") { |
| addCellsInline(node, b++, null, baseTextLines, change + " span6"); |
| } else { |
| // equal |
| addCellsInline(node, b++, n++, baseTextLines, change + " span6"); |
| } |
| } else { |
| b = addCells(node, b, be, baseTextLines, change + " span6"); |
| n = addCells(node, n, ne, newTextLines, change + " span6"); |
| } |
| } |
| |
| for (var i = 0; i < toprows.length; i++) rows.push(toprows[i]); |
| for (var i = 0; i < botrows.length; i++) rows.push(botrows[i]); |
| } |
| |
| tdata.push(node = document.createElement("tbody")); |
| for (var idx in rows) rows.hasOwnProperty(idx) && node.appendChild(rows[idx]); |
| |
| node = celt("table", "diff" + (inline ? " inlinediff" : "")); |
| for (var idx in tdata) tdata.hasOwnProperty(idx) && node.appendChild(tdata[idx]); |
| return node; |
| } |
| }; |
| |