Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
284 changes: 214 additions & 70 deletions src/z2ui5_cl_smps_app_00.clas.abap
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@
"! button disabled. The price is that a renamed class no longer breaks the
"! build - the CI check `npm run check:overview` covers that instead.
"!
"! The page header carries the SHARED OVERVIEW HEADER of the abap2UI5 family -
"! six icon buttons pointing at the framework start page, the three sample
"! repositories, the documentation and this repository (render_header). It
"! answers the same question per button, and for the same reason: a sibling
"! repository is installed on its own, so an installed overview app is entered
"! with nav_app_call( ) and a missing one opens its GitHub repository instead.
"! Keep it in sync with the copies in abap2UI5/samples and
"! abap2UI5/samples-controls.
"! The page has no header of its own: render_header( ) puts a Bar into its
"! customHeader, with the back button and the title on the left and the SHARED
"! OVERVIEW HEADER of the abap2UI5 family on the right - one core:Icon per
"! sample repository, a ToolbarSeparator, then the documentation and this
"! repository. It answers the same question per icon, and for the same reason:
"! a sibling repository is installed on its own, so an installed overview app
"! is entered with nav_app_call( ) and a missing one opens a popover saying it
"! has to be installed first, with the link to its repository. Keep it in sync
"! with the copies in abap2UI5/samples and abap2UI5/samples-controls.
CLASS z2ui5_cl_smps_app_00 DEFINITION PUBLIC.

PUBLIC SECTION.
Expand Down Expand Up @@ -73,18 +74,28 @@ CLASS z2ui5_cl_smps_app_00 DEFINITION PUBLIC.
"! Regenerate Demo Data button has something to call
DATA demo_data_installed TYPE abap_bool.

"! sap.ui.core.IconColor knows no blue - Positive, Critical, Negative and
"! Neutral are the semantic four - so the interactive icons of the header
"! carry the accent of the sap_horizon theme as a plain CSS colour, and the
"! one that leads nowhere keeps the semantic grey
CONSTANTS:
BEGIN OF cs_color,
active TYPE string VALUE `#0064D9` ##NO_TEXT,
inactive TYPE string VALUE `Neutral` ##NO_TEXT,
END OF cs_color.

CONSTANTS:
BEGIN OF cs_event,
regenerate TYPE string VALUE `REGENERATE` ##NO_TEXT,
nav TYPE string VALUE `NAV_APP` ##NO_TEXT,
install TYPE string VALUE `INSTALL` ##NO_TEXT,
END OF cs_event.

"! the overview apps of the abap2UI5 family, in the order the shared header
"! renders them - each repository is installed on its own, so the header
"! asks per entry whether its overview app is on THIS system
CONSTANTS:
BEGIN OF cs_overview,
startup TYPE string VALUE `z2ui5_cl_app_startup` ##NO_TEXT,
samples TYPE string VALUE `z2ui5_cl_smp_app_000` ##NO_TEXT,
controls TYPE string VALUE `z2ui5_cl_smpc_app_overview` ##NO_TEXT,
"! the overview app of samples-controls before its 2026-08 rename - an
Expand All @@ -96,7 +107,6 @@ CLASS z2ui5_cl_smps_app_00 DEFINITION PUBLIC.
CONSTANTS:
BEGIN OF cs_url,
docs TYPE string VALUE `https://abap2UI5.org` ##NO_TEXT,
framework TYPE string VALUE `https://github.com/abap2UI5/abap2UI5` ##NO_TEXT,
samples TYPE string VALUE `https://github.com/abap2UI5/samples` ##NO_TEXT,
controls TYPE string VALUE `https://github.com/abap2UI5/samples-controls` ##NO_TEXT,
stack TYPE string VALUE `https://github.com/abap2UI5/samples-stack` ##NO_TEXT,
Expand All @@ -115,21 +125,40 @@ CLASS z2ui5_cl_smps_app_00 DEFINITION PUBLIC.
METHODS model_init.

