diff --git a/.github/badges/abap2ui5.json b/.github/badges/abap2ui5.json index b968d0d2..8cd05b90 100644 --- a/.github/badges/abap2ui5.json +++ b/.github/badges/abap2ui5.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "label": "abap2UI5", - "message": "146 apps · 169 views · 2,162 controls", + "message": "148 apps · 171 views · 2,202 controls", "color": "007ec6", "labelColor": "555", "cacheSeconds": 3600 diff --git a/.github/badges/check-abap2ui5.json b/.github/badges/check-abap2ui5.json index 2ece9c42..e6ac1004 100644 --- a/.github/badges/check-abap2ui5.json +++ b/.github/badges/check-abap2ui5.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, "label": "check-abap2UI5", - "message": "2 problems", - "color": "dfb317", + "message": "111 rules passed", + "color": "4c1", "labelColor": "555", "cacheSeconds": 3600 } diff --git a/src/00/98/z2ui5_cl_smp_app_500.clas.abap b/src/00/98/z2ui5_cl_smp_app_500.clas.abap index ff09293d..7f6e2ac6 100644 --- a/src/00/98/z2ui5_cl_smp_app_500.clas.abap +++ b/src/00/98/z2ui5_cl_smp_app_500.clas.abap @@ -19,9 +19,8 @@ CLASS z2ui5_cl_smp_app_500 DEFINITION DATA mt_table TYPE ty_t_rows. PROTECTED SECTION. - DATA client TYPE REF TO z2ui5_if_client. - DATA check_initialized TYPE abap_bool. - DATA mv_next_id TYPE i. + DATA client TYPE REF TO z2ui5_if_client. + DATA mv_next_id TYPE i. METHODS on_init. METHODS render_main. @@ -35,16 +34,19 @@ ENDCLASS. CLASS z2ui5_cl_smp_app_500 IMPLEMENTATION. METHOD z2ui5_if_app~main. + me->client = client. - IF check_initialized = abap_false. - check_initialized = abap_true. + IF client->check_on_init( ). on_init( ). render_main( ). + ELSEIF client->check_on_navigated( ). + on_after_popup( ). + render_main( ). + ELSEIF client->check_on_event( ). + on_event( ). ENDIF. - on_after_popup( ). - on_event( ). ENDMETHOD. @@ -61,115 +63,147 @@ CLASS z2ui5_cl_smp_app_500 IMPLEMENTATION. METHOD render_main. - DATA(view) = z2ui5_cl_xml_view=>factory( ). - DATA(page) = view->page( title = 'Demo Table (Simple Selection)' - shownavbutton = abap_false ). - - DATA(table) = page->table( - growing = 'true' - width = 'auto' - items = client->_bind_edit( mt_table ) ). - - " columns (hardcoded instead of the layout manager) - DATA(columns) = table->columns( ). - columns->column( )->text( 'Sel' ). - columns->column( )->text( 'Carrier' ). - columns->column( )->text( 'Conn.' ). - columns->column( )->text( 'From' ). - columns->column( )->text( 'To' ). - - " one row template; row press opens the edit popup, passing ROW_ID - DATA(cells) = columns->get_parent( )->items( - )->column_list_item( - type = 'Navigation' - press = client->_event( val = 'ROW_SELECT' - t_arg = VALUE #( ( `${ROW_ID}` ) ) ) - )->cells( ). - - cells->checkbox( '{SELKZ}' ). - cells->text( '{CARRID}' ). - cells->text( '{CONNID}' ). - cells->text( '{CITYFROM}' ). - cells->text( '{CITYTO}' ). + DATA(view) = z2ui5_cl_ui5_view_builder=>factory( + )->ele( n = `View` ns = `mvc` + )->a( n = `displayBlock` v = `true` + )->a( n = `height` v = `100%` + )->a( n = `xmlns` v = `sap.m` + )->a( n = `xmlns:mvc` v = `sap.ui.core.mvc` + )->a( n = `xmlns:core` v = `sap.ui.core` ). + + DATA(page) = view->ele( `Shell` + )->ele( `Page` + )->a( n = `title` v = `abap2UI5 - Table - Simple Selection` + )->a( n = `showNavButton` b = abap_false ). + + DATA(table) = page->ele( `Table` + )->a( n = `growing` b = abap_true + )->a( n = `width` v = `auto` + )->a( n = `items` v = client->_bind( mt_table ) ). + + " the columns, hardcoded instead of driven by a layout manager + DATA(columns) = table->ele( `columns` ). + + columns->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `Sel` ). + columns->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `Carrier` ). + columns->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `Conn.` ). + columns->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `From` ). + columns->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `To` ). + + " one row template; the row press opens the edit popup, carrying ROW_ID + DATA(cells) = table->ele( `items` + )->ele( `ColumnListItem` + )->a( n = `type` v = `Navigation` + )->a( n = `press` v = client->_event( val = `ROW_SELECT` + t_arg = VALUE #( ( `${ROW_ID}` ) ) ) + )->ele( `cells` ). + + cells->tag( `CheckBox` + )->a( n = `selected` v = `{SELKZ}` ). + cells->tag( `Text` + )->a( n = `text` v = `{CARRID}` ). + cells->tag( `Text` + )->a( n = `text` v = `{CONNID}` ). + cells->tag( `Text` + )->a( n = `text` v = `{CITYFROM}` ). + cells->tag( `Text` + )->a( n = `text` v = `{CITYTO}` ). " footer buttons: Add / Delete / Refresh / Save - page->footer( )->overflow_toolbar( )->toolbar_spacer( - )->button( text = 'Add' - icon = 'sap-icon://add' - press = client->_event( 'BUTTON_ADD' ) - )->button( text = 'Delete' - type = 'Reject' - icon = 'sap-icon://delete' - press = client->_event( 'BUTTON_DELETE' ) - )->button( text = 'Refresh' - icon = 'sap-icon://refresh' - press = client->_event( 'BUTTON_REFRESH' ) - )->button( text = 'Save' - type = 'Success' - press = client->_event( 'BUTTON_SAVE' ) ). - - client->view_display( page->stringify( ) ). + page->ele( `footer` + )->ele( `OverflowToolbar` + )->tag( `ToolbarSpacer` + + )->tag( `Button` + )->a( n = `text` v = `Add` + )->a( n = `icon` v = `sap-icon://add` + )->a( n = `press` v = client->_event( `BUTTON_ADD` ) + )->tag( `Button` + )->a( n = `text` v = `Delete` + )->a( n = `type` v = `Reject` + )->a( n = `icon` v = `sap-icon://delete` + )->a( n = `press` v = client->_event( `BUTTON_DELETE` ) + )->tag( `Button` + )->a( n = `text` v = `Refresh` + )->a( n = `icon` v = `sap-icon://refresh` + )->a( n = `press` v = client->_event( `BUTTON_REFRESH` ) + )->tag( `Button` + )->a( n = `text` v = `Save` + )->a( n = `type` v = `Accept` + )->a( n = `press` v = client->_event( `BUTTON_SAVE` ) ). + + client->view_display( view->stringify( ) ). + ENDMETHOD. METHOD on_event. - CASE client->get( )-event. - - WHEN 'ROW_SELECT'. - DATA(t_arg) = client->get( )-t_event_arg. - DATA(arg) = t_arg[ 1 ]. + CASE client->get_event( ). - DATA(row_id) = arg. + WHEN `ROW_SELECT`. client->nav_app_call( z2ui5_cl_smp_app_501=>factory( it_table = mt_table - iv_row_id = CONV #( row_id ) + iv_row_id = CONV #( client->get_event_arg( ) ) iv_edit = abap_true ) ). - WHEN 'BUTTON_ADD'. + WHEN `BUTTON_ADD`. client->nav_app_call( z2ui5_cl_smp_app_501=>factory( it_table = mt_table iv_row_id = mv_next_id iv_edit = abap_false ) ). mv_next_id = mv_next_id + 1. - WHEN 'BUTTON_DELETE'. - + WHEN `BUTTON_DELETE`. button_delete( ). - WHEN 'BUTTON_REFRESH'. + WHEN `BUTTON_REFRESH`. on_init( ). - WHEN 'BUTTON_SAVE'. + WHEN `BUTTON_SAVE`. button_save( ). + ENDCASE. + ENDMETHOD. METHOD button_delete. + DELETE mt_table WHERE selkz = abap_true. + ENDMETHOD. METHOD button_save. + " no DB / no transport in the test version - just confirm client->message_toast_display( |{ lines( mt_table ) } rows "saved"| ). + ENDMETHOD. METHOD on_after_popup. - " same idea as the original: read the previous app's data back - IF client->get( )-check_on_navigated = abap_false. - RETURN. - ENDIF. + " same idea as the original: read the edited table back out of the app + " that was called, which get_app_prev( ) hands over TRY. - DATA(app) = CAST z2ui5_cl_smp_app_501( - client->get_app( client->get( )-s_draft-id_prev_app ) ). + DATA(app) = CAST z2ui5_cl_smp_app_501( client->get_app_prev( ) ). mt_table = app->mt_table. - CATCH cx_root. + CATCH cx_root ##NO_HANDLER. ENDTRY. + ENDMETHOD. -ENDCLASS. \ No newline at end of file +ENDCLASS. diff --git a/src/00/98/z2ui5_cl_smp_app_501.clas.abap b/src/00/98/z2ui5_cl_smp_app_501.clas.abap index 9549d665..27ce0a2e 100644 --- a/src/00/98/z2ui5_cl_smp_app_501.clas.abap +++ b/src/00/98/z2ui5_cl_smp_app_501.clas.abap @@ -15,9 +15,8 @@ CLASS z2ui5_cl_smp_app_501 DEFINITION RETURNING VALUE(result) TYPE REF TO z2ui5_cl_smp_app_501. PROTECTED SECTION. - DATA client TYPE REF TO z2ui5_if_client. - DATA mv_init TYPE abap_bool. - DATA mv_edit TYPE abap_bool. + DATA client TYPE REF TO z2ui5_if_client. + DATA mv_edit TYPE abap_bool. DATA mv_row_id TYPE i. METHODS on_init. @@ -32,104 +31,148 @@ ENDCLASS. CLASS z2ui5_cl_smp_app_501 IMPLEMENTATION. METHOD factory. + result = NEW #( ). result->mt_table = it_table. result->mv_row_id = iv_row_id. result->mv_edit = iv_edit. + ENDMETHOD. METHOD z2ui5_if_app~main. + me->client = client. - IF mv_init = abap_false. - mv_init = abap_true. + + IF client->check_on_init( ). on_init( ). render_popup( ). + ELSEIF client->check_on_navigated( ). + render_popup( ). + ELSEIF client->check_on_event( ). + on_event( ). ENDIF. - on_event( ). + ENDMETHOD. METHOD on_init. - " table -> single edit row (table_to_row in the original) + + " table -> the single row the popup edits (table_to_row in the original) ms_row = VALUE #( mt_table[ row_id = mv_row_id ] DEFAULT VALUE #( row_id = mv_row_id ) ). + ENDMETHOD. METHOD render_popup. - DATA(popup) = z2ui5_cl_xml_view=>factory_popup( ). - - DATA(form) = popup->dialog( - title = COND #( WHEN mv_edit = abap_true THEN 'Edit Row' ELSE 'Add Row' ) - afterclose = client->_event( 'POPUP_CLOSE' ) - )->simple_form( editable = abap_true - )->content( 'form' ). - - " key field disabled in edit mode, like the original - form->label( 'Carrier' ). - form->input( value = client->_bind_edit( ms_row-carrid ) - enabled = xsdbool( mv_edit = abap_false ) ). - - form->label( 'Connection' ). - form->input( value = client->_bind_edit( ms_row-connid ) - enabled = xsdbool( mv_edit = abap_false ) ). - form->label( 'From' ). - form->input( client->_bind_edit( ms_row-cityfrom ) ). + DATA(popup) = z2ui5_cl_ui5_view_builder=>factory( + )->ele( n = `FragmentDefinition` ns = `core` + )->a( n = `xmlns` v = `sap.m` + )->a( n = `xmlns:core` v = `sap.ui.core` + )->a( n = `xmlns:form` v = `sap.ui.layout.form` ). + + DATA(dialog) = popup->ele( `Dialog` + )->a( n = `title` v = COND #( WHEN mv_edit = abap_true THEN `Edit Row` ELSE `Add Row` ) + )->a( n = `afterClose` v = client->_event( `POPUP_CLOSE` ) ). + + DATA(form) = dialog->ele( n = `SimpleForm` ns = `form` + )->a( n = `editable` b = abap_true + )->ele( n = `content` ns = `form` ). + + " the key fields are disabled in edit mode, like the original + form->tag( `Label` + )->a( n = `text` v = `Carrier` ). + form->tag( `Input` + )->a( n = `value` v = client->_bind( ms_row-carrid ) + )->a( n = `enabled` b = xsdbool( mv_edit = abap_false ) ). + + form->tag( `Label` + )->a( n = `text` v = `Connection` ). + form->tag( `Input` + )->a( n = `value` v = client->_bind( ms_row-connid ) + )->a( n = `enabled` b = xsdbool( mv_edit = abap_false ) ). + + form->tag( `Label` + )->a( n = `text` v = `From` ). + form->tag( `Input` + )->a( n = `value` v = client->_bind( ms_row-cityfrom ) ). + + form->tag( `Label` + )->a( n = `text` v = `To` ). + form->tag( `Input` + )->a( n = `value` v = client->_bind( ms_row-cityto ) ). + + DATA(buttons) = dialog->ele( `buttons` ). + + buttons->tag( `Button` + )->a( n = `text` v = `Cancel` + )->a( n = `press` v = client->_event( `POPUP_CLOSE` ) ). - form->label( 'To' ). - form->input( client->_bind_edit( ms_row-cityto ) ). - - DATA(toolbar) = form->get_root( )->get_child( )->buttons( ). - toolbar->button( text = 'Cancel' - press = client->_event( 'POPUP_CLOSE' ) ). IF mv_edit = abap_true. - toolbar->button( text = 'Delete' - type = 'Reject' - press = client->_event( 'POPUP_DELETE' ) ). + buttons->tag( `Button` + )->a( n = `text` v = `Delete` + )->a( n = `type` v = `Reject` + )->a( n = `press` v = client->_event( `POPUP_DELETE` ) ). ENDIF. - toolbar->button( text = 'OK' - type = 'Emphasized' - press = client->_event( COND #( WHEN mv_edit = abap_true - THEN 'POPUP_EDIT' ELSE 'POPUP_ADD' ) ) ). + + buttons->tag( `Button` + )->a( n = `text` v = `OK` + )->a( n = `type` v = `Emphasized` + )->a( n = `press` v = client->_event( COND #( WHEN mv_edit = abap_true + THEN `POPUP_EDIT` ELSE `POPUP_ADD` ) ) ). client->popup_display( popup->stringify( ) ). + ENDMETHOD. METHOD on_event. - CASE client->get( )-event. - WHEN 'POPUP_EDIT'. + + CASE client->get_event( ). + + WHEN `POPUP_EDIT`. popup_edit( ). leave( ). - WHEN 'POPUP_ADD'. + + WHEN `POPUP_ADD`. APPEND ms_row TO mt_table. leave( ). - WHEN 'POPUP_DELETE'. + + WHEN `POPUP_DELETE`. popup_delete( ). leave( ). - WHEN 'POPUP_CLOSE'. + + WHEN `POPUP_CLOSE`. leave( ). + ENDCASE. + ENDMETHOD. METHOD popup_edit. + DATA(row) = REF #( mt_table[ row_id = mv_row_id ] OPTIONAL ). IF row IS BOUND. row->* = ms_row. ENDIF. + ENDMETHOD. METHOD popup_delete. + DELETE mt_table WHERE row_id = mv_row_id. + ENDMETHOD. METHOD leave. + client->popup_destroy( ). client->nav_app_leave( client->get_app( client->get( )-s_draft-id_prev_app_stack ) ). + ENDMETHOD. -ENDCLASS. \ No newline at end of file +ENDCLASS. diff --git a/src/01/z2ui5_cl_smp_app_202.clas.abap b/src/01/z2ui5_cl_smp_app_202.clas.abap index a8f6a2c3..6ce87093 100644 --- a/src/01/z2ui5_cl_smp_app_202.clas.abap +++ b/src/01/z2ui5_cl_smp_app_202.clas.abap @@ -6,6 +6,7 @@ CLASS z2ui5_cl_smp_app_202 DEFINITION PUBLIC. PUBLIC SECTION. INTERFACES z2ui5_if_app. + DATA next_step TYPE string. PROTECTED SECTION. METHODS view_display @@ -95,6 +96,17 @@ CLASS z2ui5_cl_smp_app_202 IMPLEMENTATION. client->view_display( lr_view->stringify( ) ). + " nextStep is an ASSOCIATION: no binding can carry it, and view_display( ) + " has just destroyed the slot XMLView.create rebuilds - so the branch the + " handler picked is gone from the fresh WizardStep while NEXT_STEP still + " describes it. Re-issuing the same call here is what makes the choice + " survive a navigation back, a draft restore or any later redisplay. + IF next_step IS NOT INITIAL. + client->follow_up_action( + val = z2ui5_if_client=>cs_event-control_by_id + t_arg = VALUE #( ( `STEP2` ) ( `setNextStep` ) ( next_step ) ) ). + ENDIF. + ENDMETHOD. @@ -114,12 +126,13 @@ CLASS z2ui5_cl_smp_app_202 IMPLEMENTATION. " generic whitelisted control calls - t_arg is positional: " id, method, params (the step params are control ids; the view " defaults to cs_view-main) + next_step = client->get_event( ). client->follow_up_action( val = z2ui5_if_client=>cs_event-control_by_id t_arg = VALUE #( ( `wiz` ) ( `discardProgress` ) ( `STEP2` ) ) ). client->follow_up_action( val = z2ui5_if_client=>cs_event-control_by_id - t_arg = VALUE #( ( `STEP2` ) ( `setNextStep` ) ( client->get_event( ) ) ) ). + t_arg = VALUE #( ( `STEP2` ) ( `setNextStep` ) ( next_step ) ) ). ENDCASE. diff --git a/src/01/z2ui5_cl_smp_app_474.clas.abap b/src/01/z2ui5_cl_smp_app_474.clas.abap index 85a49b60..bf8774c5 100644 --- a/src/01/z2ui5_cl_smp_app_474.clas.abap +++ b/src/01/z2ui5_cl_smp_app_474.clas.abap @@ -57,10 +57,19 @@ CLASS z2ui5_cl_smp_app_474 IMPLEMENTATION. " backend payload can carry - the frontend therefore takes the NAME of a " built-in policy and installs the matching validator itself: " RELATIVE_ONLY (only in-app links stay clickable), ALLOW_ALL, DENY_ALL + " + " The handler is live control state a rebuild destroys, and this method is + " not on the display path - control-state-lost-on-rebuild is right about + " both. It is still not a defect HERE: every open goes through this method, + " so the validator is re-installed immediately before each openBy( ) below, + " and there is no window in which the popover is visible without it. That + " is the one thing the rule cannot see, so it is said here instead. + " abap2ui5lint-disable control-state-lost-on-rebuild -- re-issued before every openBy client->follow_up_action( val = z2ui5_if_client=>cs_event-control_by_id t_arg = VALUE #( ( `msgPopover` ) ( `setAsyncURLHandler` ) ( policy ) ) ). + " abap2ui5lint-enable control-state-lost-on-rebuild " ... and only then open it, anchored to the button that fired the event client->follow_up_action( val = z2ui5_if_client=>cs_event-control_by_id