diff --git a/editor/editor.js b/editor/editor.js index 54ce6b0..3c577a2 100755 --- a/editor/editor.js +++ b/editor/editor.js @@ -251,7 +251,7 @@ $(document).ready(function () { var dlg = $('#dialog-settings').css('visibility','visible').hide(); var f = $.farbtastic('#picker'); var sd = $(''); - var sa = $(''); + var sa = $(''); var sc = $(''); $('body').append(sd); $('body').append(sa); @@ -265,10 +265,11 @@ $(document).ready(function () { }; $.each(conf, function(key, item){ $(item.id).val(item.getColor()); }); + $('#ignore-ws').prop('checked', $('#compare').mergely('options').ignorews); $('#settings').click(function(){ dlg.dialog({ - height: 330, width: 450, modal: true, + height: 350, width: 450, modal: true, buttons: { Apply: function() { var cborder = $('#c-border').val(); @@ -277,11 +278,12 @@ $(document).ready(function () { var abg = $('#a-bg').val(); var dbg = $('#d-bg').val(); var cbg = $('#c-bg').val(); + var ignorews = $('#ignore-ws').prop('checked'); var text = '.mergely.a.rhs.start { border-top: 1px solid ' + aborder + ' }\n\ .mergely.a.lhs.start.end,\n\ .mergely.a.rhs.end { border-bottom: 1px solid ' + aborder + ' }\n\ - .mergely.a.rhs { background-color: ' + abg + ' }\n\ + .mergely.bg.a.rhs { background-color: ' + abg + ' }\n\ .mergely.d.lhs { background-color: ' + dbg + ' }\n\ .mergely.d.lhs.end,\n\ .mergely.d.rhs.start.end { border-bottom: 1px solid ' + dborder + '; }\n\ @@ -296,7 +298,7 @@ $(document).ready(function () { .mergely.ch.d.lhs { background-color: ' + dbg + '; text-decoration: line-through; color: #888; }\n' $('').appendTo('head'); - $('#compare').mergely('options', {fgcolor:{a:aborder,c:cborder,d:dborder}}); + $('#compare').mergely('options', {ignorews: ignorews, fgcolor:{a:aborder,c:cborder,d:dborder}}); $('#compare').mergely('update'); }, Reset: function() { diff --git a/lib/mergely.css b/lib/mergely.css index 26dc42f..fc713fe 100644 --- a/lib/mergely.css +++ b/lib/mergely.css @@ -15,7 +15,7 @@ .mergely.a.rhs.start { border-top: 1px solid #4ba3fa; } .mergely.a.lhs.start.end, .mergely.a.rhs.end { border-bottom: 1px solid #4ba3fa; } -.mergely.a.rhs { background-color: #ddeeff; } +.mergely.bg.a.rhs { background-color: #ddeeff; } .mergely.d.lhs { background-color: #f9e9e9; } .mergely.d.lhs.end, diff --git a/lib/mergely.js b/lib/mergely.js index 5166b6b..d3bcc96 100644 --- a/lib/mergely.js +++ b/lib/mergely.js @@ -90,7 +90,7 @@ jQuery.extend(Mgly.LCS.prototype, { } }); -Mgly.diff = function(lhs, rhs, retain_lines) { +Mgly.diff = function(lhs, rhs, retain_lines, ignore_ws) { this.diff_codes = {}; this.max_code = 0; var lhs_lines = lhs.split('\n'); @@ -99,12 +99,12 @@ Mgly.diff = function(lhs, rhs, retain_lines) { if (rhs.length == 0) rhs_lines = []; var lhs_data = new Object(); - lhs_data.data = this._diff_codes(lhs_lines); + lhs_data.data = this._diff_codes(lhs_lines, ignore_ws); lhs_data.modified = {}; lhs_data.length = Mgly.sizeOf(lhs_data.data); var rhs_data = new Object(); - rhs_data.data = this._diff_codes(rhs_lines); + rhs_data.data = this._diff_codes(rhs_lines, ignore_ws); rhs_data.modified = {}; rhs_data.length = Mgly.sizeOf(rhs_data.data); @@ -154,11 +154,14 @@ jQuery.extend(Mgly.diff.prototype, { } return nf; }, - _diff_codes: function(lines) { + _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; @@ -207,7 +210,7 @@ jQuery.extend(Mgly.diff.prototype, { var maxd = ((lhs_upper - lhs_lower + rhs_upper - rhs_lower) / 2) + 1; vector_d[ offset_down + kdown + 1 ] = lhs_lower; vector_u[ offset_up + kup - 1 ] = lhs_upper; - var ret = new Object(); + var ret = {x:0,y:0}; for (var d = 0; d <= maxd; ++d) { for (var k = kdown - d; k <= kdown + d; k += 2) { var x, y; @@ -335,14 +338,16 @@ Mgly.mergely = function(el, options) { }; jQuery.extend(Mgly.mergely.prototype, { - name: "mergely", + name: 'mergely', //http://jupiterjs.com/news/writing-the-perfect-jquery-plugin init: function(el, options) { this.settings = { autoupdate: true, autoresize: true, + ignorews: false, fadein: 'fast', - editor_width: '400px', editor_height: '400px', + editor_width: '400px', + editor_height: '400px', resize_timeout: 500, change_timeout: 150, fgcolor: {a:'#4ba3fa',c:'#cccccc',d:'#ff7f7f'}, @@ -475,7 +480,12 @@ jQuery.extend(Mgly.mergely.prototype, { } }, options: function(opts) { - jQuery.extend(this.settings, opts); + if (opts) { + jQuery.extend(this.settings, opts); + } + else { + return this.settings; + } }, swap: function() { if (this.lhs_cmsettings.readOnly || this.rhs_cmsettings.readOnly) return; @@ -530,7 +540,7 @@ jQuery.extend(Mgly.mergely.prototype, { 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); + var d = new Mgly.diff(lhs, rhs, retain_lines = true, ignore_ws = this.settings.ignorews); return d.normal_form(); }, _setup: function(el) { @@ -728,7 +738,7 @@ jQuery.extend(Mgly.mergely.prototype, { _diff: function(editor_name1, editor_name2) { var lhs = this.editor[editor_name1].getValue(); var rhs = this.editor[editor_name2].getValue(); - var d = new Mgly.diff(lhs, rhs); + var d = new Mgly.diff(lhs, rhs, false, this.settings.ignorews); this.changes = this._parse_diff(editor_name1, editor_name2, d.normal_form()); this._calculate_offsets(editor_name1, editor_name2, this.changes); this._markup_changes(editor_name1, editor_name2, this.changes); diff --git a/test/tests.js b/test/tests.js index 42157b3..0d07daa 100755 --- a/test/tests.js +++ b/test/tests.js @@ -21,11 +21,12 @@ $(document).ready(function(){
\ '); - var init = function() { + var init = function(options) { $('body').append(DMERGELY); console.log($('#test-mergely').length); var mergely = new Mgly.mergely(); mergely.init($('#mergely'), { + ignorews: (options && options['ignorews']) || false, height: function(h) { return 400; } }); return mergely; @@ -34,7 +35,6 @@ $(document).ready(function(){ (function (JsUnit) { JsUnit.module('Tests'); - // Summary: // Add one line to the rhs where the lhs is empty. // Description: @@ -987,6 +987,215 @@ $(document).ready(function(){ var t1 = new Date().getTime(); console.log('diff', diff, 'time: ' + (t1 - t0)); }); + + // Summary: + // Compare two lines where only difference is white-space, with ignore white-space disabled. + // Description: + // This tests comparing two lines that differ only in white-space, without ignoring + // white-space. + // Example: + // one one. + // two .two + JsUnit.test('case-12-whitespace-not-ignore', function() { + mergely = init(); + mergely.lhs('one\ntwo'); + mergely.rhs('one\t\n two'); + JsUnit.okay(mergely.get('lhs') == 'one\ntwo', 'Expected "one\ntwo"'); + JsUnit.okay(mergely.get('rhs') == 'one\t\n two', 'Expected "one\t\n two"'); + var diff = '1,2c1,2\n' + + '< one\n' + + '< two\n' + + '---\n' + + '> one\t\n' + + '> two\n'; + JsUnit.okay(mergely.diff() == diff, 'Unexpected change diff'); + console.log('diff', mergely.diff()); + + var d = new Mgly.diff(mergely.get('lhs'), mergely.get('rhs')); + var changes = mergely._parse_diff('#mergely-lhs', '#mergely-rhs', d.normal_form()); + console.log('changes', changes); + changes = mergely._calculate_offsets('mergely-lhs', 'mergely-rhs', changes); + mergely._markup_changes('mergely-lhs', 'mergely-rhs', changes); + console.log('changes', changes); + JsUnit.okay(changes.length == 1, 'Expected 1 change'); + + // test lhs classes + var lhs_info = mergely.editor['mergely-lhs'].lineInfo(0); + var classes = lhs_info.bgClass.split(' '); + var ok_classes = ['mergely', 'c', 'lhs', 'start']; + var notok_classes = ['d', 'a', 'end']; + for (var i in ok_classes) { + var clazz = ok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) >= 0, 'Expected lhs[0] row to have class, "' + clazz + '", classes: ' + lhs_info.bgClass); + } + for (var i in notok_classes) { + var clazz = notok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) < 0, 'Did not expect lhs[0] row to have class, "' + clazz + '"'); + } + lhs_info = mergely.editor['mergely-lhs'].lineInfo(1); + classes = lhs_info.bgClass.split(' '); + ok_classes = ['mergely', 'c', 'lhs', 'end']; + notok_classes = ['d', 'a', 'start']; + for (var i in ok_classes) { + var clazz = ok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) >= 0, 'Expected lhs[1] row to have class, "' + clazz + '", classes: ' + lhs_info.bgClass); + } + for (var i in notok_classes) { + var clazz = notok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) < 0, 'Did not expect lhs[1] row to have class, "' + clazz + '"'); + } + + // test rhs classes + var rhs_info = mergely.editor['mergely-rhs'].lineInfo(0); + var classes = rhs_info.bgClass.split(' '); + var ok_classes = ['mergely', 'c', 'rhs', 'start']; + var notok_classes = ['d', 'a', 'end']; + for (var i in ok_classes) { + var clazz = ok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) >= 0, 'Expected rhs row[0] to have class, "' + clazz + '", classes: ' + rhs_info.bgClass); + } + for (var i in notok_classes) { + var clazz = notok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) < 0, 'Did not expect rhs[0] row to have class, "' + clazz + '"'); + } + var rhs_info = mergely.editor['mergely-rhs'].lineInfo(1); + classes = rhs_info.bgClass.split(' '); + ok_classes = ['mergely', 'a', 'rhs', 'end']; + notok_classes = ['d', 'start']; + for (var i in ok_classes) { + var clazz = ok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) >= 0, 'Expected rhs row[1] to have class, "' + clazz + '", classes: ' + rhs_info.bgClass); + } + for (var i in notok_classes) { + var clazz = notok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) < 0, 'Did not expect rhs[1] row to have class, "' + clazz + '"'); + } + + var extents = mergely._get_extents(); + console.log('extents', extents); + var valign = 2.0;//vertical, esthetic alignment + var change = changes[0]; + // diff + JsUnit.okay(change['lhs-line-from'] == 0, 'Expected lhs change to be start from 0'); + JsUnit.okay(change['lhs-line-to'] == 1, 'Expected lhs change to be finish at 1'); + JsUnit.okay(change['rhs-line-from'] == 0, 'Expected rhs change to be finish at 0'); + JsUnit.okay(change['rhs-line-to'] == 1, 'Expected rhs change to be finish at 1'); + // markup + JsUnit.okay(change['lhs-y-start'] == change['rhs-y-start'], 'Expected lhs/rhs start to be the same'); + JsUnit.okay(change['lhs-y-end'] == change['rhs-y-end'], 'Expected lhs/rhs end to be the same'); + JsUnit.okay(change['lhs-y-start'] > 0.0, 'Expected lhs start to be more than 0'); + JsUnit.okay(change['lhs-y-end'] > 0.0, 'Expected lhs end to be more than 0'); + JsUnit.okay(change['rhs-y-start'] > 0.0, 'Expected rhs start to be more than 0'); + JsUnit.okay(change['rhs-y-end'] > 0.0, 'Expected rhs end to be more than 0'); + + if (window[this.name] != true) { + mergely.unbind(); + $('#test-mergely').remove(); + } + window[this.name] = true; + }); + + // Summary: + // Compare two lines where only difference is white-space, with ignore white-space. + // Description: + // This tests comparing two lines that differ only in white-space, ignoring + // white-space. + // Example: + // one one. + // two .two + JsUnit.test('case-13-whitespace-ignore', function() { + mergely = init({ignorews: true}); + mergely.lhs('one\ntwo'); + mergely.rhs('one\t\n two'); + JsUnit.okay(mergely.get('lhs') == 'one\ntwo', 'Expected "one\ntwo"'); + JsUnit.okay(mergely.get('rhs') == 'one\t\n two', 'Expected "one\t\n two"'); + var diff = ''; + JsUnit.okay(mergely.diff() == diff, 'Unexpected change diff'); + console.log('diff', mergely.diff()); + + var d = new Mgly.diff(mergely.get('lhs'), mergely.get('rhs')); + var changes = mergely._parse_diff('#mergely-lhs', '#mergely-rhs', d.normal_form()); + console.log('changes', changes); + changes = mergely._calculate_offsets('mergely-lhs', 'mergely-rhs', changes); + mergely._markup_changes('mergely-lhs', 'mergely-rhs', changes); + console.log('changes', changes); + JsUnit.okay(changes.length == 1, 'Expected 1 change'); + + // test lhs classes + var lhs_info = mergely.editor['mergely-lhs'].lineInfo(0); + var classes = lhs_info.bgClass.split(' '); + var ok_classes = ['mergely', 'c', 'lhs', 'start']; + var notok_classes = ['d', 'a', 'end']; + for (var i in ok_classes) { + var clazz = ok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) >= 0, 'Expected lhs[0] row to have class, "' + clazz + '", classes: ' + lhs_info.bgClass); + } + for (var i in notok_classes) { + var clazz = notok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) < 0, 'Did not expect lhs[0] row to have class, "' + clazz + '"'); + } + lhs_info = mergely.editor['mergely-lhs'].lineInfo(1); + classes = lhs_info.bgClass.split(' '); + ok_classes = ['mergely', 'c', 'lhs', 'end']; + notok_classes = ['d', 'a', 'start']; + for (var i in ok_classes) { + var clazz = ok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) >= 0, 'Expected lhs[1] row to have class, "' + clazz + '", classes: ' + lhs_info.bgClass); + } + for (var i in notok_classes) { + var clazz = notok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) < 0, 'Did not expect lhs[1] row to have class, "' + clazz + '"'); + } + + // test rhs classes + var rhs_info = mergely.editor['mergely-rhs'].lineInfo(0); + var classes = rhs_info.bgClass.split(' '); + var ok_classes = ['mergely', 'c', 'rhs', 'start']; + var notok_classes = ['d', 'a', 'end']; + for (var i in ok_classes) { + var clazz = ok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) >= 0, 'Expected rhs row[0] to have class, "' + clazz + '", classes: ' + rhs_info.bgClass); + } + for (var i in notok_classes) { + var clazz = notok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) < 0, 'Did not expect rhs[0] row to have class, "' + clazz + '"'); + } + var rhs_info = mergely.editor['mergely-rhs'].lineInfo(1); + classes = rhs_info.bgClass.split(' '); + ok_classes = ['mergely', 'a', 'rhs', 'end']; + notok_classes = ['d', 'start']; + for (var i in ok_classes) { + var clazz = ok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) >= 0, 'Expected rhs row[1] to have class, "' + clazz + '", classes: ' + rhs_info.bgClass); + } + for (var i in notok_classes) { + var clazz = notok_classes[i]; + JsUnit.okay($.inArray(clazz, classes) < 0, 'Did not expect rhs[1] row to have class, "' + clazz + '"'); + } + + var extents = mergely._get_extents(); + console.log('extents', extents); + var valign = 2.0;//vertical, esthetic alignment + var change = changes[0]; + // diff + JsUnit.okay(change['lhs-line-from'] == 0, 'Expected lhs change to be start from 0'); + JsUnit.okay(change['lhs-line-to'] == 1, 'Expected lhs change to be finish at 1'); + JsUnit.okay(change['rhs-line-from'] == 0, 'Expected rhs change to be finish at 0'); + JsUnit.okay(change['rhs-line-to'] == 1, 'Expected rhs change to be finish at 1'); + // markup + JsUnit.okay(change['lhs-y-start'] == change['rhs-y-start'], 'Expected lhs/rhs start to be the same'); + JsUnit.okay(change['lhs-y-end'] == change['rhs-y-end'], 'Expected lhs/rhs end to be the same'); + JsUnit.okay(change['lhs-y-start'] > 0.0, 'Expected lhs start to be more than 0'); + JsUnit.okay(change['lhs-y-end'] > 0.0, 'Expected lhs end to be more than 0'); + JsUnit.okay(change['rhs-y-start'] > 0.0, 'Expected rhs start to be more than 0'); + JsUnit.okay(change['rhs-y-end'] > 0.0, 'Expected rhs end to be more than 0'); + + if (window[this.name] != true) { + mergely.unbind(); + $('#test-mergely').remove(); + } + window[this.name] = true; + }); JsUnit.start(); }(JsUnit));