Changeset - aa3b55946089
[Not reviewed]
"Bradley M. Kuhn" - 12 years ago 2014-05-27 02:21:00
bkuhn@ebb.org
Migrate to Mergely 3.3.4.

RhodeCode 2.2.5 distributed Mergely 3.3.4 with some of the changes that
Mergely 3.3.3 in RhodeCode 1.7.2 also had. That do however not seem to be
changes we want for Kallithea this way and we take the 3.3.4 files as they are.

I've also included the Mergely license file, as downloaded from:
http://www.mergely.com/license.php

That LICENSE file is kept in HTML just as it was downloaded from their
website. While it's a bit annoying to keep the license file in HTML, this is
the way it came from upstream so we'll leave it that way.

Since the Javascript code is used with other GPLv3 Javascript, we are using the
GPL option of Mergely's tri-license.

Finally, note that previously, this was incorrectly called "mergerly", so the
opportunity is taken here to correct the name. That required changes to
diff_2way.html.

As commands::

$ wget -N --output-document LICENSE-MERGELY.html http://www.mergely.com/license.php
$ hg add LICENSE-MERGELY.html
$ hg mv rhodecode/public/css/mergerly.css rhodecode/public/css/mergely.css
$ hg mv rhodecode/public/js/mergerly.js rhodecode/public/js/mergely.js
$ sed -i 's,mergerly\.,mergely,g' rhodecode/templates/files/diff_2way.html
$ ( cd /tmp; \
wget -N http://www.mergely.com/releases/mergely-3.3.4.zip; \
unzip mergely-3.3.4.zip )
$ sha256sum /tmp/mergely-3.3.4.zip
87415d30494bbe829c248881aa7cdc0303f7e70b458a5f687615564d4498cc82 mergely-3.3.4.zip
$ cp /tmp/mergely-3.3.4/lib/mergely.js rhodecode/public/js/mergely.js
$ cp /tmp/mergely-3.3.4/lib/mergely.css rhodecode/public/css/mergely.css
$ sed -i -e '/^ \* Version/a\ *\n * NOTE by bkuhn@sfconservancy.org for Kallithea:\n * Mergely license appears at http://www.mergely.com/license.php and in LICENSE-MERGELY.html' rhodecode/public/js/mergely.js rhodecode/public/css/mergely.css
5 files changed with 353 insertions and 172 deletions:
0 comments (0 inline, 0 general)
LICENSE-MERGELY.html
Show inline comments
 
new file 100644
 
<!DOCTYPE html>
 
<html lang="en">
 
<!--[if IE]>
 
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
 
<![endif]-->
 
<head>
 
	<meta charset="utf-8" /><title>Mergely License</title>
 
	<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
 
	<meta name="description" content="Mergely license requirements for open source software and commercial software" />
 
	<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" />
 
	<meta name="author" content="Jamie Peabody" />
 
	<meta name="author" content="Jamie Peabody" />
 
	<link rel="shortcut icon" href="http://www.mergely.com/favicon.ico" />
 
    <link href='http://fonts.googleapis.com/css?family=Noto+Sans:400,700' rel='stylesheet' type='text/css' />
 
    <link href='fonts/berlin-sans-fb-demi.css' rel='stylesheet' type='text/css' />
 
    <link href='style/mergely.css' rel='stylesheet' type='text/css' />
 
    <link href='/Mergely/lib/mergely.css' rel='stylesheet' type='text/css' />
 
	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
 
	<script type="text/javascript">
 
		var _gaq = _gaq || [];
 
		_gaq.push(['_setAccount', 'UA-85576-5']);
 
		_gaq.push(['_trackPageview']);
 
		(function() {
 
			var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
 
			ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
 
			var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
 
		})();
 
	</script>
 
</head>
 
