From df0aca8272f196946580312e15ce1350f8e21d47 Mon Sep 17 00:00:00 2001 From: Alexander Tsybulsky Date: Tue, 2 Jul 2019 06:53:43 +0300 Subject: [PATCH] Improve css preprocessing (#2765) * improve assetman get_text_asset * move css_processor to ui_core, reuse get_text_asse * fix %26 refactor UTs * zcl_abapgit_gui_html_processor * if fix * replace core logic * comment finetuning * linter fixes * more linter fixes * fix UTs, based on review --- src/ui/core/zcl_abapgit_gui.clas.abap | 125 ++++++------- .../zcl_abapgit_gui_asset_manager.clas.abap | 10 +- ...it_gui_asset_manager.clas.testclasses.abap | 31 +++- .../zcl_abapgit_gui_css_processor.clas.abap | 110 ++++++----- ...it_gui_css_processor.clas.testclasses.abap | 43 +---- .../zcl_abapgit_gui_css_processor.clas.xml | 0 .../zcl_abapgit_gui_html_processor.clas.abap | 152 +++++++++++++++ ...t_gui_html_processor.clas.testclasses.abap | 174 ++++++++++++++++++ .../zcl_abapgit_gui_html_processor.clas.xml | 17 ++ .../zif_abapgit_gui_asset_manager.intf.abap | 5 +- .../zif_abapgit_gui_html_processor.intf.abap | 13 ++ .../zif_abapgit_gui_html_processor.intf.xml | 15 ++ .../core/zif_abapgit_gui_services.intf.abap | 17 ++ src/ui/core/zif_abapgit_gui_services.intf.xml | 15 ++ src/ui/zcl_abapgit_gui_page.clas.abap | 9 +- src/ui/zcl_abapgit_ui_factory.clas.abap | 10 +- 16 files changed, 583 insertions(+), 163 deletions(-) rename src/ui/{ => core}/zcl_abapgit_gui_css_processor.clas.abap (81%) rename src/ui/{ => core}/zcl_abapgit_gui_css_processor.clas.testclasses.abap (86%) rename src/ui/{ => core}/zcl_abapgit_gui_css_processor.clas.xml (100%) create mode 100644 src/ui/core/zcl_abapgit_gui_html_processor.clas.abap create mode 100644 src/ui/core/zcl_abapgit_gui_html_processor.clas.testclasses.abap create mode 100644 src/ui/core/zcl_abapgit_gui_html_processor.clas.xml create mode 100644 src/ui/core/zif_abapgit_gui_html_processor.intf.abap create mode 100644 src/ui/core/zif_abapgit_gui_html_processor.intf.xml create mode 100644 src/ui/core/zif_abapgit_gui_services.intf.abap create mode 100644 src/ui/core/zif_abapgit_gui_services.intf.xml diff --git a/src/ui/core/zcl_abapgit_gui.clas.abap b/src/ui/core/zcl_abapgit_gui.clas.abap index b97d51c02..86ca1c370 100644 --- a/src/ui/core/zcl_abapgit_gui.clas.abap +++ b/src/ui/core/zcl_abapgit_gui.clas.abap @@ -20,6 +20,10 @@ CLASS zcl_abapgit_gui DEFINITION go_home TYPE string VALUE 'go_home', END OF c_action. + INTERFACES zif_abapgit_gui_services. + ALIASES: + cache_asset FOR zif_abapgit_gui_services~cache_asset. + METHODS go_home RAISING zcx_abapgit_exception. @@ -52,6 +56,7 @@ CLASS zcl_abapgit_gui DEFINITION io_component TYPE REF TO object OPTIONAL ii_asset_man TYPE REF TO zif_abapgit_gui_asset_manager OPTIONAL ii_error_handler TYPE REF TO zif_abapgit_gui_error_handler OPTIONAL + ii_html_processor TYPE REF TO zif_abapgit_gui_html_processor OPTIONAL RAISING zcx_abapgit_exception. @@ -71,6 +76,7 @@ CLASS zcl_abapgit_gui DEFINITION mi_router TYPE REF TO zif_abapgit_gui_event_handler, mi_asset_man TYPE REF TO zif_abapgit_gui_asset_manager, mi_error_handler TYPE REF TO zif_abapgit_gui_error_handler, + mi_html_processor TYPE REF TO zif_abapgit_gui_html_processor, mo_html_viewer TYPE REF TO cl_gui_html_viewer. METHODS startup @@ -83,16 +89,6 @@ CLASS zcl_abapgit_gui DEFINITION RETURNING VALUE(rv_url) TYPE w3url. - METHODS cache_asset - IMPORTING - iv_text TYPE string OPTIONAL - iv_xdata TYPE xstring OPTIONAL - iv_url TYPE w3url OPTIONAL - iv_type TYPE c - iv_subtype TYPE c - RETURNING - VALUE(rv_url) TYPE w3url. - METHODS render RAISING zcx_abapgit_exception. @@ -121,7 +117,7 @@ ENDCLASS. -CLASS zcl_abapgit_gui IMPLEMENTATION. +CLASS ZCL_ABAPGIT_GUI IMPLEMENTATION. METHOD back. @@ -156,45 +152,6 @@ CLASS zcl_abapgit_gui IMPLEMENTATION. ENDMETHOD. - METHOD cache_asset. - - DATA: lv_xstr TYPE xstring, - lt_xdata TYPE lvc_t_mime, - lv_size TYPE int4. - - ASSERT iv_text IS SUPPLIED OR iv_xdata IS SUPPLIED. - - IF iv_text IS SUPPLIED. " String input - lv_xstr = zcl_abapgit_convert=>string_to_xstring( iv_text ). - ELSE. " Raw input - lv_xstr = iv_xdata. - ENDIF. - - zcl_abapgit_convert=>xstring_to_bintab( - EXPORTING - iv_xstr = lv_xstr - IMPORTING - ev_size = lv_size - et_bintab = lt_xdata ). - - mo_html_viewer->load_data( - EXPORTING - type = iv_type - subtype = iv_subtype - size = lv_size - url = iv_url - IMPORTING - assigned_url = rv_url - CHANGING - data_table = lt_xdata - EXCEPTIONS - OTHERS = 1 ) ##NO_TEXT. - - ASSERT sy-subrc = 0. " Image data error - - ENDMETHOD. - - METHOD cache_html. rv_url = cache_asset( @@ -236,6 +193,7 @@ CLASS zcl_abapgit_gui IMPLEMENTATION. mi_asset_man = ii_asset_man. mi_error_handler = ii_error_handler. + mi_html_processor = ii_html_processor. " Maybe improve to middlewares stack ?? startup( ). ENDMETHOD. @@ -371,6 +329,7 @@ CLASS zcl_abapgit_gui IMPLEMENTATION. METHOD render. DATA: lv_url TYPE w3url, + lv_html TYPE string, li_html TYPE REF TO zif_abapgit_html, lo_css_processor TYPE REF TO zcl_abapgit_gui_css_processor. @@ -378,27 +337,16 @@ CLASS zcl_abapgit_gui IMPLEMENTATION. zcx_abapgit_exception=>raise( 'GUI error: no current page' ). ENDIF. - CREATE OBJECT lo_css_processor - EXPORTING - ii_asset_manager = mi_asset_man. - - lo_css_processor->add_file( 'css/theme-default.css' ). - - CASE zcl_abapgit_persist_settings=>get_instance( )->read( )->get_ui_theme( ). - WHEN zcl_abapgit_settings=>c_ui_theme-dark. - "TODO - WHEN zcl_abapgit_settings=>c_ui_theme-belize. - lo_css_processor->add_file( 'css/theme-belize-blue.css' ). - ENDCASE. - - cache_asset( iv_text = lo_css_processor->process( ) - iv_url = 'css/theme.css' - iv_type = 'text' - iv_subtype = 'css' ). - li_html = mi_cur_page->render( ). - lv_url = cache_html( li_html->render( iv_no_indent_jscss = abap_true ) ). + lv_html = li_html->render( iv_no_indent_jscss = abap_true ). + IF mi_html_processor IS BOUND. + lv_html = mi_html_processor->process( + iv_html = lv_html + ii_gui_services = me ). + ENDIF. + + lv_url = cache_html( lv_html ). mo_html_viewer->show_url( lv_url ). ENDMETHOD. @@ -435,4 +383,43 @@ CLASS zcl_abapgit_gui IMPLEMENTATION. SET HANDLER me->on_event FOR mo_html_viewer. ENDMETHOD. + + + METHOD cache_asset. + + DATA: lv_xstr TYPE xstring, + lt_xdata TYPE lvc_t_mime, + lv_size TYPE int4. + + ASSERT iv_text IS SUPPLIED OR iv_xdata IS SUPPLIED. + + IF iv_text IS SUPPLIED. " String input + lv_xstr = zcl_abapgit_convert=>string_to_xstring( iv_text ). + ELSE. " Raw input + lv_xstr = iv_xdata. + ENDIF. + + zcl_abapgit_convert=>xstring_to_bintab( + EXPORTING + iv_xstr = lv_xstr + IMPORTING + ev_size = lv_size + et_bintab = lt_xdata ). + + mo_html_viewer->load_data( + EXPORTING + type = iv_type + subtype = iv_subtype + size = lv_size + url = iv_url + IMPORTING + assigned_url = rv_url + CHANGING + data_table = lt_xdata + EXCEPTIONS + OTHERS = 1 ) ##NO_TEXT. + + ASSERT sy-subrc = 0. " Image data error + + ENDMETHOD. ENDCLASS. diff --git a/src/ui/core/zcl_abapgit_gui_asset_manager.clas.abap b/src/ui/core/zcl_abapgit_gui_asset_manager.clas.abap index 0b5320fa6..1224da1ab 100644 --- a/src/ui/core/zcl_abapgit_gui_asset_manager.clas.abap +++ b/src/ui/core/zcl_abapgit_gui_asset_manager.clas.abap @@ -45,7 +45,7 @@ ENDCLASS. -CLASS zcl_abapgit_gui_asset_manager IMPLEMENTATION. +CLASS ZCL_ABAPGIT_GUI_ASSET_MANAGER IMPLEMENTATION. METHOD get_mime_asset. @@ -158,6 +158,14 @@ CLASS zcl_abapgit_gui_asset_manager IMPLEMENTATION. DATA ls_asset TYPE zif_abapgit_gui_asset_manager~ty_web_asset. ls_asset = me->zif_abapgit_gui_asset_manager~get_asset( iv_url ). + IF ls_asset-type <> 'text'. + zcx_abapgit_exception=>raise( |Not a text asset: { iv_url }| ). + ENDIF. + + IF iv_assert_subtype IS NOT INITIAL AND ls_asset-subtype <> iv_assert_subtype. + zcx_abapgit_exception=>raise( |Wrong subtype ({ iv_assert_subtype }): { iv_url }| ). + ENDIF. + rv_asset = zcl_abapgit_convert=>xstring_to_string_utf8( ls_asset-content ). ENDMETHOD. diff --git a/src/ui/core/zcl_abapgit_gui_asset_manager.clas.testclasses.abap b/src/ui/core/zcl_abapgit_gui_asset_manager.clas.testclasses.abap index 5391e137f..674850fd5 100644 --- a/src/ui/core/zcl_abapgit_gui_asset_manager.clas.testclasses.abap +++ b/src/ui/core/zcl_abapgit_gui_asset_manager.clas.testclasses.abap @@ -31,9 +31,7 @@ CLASS ltcl_abapgit_gui_asset_manager IMPLEMENTATION. cl_abap_unit_assert=>assert_equals( act = ls_asset-type exp = 'text' ). cl_abap_unit_assert=>assert_equals( act = ls_asset-subtype exp = 'css' ). cl_abap_unit_assert=>assert_equals( - act = cl_bcs_convert=>xstring_to_string( - iv_xstr = ls_asset-content - iv_cp = '4110' ) + act = zcl_abapgit_convert=>xstring_to_string_utf8( ls_asset-content ) exp = 'ABC' ). ENDMETHOD. @@ -52,6 +50,33 @@ CLASS ltcl_abapgit_gui_asset_manager IMPLEMENTATION. act = lo_assetman->zif_abapgit_gui_asset_manager~get_text_asset( 'css/common.css' ) exp = 'ABC' ). + cl_abap_unit_assert=>assert_equals( + act = lo_assetman->zif_abapgit_gui_asset_manager~get_text_asset( + iv_url = 'css/common.css' + iv_assert_subtype = 'css' ) + exp = 'ABC' ). + + TRY . + lo_assetman->zif_abapgit_gui_asset_manager~get_text_asset( + iv_url = 'css/common.css' + iv_assert_subtype = 'xyz' ). + cl_abap_unit_assert=>fail( ). + CATCH zcx_abapgit_exception. + " no futher check + ENDTRY. + + lo_assetman->register_asset( + iv_url = 'css/common.xyz' + iv_type = 'nottext/bin' + iv_inline = 'XYZ' ). + + TRY . + lo_assetman->zif_abapgit_gui_asset_manager~get_text_asset( 'css/common.xyz' ). + cl_abap_unit_assert=>fail( ). + CATCH zcx_abapgit_exception. + " no futher check + ENDTRY. + ENDMETHOD. METHOD get_mime_asset. diff --git a/src/ui/zcl_abapgit_gui_css_processor.clas.abap b/src/ui/core/zcl_abapgit_gui_css_processor.clas.abap similarity index 81% rename from src/ui/zcl_abapgit_gui_css_processor.clas.abap rename to src/ui/core/zcl_abapgit_gui_css_processor.clas.abap index da8e8b18c..61aa87849 100644 --- a/src/ui/zcl_abapgit_gui_css_processor.clas.abap +++ b/src/ui/core/zcl_abapgit_gui_css_processor.clas.abap @@ -1,4 +1,3 @@ -"! CSS preprocessor CLASS zcl_abapgit_gui_css_processor DEFINITION PUBLIC FINAL @@ -6,10 +5,17 @@ CLASS zcl_abapgit_gui_css_processor DEFINITION PUBLIC SECTION. METHODS: - constructor IMPORTING ii_asset_manager TYPE REF TO zif_abapgit_gui_asset_manager, - add_file IMPORTING iv_url TYPE string, - process RETURNING VALUE(rv_result) TYPE string - RAISING zcx_abapgit_exception. + constructor + IMPORTING + ii_asset_manager TYPE REF TO zif_abapgit_gui_asset_manager, + add_file + IMPORTING + iv_url TYPE string, + process + RETURNING + VALUE(rv_result) TYPE string + RAISING zcx_abapgit_exception. + PROTECTED SECTION. PRIVATE SECTION. TYPES: @@ -18,30 +24,70 @@ CLASS zcl_abapgit_gui_css_processor DEFINITION value TYPE string, END OF gty_css_var, gty_css_var_tab TYPE SORTED TABLE OF gty_css_var WITH UNIQUE KEY name. + METHODS: - get_css_vars_in_string IMPORTING iv_string TYPE string - RETURNING VALUE(rt_variables) TYPE gty_css_var_tab, - resolve_var_recursively IMPORTING iv_variable_name TYPE string - CHANGING ct_variables TYPE gty_css_var_tab - RAISING zcx_abapgit_exception. + get_css_vars_in_string + IMPORTING + iv_string TYPE string + RETURNING + VALUE(rt_variables) TYPE gty_css_var_tab, + resolve_var_recursively + IMPORTING + iv_variable_name TYPE string + CHANGING + ct_variables TYPE gty_css_var_tab + RAISING + zcx_abapgit_exception. DATA: mi_asset_manager TYPE REF TO zif_abapgit_gui_asset_manager, - mt_files TYPE STANDARD TABLE OF string. + mt_files TYPE string_table. ENDCLASS. -CLASS zcl_abapgit_gui_css_processor IMPLEMENTATION. - METHOD constructor. - mi_asset_manager = ii_asset_manager. - ENDMETHOD. +CLASS ZCL_ABAPGIT_GUI_CSS_PROCESSOR IMPLEMENTATION. + METHOD add_file. APPEND iv_url TO mt_files. ENDMETHOD. + + METHOD constructor. + mi_asset_manager = ii_asset_manager. + ENDMETHOD. + + + METHOD get_css_vars_in_string. + CONSTANTS: lc_root_pattern TYPE string VALUE `:root\s*\{([^\}]*)\}`, + lc_variable_pattern TYPE string VALUE `\-\-([\w\d-]+)\s*:\s*([^\n\r;]*);`. + DATA: lv_root TYPE string, + lo_matcher TYPE REF TO cl_abap_matcher, + lo_regex TYPE REF TO cl_abap_regex, + ls_variable LIKE LINE OF rt_variables. + + " Only the :root element may define variables for now + + FIND FIRST OCCURRENCE OF REGEX lc_root_pattern IN iv_string SUBMATCHES lv_root. + IF sy-subrc = 0 AND lv_root IS NOT INITIAL. + CREATE OBJECT lo_regex + EXPORTING + pattern = lc_variable_pattern. + lo_matcher = lo_regex->create_matcher( text = lv_root ). + WHILE lo_matcher->find_next( ) = abap_true. + ls_variable-name = lo_matcher->get_submatch( 1 ). + ls_variable-value = lo_matcher->get_submatch( 2 ). + INSERT ls_variable INTO TABLE rt_variables. + IF sy-subrc <> 0. + MODIFY TABLE rt_variables FROM ls_variable. + ENDIF. + ENDWHILE. + ENDIF. + ENDMETHOD. + + METHOD process. - DATA: ls_asset TYPE zif_abapgit_gui_asset_manager=>ty_web_asset, + DATA: lt_contents TYPE STANDARD TABLE OF string, lv_content TYPE string, lt_css_variables TYPE gty_css_var_tab, @@ -52,9 +98,9 @@ CLASS zcl_abapgit_gui_css_processor IMPLEMENTATION. " 1. Determine all variables and their values. Later definitions overwrite previous ones. LOOP AT mt_files ASSIGNING . - ls_asset = mi_asset_manager->get_asset( ). - ASSERT ls_asset-type = 'text' AND ls_asset-subtype = 'css'. - lv_content = zcl_abapgit_convert=>xstring_to_string_utf8( ls_asset-content ). + lv_content = mi_asset_manager->get_text_asset( + iv_url = + iv_assert_subtype = 'css' ). lt_css_vars_in_file = get_css_vars_in_string( lv_content ). @@ -86,32 +132,6 @@ CLASS zcl_abapgit_gui_css_processor IMPLEMENTATION. rv_result = concat_lines_of( table = lt_contents sep = cl_abap_char_utilities=>newline ). ENDMETHOD. - METHOD get_css_vars_in_string. - CONSTANTS: lc_root_pattern TYPE string VALUE `:root\s*\{([^\}]*)\}`, - lc_variable_pattern TYPE string VALUE `\-\-([\w\d-]+)\s*:\s*([^\n\r;]*);`. - DATA: lv_root TYPE string, - lo_matcher TYPE REF TO cl_abap_matcher, - lo_regex TYPE REF TO cl_abap_regex, - ls_variable LIKE LINE OF rt_variables. - - " Only the :root element may define variables for now - - FIND FIRST OCCURRENCE OF REGEX lc_root_pattern IN iv_string SUBMATCHES lv_root. - IF sy-subrc = 0 AND lv_root IS NOT INITIAL. - CREATE OBJECT lo_regex - EXPORTING - pattern = lc_variable_pattern. - lo_matcher = lo_regex->create_matcher( text = lv_root ). - WHILE lo_matcher->find_next( ) = abap_true. - ls_variable-name = lo_matcher->get_submatch( 1 ). - ls_variable-value = lo_matcher->get_submatch( 2 ). - INSERT ls_variable INTO TABLE rt_variables. - IF sy-subrc <> 0. - MODIFY TABLE rt_variables FROM ls_variable. - ENDIF. - ENDWHILE. - ENDIF. - ENDMETHOD. METHOD resolve_var_recursively. CONSTANTS: lc_variable_usage_pattern TYPE string VALUE `var\(\-\-([^\)]*)\)`. diff --git a/src/ui/zcl_abapgit_gui_css_processor.clas.testclasses.abap b/src/ui/core/zcl_abapgit_gui_css_processor.clas.testclasses.abap similarity index 86% rename from src/ui/zcl_abapgit_gui_css_processor.clas.testclasses.abap rename to src/ui/core/zcl_abapgit_gui_css_processor.clas.testclasses.abap index bd02c1d13..e3616b852 100644 --- a/src/ui/zcl_abapgit_gui_css_processor.clas.testclasses.abap +++ b/src/ui/core/zcl_abapgit_gui_css_processor.clas.testclasses.abap @@ -1,32 +1,3 @@ -*"* use this source file for your ABAP unit test classes - -CLASS ltcl_asset_manager_double DEFINITION FOR TESTING. - PUBLIC SECTION. - INTERFACES: - zif_abapgit_gui_asset_manager. - DATA: - mt_assets TYPE zif_abapgit_gui_asset_manager=>tt_web_assets. - PROTECTED SECTION. - PRIVATE SECTION. -ENDCLASS. - -CLASS ltcl_asset_manager_double IMPLEMENTATION. - METHOD zif_abapgit_gui_asset_manager~get_all_assets. - cl_abap_unit_assert=>fail( ). - ENDMETHOD. - - METHOD zif_abapgit_gui_asset_manager~get_asset. - READ TABLE mt_assets WITH KEY url = iv_url INTO rs_asset. - IF sy-subrc <> 0. - zcx_abapgit_exception=>raise( 'Asset not found' ). - ENDIF. - ENDMETHOD. - - METHOD zif_abapgit_gui_asset_manager~get_text_asset. - cl_abap_unit_assert=>fail( ). - ENDMETHOD. -ENDCLASS. - CLASS ltcl_test_base DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT ABSTRACT. PUBLIC SECTION. PROTECTED SECTION. @@ -34,7 +5,7 @@ CLASS ltcl_test_base DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT A add_file IMPORTING iv_url TYPE string iv_content TYPE string OPTIONAL. DATA: - mo_asset_manager TYPE REF TO ltcl_asset_manager_double, + mo_asset_manager TYPE REF TO zcl_abapgit_gui_asset_manager, mo_cut TYPE REF TO zcl_abapgit_gui_css_processor. PRIVATE SECTION. METHODS: @@ -57,12 +28,10 @@ CLASS ltcl_test_base IMPLEMENTATION. METHOD add_file. DATA: ls_asset TYPE zif_abapgit_gui_asset_manager=>ty_web_asset. - ls_asset-url = iv_url. - ls_asset-type = 'text'. - ls_asset-subtype = 'css'. - ls_asset-content = zcl_abapgit_convert=>string_to_xstring_utf8( iv_content ). - - APPEND ls_asset TO mo_asset_manager->mt_assets. + mo_asset_manager->register_asset( + iv_url = iv_url + iv_type = 'text/css' + iv_inline = iv_content ). ENDMETHOD. ENDCLASS. @@ -105,8 +74,8 @@ CLASS ltcl_single_file IMPLEMENTATION. mo_cut->add_file( 'does/exist.css' ). TRY. mo_cut->process( ). + cl_abap_unit_assert=>fail( ). " Assetman fails on empty content CATCH zcx_abapgit_exception. - cl_abap_unit_assert=>fail( ). ENDTRY. ENDMETHOD. diff --git a/src/ui/zcl_abapgit_gui_css_processor.clas.xml b/src/ui/core/zcl_abapgit_gui_css_processor.clas.xml similarity index 100% rename from src/ui/zcl_abapgit_gui_css_processor.clas.xml rename to src/ui/core/zcl_abapgit_gui_css_processor.clas.xml diff --git a/src/ui/core/zcl_abapgit_gui_html_processor.clas.abap b/src/ui/core/zcl_abapgit_gui_html_processor.clas.abap new file mode 100644 index 000000000..ab54ab370 --- /dev/null +++ b/src/ui/core/zcl_abapgit_gui_html_processor.clas.abap @@ -0,0 +1,152 @@ +CLASS zcl_abapgit_gui_html_processor DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + + CONSTANTS c_css_build_name TYPE string VALUE 'css/bundle.css'. + CONSTANTS c_comment_start TYPE string VALUE ``. + + INTERFACES zif_abapgit_gui_html_processor . + + METHODS constructor + IMPORTING + ii_asset_man TYPE REF TO zif_abapgit_gui_asset_manager. + + METHODS preserve_css + IMPORTING + !iv_css_url TYPE string . + + PROTECTED SECTION. + PRIVATE SECTION. + DATA mt_preserve_css TYPE string_table. + DATA mi_asset_man TYPE REF TO zif_abapgit_gui_asset_manager. + + METHODS patch_html + IMPORTING + iv_html TYPE string + EXPORTING + ev_html TYPE string + et_css_urls TYPE string_table + RAISING + zcx_abapgit_exception. + + METHODS is_preserved + IMPORTING + !iv_css_url TYPE string + RETURNING + VALUE(rv_yes) TYPE abap_bool. + +ENDCLASS. + + + +CLASS ZCL_ABAPGIT_GUI_HTML_PROCESSOR IMPLEMENTATION. + + + METHOD constructor. + mi_asset_man = ii_asset_man. + ENDMETHOD. + + + METHOD is_preserved. + READ TABLE mt_preserve_css TRANSPORTING NO FIELDS WITH KEY table_line = iv_css_url. + rv_yes = boolc( sy-subrc = 0 ). + ENDMETHOD. + + + METHOD patch_html. + + CONSTANTS lc_css_re TYPE string VALUE ``. + + DATA lv_head_end TYPE i. + DATA lo_css_re TYPE REF TO cl_abap_regex. + DATA lo_matcher TYPE REF TO cl_abap_matcher. + DATA lv_css_path TYPE string. + + DATA lv_off TYPE i. + DATA lv_len TYPE i. + DATA lv_cur TYPE i. + + DATA lc_css_build TYPE string VALUE ''. + REPLACE FIRST OCCURRENCE OF '$BUILD_NAME' IN lc_css_build WITH c_css_build_name. " Mmmm + + CLEAR: ev_html, et_css_urls. + + lv_head_end = find( val = iv_html regex = |{ cl_abap_char_utilities=>newline }?\\s*| case = abap_false ). + IF lv_head_end <= 0. + zcx_abapgit_exception=>raise( 'HTML preprocessor: not found' ). + ENDIF. + + CREATE OBJECT lo_css_re + EXPORTING + ignore_case = abap_true + pattern = lc_css_re. + + lo_matcher = lo_css_re->create_matcher( text = substring( val = iv_html len = lv_head_end ) ). + WHILE lo_matcher->find_next( ) = abap_true. + lv_css_path = lo_matcher->get_submatch( 1 ). + IF abap_false = is_preserved( lv_css_path ). + lv_off = lo_matcher->get_offset( ). + lv_len = lo_matcher->get_length( ). + ev_html = ev_html && substring( val = iv_html off = lv_cur len = lv_off - lv_cur ). + ev_html = ev_html && c_comment_start && substring( val = iv_html off = lv_off len = lv_len ) && c_comment_end. + lv_cur = lv_off + lv_len. + APPEND lv_css_path TO et_css_urls. + ENDIF. + ENDWHILE. + + ev_html = ev_html && substring( val = iv_html off = lv_cur len = lv_head_end - lv_cur ). + IF lines( et_css_urls ) > 0. + ev_html = ev_html + && cl_abap_char_utilities=>newline && ` ` " Assume 4 space indent, maybe improve and detect ? + && c_comment_start && c_comment_end + && lc_css_build. + ENDIF. + ev_html = ev_html && substring( val = iv_html off = lv_head_end ). + + ENDMETHOD. + + + METHOD preserve_css. + APPEND iv_css_url TO mt_preserve_css. + ENDMETHOD. + + + METHOD zif_abapgit_gui_html_processor~process. + + DATA lo_css_processor TYPE REF TO zcl_abapgit_gui_css_processor. + DATA lt_css_urls TYPE string_table. + DATA lv_css_build TYPE string. + + FIELD-SYMBOLS LIKE LINE OF lt_css_urls. + + patch_html( + EXPORTING + iv_html = iv_html + IMPORTING + ev_html = rv_html + et_css_urls = lt_css_urls ). + + IF lines( lt_css_urls ) > 0. + CREATE OBJECT lo_css_processor + EXPORTING + ii_asset_manager = mi_asset_man. + + LOOP AT lt_css_urls ASSIGNING . + lo_css_processor->add_file( ). + ENDLOOP. + + lv_css_build = lo_css_processor->process( ). + + ii_gui_services->cache_asset( + iv_url = |{ c_css_build_name }| + iv_type = 'text' + iv_subtype = 'css' + iv_text = lv_css_build ). + ENDIF. + + ENDMETHOD. +ENDCLASS. diff --git a/src/ui/core/zcl_abapgit_gui_html_processor.clas.testclasses.abap b/src/ui/core/zcl_abapgit_gui_html_processor.clas.testclasses.abap new file mode 100644 index 000000000..4044429c6 --- /dev/null +++ b/src/ui/core/zcl_abapgit_gui_html_processor.clas.testclasses.abap @@ -0,0 +1,174 @@ +CLASS lcl_gui_mock DEFINITION. + PUBLIC SECTION. + TYPES: + BEGIN OF ty_cache_signature, + url TYPE string, + type TYPE string, + data TYPE string, + END OF ty_cache_signature. + DATA ms_last_cache_signature TYPE ty_cache_signature. + + INTERFACES zif_abapgit_gui_services. +ENDCLASS. + +CLASS lcl_gui_mock IMPLEMENTATION. + METHOD zif_abapgit_gui_services~cache_asset. + ms_last_cache_signature-url = iv_url. + ms_last_cache_signature-type = iv_type && '/' && iv_subtype. + ms_last_cache_signature-data = iv_text. + ENDMETHOD. +ENDCLASS. + +CLASS ltcl_html_processor_test DEFINITION + FOR TESTING + DURATION SHORT + RISK LEVEL HARMLESS + FINAL. + + PRIVATE SECTION. + DATA mv_source TYPE string. + DATA mo_cut TYPE REF TO zcl_abapgit_gui_html_processor. + DATA mo_gui_mock TYPE REF TO lcl_gui_mock. + + METHODS render_html + IMPORTING + iv_src TYPE string + RETURNING + VALUE(rv_html) TYPE string. + + METHODS setup. + METHODS process_typical FOR TESTING RAISING zcx_abapgit_exception. + METHODS process_with_preserve FOR TESTING RAISING zcx_abapgit_exception. + METHODS process_no_css FOR TESTING RAISING zcx_abapgit_exception. + METHODS process_fails FOR TESTING RAISING zcx_abapgit_exception. + +ENDCLASS. + +CLASS ltcl_html_processor_test IMPLEMENTATION. + + METHOD render_html. + rv_html = iv_src. + REPLACE ALL OCCURRENCES OF '\n' IN rv_html WITH cl_abap_char_utilities=>newline. + ENDMETHOD. + + METHOD setup. + + DATA lo_asset_man TYPE REF TO zcl_abapgit_gui_asset_manager. + + CREATE OBJECT lo_asset_man. + lo_asset_man->register_asset( iv_url = 'css/style1.css' iv_type = 'text/css' iv_inline = 'dummy1' ). + lo_asset_man->register_asset( iv_url = 'css/style2.css' iv_type = 'text/css' iv_inline = 'dummy2' ). + lo_asset_man->register_asset( iv_url = 'css/style3.css' iv_type = 'text/css' iv_inline = 'dummy3' ). + + CREATE OBJECT mo_cut + EXPORTING + ii_asset_man = lo_asset_man. + + CREATE OBJECT mo_gui_mock. + + mv_source = render_html( + `\n` && + ` \n` && + ` abapGit\n` && + ` \n` && " +case & extra space + ` \n` && + ` \n` && + ` \n` && + ` \n` && + ` hello\n` && + `\n` ). + + ENDMETHOD. + + METHOD process_typical. + + DATA lv_act TYPE string. + + lv_act = mo_cut->zif_abapgit_gui_html_processor~process( + iv_html = mv_source + ii_gui_services = mo_gui_mock ). + + cl_abap_unit_assert=>assert_equals( + act = lv_act + exp = render_html( + `\n` && + ` \n` && + ` abapGit\n` && + ` \n` && + ` \n` && + ` \n` && + ` \n` && + ` \n` && + ` \n` && + ` hello\n` && + `\n` + ) ). + + " GUI call checks + cl_abap_unit_assert=>assert_equals( + act = mo_gui_mock->ms_last_cache_signature-url + exp = 'css/bundle.css' ). + cl_abap_unit_assert=>assert_equals( + act = mo_gui_mock->ms_last_cache_signature-type + exp = 'text/css' ). + cl_abap_unit_assert=>assert_equals( + act = mo_gui_mock->ms_last_cache_signature-data + exp = render_html( 'dummy1\ndummy2\ndummy3' ) ). + + ENDMETHOD. + + METHOD process_with_preserve. + + DATA lv_act TYPE string. + + mo_cut->preserve_css( 'css/style2.css' ). + lv_act = mo_cut->zif_abapgit_gui_html_processor~process( + iv_html = mv_source + ii_gui_services = mo_gui_mock ). + + cl_abap_unit_assert=>assert_equals( + act = lv_act + exp = render_html( + `\n` && + ` \n` && + ` abapGit\n` && + ` \n` && + ` \n` && " Preserved + ` \n` && + ` \n` && + ` \n` && + ` \n` && + ` hello\n` && + `\n` + ) ). + + ENDMETHOD. + + METHOD process_no_css. + + DATA lv_act TYPE string. + + lv_act = mo_cut->zif_abapgit_gui_html_processor~process( + iv_html = '' + ii_gui_services = mo_gui_mock ). + + cl_abap_unit_assert=>assert_equals( + act = lv_act + exp = '' ). + + ENDMETHOD. + + METHOD process_fails. + + TRY . + " BTW this is valid HTML, maybe refactor the code ... + mo_cut->zif_abapgit_gui_html_processor~process( + iv_html = '' + ii_gui_services = mo_gui_mock ). + cl_abap_unit_assert=>fail( ). + CATCH zcx_abapgit_exception ##NO_HANDLER. + ENDTRY. + + ENDMETHOD. + +ENDCLASS. diff --git a/src/ui/core/zcl_abapgit_gui_html_processor.clas.xml b/src/ui/core/zcl_abapgit_gui_html_processor.clas.xml new file mode 100644 index 000000000..987fd064e --- /dev/null +++ b/src/ui/core/zcl_abapgit_gui_html_processor.clas.xml @@ -0,0 +1,17 @@ + + + + + + ZCL_ABAPGIT_GUI_HTML_PROCESSOR + E + abapgit GUI html processor + 1 + X + X + X + X + + + + diff --git a/src/ui/core/zif_abapgit_gui_asset_manager.intf.abap b/src/ui/core/zif_abapgit_gui_asset_manager.intf.abap index 0e25a5d79..831c67d5f 100644 --- a/src/ui/core/zif_abapgit_gui_asset_manager.intf.abap +++ b/src/ui/core/zif_abapgit_gui_asset_manager.intf.abap @@ -28,9 +28,10 @@ INTERFACE zif_abapgit_gui_asset_manager METHODS get_text_asset IMPORTING - iv_url TYPE string + iv_url TYPE string + iv_assert_subtype TYPE string OPTIONAL RETURNING - VALUE(rv_asset) TYPE string + VALUE(rv_asset) TYPE string RAISING zcx_abapgit_exception. diff --git a/src/ui/core/zif_abapgit_gui_html_processor.intf.abap b/src/ui/core/zif_abapgit_gui_html_processor.intf.abap new file mode 100644 index 000000000..678d7fb8f --- /dev/null +++ b/src/ui/core/zif_abapgit_gui_html_processor.intf.abap @@ -0,0 +1,13 @@ +INTERFACE zif_abapgit_gui_html_processor + PUBLIC . + + METHODS process + IMPORTING + !iv_html TYPE string + !ii_gui_services TYPE REF TO zif_abapgit_gui_services + RETURNING + VALUE(rv_html) TYPE string + RAISING + zcx_abapgit_exception. + +ENDINTERFACE. diff --git a/src/ui/core/zif_abapgit_gui_html_processor.intf.xml b/src/ui/core/zif_abapgit_gui_html_processor.intf.xml new file mode 100644 index 000000000..d434121b0 --- /dev/null +++ b/src/ui/core/zif_abapgit_gui_html_processor.intf.xml @@ -0,0 +1,15 @@ + + + + + + ZIF_ABAPGIT_GUI_HTML_PROCESSOR + E + abapgit GUI html preprocessor interface + 2 + 1 + X + + + + diff --git a/src/ui/core/zif_abapgit_gui_services.intf.abap b/src/ui/core/zif_abapgit_gui_services.intf.abap new file mode 100644 index 000000000..c495d6b30 --- /dev/null +++ b/src/ui/core/zif_abapgit_gui_services.intf.abap @@ -0,0 +1,17 @@ +INTERFACE zif_abapgit_gui_services + PUBLIC . + + METHODS cache_asset + IMPORTING + iv_text TYPE string OPTIONAL + iv_xdata TYPE xstring OPTIONAL + iv_url TYPE w3url OPTIONAL + iv_type TYPE c + iv_subtype TYPE c + RETURNING + VALUE(rv_url) TYPE w3url. + + " For future refactoring + " Potentially also: back, go_home, go_page, +some access to page stack + +ENDINTERFACE. diff --git a/src/ui/core/zif_abapgit_gui_services.intf.xml b/src/ui/core/zif_abapgit_gui_services.intf.xml new file mode 100644 index 000000000..0824502d5 --- /dev/null +++ b/src/ui/core/zif_abapgit_gui_services.intf.xml @@ -0,0 +1,15 @@ + + + + + + ZIF_ABAPGIT_GUI_SERVICES + E + Selected services of abapgit GUI + 2 + 1 + X + + + + diff --git a/src/ui/zcl_abapgit_gui_page.clas.abap b/src/ui/zcl_abapgit_gui_page.clas.abap index ee48133f1..5cc43b98e 100644 --- a/src/ui/zcl_abapgit_gui_page.clas.abap +++ b/src/ui/zcl_abapgit_gui_page.clas.abap @@ -87,7 +87,7 @@ ENDCLASS. -CLASS zcl_abapgit_gui_page IMPLEMENTATION. +CLASS ZCL_ABAPGIT_GUI_PAGE IMPLEMENTATION. METHOD call_browser. @@ -216,10 +216,10 @@ CLASS zcl_abapgit_gui_page IMPLEMENTATION. ro_html->add( 'abapGit' ). "#EC NOTEXT ro_html->add( '' ). + ro_html->add( '' ). - " theme.css is created at runtime in ZCL_ABAPGIT_GUI->RENDER( ) - ro_html->add( '' ). - + " Themes + ro_html->add( '' ). " Theme basis CASE mo_settings->get_ui_theme( ). WHEN zcl_abapgit_settings=>c_ui_theme-dark. "TODO @@ -227,7 +227,6 @@ CLASS zcl_abapgit_gui_page IMPLEMENTATION. ro_html->add( '' ). ENDCASE. - ro_html->add( '' ). ro_html->add( '' ). "#EC NOTEXT CASE mo_settings->get_icon_scaling( ). " Enforce icon scaling diff --git a/src/ui/zcl_abapgit_ui_factory.clas.abap b/src/ui/zcl_abapgit_ui_factory.clas.abap index 2b64cf113..1c03fea51 100644 --- a/src/ui/zcl_abapgit_ui_factory.clas.abap +++ b/src/ui/zcl_abapgit_ui_factory.clas.abap @@ -41,7 +41,7 @@ ENDCLASS. -CLASS zcl_abapgit_ui_factory IMPLEMENTATION. +CLASS ZCL_ABAPGIT_UI_FACTORY IMPLEMENTATION. METHOD get_frontend_services. @@ -62,15 +62,23 @@ CLASS zcl_abapgit_ui_factory IMPLEMENTATION. li_asset_man TYPE REF TO zif_abapgit_gui_asset_manager. DATA lo_error_handler TYPE REF TO lcl_gui_error_handler. + DATA lo_html_preprocessor TYPE REF TO zcl_abapgit_gui_html_processor. IF go_gui IS INITIAL. li_asset_man ?= init_asset_manager( ). + + CREATE OBJECT lo_html_preprocessor EXPORTING ii_asset_man = li_asset_man. + lo_html_preprocessor->preserve_css( 'css/ag-icons.css' ). + lo_html_preprocessor->preserve_css( 'css/common.css' ). + CREATE OBJECT li_router TYPE zcl_abapgit_gui_router. CREATE OBJECT lo_error_handler. + CREATE OBJECT go_gui EXPORTING io_component = li_router ii_error_handler = lo_error_handler + ii_html_processor = lo_html_preprocessor ii_asset_man = li_asset_man. ENDIF. ro_gui = go_gui.