|
|
- /*
- 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 baseTextName = params.baseTextName ? params.baseTextName : "Base Text";
- var newTextName = params.newTextName ? params.newTextName : "New Text";
- 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 = document.createElement("thead");
- var node = document.createElement("tr");
- tdata.appendChild(node);
- if (inline) {
- node.appendChild(document.createElement("th"));
- node.appendChild(document.createElement("th"));
- node.appendChild(ctelt("th", "texttitle", baseTextName + " vs. " + newTextName));
- } else {
- node.appendChild(document.createElement("th"));
- node.appendChild(ctelt("th", "texttitle", baseTextName));
- node.appendChild(document.createElement("th"));
- node.appendChild(ctelt("th", "texttitle", newTextName));
- }
- tdata = [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(telt("th", (tidx + 1).toString()));
- row.appendChild(ctelt("td", change, textLines[tidx].replace(/\t/g, "\u00a0\u00a0\u00a0\u00a0")));
- return tidx + 1;
- } else {
- row.appendChild(document.createElement("th"));
- row.appendChild(celt("td", "empty"));
- return tidx;
- }
- }
-
- function addCellsInline (row, tidx, tidx2, textLines, change) {
- row.appendChild(telt("th", tidx == null ? "" : (tidx + 1).toString()));
- row.appendChild(telt("th", tidx2 == null ? "" : (tidx2 + 1).toString()));
- 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 = document.createElement("tr"));
-
- b += jump;
- n += jump;
- i += jump - 1;
- node.appendChild(telt("th", "..."));
- if (!inline) node.appendChild(ctelt("td", "skip", ""));
- node.appendChild(telt("th", "..."));
- node.appendChild(ctelt("td", "skip", ""));
-
- // skip last lines if they're all equal
- if (idx + 1 == opcodes.length) {
- break;
- } else {
- continue;
- }
- }
- }
-
- toprows.push(node = document.createElement("tr"));
- if (inline) {
- if (change == "insert") {
- addCellsInline(node, null, n++, newTextLines, change);
- } else if (change == "replace") {
- botrows.push(node2 = document.createElement("tr"));
- if (b < be) addCellsInline(node, b++, null, baseTextLines, "delete");
- if (n < ne) addCellsInline(node2, null, n++, newTextLines, "insert");
- } else if (change == "delete") {
- addCellsInline(node, b++, null, baseTextLines, change);
- } else {
- // equal
- addCellsInline(node, b++, n++, baseTextLines, change);
- }
- } else {
- b = addCells(node, b, be, baseTextLines, change);
- n = addCells(node, n, ne, newTextLines, change);
- }
- }
-
- for (var i = 0; i < toprows.length; i++) rows.push(toprows[i]);
- for (var i = 0; i < botrows.length; i++) rows.push(botrows[i]);
- }
-
- rows.push(node = ctelt("th", "author", "diff view generated by "));
- node.setAttribute("colspan", inline ? 3 : 4);
- node.appendChild(node2 = telt("a", "jsdifflib"));
- node2.setAttribute("href", "http://github.com/cemerick/jsdifflib");
-
- 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;
- }
- };
-
|