"! The header every abap2UI5 overview app shares: one icon button per
"! sibling repository - it jumps into that repository's overview app when
"! the app is on this system and opens the repository on GitHub when it is
"! not - followed by the documentation and this repository. The entry of
"! the repository you are looking at stays visible but disabled, so the
"! header reads the same everywhere. Keep it in sync with the copies in
"! abap2UI5/samples and abap2UI5/samples-controls.
"! sample repository - it jumps into that repository's overview app when
"! the app is on this system and says how to install it when it is not -
"! followed by a separator and what leaves the system, the documentation
"! and this repository. Exactly one entry is inactive: the repository you
"! are looking at, there is nowhere to go from it. Keep it in sync with the
"! copies in abap2UI5/samples and abap2UI5/samples-controls.
METHODS render_header
IMPORTING
page TYPE REF TO z2ui5_cl_ai_xml
title TYPE string.

"! the vertical line that groups the header row: the sample repositories of
"! the family first, then what leaves the system
METHODS header_separator
IMPORTING
toolbar TYPE REF TO z2ui5_cl_ai_xml.

"! A repository that is not on this system stays clickable and says what is
"! missing - a popover on the icon that was pressed, with the GitHub link
"! to install it from.
METHODS install_display
IMPORTING
anchor TYPE string
href TYPE string
name TYPE string.

METHODS header_button
IMPORTING
toolbar TYPE REF TO z2ui5_cl_ai_xml
icon TYPE string
tooltip TYPE string
"! the entry's name - the tooltip opens with it and the popover of an
"! uninstalled repository is titled after it
name TYPE string
descr TYPE string
href TYPE string
class TYPE string OPTIONAL
"! the overview app's PREVIOUS name, tried when CLASS is not on the
Expand Down Expand Up @@ -221,6 +250,14 @@ CLASS z2ui5_cl_smps_app_00 IMPLEMENTATION.
ENDIF.
client->message_toast_display( text ).

WHEN cs_event-install.

" a header icon whose repository is not on this system - anchor class,
" GitHub URL and repository name travel as the event arguments
install_display( anchor = client->get_event_arg( )
href = client->get_event_arg( 2 )
name = client->get_event_arg( 3 ) ).

WHEN cs_event-nav.

" a header button whose target overview app is on this system - the
Expand All @@ -246,24 +283,17 @@ CLASS z2ui5_cl_smps_app_00 IMPLEMENTATION.
DATA(page) = view->open( n = `View` ns = `mvc`
)->a( n = `xmlns` v = `sap.m`
)->a( n = `xmlns:mvc` v = `sap.ui.core.mvc`
)->a( n = `xmlns:core` v = `sap.ui.core`
)->a( n = `displayBlock` v = `true`
)->a( n = `height` v = `100%`
)->open( `Shell`
)->open( `Page`
)->a( n = `title` v = `abap2UI5 - samples-stack - 00 Overview`
)->a( n = `class` v = `sapUiContentPadding` ).

" the button sits in the page header, so it stays reachable no matter
" which package the user has scrolled to. It is hidden outright when
" neither RAP package is installed - there would be nothing to fill.
DATA(toolbar) = page->open( `headerContent` ).
toolbar->leaf( `Button`
)->a( n = `text` v = `Regenerate Demo Data`
)->a( n = `icon` v = `sap-icon://refresh`
)->a( n = `visible` v = z2ui5_cl_ai_xml=>as_bool( demo_data_installed )
)->a( n = `press` v = client->_event( cs_event-regenerate ) ).

render_header( toolbar ).
" title and back button come with the custom header (render_header), not
" with the page - a Page renders either its own header or a custom one
render_header( page = page
title = `abap2UI5 - samples-stack - 00 Overview` ).