<body>
 
    <div id="page">
 
        <div id="content">
 
            <div id="header">
 
                <h1><span>Mergely License - Closed Distribution License</span></h1>
 
                <div id="options">
 
                    <a href="/editor" class="button">Online Diff</a>
 
                    <a href="/download" class="button">Download</a>
 
                </div>
 
                <nav>
 
                    <ul>
 
                        <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>
 
                </nav>
 
            </div>
 

	
 
            <div id="main">
 
				<h1>Mergely License</h1>
 
				<p>
 
					All Mergely code is Copyright 2014 by Jamie Peabody.
 
					Mergely is distributed under the 
 
					<a href="http://www.gnu.org/licenses/gpl.html">GPL</a>, 
 
					<a href="http://www.gnu.org/licenses/lgpl.html">LGPL</a>
 
					and 
 
					<a href="http://www.mozilla.org/MPL/MPL-1.1.html">MPL</a> open source licenses. 
 
					This triple <b>copyleft</b> licensing model avoids incompatibility with other open 
 
					source licenses. These open source licenses are specially indicated for:
 
					<ul>
 
						<li>Integrating Mergely into Open Source software;</li>
 
						<li>Personal and educational use of Mergely;</li>
 
						<li>
 
							Integrating Mergely in commercial software, taking care of satisfying 
 
							the Open Source licenses terms, while not able or interested on supporting 
 
							Mergely and its development.
 
						</li>
 
					</ul>
 
				</p>
 
				<h2>Mergely Commercial License - Closed Distribution License - CDL</h2>
 
				<p>
 
					You may contact <a href="mailto:jamie.peabody@gmail.com">Jamie Peabody</a> to enquire about
 
					obtaining a CDL license.
 
				</p>
 
				<p>
 
					This license offers a very flexible way to integrate Mergely in your commercial 
 
					application. These are the main advantages it offers over an Open Source license:
 
				</p>
 
				<p>
 
					Modifications and enhancements do not need to be released under an Open 
 
					Source license; There is no need to distribute any Open Source license terms 
 
					along with your product and no reference to it have to be done; You do not have
 
					to mention any reference to Mergely in your product; Mergely source code does not
 
					have to be distributed with your product; You can remove any file from Mergely 
 
					when integrating it with your product.
 
				</p>
 
				<p>
 
					The CDL is a lifetime license valid for all previous releases of Mergely published 
 
                    prior to the year of purchase, and any releases in the following year. Please select 
 
                    the license option that best fit your needs above. It includes 1 year of 
 
                    <b>personal e-mail support</b>.
 
				</p>
 
				<h2>Third party codes</h2>
 
				<p>
 
					Mergely utilizes <b>CodeMirror</b>, a third-party library released under an 
 
					<a href="http://en.wikipedia.org/wiki/MIT_License">MIT</a>
 
					license.  Also used is <b>jQuery</b> and is released under the 
 
					<a href="http://en.wikipedia.org/wiki/MIT_License">MIT</a> or 
 
					<a href="http://www.gnu.org/licenses/gpl.html">GPL</a> Version 2 license.
 
				</p>
 
            </div>
 
            
 
            <div id="footer">
 
                <a href="/download" class="download">Download</a>
 
                <ul>
 
                    <li id="google-plus"><a target="_blank" href="http://groups.google.com/group/mergely">http://groups.google.com/group/mergely</a></li>
 
                    <li id="github"><a target="_blank" href="https://github.com/wickedest/Mergely">https://github.com/wickedest/Mergely</a></li>
 
                    <li id="email"><a target="_blank" href="mailto:jamie.peabody@gmail.com">jamie.peabody@gmail.com</a></li>
 
                </ul>
 
            </div>
 
        </div>
 
        <div id="copyright">By <b>Jamie Peabody</b></div>
 
    </div>
 
</body>
 
</html>
LICENSE.md
Show inline comments
 
@@ -55,4 +55,16 @@ It is Copyright 2013 jQuery Foundation a
 

	
 

	
 

	
 
Mergely
 
-------
 

	
 
Kallithea incorporates some code from the Javascript system called
 
