From 16e8f3d02d36cacaa08c836578d0382cc9effca6 Mon Sep 17 00:00:00 2001 From: Marc Bernard <59966492+mbtools@users.noreply.github.com> Date: Sat, 14 Nov 2020 05:28:19 -0500 Subject: [PATCH] Dialogs: HTML form enhancements (#4172) * Dialogs: HTML form enhancements In preparation for https://github.com/abapGit/abapGit/issues/4171, HTML forms were enhanced as follows: - New integer fields (type "number") with min/max, https://github.com/abapGit/abapGit/issues/3559 - Added support for minlength/maxlength for text fields - Added support for read-only fields - Added support for password fields - New option for adding a help button to the form (with URL link) - Moved HTML snippets to render method - Changed parameters to csequence to also accept char variables (like abap_true) - Minor adjustments to styles * Lint and fix ul/fieldgroup * Min/max validation, textarea * Close textarea tag Co-authored-by: Lars Hvam --- src/ui/zabapgit_css_common.w3mi.data.css | 17 +- .../zabapgit_css_theme_default.w3mi.data.css | 12 +- src/ui/zcl_abapgit_html_form.clas.abap | 316 +++++++++++++----- src/ui/zcl_abapgit_html_form.clas.xml | 2 +- 4 files changed, 264 insertions(+), 83 deletions(-) diff --git a/src/ui/zabapgit_css_common.w3mi.data.css b/src/ui/zabapgit_css_common.w3mi.data.css index 8f5de8104..c5c308fda 100644 --- a/src/ui/zabapgit_css_common.w3mi.data.css +++ b/src/ui/zabapgit_css_common.w3mi.data.css @@ -1096,7 +1096,12 @@ settings_tab tr:first-child td { border-top: 0px; } } .dialog input[type="text"] { width: 100%; - box-sizing : border-box; + box-sizing: border-box; + height: 2.5em; +} +.dialog input[type="number"] { + width: 25%; + box-sizing: border-box; height: 2.5em; } .dialog .radio-container input[type="radio"] { @@ -1130,6 +1135,9 @@ settings_tab tr:first-child td { border-top: 0px; } .dialog fieldset { margin-top: 1em; border: 1px solid; + border-right: none; + border-left: none; + border-bottom: none; border-radius: 6px; /* doesn't work in IE ? */ padding-bottom: 1em; } @@ -1137,8 +1145,11 @@ settings_tab tr:first-child td { border-top: 0px; } margin-top: 0; } .dialog fieldset legend { - font-size: small; - text-transform: uppercase; + font-size: large; + font-style: bold; padding-left: 0.5em; padding-right: 0.5em; } +.dialog .dialog-help { + float: left; +} diff --git a/src/ui/zabapgit_css_theme_default.w3mi.data.css b/src/ui/zabapgit_css_theme_default.w3mi.data.css index 84392d047..e90318d95 100644 --- a/src/ui/zabapgit_css_theme_default.w3mi.data.css +++ b/src/ui/zabapgit_css_theme_default.w3mi.data.css @@ -497,6 +497,7 @@ table.settings_tab input:focus { .dialog li.error small { color: #ff5959; } +.dialog li.error input[type="number"], .dialog li.error input[type="text"] { border-color: #ff5959; } @@ -519,5 +520,14 @@ table.settings_tab input:focus { border-color: #dfdfdf; } .dialog fieldset legend { - color: #ccc; + color: #444; +} +.dialog input:read-only { + background-color: #f4f4f4; + color: var(--theme-greyscale-dark); +} +/* for IE */ +.dialog input[readonly] { + background-color: #f4f4f4; + color: var(--theme-greyscale-dark); } diff --git a/src/ui/zcl_abapgit_html_form.clas.abap b/src/ui/zcl_abapgit_html_form.clas.abap index 3e0ac5241..aecfe6983 100644 --- a/src/ui/zcl_abapgit_html_form.clas.abap +++ b/src/ui/zcl_abapgit_html_form.clas.abap @@ -1,83 +1,110 @@ CLASS zcl_abapgit_html_form DEFINITION PUBLIC FINAL - CREATE PRIVATE . + CREATE PRIVATE. PUBLIC SECTION. CLASS-METHODS create IMPORTING - !iv_form_id TYPE string OPTIONAL + !iv_form_id TYPE csequence OPTIONAL + !iv_help_page TYPE csequence OPTIONAL RETURNING - VALUE(ro_form) TYPE REF TO zcl_abapgit_html_form . + VALUE(ro_form) TYPE REF TO zcl_abapgit_html_form. METHODS render IMPORTING - !iv_form_class TYPE string + !iv_form_class TYPE csequence !io_values TYPE REF TO zcl_abapgit_string_map !io_validation_log TYPE REF TO zcl_abapgit_string_map OPTIONAL RETURNING - VALUE(ri_html) TYPE REF TO zif_abapgit_html . + VALUE(ri_html) TYPE REF TO zif_abapgit_html. METHODS command IMPORTING - !iv_label TYPE string - !iv_action TYPE string + !iv_label TYPE csequence + !iv_action TYPE csequence !iv_is_main TYPE abap_bool DEFAULT abap_false !iv_as_a TYPE abap_bool DEFAULT abap_false RETURNING - VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form . + VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form. METHODS text IMPORTING - !iv_label TYPE string - !iv_name TYPE string - !iv_hint TYPE string OPTIONAL + !iv_label TYPE csequence + !iv_name TYPE csequence + !iv_hint TYPE csequence OPTIONAL !iv_required TYPE abap_bool DEFAULT abap_false !iv_upper_case TYPE abap_bool DEFAULT abap_false - !iv_placeholder TYPE string OPTIONAL - !iv_side_action TYPE string OPTIONAL + !iv_readonly TYPE abap_bool DEFAULT abap_false + !iv_password TYPE abap_bool DEFAULT abap_false + !iv_placeholder TYPE csequence OPTIONAL + !iv_side_action TYPE csequence OPTIONAL + !iv_min TYPE i DEFAULT cl_abap_math=>min_int4 + !iv_max TYPE i DEFAULT cl_abap_math=>max_int4 RETURNING - VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form . + VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form. + METHODS textarea + IMPORTING + !iv_label TYPE csequence + !iv_name TYPE csequence + !iv_rows TYPE i DEFAULT 3 + !iv_hint TYPE csequence OPTIONAL + !iv_required TYPE abap_bool DEFAULT abap_false + !iv_readonly TYPE abap_bool DEFAULT abap_false + !iv_placeholder TYPE csequence OPTIONAL + RETURNING + VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form. + METHODS number + IMPORTING + !iv_label TYPE csequence + !iv_name TYPE csequence + !iv_hint TYPE csequence OPTIONAL + !iv_required TYPE abap_bool DEFAULT abap_false + !iv_readonly TYPE abap_bool DEFAULT abap_false + !iv_min TYPE i DEFAULT cl_abap_math=>min_int4 + !iv_max TYPE i DEFAULT cl_abap_math=>max_int4 + RETURNING + VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form. METHODS checkbox IMPORTING - !iv_label TYPE string - !iv_name TYPE string - !iv_hint TYPE string OPTIONAL + !iv_label TYPE csequence + !iv_name TYPE csequence + !iv_hint TYPE csequence OPTIONAL RETURNING - VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form . + VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form. METHODS radio IMPORTING - !iv_label TYPE string - !iv_name TYPE string - !iv_default_value TYPE string OPTIONAL - !iv_hint TYPE string OPTIONAL + !iv_label TYPE csequence + !iv_name TYPE csequence + !iv_default_value TYPE csequence OPTIONAL + !iv_hint TYPE csequence OPTIONAL RETURNING - VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form . + VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form. METHODS option IMPORTING - !iv_label TYPE string - !iv_value TYPE string + !iv_label TYPE csequence + !iv_value TYPE csequence RETURNING - VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form . + VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form. METHODS start_group IMPORTING - !iv_label TYPE string - !iv_name TYPE string - !iv_hint TYPE string OPTIONAL + !iv_label TYPE csequence + !iv_name TYPE csequence + !iv_hint TYPE csequence OPTIONAL RETURNING - VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form . + VALUE(ro_self) TYPE REF TO zcl_abapgit_html_form. METHODS normalize_form_data IMPORTING !io_form_data TYPE REF TO zcl_abapgit_string_map RETURNING VALUE(ro_form_data) TYPE REF TO zcl_abapgit_string_map RAISING - zcx_abapgit_exception . + zcx_abapgit_exception. METHODS validate_required_fields IMPORTING !io_form_data TYPE REF TO zcl_abapgit_string_map RETURNING VALUE(ro_validation_log) TYPE REF TO zcl_abapgit_string_map RAISING - zcx_abapgit_exception . + zcx_abapgit_exception. PROTECTED SECTION. PRIVATE SECTION. @@ -85,9 +112,9 @@ CLASS zcl_abapgit_html_form DEFINITION BEGIN OF ty_subitem, label TYPE string, value TYPE string, - END OF ty_subitem . + END OF ty_subitem. TYPES: - ty_subitems TYPE STANDARD TABLE OF ty_subitem WITH DEFAULT KEY . + ty_subitems TYPE STANDARD TABLE OF ty_subitem WITH DEFAULT KEY. TYPES: BEGIN OF ty_field, type TYPE i, @@ -103,8 +130,13 @@ CLASS zcl_abapgit_html_form DEFINITION default_value TYPE string, side_action TYPE string, subitems TYPE ty_subitems, + readonly TYPE abap_bool, + password TYPE abap_bool, + min TYPE i, + max TYPE i, + rows TYPE i, * onclick ??? - END OF ty_field . + END OF ty_field. TYPES: BEGIN OF ty_command, label TYPE string, @@ -112,7 +144,7 @@ CLASS zcl_abapgit_html_form DEFINITION is_main TYPE abap_bool, as_a TYPE abap_bool, * onclick ??? - END OF ty_command . + END OF ty_command. CONSTANTS: BEGIN OF c_field_type, @@ -120,29 +152,32 @@ CLASS zcl_abapgit_html_form DEFINITION radio TYPE i VALUE 2, checkbox TYPE i VALUE 3, field_group TYPE i VALUE 4, - END OF c_field_type . + number TYPE i VALUE 5, + textarea TYPE i VALUE 6, + END OF c_field_type. DATA: mt_fields TYPE STANDARD TABLE OF ty_field - WITH UNIQUE SORTED KEY by_name COMPONENTS name. + WITH UNIQUE SORTED KEY by_name COMPONENTS name. DATA: mt_commands TYPE STANDARD TABLE OF ty_command. - DATA mv_form_id TYPE string . + DATA mv_form_id TYPE string. + DATA mv_help_page TYPE string. METHODS render_field IMPORTING !ii_html TYPE REF TO zif_abapgit_html !io_values TYPE REF TO zcl_abapgit_string_map !io_validation_log TYPE REF TO zcl_abapgit_string_map - !is_field TYPE ty_field . + !is_field TYPE ty_field. METHODS render_command IMPORTING !ii_html TYPE REF TO zif_abapgit_html - !is_cmd TYPE ty_command . + !is_cmd TYPE ty_command. ENDCLASS. -CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. +CLASS zcl_abapgit_html_form IMPLEMENTATION. METHOD checkbox. @@ -152,10 +187,7 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. ls_field-type = c_field_type-checkbox. ls_field-name = iv_name. ls_field-label = iv_label. - - IF iv_hint IS NOT INITIAL. - ls_field-hint = | title="{ iv_hint }"|. - ENDIF. + ls_field-hint = iv_hint. APPEND ls_field TO mt_fields. @@ -188,6 +220,7 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. CREATE OBJECT ro_form. ro_form->mv_form_id = iv_form_id. + ro_form->mv_help_page = iv_help_page. IF ro_form->mv_form_id IS INITIAL. GET TIME STAMP FIELD lv_ts. @@ -216,6 +249,13 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. ro_form_data->set( iv_key = -name iv_val = to_upper( lv_value ) ). + ELSEIF -type = c_field_type-number. + IF lv_value NA '0123456789- '. + + ENDIF. + ro_form_data->set( + iv_key = -name + iv_val = lv_value ). ELSE. ro_form_data->set( iv_key = -name @@ -227,6 +267,26 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. ENDMETHOD. + METHOD number. + + DATA ls_field LIKE LINE OF mt_fields. + + ls_field-type = c_field_type-number. + ls_field-name = iv_name. + ls_field-label = iv_label. + ls_field-readonly = iv_readonly. + ls_field-min = iv_min. + ls_field-max = iv_max. + ls_field-hint = iv_hint. + ls_field-required = iv_required. + + APPEND ls_field TO mt_fields. + + ro_self = me. + + ENDMETHOD. + + METHOD option. FIELD-SYMBOLS LIKE LINE OF mt_fields. @@ -258,10 +318,7 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. ls_field-name = iv_name. ls_field-label = iv_label. ls_field-default_value = iv_default_value. - - IF iv_hint IS NOT INITIAL. - ls_field-hint = | title="{ iv_hint }"|. - ENDIF. + ls_field-hint = iv_hint. APPEND ls_field TO mt_fields. @@ -274,6 +331,7 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. FIELD-SYMBOLS LIKE LINE OF mt_fields. FIELD-SYMBOLS LIKE LINE OF mt_commands. + DATA lv_hint TYPE string. DATA ls_form_id TYPE string. DATA lv_cur_group TYPE string. @@ -293,17 +351,27 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. EXIT. ENDLOOP. - ri_html->add( |
    | ). - LOOP AT mt_fields ASSIGNING . + AT FIRST. + IF -type <> c_field_type-field_group. + ri_html->add( |
      | ). + ENDIF. + ENDAT. IF -type = c_field_type-field_group. IF lv_cur_group IS NOT INITIAL AND lv_cur_group <> -name. - ri_html->add( '' ). + ri_html->add( |
    | ). + ri_html->add( || ). + ENDIF. + IF -hint IS NOT INITIAL. + lv_hint = | title="{ -hint }"|. + ELSE. + lv_hint = ''. ENDIF. lv_cur_group = -name. ri_html->add( |
    | ). - ri_html->add( |-hint }>{ -label }| ). + ri_html->add( |{ -label }| ). + ri_html->add( |
      | ). CONTINUE. ENDIF. @@ -314,14 +382,25 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. is_field = ). AT LAST. + ri_html->add( |
    | ). IF lv_cur_group IS NOT INITIAL. - ri_html->add( '
    ' ). + ri_html->add( || ). ENDIF. ENDAT. ENDLOOP. + ri_html->add( |
      | ). ri_html->add( |
    • | ). + IF mv_help_page IS NOT INITIAL. + ri_html->add_a( + iv_txt = zcl_abapgit_gui_buttons=>help( ) + iv_typ = zif_abapgit_html=>c_action_type-url + iv_act = mv_help_page + iv_class = 'dialog-help' + iv_title = 'Help' ). + ENDIF. + LOOP AT mt_commands ASSIGNING . render_command( ii_html = ri_html @@ -329,7 +408,6 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. ENDLOOP. ri_html->add( |
    • | ). - ri_html->add( |
    | ). ri_html->add( || ). ri_html->add( || ). @@ -366,6 +444,10 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. DATA lv_value TYPE string. DATA lv_checked TYPE string. DATA lv_item_class TYPE string. + DATA lv_hint TYPE string. + DATA lv_required TYPE string. + DATA lv_attr TYPE string. + DATA lv_type TYPE string. FIELD-SYMBOLS LIKE LINE OF is_field-subitems. " Get value and validation error from maps @@ -383,14 +465,29 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. lv_item_class = | class="{ lv_item_class }"|. ENDIF. + IF is_field-required = abap_true. + lv_required = ' *'. + ENDIF. + + IF is_field-hint IS NOT INITIAL. + lv_hint = | title="{ is_field-hint }"|. + ENDIF. + + IF is_field-readonly = abap_true. + lv_attr = lv_attr && ' readonly'. + ENDIF. + + IF is_field-placeholder IS NOT INITIAL. + lv_attr = lv_attr && | placeholder="{ is_field-placeholder }"|. + ENDIF. + " Render field ii_html->add( || ). CASE is_field-type. - WHEN c_field_type-text. + WHEN c_field_type-text OR c_field_type-number. - ii_html->add( || ). + ii_html->add( || ). IF lv_error IS NOT INITIAL. ii_html->add( |{ lv_error }| ). ENDIF. @@ -399,8 +496,16 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. ii_html->add( '
    ' ). " Ugly :( ENDIF. - ii_html->add( || ). + IF is_field-type = c_field_type-number. + lv_type = 'number'. + ELSEIF is_field-password = abap_true. + lv_type = 'password'. + ELSE. + lv_type = 'text'. + ENDIF. + + ii_html->add( || ). IF is_field-side_action IS NOT INITIAL. ii_html->add( '
    ' ). @@ -409,6 +514,17 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. ii_html->add( '' ). ENDIF. + WHEN c_field_type-textarea. + + ii_html->add( || ). + IF lv_error IS NOT INITIAL. + ii_html->add( |{ lv_error }| ). + ENDIF. + + ii_html->add( || ). + WHEN c_field_type-checkbox. IF lv_error IS NOT INITIAL. @@ -418,12 +534,11 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. lv_checked = ' checked'. ENDIF. ii_html->add( || ). - ii_html->add( || ). + ii_html->add( || ). WHEN c_field_type-radio. - ii_html->add( |{ is_field-label }{ is_field-required }| ). + ii_html->add( |{ is_field-label }| ). IF lv_error IS NOT INITIAL. ii_html->add( |{ lv_error }| ). ENDIF. @@ -458,10 +573,7 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. ls_field-type = c_field_type-field_group. ls_field-label = iv_label. ls_field-name = iv_name. - - IF iv_hint IS NOT INITIAL. - ls_field-hint = | title="{ iv_hint }"|. - ENDIF. + ls_field-hint = iv_hint. APPEND ls_field TO mt_fields. @@ -478,10 +590,13 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. ls_field-name = iv_name. ls_field-label = iv_label. ls_field-upper_case = iv_upper_case. - - IF iv_hint IS NOT INITIAL. - ls_field-hint = | title="{ iv_hint }"|. - ENDIF. + ls_field-readonly = iv_readonly. + ls_field-min = iv_min. + ls_field-max = iv_max. + ls_field-password = iv_password. + ls_field-hint = iv_hint. + ls_field-required = iv_required. + ls_field-placeholder = iv_placeholder. IF iv_side_action IS NOT INITIAL AND mv_form_id IS NOT INITIAL. ls_field-item_class = 'with-command'. @@ -492,13 +607,25 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. }').submit()"|. ENDIF. - IF iv_required = abap_true. - ls_field-required = ' *'. - ENDIF. + APPEND ls_field TO mt_fields. - IF iv_placeholder IS NOT INITIAL. - ls_field-placeholder = | placeholder="{ iv_placeholder }"|. - ENDIF. + ro_self = me. + + ENDMETHOD. + + + METHOD textarea. + + DATA ls_field LIKE LINE OF mt_fields. + + ls_field-type = c_field_type-textarea. + ls_field-name = iv_name. + ls_field-label = iv_label. + ls_field-readonly = iv_readonly. + ls_field-hint = iv_hint. + ls_field-required = iv_required. + ls_field-placeholder = iv_placeholder. + ls_field-rows = iv_rows. APPEND ls_field TO mt_fields. @@ -510,6 +637,7 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. METHOD validate_required_fields. DATA lv_value TYPE string. + DATA lv_number TYPE i. FIELD-SYMBOLS LIKE LINE OF mt_fields. CREATE OBJECT ro_validation_log. @@ -521,6 +649,38 @@ CLASS ZCL_ABAPGIT_HTML_FORM IMPLEMENTATION. iv_key = -name iv_val = |{ -label } cannot be empty| ). ENDIF. + CASE -type. + WHEN c_field_type-text. + IF -min <> cl_abap_math=>min_int4 AND strlen( lv_value ) < -min. + ro_validation_log->set( + iv_key = -name + iv_val = |{ -label } must not be shorter than { -min } characters| ). + ENDIF. + IF -max <> cl_abap_math=>max_int4 AND strlen( lv_value ) > -max. + ro_validation_log->set( + iv_key = -name + iv_val = |{ -label } must not be longer than { -max } characters| ). + ENDIF. + WHEN c_field_type-number. + TRY. + lv_number = lv_value. + CATCH cx_root. + ro_validation_log->set( + iv_key = -name + iv_val = |{ -label } is not a number| ). + CONTINUE. + ENDTRY. + IF -min <> cl_abap_math=>min_int4 AND lv_number < -min. + ro_validation_log->set( + iv_key = -name + iv_val = |{ -label } must not be lower than { -min }| ). + ENDIF. + IF -max <> cl_abap_math=>max_int4 AND lv_number > -max. + ro_validation_log->set( + iv_key = -name + iv_val = |{ -label } must not be higher than { -max }| ). + ENDIF. + ENDCASE. ENDLOOP. ENDMETHOD. diff --git a/src/ui/zcl_abapgit_html_form.clas.xml b/src/ui/zcl_abapgit_html_form.clas.xml index e498c2b17..2d3568b2d 100644 --- a/src/ui/zcl_abapgit_html_form.clas.xml +++ b/src/ui/zcl_abapgit_html_form.clas.xml @@ -5,7 +5,7 @@ ZCL_ABAPGIT_HTML_FORM E - abapgit html form component + abapgit - HTML form component 1 X X