Added keyboard shortcuts à la WinMerge.

Alt + Up or Down arrow : go to previous or next difference
Alt + Left or Right arrow : merge difference using right or left content

Shift, Ctr, Alt or Meta keys can be used indifferntly (to cope with browser's idiosyncratics).
Event handler is now attached to text editor. This is clearly to review (does not capture all page events and too intrusive).

New state "current_diff" has been added.

Need to scroll the editor to center it on currently active state (scrollToChange function to add).
This commit is contained in:
Kljh
2014-08-16 17:31:15 +01:00
parent e4c36f35ef
commit 885fcd4e05

View File

@@ -386,11 +386,13 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
viewport: false,
ignorews: false,
fadein: 'fast',
editor_width: '400px',
editor_width: '650px',
editor_height: '400px',
resize_timeout: 500,
change_timeout: 150,
fgcolor: {a:'#4ba3fa',c:'#a3a3a3',d:'#ff7f7f'},
current_diff: 0, // currently active difference, in 0 .. changes.length range.
fgcolor: {a:'#4ba3fa',c:'#a3a3a3',d:'#ff7f7f', // color for differences (soft color)
ca:'#4b73ff',cc:'#737373',cd:'#ff4f4f'}, // color for currently active difference (bright color)
bgcolor: '#eee',
vpcolor: 'rgba(0, 0, 200, 0.5)',
lhs: function(setValue) { },
@@ -686,6 +688,74 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
var setv = this.editor[this.id + '-rhs'].getDoc().setValue;
this.settings.rhs(setv.bind(this.editor[this.id + '-rhs'].getDoc()));
}
// kljh: register WinMerge style key bindings
var self = this;
el.addEventListener("keydown", function(evt) {
if (evt.defaultPrevented)
;//return; // Should do nothing if the key event was already consumed.
if (!evt.shiftKey && !evt.altKey && !evt.ctrlKey && !evt.metaKey)
return; // if none of Shift, Alt, Ctrl or Meta key is used then do nothing
var shift_key = 16, alt_key = 17, ctrlKey = 18, metaKey = 91; // 13, 27 ?
var up_arrow = 38, down_arrow = 40, left_arrow = 37, right_arrow = 39;
if (!evt.key) {
// use keyCode as key
evt.key = evt.which;
}
switch (evt.key) {
case "ArrowDown":
case down_arrow:
self.settings.current_diff++;
self._changed(self.id + '-lhs', self.id + '-rhs');
break;
case "ArrowUp":
case up_arrow:
self.settings.current_diff--;
self.settings.current_diff = Math.max(self.settings.current_diff, 0);
self._changed(self.id + '-lhs', self.id + '-rhs');
break;
case "ArrowLeft":
case left_arrow:
// !! recalculating the changes !!
var editor_name1 = self.id + '-lhs';
var editor_name2 = self.id + '-rhs';
var lhs = self.editor[editor_name1].getValue();
var rhs = self.editor[editor_name2].getValue();
var d = new Mgly.diff(lhs, rhs, self.settings);
var changes = Mgly.DiffParser(d.normal_form());
var change = changes[self.settings.current_diff];
self._merge_change(change, "rhs", "lhs");
break;
case "ArrowRight":
case right_arrow:
// !! recalculating the changes !!
var editor_name1 = self.id + '-lhs';
var editor_name2 = self.id + '-rhs';
var lhs = self.editor[editor_name1].getValue();
var rhs = self.editor[editor_name2].getValue();
var d = new Mgly.diff(lhs, rhs, self.settings);
var changes = Mgly.DiffParser(d.normal_form());
var change = changes[self.settings.current_diff];
self._merge_change(change, "lhs", "rhs");
break;
case "Enter":
// Do something for "enter" or "return" key press.
break;
case "Escape":
// Do something for "esc" key press.
break;
default:
return; // Quit when this doesn't handle the key event.
}
// Consume the event for suppressing "double action".
//event.preventDefault();
});
},
_scrolling: function(editor_name) {
@@ -1230,7 +1300,21 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
});
var change = self.changes[cid];
var line = {lhs: ed['lhs'].lineInfo(llt), rhs: ed['rhs'].lineInfo(rlt)};
// kljh: not used
//var line = {lhs: ed['lhs'].lineInfo(llt), rhs: ed['rhs'].lineInfo(rlt)};
self._merge_change(change, side, oside);
return false;
});
this.trace('change', 'markup buttons time', timer.stop());
},
_merge_change : function(change, side, oside) {
var editor_name1 = this.id + '-lhs';
var editor_name2 = this.id + '-rhs';
var led = this.editor[editor_name1];
var red = this.editor[editor_name2];
var ed = {lhs:led, rhs:red};
var text = ed[side].getRange(
CodeMirror.Pos(change[side + '-line-from'], 0),
@@ -1271,9 +1355,6 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
//reset
ed['lhs'].setValue(ed['lhs'].getValue());
ed['rhs'].setValue(ed['rhs'].getValue());
return false;
});
this.trace('change', 'markup buttons time', timer.stop());
},
_draw_info: function(editor_name1, editor_name2) {
var visible_page_height = jQuery(this.editor[editor_name1].getScrollerElement()).height();
@@ -1344,14 +1425,14 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
this.trace('draw', 'marker calculated', lhs_y_start, lhs_y_end, rhs_y_start, rhs_y_end);
ctx_lhs.beginPath();
ctx_lhs.fillStyle = this.settings.fgcolor[change['op']];
ctx_lhs.fillStyle = this.settings.fgcolor[(this.settings.current_diff==i?'c':'')+change['op']];
ctx_lhs.strokeStyle = '#000';
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.fillStyle = this.settings.fgcolor[(this.settings.current_diff==i?'c':'')+change['op']];
ctx_rhs.strokeStyle = '#000';
ctx_rhs.lineWidth = 0.5;
ctx_rhs.fillRect(1.5, rhs_y_start, 4.5, Math.max(rhs_y_end - rhs_y_start, 5));
@@ -1370,8 +1451,8 @@ jQuery.extend(Mgly.CodeMirrorDiffView.prototype, {
// draw left box
ctx.beginPath();
ctx.strokeStyle = this.settings.fgcolor[change['op']];
ctx.lineWidth = 1;
ctx.strokeStyle = this.settings.fgcolor[(this.settings.current_diff==i?'c':'')+change['op']];
ctx.lineWidth = (this.settings.current_diff==i) ? 1.5 : 1;
var rectWidth = this.draw_lhs_width;
var rectHeight = lhs_y_end - lhs_y_start - 1;