##// END OF EJS Templates
Migrate to Mergely 3.3.4....
"Bradley M. Kuhn" -
r4125:aa3b5594 rhodecode-2.2.5-gpl
parent child Browse files
Show More
@@ -0,0 +1,111 b''
1 <!DOCTYPE html>
2 <html lang="en">
3 <!--[if IE]>
4 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
5 <![endif]-->
6 <head>
7 <meta charset="utf-8" /><title>Mergely License</title>
8 <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
9 <meta name="description" content="Mergely license requirements for open source software and commercial software" />
10 <meta name="keywords" content="diff,merge,compare,compare documents,js diff,javascript diff,comparison,online diff,difference,file,text,unix,patch,algorithm,saas,longest common subsequence,diff online" />
11 <meta name="author" content="Jamie Peabody" />
12 <meta name="author" content="Jamie Peabody" />
13 <link rel="shortcut icon" href="http://www.mergely.com/favicon.ico" />
14 <link href='http://fonts.googleapis.com/css?family=Noto+Sans:400,700' rel='stylesheet' type='text/css' />
15 <link href='fonts/berlin-sans-fb-demi.css' rel='stylesheet' type='text/css' />
16 <link href='style/mergely.css' rel='stylesheet' type='text/css' />
17 <link href='/Mergely/lib/mergely.css' rel='stylesheet' type='text/css' />
18 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
19 <script type="text/javascript">
20 var _gaq = _gaq || [];
21 _gaq.push(['_setAccount', 'UA-85576-5']);
22 _gaq.push(['_trackPageview']);
23 (function() {
24 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
25 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
26 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
27 })();
28 </script>
29 </head>
30 <body>
31 <div id="page">
32 <div id="content">
33 <div id="header">
34 <h1><span>Mergely License - Closed Distribution License</span></h1>
35 <div id="options">
36 <a href="/editor" class="button">Online Diff</a>
37 <a href="/download" class="button">Download</a>
38 </div>
39 <nav>
40 <ul>
41 <li><a href="/">Home</a></li> <li><a href="/doc">Documentation</a></li> <li><a href="/about">About Mergely</a></li> <li><a href="/license">License</a></li> <li><a href="#footer">Contact</a></li> </ul>
42 </nav>
43 </div>
44
45 <div id="main">
46 <h1>Mergely License</h1>
47 <p>
48 All Mergely code is Copyright 2014 by Jamie Peabody.
49 Mergely is distributed under the
50 <a href="http://www.gnu.org/licenses/gpl.html">GPL</a>,
51 <a href="http://www.gnu.org/licenses/lgpl.html">LGPL</a>
52 and
53 <a href="http://www.mozilla.org/MPL/MPL-1.1.html">MPL</a> open source licenses.
54 This triple <b>copyleft</b> licensing model avoids incompatibility with other open
55 source licenses. These open source licenses are specially indicated for:
56 <ul>
57 <li>Integrating Mergely into Open Source software;</li>
58 <li>Personal and educational use of Mergely;</li>
59 <li>
60 Integrating Mergely in commercial software, taking care of satisfying
61 the Open Source licenses terms, while not able or interested on supporting
62 Mergely and its development.
63 </li>
64 </ul>
65 </p>
66 <h2>Mergely Commercial License - Closed Distribution License - CDL</h2>
67 <p>
68 You may contact <a href="mailto:jamie.peabody@gmail.com">Jamie Peabody</a> to enquire about
69 obtaining a CDL license.
70 </p>
71 <p>
72 This license offers a very flexible way to integrate Mergely in your commercial
73 application. These are the main advantages it offers over an Open Source license:
74 </p>
75 <p>
76 Modifications and enhancements do not need to be released under an Open
77 Source license; There is no need to distribute any Open Source license terms
78 along with your product and no reference to it have to be done; You do not have
79 to mention any reference to Mergely in your product; Mergely source code does not
80 have to be distributed with your product; You can remove any file from Mergely
81 when integrating it with your product.
82 </p>
83 <p>
84 The CDL is a lifetime license valid for all previous releases of Mergely published
85 prior to the year of purchase, and any releases in the following year. Please select
86 the license option that best fit your needs above. It includes 1 year of
87 <b>personal e-mail support</b>.
88 </p>
89 <h2>Third party codes</h2>
90 <p>
91 Mergely utilizes <b>CodeMirror</b>, a third-party library released under an
92 <a href="http://en.wikipedia.org/wiki/MIT_License">MIT</a>
93 license. Also used is <b>jQuery</b> and is released under the
94 <a href="http://en.wikipedia.org/wiki/MIT_License">MIT</a> or
95 <a href="http://www.gnu.org/licenses/gpl.html">GPL</a> Version 2 license.
96 </p>
97 </div>
98
99 <div id="footer">
100 <a href="/download" class="download">Download</a>
101 <ul>
102 <li id="google-plus"><a target="_blank" href="http://groups.google.com/group/mergely">http://groups.google.com/group/mergely</a></li>
103 <li id="github"><a target="_blank" href="https://github.com/wickedest/Mergely">https://github.com/wickedest/Mergely</a></li>
104 <li id="email"><a target="_blank" href="mailto:jamie.peabody@gmail.com">jamie.peabody@gmail.com</a></li>
105 </ul>
106 </div>
107 </div>
108 <div id="copyright">By <b>Jamie Peabody</b></div>
109 </div>
110 </body>
111 </html>
@@ -55,4 +55,16 b' It is Copyright 2013 jQuery Foundation a'
55
55
56
56
57
57
58 Mergely
59 -------
60
61 Kallithea incorporates some code from the Javascript system called
62 [Mergely](http://http://www.mergely.com/).
63 [Mergely's license](http://www.mergely.com/license.php), a
64 [copy of which is included in this repository](LICENSE-MERGELY.html),
65 is (GPL|LGPL|MPL). Kallithea as GPLv3'd project chooses the GPL arm of that
66 tri-license.
67
68
69
58 EOF
70 EOF
@@ -1,3 +1,11 b''
1 /**
2 * Copyright (c) 2013 by Jamie Peabody, http://www.mergely.com
3 * All rights reserved.
4 * Version: 3.3.4 2013-11-02
5 *
6 * NOTE by bkuhn@sfconservancy.org for Kallithea:
7 * Mergely license appears at http://www.mergely.com/license.php and in LICENSE-MERGELY.html
8 */
1
9
2 /* required */
10 /* required */
3 .mergely-column textarea { width: 80px; height: 200px; }
11 .mergely-column textarea { width: 80px; height: 200px; }
@@ -12,17 +20,17 b''
12 .mergely-column { border: 1px solid #ccc; }
20 .mergely-column { border: 1px solid #ccc; }
13 .mergely-active { border: 1px solid #a3d1ff; }
21 .mergely-active { border: 1px solid #a3d1ff; }
14
22
15 .mergely.a.rhs.start { border-top: 1px solid #ddffdd; }
23 .mergely.a.rhs.start { border-top: 1px solid #a3d1ff; }
16 .mergely.a.lhs.start.end,
24 .mergely.a.lhs.start.end,
17 .mergely.a.rhs.end { border-bottom: 1px solid #ddffdd; }
25 .mergely.a.rhs.end { border-bottom: 1px solid #a3d1ff; }
18 .mergely.a.rhs { background-color: #ddffdd; }
26 .mergely.a.rhs { background-color: #ddeeff; }
19 .mergely.a.lhs.start.end.first { border-bottom: 0; border-top: 1px solid #ddffdd; }
27 .mergely.a.lhs.start.end.first { border-bottom: 0; border-top: 1px solid #a3d1ff; }
20
28
21 .mergely.d.lhs { background-color: #edc0c0; }
29 .mergely.d.lhs { background-color: #edc0c0; }
22 .mergely.d.lhs.end,
30 .mergely.d.lhs.end,
23 .mergely.d.rhs.start.end { border-bottom: 1px solid #ffdddd; }
31 .mergely.d.rhs.start.end { border-bottom: 1px solid #ff7f7f; }
24 .mergely.d.rhs.start.end.first { border-bottom: 0; border-top: 1px solid #ffdddd; }
32 .mergely.d.rhs.start.end.first { border-bottom: 0; border-top: 1px solid #ff7f7f; }
25 .mergely.d.lhs.start { border-top: 1px solid #ffdddd; }
33 .mergely.d.lhs.start { border-top: 1px solid #ff7f7f; }
26
34
27 .mergely.c.lhs,
35 .mergely.c.lhs,
28 .mergely.c.rhs { background-color: #fafafa; }
36 .mergely.c.rhs { background-color: #fafafa; }
@@ -31,11 +39,5 b''
31 .mergely.c.lhs.end,
39 .mergely.c.lhs.end,
32 .mergely.c.rhs.end { border-bottom: 1px solid #a3a3a3; }
40 .mergely.c.rhs.end { border-bottom: 1px solid #a3a3a3; }
33
41
34 .mergely.ch.a.rhs { background-color: #ddffdd; }
42 .mergely.ch.a.rhs { background-color: #ddeeff; }
35 .mergely.ch.d.lhs { background-color: #ffdddd; }
43 .mergely.ch.d.lhs { background-color: #edc0c0; text-decoration: line-through; color: #888; }
36
37
38 .mergely-margin #compare-lhs-margin,
39 .mergely-margin #compare-rhs-margin {
40 cursor: pointer
41 }
@@ -1,3 +1,11 b''
1 /**
2 * Copyright (c) 2013 by Jamie Peabody, http://www.mergely.com
3 * All rights reserved.
4 * Version: 3.3.4 2013-11-02
5 *
6 * NOTE by bkuhn@sfconservancy.org for Kallithea:
7 * Mergely license appears at http://www.mergely.com/license.php and in LICENSE-MERGELY.html
8 */
1 Mgly = {};
9 Mgly = {};
2
10
3 Mgly.Timer = function(){
11 Mgly.Timer = function(){
@@ -54,18 +62,18 b' Mgly.LCS = function(x, y) {'
54 jQuery.extend(Mgly.LCS.prototype, {
62 jQuery.extend(Mgly.LCS.prototype, {
55 clear: function() { this.ready = 0; },
63 clear: function() { this.ready = 0; },
56 diff: function(added, removed) {
64 diff: function(added, removed) {
57 var d = new Mgly.diff(this.x, this.y, retain_lines = true, ignore_ws = false);
65 var d = new Mgly.diff(this.x, this.y, {ignorews: false});
58 var changes = Mgly.DiffParser(d.normal_form());
66 var changes = Mgly.DiffParser(d.normal_form());
59 var li = 0, lj = 0;
67 var li = 0, lj = 0;
60 for (var i = 0; i < changes.length; ++i) {
68 for (var i = 0; i < changes.length; ++i) {
61 var change = changes[i];
69 var change = changes[i];
62 if (change.op != 'a') {
70 if (change.op != 'a') {
63 // find the starting index of the line
71 // find the starting index of the line
64 li = d.lhs_lines.slice(0, change['lhs-line-from']).join(' ').length;
72 li = d.getLines('lhs').slice(0, change['lhs-line-from']).join(' ').length;
65 // get the index of the the span of the change
73 // get the index of the the span of the change
66 lj = change['lhs-line-to'] + 1;
74 lj = change['lhs-line-to'] + 1;
67 // get the changed text
75 // get the changed text
68 var lchange = d.lhs_lines.slice(change['lhs-line-from'], lj).join(' ');
76 var lchange = d.getLines('lhs').slice(change['lhs-line-from'], lj).join(' ');
69 if (change.op == 'd') lchange += ' ';// include the leading space
77 if (change.op == 'd') lchange += ' ';// include the leading space
70 else if (li > 0 && change.op == 'c') li += 1; // ignore leading space if not first word
78 else if (li > 0 && change.op == 'c') li += 1; // ignore leading space if not first word
71 // output the changed index and text
79 // output the changed index and text
@@ -73,11 +81,11 b' jQuery.extend(Mgly.LCS.prototype, {'
73 }
81 }
74 if (change.op != 'd') {
82 if (change.op != 'd') {
75 // find the starting index of the line
83 // find the starting index of the line
76 li = d.rhs_lines.slice(0, change['rhs-line-from']).join(' ').length;
84 li = d.getLines('lhs').slice(0, change['rhs-line-from']).join(' ').length;
77 // get the index of the the span of the change
85 // get the index of the the span of the change
78 lj = change['rhs-line-to'] + 1;
86 lj = change['rhs-line-to'] + 1;
79 // get the changed text
87 // get the changed text
80 var rchange = d.rhs_lines.slice(change['rhs-line-from'], lj).join(' ');
88 var rchange = d.getLines('lhs').slice(change['rhs-line-from'], lj).join(' ');
81 if (change.op == 'a') rchange += ' ';// include the leading space
89 if (change.op == 'a') rchange += ' ';// include the leading space
82 else if (li > 0 && change.op == 'c') li += 1; // ignore leading space if not first word
90 else if (li > 0 && change.op == 'c') li += 1; // ignore leading space if not first word
83 // output the changed index and text
91 // output the changed index and text
@@ -86,39 +94,83 b' jQuery.extend(Mgly.LCS.prototype, {'
86 }
94 }
87 }
95 }
88 });
96 });
89 Mgly.diff = function(lhs, rhs, retain_lines, ignore_ws) {
97
90 this.diff_codes = {};
98 Mgly.CodeifyText = function(settings) {
91 this.max_code = 0;
99 this._max_code = 0;
92 var lhs_lines = lhs.split('\n');
100 this._diff_codes = {};
93 var rhs_lines = rhs.split('\n');
101 this.ctxs = {};
94 if (lhs.length == 0) lhs_lines = [];
102 this.options = {ignorews: false};
95 if (rhs.length == 0) rhs_lines = [];
103 jQuery.extend(this, settings);
104 this.lhs = settings.lhs.split('\n');
105 this.rhs = settings.rhs.split('\n');
106 }
96
107
97 var lhs_data = new Object();
108 jQuery.extend(Mgly.CodeifyText.prototype, {
98 lhs_data.data = this._diff_codes(lhs_lines, ignore_ws);
109 getCodes: function(side) {
99 lhs_data.modified = {};
110 if (!this.ctxs.hasOwnProperty(side)) {
100 lhs_data.length = Mgly.sizeOf(lhs_data.data);
111 var ctx = this._diff_ctx(this[side]);
112 this.ctxs[side] = ctx;
113 ctx.codes.length = Object.keys(ctx.codes).length;
114 }
115 return this.ctxs[side].codes;
116 },
117 getLines: function(side) {
118 return this.ctxs[side].lines;
119 },
120 _diff_ctx: function(lines) {
121 var ctx = {i: 0, codes: {}, lines: lines};
122 this._codeify(lines, ctx);
123 return ctx;
124 },
125 _codeify: function(lines, ctx) {
126 var code = this._max_code;
127 for (var i = 0; i < lines.length; ++i) {
128 var line = lines[i];
129 if (this.options.ignorews) {
130 line = line.replace(/\s+/g, '');
131 }
132 var aCode = this._diff_codes[line];
133 if (aCode != undefined) {
134 ctx.codes[i] = aCode;
135 }
136 else {
137 this._max_code++;
138 this._diff_codes[line] = this._max_code;
139 ctx.codes[i] = this._max_code;
140 }
141 }
142 }
143 });
101
144
102 var rhs_data = new Object();
145 Mgly.diff = function(lhs, rhs, options) {
103 rhs_data.data = this._diff_codes(rhs_lines, ignore_ws);
146 var opts = jQuery.extend({ignorews: false}, options);
104 rhs_data.modified = {};
147 this.codeify = new Mgly.CodeifyText({
105 rhs_data.length = Mgly.sizeOf(rhs_data.data);
148 lhs: lhs,
106
149 rhs: rhs,
107 var max = (lhs_data.length + rhs_data.length + 1);
150 options: opts
151 });
152 var lhs_ctx = {
153 codes: this.codeify.getCodes('lhs'),
154 modified: {}
155 };
156 var rhs_ctx = {
157 codes: this.codeify.getCodes('rhs'),
158 modified: {}
159 };
160 var max = (lhs_ctx.codes.length + rhs_ctx.codes.length + 1);
108 var vector_d = Array( 2 * max + 2 );
161 var vector_d = Array( 2 * max + 2 );
109 var vector_u = Array( 2 * max + 2 );
162 var vector_u = Array( 2 * max + 2 );
163 this._lcs(lhs_ctx, 0, lhs_ctx.codes.length, rhs_ctx, 0, rhs_ctx.codes.length, vector_u, vector_d);
164 this._optimize(lhs_ctx);
165 this._optimize(rhs_ctx);
166 this.items = this._create_diffs(lhs_ctx, rhs_ctx);
167 };
110
168
111 this._lcs(lhs_data, 0, lhs_data.length, rhs_data, 0, rhs_data.length, vector_u, vector_d);
112 this._optimize(lhs_data);
113 this._optimize(rhs_data);
114 this.items = this._create_diffs(lhs_data, rhs_data);
115 if (retain_lines) {
116 this.lhs_lines = lhs_lines;
117 this.rhs_lines = rhs_lines;
118 }
119 };
120 jQuery.extend(Mgly.diff.prototype, {
169 jQuery.extend(Mgly.diff.prototype, {
121 changes: function() { return this.items; },
170 changes: function() { return this.items; },
171 getLines: function(side) {
172 return this.codeify.getLines(side);
173 },
122 normal_form: function() {
174 normal_form: function() {
123 var nf = '';
175 var nf = '';
124 for (var index = 0; index < this.items.length; ++index) {
176 for (var index = 0; index < this.items.length; ++index) {
@@ -150,53 +202,33 b' jQuery.extend(Mgly.diff.prototype, {'
150 }
202 }
151 return nf;
203 return nf;
152 },
204 },
153 _diff_codes: function(lines, ignore_ws) {
205 _lcs: function(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d) {
154 var code = this.max_code;
206 while ( (lhs_lower < lhs_upper) && (rhs_lower < rhs_upper) && (lhs_ctx.codes[lhs_lower] == rhs_ctx.codes[rhs_lower]) ) {
155 var codes = {};
156 for (var i = 0; i < lines.length; ++i) {
157 var line = lines[i];
158 if (ignore_ws) {
159 line = line.replace(/\s+/g, '');
160 }
161 var aCode = this.diff_codes[line];
162 if (aCode != undefined) {
163 codes[i] = aCode;
164 }
165 else {
166 this.max_code++;
167 this.diff_codes[line] = this.max_code;
168 codes[i] = this.max_code;
169 }
170 }
171 return codes;
172 },
173 _lcs: function(lhs, lhs_lower, lhs_upper, rhs, rhs_lower, rhs_upper, vector_u, vector_d) {
174 while ( (lhs_lower < lhs_upper) && (rhs_lower < rhs_upper) && (lhs.data[lhs_lower] == rhs.data[rhs_lower]) ) {
175 ++lhs_lower;
207 ++lhs_lower;
176 ++rhs_lower;
208 ++rhs_lower;
177 }
209 }
178 while ( (lhs_lower < lhs_upper) && (rhs_lower < rhs_upper) && (lhs.data[lhs_upper - 1] == rhs.data[rhs_upper - 1]) ) {
210 while ( (lhs_lower < lhs_upper) && (rhs_lower < rhs_upper) && (lhs_ctx.codes[lhs_upper - 1] == rhs_ctx.codes[rhs_upper - 1]) ) {
179 --lhs_upper;
211 --lhs_upper;
180 --rhs_upper;
212 --rhs_upper;
181 }
213 }
182 if (lhs_lower == lhs_upper) {
214 if (lhs_lower == lhs_upper) {
183 while (rhs_lower < rhs_upper) {
215 while (rhs_lower < rhs_upper) {
184 rhs.modified[ rhs_lower++ ] = true;
216 rhs_ctx.modified[ rhs_lower++ ] = true;
185 }
217 }
186 }
218 }
187 else if (rhs_lower == rhs_upper) {
219 else if (rhs_lower == rhs_upper) {
188 while (lhs_lower < lhs_upper) {
220 while (lhs_lower < lhs_upper) {
189 lhs.modified[ lhs_lower++ ] = true;
221 lhs_ctx.modified[ lhs_lower++ ] = true;
190 }
222 }
191 }
223 }
192 else {
224 else {
193 var sms = this._sms(lhs, lhs_lower, lhs_upper, rhs, rhs_lower, rhs_upper, vector_u, vector_d);
225 var sms = this._sms(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d);
194 this._lcs(lhs, lhs_lower, sms.x, rhs, rhs_lower, sms.y, vector_u, vector_d);
226 this._lcs(lhs_ctx, lhs_lower, sms.x, rhs_ctx, rhs_lower, sms.y, vector_u, vector_d);
195 this._lcs(lhs, sms.x, lhs_upper, rhs, sms.y, rhs_upper, vector_u, vector_d);
227 this._lcs(lhs_ctx, sms.x, lhs_upper, rhs_ctx, sms.y, rhs_upper, vector_u, vector_d);
196 }
228 }
197 },
229 },
198 _sms: function(lhs, lhs_lower, lhs_upper, rhs, rhs_lower, rhs_upper, vector_u, vector_d) {
230 _sms: function(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d) {
199 var max = lhs.length + rhs.length + 1;
231 var max = lhs_ctx.codes.length + rhs_ctx.codes.length + 1;
200 var kdown = lhs_lower - rhs_lower;
232 var kdown = lhs_lower - rhs_lower;
201 var kup = lhs_upper - rhs_upper;
233 var kup = lhs_upper - rhs_upper;
202 var delta = (lhs_upper - lhs_lower) - (rhs_upper - rhs_lower);
234 var delta = (lhs_upper - lhs_lower) - (rhs_upper - rhs_lower);
@@ -221,7 +253,7 b' jQuery.extend(Mgly.diff.prototype, {'
221 }
253 }
222 y = x - k;
254 y = x - k;
223 // find the end of the furthest reaching forward D-path in diagonal k.
255 // find the end of the furthest reaching forward D-path in diagonal k.
224 while ((x < lhs_upper) && (y < rhs_upper) && (lhs.data[x] == rhs.data[y])) {
256 while ((x < lhs_upper) && (y < rhs_upper) && (lhs_ctx.codes[x] == rhs_ctx.codes[y])) {
225 x++; y++;
257 x++; y++;
226 }
258 }
227 vector_d[ offset_down + k ] = x;
259 vector_d[ offset_down + k ] = x;
@@ -246,7 +278,7 b' jQuery.extend(Mgly.diff.prototype, {'
246 x = vector_u[offset_up + k - 1]; // up
278 x = vector_u[offset_up + k - 1]; // up
247 }
279 }
248 y = x - k;
280 y = x - k;
249 while ((x > lhs_lower) && (y > rhs_lower) && (lhs.data[x - 1] == rhs.data[y - 1])) {
281 while ((x > lhs_lower) && (y > rhs_lower) && (lhs_ctx.codes[x - 1] == rhs_ctx.codes[y - 1])) {
250 // diagonal
282 // diagonal
251 x--;
283 x--;
252 y--;
284 y--;
@@ -264,33 +296,33 b' jQuery.extend(Mgly.diff.prototype, {'
264 }
296 }
265 throw "the algorithm should never come here.";
297 throw "the algorithm should never come here.";
266 },
298 },
267 _optimize: function(data) {
299 _optimize: function(ctx) {
268 var start = 0, end = 0;
300 var start = 0, end = 0;
269 while (start < data.length) {
301 while (start < ctx.length) {
270 while ((start < data.length) && (data.modified[start] == undefined || data.modified[start] == false)) {
302 while ((start < ctx.length) && (ctx.modified[start] == undefined || ctx.modified[start] == false)) {
271 start++;
303 start++;
272 }
304 }
273 end = start;
305 end = start;
274 while ((end < data.length) && (data.modified[end] == true)) {
306 while ((end < ctx.length) && (ctx.modified[end] == true)) {
275 end++;
307 end++;
276 }
308 }
277 if ((end < data.length) && (data.data[start] == data.data[end])) {
309 if ((end < ctx.length) && (ctx.ctx[start] == ctx.codes[end])) {
278 data.modified[start] = false;
310 ctx.modified[start] = false;
279 data.modified[end] = true;
311 ctx.modified[end] = true;
280 }
312 }
281 else {
313 else {
282 start = end;
314 start = end;
283 }
315 }
284 }
316 }
285 },
317 },
286 _create_diffs: function(lhs_data, rhs_data) {
318 _create_diffs: function(lhs_ctx, rhs_ctx) {
287 var items = [];
319 var items = [];
288 var lhs_start = 0, rhs_start = 0;
320 var lhs_start = 0, rhs_start = 0;
289 var lhs_line = 0, rhs_line = 0;
321 var lhs_line = 0, rhs_line = 0;
290
322
291 while (lhs_line < lhs_data.length || rhs_line < rhs_data.length) {
323 while (lhs_line < lhs_ctx.codes.length || rhs_line < rhs_ctx.codes.length) {
292 if ((lhs_line < lhs_data.length) && (!lhs_data.modified[lhs_line])
324 if ((lhs_line < lhs_ctx.codes.length) && (!lhs_ctx.modified[lhs_line])
293 && (rhs_line < rhs_data.length) && (!rhs_data.modified[rhs_line])) {
325 && (rhs_line < rhs_ctx.codes.length) && (!rhs_ctx.modified[rhs_line])) {
294 // equal lines
326 // equal lines
295 lhs_line++;
327 lhs_line++;
296 rhs_line++;
328 rhs_line++;
@@ -300,20 +332,20 b' jQuery.extend(Mgly.diff.prototype, {'
300 lhs_start = lhs_line;
332 lhs_start = lhs_line;
301 rhs_start = rhs_line;
333 rhs_start = rhs_line;
302
334
303 while (lhs_line < lhs_data.length && (rhs_line >= rhs_data.length || lhs_data.modified[lhs_line]))
335 while (lhs_line < lhs_ctx.codes.length && (rhs_line >= rhs_ctx.codes.length || lhs_ctx.modified[lhs_line]))
304 lhs_line++;
336 lhs_line++;
305
337
306 while (rhs_line < rhs_data.length && (lhs_line >= lhs_data.length || rhs_data.modified[rhs_line]))
338 while (rhs_line < rhs_ctx.codes.length && (lhs_line >= lhs_ctx.codes.length || rhs_ctx.modified[rhs_line]))
307 rhs_line++;
339 rhs_line++;
308
340
309 if ((lhs_start < lhs_line) || (rhs_start < rhs_line)) {
341 if ((lhs_start < lhs_line) || (rhs_start < rhs_line)) {
310 // store a new difference-item
342 // store a new difference-item
311 var aItem = new Object();
343 items.push({
312 aItem.lhs_start = lhs_start;
344 lhs_start: lhs_start,
313 aItem.rhs_start = rhs_start;
345 rhs_start: rhs_start,
314 aItem.lhs_deleted_count = lhs_line - lhs_start;
346 lhs_deleted_count: lhs_line - lhs_start,
315 aItem.rhs_inserted_count = rhs_line - rhs_start;
347 rhs_inserted_count: rhs_line - rhs_start
316 items.push(aItem);
348 });
317 }
349 }
318 }
350 }
319 }
351 }
@@ -322,12 +354,6 b' jQuery.extend(Mgly.diff.prototype, {'
322 });
354 });
323
355
324 Mgly.mergely = function(el, options) {
356 Mgly.mergely = function(el, options) {
325 CodeMirror.defineExtension('centerOnCursor', function() {
326 var coords = this.cursorCoords(null, 'local');
327 this.scrollTo(null,
328 (coords.y + coords.yBot) / 2 - (this.getScrollerElement().clientHeight / 2));
329 });
330
331 if (el) {
357 if (el) {
332 this.init(el, options);
358 this.init(el, options);
333 }
359 }
@@ -337,6 +363,25 b' jQuery.extend(Mgly.mergely.prototype, {'
337 name: 'mergely',
363 name: 'mergely',
338 //http://jupiterjs.com/news/writing-the-perfect-jquery-plugin
364 //http://jupiterjs.com/news/writing-the-perfect-jquery-plugin
339 init: function(el, options) {
365 init: function(el, options) {
366 this.diffView = new Mgly.CodeMirrorDiffView(el, options);
367 this.bind(el);
368 },
369 bind: function(el) {
370 this.diffView.bind(el);
371 }
372 });
373
374 Mgly.CodeMirrorDiffView = function(el, options) {
375 CodeMirror.defineExtension('centerOnCursor', function() {
376 var coords = this.cursorCoords(null, 'local');
377 this.scrollTo(null,
378 (coords.y + coords.yBot) / 2 - (this.getScrollerElement().clientHeight / 2));
379 });
380 this.init(el, options);
381 };
382
383 jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
384 init: function(el, options) {
340 this.settings = {
385 this.settings = {
341 autoupdate: true,
386 autoupdate: true,
342 autoresize: true,
387 autoresize: true,
@@ -352,14 +397,14 b' jQuery.extend(Mgly.mergely.prototype, {'
352 change_timeout: 150,
397 change_timeout: 150,
353 fgcolor: {a:'#4ba3fa',c:'#a3a3a3',d:'#ff7f7f'},
398 fgcolor: {a:'#4ba3fa',c:'#a3a3a3',d:'#ff7f7f'},
354 bgcolor: '#eee',
399 bgcolor: '#eee',
355 vpcolor: 'rgba(0, 0, 200, 0.2)',
400 vpcolor: 'rgba(0, 0, 200, 0.5)',
356 lhs: function(setValue) { },
401 lhs: function(setValue) { },
357 rhs: function(setValue) { },
402 rhs: function(setValue) { },
358 loaded: function() { },
403 loaded: function() { },
359 //_auto_height: function(h) { return h - 20; },
404 //_auto_height: function(h) { return h - 20; },
360 _auto_width: function(w) { return w; },
405 _auto_width: function(w) { return w; },
361 resize: function(init) {
406 resize: function(init) {
362 var scrollbar = init ? -15 : 0;
407 var scrollbar = init ? 16 : 0;
363 var w = jQuery(el).parent().width() + scrollbar;
408 var w = jQuery(el).parent().width() + scrollbar;
364 if (this.width == 'auto') {
409 if (this.width == 'auto') {
365 w = this._auto_width(w);
410 w = this._auto_width(w);
@@ -415,53 +460,8 b' jQuery.extend(Mgly.mergely.prototype, {'
415 // bind if the element is destroyed
460 // bind if the element is destroyed
416 this.element.bind('destroyed', jQuery.proxy(this.teardown, this));
461 this.element.bind('destroyed', jQuery.proxy(this.teardown, this));
417
462
418 // save this instance in jQuery data
463 // save this instance in jQuery data, binding this view to the node
419 jQuery.data(el, this.name, this);
464 jQuery.data(el, 'mergely', this);
420
421 this._setup(el);
422 },
423 // bind events to this instance's methods
424 bind: function() {
425 var rhstx = jQuery('#' + this.id + '-rhs').get(0);
426 if (!rhstx) {
427 console.error('rhs textarea not defined - Mergely not initialized properly');
428 return;
429 }
430 var lhstx = jQuery('#' + this.id + '-lhs').get(0);
431 if (!rhstx) {
432 console.error('lhs textarea not defined - Mergely not initialized properly');
433 return;
434 }
435 var self = this;
436 this.editor = [];
437
438 this.editor[this.id + '-lhs'] = CodeMirror.fromTextArea(lhstx, this.lhs_cmsettings);
439 this.editor[this.id + '-rhs'] = CodeMirror.fromTextArea(rhstx, this.rhs_cmsettings);
440 this.editor[this.id + '-lhs'].on('change', function(){ if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); });
441 this.editor[this.id + '-lhs'].on('scroll', function(){ self._scrolling(self.id + '-lhs'); });
442 this.editor[this.id + '-rhs'].on('change', function(){ if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); });
443 this.editor[this.id + '-rhs'].on('scroll', function(){ self._scrolling(self.id + '-rhs'); });
444
445 // resize
446 if (this.settings.autoresize) {
447 var sz_timeout1 = null;
448 var sz = function(init) {
449 //self.em_height = null; //recalculate
450 if (self.settings.resize) self.settings.resize(init);
451 self.editor[self.id + '-lhs'].refresh();
452 self.editor[self.id + '-rhs'].refresh();
453 if (self.settings.autoupdate) {
454 self._changing(self.id + '-lhs', self.id + '-rhs');
455 }
456 }
457 jQuery(window).resize(
458 function () {
459 if (sz_timeout1) clearTimeout(sz_timeout1);
460 sz_timeout1 = setTimeout(sz, self.settings.resize_timeout);
461 }
462 );
463 sz(true);
464 }
465 },
465 },
466 unbind: function() {
466 unbind: function() {
467 if (this.changed_timeout != null) clearTimeout(this.changed_timeout);
467 if (this.changed_timeout != null) clearTimeout(this.changed_timeout);
@@ -502,11 +502,11 b' jQuery.extend(Mgly.mergely.prototype, {'
502 options: function(opts) {
502 options: function(opts) {
503 if (opts) {
503 if (opts) {
504 jQuery.extend(this.settings, opts);
504 jQuery.extend(this.settings, opts);
505 if (opts.autoresize) this.resize();
505 if (this.settings.autoresize) this.resize();
506 if (opts.autoupdate) this.update();
506 if (this.settings.autoupdate) this.update();
507 if (opts.hasOwnProperty('rhs_margin')) {
507 if (this.settings.hasOwnProperty('rhs_margin')) {
508 // dynamically swap the margin
508 // dynamically swap the margin
509 if (opts.rhs_margin == 'left') {
509 if (this.settings.rhs_margin == 'left') {
510 this.element.find('.mergely-margin:last-child').insertAfter(
510 this.element.find('.mergely-margin:last-child').insertAfter(
511 this.element.find('.mergely-canvas'));
511 this.element.find('.mergely-canvas'));
512 }
512 }
@@ -515,9 +515,9 b' jQuery.extend(Mgly.mergely.prototype, {'
515 target.appendTo(target.parent());
515 target.appendTo(target.parent());
516 }
516 }
517 }
517 }
518 if (opts.hasOwnProperty('sidebar')) {
518 if (this.settings.hasOwnProperty('sidebar')) {
519 // dynamically enable sidebars
519 // dynamically enable sidebars
520 if (opts.sidebar) {
520 if (this.settings.sidebar) {
521 jQuery(this.element).find('.mergely-margin').css({display: 'block'});
521 jQuery(this.element).find('.mergely-margin').css({display: 'block'});
522 }
522 }
523 else {
523 else {
@@ -581,14 +581,15 b' jQuery.extend(Mgly.mergely.prototype, {'
581 resize: function() {
581 resize: function() {
582 this.settings.resize();
582 this.settings.resize();
583 this._changing(this.id + '-lhs', this.id + '-rhs');
583 this._changing(this.id + '-lhs', this.id + '-rhs');
584 this._set_top_offset(this.id + '-lhs');
584 },
585 },
585 diff: function() {
586 diff: function() {
586 var lhs = this.editor[this.id + '-lhs'].getValue();
587 var lhs = this.editor[this.id + '-lhs'].getValue();
587 var rhs = this.editor[this.id + '-rhs'].getValue();
588 var rhs = this.editor[this.id + '-rhs'].getValue();
588 var d = new Mgly.diff(lhs, rhs, retain_lines = true, ignore_ws = this.settings.ignorews);
589 var d = new Mgly.diff(lhs, rhs, this.settings);
589 return d.normal_form();
590 return d.normal_form();
590 },
591 },
591 _setup: function(el) {
592 bind: function(el) {
592 jQuery(this.element).hide();//hide
593 jQuery(this.element).hide();//hide
593 this.id = jQuery(el).attr('id');
594 this.id = jQuery(el).attr('id');
594 var height = this.settings.editor_height;
595 var height = this.settings.editor_height;
@@ -640,7 +641,48 b' jQuery.extend(Mgly.mergely.prototype, {'
640 cmstyle += this.id + ' .CodeMirror-scroll { height: 100%; overflow: auto; }';
641 cmstyle += this.id + ' .CodeMirror-scroll { height: 100%; overflow: auto; }';
641 }
642 }
642 jQuery('<style type="text/css">' + cmstyle + '</style>').appendTo('head');
643 jQuery('<style type="text/css">' + cmstyle + '</style>').appendTo('head');
643 this.bind();
644
645 //bind
646 var rhstx = jQuery('#' + this.id + '-rhs').get(0);
647 if (!rhstx) {
648 console.error('rhs textarea not defined - Mergely not initialized properly');
649 return;
650 }
651 var lhstx = jQuery('#' + this.id + '-lhs').get(0);
652 if (!rhstx) {
653 console.error('lhs textarea not defined - Mergely not initialized properly');
654 return;
655 }
656 var self = this;
657 this.editor = [];
658 this.editor[this.id + '-lhs'] = CodeMirror.fromTextArea(lhstx, this.lhs_cmsettings);
659 this.editor[this.id + '-rhs'] = CodeMirror.fromTextArea(rhstx, this.rhs_cmsettings);
660 this.editor[this.id + '-lhs'].on('change', function(){ if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); });
661 this.editor[this.id + '-lhs'].on('scroll', function(){ self._scrolling(self.id + '-lhs'); });
662 this.editor[this.id + '-rhs'].on('change', function(){ if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); });
663 this.editor[this.id + '-rhs'].on('scroll', function(){ self._scrolling(self.id + '-rhs'); });
664 // resize
665 if (this.settings.autoresize) {
666 var sz_timeout1 = null;
667 var sz = function(init) {
668 //self.em_height = null; //recalculate
669 if (self.settings.resize) self.settings.resize(init);
670 self.editor[self.id + '-lhs'].refresh();
671 self.editor[self.id + '-rhs'].refresh();
672 if (self.settings.autoupdate) {
673 self._changing(self.id + '-lhs', self.id + '-rhs');
674 }
675 }
676 jQuery(window).resize(
677 function () {
678 if (sz_timeout1) clearTimeout(sz_timeout1);
679 sz_timeout1 = setTimeout(sz, self.settings.resize_timeout);
680 }
681 );
682 sz(true);
683 }
684 //bind
685
644 if (this.settings.lhs) {
686 if (this.settings.lhs) {
645 var setv = this.editor[this.id + '-lhs'].getDoc().setValue;
687 var setv = this.editor[this.id + '-lhs'].getDoc().setValue;
646 this.settings.lhs(setv.bind(this.editor[this.id + '-lhs'].getDoc()));
688 this.settings.lhs(setv.bind(this.editor[this.id + '-lhs'].getDoc()));
@@ -803,7 +845,7 b' jQuery.extend(Mgly.mergely.prototype, {'
803 var lhs = this.editor[editor_name1].getValue();
845 var lhs = this.editor[editor_name1].getValue();
804 var rhs = this.editor[editor_name2].getValue();
846 var rhs = this.editor[editor_name2].getValue();
805 var timer = new Mgly.Timer();
847 var timer = new Mgly.Timer();
806 var d = new Mgly.diff(lhs, rhs, false, this.settings.ignorews);
848 var d = new Mgly.diff(lhs, rhs, this.settings);
807 this.trace('change', 'diff time', timer.stop());
849 this.trace('change', 'diff time', timer.stop());
808 this.changes = Mgly.DiffParser(d.normal_form());
850 this.changes = Mgly.DiffParser(d.normal_form());
809 this.trace('change', 'parse time', timer.stop());
851 this.trace('change', 'parse time', timer.stop());
@@ -861,13 +903,27 b' jQuery.extend(Mgly.mergely.prototype, {'
861 }
903 }
862 return true;
904 return true;
863 },
905 },
906 _set_top_offset: function (editor_name1) {
907 // save the current scroll position of the editor
908 var saveY = this.editor[editor_name1].getScrollInfo().top;
909 // temporarily scroll to top
910 this.editor[editor_name1].scrollTo(null, 0);
911
912 // this is the distance from the top of the screen to the top of the
913 // content of the first codemirror editor
914 var topnode = jQuery('#' + this.id + ' .CodeMirror-measure').first();
915 var top_offset = topnode.offset().top - 4;
916 if(!top_offset) return false;
917
918 // restore editor's scroll position
919 this.editor[editor_name1].scrollTo(null, saveY);
920
921 this.draw_top_offset = 0.5 - top_offset;
922 return true;
923 },
864 _calculate_offsets: function (editor_name1, editor_name2, changes) {
924 _calculate_offsets: function (editor_name1, editor_name2, changes) {
865 if (this.em_height == null) {
925 if (this.em_height == null) {
866 // this is the distance from the top of the screen
926 if(!this._set_top_offset(editor_name1)) return; //try again
867 var topnode = jQuery('#' + this.id + ' .CodeMirror-measure').first();
868 var top_offset = topnode.offset().top - 4;
869 if (!top_offset) return;//try again
870 this.draw_top_offset = 0.5 - top_offset;
871 this.em_height = this.editor[editor_name1].defaultTextHeight();
927 this.em_height = this.editor[editor_name1].defaultTextHeight();
872 if (!this.em_height) {
928 if (!this.em_height) {
873 console.warn('Failed to calculate offsets, using 18 by default');
929 console.warn('Failed to calculate offsets, using 18 by default');
@@ -886,7 +942,7 b' jQuery.extend(Mgly.mergely.prototype, {'
886 this.draw_rhs_max = this.draw_mid_width - 0.5; //24.5;
942 this.draw_rhs_max = this.draw_mid_width - 0.5; //24.5;
887 this.draw_lhs_width = 5;
943 this.draw_lhs_width = 5;
888 this.draw_rhs_width = 5;
944 this.draw_rhs_width = 5;
889 this.trace('calc', 'change offsets calculated', {top_offset: top_offset, lhs_min: this.draw_lhs_min, rhs_max: this.draw_rhs_max, lhs_width: this.draw_lhs_width, rhs_width: this.draw_rhs_width});
945 this.trace('calc', 'change offsets calculated', {top_offset: this.draw_top_offset, lhs_min: this.draw_lhs_min, rhs_max: this.draw_rhs_max, lhs_width: this.draw_lhs_width, rhs_width: this.draw_rhs_width});
890 }
946 }
891 var lhschc = this.editor[editor_name1].charCoords({line: 0});
947 var lhschc = this.editor[editor_name1].charCoords({line: 0});
892 var rhschc = this.editor[editor_name2].charCoords({line: 0});
948 var rhschc = this.editor[editor_name2].charCoords({line: 0});
@@ -1295,14 +1351,14 b' jQuery.extend(Mgly.mergely.prototype, {'
1295 ctx_lhs.beginPath();
1351 ctx_lhs.beginPath();
1296 ctx_lhs.fillStyle = this.settings.fgcolor[change['op']];
1352 ctx_lhs.fillStyle = this.settings.fgcolor[change['op']];
1297 ctx_lhs.strokeStyle = '#000';
1353 ctx_lhs.strokeStyle = '#000';
1298 ctx_lhs.lineWidth = 1.0;
1354 ctx_lhs.lineWidth = 0.5;
1299 ctx_lhs.fillRect(1.5, lhs_y_start, 4.5, Math.max(lhs_y_end - lhs_y_start, 5));
1355 ctx_lhs.fillRect(1.5, lhs_y_start, 4.5, Math.max(lhs_y_end - lhs_y_start, 5));
1300 ctx_lhs.strokeRect(1.5, lhs_y_start, 4.5, Math.max(lhs_y_end - lhs_y_start, 5));
1356 ctx_lhs.strokeRect(1.5, lhs_y_start, 4.5, Math.max(lhs_y_end - lhs_y_start, 5));
1301
1357
1302 ctx_rhs.beginPath();
1358 ctx_rhs.beginPath();
1303 ctx_rhs.fillStyle = this.settings.fgcolor[change['op']];
1359 ctx_rhs.fillStyle = this.settings.fgcolor[change['op']];
1304 ctx_rhs.strokeStyle = '#000';
1360 ctx_rhs.strokeStyle = '#000';
1305 ctx_rhs.lineWidth = 1.0;
1361 ctx_rhs.lineWidth = 0.5;
1306 ctx_rhs.fillRect(1.5, rhs_y_start, 4.5, Math.max(rhs_y_end - rhs_y_start, 5));
1362 ctx_rhs.fillRect(1.5, rhs_y_start, 4.5, Math.max(rhs_y_end - rhs_y_start, 5));
1307 ctx_rhs.strokeRect(1.5, rhs_y_start, 4.5, Math.max(rhs_y_end - rhs_y_start, 5));
1363 ctx_rhs.strokeRect(1.5, rhs_y_start, 4.5, Math.max(rhs_y_end - rhs_y_start, 5));
1308
1364
@@ -4,11 +4,11 b''
4
4
5 <%def name="js_extra()">
5 <%def name="js_extra()">
6 <script type="text/javascript" src="${h.url('/js/codemirror.js')}"></script>
6 <script type="text/javascript" src="${h.url('/js/codemirror.js')}"></script>
7 <script type="text/javascript" src="${h.url('/js/mergerly.js')}"></script>
7 <script type="text/javascript" src="${h.url('/js/mergely.js')}"></script>
8 </%def>
8 </%def>
9 <%def name="css_extra()">
9 <%def name="css_extra()">
10 <link rel="stylesheet" type="text/css" href="${h.url('/css/codemirror.css')}"/>
10 <link rel="stylesheet" type="text/css" href="${h.url('/css/codemirror.css')}"/>
11 <link rel="stylesheet" type="text/css" href="${h.url('/css/mergerly.css')}"/>
11 <link rel="stylesheet" type="text/css" href="${h.url('/css/mergely.css')}"/>
12 </%def>
12 </%def>
13
13
14 <%def name="title()">
14 <%def name="title()">
General Comments 0
You need to be logged in to leave comments. Login now