page->leaf( `MessageStrip`
)->a( n = `text` v = `Every sample of this repository, one package per section - Open starts it ` &&
Expand Down Expand Up @@ -326,81 +356,195 @@ CLASS z2ui5_cl_smps_app_00 IMPLEMENTATION.

METHOD render_header.

header_button( toolbar = toolbar
icon = `sap-icon://home`
tooltip = `abap2UI5 - the start page of the framework`
class = cs_overview-startup
href = cs_url-framework ).
DATA(bar) = page->open( `customHeader` )->open( `Bar` ).

" left: what the stock page header would render on its own
DATA(left) = bar->open( `contentLeft` ).

left->leaf( `Button`
)->a( n = `icon` v = `sap-icon://nav-back`
)->a( n = `type` v = `Transparent`
)->a( n = `tooltip` v = `Back`
)->a( n = `visible` v = z2ui5_cl_ai_xml=>as_bool( client->check_app_prev_stack( ) )
)->a( n = `press` v = client->_event_nav_app_leave( ) ).

left->leaf( `Title`
)->a( n = `text` v = title
)->a( n = `level` v = `H2` ).

DATA(right) = bar->open( `contentRight` ).

" this repository's own action first - it fills the tables the RAP samples
" read, and it is hidden outright when neither RAP package is installed
right->leaf( `Button`
)->a( n = `text` v = `Regenerate Demo Data`
)->a( n = `icon` v = `sap-icon://refresh`
)->a( n = `type` v = `Transparent`
)->a( n = `visible` v = z2ui5_cl_ai_xml=>as_bool( demo_data_installed )
)->a( n = `press` v = client->_event( cs_event-regenerate ) ).

header_separator( right ).

header_button( toolbar = toolbar
" then the sample repositories of the abap2UI5 family, one icon each ...
header_button( toolbar = right
icon = `sap-icon://lightbulb`
tooltip = `Samples - binding, events, popups, tables and much more`
name = `Samples`
descr = `binding, events, popups, tables and much more`
class = cs_overview-samples
href = cs_url-samples ).

header_button( toolbar = toolbar
header_button( toolbar = right
icon = `sap-icon://palette`
tooltip = `Controls - the UI5 Demo Kit, rebuilt with abap2UI5`
name = `Control Samples`
descr = `the UI5 Demo Kit, rebuilt with abap2UI5`
class = cs_overview-controls
class_old = cs_overview-controls_old
href = cs_url-controls ).

header_button( toolbar = toolbar
header_button( toolbar = right
icon = `sap-icon://database`
tooltip = `Stack - OData, RAP, WebSockets and the Fiori Launchpad`
name = `Stack Samples`
descr = `OData, RAP, WebSockets and the Fiori Launchpad`
class = cs_overview-stack
href = cs_url-stack
here = abap_true ).

header_button( toolbar = toolbar
" ... and then, set apart by a separator line, the two entries that leave
" the system: the three icons above open an app, these open a site
header_separator( right ).

header_button( toolbar = right
icon = `sap-icon://learning-assistant`
tooltip = `Documentation - guides, tutorials and the API reference`
name = `Documentation`
descr = `guides, tutorials and the API reference`
href = cs_url-docs ).

header_button( toolbar = toolbar
icon = `sap-icon://source-code`
tooltip = `GitHub - the source code of this repository`
" not source-code: in the shared header that icon is reserved for the
" per-sample source links the overviews render in their lists
header_button( toolbar = right
icon = `sap-icon://globe`
name = `GitHub`
descr = `the source code of this repository`
href = cs_url-stack ).

ENDMETHOD.


METHOD header_separator.

toolbar->leaf( `ToolbarSeparator`
)->a( n = `class` v = `sapUiSmallMarginBegin sapUiSmallMarginEnd` ).

ENDMETHOD.


METHOD install_display.

DATA(info) = z2ui5_cl_ai_xml=>factory( ).

info->open( n = `FragmentDefinition` ns = `core`
)->a( n = `xmlns` v = `sap.m`
)->a( n = `xmlns:core` v = `sap.ui.core`

)->open( `Popover`
)->a( n = `title` v = |{ name } - not installed|
)->a( n = `placement` v = `Bottom`
)->a( n = `contentWidth` v = `26rem`

)->open( `VBox`
)->a( n = `class` v = `sapUiContentPadding`

)->leaf( `Text`
)->a( n = `text` v = |This system does not have { name } installed, so there is no app to | &&
|jump to. Install the repository with abapGit, then this icon opens it right here.|
)->leaf( `Link`
)->a( n = `text` v = href
)->a( n = `href` v = href
)->a( n = `target` v = `_blank`
)->a( n = `class` v = `sapUiSmallMarginTop` ).

client->popover_display( xml = info->stringify( )
by_id = anchor ).

ENDMETHOD.


METHOD header_button.

DATA target TYPE string.
DATA hint TYPE string.
DATA color TYPE string.
DATA press TYPE string.

DATA(button) = toolbar->leaf( `Button` ).
button->a( n = `icon` v = icon
)->a( n = `type` v = `Transparent` ).
DATA(tooltip) = |{ name } - { descr }|.

IF here = abap_true.
" where you are: the button stays, so every overview shows the same row,
" but there is nowhere to go
button->a( n = `tooltip` v = |{ tooltip } - you are here|
)->a( n = `enabled` v = z2ui5_cl_ai_xml=>as_bool( abap_false ) ).
RETURN.
ENDIF.

" to_upper: the repository stores class names in upper case, while the
" constants above follow this repository's lower-case spelling of them
IF class IS NOT INITIAL AND class_check_installed( to_upper( class ) ) = abap_true.
target = class.
ELSEIF class_old IS NOT INITIAL AND class_check_installed( to_upper( class_old ) ) = abap_true.
target = class_old.
" where you are: the entry stays, so every overview shows the same row,
" but there is nowhere to go - and no press
hint = |{ tooltip } - you are here|.
color = cs_color-inactive.

ELSE.

color = cs_color-active.

" to_upper: the repository stores class names in upper case, while the
" constants above follow this repository's lower-case spelling of them
IF class IS NOT INITIAL AND class_check_installed( to_upper( class ) ) = abap_true.
target = class.
ELSEIF class_old IS NOT INITIAL AND class_check_installed( to_upper( class_old ) ) = abap_true.
target = class_old.
ENDIF.

IF target IS NOT INITIAL.
" installed on this system: jump right into it, the back button returns
hint = tooltip.
press = client->_event( val = cs_event-nav
t_arg = VALUE #( ( target ) ) ).

ELSEIF class IS INITIAL.
" no CLASS to look for: the documentation and GitHub entries are no
" destination inside the system to begin with, they open their site
hint = tooltip.
press = open_url( href ).

ELSE.
" a repository that is not on this system is a normal, active entry -
" the press says what is missing and where to get it (install_display),
" instead of dropping the user on GitHub without a word
hint = |{ tooltip } - not installed on this system|.
press = client->_event( val = cs_event-install
t_arg = VALUE #( ( class )
( href )
( name ) ) ).
ENDIF.

ENDIF.

IF target IS NOT INITIAL.
" installed on this system: jump right into it, the back button returns
button->a( n = `tooltip` v = tooltip
)->a( n = `press` v = client->_event( val = cs_event-nav
t_arg = VALUE #( ( target ) ) ) ).
RETURN.
" a core:Icon, not a Button: on 1.71 a Button cannot carry a colour - the
" coloured sap.m.ButtonType values (Critical, Neutral, ...) are 1.73+ - and
" the colour is what separates the active entries from the ONE inactive
" one, the overview you are already in. Everything else is active, whether
" its repository is on this system or not. The class name doubles as the
" icon id, so install_display( ) can anchor its popover to the icon pressed
toolbar->leaf( n = `Icon` ns = `core`
)->a( n = `src` v = icon
)->a( n = `size` v = `1.125rem`
)->a( n = `class` v = `sapUiTinyMarginBeginEnd`
)->a( n = `color` v = color
)->a( n = `tooltip` v = hint ).

" a( ) writes on the element just added, and an EMPTY attribute would be
" rendered as one - id="" and press="" are not valid, so the two optional
" ones are added only when they carry something
IF class IS NOT INITIAL.
toolbar->a( n = `id` v = class ).
ENDIF.

button->a( n = `tooltip` v = COND #( WHEN class IS INITIAL
THEN tooltip
ELSE |{ tooltip } - not installed, opens GitHub| )
)->a( n = `press` v = open_url( href ) ).
IF press IS NOT INITIAL.
toolbar->a( n = `press` v = press ).
ENDIF.

ENDMETHOD.

Expand Down