[Mergely](http://http://www.mergely.com/).
 
[Mergely's license](http://www.mergely.com/license.php), a
 
[copy of which is included in this repository](LICENSE-MERGELY.html),
 
is (GPL|LGPL|MPL).  Kallithea as GPLv3'd project chooses the GPL arm of that
 
tri-license.
 

	
 

	
 

	
 
EOF
rhodecode/public/css/mergely.css
Show inline comments
 
file renamed from rhodecode/public/css/mergerly.css to rhodecode/public/css/mergely.css
 
/**
 
 * Copyright (c) 2013 by Jamie Peabody, http://www.mergely.com
 
 * All rights reserved.
 
 * Version: 3.3.4 2013-11-02
 
 *
 
 * NOTE by bkuhn@sfconservancy.org for Kallithea:
 
 * Mergely license appears at http://www.mergely.com/license.php and in LICENSE-MERGELY.html
 
 */
 

	
 
/* required */
 
.mergely-column textarea { width: 80px; height: 200px; }
 
@@ -12,17 +20,17 @@
 
.mergely-column { border: 1px solid #ccc; }
 
.mergely-active { border: 1px solid #a3d1ff; }
 

	
 
.mergely.a.rhs.start { border-top: 1px solid #ddffdd; }
 
.mergely.a.rhs.start { border-top: 1px solid #a3d1ff; }
 
.mergely.a.lhs.start.end,
 
.mergely.a.rhs.end { border-bottom: 1px solid #ddffdd; }
 
.mergely.a.rhs { background-color: #ddffdd; }
 
.mergely.a.lhs.start.end.first { border-bottom: 0; border-top: 1px solid #ddffdd; }
 
.mergely.a.rhs.end { border-bottom: 1px solid #a3d1ff; }
 
.mergely.a.rhs { background-color: #ddeeff; }
 
.mergely.a.lhs.start.end.first { border-bottom: 0; border-top: 1px solid #a3d1ff; }
 

	
 
.mergely.d.lhs { background-color: #edc0c0; }
 
.mergely.d.lhs.end,
 
.mergely.d.rhs.start.end { border-bottom: 1px solid #ffdddd; }
 
.mergely.d.rhs.start.end.first { border-bottom: 0; border-top: 1px solid #ffdddd; }
 
.mergely.d.lhs.start { border-top: 1px solid #ffdddd; }
 
.mergely.d.rhs.start.end { border-bottom: 1px solid #ff7f7f; }
 
.mergely.d.rhs.start.end.first { border-bottom: 0; border-top: 1px solid #ff7f7f; }
 
.mergely.d.lhs.start { border-top: 1px solid #ff7f7f; }
 

	
 
.mergely.c.lhs,
 
.mergely.c.rhs { background-color: #fafafa; }
 
@@ -31,11 +39,5 @@
 
.mergely.c.lhs.end,
 
.mergely.c.rhs.end { border-bottom: 1px solid #a3a3a3; }
 

	
 
.mergely.ch.a.rhs { background-color: #ddffdd; }
 
.mergely.ch.d.lhs { background-color: #ffdddd; }
 

	
 

	
 
.mergely-margin #compare-lhs-margin,
 
.mergely-margin #compare-rhs-margin {
 
    cursor: pointer
 
}
 
.mergely.ch.a.rhs { background-color: #ddeeff; }
 
.mergely.ch.d.lhs { background-color: #edc0c0; text-decoration: line-through; color: #888; }
rhodecode/public/js/mergely.js
Show inline comments
 
file renamed from rhodecode/public/js/mergerly.js to rhodecode/public/js/mergely.js
 
/**
 
 * Copyright (c) 2013 by Jamie Peabody, http://www.mergely.com
 
 * All rights reserved.
 
 * Version: 3.3.4 2013-11-02
 
 *
 
 * NOTE by bkuhn@sfconservancy.org for Kallithea:
 
 * Mergely license appears at http://www.mergely.com/license.php and in LICENSE-MERGELY.html
 
 */
 
Mgly = {};
 

	
 
Mgly.Timer = function(){
 
@@ -54,18 +62,18 @@ Mgly.LCS = function(x, y) {
 
jQuery.extend(Mgly.LCS.prototype, {
 
	clear: function() { this.ready = 0; },
 
	diff: function(added, removed) {
 
		var d = new Mgly.diff(this.x, this.y, retain_lines = true, ignore_ws = false);
 
		var d = new Mgly.diff(this.x, this.y, {ignorews: false});
 
		var changes = Mgly.DiffParser(d.normal_form());
 
		var li = 0, lj = 0;
 
		for (var i = 0; i < changes.length; ++i) {
 
			var change = changes[i];
 
			if (change.op != 'a') {
 
				// find the starting index of the line
 
				li = d.lhs_lines.slice(0, change['lhs-line-from']).join(' ').length;
 
				li = d.getLines('lhs').slice(0, change['lhs-line-from']).join(' ').length;
 
				// get the index of the the span of the change
 
				lj = change['lhs-line-to'] + 1;
 
				// get the changed text
 
				var lchange = d.lhs_lines.slice(change['lhs-line-from'], lj).join(' ');
 
				var lchange = d.getLines('lhs').slice(change['lhs-line-from'], lj).join(' ');
 
				if (change.op == 'd') lchange += ' ';// include the leading space
 
				else if (li > 0 && change.op == 'c') li += 1; // ignore leading space if not first word
 
				// output the changed index and text
 
@@ -73,11 +81,11 @@ jQuery.extend(Mgly.LCS.prototype, {
 
			}
 
			if (change.op != 'd') {
 
				// find the starting index of the line
 
				li = d.rhs_lines.slice(0, change['rhs-line-from']).join(' ').length;
 
				li = d.getLines('lhs').slice(0, change['rhs-line-from']).join(' ').length;
 
				// get the index of the the span of the change
 
				lj = change['rhs-line-to'] + 1;
 
				// get the changed text
 
				var rchange = d.rhs_lines.slice(change['rhs-line-from'], lj).join(' ');
 
				var rchange = d.getLines('lhs').slice(change['rhs-line-from'], lj).join(' ');
 
				if (change.op == 'a') rchange += ' ';// include the leading space
 
				else if (li > 0 && change.op == 'c') li += 1; // ignore leading space if not first word
 
				// output the changed index and text
 
@@ -86,39 +94,83 @@ jQuery.extend(Mgly.LCS.prototype, {
 
		}
 
	}
 
});
 
Mgly.diff = function(lhs, rhs, retain_lines, ignore_ws) {
 
	this.diff_codes = {};
 
	this.max_code = 0;
 
	var lhs_lines = lhs.split('\n');
 
	var rhs_lines = rhs.split('\n');
 
	if (lhs.length == 0) lhs_lines = [];
 
	if (rhs.length == 0) rhs_lines = [];
 

	
 
Mgly.CodeifyText = function(settings) {
 
    this._max_code = 0;
 
    this._diff_codes = {};
 
	this.ctxs = {};
 
	this.options = {ignorews: false};
 
	jQuery.extend(this, settings);
 
	this.lhs = settings.lhs.split('\n');
 
	this.rhs = settings.rhs.split('\n');
 
}
 

	
 
	var lhs_data = new Object();
 
	lhs_data.data = this._diff_codes(lhs_lines, ignore_ws);
 
	lhs_data.modified = {};
 
	lhs_data.length = Mgly.sizeOf(lhs_data.data);
 
jQuery.extend(Mgly.CodeifyText.prototype, {
 
	getCodes: function(side) {
 
		if (!this.ctxs.hasOwnProperty(side)) {
 
			var ctx = this._diff_ctx(this[side]);
 
			this.ctxs[side] = ctx;
 
			ctx.codes.length = Object.keys(ctx.codes).length;
 
		}
 
		return this.ctxs[side].codes;
 
	},
 
	getLines: function(side) {
 
		return this.ctxs[side].lines;
 
	},
 
	_diff_ctx: function(lines) {
 
		var ctx = {i: 0, codes: {}, lines: lines};
 
		this._codeify(lines, ctx);
 
		return ctx;
 
	},
 
	_codeify: function(lines, ctx) {
 
		var code = this._max_code;
 
		for (var i = 0; i < lines.length; ++i) {
 
			var line = lines[i];
 
			if (this.options.ignorews) {
 
				line = line.replace(/\s+/g, '');
 
			}
 
			var aCode = this._diff_codes[line];
 
			if (aCode != undefined) {
 
				ctx.codes[i] = aCode;
 
			}
 
			else {
 
				this._max_code++;
 
				this._diff_codes[line] = this._max_code;
 
				ctx.codes[i] = this._max_code;
 
			}
 
		}
 
	}
 
});
 

	
 
	var rhs_data = new Object();
 
	rhs_data.data = this._diff_codes(rhs_lines, ignore_ws);
 
	rhs_data.modified = {};
 
	rhs_data.length = Mgly.sizeOf(rhs_data.data);
 

	
 
	var max = (lhs_data.length + rhs_data.length + 1);
 
Mgly.diff = function(lhs, rhs, options) {
 
	var opts = jQuery.extend({ignorews: false}, options);
 
	this.codeify = new Mgly.CodeifyText({
 
		lhs: lhs,
 
		rhs: rhs,
 
		options: opts
 
	});
 
	var lhs_ctx = {
 
		codes: this.codeify.getCodes('lhs'),
 
		modified: {}
 
	};
 
	var rhs_ctx = {
 
		codes: this.codeify.getCodes('rhs'),
 
		modified: {}
 
	};
 
	var max = (lhs_ctx.codes.length + rhs_ctx.codes.length + 1);
 
	var vector_d = Array( 2 * max + 2 );
 
	var vector_u = Array( 2 * max + 2 );
 
	this._lcs(lhs_ctx, 0, lhs_ctx.codes.length, rhs_ctx, 0, rhs_ctx.codes.length, vector_u, vector_d);
 
	this._optimize(lhs_ctx);
 
	this._optimize(rhs_ctx);
 
	this.items = this._create_diffs(lhs_ctx, rhs_ctx);
 
};
 

	
 
	this._lcs(lhs_data, 0, lhs_data.length, rhs_data, 0, rhs_data.length, vector_u, vector_d);
 
	this._optimize(lhs_data);
 
	this._optimize(rhs_data);
 
	this.items = this._create_diffs(lhs_data, rhs_data);
 
	if (retain_lines) {
 
		this.lhs_lines = lhs_lines;
 
		this.rhs_lines = rhs_lines;
 
	}
 
};
 
jQuery.extend(Mgly.diff.prototype, {
 
	changes: function() { return this.items; },
 
	getLines: function(side) {
 
		return this.codeify.getLines(side);
 
	},
 
	normal_form: function() {
 
		var nf = '';
 
		for (var index = 0; index < this.items.length; ++index) {
 
@@ -150,53 +202,33 @@ jQuery.extend(Mgly.diff.prototype, {
 
		}
 
		return nf;
 
	},
 
	_diff_codes: function(lines, ignore_ws) {
 
		var code = this.max_code;
 
		var codes = {};
 
		for (var i = 0; i < lines.length; ++i) {
 
			var line = lines[i];
 
			if (ignore_ws) {
 
				line = line.replace(/\s+/g, '');
 
			}
 
			var aCode = this.diff_codes[line];
 
			if (aCode != undefined) {
 
				codes[i] = aCode;
 
			}
 
			else {
 
				this.max_code++;
 
				this.diff_codes[line] = this.max_code;
 
				codes[i] = this.max_code;
 
			}
 
		}
 
		return codes;
 
	},
 
	_lcs: function(lhs, lhs_lower, lhs_upper, rhs, rhs_lower, rhs_upper, vector_u, vector_d) {
 
		while ( (lhs_lower < lhs_upper) && (rhs_lower < rhs_upper) && (lhs.data[lhs_lower] == rhs.data[rhs_lower]) ) {
 
	_lcs: function(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d) {
 
		while ( (lhs_lower < lhs_upper) && (rhs_lower < rhs_upper) && (lhs_ctx.codes[lhs_lower] == rhs_ctx.codes[rhs_lower]) ) {
 
			++lhs_lower;
 
			++rhs_lower;
 
		}
 
		while ( (lhs_lower < lhs_upper) && (rhs_lower < rhs_upper) && (lhs.data[lhs_upper - 1] == rhs.data[rhs_upper - 1]) ) {
 
		while ( (lhs_lower < lhs_upper) && (rhs_lower < rhs_upper) && (lhs_ctx.codes[lhs_upper - 1] == rhs_ctx.codes[rhs_upper - 1]) ) {
 
			--lhs_upper;
 
			--rhs_upper;
 
		}
 
		if (lhs_lower == lhs_upper) {
 
			while (rhs_lower < rhs_upper) {
 
				rhs.modified[ rhs_lower++ ] = true;
 
				rhs_ctx.modified[ rhs_lower++ ] = true;
 
			}
 
		}
 
		else if (rhs_lower == rhs_upper) {
 
			while (lhs_lower < lhs_upper) {
 
				lhs.modified[ lhs_lower++ ] = true;
 
				lhs_ctx.modified[ lhs_lower++ ] = true;
 
			}
 
		}
 
		else {
 
			var sms = this._sms(lhs, lhs_lower, lhs_upper, rhs, rhs_lower, rhs_upper, vector_u, vector_d);
 
			this._lcs(lhs, lhs_lower, sms.x, rhs, rhs_lower, sms.y, vector_u, vector_d);
 
			this._lcs(lhs, sms.x, lhs_upper, rhs, sms.y, rhs_upper, vector_u, vector_d);
 
			var sms = this._sms(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d);
 
			this._lcs(lhs_ctx, lhs_lower, sms.x, rhs_ctx, rhs_lower, sms.y, vector_u, vector_d);
 
			this._lcs(lhs_ctx, sms.x, lhs_upper, rhs_ctx, sms.y, rhs_upper, vector_u, vector_d);
 
		}
 
	},
 
	_sms: function(lhs, lhs_lower, lhs_upper, rhs, rhs_lower, rhs_upper, vector_u, vector_d) {
 
		var max = lhs.length + rhs.length + 1;
 
	_sms: function(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d) {
 
		var max = lhs_ctx.codes.length + rhs_ctx.codes.length + 1;
 
		var kdown = lhs_lower - rhs_lower;
 
		var kup = lhs_upper - rhs_upper;
 
		var delta = (lhs_upper - lhs_lower) - (rhs_upper - rhs_lower);
 
@@ -221,7 +253,7 @@ jQuery.extend(Mgly.diff.prototype, {
 
				}
 
				y = x - k;
 
				// find the end of the furthest reaching forward D-path in diagonal k.
 
				while ((x < lhs_upper) && (y < rhs_upper) && (lhs.data[x] == rhs.data[y])) {
 
				while ((x < lhs_upper) && (y < rhs_upper) && (lhs_ctx.codes[x] == rhs_ctx.codes[y])) {
 
					x++; y++;
 
				}
 
				vector_d[ offset_down + k ] = x;
 
@@ -246,7 +278,7 @@ jQuery.extend(Mgly.diff.prototype, {
 
						x = vector_u[offset_up + k - 1]; // up
 
				}
 
				y = x - k;
 
				while ((x > lhs_lower) && (y > rhs_lower) && (lhs.data[x - 1] == rhs.data[y - 1])) {
 
				while ((x > lhs_lower) && (y > rhs_lower) && (lhs_ctx.codes[x - 1] == rhs_ctx.codes[y - 1])) {
 
					// diagonal
 
					x--;
 
					y--;
 
@@ -264,33 +296,33 @@ jQuery.extend(Mgly.diff.prototype, {
 
		}
 
		throw "the algorithm should never come here.";
 
	},
 
	_optimize: function(data) {
 
	_optimize: function(ctx) {
 
		var start = 0, end = 0;
 
		while (start < data.length) {
 
			while ((start < data.length) && (data.modified[start] == undefined || data.modified[start] == false)) {
 
		while (start < ctx.length) {
 
			while ((start < ctx.length) && (ctx.modified[start] == undefined || ctx.modified[start] == false)) {
 
				start++;
 
			}
 
			end = start;
 
			while ((end < data.length) && (data.modified[end] == true)) {
 
			while ((end < ctx.length) && (ctx.modified[end] == true)) {
 
				end++;
 
			}
 
			if ((end < data.length) && (data.data[start] == data.data[end])) {
 
				data.modified[start] = false;
 
				data.modified[end] = true;
 
			if ((end < ctx.length) && (ctx.ctx[start] == ctx.codes[end])) {
 
				ctx.modified[start] = false;
 
				ctx.modified[end] = true;
 
			}
 
			else {
 
				start = end;
 
			}
 
		}
 
	},
 
	_create_diffs: function(lhs_data, rhs_data) {
 
	_create_diffs: function(lhs_ctx, rhs_ctx) {
 
		var items = [];
 
		var lhs_start = 0, rhs_start = 0;
 
		var lhs_line = 0, rhs_line = 0;
 

	
 
		while (lhs_line < lhs_data.length || rhs_line < rhs_data.length) {
 
			if ((lhs_line < lhs_data.length) && (!lhs_data.modified[lhs_line])
 
				&& (rhs_line < rhs_data.length) && (!rhs_data.modified[rhs_line])) {
 
		while (lhs_line < lhs_ctx.codes.length || rhs_line < rhs_ctx.codes.length) {
 
			if ((lhs_line < lhs_ctx.codes.length) && (!lhs_ctx.modified[lhs_line])
 
				&& (rhs_line < rhs_ctx.codes.length) && (!rhs_ctx.modified[rhs_line])) {
 
				// equal lines
 
				lhs_line++;
 
				rhs_line++;
 
@@ -300,20 +332,20 @@ jQuery.extend(Mgly.diff.prototype, {
 
				lhs_start = lhs_line;
 
				rhs_start = rhs_line;
 

	
 
				while (lhs_line < lhs_data.length && (rhs_line >= rhs_data.length || lhs_data.modified[lhs_line]))
 
				while (lhs_line < lhs_ctx.codes.length && (rhs_line >= rhs_ctx.codes.length || lhs_ctx.modified[lhs_line]))
 
					lhs_line++;
 

	
 
				while (rhs_line < rhs_data.length && (lhs_line >= lhs_data.length || rhs_data.modified[rhs_line]))
 
				while (rhs_line < rhs_ctx.codes.length && (lhs_line >= lhs_ctx.codes.length || rhs_ctx.modified[rhs_line]))
 
					rhs_line++;
 

	
 
				if ((lhs_start < lhs_line) || (rhs_start < rhs_line)) {
 
					// store a new difference-item
 
					var aItem = new Object();
 
					aItem.lhs_start = lhs_start;
 
					aItem.rhs_start = rhs_start;
 
					aItem.lhs_deleted_count = lhs_line - lhs_start;
 
					aItem.rhs_inserted_count = rhs_line - rhs_start;
 
					items.push(aItem);
 
					items.push({
 
						lhs_start: lhs_start,
 
						rhs_start: rhs_start,
 
						lhs_deleted_count: lhs_line - lhs_start,
 
						rhs_inserted_count: rhs_line - rhs_start
 
					});
 
				}
 
			}
 
		}
 
@@ -322,12 +354,6 @@ jQuery.extend(Mgly.diff.prototype, {
 
});
 

	
 
Mgly.mergely = function(el, options) {
 
	CodeMirror.defineExtension('centerOnCursor', function() {
 
		var coords = this.cursorCoords(null, 'local');
 
		this.scrollTo(null,
 
			(coords.y + coords.yBot) / 2 - (this.getScrollerElement().clientHeight / 2));
 
	});
 

	
 
	if (el) {
 
		this.init(el, options);
 
	}
 
@@ -337,6 +363,25 @@ jQuery.extend(Mgly.mergely.prototype, {
 
	name: 'mergely',
 
	//http://jupiterjs.com/news/writing-the-perfect-jquery-plugin
 
	init: function(el, options) {
 
		this.diffView = new Mgly.CodeMirrorDiffView(el, options);
 
		this.bind(el);
 
	},
 
	bind: function(el) {
 
		this.diffView.bind(el);
 
	}
 
});
 

	
 
Mgly.CodeMirrorDiffView = function(el, options) {
 
	CodeMirror.defineExtension('centerOnCursor', function() {
 
		var coords = this.cursorCoords(null, 'local');
 
		this.scrollTo(null, 
 
			(coords.y + coords.yBot) / 2 - (this.getScrollerElement().clientHeight / 2));
 
	});
 
	this.init(el, options);
 
};
 

	
 
jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
 
	init: function(el, options) {
 
		this.settings = {
 
			autoupdate: true,
 
			autoresize: true,
 
@@ -352,14 +397,14 @@ jQuery.extend(Mgly.mergely.prototype, {
 
			change_timeout: 150,
 
			fgcolor: {a:'#4ba3fa',c:'#a3a3a3',d:'#ff7f7f'},
 
			bgcolor: '#eee',
 
			vpcolor: 'rgba(0, 0, 200, 0.2)',
 
			vpcolor: 'rgba(0, 0, 200, 0.5)',
 
			lhs: function(setValue) { },
 
			rhs: function(setValue) { },
 
			loaded: function() { },
 
			//_auto_height: function(h) { return h - 20; },
 
			_auto_width: function(w) { return w; },
 
			resize: function(init) {
 
				var scrollbar = init ? -15 : 0;
 
				var scrollbar = init ? 16 : 0;
 
				var w = jQuery(el).parent().width() + scrollbar;
 
				if (this.width == 'auto') {
 
					w = this._auto_width(w);
 
@@ -415,53 +460,8 @@ jQuery.extend(Mgly.mergely.prototype, {
 
		// bind if the element is destroyed
 
		this.element.bind('destroyed', jQuery.proxy(this.teardown, this));
 

	
 
		// save this instance in jQuery data
 
		jQuery.data(el, this.name, this);
 

	
 
		this._setup(el);
 
	},
 
	// bind events to this instance's methods
 
	bind: function() {
 
		var rhstx = jQuery('#' + this.id + '-rhs').get(0);
 
		if (!rhstx) {
 
			console.error('rhs textarea not defined - Mergely not initialized properly');
 
			return;
 
		}
 
		var lhstx = jQuery('#' + this.id + '-lhs').get(0);
 
		if (!rhstx) {
 
			console.error('lhs textarea not defined - Mergely not initialized properly');
 
			return;
 
		}
 
		var self = this;
 
		this.editor = [];
 

	
 
		this.editor[this.id + '-lhs'] = CodeMirror.fromTextArea(lhstx, this.lhs_cmsettings);
 
		this.editor[this.id + '-rhs'] = CodeMirror.fromTextArea(rhstx, this.rhs_cmsettings);
 
		this.editor[this.id + '-lhs'].on('change', function(){ if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); });
 
		this.editor[this.id + '-lhs'].on('scroll', function(){ self._scrolling(self.id + '-lhs'); });
 
		this.editor[this.id + '-rhs'].on('change', function(){ if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); });
 
		this.editor[this.id + '-rhs'].on('scroll', function(){ self._scrolling(self.id + '-rhs'); });
 

	
 
		// resize
 
		if (this.settings.autoresize) {
 
			var sz_timeout1 = null;
 
			var sz = function(init) {
 
				//self.em_height = null; //recalculate
 
				if (self.settings.resize) self.settings.resize(init);
 
				self.editor[self.id + '-lhs'].refresh();
 
				self.editor[self.id + '-rhs'].refresh();
 
				if (self.settings.autoupdate) {
 
					self._changing(self.id + '-lhs', self.id + '-rhs');
 
				}
 
			}
 
			jQuery(window).resize(
 
				function () {
 
					if (sz_timeout1) clearTimeout(sz_timeout1);
 
					sz_timeout1 = setTimeout(sz, self.settings.resize_timeout);
 
				}
 
			);
 
			sz(true);
 
		}
 
		// save this instance in jQuery data, binding this view to the node
 
		jQuery.data(el, 'mergely', this);
 
	},
 
	unbind: function() {
 
		if (this.changed_timeout != null) clearTimeout(this.changed_timeout);
 
@@ -502,11 +502,11 @@ jQuery.extend(Mgly.mergely.prototype, {
 
	options: function(opts) {
 
		if (opts) {
 
			jQuery.extend(this.settings, opts);
 
			if (opts.autoresize) this.resize();
 
			if (opts.autoupdate) this.update();
 
			if (opts.hasOwnProperty('rhs_margin')) {
 
			if (this.settings.autoresize) this.resize();
 
			if (this.settings.autoupdate) this.update();
 
			if (this.settings.hasOwnProperty('rhs_margin')) {
 
				// dynamically swap the margin
 
				if (opts.rhs_margin == 'left') {
 
				if (this.settings.rhs_margin == 'left') {
 
					this.element.find('.mergely-margin:last-child').insertAfter(
 
						this.element.find('.mergely-canvas'));
 
				}
 
@@ -515,9 +515,9 @@ jQuery.extend(Mgly.mergely.prototype, {
 
					target.appendTo(target.parent());
 
				}
 
			}
 
			if (opts.hasOwnProperty('sidebar')) {
 
			if (this.settings.hasOwnProperty('sidebar')) {
 
				// dynamically enable sidebars
 
				if (opts.sidebar) {
 
				if (this.settings.sidebar) {
 
					jQuery(this.element).find('.mergely-margin').css({display: 'block'});
 
				}
 
				else {
 
@@ -581,14 +581,15 @@ jQuery.extend(Mgly.mergely.prototype, {
 
	resize: function() {
 
		this.settings.resize();
 
		this._changing(this.id + '-lhs', this.id + '-rhs');
 
		this._set_top_offset(this.id + '-lhs');
 
	},
 
	diff: function() {
 
		var lhs = this.editor[this.id + '-lhs'].getValue();
 
		var rhs = this.editor[this.id + '-rhs'].getValue();
 
		var d = new Mgly.diff(lhs, rhs, retain_lines = true, ignore_ws = this.settings.ignorews);
 
		var d = new Mgly.diff(lhs, rhs, this.settings);
 
		return d.normal_form();
 
	},
 
	_setup: function(el) {
 
	bind: function(el) {
 
		jQuery(this.element).hide();//hide
 
		this.id = jQuery(el).attr('id');
 
		var height = this.settings.editor_height;
 
@@ -640,7 +641,48 @@ jQuery.extend(Mgly.mergely.prototype, {
 
			cmstyle += this.id + ' .CodeMirror-scroll { height: 100%; overflow: auto; }';
 
		}
 
		jQuery('<style type="text/css">' + cmstyle + '</style>').appendTo('head');
 
		this.bind();
 

	
 
		//bind
 
		var rhstx = jQuery('#' + this.id + '-rhs').get(0);
 
		if (!rhstx) {
 
			console.error('rhs textarea not defined - Mergely not initialized properly');
 
			return;
 
		}
 
		var lhstx = jQuery('#' + this.id + '-lhs').get(0);
 
		if (!rhstx) {
 
			console.error('lhs textarea not defined - Mergely not initialized properly');
 
			return;
 
		}
 
		var self = this;
 
		this.editor = [];
 
		this.editor[this.id + '-lhs'] = CodeMirror.fromTextArea(lhstx, this.lhs_cmsettings);
 
		this.editor[this.id + '-rhs'] = CodeMirror.fromTextArea(rhstx, this.rhs_cmsettings);
 
		this.editor[this.id + '-lhs'].on('change', function(){ if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); });
 
		this.editor[this.id + '-lhs'].on('scroll', function(){ self._scrolling(self.id + '-lhs'); });
 
		this.editor[this.id + '-rhs'].on('change', function(){ if (self.settings.autoupdate) self._changing(self.id + '-lhs', self.id + '-rhs'); });
 
		this.editor[this.id + '-rhs'].on('scroll', function(){ self._scrolling(self.id + '-rhs'); });
 
		// resize
 
		if (this.settings.autoresize) {
 
			var sz_timeout1 = null;
 
			var sz = function(init) {
 
				//self.em_height = null; //recalculate
 
				if (self.settings.resize) self.settings.resize(init);
 
				self.editor[self.id + '-lhs'].refresh();
 
				self.editor[self.id + '-rhs'].refresh();
 
				if (self.settings.autoupdate) {
 
					self._changing(self.id + '-lhs', self.id + '-rhs');
 
				}
 
			}
 
			jQuery(window).resize(
 
				function () {
 
					if (sz_timeout1) clearTimeout(sz_timeout1);
 
					sz_timeout1 = setTimeout(sz, self.settings.resize_timeout);
 
				}
 
			);
 
			sz(true);
 
		}
 
		//bind
 
		
 
		if (this.settings.lhs) {
 
			var setv = this.editor[this.id + '-lhs'].getDoc().setValue;
 
			this.settings.lhs(setv.bind(this.editor[this.id + '-lhs'].getDoc()));
 
@@ -803,7 +845,7 @@ jQuery.extend(Mgly.mergely.prototype, {
 
		var lhs = this.editor[editor_name1].getValue();
 
		var rhs = this.editor[editor_name2].getValue();
 
		var timer = new Mgly.Timer();
 
		var d = new Mgly.diff(lhs, rhs, false, this.settings.ignorews);
 
		var d = new Mgly.diff(lhs, rhs, this.settings);
 
		this.trace('change', 'diff time', timer.stop());
 
		this.changes = Mgly.DiffParser(d.normal_form());
 
		this.trace('change', 'parse time', timer.stop());
 
@@ -861,13 +903,27 @@ jQuery.extend(Mgly.mergely.prototype, {
 
		}
 
		return true;
 
	},
 
	_set_top_offset: function (editor_name1) {
 
		// save the current scroll position of the editor
 
		var saveY = this.editor[editor_name1].getScrollInfo().top;
 
		// temporarily scroll to top
 
		this.editor[editor_name1].scrollTo(null, 0);
 
		
 
		// this is the distance from the top of the screen to the top of the 
 
		// content of the first codemirror editor
 
		var topnode = jQuery('#' + this.id + ' .CodeMirror-measure').first();
 
		var top_offset = topnode.offset().top - 4;
 
		if(!top_offset) return false;
 
		
 
		// restore editor's scroll position
 
		this.editor[editor_name1].scrollTo(null, saveY);
 
		
 
		this.draw_top_offset = 0.5 - top_offset;
 
		return true;
 
	},
 
	_calculate_offsets: function (editor_name1, editor_name2, changes) {
 
		if (this.em_height == null) {
 
			// this is the distance from the top of the screen
 
			var topnode = jQuery('#' + this.id + ' .CodeMirror-measure').first();
 
			var top_offset = topnode.offset().top - 4;
 
			if (!top_offset) return;//try again
 
			this.draw_top_offset = 0.5 - top_offset;
 
			if(!this._set_top_offset(editor_name1)) return; //try again
 
			this.em_height = this.editor[editor_name1].defaultTextHeight();
 
			if (!this.em_height) {
 
				console.warn('Failed to calculate offsets, using 18 by default');
 
@@ -886,7 +942,7 @@ jQuery.extend(Mgly.mergely.prototype, {
 
			this.draw_rhs_max = this.draw_mid_width - 0.5; //24.5;
 
			this.draw_lhs_width = 5;
 
			this.draw_rhs_width = 5;
 
			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});
 
			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});
 
		}
 
		var lhschc = this.editor[editor_name1].charCoords({line: 0});
 
		var rhschc = this.editor[editor_name2].charCoords({line: 0});
 
@@ -1295,14 +1351,14 @@ jQuery.extend(Mgly.mergely.prototype, {
 
			ctx_lhs.beginPath();
 
			ctx_lhs.fillStyle = this.settings.fgcolor[change['op']];
 
			ctx_lhs.strokeStyle = '#000';
 
			ctx_lhs.lineWidth = 1.0;
 
			ctx_lhs.lineWidth = 0.5;
 
			ctx_lhs.fillRect(1.5, lhs_y_start, 4.5, Math.max(lhs_y_end - lhs_y_start, 5));
 
			ctx_lhs.strokeRect(1.5, lhs_y_start, 4.5, Math.max(lhs_y_end - lhs_y_start, 5));
 

	
 
			ctx_rhs.beginPath();
 
			ctx_rhs.fillStyle = this.settings.fgcolor[change['op']];
 
			ctx_rhs.strokeStyle = '#000';
 
			ctx_rhs.lineWidth = 1.0;
 
			ctx_rhs.lineWidth = 0.5;
 
			ctx_rhs.fillRect(1.5, rhs_y_start, 4.5, Math.max(rhs_y_end - rhs_y_start, 5));
 
			ctx_rhs.strokeRect(1.5, rhs_y_start, 4.5, Math.max(rhs_y_end - rhs_y_start, 5));
 

	
rhodecode/templates/files/diff_2way.html
Show inline comments
 
@@ -4,11 +4,11 @@
 

	
 
<%def name="js_extra()">
 
<script type="text/javascript" src="${h.url('/js/codemirror.js')}"></script>
 
<script type="text/javascript" src="${h.url('/js/mergerly.js')}"></script>
 
<script type="text/javascript" src="${h.url('/js/mergely.js')}"></script>
 
</%def>
 
<%def name="css_extra()">
 
<link rel="stylesheet" type="text/css" href="${h.url('/css/codemirror.css')}"/>
 
<link rel="stylesheet" type="text/css" href="${h.url('/css/mergerly.css')}"/>
 
<link rel="stylesheet" type="text/css" href="${h.url('/css/mergely.css')}"/>
 
</%def>
 

	
 
<%def name="title()">
0 comments (0 inline, 0 general)