CLASS zcl_abapgit_gui_page_diff DEFINITION PUBLIC INHERITING FROM zcl_abapgit_gui_page CREATE PUBLIC. PUBLIC SECTION. TYPES: BEGIN OF ty_file_diff, path TYPE string, filename TYPE string, obj_type TYPE string, obj_name TYPE string, lstate TYPE char1, rstate TYPE char1, fstate TYPE char1, " FILE state - Abstraction for shorter ifs o_diff TYPE REF TO zcl_abapgit_diff, changed_by TYPE xubname, type TYPE string, END OF ty_file_diff. TYPES: tt_file_diff TYPE STANDARD TABLE OF ty_file_diff WITH NON-UNIQUE DEFAULT KEY WITH NON-UNIQUE SORTED KEY secondary COMPONENTS path filename. CONSTANTS: BEGIN OF c_fstate, local TYPE char1 VALUE 'L', remote TYPE char1 VALUE 'R', both TYPE char1 VALUE 'B', END OF c_fstate. METHODS constructor IMPORTING !iv_key TYPE zif_abapgit_persistence=>ty_repo-key !is_file TYPE zif_abapgit_definitions=>ty_file OPTIONAL !is_object TYPE zif_abapgit_definitions=>ty_item OPTIONAL RAISING zcx_abapgit_exception. METHODS zif_abapgit_gui_event_handler~on_event REDEFINITION. PROTECTED SECTION. DATA mv_unified TYPE abap_bool VALUE abap_true ##NO_TEXT. DATA mo_repo TYPE REF TO zcl_abapgit_repo. DATA mt_diff_files TYPE tt_file_diff . METHODS: get_normalized_fname_with_path IMPORTING is_diff TYPE ty_file_diff RETURNING VALUE(rv_filename) TYPE string, normalize_path IMPORTING iv_path TYPE string RETURNING VALUE(rv_normalized) TYPE string, normalize_filename IMPORTING iv_filename TYPE string RETURNING VALUE(rv_normalized) TYPE string, render_content REDEFINITION, add_menu_end IMPORTING io_menu TYPE REF TO zcl_abapgit_html_toolbar , calculate_diff IMPORTING is_file TYPE zif_abapgit_definitions=>ty_file OPTIONAL is_object TYPE zif_abapgit_definitions=>ty_item OPTIONAL RAISING zcx_abapgit_exception, add_menu_begin IMPORTING io_menu TYPE REF TO zcl_abapgit_html_toolbar, render_table_head_non_unified IMPORTING io_html TYPE REF TO zcl_abapgit_html is_diff TYPE ty_file_diff, render_beacon_begin_of_row IMPORTING io_html TYPE REF TO zcl_abapgit_html is_diff TYPE ty_file_diff, render_diff_head_after_state IMPORTING io_html TYPE REF TO zcl_abapgit_html is_diff TYPE ty_file_diff, insert_nav RETURNING VALUE(rv_insert_nav) TYPE abap_bool, render_line_split_row IMPORTING io_html TYPE REF TO zcl_abapgit_html iv_filename TYPE string is_diff_line TYPE zif_abapgit_definitions=>ty_diff iv_index TYPE sy-tabix iv_fstate TYPE char1 iv_new TYPE string iv_old TYPE string RAISING zcx_abapgit_exception, build_menu RETURNING VALUE(ro_menu) TYPE REF TO zcl_abapgit_html_toolbar. PRIVATE SECTION. CONSTANTS: BEGIN OF c_actions, toggle_unified TYPE string VALUE 'toggle_unified', END OF c_actions . DATA mt_delayed_lines TYPE zif_abapgit_definitions=>ty_diffs_tt . DATA mv_repo_key TYPE zif_abapgit_persistence=>ty_repo-key . DATA mv_seed TYPE string . " Unique page id to bind JS sessionStorage METHODS render_diff IMPORTING !is_diff TYPE ty_file_diff RETURNING VALUE(ro_html) TYPE REF TO zcl_abapgit_html RAISING zcx_abapgit_exception . METHODS render_diff_head IMPORTING !is_diff TYPE ty_file_diff RETURNING VALUE(ro_html) TYPE REF TO zcl_abapgit_html . METHODS render_table_head IMPORTING !is_diff TYPE ty_file_diff RETURNING VALUE(ro_html) TYPE REF TO zcl_abapgit_html . METHODS render_beacon IMPORTING !is_diff_line TYPE zif_abapgit_definitions=>ty_diff !is_diff TYPE ty_file_diff RETURNING VALUE(ro_html) TYPE REF TO zcl_abapgit_html . METHODS render_line_split IMPORTING !is_diff_line TYPE zif_abapgit_definitions=>ty_diff !iv_filename TYPE string !iv_fstate TYPE char1 !iv_index TYPE sy-tabix RETURNING VALUE(ro_html) TYPE REF TO zcl_abapgit_html RAISING zcx_abapgit_exception . METHODS render_line_unified IMPORTING !is_diff_line TYPE zif_abapgit_definitions=>ty_diff OPTIONAL RETURNING VALUE(ro_html) TYPE REF TO zcl_abapgit_html . METHODS append_diff IMPORTING !it_remote TYPE zif_abapgit_definitions=>ty_files_tt !it_local TYPE zif_abapgit_definitions=>ty_files_item_tt !is_status TYPE zif_abapgit_definitions=>ty_result RAISING zcx_abapgit_exception . METHODS is_binary IMPORTING !iv_d1 TYPE xstring !iv_d2 TYPE xstring RETURNING VALUE(rv_yes) TYPE abap_bool . METHODS add_jump_sub_menu IMPORTING !io_menu TYPE REF TO zcl_abapgit_html_toolbar . METHODS add_filter_sub_menu IMPORTING io_menu TYPE REF TO zcl_abapgit_html_toolbar . METHODS render_lines IMPORTING is_diff TYPE ty_file_diff RETURNING VALUE(ro_html) TYPE REF TO zcl_abapgit_html RAISING zcx_abapgit_exception. METHODS render_table_head_unified IMPORTING io_html TYPE REF TO zcl_abapgit_html. METHODS render_scripts RETURNING VALUE(ro_html) TYPE REF TO zcl_abapgit_html RAISING zcx_abapgit_exception. ENDCLASS. CLASS ZCL_ABAPGIT_GUI_PAGE_DIFF IMPLEMENTATION. METHOD add_filter_sub_menu. DATA: lo_sub_filter TYPE REF TO zcl_abapgit_html_toolbar, lt_types TYPE string_table, lt_users TYPE string_table. FIELD-SYMBOLS: LIKE LINE OF mt_diff_files, TYPE string. " Get unique LOOP AT mt_diff_files ASSIGNING . APPEND -type TO lt_types. APPEND -changed_by TO lt_users. ENDLOOP. SORT lt_types. DELETE ADJACENT DUPLICATES FROM lt_types. SORT lt_users. DELETE ADJACENT DUPLICATES FROM lt_users. IF lines( lt_types ) > 1 OR lines( lt_users ) > 1. CREATE OBJECT lo_sub_filter EXPORTING iv_id = 'diff-filter'. " File types IF lines( lt_types ) > 1. lo_sub_filter->add( iv_txt = 'TYPE' iv_typ = zif_abapgit_html=>c_action_type-separator ). LOOP AT lt_types ASSIGNING . lo_sub_filter->add( iv_txt = iv_typ = zif_abapgit_html=>c_action_type-onclick iv_aux = 'type' iv_chk = abap_true ). ENDLOOP. ENDIF. " Changed by IF lines( lt_users ) > 1. lo_sub_filter->add( iv_txt = 'CHANGED BY' iv_typ = zif_abapgit_html=>c_action_type-separator ). LOOP AT lt_users ASSIGNING . lo_sub_filter->add( iv_txt = iv_typ = zif_abapgit_html=>c_action_type-onclick iv_aux = 'changed-by' iv_chk = abap_true ). ENDLOOP. ENDIF. io_menu->add( iv_txt = 'Filter' io_sub = lo_sub_filter ) ##NO_TEXT. ENDIF. ENDMETHOD. METHOD add_jump_sub_menu. DATA: lo_sub_jump TYPE REF TO zcl_abapgit_html_toolbar, lv_jump_target TYPE string. FIELD-SYMBOLS: LIKE LINE OF mt_diff_files. CREATE OBJECT lo_sub_jump EXPORTING iv_id = 'jump'. LOOP AT mt_diff_files ASSIGNING . lv_jump_target = -path && -filename. lo_sub_jump->add( iv_id = |li_jump_{ sy-tabix }| iv_txt = lv_jump_target iv_typ = zif_abapgit_html=>c_action_type-onclick ). ENDLOOP. io_menu->add( iv_txt = 'Jump' io_sub = lo_sub_jump ) ##NO_TEXT. ENDMETHOD. METHOD add_menu_begin. ENDMETHOD. METHOD add_menu_end. io_menu->add( iv_txt = 'Split/Unified view' iv_act = c_actions-toggle_unified ) ##NO_TEXT. ENDMETHOD. METHOD append_diff. DATA: lv_offs TYPE i, ls_r_dummy LIKE LINE OF it_remote ##NEEDED, ls_l_dummy LIKE LINE OF it_local ##NEEDED. FIELD-SYMBOLS: LIKE LINE OF it_remote, LIKE LINE OF it_local, LIKE LINE OF mt_diff_files. READ TABLE it_remote ASSIGNING WITH KEY filename = is_status-filename path = is_status-path. IF sy-subrc <> 0. ASSIGN ls_r_dummy TO . ENDIF. READ TABLE it_local ASSIGNING WITH KEY file-filename = is_status-filename file-path = is_status-path. IF sy-subrc <> 0. ASSIGN ls_l_dummy TO . ENDIF. IF IS INITIAL AND IS INITIAL. zcx_abapgit_exception=>raise( |DIFF: file not found { is_status-filename }| ). ENDIF. APPEND INITIAL LINE TO mt_diff_files ASSIGNING . -path = is_status-path. -filename = is_status-filename. -obj_type = is_status-obj_type. -obj_name = is_status-obj_name. -lstate = is_status-lstate. -rstate = is_status-rstate. IF -lstate IS NOT INITIAL AND -rstate IS NOT INITIAL. -fstate = c_fstate-both. ELSEIF -lstate IS NOT INITIAL. -fstate = c_fstate-local. ELSE. "rstate IS NOT INITIAL, lstate = empty. -fstate = c_fstate-remote. ENDIF. " Changed by IF -item-obj_type IS NOT INITIAL. -changed_by = to_lower( zcl_abapgit_objects=>changed_by( -item ) ). ENDIF. IF -changed_by IS INITIAL. -changed_by = to_lower( zcl_abapgit_objects_super=>c_user_unknown ). ENDIF. " Extension IF -file-filename IS NOT INITIAL. -type = reverse( -file-filename ). ELSE. -type = reverse( -filename ). ENDIF. FIND FIRST OCCURRENCE OF '.' IN -type MATCH OFFSET lv_offs. -type = reverse( substring( val = -type len = lv_offs ) ). IF -type <> 'xml' AND -type <> 'abap'. -type = 'other'. ENDIF. IF -type = 'other' AND is_binary( iv_d1 = -data iv_d2 = -file-data ) = abap_true. -type = 'binary'. ENDIF. " Diff data IF -type <> 'binary'. IF -fstate = c_fstate-remote. " Remote file leading changes CREATE OBJECT -o_diff EXPORTING iv_new = -data iv_old = -file-data. ELSE. " Local leading changes or both were modified CREATE OBJECT -o_diff EXPORTING iv_new = -file-data iv_old = -data. ENDIF. ENDIF. ENDMETHOD. METHOD build_menu. CREATE OBJECT ro_menu. add_menu_begin( ro_menu ). add_jump_sub_menu( ro_menu ). add_filter_sub_menu( ro_menu ). add_menu_end( ro_menu ). ENDMETHOD. METHOD calculate_diff. DATA: lt_remote TYPE zif_abapgit_definitions=>ty_files_tt, lt_local TYPE zif_abapgit_definitions=>ty_files_item_tt, lt_status TYPE zif_abapgit_definitions=>ty_results_tt. FIELD-SYMBOLS: LIKE LINE OF lt_status. CLEAR: mt_diff_files. lt_remote = mo_repo->get_files_remote( ). lt_local = mo_repo->get_files_local( ). mo_repo->reset_status( ). lt_status = mo_repo->status( ). IF is_file IS NOT INITIAL. " Diff for one file READ TABLE lt_status ASSIGNING WITH KEY path = is_file-path filename = is_file-filename. append_diff( it_remote = lt_remote it_local = lt_local is_status = ). ELSEIF is_object IS NOT INITIAL. " Diff for whole object LOOP AT lt_status ASSIGNING WHERE obj_type = is_object-obj_type AND obj_name = is_object-obj_name AND match IS INITIAL. append_diff( it_remote = lt_remote it_local = lt_local is_status = ). ENDLOOP. ELSE. " Diff for the whole repo SORT lt_status BY path ASCENDING filename ASCENDING. LOOP AT lt_status ASSIGNING WHERE match IS INITIAL. append_diff( it_remote = lt_remote it_local = lt_local is_status = ). ENDLOOP. ENDIF. ENDMETHOD. METHOD constructor. DATA: lv_ts TYPE timestamp. super->constructor( ). ms_control-page_title = 'DIFF'. mv_unified = zcl_abapgit_persistence_user=>get_instance( )->get_diff_unified( ). mv_repo_key = iv_key. mo_repo ?= zcl_abapgit_repo_srv=>get_instance( )->get( iv_key ). GET TIME STAMP FIELD lv_ts. mv_seed = |diff{ lv_ts }|. " Generate based on time ASSERT is_file IS INITIAL OR is_object IS INITIAL. " just one passed calculate_diff( is_file = is_file is_object = is_object ). IF lines( mt_diff_files ) = 0. zcx_abapgit_exception=>raise( 'PAGE_DIFF ERROR: No diff files found' ). ENDIF. ms_control-page_menu = build_menu( ). ENDMETHOD. METHOD get_normalized_fname_with_path. rv_filename = normalize_path( is_diff-path ) && `_` && normalize_filename( is_diff-filename ). ENDMETHOD. METHOD insert_nav. ENDMETHOD. METHOD is_binary. FIELD-SYMBOLS LIKE iv_d1. IF iv_d1 IS NOT INITIAL. " One of them might be new and so empty ASSIGN iv_d1 TO . ELSE. ASSIGN iv_d2 TO . ENDIF. rv_yes = zcl_abapgit_utils=>is_binary( ). ENDMETHOD. METHOD normalize_filename. rv_normalized = replace( val = iv_filename sub = '.' occ = 0 with = '_' ). ENDMETHOD. METHOD normalize_path. rv_normalized = replace( val = iv_path sub = '/' occ = 0 with = '_' ). ENDMETHOD. METHOD render_beacon. DATA: lv_beacon TYPE string, lt_beacons TYPE zif_abapgit_definitions=>ty_string_tt. CREATE OBJECT ro_html. IF is_diff_line-beacon > 0. lt_beacons = is_diff-o_diff->get_beacons( ). READ TABLE lt_beacons INTO lv_beacon INDEX is_diff_line-beacon. ELSE. lv_beacon = '---'. ENDIF. ro_html->add( '' ). ro_html->add( '' ). render_beacon_begin_of_row( io_html = ro_html is_diff = is_diff ). 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 }| ). ENDIF. ro_html->add( '' ). ro_html->add( '' ). ENDMETHOD. METHOD render_beacon_begin_of_row. io_html->add( '' ). ENDMETHOD. METHOD render_content. DATA: ls_diff_file LIKE LINE OF mt_diff_files, li_progress TYPE REF TO zif_abapgit_progress. CREATE OBJECT ro_html. li_progress = zcl_abapgit_progress=>get_instance( lines( mt_diff_files ) ). ro_html->add( |
| ). ro_html->add( zcl_abapgit_gui_chunk_lib=>render_js_error_banner( ) ). LOOP AT mt_diff_files INTO ls_diff_file. li_progress->show( iv_current = sy-tabix iv_text = |Render Diff - { ls_diff_file-filename }| ). ro_html->add( render_diff( ls_diff_file ) ). ENDLOOP. IF sy-subrc <> 0. ro_html->add( |No more diffs| ). ENDIF. ro_html->add( '
' ). register_deferred_script( render_scripts( ) ). ENDMETHOD. METHOD render_diff. CREATE OBJECT ro_html. ro_html->add( |
| ). "#EC NOTEXT ro_html->add( render_diff_head( is_diff ) ). " Content IF is_diff-type <> 'binary'. ro_html->add( '
' ). "#EC NOTEXT ro_html->add( || ). "#EC NOTEXT ro_html->add( render_table_head( is_diff ) ). ro_html->add( render_lines( is_diff ) ). ro_html->add( '
' ). "#EC NOTEXT ELSE. ro_html->add( '
' ). "#EC NOTEXT ro_html->add( 'The content seems to be binary.' ). "#EC NOTEXT ro_html->add( 'Cannot display as diff.' ). "#EC NOTEXT ENDIF. ro_html->add( '
' ). "#EC NOTEXT ro_html->add( '
' ). "#EC NOTEXT ENDMETHOD. METHOD render_diff_head. DATA: ls_stats TYPE zif_abapgit_definitions=>ty_count, lv_adt_link TYPE string. CREATE OBJECT ro_html. ro_html->add( '
' ). "#EC NOTEXT ro_html->add_icon( iv_name = 'chevron-down' iv_hint = 'Collapse/Expand' iv_class = 'cursor-pointer' iv_onclick = 'onDiffCollapse(event)' ). IF is_diff-type <> 'binary'. ls_stats = is_diff-o_diff->stats( ). IF is_diff-fstate = c_fstate-both. " Merge stats into 'update' if both were changed ls_stats-update = ls_stats-update + ls_stats-insert + ls_stats-delete. CLEAR: ls_stats-insert, ls_stats-delete. ENDIF. ro_html->add( |+ { ls_stats-insert }| ). ro_html->add( |- { ls_stats-delete }| ). ro_html->add( |~ { ls_stats-update }| ). ENDIF. " no links for nonexistent or deleted objects IF is_diff-lstate IS NOT INITIAL AND is_diff-lstate <> 'D'. lv_adt_link = zcl_abapgit_html=>a( iv_txt = |{ is_diff-path }{ is_diff-filename }| iv_typ = zif_abapgit_html=>c_action_type-sapevent iv_act = |jump?TYPE={ is_diff-obj_type }&NAME={ is_diff-obj_name }| ). ENDIF. IF lv_adt_link IS NOT INITIAL. ro_html->add( |{ lv_adt_link }| ). "#EC NOTEXT ELSE. ro_html->add( |{ is_diff-path }{ is_diff-filename }| ). "#EC NOTEXT ENDIF. ro_html->add( zcl_abapgit_gui_chunk_lib=>render_item_state( iv_lstate = is_diff-lstate iv_rstate = is_diff-rstate ) ). render_diff_head_after_state( io_html = ro_html is_diff = is_diff ). ro_html->add( |last change by: { is_diff-changed_by }| ). ro_html->add( '
' ). "#EC NOTEXT ENDMETHOD. METHOD render_diff_head_after_state. IF is_diff-fstate = c_fstate-both AND mv_unified = abap_true. io_html->add( 'Attention: Unified mode' && ' highlighting for MM assumes local file is newer ! ' ). "#EC NOTEXT ENDIF. ENDMETHOD. METHOD render_lines. DATA: lo_highlighter TYPE REF TO zcl_abapgit_syntax_highlighter, lt_diffs TYPE zif_abapgit_definitions=>ty_diffs_tt, lv_insert_nav TYPE abap_bool, lv_tabix TYPE syst-tabix. FIELD-SYMBOLS LIKE LINE OF lt_diffs. lo_highlighter = zcl_abapgit_syntax_highlighter=>create( is_diff-filename ). CREATE OBJECT ro_html. lt_diffs = is_diff-o_diff->get( ). lv_insert_nav = insert_nav( ). LOOP AT lt_diffs ASSIGNING . lv_tabix = sy-tabix. IF -short = abap_false. lv_insert_nav = abap_true. CONTINUE. ENDIF. IF lv_insert_nav = abap_true. " Insert separator line with navigation ro_html->add( render_beacon( is_diff_line = is_diff = is_diff ) ). lv_insert_nav = abap_false. ENDIF. IF lo_highlighter IS BOUND. -new = lo_highlighter->process_line( -new ). -old = lo_highlighter->process_line( -old ). ELSE. -new = escape( val = -new format = cl_abap_format=>e_html_attr ). -old = escape( val = -old format = cl_abap_format=>e_html_attr ). ENDIF. CONDENSE -new_num. "get rid of leading spaces CONDENSE -old_num. IF mv_unified = abap_true. ro_html->add( render_line_unified( is_diff_line = ) ). ELSE. ro_html->add( render_line_split( is_diff_line = iv_filename = get_normalized_fname_with_path( is_diff ) iv_fstate = is_diff-fstate iv_index = lv_tabix ) ). ENDIF. ENDLOOP. IF mv_unified = abap_true. ro_html->add( render_line_unified( ) ). " Release delayed lines ENDIF. ENDMETHOD. METHOD render_line_split. DATA: lv_new TYPE string, lv_old TYPE string, lv_mark TYPE string, lv_bg TYPE string. CREATE OBJECT ro_html. " New line lv_mark = ` `. IF is_diff_line-result IS NOT INITIAL. IF iv_fstate = c_fstate-both OR is_diff_line-result = zif_abapgit_definitions=>c_diff-update. lv_bg = ' diff_upd'. lv_mark = `~`. ELSEIF is_diff_line-result = zif_abapgit_definitions=>c_diff-insert. lv_bg = ' diff_ins'. lv_mark = `+`. ENDIF. ENDIF. lv_new = || && |{ lv_mark }| && |{ is_diff_line-new }|. " Old line CLEAR lv_bg. lv_mark = ` `. IF is_diff_line-result IS NOT INITIAL. IF iv_fstate = c_fstate-both OR is_diff_line-result = zif_abapgit_definitions=>c_diff-update. lv_bg = ' diff_upd'. lv_mark = `~`. ELSEIF is_diff_line-result = zif_abapgit_definitions=>c_diff-delete. lv_bg = ' diff_del'. lv_mark = `-`. ENDIF. ENDIF. lv_old = || && |{ lv_mark }| && |{ is_diff_line-old }|. " render line, inverse sides if remote is newer ro_html->add( '' ). "#EC NOTEXT render_line_split_row( io_html = ro_html iv_filename = iv_filename is_diff_line = is_diff_line iv_index = iv_index iv_fstate = iv_fstate iv_old = lv_old iv_new = lv_new ). ro_html->add( '' ). "#EC NOTEXT ENDMETHOD. METHOD render_line_split_row. IF iv_fstate = c_fstate-remote. " Remote file leading changes io_html->add( iv_old ). " local io_html->add( iv_new ). " remote ELSE. " Local leading changes or both were modified io_html->add( iv_new ). " local io_html->add( iv_old ). " remote ENDIF. ENDMETHOD. METHOD render_line_unified. FIELD-SYMBOLS LIKE LINE OF mt_delayed_lines. CREATE OBJECT ro_html. " Release delayed subsequent update lines 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( '' ). "#EC NOTEXT ENDLOOP. LOOP AT mt_delayed_lines ASSIGNING . ro_html->add( '' ). "#EC NOTEXT ro_html->add( || && || && |+| && |{ -new }| ). ro_html->add( '' ). "#EC NOTEXT ENDLOOP. CLEAR mt_delayed_lines. ENDIF. ro_html->add( '' ). "#EC NOTEXT CASE is_diff_line-result. 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 }| ). WHEN zif_abapgit_definitions=>c_diff-delete. ro_html->add( || && || && |-| && |{ is_diff_line-old }| ). WHEN OTHERS. "none ro_html->add( || && || && | | && |{ is_diff_line-old }| ). ENDCASE. ro_html->add( '' ). "#EC NOTEXT ENDMETHOD. METHOD render_scripts. CREATE OBJECT ro_html. ro_html->add( 'restoreScrollPosition();' ). ro_html->add( 'var gHelper = new DiffHelper({' ). ro_html->add( | seed: "{ mv_seed }",| ). ro_html->add( ' ids: {' ). ro_html->add( ' jump: "jump",' ). ro_html->add( ' diffList: "diff-list",' ). ro_html->add( ' filterMenu: "diff-filter",' ). ro_html->add( ' }' ). ro_html->add( '});' ). ro_html->add( 'addMarginBottom();' ). ro_html->add( 'var gGoJumpPalette = new CommandPalette(enumerateJumpAllFiles, {' ). ro_html->add( ' toggleKey: "F2",' ). 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. METHOD render_table_head. CREATE OBJECT ro_html. ro_html->add( '' ). "#EC NOTEXT ro_html->add( '' ). "#EC NOTEXT IF mv_unified = abap_true. render_table_head_unified( ro_html ). ELSE. render_table_head_non_unified( io_html = ro_html is_diff = is_diff ). ENDIF. ro_html->add( '' ). "#EC NOTEXT ro_html->add( '' ). "#EC NOTEXT ENDMETHOD. METHOD render_table_head_non_unified. io_html->add( '' ). "#EC NOTEXT io_html->add( '' ). "#EC NOTEXT io_html->add( 'LOCAL' ). "#EC NOTEXT io_html->add( '' ). "#EC NOTEXT io_html->add( '' ). "#EC NOTEXT io_html->add( 'REMOTE' ). "#EC NOTEXT ENDMETHOD. METHOD render_table_head_unified. io_html->add( 'old' ). "#EC NOTEXT io_html->add( 'new' ). "#EC NOTEXT io_html->add( '' ). "#EC NOTEXT io_html->add( 'code' ). "#EC NOTEXT ENDMETHOD. METHOD zif_abapgit_gui_event_handler~on_event. CASE iv_action. WHEN c_actions-toggle_unified. " Toggle file diplay mv_unified = zcl_abapgit_persistence_user=>get_instance( )->toggle_diff_unified( ). ev_state = zcl_abapgit_gui=>c_event_state-re_render. WHEN OTHERS. super->zif_abapgit_gui_event_handler~on_event( EXPORTING iv_action = iv_action iv_getdata = iv_getdata it_postdata = it_postdata IMPORTING ei_page = ei_page ev_state = ev_state ). ENDCASE. ENDMETHOD. ENDCLASS.