Code selection by column on DIFF screen (#3091)

* Code selection by column on DIFF screen

Fix of #3089

Two ways to select a text:

1. Position the mouse at the start of the text, press mouse left button, keep pressed, drag to the end of the text, release the button

2. Position the mouse at the start of the text, press mouse left button, release the button, position the mouse to the end of the text, press shift key + mouse left button.

Two ways to copy the selected text:

1. Press Ctrl + C or Ctrl + Ins

2. Mouse right button on the text to display the context menu and choose Copy

SPLIT VIEW (code at the left is the LOCAL code and code at the right is the REMOTE code):
- Text can be selected only at the left side, or only at the right side.
- The dummy empty lines which show the place of lines which exist only at the other side are not copied.

UNIFIED VIEW (LOCAL and REMOTE are mixed in the same column, "green plus" lines correspond to lines only in the LOCAL code, "red minus" lines correspond to lines only in the REMOTE code.
- Only the lines from the REMOTE code are copied

PATCH VIEW (split view + one extra column on the left)
- Same features as the SPLIT VIEW

* corrections lint javascript

* merge latest abapgit changes

* corrections lint javascript

* JS refactor functions to prototyped fns (classes)

* JS lint corrections + minor last minute changes

* conform current common.js standards

* LINT conform to common.js standards

* unused lines removed
This commit is contained in:
sandraros 2019-12-02 09:32:15 +01:00 committed by Lars Hvam
parent 02204d07b4
commit 175f2fabec
4 changed files with 214 additions and 21 deletions

View File

@ -432,6 +432,58 @@ table.diff_tab td.code {
table.diff_tab tbody tr:first-child td { padding-top: 0.5em; }
table.diff_tab tbody tr:last-child td { padding-bottom: 0.5em; }
table.diff_tab td.mark, th.mark {
width: 0.1%;
-ms-user-select: none;
user-select: none;
cursor: default;
}
.diff_select_left td.diff_right,
.diff_select_left td.diff_right *,
.diff_select_left th.diff_right,
.diff_select_left th.diff_right *,
.diff_select_right td.diff_left,
.diff_select_right td.diff_left *,
.diff_select_right th.diff_left,
.diff_select_right th.diff_left * {
-ms-user-select: none;
user-select: none;
cursor: text;
}
.diff_select_left td.diff_left,
.diff_select_left td.diff_left *,
.diff_select_left th.diff_left,
.diff_select_left th.diff_left *,
.diff_select_right td.diff_right,
.diff_select_right td.diff_right *,
.diff_select_right th.diff_right,
.diff_select_right th.diff_right * {
-ms-user-select: text;
user-select: text;
}
td.diff_others::selection,
td.diff_others *::selection,
th.diff_others::selection,
th.diff_others *::selection {
background-color: transparent;
cursor: default;
}
.diff_select_left td.diff_right::selection,
.diff_select_left td.diff_right *::selection,
.diff_select_left th.diff_right::selection,
.diff_select_left th.diff_right *::selection,
.diff_select_right td.diff_left::selection,
.diff_select_right td.diff_left *::selection,
.diff_select_right th.diff_left::selection,
.diff_select_right th.diff_left *::selection {
background-color: transparent;
cursor: text;
}
/* DEBUG INFO STYLES */
div.debug_container {
padding: 0.5em;

View File

@ -15,7 +15,7 @@
<RELID>MI</RELID>
<OBJID>ZABAPGIT_CSS_COMMON</OBJID>
<NAME>filename</NAME>
<VALUE>~wwwtmp.css</VALUE>
<VALUE>common.css</VALUE>
</WWWPARAMS>
<WWWPARAMS>
<RELID>MI</RELID>

View File

@ -770,6 +770,133 @@ function addMarginBottom(){
document.getElementsByTagName("body")[0].style.marginBottom = screen.height + "px";
}
/**********************************************************
* Diff page logic of column selection
**********************************************************/
function DiffColumnSelection() {
this.selectedColumnIdx = -1;
this.lineNumColumnIdx = -1;
//https://stackoverflow.com/questions/2749244/javascript-setinterval-and-this-solution
document.addEventListener("mousedown", this.mousedownEventListener.bind(this));
document.addEventListener("copy", this.copyEventListener.bind(this));
}
DiffColumnSelection.prototype.mousedownEventListener = function(e) {
// Select text in a column of an HTML table and copy to clipboard (in DIFF view)
// (https://stackoverflow.com/questions/6619805/select-text-in-a-column-of-an-html-table)
// Process mousedown event for all TD elements -> apply CSS class at TABLE level.
// (https://stackoverflow.com/questions/40956717/how-to-addeventlistener-to-multiple-elements-in-a-single-line)
var unifiedLineNumColumnIdx = 0;
var unifiedCodeColumnIdx = 3;
var splitLineNumLeftColumnIdx = 0;
var splitCodeLeftColumnIdx = 2;
var splitLineNumRightColumnIdx = 3;
var splitCodeRightColumnIdx = 5;
if (e.button !== 0) return; // function is only valid for left button, not right button
var td = e.target;
while (td != undefined && td.tagName != "TD" && td.tagName != "TBODY") td = td.parentElement;
if (td == undefined) return;
var table = td.parentElement.parentElement;
var patchColumnCount = 0;
if (td.parentElement.cells[0].classList.contains("patch")) {
patchColumnCount = 1;
}
if (td.classList.contains("diff_left")) {
table.classList.remove("diff_select_right");
table.classList.add("diff_select_left");
if ( window.getSelection() && this.selectedColumnIdx != splitCodeLeftColumnIdx + patchColumnCount ) {
// De-select to avoid effect of dragging selection in case the right column was first selected
if (document.body.createTextRange) { // All IE but Edge
// document.getSelection().removeAllRanges() may trigger error
// so use this code which is equivalent but does not fail
// (https://stackoverflow.com/questions/22914075/javascript-error-800a025e-using-range-selector)
range = document.body.createTextRange();
range.collapse();
range.select();
} else {
document.getSelection().removeAllRanges();
}}
this.selectedColumnIdx = splitCodeLeftColumnIdx + patchColumnCount;
this.lineNumColumnIdx = splitLineNumLeftColumnIdx + patchColumnCount;
} else if (td.classList.contains("diff_right")) {
table.classList.remove("diff_select_left");
table.classList.add("diff_select_right");
if ( window.getSelection() && this.selectedColumnIdx != splitCodeRightColumnIdx + patchColumnCount ) {
if (document.body.createTextRange) { // All IE but Edge
// document.getSelection().removeAllRanges() may trigger error
// so use this code which is equivalent but does not fail
// (https://stackoverflow.com/questions/22914075/javascript-error-800a025e-using-range-selector)
var range = document.body.createTextRange();
range.collapse();
range.select();
} else {
document.getSelection().removeAllRanges();
}}
this.selectedColumnIdx = splitCodeRightColumnIdx + patchColumnCount;
this.lineNumColumnIdx = splitLineNumRightColumnIdx + patchColumnCount;
} else if (td.classList.contains("diff_unified")) {
this.selectedColumnIdx = unifiedCodeColumnIdx;
this.lineNumColumnIdx = unifiedLineNumColumnIdx;
} else {
this.selectedColumnIdx = -1;
this.lineNumColumnIdx = -1;
}
};
DiffColumnSelection.prototype.copyEventListener = function(e) {
// Select text in a column of an HTML table and copy to clipboard (in DIFF view)
// (https://stackoverflow.com/questions/6619805/select-text-in-a-column-of-an-html-table)
var td = e.target;
while (td != undefined && td.tagName != "TD" && td.tagName != "TBODY") td = td.parentElement;
if(td != undefined){
// Use window.clipboardData instead of e.clipboardData
// (https://stackoverflow.com/questions/23470958/ie-10-copy-paste-issue)
var clipboardData = ( e.clipboardData == undefined ? window.clipboardData : e.clipboardData );
var text = this.getSelectedText();
clipboardData.setData("text", text);
e.preventDefault();
}
};
DiffColumnSelection.prototype.getSelectedText = function() {
// Select text in a column of an HTML table and copy to clipboard (in DIFF view)
// (https://stackoverflow.com/questions/6619805/select-text-in-a-column-of-an-html-table)
var sel = window.getSelection(),
range = sel.getRangeAt(0),
doc = range.cloneContents(),
nodes = doc.querySelectorAll("tr"),
text = "";
if (nodes.length === 0) {
text = doc.textContent;
} else {
var newline = "",
realThis = this;
[].forEach.call(nodes, function(tr, i) {
var cellIdx = ( i==0 ? 0 : realThis.selectedColumnIdx );
if (tr.cells.length > cellIdx) {
var tdSelected = tr.cells[cellIdx];
var tdLineNum = tr.cells[realThis.lineNumColumnIdx];
// copy is interesting for remote code, don't copy lines which exist only locally
if (i==0 || tdLineNum.getAttribute("line-num")!="") {
text += newline + tdSelected.textContent;
// special processing for TD tag which sometimes contains newline
// (expl: /src/ui/zabapgit_js_common.w3mi.data.js) so don't add newline again in that case.
var lastChar = tdSelected.textContent[ tdSelected.textContent.length - 1 ];
if ( lastChar == "\n" ) newline = "";
else newline = "\n";
}}});}
return text;
};
/**********************************************************
* Other functions
**********************************************************/

View File

@ -669,9 +669,10 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_DIFF IMPLEMENTATION.
ENDIF.
IF mv_unified = abap_true.
ro_html->add( '<th class="num"></th>' ).
ro_html->add( '<th class="mark"></th>' ).
ro_html->add( |<th>@@ { is_diff_line-new_num } @@ { lv_beacon }</th>| ).
ELSE.
ro_html->add( |<th colspan="3">@@ { is_diff_line-new_num } @@ { lv_beacon }</th>| ).
ro_html->add( |<th colspan="6">@@ { is_diff_line-new_num } @@ { lv_beacon }</th>| ).
ENDIF.
ro_html->add( '</tr>' ).
@ -850,8 +851,9 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_DIFF IMPLEMENTATION.
lv_mark = `+`.
ENDIF.
ENDIF.
lv_new = |<td class="num" line-num="{ is_diff_line-new_num }"></td>|
&& |<td class="code{ lv_bg }">{ lv_mark }{ is_diff_line-new }</td>|.
lv_new = |<td class="num diff_others" line-num="{ is_diff_line-new_num }"></td>|
&& |<td class="mark diff_others">{ lv_mark }</td>|
&& |<td class="code{ lv_bg } diff_left">{ is_diff_line-new }</td>|.
IF lv_mark <> ` `.
lv_patch_line_possible = abap_true.
@ -869,8 +871,9 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_DIFF IMPLEMENTATION.
lv_mark = `-`.
ENDIF.
ENDIF.
lv_old = |<td class="num" line-num="{ is_diff_line-old_num }"></td>|
&& |<td class="code{ lv_bg }">{ lv_mark }{ is_diff_line-old }</td>|.
lv_old = |<td class="num diff_others" line-num="{ is_diff_line-old_num }"></td>|
&& |<td class="mark diff_others">{ lv_mark }</td>|
&& |<td class="code{ lv_bg } diff_right">{ is_diff_line-old }</td>|.
IF lv_mark <> ` `.
lv_patch_line_possible = abap_true.
@ -912,16 +915,18 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_DIFF IMPLEMENTATION.
IF is_diff_line-result <> zif_abapgit_definitions=>c_diff-update.
LOOP AT mt_delayed_lines ASSIGNING <ls_diff_line>.
ro_html->add( '<tr>' ). "#EC NOTEXT
ro_html->add( |<td class="num" line-num="{ <ls_diff_line>-old_num }"></td>|
&& |<td class="num" line-num=""></td>|
&& |<td class="code diff_del">-{ <ls_diff_line>-old }</td>| ).
ro_html->add( |<td class="num diff_others" line-num="{ <ls_diff_line>-old_num }"></td>|
&& |<td class="num diff_others" line-num=""></td>|
&& |<td class="mark diff_others">-</td>|
&& |<td class="code diff_del diff_unified">{ <ls_diff_line>-old }</td>| ).
ro_html->add( '</tr>' ). "#EC NOTEXT
ENDLOOP.
LOOP AT mt_delayed_lines ASSIGNING <ls_diff_line>.
ro_html->add( '<tr>' ). "#EC NOTEXT
ro_html->add( |<td class="num" line-num=""></td>|
&& |<td class="num" line-num="{ <ls_diff_line>-new_num }"></td>|
&& |<td class="code diff_ins">+{ <ls_diff_line>-new }</td>| ).
ro_html->add( |<td class="num diff_others" line-num=""></td>|
&& |<td class="num diff_others" line-num="{ <ls_diff_line>-new_num }"></td>|
&& |<td class="mark diff_others">+</td>|
&& |<td class="code diff_ins diff_others">{ <ls_diff_line>-new }</td>| ).
ro_html->add( '</tr>' ). "#EC NOTEXT
ENDLOOP.
CLEAR mt_delayed_lines.
@ -932,17 +937,20 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_DIFF IMPLEMENTATION.
WHEN zif_abapgit_definitions=>c_diff-update.
APPEND is_diff_line TO mt_delayed_lines. " Delay output of subsequent updates
WHEN zif_abapgit_definitions=>c_diff-insert.
ro_html->add( |<td class="num" line-num=""></td>|
&& |<td class="num" line-num="{ is_diff_line-new_num }"></td>|
&& |<td class="code diff_ins">+{ is_diff_line-new }</td>| ).
ro_html->add( |<td class="num diff_others" line-num=""></td>|
&& |<td class="num diff_others" line-num="{ is_diff_line-new_num }"></td>|
&& |<td class="mark diff_others">+</td>|
&& |<td class="code diff_ins diff_others">{ is_diff_line-new }</td>| ).
WHEN zif_abapgit_definitions=>c_diff-delete.
ro_html->add( |<td class="num" line-num="{ is_diff_line-old_num }"></td>|
&& |<td class="num" line-num=""></td>|
&& |<td class="code diff_del">-{ is_diff_line-old }</td>| ).
ro_html->add( |<td class="num diff_others" line-num="{ is_diff_line-old_num }"></td>|
&& |<td class="num diff_others" line-num=""></td>|
&& |<td class="mark diff_others">-</td>|
&& |<td class="code diff_del diff_unified">{ is_diff_line-old }</td>| ).
WHEN OTHERS. "none
ro_html->add( |<td class="num" line-num="{ is_diff_line-old_num }"></td>|
&& |<td class="num" line-num="{ is_diff_line-new_num }"></td>|
&& |<td class="code"> { is_diff_line-old }</td>| ).
ro_html->add( |<td class="num diff_others" line-num="{ is_diff_line-old_num }"></td>|
&& |<td class="num diff_others" line-num="{ is_diff_line-new_num }"></td>|
&& |<td class="mark diff_others">&nbsp;</td>|
&& |<td class="code diff_unified">{ is_diff_line-old }</td>| ).
ENDCASE.
ro_html->add( '</tr>' ). "#EC NOTEXT
@ -1000,6 +1008,7 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_DIFF IMPLEMENTATION.
IF mv_unified = abap_true.
ro_html->add( '<th class="num">old</th>' ). "#EC NOTEXT
ro_html->add( '<th class="num">new</th>' ). "#EC NOTEXT
ro_html->add( '<th class="mark"></th>' ). "#EC NOTEXT
ro_html->add( '<th>code</th>' ). "#EC NOTEXT
ELSE.
@ -1011,8 +1020,10 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_DIFF IMPLEMENTATION.
ENDIF.
ro_html->add( '<th class="num"></th>' ). "#EC NOTEXT
ro_html->add( '<th class="mark"></th>' ). "#EC NOTEXT
ro_html->add( '<th>LOCAL</th>' ). "#EC NOTEXT
ro_html->add( '<th class="num"></th>' ). "#EC NOTEXT
ro_html->add( '<th class="mark"></th>' ). "#EC NOTEXT
ro_html->add( '<th>REMOTE</th>' ). "#EC NOTEXT
ENDIF.
@ -1048,6 +1059,9 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_DIFF IMPLEMENTATION.
ro_html->add( ' hotkeyDescription: "Jump to file ..."' ).
ro_html->add( '});' ).
" Feature for selecting ABAP code by column and copy to clipboard
ro_html->add( 'var columnSelection = new DiffColumnSelection();' ).
ENDMETHOD.