diff --git a/doc/index.html b/doc/index.html index 73ff08b..540b90b 100644 --- a/doc/index.html +++ b/doc/index.html @@ -1,193 +1,193 @@ - - - - Mergely Manual - - - - - - - - - - - - -
- -
-
-

Mergely Reference Manual

- -

Overview

-

- The core of mergely is a javascript-based diff and customizable markup engine. - Mergely provides a rich API that enables integration into your own application. It - can be used as a diff tool (read-only) or as both a diff and merge - tool for plain text, CSS, HTML, XML, javascript, PHP, C, C++, etc. -

-

- -

- -

Basic Usage

-

- Mergely requires jQuery and CodeMirror. - A supported implementation of CodeMirror is provided in the Mergely download. -

-

- To use Mergely, you need to first load the required javascript and css files: -

-
-<script type="text/javascript"
- src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
-
-<script type="text/javascript" src="../lib/codemirror.min.js"></script>
-<link type="text/css" rel="stylesheet" href="../lib/codemirror.css" />
-
-<script type="text/javascript" src="../lib/mergely.js"></script>
-<link type="text/css" rel="stylesheet" href="../lib/mergely.css" />
-				
-

- Then, create a div for the editor: -

-
-<div id="compare"><div>
-				
-

- Then, initialize the 'compare' div with the mergely jquery plugin, setting - options as required: -

-
-$(document).ready(function () {
-	$('#compare').mergely({
-		cmsettings: { readOnly: false, lineNumbers: true },
-		lhs: function(setValue) {
-			setValue('the quick red fox\njumped over the hairy dog');
-		},
-		rhs: function(setValue) {
-			setValue('the quick brown fox\njumped over the lazy dog');
-		}
-	});
-});
-				
- -

Options

-

- The following options are available on initialization: -

-
-
autoresize
-
Enables/disables the auto-resizing of the editor. Defaults to true.
-
cmsettings
-
CodeMirror settings (see CodeMirror). Defaults to {mode: 'application/xml', readOnly: false, lineWrapping: false, lineNumbers: true}.
-
editor_width
-
Starting width. Defaults to '400px'.
-
editor_height
-
Starting height. Defaults to '400px'.
-
resize_timeout
-
The timeout, after a resize, before Mergely auto-resizes. Only used when autoresize enabled. Defaults to 500.
-
change_timeout
-
The timeout, after a text change, before Mergely calcualtes a diff. Only used when readonly enabled. Defaults to 500.
-
fgcolor
-
The foreground color that mergely marks changes with on the canvas. Defaults to '#4ba3fa'
-
bgcolor
-
The background color that mergely fills the margin canvas with. Defaults to '#eeeeee'
-
fadein
-
A jQuery fade-in value to enable the editor to fade in. Set to empty string to disable. Defaults to 'fast'
-
- -

Callbacks

-

- The following callbacks are available on initialization: -

-

-
lhs(setValue)
-
Allows the opportunity to set the value of the left-hand editor on initialization. A handle to a setValue function is passed as an argument.
-
rhs(setValue)
-
Allows the opportunity to set the value of the right-hand editor on initialization. A handle to a setValue function is passed as an argument.
-
height(h)
-
Allows the opportunity to adjust the height when then the editor is resized. Return the adjusted height.
-
width(w)
-
Allows the opportunity to adjust the width when the editor is resized. Return the adjusted width.
-
loaded()
-
A callback to indicate that Mergely has finished initializing and is loaded.
-
resized()
-
A callback to indicate that Mergely has been resized.
-
- -

Methods

-

- The following methods are available after initialization: -

-

-
$(selector).mergely('lhs', value)
-
Set the value of the left-hand editor. Best used with ajax.
-
$(selector).mergely('rhs', value)
-
Set the value of the right-hand editor. Best used with ajax.
-
$(selector).mergely('swap')
-
Swap the content of the left and right editors.
-
$(selector).mergely('merge', side)
-
Merge from side to the opposite side.
-
$(selector).mergely('get', side)
-
Gets the editor contents.
-
$(selector).mergely('clear', side)
-
Clears the editor contents.
-
$(selector).mergely('search', side, text)
-
Search the editor for text. Repeating the call will find the next available token.
-
$(selector).resize()
-
Resize the editor.
-
- -

Styles

-

- The following styles will allow you to brand your own editor: -

-
-
.mergely-column
-
The editors.
-
.mergely-active
-
The active editor.
-
mergely-c-start
-
Styles the starting line of a change.
-
mergely-c-end
-
Styles the ending line of a change.
-
mergely-a-start
-
Styles the starting line of an addition.
-
mergely-a-mid
-
Styles the middle text region of an addition.
-
mergely-a-end
-
Styles the ending line of an addition.
-
mergely-d-start
-
Styles the starting line of a deletion.
-
mergely-d-mid
-
Styles the middle text region of a deletion.
-
mergely-d-end
-
Styles the ending line of a deletion.
-
mergely-c-rem
-
Styles the middle text region of a deletion.
-
mergely-c-add
-
Styles the middle text region of an addition.
-
mergely-a-start-lhs
-
Styles the start of an addition on the left-hand side.
-
mergely-a-end-lhs
-
Styles the end of an addition on the left-hand side.
-
mergely-d-start-rhs
-
Styles the start of an deletion on the right-hand side.
-
mergely-d-end-rhs
-
Styles the start of an deletion on the right-hand side.
-
-
-
-
- - - + + + + Mergely Manual + + + + + + + + + + + + +
+ +
+
+

Mergely Reference Manual

+ +

Overview

+

+ The core of mergely is a javascript-based diff and customizable markup engine. + Mergely provides a rich API that enables integration into your own application. It + can be used as a diff tool (read-only) or as both a diff and merge + tool for plain text, CSS, HTML, XML, javascript, PHP, C, C++, etc. +

+

+ +

+ +

Basic Usage

+

+ Mergely requires jQuery and CodeMirror. + A supported implementation of CodeMirror is provided in the Mergely download. +

+

+ To use Mergely, you need to first load the required javascript and css files: +

+
+<script type="text/javascript"
+ src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
+
+<script type="text/javascript" src="../lib/codemirror.min.js"></script>
+<link type="text/css" rel="stylesheet" href="../lib/codemirror.css" />
+
+<script type="text/javascript" src="../lib/mergely.js"></script>
+<link type="text/css" rel="stylesheet" href="../lib/mergely.css" />
+				
+

+ Then, create a div for the editor: +

+
+<div id="compare"><div>
+				
+

+ Then, initialize the 'compare' div with the mergely jquery plugin, setting + options as required: +

+
+$(document).ready(function () {
+	$('#compare').mergely({
+		cmsettings: { readOnly: false, lineNumbers: true },
+		lhs: function(setValue) {
+			setValue('the quick red fox\njumped over the hairy dog');
+		},
+		rhs: function(setValue) {
+			setValue('the quick brown fox\njumped over the lazy dog');
+		}
+	});
+});
+				
+ +

Options

+

+ The following options are available on initialization: +

+
+
autoresize
+
Enables/disables the auto-resizing of the editor. Defaults to true.
+
cmsettings
+
CodeMirror settings (see CodeMirror). Defaults to {mode: 'application/xml', readOnly: false, lineWrapping: false, lineNumbers: true}.
+
editor_width
+
Starting width. Defaults to '400px'.
+
editor_height
+
Starting height. Defaults to '400px'.
+
resize_timeout
+
The timeout, after a resize, before Mergely auto-resizes. Only used when autoresize enabled. Defaults to 500.
+
change_timeout
+
The timeout, after a text change, before Mergely calcualtes a diff. Only used when readonly enabled. Defaults to 500.
+
fgcolor
+
The foreground color that mergely marks changes with on the canvas. Defaults to '#4ba3fa'
+
bgcolor
+
The background color that mergely fills the margin canvas with. Defaults to '#eeeeee'
+
fadein
+
A jQuery fade-in value to enable the editor to fade in. Set to empty string to disable. Defaults to 'fast'
+
+ +

Callbacks

+

+ The following callbacks are available on initialization: +

+

+
lhs(setValue)
+
Allows the opportunity to set the value of the left-hand editor on initialization. A handle to a setValue function is passed as an argument.
+
rhs(setValue)
+
Allows the opportunity to set the value of the right-hand editor on initialization. A handle to a setValue function is passed as an argument.
+
height(h)
+
Allows the opportunity to adjust the height when then the editor is resized. Return the adjusted height.
+
width(w)
+
Allows the opportunity to adjust the width when the editor is resized. Return the adjusted width.
+
loaded()
+
A callback to indicate that Mergely has finished initializing and is loaded.
+
resized()
+
A callback to indicate that Mergely has been resized.
+
+ +

Methods

+

+ The following methods are available after initialization: +

+

+
$(selector).mergely('lhs', value)
+
Set the value of the left-hand editor. Best used with ajax.
+
$(selector).mergely('rhs', value)
+
Set the value of the right-hand editor. Best used with ajax.
+
$(selector).mergely('swap')
+
Swap the content of the left and right editors.
+
$(selector).mergely('merge', side)
+
Merge from side to the opposite side.
+
$(selector).mergely('get', side)
+
Gets the editor contents.
+
$(selector).mergely('clear', side)
+
Clears the editor contents.
+
$(selector).mergely('search', side, text)
+
Search the editor for text. Repeating the call will find the next available token.
+
$(selector).resize()
+
Resize the editor.
+
+ +

