diff --git a/src/ui/zabapgit_css_common.w3mi.data.css b/src/ui/zabapgit_css_common.w3mi.data.css index 794e75271..1bc27f6fd 100644 --- a/src/ui/zabapgit_css_common.w3mi.data.css +++ b/src/ui/zabapgit_css_common.w3mi.data.css @@ -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; diff --git a/src/ui/zabapgit_css_common.w3mi.xml b/src/ui/zabapgit_css_common.w3mi.xml index dbdbed67e..cbea95037 100644 --- a/src/ui/zabapgit_css_common.w3mi.xml +++ b/src/ui/zabapgit_css_common.w3mi.xml @@ -15,7 +15,7 @@ MI ZABAPGIT_CSS_COMMON filename - ~wwwtmp.css + common.css MI diff --git a/src/ui/zabapgit_js_common.w3mi.data.js b/src/ui/zabapgit_js_common.w3mi.data.js index 1177f8255..371196409 100644 --- a/src/ui/zabapgit_js_common.w3mi.data.js +++ b/src/ui/zabapgit_js_common.w3mi.data.js @@ -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 **********************************************************/ diff --git a/src/ui/zcl_abapgit_gui_page_diff.clas.abap b/src/ui/zcl_abapgit_gui_page_diff.clas.abap index cc3b7435f..7e872aa71 100644 --- a/src/ui/zcl_abapgit_gui_page_diff.clas.abap +++ b/src/ui/zcl_abapgit_gui_page_diff.clas.abap @@ -669,9 +669,10 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_DIFF IMPLEMENTATION. ENDIF. IF mv_unified = abap_true. ro_html->add( '' ). + ro_html->add( '' ). ro_html->add( |@@ { is_diff_line-new_num } @@ { lv_beacon }| ). ELSE. - ro_html->add( |@@ { is_diff_line-new_num } @@ { lv_beacon }| ). + ro_html->add( |@@ { is_diff_line-new_num } @@ { lv_beacon }| ). ENDIF. ro_html->add( '' ). @@ -850,8 +851,9 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_DIFF IMPLEMENTATION. lv_mark = `+`. ENDIF. ENDIF. - lv_new = || - && |{ lv_mark }{ is_diff_line-new }|. + lv_new = || + && |{ lv_mark }| + && |{ is_diff_line-new }|. 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 = || - && |{ lv_mark }{ is_diff_line-old }|. + lv_old = || + && |{ lv_mark }| + && |{ is_diff_line-old }|. 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 . ro_html->add( '' ). "#EC NOTEXT - ro_html->add( || - && || - && |-{ -old }| ). + ro_html->add( || + && || + && |-| + && |{ -old }| ). ro_html->add( '' ). "#EC NOTEXT ENDLOOP. LOOP AT mt_delayed_lines ASSIGNING . ro_html->add( '' ). "#EC NOTEXT - ro_html->add( || - && || - && |+{ -new }| ). + ro_html->add( || + && || + && |+| + && |{ -new }| ). ro_html->add( '' ). "#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( || - && || - && |+{ is_diff_line-new }| ). + ro_html->add( || + && || + && |+| + && |{ is_diff_line-new }| ). WHEN zif_abapgit_definitions=>c_diff-delete. - ro_html->add( || - && || - && |-{ is_diff_line-old }| ). + ro_html->add( || + && || + && |-| + && |{ is_diff_line-old }| ). WHEN OTHERS. "none - ro_html->add( || - && || - && | { is_diff_line-old }| ). + ro_html->add( || + && || + && | | + && |{ is_diff_line-old }| ). ENDCASE. ro_html->add( '' ). "#EC NOTEXT @@ -1000,6 +1008,7 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_DIFF IMPLEMENTATION. IF mv_unified = abap_true. ro_html->add( 'old' ). "#EC NOTEXT ro_html->add( 'new' ). "#EC NOTEXT + ro_html->add( '' ). "#EC NOTEXT ro_html->add( 'code' ). "#EC NOTEXT ELSE. @@ -1011,8 +1020,10 @@ CLASS ZCL_ABAPGIT_GUI_PAGE_DIFF IMPLEMENTATION. ENDIF. ro_html->add( '' ). "#EC NOTEXT + ro_html->add( '' ). "#EC NOTEXT ro_html->add( 'LOCAL' ). "#EC NOTEXT ro_html->add( '' ). "#EC NOTEXT + ro_html->add( '' ). "#EC NOTEXT ro_html->add( 'REMOTE' ). "#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.