• R/O
  • SSH
  • HTTPS

fswiki: Commit


Commit MetaInfo

Revision145 (tree)
Time2012-04-16 01:25:27
Authortakezoe

Log Message

差分表示にjsdifflibを使うようにしてみた。

Change Summary

Incremental Difference

--- fswiki/trunk/fswiki/theme/resources/jsdifflib/difflib.js (nonexistent)
+++ fswiki/trunk/fswiki/theme/resources/jsdifflib/difflib.js (revision 145)
@@ -0,0 +1,396 @@
1+/***
2+This is part of jsdifflib v1.0. <http://snowtide.com/jsdifflib>
3+
4+Copyright (c) 2007, Snowtide Informatics Systems, Inc.
5+All rights reserved.
6+
7+Redistribution and use in source and binary forms, with or without modification,
8+are permitted provided that the following conditions are met:
9+
10+ * Redistributions of source code must retain the above copyright notice, this
11+ list of conditions and the following disclaimer.
12+ * Redistributions in binary form must reproduce the above copyright notice,
13+ this list of conditions and the following disclaimer in the documentation
14+ and/or other materials provided with the distribution.
15+ * Neither the name of the Snowtide Informatics Systems nor the names of its
16+ contributors may be used to endorse or promote products derived from this
17+ software without specific prior written permission.
18+
19+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
22+SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28+DAMAGE.
29+***/
30+/* Author: Chas Emerick <cemerick@snowtide.com> */
31+__whitespace = {" ":true, "\t":true, "\n":true, "\f":true, "\r":true};
32+
33+difflib = {
34+ defaultJunkFunction: function (c) {
35+ return c in __whitespace;
36+ },
37+
38+ stripLinebreaks: function (str) { return str.replace(/^[\n\r]*|[\n\r]*$/g, ""); },
39+
40+ stringAsLines: function (str) {
41+ var lfpos = str.indexOf("\n");
42+ var crpos = str.indexOf("\r");
43+ var linebreak = ((lfpos > -1 && crpos > -1) || crpos < 0) ? "\n" : "\r";
44+
45+ var lines = str.split(linebreak);
46+ for (var i = 0; i < lines.length; i++) {
47+ lines[i] = difflib.stripLinebreaks(lines[i]);
48+ }
49+
50+ return lines;
51+ },
52+
53+ // iteration-based reduce implementation
54+ __reduce: function (func, list, initial) {
55+ if (initial != null) {
56+ var value = initial;
57+ var idx = 0;
58+ } else if (list) {
59+ var value = list[0];
60+ var idx = 1;
61+ } else {
62+ return null;
63+ }
64+
65+ for (; idx < list.length; idx++) {
66+ value = func(value, list[idx]);
67+ }
68+
69+ return value;
70+ },
71+
72+ // comparison function for sorting lists of numeric tuples
73+ __ntuplecomp: function (a, b) {
74+ var mlen = Math.max(a.length, b.length);
75+ for (var i = 0; i < mlen; i++) {
76+ if (a[i] < b[i]) return -1;
77+ if (a[i] > b[i]) return 1;
78+ }
79+
80+ return a.length == b.length ? 0 : (a.length < b.length ? -1 : 1);
81+ },
82+
83+ __calculate_ratio: function (matches, length) {
84+ return length ? 2.0 * matches / length : 1.0;
85+ },
86+
87+ // returns a function that returns true if a key passed to the returned function
88+ // is in the dict (js object) provided to this function; replaces being able to
89+ // carry around dict.has_key in python...
90+ __isindict: function (dict) {
91+ return function (key) { return key in dict; };
92+ },
93+
94+ // replacement for python's dict.get function -- need easy default values
95+ __dictget: function (dict, key, defaultValue) {
96+ return key in dict ? dict[key] : defaultValue;
97+ },
98+
99+ SequenceMatcher: function (a, b, isjunk) {
100+ this.set_seqs = function (a, b) {
101+ this.set_seq1(a);
102+ this.set_seq2(b);
103+ }
104+
105+ this.set_seq1 = function (a) {
106+ if (a == this.a) return;
107+ this.a = a;
108+ this.matching_blocks = this.opcodes = null;
109+ }
110+
111+ this.set_seq2 = function (b) {
112+ if (b == this.b) return;
113+ this.b = b;
114+ this.matching_blocks = this.opcodes = this.fullbcount = null;
115+ this.__chain_b();
116+ }
117+
118+ this.__chain_b = function () {
119+ var b = this.b;
120+ var n = b.length;
121+ var b2j = this.b2j = {};
122+ var populardict = {};
123+ for (var i = 0; i < b.length; i++) {
124+ var elt = b[i];
125+ if (elt in b2j) {
126+ var indices = b2j[elt];
127+ if (n >= 200 && indices.length * 100 > n) {
128+ populardict[elt] = 1;
129+ delete b2j[elt];
130+ } else {
131+ indices.push(i);
132+ }
133+ } else {
134+ b2j[elt] = [i];
135+ }
136+ }
137+
138+ for (var elt in populardict)
139+ delete b2j[elt];
140+
141+ var isjunk = this.isjunk;
142+ var junkdict = {};
143+ if (isjunk) {
144+ for (var elt in populardict) {
145+ if (isjunk(elt)) {
146+ junkdict[elt] = 1;
147+ delete populardict[elt];
148+ }
149+ }
150+ for (var elt in b2j) {
151+ if (isjunk(elt)) {
152+ junkdict[elt] = 1;
153+ delete b2j[elt];
154+ }
155+ }
156+ }
157+
158+ this.isbjunk = difflib.__isindict(junkdict);
159+ this.isbpopular = difflib.__isindict(populardict);
160+ }
161+
162+ this.find_longest_match = function (alo, ahi, blo, bhi) {
163+ var a = this.a;
164+ var b = this.b;
165+ var b2j = this.b2j;
166+ var isbjunk = this.isbjunk;
167+ var besti = alo;
168+ var bestj = blo;
169+ var bestsize = 0;
170+ var j = null;
171+
172+ var j2len = {};
173+ var nothing = [];
174+ for (var i = alo; i < ahi; i++) {
175+ var newj2len = {};
176+ var jdict = difflib.__dictget(b2j, a[i], nothing);
177+ for (var jkey in jdict) {
178+ j = jdict[jkey];
179+ if (j < blo) continue;
180+ if (j >= bhi) break;
181+ newj2len[j] = k = difflib.__dictget(j2len, j - 1, 0) + 1;
182+ if (k > bestsize) {
183+ besti = i - k + 1;
184+ bestj = j - k + 1;
185+ bestsize = k;
186+ }
187+ }
188+ j2len = newj2len;
189+ }
190+
191+ while (besti > alo && bestj > blo && !isbjunk(b[bestj - 1]) && a[besti - 1] == b[bestj - 1]) {
192+ besti--;
193+ bestj--;
194+ bestsize++;
195+ }
196+
197+ while (besti + bestsize < ahi && bestj + bestsize < bhi &&
198+ !isbjunk(b[bestj + bestsize]) &&
199+ a[besti + bestsize] == b[bestj + bestsize]) {
200+ bestsize++;
201+ }
202+
203+ while (besti > alo && bestj > blo && isbjunk(b[bestj - 1]) && a[besti - 1] == b[bestj - 1]) {
204+ besti--;
205+ bestj--;
206+ bestsize++;
207+ }
208+
209+ while (besti + bestsize < ahi && bestj + bestsize < bhi && isbjunk(b[bestj + bestsize]) &&
210+ a[besti + bestsize] == b[bestj + bestsize]) {
211+ bestsize++;
212+ }
213+
214+ return [besti, bestj, bestsize];
215+ }
216+
217+ this.get_matching_blocks = function () {
218+ if (this.matching_blocks != null) return this.matching_blocks;
219+ var la = this.a.length;
220+ var lb = this.b.length;
221+
222+ var queue = [[0, la, 0, lb]];
223+ var matching_blocks = [];
224+ var alo, ahi, blo, bhi, qi, i, j, k, x;
225+ while (queue.length) {
226+ qi = queue.pop();
227+ alo = qi[0];
228+ ahi = qi[1];
229+ blo = qi[2];
230+ bhi = qi[3];
231+ x = this.find_longest_match(alo, ahi, blo, bhi);
232+ i = x[0];
233+ j = x[1];
234+ k = x[2];
235+
236+ if (k) {
237+ matching_blocks.push(x);
238+ if (alo < i && blo < j)
239+ queue.push([alo, i, blo, j]);
240+ if (i+k < ahi && j+k < bhi)
241+ queue.push([i + k, ahi, j + k, bhi]);
242+ }
243+ }
244+
245+ matching_blocks.sort(difflib.__ntuplecomp);
246+
247+ var i1 = j1 = k1 = block = 0;
248+ var non_adjacent = [];
249+ for (var idx in matching_blocks) {
250+ block = matching_blocks[idx];
251+ i2 = block[0];
252+ j2 = block[1];
253+ k2 = block[2];
254+ if (i1 + k1 == i2 && j1 + k1 == j2) {
255+ k1 += k2;
256+ } else {
257+ if (k1) non_adjacent.push([i1, j1, k1]);
258+ i1 = i2;
259+ j1 = j2;
260+ k1 = k2;
261+ }
262+ }
263+
264+ if (k1) non_adjacent.push([i1, j1, k1]);
265+
266+ non_adjacent.push([la, lb, 0]);
267+ this.matching_blocks = non_adjacent;
268+ return this.matching_blocks;
269+ }
270+
271+ this.get_opcodes = function () {
272+ if (this.opcodes != null) return this.opcodes;
273+ var i = 0;
274+ var j = 0;
275+ var answer = [];
276+ this.opcodes = answer;
277+ var block, ai, bj, size, tag;
278+ var blocks = this.get_matching_blocks();
279+ for (var idx in blocks) {
280+ block = blocks[idx];
281+ ai = block[0];
282+ bj = block[1];
283+ size = block[2];
284+ tag = '';
285+ if (i < ai && j < bj) {
286+ tag = 'replace';
287+ } else if (i < ai) {
288+ tag = 'delete';
289+ } else if (j < bj) {
290+ tag = 'insert';
291+ }
292+ if (tag) answer.push([tag, i, ai, j, bj]);
293+ i = ai + size;
294+ j = bj + size;
295+
296+ if (size) answer.push(['equal', ai, i, bj, j]);
297+ }
298+
299+ return answer;
300+ }
301+
302+ // this is a generator function in the python lib, which of course is not supported in javascript
303+ // the reimplementation builds up the grouped opcodes into a list in their entirety and returns that.
304+ this.get_grouped_opcodes = function (n) {
305+ if (!n) n = 3;
306+ var codes = this.get_opcodes();
307+ if (!codes) codes = [["equal", 0, 1, 0, 1]];
308+ var code, tag, i1, i2, j1, j2;
309+ if (codes[0][0] == 'equal') {
310+ code = codes[0];
311+ tag = code[0];
312+ i1 = code[1];
313+ i2 = code[2];
314+ j1 = code[3];
315+ j2 = code[4];
316+ codes[0] = [tag, Math.max(i1, i2 - n), i2, Math.max(j1, j2 - n), j2];
317+ }
318+ if (codes[codes.length - 1][0] == 'equal') {
319+ code = codes[codes.length - 1];
320+ tag = code[0];
321+ i1 = code[1];
322+ i2 = code[2];
323+ j1 = code[3];
324+ j2 = code[4];
325+ codes[codes.length - 1] = [tag, i1, Math.min(i2, i1 + n), j1, Math.min(j2, j1 + n)];
326+ }
327+
328+ var nn = n + n;
329+ var groups = [];
330+ for (var idx in codes) {
331+ code = codes[idx];
332+ tag = code[0];
333+ i1 = code[1];
334+ i2 = code[2];
335+ j1 = code[3];
336+ j2 = code[4];
337+ if (tag == 'equal' && i2 - i1 > nn) {
338+ groups.push([tag, i1, Math.min(i2, i1 + n), j1, Math.min(j2, j1 + n)]);
339+ i1 = Math.max(i1, i2-n);
340+ j1 = Math.max(j1, j2-n);
341+ }
342+
343+ groups.push([tag, i1, i2, j1, j2]);
344+ }
345+
346+ if (groups && groups[groups.length - 1][0] == 'equal') groups.pop();
347+
348+ return groups;
349+ }
350+
351+ this.ratio = function () {
352+ matches = difflib.__reduce(
353+ function (sum, triple) { return sum + triple[triple.length - 1]; },
354+ this.get_matching_blocks(), 0);
355+ return difflib.__calculate_ratio(matches, this.a.length + this.b.length);
356+ }
357+
358+ this.quick_ratio = function () {
359+ var fullbcount, elt;
360+ if (this.fullbcount == null) {
361+ this.fullbcount = fullbcount = {};
362+ for (var i = 0; i < this.b.length; i++) {
363+ elt = this.b[i];
364+ fullbcount[elt] = difflib.__dictget(fullbcount, elt, 0) + 1;
365+ }
366+ }
367+ fullbcount = this.fullbcount;
368+
369+ var avail = {};
370+ var availhas = difflib.__isindict(avail);
371+ var matches = numb = 0;
372+ for (var i = 0; i < this.a.length; i++) {
373+ elt = this.a[i];
374+ if (availhas(elt)) {
375+ numb = avail[elt];
376+ } else {
377+ numb = difflib.__dictget(fullbcount, elt, 0);
378+ }
379+ avail[elt] = numb - 1;
380+ if (numb > 0) matches++;
381+ }
382+
383+ return difflib.__calculate_ratio(matches, this.a.length + this.b.length);
384+ }
385+
386+ this.real_quick_ratio = function () {
387+ var la = this.a.length;
388+ var lb = this.b.length;
389+ return _calculate_ratio(Math.min(la, lb), la + lb);
390+ }
391+
392+ this.isjunk = isjunk ? isjunk : difflib.defaultJunkFunction;
393+ this.a = this.b = null;
394+ this.set_seqs(a, b);
395+ }
396+}
--- fswiki/trunk/fswiki/theme/resources/jsdifflib/diffview.css (nonexistent)
+++ fswiki/trunk/fswiki/theme/resources/jsdifflib/diffview.css (revision 145)
@@ -0,0 +1,83 @@
1+/***
2+This is part of jsdifflib v1.0. <http://snowtide.com/jsdifflib>
3+
4+Copyright (c) 2007, Snowtide Informatics Systems, Inc.
5+All rights reserved.
6+
7+Redistribution and use in source and binary forms, with or without modification,
8+are permitted provided that the following conditions are met:
9+
10+ * Redistributions of source code must retain the above copyright notice, this
11+ list of conditions and the following disclaimer.
12+ * Redistributions in binary form must reproduce the above copyright notice,
13+ this list of conditions and the following disclaimer in the documentation
14+ and/or other materials provided with the distribution.
15+ * Neither the name of the Snowtide Informatics Systems nor the names of its
16+ contributors may be used to endorse or promote products derived from this
17+ software without specific prior written permission.
18+
19+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
22+SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28+DAMAGE.
29+***/
30+/* Author: Chas Emerick <cemerick@snowtide.com> */
31+table.diff {
32+ border-collapse:collapse;
33+ border:1px solid darkgray
34+}
35+table.diff tbody {
36+ font-family:Courier, monospace
37+}
38+table.diff tbody th {
39+ font-family:verdana,arial,'Bitstream Vera Sans',helvetica,sans-serif;
40+ background:#EED;
41+ font-size:11px;
42+ font-weight:normal;
43+ border:1px solid #BBC;
44+ color:#886;
45+ padding:.3em .5em .1em 2em;
46+ text-align:right;
47+ vertical-align:top
48+}
49+table.diff thead {
50+ border-bottom:1px solid #BBC;
51+ background:#EFEFEF;
52+ font-family:Verdana
53+}
54+table.diff thead th.texttitle {
55+ text-align:left
56+}
57+table.diff tbody td {
58+ padding:0px .4em;
59+ padding-top:.4em;
60+ vertical-align:top;
61+}
62+table.diff .empty {
63+ background-color:#DDD;
64+}
65+table.diff .replace {
66+ background-color:#FD8
67+}
68+table.diff .delete {
69+ background-color:#E99;
70+}
71+table.diff .skip {
72+ background-color:#EFEFEF;
73+ border:1px solid #AAA;
74+ border-right:1px solid #BBC;
75+}
76+table.diff .insert {
77+ background-color:#9E9
78+}
79+table.diff th.author {
80+ text-align:right;
81+ border-top:1px solid #BBC;
82+ background:#EFEFEF
83+}
\ No newline at end of file
--- fswiki/trunk/fswiki/theme/resources/jsdifflib/diffview.js (nonexistent)
+++ fswiki/trunk/fswiki/theme/resources/jsdifflib/diffview.js (revision 145)
@@ -0,0 +1,198 @@
1+/***
2+This is part of jsdifflib v1.0. <http://snowtide.com/jsdifflib>
3+
4+Copyright (c) 2007, Snowtide Informatics Systems, Inc.
5+All rights reserved.
6+
7+Redistribution and use in source and binary forms, with or without modification,
8+are permitted provided that the following conditions are met:
9+
10+ * Redistributions of source code must retain the above copyright notice, this
11+ list of conditions and the following disclaimer.
12+ * Redistributions in binary form must reproduce the above copyright notice,
13+ this list of conditions and the following disclaimer in the documentation
14+ and/or other materials provided with the distribution.
15+ * Neither the name of the Snowtide Informatics Systems nor the names of its
16+ contributors may be used to endorse or promote products derived from this
17+ software without specific prior written permission.
18+
19+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
22+SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28+DAMAGE.
29+***/
30+/* Author: Chas Emerick <cemerick@snowtide.com> */
31+diffview = {
32+ /**
33+ * Builds and returns a visual diff view. The single parameter, `params', should contain
34+ * the following values:
35+ *
36+ * - baseTextLines: the array of strings that was used as the base text input to SequenceMatcher
37+ * - newTextLines: the array of strings that was used as the new text input to SequenceMatcher
38+ * - opcodes: the array of arrays returned by SequenceMatcher.get_opcodes()
39+ * - baseTextName: the title to be displayed above the base text listing in the diff view; defaults
40+ * to "Base Text"
41+ * - newTextName: the title to be displayed above the new text listing in the diff view; defaults
42+ * to "New Text"
43+ * - contextSize: the number of lines of context to show around differences; by default, all lines
44+ * are shown
45+ * - viewType: if 0, a side-by-side diff view is generated (default); if 1, an inline diff view is
46+ * generated
47+ */
48+ buildView: function (params) {
49+ var baseTextLines = params.baseTextLines;
50+ var newTextLines = params.newTextLines;
51+ var opcodes = params.opcodes;
52+ var baseTextName = params.baseTextName ? params.baseTextName : "Base Text";
53+ var newTextName = params.newTextName ? params.newTextName : "New Text";
54+ var contextSize = params.contextSize;
55+ var inline = (params.viewType == 0 || params.viewType == 1) ? params.viewType : 0;
56+
57+ if (baseTextLines == null)
58+ throw "Cannot build diff view; baseTextLines is not defined.";
59+ if (newTextLines == null)
60+ throw "Cannot build diff view; newTextLines is not defined.";
61+ if (!opcodes)
62+ throw "Canno build diff view; opcodes is not defined.";
63+
64+ function celt (name, clazz) {
65+ var e = document.createElement(name);
66+ e.className = clazz;
67+ return e;
68+ }
69+
70+ function telt (name, text) {
71+ var e = document.createElement(name);
72+ e.appendChild(document.createTextNode(text));
73+ return e;
74+ }
75+
76+ function ctelt (name, clazz, text) {
77+ var e = document.createElement(name);
78+ e.className = clazz;
79+ e.appendChild(document.createTextNode(text));
80+ return e;
81+ }
82+
83+ var tdata = document.createElement("thead");
84+ var node = document.createElement("tr");
85+ tdata.appendChild(node);
86+ if (inline) {
87+ node.appendChild(document.createElement("th"));
88+ node.appendChild(document.createElement("th"));
89+ node.appendChild(ctelt("th", "texttitle", baseTextName + " vs. " + newTextName));
90+ } else {
91+ node.appendChild(document.createElement("th"));
92+ node.appendChild(ctelt("th", "texttitle", baseTextName));
93+ node.appendChild(document.createElement("th"));
94+ node.appendChild(ctelt("th", "texttitle", newTextName));
95+ }
96+ tdata = [tdata];
97+
98+ var rows = [];
99+ var node2;
100+
101+ /**
102+ * Adds two cells to the given row; if the given row corresponds to a real
103+ * line number (based on the line index tidx and the endpoint of the
104+ * range in question tend), then the cells will contain the line number
105+ * and the line of text from textLines at position tidx (with the class of
106+ * the second cell set to the name of the change represented), and tidx + 1 will
107+ * be returned. Otherwise, tidx is returned, and two empty cells are added
108+ * to the given row.
109+ */
110+ function addCells (row, tidx, tend, textLines, change) {
111+ if (tidx < tend) {
112+ row.appendChild(telt("th", (tidx + 1).toString()));
113+ row.appendChild(ctelt("td", change, textLines[tidx].replace(/\t/g, "\u00a0\u00a0\u00a0\u00a0")));
114+ return tidx + 1;
115+ } else {
116+ row.appendChild(document.createElement("th"));
117+ row.appendChild(celt("td", "empty"));
118+ return tidx;
119+ }
120+ }
121+
122+ function addCellsInline (row, tidx, tidx2, textLines, change) {
123+ row.appendChild(telt("th", tidx == null ? "" : (tidx + 1).toString()));
124+ row.appendChild(telt("th", tidx2 == null ? "" : (tidx2 + 1).toString()));
125+ row.appendChild(ctelt("td", change, textLines[tidx != null ? tidx : tidx2].replace(/\t/g, "\u00a0\u00a0\u00a0\u00a0")));
126+ }
127+
128+ for (var idx = 0; idx < opcodes.length; idx++) {
129+ code = opcodes[idx];
130+ change = code[0];
131+ var b = code[1];
132+ var be = code[2];
133+ var n = code[3];
134+ var ne = code[4];
135+ var rowcnt = Math.max(be - b, ne - n);
136+ var toprows = [];
137+ var botrows = [];
138+ for (var i = 0; i < rowcnt; i++) {
139+ // jump ahead if we've alredy provided leading context or if this is the first range
140+ if (contextSize && opcodes.length > 1 && ((idx > 0 && i == contextSize) || (idx == 0 && i == 0)) && change=="equal") {
141+ var jump = rowcnt - ((idx == 0 ? 1 : 2) * contextSize);
142+ if (jump > 1) {
143+ toprows.push(node = document.createElement("tr"));
144+
145+ b += jump;
146+ n += jump;
147+ i += jump - 1;
148+ node.appendChild(telt("th", "..."));
149+ if (!inline) node.appendChild(ctelt("td", "skip", ""));
150+ node.appendChild(telt("th", "..."));
151+ node.appendChild(ctelt("td", "skip", ""));
152+
153+ // skip last lines if they're all equal
154+ if (idx + 1 == opcodes.length) {
155+ break;
156+ } else {
157+ continue;
158+ }
159+ }
160+ }
161+
162+ toprows.push(node = document.createElement("tr"));
163+ if (inline) {
164+ if (change == "insert") {
165+ addCellsInline(node, null, n++, newTextLines, change);
166+ } else if (change == "replace") {
167+ botrows.push(node2 = document.createElement("tr"));
168+ if (b < be) addCellsInline(node, b++, null, baseTextLines, "delete");
169+ if (n < ne) addCellsInline(node2, null, n++, newTextLines, "insert");
170+ } else if (change == "delete") {
171+ addCellsInline(node, b++, null, baseTextLines, change);
172+ } else {
173+ // equal
174+ addCellsInline(node, b++, n++, baseTextLines, change);
175+ }
176+ } else {
177+ b = addCells(node, b, be, baseTextLines, change);
178+ n = addCells(node, n, ne, newTextLines, change);
179+ }
180+ }
181+
182+ for (var i = 0; i < toprows.length; i++) rows.push(toprows[i]);
183+ for (var i = 0; i < botrows.length; i++) rows.push(botrows[i]);
184+ }
185+
186+ rows.push(node = ctelt("th", "author", "diff view generated by "));
187+ node.setAttribute("colspan", inline ? 3 : 4);
188+ node.appendChild(node2 = telt("a", "jsdifflib"));
189+ node2.setAttribute("href", "http://snowtide.com/jsdifflib");
190+
191+ tdata.push(node = document.createElement("tbody"));
192+ for (var idx in rows) node.appendChild(rows[idx]);
193+
194+ node = celt("table", "diff" + (inline ? " inlinediff" : ""));
195+ for (var idx in tdata) node.appendChild(tdata[idx]);
196+ return node;
197+ }
198+}
\ No newline at end of file
Show on old repository browser