Styles

+

+ The following styles will allow you to brand your own editor: +

+
+
.mergely-column
+
The editors.
+
.mergely-active
+
The active editor.
+
mergely-c-start
+
Styles the starting line of a change.
+
mergely-c-end
+
Styles the ending line of a change.
+
mergely-a-start
+
Styles the starting line of an addition.
+
mergely-a-mid
+
Styles the middle text region of an addition.
+
mergely-a-end
+
Styles the ending line of an addition.
+
mergely-d-start
+
Styles the starting line of a deletion.
+
mergely-d-mid
+
Styles the middle text region of a deletion.
+
mergely-d-end
+
Styles the ending line of a deletion.
+
mergely-c-rem
+
Styles the middle text region of a deletion.
+
mergely-c-add
+
Styles the middle text region of an addition.
+
mergely-a-start-lhs
+
Styles the start of an addition on the left-hand side.
+
mergely-a-end-lhs
+
Styles the end of an addition on the left-hand side.
+
mergely-d-start-rhs
+
Styles the start of an deletion on the right-hand side.
+
mergely-d-end-rhs
+
Styles the start of an deletion on the right-hand side.
+
+
+
+
+ + + diff --git a/examples/example1.html b/examples/example1.html index e587aac..fe99701 100644 --- a/examples/example1.html +++ b/examples/example1.html @@ -1,49 +1,49 @@ - - - - - Mergely - Simple Example - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - - + + + + + Mergely - Simple Example + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + diff --git a/examples/example2.html b/examples/example2.html index 4711863..f8a562e 100644 --- a/examples/example2.html +++ b/examples/example2.html @@ -1,57 +1,57 @@ - - - - - Mergely - Simple Example - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - - + + + + + Mergely - Simple Example + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + diff --git a/examples/example3.html b/examples/example3.html index 539bd9a..bf9c5de 100644 --- a/examples/example3.html +++ b/examples/example3.html @@ -1,57 +1,57 @@ - - - - - Mergely - Simple Example - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- - - + + + + + Mergely - Simple Example + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + diff --git a/examples/jquery.corner.js b/examples/jquery.corner.js index c416613..9b94ec9 100644 --- a/examples/jquery.corner.js +++ b/examples/jquery.corner.js @@ -1,249 +1,249 @@ -/*! - * jQuery corner plugin: simple corner rounding - * Examples and documentation at: http://jquery.malsup.com/corner/ - * version 2.12 (23-MAY-2011) - * Requires jQuery v1.3.2 or later - * Dual licensed under the MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - * Authors: Dave Methvin and Mike Alsup - */ - -/** - * corner() takes a single string argument: $('#myDiv').corner("effect corners width") - * - * effect: name of the effect to apply, such as round, bevel, notch, bite, etc (default is round). - * corners: one or more of: top, bottom, tr, tl, br, or bl. (default is all corners) - * width: width of the effect; in the case of rounded corners this is the radius. - * specify this value using the px suffix such as 10px (yes, it must be pixels). - */ -;(function($) { - -var style = document.createElement('div').style, - moz = style['MozBorderRadius'] !== undefined, - webkit = style['WebkitBorderRadius'] !== undefined, - radius = style['borderRadius'] !== undefined || style['BorderRadius'] !== undefined, - mode = document.documentMode || 0, - noBottomFold = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8), - - expr = $.browser.msie && (function() { - var div = document.createElement('div'); - try { div.style.setExpression('width','0+0'); div.style.removeExpression('width'); } - catch(e) { return false; } - return true; - })(); - -$.support = $.support || {}; -$.support.borderRadius = moz || webkit || radius; // so you can do: if (!$.support.borderRadius) $('#myDiv').corner(); - -function sz(el, p) { - return parseInt($.css(el,p))||0; -}; -function hex2(s) { - s = parseInt(s).toString(16); - return ( s.length < 2 ) ? '0'+s : s; -}; -function gpc(node) { - while(node) { - var v = $.css(node,'backgroundColor'), rgb; - if (v && v != 'transparent' && v != 'rgba(0, 0, 0, 0)') { - if (v.indexOf('rgb') >= 0) { - rgb = v.match(/\d+/g); - return '#'+ hex2(rgb[0]) + hex2(rgb[1]) + hex2(rgb[2]); - } - return v; - } - if (node.nodeName.toLowerCase() == 'html') - break; - node = node.parentNode; // keep walking if transparent - } - return '#ffffff'; -}; - -function getWidth(fx, i, width) { - switch(fx) { - case 'round': return Math.round(width*(1-Math.cos(Math.asin(i/width)))); - case 'cool': return Math.round(width*(1+Math.cos(Math.asin(i/width)))); - case 'sharp': return width-i; - case 'bite': return Math.round(width*(Math.cos(Math.asin((width-i-1)/width)))); - case 'slide': return Math.round(width*(Math.atan2(i,width/i))); - case 'jut': return Math.round(width*(Math.atan2(width,(width-i-1)))); - case 'curl': return Math.round(width*(Math.atan(i))); - case 'tear': return Math.round(width*(Math.cos(i))); - case 'wicked': return Math.round(width*(Math.tan(i))); - case 'long': return Math.round(width*(Math.sqrt(i))); - case 'sculpt': return Math.round(width*(Math.log((width-i-1),width))); - case 'dogfold': - case 'dog': return (i&1) ? (i+1) : width; - case 'dog2': return (i&2) ? (i+1) : width; - case 'dog3': return (i&3) ? (i+1) : width; - case 'fray': return (i%2)*width; - case 'notch': return width; - case 'bevelfold': - case 'bevel': return i+1; - case 'steep': return i/2 + 1; - case 'invsteep':return (width-i)/2+1; - } -}; - -$.fn.corner = function(options) { - // in 1.3+ we can fix mistakes with the ready state - if (this.length == 0) { - if (!$.isReady && this.selector) { - var s = this.selector, c = this.context; - $(function() { - $(s,c).corner(options); - }); - } - return this; - } - - return this.each(function(index){ - var $this = $(this), - // meta values override options - o = [$this.attr($.fn.corner.defaults.metaAttr) || '', options || ''].join(' ').toLowerCase(), - keep = /keep/.test(o), // keep borders? - cc = ((o.match(/cc:(#[0-9a-f]+)/)||[])[1]), // corner color - sc = ((o.match(/sc:(#[0-9a-f]+)/)||[])[1]), // strip color - width = parseInt((o.match(/(\d+)px/)||[])[1]) || 10, // corner width - re = /round|bevelfold|bevel|notch|bite|cool|sharp|slide|jut|curl|tear|fray|wicked|sculpt|long|dog3|dog2|dogfold|dog|invsteep|steep/, - fx = ((o.match(re)||['round'])[0]), - fold = /dogfold|bevelfold/.test(o), - edges = { T:0, B:1 }, - opts = { - TL: /top|tl|left/.test(o), TR: /top|tr|right/.test(o), - BL: /bottom|bl|left/.test(o), BR: /bottom|br|right/.test(o) - }, - // vars used in func later - strip, pad, cssHeight, j, bot, d, ds, bw, i, w, e, c, common, $horz; - - if ( !opts.TL && !opts.TR && !opts.BL && !opts.BR ) - opts = { TL:1, TR:1, BL:1, BR:1 }; - - // support native rounding - if ($.fn.corner.defaults.useNative && fx == 'round' && (radius || moz || webkit) && !cc && !sc) { - if (opts.TL) - $this.css(radius ? 'border-top-left-radius' : moz ? '-moz-border-radius-topleft' : '-webkit-border-top-left-radius', width + 'px'); - if (opts.TR) - $this.css(radius ? 'border-top-right-radius' : moz ? '-moz-border-radius-topright' : '-webkit-border-top-right-radius', width + 'px'); - if (opts.BL) - $this.css(radius ? 'border-bottom-left-radius' : moz ? '-moz-border-radius-bottomleft' : '-webkit-border-bottom-left-radius', width + 'px'); - if (opts.BR) - $this.css(radius ? 'border-bottom-right-radius' : moz ? '-moz-border-radius-bottomright' : '-webkit-border-bottom-right-radius', width + 'px'); - return; - } - - strip = document.createElement('div'); - $(strip).css({ - overflow: 'hidden', - height: '1px', - minHeight: '1px', - fontSize: '1px', - backgroundColor: sc || 'transparent', - borderStyle: 'solid' - }); - - pad = { - T: parseInt($.css(this,'paddingTop'))||0, R: parseInt($.css(this,'paddingRight'))||0, - B: parseInt($.css(this,'paddingBottom'))||0, L: parseInt($.css(this,'paddingLeft'))||0 - }; - - if (typeof this.style.zoom != undefined) this.style.zoom = 1; // force 'hasLayout' in IE - if (!keep) this.style.border = 'none'; - strip.style.borderColor = cc || gpc(this.parentNode); - cssHeight = $(this).outerHeight(); - - for (j in edges) { - bot = edges[j]; - // only add stips if needed - if ((bot && (opts.BL || opts.BR)) || (!bot && (opts.TL || opts.TR))) { - strip.style.borderStyle = 'none '+(opts[j+'R']?'solid':'none')+' none '+(opts[j+'L']?'solid':'none'); - d = document.createElement('div'); - $(d).addClass('jquery-corner'); - ds = d.style; - - bot ? this.appendChild(d) : this.insertBefore(d, this.firstChild); - - if (bot && cssHeight != 'auto') { - if ($.css(this,'position') == 'static') - this.style.position = 'relative'; - ds.position = 'absolute'; - ds.bottom = ds.left = ds.padding = ds.margin = '0'; - if (expr) - ds.setExpression('width', 'this.parentNode.offsetWidth'); - else - ds.width = '100%'; - } - else if (!bot && $.browser.msie) { - if ($.css(this,'position') == 'static') - this.style.position = 'relative'; - ds.position = 'absolute'; - ds.top = ds.left = ds.right = ds.padding = ds.margin = '0'; - - // fix ie6 problem when blocked element has a border width - if (expr) { - bw = sz(this,'borderLeftWidth') + sz(this,'borderRightWidth'); - ds.setExpression('width', 'this.parentNode.offsetWidth - '+bw+'+ "px"'); - } - else - ds.width = '100%'; - } - else { - ds.position = 'relative'; - ds.margin = !bot ? '-'+pad.T+'px -'+pad.R+'px '+(pad.T-width)+'px -'+pad.L+'px' : - (pad.B-width)+'px -'+pad.R+'px -'+pad.B+'px -'+pad.L+'px'; - } - - for (i=0; i < width; i++) { - w = Math.max(0,getWidth(fx,i, width)); - e = strip.cloneNode(false); - e.style.borderWidth = '0 '+(opts[j+'R']?w:0)+'px 0 '+(opts[j+'L']?w:0)+'px'; - bot ? d.appendChild(e) : d.insertBefore(e, d.firstChild); - } - - if (fold && $.support.boxModel) { - if (bot && noBottomFold) continue; - for (c in opts) { - if (!opts[c]) continue; - if (bot && (c == 'TL' || c == 'TR')) continue; - if (!bot && (c == 'BL' || c == 'BR')) continue; - - common = { position: 'absolute', border: 'none', margin: 0, padding: 0, overflow: 'hidden', backgroundColor: strip.style.borderColor }; - $horz = $('
').css(common).css({ width: width + 'px', height: '1px' }); - switch(c) { - case 'TL': $horz.css({ bottom: 0, left: 0 }); break; - case 'TR': $horz.css({ bottom: 0, right: 0 }); break; - case 'BL': $horz.css({ top: 0, left: 0 }); break; - case 'BR': $horz.css({ top: 0, right: 0 }); break; - } - d.appendChild($horz[0]); - - var $vert = $('
').css(common).css({ top: 0, bottom: 0, width: '1px', height: width + 'px' }); - switch(c) { - case 'TL': $vert.css({ left: width }); break; - case 'TR': $vert.css({ right: width }); break; - case 'BL': $vert.css({ left: width }); break; - case 'BR': $vert.css({ right: width }); break; - } - d.appendChild($vert[0]); - } - } - } - } - }); -}; - -$.fn.uncorner = function() { - if (radius || moz || webkit) - this.css(radius ? 'border-radius' : moz ? '-moz-border-radius' : '-webkit-border-radius', 0); - $('div.jquery-corner', this).remove(); - return this; -}; - -// expose options -$.fn.corner.defaults = { - useNative: true, // true if plugin should attempt to use native browser support for border radius rounding - metaAttr: 'data-corner' // name of meta attribute to use for options -}; - -})(jQuery); +/*! + * jQuery corner plugin: simple corner rounding + * Examples and documentation at: http://jquery.malsup.com/corner/ + * version 2.12 (23-MAY-2011) + * Requires jQuery v1.3.2 or later + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * Authors: Dave Methvin and Mike Alsup + */ + +/** + * corner() takes a single string argument: $('#myDiv').corner("effect corners width") + * + * effect: name of the effect to apply, such as round, bevel, notch, bite, etc (default is round). + * corners: one or more of: top, bottom, tr, tl, br, or bl. (default is all corners) + * width: width of the effect; in the case of rounded corners this is the radius. + * specify this value using the px suffix such as 10px (yes, it must be pixels). + */ +;(function($) { + +var style = document.createElement('div').style, + moz = style['MozBorderRadius'] !== undefined, + webkit = style['WebkitBorderRadius'] !== undefined, + radius = style['borderRadius'] !== undefined || style['BorderRadius'] !== undefined, + mode = document.documentMode || 0, + noBottomFold = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8), + + expr = $.browser.msie && (function() { + var div = document.createElement('div'); + try { div.style.setExpression('width','0+0'); div.style.removeExpression('width'); } + catch(e) { return false; } + return true; + })(); + +$.support = $.support || {}; +$.support.borderRadius = moz || webkit || radius; // so you can do: if (!$.support.borderRadius) $('#myDiv').corner(); + +function sz(el, p) { + return parseInt($.css(el,p))||0; +}; +function hex2(s) { + s = parseInt(s).toString(16); + return ( s.length < 2 ) ? '0'+s : s; +}; +function gpc(node) { + while(node) { + var v = $.css(node,'backgroundColor'), rgb; + if (v && v != 'transparent' && v != 'rgba(0, 0, 0, 0)') { + if (v.indexOf('rgb') >= 0) { + rgb = v.match(/\d+/g); + return '#'+ hex2(rgb[0]) + hex2(rgb[1]) + hex2(rgb[2]); + } + return v; + } + if (node.nodeName.toLowerCase() == 'html') + break; + node = node.parentNode; // keep walking if transparent + } + return '#ffffff'; +}; + +function getWidth(fx, i, width) { + switch(fx) { + case 'round': return Math.round(width*(1-Math.cos(Math.asin(i/width)))); + case 'cool': return Math.round(width*(1+Math.cos(Math.asin(i/width)))); + case 'sharp': return width-i; + case 'bite': return Math.round(width*(Math.cos(Math.asin((width-i-1)/width)))); + case 'slide': return Math.round(width*(Math.atan2(i,width/i))); + case 'jut': return Math.round(width*(Math.atan2(width,(width-i-1)))); + case 'curl': return Math.round(width*(Math.atan(i))); + case 'tear': return Math.round(width*(Math.cos(i))); + case 'wicked': return Math.round(width*(Math.tan(i))); + case 'long': return Math.round(width*(Math.sqrt(i))); + case 'sculpt': return Math.round(width*(Math.log((width-i-1),width))); + case 'dogfold': + case 'dog': return (i&1) ? (i+1) : width; + case 'dog2': return (i&2) ? (i+1) : width; + case 'dog3': return (i&3) ? (i+1) : width; + case 'fray': return (i%2)*width; + case 'notch': return width; + case 'bevelfold': + case 'bevel': return i+1; + case 'steep': return i/2 + 1; + case 'invsteep':return (width-i)/2+1; + } +}; + +$.fn.corner = function(options) { + // in 1.3+ we can fix mistakes with the ready state + if (this.length == 0) { + if (!$.isReady && this.selector) { + var s = this.selector, c = this.context; + $(function() { + $(s,c).corner(options); + }); + } + return this; + } + + return this.each(function(index){ + var $this = $(this), + // meta values override options + o = [$this.attr($.fn.corner.defaults.metaAttr) || '', options || ''].join(' ').toLowerCase(), + keep = /keep/.test(o), // keep borders? + cc = ((o.match(/cc:(#[0-9a-f]+)/)||[])[1]), // corner color + sc = ((o.match(/sc:(#[0-9a-f]+)/)||[])[1]), // strip color + width = parseInt((o.match(/(\d+)px/)||[])[1]) || 10, // corner width + re = /round|bevelfold|bevel|notch|bite|cool|sharp|slide|jut|curl|tear|fray|wicked|sculpt|long|dog3|dog2|dogfold|dog|invsteep|steep/, + fx = ((o.match(re)||['round'])[0]), + fold = /dogfold|bevelfold/.test(o), + edges = { T:0, B:1 }, + opts = { + TL: /top|tl|left/.test(o), TR: /top|tr|right/.test(o), + BL: /bottom|bl|left/.test(o), BR: /bottom|br|right/.test(o) + }, + // vars used in func later + strip, pad, cssHeight, j, bot, d, ds, bw, i, w, e, c, common, $horz; + + if ( !opts.TL && !opts.TR && !opts.BL && !opts.BR ) + opts = { TL:1, TR:1, BL:1, BR:1 }; + + // support native rounding + if ($.fn.corner.defaults.useNative && fx == 'round' && (radius || moz || webkit) && !cc && !sc) { + if (opts.TL) + $this.css(radius ? 'border-top-left-radius' : moz ? '-moz-border-radius-topleft' : '-webkit-border-top-left-radius', width + 'px'); + if (opts.TR) + $this.css(radius ? 'border-top-right-radius' : moz ? '-moz-border-radius-topright' : '-webkit-border-top-right-radius', width + 'px'); + if (opts.BL) + $this.css(radius ? 'border-bottom-left-radius' : moz ? '-moz-border-radius-bottomleft' : '-webkit-border-bottom-left-radius', width + 'px'); + if (opts.BR) + $this.css(radius ? 'border-bottom-right-radius' : moz ? '-moz-border-radius-bottomright' : '-webkit-border-bottom-right-radius', width + 'px'); + return; + } + + strip = document.createElement('div'); + $(strip).css({ + overflow: 'hidden', + height: '1px', + minHeight: '1px', + fontSize: '1px', + backgroundColor: sc || 'transparent', + borderStyle: 'solid' + }); + + pad = { + T: parseInt($.css(this,'paddingTop'))||0, R: parseInt($.css(this,'paddingRight'))||0, + B: parseInt($.css(this,'paddingBottom'))||0, L: parseInt($.css(this,'paddingLeft'))||0 + }; + + if (typeof this.style.zoom != undefined) this.style.zoom = 1; // force 'hasLayout' in IE + if (!keep) this.style.border = 'none'; + strip.style.borderColor = cc || gpc(this.parentNode); + cssHeight = $(this).outerHeight(); + + for (j in edges) { + bot = edges[j]; + // only add stips if needed + if ((bot && (opts.BL || opts.BR)) || (!bot && (opts.TL || opts.TR))) { + strip.style.borderStyle = 'none '+(opts[j+'R']?'solid':'none')+' none '+(opts[j+'L']?'solid':'none'); + d = document.createElement('div'); + $(d).addClass('jquery-corner'); + ds = d.style; + + bot ? this.appendChild(d) : this.insertBefore(d, this.firstChild); + + if (bot && cssHeight != 'auto') { + if ($.css(this,'position') == 'static') + this.style.position = 'relative'; + ds.position = 'absolute'; + ds.bottom = ds.left = ds.padding = ds.margin = '0'; + if (expr) + ds.setExpression('width', 'this.parentNode.offsetWidth'); + else + ds.width = '100%'; + } + else if (!bot && $.browser.msie) { + if ($.css(this,'position') == 'static') + this.style.position = 'relative'; + ds.position = 'absolute'; + ds.top = ds.left = ds.right = ds.padding = ds.margin = '0'; + + // fix ie6 problem when blocked element has a border width + if (expr) { + bw = sz(this,'borderLeftWidth') + sz(this,'borderRightWidth'); + ds.setExpression('width', 'this.parentNode.offsetWidth - '+bw+'+ "px"'); + } + else + ds.width = '100%'; + } + else { + ds.position = 'relative'; + ds.margin = !bot ? '-'+pad.T+'px -'+pad.R+'px '+(pad.T-width)+'px -'+pad.L+'px' : + (pad.B-width)+'px -'+pad.R+'px -'+pad.B+'px -'+pad.L+'px'; + } + + for (i=0; i < width; i++) { + w = Math.max(0,getWidth(fx,i, width)); + e = strip.cloneNode(false); + e.style.borderWidth = '0 '+(opts[j+'R']?w:0)+'px 0 '+(opts[j+'L']?w:0)+'px'; + bot ? d.appendChild(e) : d.insertBefore(e, d.firstChild); + } + + if (fold && $.support.boxModel) { + if (bot && noBottomFold) continue; + for (c in opts) { + if (!opts[c]) continue; + if (bot && (c == 'TL' || c == 'TR')) continue; + if (!bot && (c == 'BL' || c == 'BR')) continue; + + common = { position: 'absolute', border: 'none', margin: 0, padding: 0, overflow: 'hidden', backgroundColor: strip.style.borderColor }; + $horz = $('
').css(common).css({ width: width + 'px', height: '1px' }); + switch(c) { + case 'TL': $horz.css({ bottom: 0, left: 0 }); break; + case 'TR': $horz.css({ bottom: 0, right: 0 }); break; + case 'BL': $horz.css({ top: 0, left: 0 }); break; + case 'BR': $horz.css({ top: 0, right: 0 }); break; + } + d.appendChild($horz[0]); + + var $vert = $('
').css(common).css({ top: 0, bottom: 0, width: '1px', height: width + 'px' }); + switch(c) { + case 'TL': $vert.css({ left: width }); break; + case 'TR': $vert.css({ right: width }); break; + case 'BL': $vert.css({ left: width }); break; + case 'BR': $vert.css({ right: width }); break; + } + d.appendChild($vert[0]); + } + } + } + } + }); +}; + +$.fn.uncorner = function() { + if (radius || moz || webkit) + this.css(radius ? 'border-radius' : moz ? '-moz-border-radius' : '-webkit-border-radius', 0); + $('div.jquery-corner', this).remove(); + return this; +}; + +// expose options +$.fn.corner.defaults = { + useNative: true, // true if plugin should attempt to use native browser support for border radius rounding + metaAttr: 'data-corner' // name of meta attribute to use for options +}; + +})(jQuery); diff --git a/examples/lhs.txt b/examples/lhs.txt index 14b478c..44b5f84 100644 --- a/examples/lhs.txt +++ b/examples/lhs.txt @@ -1,2 +1,2 @@ -the quick red fox jumped -over the hairy dog +the quick red fox jumped +over the hairy dog diff --git a/examples/lhs_long.txt b/examples/lhs_long.txt index d155599..b157f67 100644 --- a/examples/lhs_long.txt +++ b/examples/lhs_long.txt @@ -1 +1 @@ -the quick red fox jumped over the hairy dog on a cold, wet, and windy day in January +the quick red fox jumped over the hairy dog on a cold, wet, and windy day in January diff --git a/examples/rhs.txt b/examples/rhs.txt index 13fde44..dfa72d9 100644 --- a/examples/rhs.txt +++ b/examples/rhs.txt @@ -1,2 +1,2 @@ -the quick brown fox jumped -over the lazy dog +the quick brown fox jumped +over the lazy dog diff --git a/examples/rhs_long.txt b/examples/rhs_long.txt index 2c3f250..483b8f4 100644 --- a/examples/rhs_long.txt +++ b/examples/rhs_long.txt @@ -1 +1 @@ -the quick brown fox jumped over the lazy dog on a cold, wet, and windy day in December +the quick brown fox jumped over the lazy dog on a cold, wet, and windy day in December diff --git a/lib/mergely.css b/lib/mergely.css index 2e3f162..8c73504 100644 --- a/lib/mergely.css +++ b/lib/mergely.css @@ -1,3 +1,8 @@ +/** + * Copyright (c) 2012 by Jamie Peabody, http://www.mergely.com + * All rights reserved. + * Version: 2.5 2012-07-31 + */ /* required */ .mergely-column textarea { width: 80px; height: 200px; } .mergely-column { float: left; } diff --git a/lib/mergely.js b/lib/mergely.js index 889a3d4..331da4c 100644 --- a/lib/mergely.js +++ b/lib/mergely.js @@ -1,3 +1,8 @@ +/** + * Copyright (c) 2012 by Jamie Peabody, http://www.mergely.com + * All rights reserved. + * Version: 2.5 2012-07-31 + */ Mgly = {}; Object.size = function(obj) { @@ -533,7 +538,7 @@ $.extend(Mgly.mergely.prototype, // create the textarea and canvas elements $(this.element).append($('
')); $(this.element).append($('
')); - $(this.element).append($('
')); + $(this.element).append($('
')); $(this.element).append($('
')); $(this.element).append($('
')); this.bind(); @@ -671,19 +676,43 @@ $.extend(Mgly.mergely.prototype, if (this.draw_top_offset == null) { var topnode = this.element.find('.CodeMirror-gutter-text pre').first(); var top_offset = topnode.offset().top; + if (!top_offset) { + // try again + return; + } this.em_height = topnode.get(0).offsetHeight; // this is the distance from the top of the screen this.draw_top_offset = 6.5 - top_offset; - if (this.em_height > 0) { - this.draw_lhs_min = 0.5; - this.draw_rhs_max = $('#' + editor_name1 + '-' + editor_name2 + '-canvas').width() - 0.5; //24.5; - this.draw_lhs_width = 5; - this.draw_rhs_width = 5; + if (!this.em_height) { + var test = $('
 
'); + this.em_height = parseInt(test.css('line-height')) - 2; + console.warn('Failed to calculate offsets, trying brute-force:', this.em_height); + } + if (!this.em_height) { + console.warn('Failed to calculate offsets, using 18 by default'); + this.em_height = 18; } - this.trace('calc', 'change offsets calculated', 'top_offset', top_offset); + this.draw_lhs_min = 0.5; + var c = $('#' + editor_name1 + '-' + editor_name2 + '-canvas'); + if (!c.width()) { + console.error('canvas width is 0'); + return; + } + this.draw_rhs_max = $('#' + editor_name1 + '-' + editor_name2 + '-canvas').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}); } for (var i in changes) { var change = changes[i]; + /* + FIXME + var lhslc = this.editor[editor_name1].lineCount(); + if (change['lhs-line-to'] + 1 >= lhslc) { + console.warn('here'); + } + */ change['lhs-y-start'] = this.draw_top_offset + this.editor[editor_name1].charCoords({line: change['lhs-line-from'], ch:0}).y; change['lhs-y-end'] = this.draw_top_offset + this.editor[editor_name1].charCoords({line: change['lhs-line-to']+1, ch:0}).y; change['rhs-y-start'] = this.draw_top_offset + this.editor[editor_name2].charCoords({line: change['rhs-line-from'], ch:0}).y; @@ -694,7 +723,7 @@ $.extend(Mgly.mergely.prototype, else if (change['op'] == 'a') { change['lhs-y-start'] = change['lhs-y-end']; } - this.trace('calc', 'change offsets calculated', i, change); + //this.trace('calc', 'change offsets calculated', i, change); } }, _markup_changes: function (editor_name1, editor_name2, changes) { @@ -1125,7 +1154,7 @@ $.extend(Mgly.mergely.prototype, trace: function(name) { if(this.settings._debug.indexOf(name) >= 0) { arguments[0] = name+':'; - //console.log(this, [].slice.apply(arguments)); + console.log(this, [].slice.apply(arguments)); } } }); diff --git a/lib/mergely.min.js b/lib/mergely.min.js index 1b82540..a4fca48 100644 --- a/lib/mergely.min.js +++ b/lib/mergely.min.js @@ -1 +1,6 @@ -Mgly={},Object.size=function(a){var b=0,c;for(c in a)a.hasOwnProperty(c)&&b++;return b},Mgly.LCS=function(a,b){this.length=this._lcs(a,b);var c=[];a=a.split(""),b=b.split(""),a.unshift(""),b.unshift(""),this.C=c,this.x=a,this.y=b;var d=0,e=0;for(d=0;d0&&b>0&&e[a]==f[b]?this._diff(a-1,b-1,c,d):b>0&&(a==0||g[a][b-1]>=g[a-1][b])?(this._diff(a,b-1,c,d),c&&c(b-1,f[b])):a>0&&(b==0||g[a][b-1]e&&(e=f[g+1][h+1])):f[g+1][h+1]=0;return e},Mgly.diff=function(a,b,c){this.diff_codes={},this.max_code=0;var d=a.split("\n"),e=b.split("\n");a.length==0&&(d=[]),b.length==0&&(e=[]);var f=new Object;f.data=this._diff_codes(d),f.modified={},f.length=Object.size(f.data);var g=new Object;g.data=this._diff_codes(e),g.modified={},g.length=Object.size(g.data);var h=f.length+g.length+1,i=Array(2*h+2),j=Array(2*h+2);this._lcs(f,0,f.length,g,0,g.length,j,i),this._optimize(f),this._optimize(g),this.items=this._create_diffs(f,g),c&&(this.lhs_lines=d,this.rhs_lines=e)},Mgly.diff.prototype.changes=function(){return this.items},Mgly.diff.prototype.normal_form=function(){var a="";for(var b in this.items){var c=this.items[b],d="",e="",f="c";c.lhs_deleted_count==0&&c.rhs_inserted_count>0?f="a":c.lhs_deleted_count>0&&c.rhs_inserted_count==0&&(f="d"),c.lhs_deleted_count==1?d=c.lhs_start+1:c.lhs_deleted_count==0?d=c.lhs_start:d=c.lhs_start+1+","+(c.lhs_start+c.lhs_deleted_count),c.rhs_inserted_count==1?e=c.rhs_start+1:c.rhs_inserted_count==0?e=c.rhs_start:e=c.rhs_start+1+","+(c.rhs_start+c.rhs_inserted_count),a+=d+f+e+"\n";if(this.rhs_lines&&this.lhs_lines){for(var g=c.lhs_start;g "+this.rhs_lines[g]+"\n"}}return a},Mgly.diff.prototype._diff_codes=function(a){var b=this.max_code,c={};for(var d=0;d=t&&(t=h[n+s+1])),u=t-s;while(tk-r&&g[o+s-1]b&&u>e&&a.data[t-1]==d.data[u-1])t--,u--;g[o+s]=t;if(!m&&j-r<=s&&s<=j+r&&g[o+s]<=h[n+s])return q.x=h[n+s],q.y=h[n+s]-s,q}}throw"the algorithm should never come here."},Mgly.diff.prototype._optimize=function(a){var b=0,c=0;while(b=b.length||a.modified[f]))f++;while(g=a.length||b.modified[g]))g++;if(d',e='';else{var f="width:1em;height:1em;background-color:#888;cursor:pointer;text-align:center;color:#eee;border:1px solid: #222;margin-right:5px;";d='
<
',e='
>
'}this.merge_right_button=$(e),this.merge_left_button=$(d),this.merge_right_button.corner&&this.merge_right_button.corner("3px"),this.merge_left_button.corner&&this.merge_left_button.corner("3px"),$(this.element).append($('
')),$(this.element).append($('
')),$(this.element).append($('
')),$(this.element).append($('
')),$(this.element).append($('
')),this.bind(),this.settings.lhs&&this.settings.lhs(this.editor[this.id+"-lhs"].setValue),this.settings.rhs&&this.settings.rhs(this.editor[this.id+"-rhs"].setValue),$(window).resize();var g="#"+this.id+" .CodeMirror-gutter-text { padding: 5px 0 0 0; }"+"#"+this.id+" .CodeMirror-lines pre, "+"#"+this.id+" .CodeMirror-gutter-text pre { line-height: 18px; }";this.settings.autoresize&&(g+=this.id+" .CodeMirror-scroll { height: 100%; overflow: auto; }"),$('").appendTo("head")},_scrolling:function(a){var b=$(this.editor[a].getScrollerElement());this.midway==undefined&&(this.midway=(b.height()/2+b.offset().top).toFixed(2));var c=this.editor[a].coordsChar({x:0,y:this.midway}),d=b.scrollTop(),e=b.scrollLeft();this.trace("scroll","midway",this.midway),this.trace("scroll","midline",c),this.trace("scroll","top_to",d),this.trace("scroll","left_to",e);for(var f in this.editor){if(a==f)continue;var g=a.replace(this.id+"-",""),h=f.replace(this.id+"-",""),i=0,j=null;for(var k in this.changes){var l=this.changes[k];c.line>=l[g+"-line-from"]&&(j=l,c.line>=j[g+"-line-to"]&&(i+=l[g+"-y-end"]-l[g+"-y-start"]-(l[h+"-y-end"]-l[h+"-y-start"])))}var m=!0;j&&(this.trace("scroll","last visible change",j),j[g+"-line-from"]c.line&&(m=!1));if(m){this.trace("scroll","scrolling other side",d-i);var b=$(this.editor[f].getScrollerElement());b.scrollTop(d-i).scrollLeft(e)}else this.trace("scroll","not scrolling other side");this._calculate_offsets(this.id+"-lhs",this.id+"-rhs",this.changes),this._draw_diff(this.id+"-lhs",this.id+"-rhs",this.changes),this.trace("scroll","scrolled")}},_changing:function(a,b){var c=this;this.changed_timeout!=null&&clearTimeout(this.changed_timeout),this.changed_timeout=setTimeout(function(){c._changed(a,b)},this.settings.change_timeout)},_changed:function(a,b){for(var c in this.editor){var d=this.editor[c];d.operation(function(){for(var a=0,b=d.lineCount();a0&&(this.draw_lhs_min=.5,this.draw_rhs_max=$("#"+a+"-"+b+"-canvas").width()-.5,this.draw_lhs_width=5,this.draw_rhs_width=5),this.trace("calc","change offsets calculated","top_offset",e)}for(var f in c){var g=c[f];g["lhs-y-start"]=this.draw_top_offset+this.editor[a].charCoords({line:g["lhs-line-from"],ch:0}).y,g["lhs-y-end"]=this.draw_top_offset+this.editor[a].charCoords({line:g["lhs-line-to"]+1,ch:0}).y,g["rhs-y-start"]=this.draw_top_offset+this.editor[b].charCoords({line:g["rhs-line-from"],ch:0}).y,g["rhs-y-end"]=this.draw_top_offset+this.editor[b].charCoords({line:g["rhs-line-to"]+1,ch:0}).y,g["op"]=="d"?g["rhs-y-start"]=g["rhs-y-end"]:g["op"]=="a"&&(g["lhs-y-start"]=g["lhs-y-end"]),this.trace("calc","change offsets calculated",f,g)}},_markup_changes:function(a,b,c){$(".merge-button").remove();var d=this.editor[a];d.operation(function(){for(var a in c){var b=c[a],e="mergely-"+b.op+"-start",f="mergely-"+b.op+"-end",g=e+" "+f;if(b["lhs-line-from"]==b["lhs-line-to"])b["op"]=="c"?d.setLineClass(b["lhs-line-from"],g):b["op"]=="a"?d.setLineClass(b["lhs-line-from"],f+"-lhs"):b["op"]=="d"&&d.setLineClass(b["lhs-line-from"],g+" mergely-c-rem");else{d.setLineClass(b["lhs-line-from"],e+(b["op"]=="d"?" mergely-c-rem":"")),d.setLineClass(b["lhs-line-to"],f+(b["op"]=="d"?" mergely-c-rem":""));if(b["op"]=="d")for(var h=b["lhs-line-from"]+1;h=g;--i)k.editor[b].removeLine(i)}else f+="\n",k.editor[b].replaceRange(f,{line:c["rhs-line-from"]+1,ch:0});return k.editor[a].setValue(k.editor[a].getValue()),k.editor[b].setValue(k.editor[b].getValue()),!1}}(f),this.trace("markup","lhs adding button",f["lhs-line-from"]),this.editor[a].addWidget({line:f["lhs-line-from"],ch:0},j.get(0),!1,"over","right"),j=this.merge_left_button.clone(),j.button&&j.button({icons:{primary:"ui-icon-triangle-1-w"},text:!1}),j.addClass("merge-button"),j.attr("id","merge-left-"+e);var k=this;$(j).get(0).onclick=function(c){return function(){var d=k.editor[a].lineInfo(c["lhs-line-to"]),e=k.editor[b].lineInfo(c["rhs-line-to"]),f=k.editor[b].getRange({line:c["rhs-line-from"],ch:0},{line:c["rhs-line-to"],ch:e.text.length});if(c["op"]=="c")k.editor[a].replaceRange(f,{line:c["lhs-line-from"],ch:0},{line:c["lhs-line-to"],ch:d.text.length});else if(c["op"]=="d"){var g=parseInt(c["lhs-line-from"]),h=parseInt(c["lhs-line-to"]);for(var i=h;i>=g;--i)k.editor[a].removeLine(i)}else f+="\n",k.editor[a].replaceRange(f,{line:c["lhs-line-from"]+1,ch:0});return k.editor[a].setValue(k.editor[a].getValue()),k.editor[b].setValue(k.editor[b].getValue()),!1}}(f),this.trace("markup","rhs adding button",f["rhs-line-from"]),this.editor[b].addWidget({line:f["rhs-line-from"],ch:0},j.get(0),!1,"over","right")}if(f["op"]=="a"){var l=f["rhs-line-from"],m=f["rhs-line-to"],n=this.editor[b].lineInfo(m);if(n){var o=this.editor[b].markText({line:l,ch:0},{line:m,ch:n.text.length},"mergely-c-add");this.change_funcs.push(o)}continue}if(f["op"]=="d"){var l=f["lhs-line-from"],m=f["lhs-line-to"],n=this.editor[a].lineInfo(m);if(n){var o=this.editor[a].markText({line:l,ch:0},{line:m,ch:n.text.length},"mergely-c-rem");this.change_funcs.push(o)}continue}var k=this;for(var p=f["lhs-line-from"],q=f["rhs-line-from"],e=0;p>=0&&p<=f["lhs-line-to"]||q>=0&&q<=f["rhs-line-to"];++p,++q){if(q+e>f["rhs-line-to"]){var r=this.editor[a].getLine(p),o=this.editor[a].markText({line:p,ch:0},{line:p,ch:r.length},"mergely-c-rem");this.change_funcs.push(o);continue}if(p+e>f["lhs-line-to"]){var s=this.editor[b].getLine(q),o=this.editor[a].markText({line:q,ch:0},{line:q,ch:r.length},"mergely-c-add");this.change_funcs.push(o);continue}var r=this.editor[a].getLine(p),s=this.editor[b].getLine(q),t={line:-1,ch:-1},u={line:-1,ch:-1},v={line:-1,ch:-1},w={line:-1,ch:-1},x=new Mgly.LCS(r,s),y=Math.max(r.length,s.length);y==0&&(y=1);var z=1*x.length/y*100;z<10&&x.clear(),x.diff(added=function(a,c){if(v.ch<0)v.line=q,v.ch=a,w.line=q,w.ch=a;else if(a==w.ch+1)w.ch=a;else{if(v.ch>=0&&w.ch>=v.ch){w.ch+=1;var d=k.editor[b].markText(v,w,"mergely-c-add");k.change_funcs.push(d)}v.ch=-1,w.ch=-1,c!="\n"&&this.added(a,c)}},removed=function(b,c){if(t.ch<0)t.line=p,t.ch=b,u.line=p,u.ch=b;else if(b==u.ch+1)u.ch=b;else{if(t.ch>=0&&u.ch>=t.ch){u.ch+=1;var d=k.editor[a].markText(t,u,"mergely-c-rem");k.change_funcs.push(d)}t.ch=-1,u.ch=-1,c!="\n"&&this.removed(b,c)}});if(v.ch>=0&&w.ch>=v.ch){w.ch+=1;var o=this.editor[b].markText(v,w,"mergely-c-add");this.change_funcs.push(o)}if(t.ch>=0&&u.ch>=t.ch){u.ch+=1;var o=this.editor[a].markText(t,u,"mergely-c-rem");this.change_funcs.push(o)}}}},_draw_diff:function(a,b,c){var d=$(this.editor[a].getScrollerElement()).height(),e=$(this.editor[a].getScrollerElement()).children(":first-child").height(),f=d/e,g=d/e,h=$(this.editor[a].getScrollerElement()),i=$(this.editor[b].getScrollerElement()),j=this.editor[a].lineCount(),k=this.editor[b].lineCount();this.trace("draw","visible_page_height",d),this.trace("draw","gutter_height",e),this.trace("draw","visible_page_ratio",f),this.trace("draw","lhs-scroller-top",h.scrollTop()),this.trace("draw","rhs-scroller-top",i.scrollTop());var l=document.getElementById(a+"-"+b+"-canvas");if(l==undefined)throw"Failed to find: "+a+"-"+b+"-canvas";$.each($("canvas"),function(){$(this).get(0).height=d});var m=$("#"+this.id+"-lhs-margin"),n=$("#"+this.id+"-rhs-margin");m.unbind("click"),n.unbind("click");var o=m.get(0),p=n.get(0),q=$(m).offset(),r=$(n).offset(),s=l.getContext("2d"),t=o.getContext("2d"),u=p.getContext("2d");t.beginPath(),t.fillStyle=this.settings.bgcolor,t.strokeStyle="#888",t.fillRect(0,0,6.5,d),t.strokeRect(0,0,6.5,d),u.beginPath(),u.fillStyle=this.settings.bgcolor,u.strokeStyle="#888",u.fillRect(0,0,6.5,d),u.strokeRect(0,0,6.5,d);for(var v in c){var w=c[v],x=w["lhs-y-start"],y=w["lhs-y-end"],z=w["rhs-y-start"],A=w["rhs-y-end"];s.beginPath(),s.strokeStyle=this.settings.fgcolor,s.lineWidth=1,s.moveTo(this.draw_lhs_min,x),s.lineTo(this.draw_lhs_min+this.draw_lhs_width,x),s.lineTo(this.draw_lhs_min+this.draw_lhs_width,y+1),s.lineTo(this.draw_lhs_min,y+1),s.stroke(),s.moveTo(this.draw_rhs_max,z),s.lineTo(this.draw_rhs_max-this.draw_rhs_width,z),s.lineTo(this.draw_rhs_max-this.draw_rhs_width,A+1),s.lineTo(this.draw_rhs_max,A+1),s.stroke(),s.moveTo(this.draw_lhs_min+this.draw_lhs_width,x+(y+1-x)/2),s.lineTo(this.draw_rhs_max-this.draw_rhs_width,z+(A+1-z)/2),s.stroke(),this.trace("draw",w),x=(w["lhs-y-start"]+h.scrollTop())*f,y=(w["lhs-y-end"]+h.scrollTop())*f+1,z=(w["rhs-y-start"]+i.scrollTop())*f,A=(w["rhs-y-end"]+i.scrollTop())*f+1,this.trace("draw","marker calculated",x,y,z,A),t.beginPath(),t.fillStyle=this.settings.fgcolor,t.strokeStyle="#000",t.lineWidth=.5,t.fillRect(1.5,x,4.5,Math.max(y-x,5)),t.strokeRect(1.5,x,4.5,Math.max(y-x,5)),u.beginPath(),u.fillStyle=this.settings.fgcolor,u.strokeStyle="#000",u.lineWidth=.5,u.fillRect(1.5,z,4.5,Math.max(A-z,5)),u.strokeRect(1.5,z,4.5,Math.max(A-z,5))}t.fillStyle="rgba(0, 0, 200, 0.5)",u.fillStyle="rgba(0, 0, 200, 0.5)";var B=m.height()*f,C=h.scrollTop()/e*m.height();this.trace("draw","cls.height",m.height()),this.trace("draw","lhs_scroller.scrollTop()",h.scrollTop()),this.trace("draw","gutter_height",e),this.trace("draw","visible_page_ratio",f),this.trace("draw","from",C,"to",B),t.fillRect(1.5,C,4.5,B),u.fillRect(1.5,C,4.5,B),m.click(function(a){var b=a.pageY-q.top-B/2,c=Math.max(0,b/o.height*h.get(0).scrollHeight);h.scrollTop(c)}),n.click(function(a){var b=a.pageY-r.top-B/2,c=Math.max(0,b/p.height*i.get(0).scrollHeight);i.scrollTop(c)})},trace:function(a){this.settings._debug.indexOf(a)>=0&&(arguments[0]=a+":")}}),$.pluginMaker=function(a){$.fn[a.prototype.name]=function(b){var c=$.makeArray(arguments),d=c.slice(1),e=undefined;this.each(function(){var f=$.data(this,a.prototype.name);if(f){if(typeof b=="string")e=f[b].apply(f,d);else if(f.update)return alert("here"),f.update.apply(f,c)}else new a(this,b)});if(e!=undefined)return e}},$.pluginMaker(Mgly.mergely) \ No newline at end of file +/** + * Copyright (c) 2012 by Jamie Peabody, http://www.mergely.com + * All rights reserved. + * Version: 2.5 2012-07-31 + */ +Mgly={},Object.size=function(e){var t=0,n;for(n in e)e.hasOwnProperty(n)&&t++;return t},Mgly.LCS=function(e,t){this.length=this._lcs(e,t);var n=[];e=e.split(""),t=t.split(""),e.unshift(""),t.unshift(""),this.C=n,this.x=e,this.y=t;var r=0,i=0;for(r=0;r0&&t>0&&i[e]==s[t]?this._diff(e-1,t-1,n,r):t>0&&(e==0||o[e][t-1]>=o[e-1][t])?(this._diff(e,t-1,n,r),n&&n(t-1,s[t])):e>0&&(t==0||o[e][t-1]n&&(n=r[i+1][s+1])):r[i+1][s+1]=0;return n},Mgly.diff=function(e,t,n){this.diff_codes={},this.max_code=0;var r=e.split("\n"),i=t.split("\n");e.length==0&&(r=[]),t.length==0&&(i=[]);var s=new Object;s.data=this._diff_codes(r),s.modified={},s.length=Object.size(s.data);var o=new Object;o.data=this._diff_codes(i),o.modified={},o.length=Object.size(o.data);var u=s.length+o.length+1,a=Array(2*u+2),f=Array(2*u+2);this._lcs(s,0,s.length,o,0,o.length,f,a),this._optimize(s),this._optimize(o),this.items=this._create_diffs(s,o),n&&(this.lhs_lines=r,this.rhs_lines=i)},Mgly.diff.prototype.changes=function(){return this.items},Mgly.diff.prototype.normal_form=function(){var e="";for(var t in this.items){var n=this.items[t],r="",i="",s="c";n.lhs_deleted_count==0&&n.rhs_inserted_count>0?s="a":n.lhs_deleted_count>0&&n.rhs_inserted_count==0&&(s="d"),n.lhs_deleted_count==1?r=n.lhs_start+1:n.lhs_deleted_count==0?r=n.lhs_start:r=n.lhs_start+1+","+(n.lhs_start+n.lhs_deleted_count),n.rhs_inserted_count==1?i=n.rhs_start+1:n.rhs_inserted_count==0?i=n.rhs_start:i=n.rhs_start+1+","+(n.rhs_start+n.rhs_inserted_count),e+=r+s+i+"\n";if(this.rhs_lines&&this.lhs_lines){for(var o=n.lhs_start;o "+this.rhs_lines[o]+"\n"}}return e},Mgly.diff.prototype._diff_codes=function(e){var t=this.max_code,n={};for(var r=0;r=b&&(b=u[p+y+1])),w=b-y;while(bl-g&&o[d+y-1]t&&w>i&&e.data[b-1]==r.data[w-1])b--,w--;o[d+y]=b;if(!h&&f-g<=y&&y<=f+g&&o[d+y]<=u[p+y])return m.x=u[p+y],m.y=u[p+y]-y,m}}throw"the algorithm should never come here."},Mgly.diff.prototype._optimize=function(e){var t=0,n=0;while(t=t.length||e.modified[s]))s++;while(o=e.length||t.modified[o]))o++;if(r',i='';else{var s="width:1em;height:1em;background-color:#888;cursor:pointer;text-align:center;color:#eee;border:1px solid: #222;margin-right:5px;";r='
<
',i='
>
'}this.merge_right_button=$(i),this.merge_left_button=$(r),this.merge_right_button.corner&&this.merge_right_button.corner("3px"),this.merge_left_button.corner&&this.merge_left_button.corner("3px"),$(this.element).append($('
')),$(this.element).append($('
')),$(this.element).append($('
')),$(this.element).append($('
')),$(this.element).append($('
')),this.bind(),this.settings.lhs&&this.settings.lhs(this.editor[this.id+"-lhs"].setValue),this.settings.rhs&&this.settings.rhs(this.editor[this.id+"-rhs"].setValue),$(window).resize();var o="#"+this.id+" .CodeMirror-gutter-text { padding: 5px 0 0 0; }"+"#"+this.id+" .CodeMirror-lines pre, "+"#"+this.id+" .CodeMirror-gutter-text pre { line-height: 18px; }";this.settings.autoresize&&(o+=this.id+" .CodeMirror-scroll { height: 100%; overflow: auto; }"),$('").appendTo("head")},_scrolling:function(e){var t=$(this.editor[e].getScrollerElement());this.midway==undefined&&(this.midway=(t.height()/2+t.offset().top).toFixed(2));var n=this.editor[e].coordsChar({x:0,y:this.midway}),r=t.scrollTop(),i=t.scrollLeft();this.trace("scroll","midway",this.midway),this.trace("scroll","midline",n),this.trace("scroll","top_to",r),this.trace("scroll","left_to",i);for(var s in this.editor){if(e==s)continue;var o=e.replace(this.id+"-",""),u=s.replace(this.id+"-",""),a=0,f=null;for(var l in this.changes){var c=this.changes[l];n.line>=c[o+"-line-from"]&&(f=c,n.line>=f[o+"-line-to"]&&(a+=c[o+"-y-end"]-c[o+"-y-start"]-(c[u+"-y-end"]-c[u+"-y-start"])))}var h=!0;f&&(this.trace("scroll","last visible change",f),f[o+"-line-from"]n.line&&(h=!1));if(h){this.trace("scroll","scrolling other side",r-a);var t=$(this.editor[s].getScrollerElement());t.scrollTop(r-a).scrollLeft(i)}else this.trace("scroll","not scrolling other side");this._calculate_offsets(this.id+"-lhs",this.id+"-rhs",this.changes),this._draw_diff(this.id+"-lhs",this.id+"-rhs",this.changes),this.trace("scroll","scrolled")}},_changing:function(e,t){var n=this;this.changed_timeout!=null&&clearTimeout(this.changed_timeout),this.changed_timeout=setTimeout(function(){n._changed(e,t)},this.settings.change_timeout)},_changed:function(e,t){for(var n in this.editor){var r=this.editor[n];r.operation(function(){for(var e=0,t=r.lineCount();e
 
');this.em_height=parseInt(s.css("line-height"))-2,console.warn("Failed to calculate offsets, trying brute-force:",this.em_height)}this.em_height||(console.warn("Failed to calculate offsets, using 18 by default"),this.em_height=18),this.draw_lhs_min=.5;var o=$("#"+e+"-"+t+"-canvas");if(!o.width()){console.error("canvas width is 0");return}this.draw_rhs_max=$("#"+e+"-"+t+"-canvas").width()-.5,this.draw_lhs_width=5,this.draw_rhs_width=5,this.trace("calc","change offsets calculated",{top_offset:i,lhs_min:this.draw_lhs_min,rhs_max:this.draw_rhs_max,lhs_width:this.draw_lhs_width,rhs_width:this.draw_rhs_width})}for(var u in n){var a=n[u];a["lhs-y-start"]=this.draw_top_offset+this.editor[e].charCoords({line:a["lhs-line-from"],ch:0}).y,a["lhs-y-end"]=this.draw_top_offset+this.editor[e].charCoords({line:a["lhs-line-to"]+1,ch:0}).y,a["rhs-y-start"]=this.draw_top_offset+this.editor[t].charCoords({line:a["rhs-line-from"],ch:0}).y,a["rhs-y-end"]=this.draw_top_offset+this.editor[t].charCoords({line:a["rhs-line-to"]+1,ch:0}).y,a["op"]=="d"?a["rhs-y-start"]=a["rhs-y-end"]:a["op"]=="a"&&(a["lhs-y-start"]=a["lhs-y-end"])}},_markup_changes:function(e,t,n){$(".merge-button").remove();var r=this.editor[e];r.operation(function(){for(var e in n){var t=n[e],i="mergely-"+t.op+"-start",s="mergely-"+t.op+"-end",o=i+" "+s;if(t["lhs-line-from"]==t["lhs-line-to"])t["op"]=="c"?r.setLineClass(t["lhs-line-from"],o):t["op"]=="a"?r.setLineClass(t["lhs-line-from"],s+"-lhs"):t["op"]=="d"&&r.setLineClass(t["lhs-line-from"],o+" mergely-c-rem");else{r.setLineClass(t["lhs-line-from"],i+(t["op"]=="d"?" mergely-c-rem":"")),r.setLineClass(t["lhs-line-to"],s+(t["op"]=="d"?" mergely-c-rem":""));if(t["op"]=="d")for(var u=t["lhs-line-from"]+1;u=o;--a)l.editor[t].removeLine(a)}else s+="\n",l.editor[t].replaceRange(s,{line:n["rhs-line-from"]+1,ch:0});return l.editor[e].setValue(l.editor[e].getValue()),l.editor[t].setValue(l.editor[t].getValue()),!1}}(s),this.trace("markup","lhs adding button",s["lhs-line-from"]),this.editor[e].addWidget({line:s["lhs-line-from"],ch:0},f.get(0),!1,"over","right"),f=this.merge_left_button.clone(),f.button&&f.button({icons:{primary:"ui-icon-triangle-1-w"},text:!1}),f.addClass("merge-button"),f.attr("id","merge-left-"+i);var l=this;$(f).get(0).onclick=function(n){return function(){var r=l.editor[e].lineInfo(n["lhs-line-to"]),i=l.editor[t].lineInfo(n["rhs-line-to"]),s=l.editor[t].getRange({line:n["rhs-line-from"],ch:0},{line:n["rhs-line-to"],ch:i.text.length});if(n["op"]=="c")l.editor[e].replaceRange(s,{line:n["lhs-line-from"],ch:0},{line:n["lhs-line-to"],ch:r.text.length});else if(n["op"]=="d"){var o=parseInt(n["lhs-line-from"]),u=parseInt(n["lhs-line-to"]);for(var a=u;a>=o;--a)l.editor[e].removeLine(a)}else s+="\n",l.editor[e].replaceRange(s,{line:n["lhs-line-from"]+1,ch:0});return l.editor[e].setValue(l.editor[e].getValue()),l.editor[t].setValue(l.editor[t].getValue()),!1}}(s),this.trace("markup","rhs adding button",s["rhs-line-from"]),this.editor[t].addWidget({line:s["rhs-line-from"],ch:0},f.get(0),!1,"over","right")}if(s["op"]=="a"){var c=s["rhs-line-from"],h=s["rhs-line-to"],p=this.editor[t].lineInfo(h);if(p){var d=this.editor[t].markText({line:c,ch:0},{line:h,ch:p.text.length},"mergely-c-add");this.change_funcs.push(d)}continue}if(s["op"]=="d"){var c=s["lhs-line-from"],h=s["lhs-line-to"],p=this.editor[e].lineInfo(h);if(p){var d=this.editor[e].markText({line:c,ch:0},{line:h,ch:p.text.length},"mergely-c-rem");this.change_funcs.push(d)}continue}var l=this;for(var v=s["lhs-line-from"],m=s["rhs-line-from"],i=0;v>=0&&v<=s["lhs-line-to"]||m>=0&&m<=s["rhs-line-to"];++v,++m){if(m+i>s["rhs-line-to"]){var g=this.editor[e].getLine(v),d=this.editor[e].markText({line:v,ch:0},{line:v,ch:g.length},"mergely-c-rem");this.change_funcs.push(d);continue}if(v+i>s["lhs-line-to"]){var y=this.editor[t].getLine(m),d=this.editor[e].markText({line:m,ch:0},{line:m,ch:g.length},"mergely-c-add");this.change_funcs.push(d);continue}var g=this.editor[e].getLine(v),y=this.editor[t].getLine(m),b={line:-1,ch:-1},w={line:-1,ch:-1},E={line:-1,ch:-1},S={line:-1,ch:-1},x=new Mgly.LCS(g,y),T=Math.max(g.length,y.length);T==0&&(T=1);var N=1*x.length/T*100;N<10&&x.clear(),x.diff(added=function(e,n){if(E.ch<0)E.line=m,E.ch=e,S.line=m,S.ch=e;else if(e==S.ch+1)S.ch=e;else{if(E.ch>=0&&S.ch>=E.ch){S.ch+=1;var r=l.editor[t].markText(E,S,"mergely-c-add");l.change_funcs.push(r)}E.ch=-1,S.ch=-1,n!="\n"&&this.added(e,n)}},removed=function(t,n){if(b.ch<0)b.line=v,b.ch=t,w.line=v,w.ch=t;else if(t==w.ch+1)w.ch=t;else{if(b.ch>=0&&w.ch>=b.ch){w.ch+=1;var r=l.editor[e].markText(b,w,"mergely-c-rem");l.change_funcs.push(r)}b.ch=-1,w.ch=-1,n!="\n"&&this.removed(t,n)}});if(E.ch>=0&&S.ch>=E.ch){S.ch+=1;var d=this.editor[t].markText(E,S,"mergely-c-add");this.change_funcs.push(d)}if(b.ch>=0&&w.ch>=b.ch){w.ch+=1;var d=this.editor[e].markText(b,w,"mergely-c-rem");this.change_funcs.push(d)}}}},_draw_diff:function(e,t,n){var r=$(this.editor[e].getScrollerElement()).height(),i=$(this.editor[e].getScrollerElement()).children(":first-child").height(),s=r/i,o=r/i,u=$(this.editor[e].getScrollerElement()),a=$(this.editor[t].getScrollerElement()),f=this.editor[e].lineCount(),l=this.editor[t].lineCount();this.trace("draw","visible_page_height",r),this.trace("draw","gutter_height",i),this.trace("draw","visible_page_ratio",s),this.trace("draw","lhs-scroller-top",u.scrollTop()),this.trace("draw","rhs-scroller-top",a.scrollTop());var c=document.getElementById(e+"-"+t+"-canvas");if(c==undefined)throw"Failed to find: "+e+"-"+t+"-canvas";$.each($("canvas"),function(){$(this).get(0).height=r});var h=$("#"+this.id+"-lhs-margin"),p=$("#"+this.id+"-rhs-margin");h.unbind("click"),p.unbind("click");var d=h.get(0),v=p.get(0),m=$(h).offset(),g=$(p).offset(),y=c.getContext("2d"),b=d.getContext("2d"),w=v.getContext("2d");b.beginPath(),b.fillStyle=this.settings.bgcolor,b.strokeStyle="#888",b.fillRect(0,0,6.5,r),b.strokeRect(0,0,6.5,r),w.beginPath(),w.fillStyle=this.settings.bgcolor,w.strokeStyle="#888",w.fillRect(0,0,6.5,r),w.strokeRect(0,0,6.5,r);for(var E in n){var S=n[E],x=S["lhs-y-start"],T=S["lhs-y-end"],N=S["rhs-y-start"],C=S["rhs-y-end"];y.beginPath(),y.strokeStyle=this.settings.fgcolor,y.lineWidth=1,y.moveTo(this.draw_lhs_min,x),y.lineTo(this.draw_lhs_min+this.draw_lhs_width,x),y.lineTo(this.draw_lhs_min+this.draw_lhs_width,T+1),y.lineTo(this.draw_lhs_min,T+1),y.stroke(),y.moveTo(this.draw_rhs_max,N),y.lineTo(this.draw_rhs_max-this.draw_rhs_width,N),y.lineTo(this.draw_rhs_max-this.draw_rhs_width,C+1),y.lineTo(this.draw_rhs_max,C+1),y.stroke(),y.moveTo(this.draw_lhs_min+this.draw_lhs_width,x+(T+1-x)/2),y.lineTo(this.draw_rhs_max-this.draw_rhs_width,N+(C+1-N)/2),y.stroke(),this.trace("draw",S),x=(S["lhs-y-start"]+u.scrollTop())*s,T=(S["lhs-y-end"]+u.scrollTop())*s+1,N=(S["rhs-y-start"]+a.scrollTop())*s,C=(S["rhs-y-end"]+a.scrollTop())*s+1,this.trace("draw","marker calculated",x,T,N,C),b.beginPath(),b.fillStyle=this.settings.fgcolor,b.strokeStyle="#000",b.lineWidth=.5,b.fillRect(1.5,x,4.5,Math.max(T-x,5)),b.strokeRect(1.5,x,4.5,Math.max(T-x,5)),w.beginPath(),w.fillStyle=this.settings.fgcolor,w.strokeStyle="#000",w.lineWidth=.5,w.fillRect(1.5,N,4.5,Math.max(C-N,5)),w.strokeRect(1.5,N,4.5,Math.max(C-N,5))}b.fillStyle="rgba(0, 0, 200, 0.5)",w.fillStyle="rgba(0, 0, 200, 0.5)";var k=h.height()*s,L=u.scrollTop()/i*h.height();this.trace("draw","cls.height",h.height()),this.trace("draw","lhs_scroller.scrollTop()",u.scrollTop()),this.trace("draw","gutter_height",i),this.trace("draw","visible_page_ratio",s),this.trace("draw","from",L,"to",k),b.fillRect(1.5,L,4.5,k),w.fillRect(1.5,L,4.5,k),h.click(function(e){var t=e.pageY-m.top-k/2,n=Math.max(0,t/d.height*u.get(0).scrollHeight);u.scrollTop(n)}),p.click(function(e){var t=e.pageY-g.top-k/2,n=Math.max(0,t/v.height*a.get(0).scrollHeight);a.scrollTop(n)})},trace:function(e){this.settings._debug.indexOf(e)>=0&&(arguments[0]=e+":",console.log(this,[].slice.apply(arguments)))}}),$.pluginMaker=function(e){$.fn[e.prototype.name]=function(t){var n=$.makeArray(arguments),r=n.slice(1),i=undefined;this.each(function(){var s=$.data(this,e.prototype.name);if(s){if(typeof t=="string")i=s[t].apply(s,r);else if(s.update)return alert("here"),s.update.apply(s,n)}else new e(this,t)});if(i!=undefined)return i}},$.pluginMaker(Mgly.mergely) \ No newline at end of file