Skip to content
Merged
Show file tree
Hide file tree
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
10 changes: 10 additions & 0 deletions docs/.vitepress/playground.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ const NEEDS_MORE_THAN_A_BROWSER = [
why: 'calls a function module, and there is no application server to call one on',
what: /\bCALL\s+FUNCTION\b/i,
},
{
/* Not a transpiler question - whatever AUTHORITY-CHECK compiles to, the
* page in the browser has no user, no roles and no authorization objects,
* so sy-subrc after it means nothing. An example whose whole point is
* which branch the check takes cannot take either one here. Reasoned
* rather than watched, unlike the lines above it, and it fails towards no
* button like the rest. */
why: 'runs an authority check, and the browser has no user and no roles for one',
what: /\bAUTHORITY-CHECK\b/i,
},
];

/*
Expand Down
8 changes: 4 additions & 4 deletions docs/advanced/extensibility/custom_control.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ view->ele( n = `View` ns = `mvc`
)->a( n = `onEvent` v = client->_event( `MY_EVENT` ) ).
```

The wrapper class the previous builder needed for this
([`z2ui5_cl_xml_view_cc`](https://github.com/abap2UI5/abap2UI5/blob/main/src/99/z2ui5_cl_xml_view_cc.clas.abap))
is frozen along with the builder itself, and adding a method to it is no longer
part of shipping a custom control.
Nothing else is needed on the ABAP side. The builder writes whatever element
and namespace you pass, verbatim, so a custom control is just another tag —
there is no wrapper class to extend and no method to add before it can be
used.

27 changes: 5 additions & 22 deletions docs/advanced/extensibility/user_exits.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ outline: [2, 4]
---
# User Exits

abap2UI5 offers predefined user exits for tweaking the standard behavior. The interface [`Z2UI5_IF_EXIT`](https://github.com/abap2UI5/abap2UI5/blob/main/src/99/z2ui5_if_exit.intf.abap) exposes the user exits. To use them on your system, build a class that implements the interface and its methods. The abap2UI5 class [`Z2UI5_CL_UI5_USER_EXIT`](https://github.com/abap2UI5/abap2UI5/blob/main/src/01/04/z2ui5_cl_ui5_user_exit.clas.abap) calls them dynamically. Put your class in a custom package — **not** in the abap2UI5 packages.
abap2UI5 offers predefined user exits for tweaking the standard behavior. The interface [`Z2UI5_IF_UI5_EXIT`](https://github.com/abap2UI5/abap2UI5/blob/main/src/02/z2ui5_if_ui5_exit.intf.abap) exposes the user exits. To use them on your system, build a class that implements the interface and its methods. The abap2UI5 class [`Z2UI5_CL_UI5_USER_EXIT`](https://github.com/abap2UI5/abap2UI5/blob/main/src/01/04/z2ui5_cl_ui5_user_exit.clas.abap) calls them dynamically. Put your class in a custom package — **not** in the abap2UI5 packages.

The interface exposes two exit methods:
- **`set_config_http_get`** — called on the initial HTTP GET request (page load). Use it to set frontend properties like the UI5 theme, the UI5 version, or the inline CSS.
Expand All @@ -15,19 +15,19 @@ Both methods take a `cs_config` changing parameter whose fields you can set as n
CLASS zcl_a2ui5_user_exit DEFINITION PUBLIC.

PUBLIC SECTION.
INTERFACES z2ui5_if_exit.
INTERFACES z2ui5_if_ui5_exit.

ENDCLASS.

CLASS zcl_a2ui5_user_exit IMPLEMENTATION.

METHOD z2ui5_if_exit~set_config_http_get.
METHOD z2ui5_if_ui5_exit~set_config_http_get.

cs_config-theme = `sap_belize`.

ENDMETHOD.

METHOD z2ui5_if_exit~set_config_http_post.
METHOD z2ui5_if_ui5_exit~set_config_http_post.

cs_config-draft_exp_time_in_hours = 8.

Expand All @@ -47,21 +47,4 @@ CLASS zcl_a2ui5_user_exit IMPLEMENTATION.
ENDCLASS.
```

::: tip The interface is being renamed
`z2ui5_if_exit` becomes
[`z2ui5_if_ui5_exit`](https://github.com/abap2UI5/abap2UI5/blob/main/src/02/z2ui5_if_ui5_exit.intf.abap),
following the framework's naming. Both work — abap2UI5 looks up both
interfaces, so an existing exit keeps running — and the examples here move to
the new name once it is in a release. On `main` the old interface has already
moved to the frozen `src/99` package, which is why the link above points
there; it still ships and is still called. See
[Deprecations](/resources/deprecations).
:::

::: warning The tab title is not set here
`cs_config-title` is still on the structure — an exit that assigns it compiles
and runs — but nothing reads it any more. The generated page always carries
`<title>abap2UI5</title>`, and the title the user sees is set by the running
app with the `set_title` frontend event: see
[Title](/cookbook/browser_interaction/title).
:::

2 changes: 1 addition & 1 deletion docs/advanced/renaming.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ alone would let them collide; the segment is what keeps them apart.

| Segment | Meaning |
|---|---|
| *(none)* — `z2ui5_if_app`, `z2ui5_if_client`, `z2ui5_if_exit` | **The public API.** The three interfaces carry no segment on purpose: they are the contract, and a contract does not move between layers. `z2ui5_if_types` carries none either and is the exception that proves the rule: it is retired, ships unchanged so existing apps keep compiling, and every type it held now sits on the object that uses it — see [Deprecations](/resources/deprecations) |
| *(none)* — `z2ui5_if_app`, `z2ui5_if_client` | **The public API.** Both interfaces carry no segment on purpose: they are the contract, and a contract does not move between layers. `z2ui5_if_types` carries none either and is the exception that proves the rule: it is retired, ships unchanged so existing apps keep compiling, and every type it held now sits on the object that uses it — see [Deprecations](/resources/deprecations) |
| `ui5` | The framework itself — the engine and the shipped apps (`z2ui5_cl_ui5_handler`, `z2ui5_cl_ui5_srv_draft`, `z2ui5_cl_ui5_app_start`), plus the two public classes `z2ui5_cl_ui5_http_handler` and `z2ui5_cl_ui5_view_builder` |
| `ui5f` | The UI5 **f**rontend, embedded as ABAP string constants and **generated** — never edit one by hand, the next build overwrites it |
| `ajson`, `srt` | [ajson](/technical/tools/ajson) and [S-RTTI](/technical/tools/srtti), mirrored from their upstream projects under this namespace |
Expand Down
47 changes: 38 additions & 9 deletions docs/configuration/authorization.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,34 +73,63 @@ Alternatively, handle authorization within individual app classes. This approach
### Example: Authorization Check in an App Class
In this approach, each app checks the user's permissions, like traditional ABAP apps.

<!-- playground: no Run button — runs an authority check and shows nothing — an empty frame demonstrates nothing -->
<!-- playground: no Run button — an authority check needs a user and roles, and the browser has neither -->
```abap
CLASS z2ui5_cl_app DEFINITION PUBLIC.

PUBLIC SECTION.
INTERFACES z2ui5_if_app.

DATA mv_status TYPE string.

PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.

CLASS z2ui5_cl_app IMPLEMENTATION.

METHOD z2ui5_if_app~main.
" Run an authorization check before launching the app
AUTHORITY-CHECK OBJECT `Z_APP_AUTH`
ID `APP` FIELD `Z2UI5_APP_001`.

IF sy-subrc <> 0.
" Authorization failed, refuse access
RETURN.
IF client->check_on_navigated( ).

" Run an authorization check before showing anything
AUTHORITY-CHECK OBJECT `Z_APP_AUTH`
ID `APP` FIELD `Z2UI5_APP_001`.

IF sy-subrc <> 0.
" Refuse, and SAY so - a blank screen looks like a broken app
mv_status = `You are not authorized to use this app.`.
client->message_box_display( text = mv_status
type = `error`
title = `Not authorized` ).
ELSE.
mv_status = |Authorized as { sy-uname }|.
ENDIF.

DATA(view) = z2ui5_cl_ui5_view_builder=>factory(
)->ele( n = `View` ns = `mvc`
)->a( n = `xmlns` v = `sap.m`
)->a( n = `xmlns:mvc` v = `sap.ui.core.mvc`

)->ele( `Page`
)->a( n = `title` v = `Authorization`

)->tag( `Text`
)->a( n = `text` v = client->_bind( mv_status ) ) ).

client->view_display( view->stringify( ) ).

ENDIF.

" Continue with app processing if authorized
" (App logic goes here)
ENDMETHOD.

ENDCLASS.
```

The refusal branch matters as much as the check. Returning without displaying
anything leaves the user on an empty frame with nothing to go on — indistinguishable
from an app that crashed. Say what happened, then return.

::: warning
If you don't add authorization checks at the app level, make sure users can't bypass service-level checks by navigating between apps.
:::
8 changes: 1 addition & 7 deletions docs/configuration/performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,12 @@ METHOD z2ui5_if_app~main.
ENDMETHOD.
```

::: tip You may see `client->view_model_update( )` in older code
It used to be the way to ask for that push. It is a **no-op** now — the
framework does it unconditionally — and it is scheduled for removal. Delete
the call; nothing replaces it.
:::


## Suggestions
Want to tune your app further? A few tips:
- Call `client->view_display` only when needed — on initialization and when the view structure changes. For a pure data change, set the attribute and return; the framework pushes the delta and UI5 re-renders only the controls that changed.

- Bind data with `client->_bind` — the framework sends only the paths the user actually edited back to ABAP (a delta), so read-only and untouched fields cost nothing on the return trip. (`_bind_edit` is an obsolete alias of `_bind`.)
- Bind data with `client->_bind` — the framework sends only the paths the user actually edited back to ABAP (a delta), so read-only and untouched fields cost nothing on the return trip.
- Declare public attributes in your app class only for variables shown on the frontend. This keeps the framework from reading unused values.
- Follow standard ABAP best practices, like cutting loops and choosing sorted tables, just like in any other ABAP project.

Expand Down
8 changes: 4 additions & 4 deletions docs/configuration/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ By default, abap2UI5 uses the CSP below (defined in `z2ui5_cl_ui5_user_exit`):
If needed, adjust the CSP in the [user exit](/advanced/extensibility/user_exits). The exit runs after the framework fills in the defaults, so whatever you set there overrides the default policy:

```abap
METHOD z2ui5_if_exit~set_config_http_get.
METHOD z2ui5_if_ui5_exit~set_config_http_get.

cs_config-content_security_policy = `<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline' ui5.sap.com *.ui5.sap.com sdk.openui5.org *.sdk.openui5.org cdn.jsdelivr.net *.cdn.jsdelivr.net"/>`.

Expand All @@ -55,7 +55,7 @@ ENDMETHOD.
`'unsafe-eval'` weakens the protection CSP provides against script injection. The default keeps it only because OpenUI5 `1.71` — the oldest supported release — still executes fetched modules via `eval()` in its module loader. If you pin a modern UI5 release, no `eval()` is involved and you can remove `'unsafe-eval'` in the same exit where you set the bootstrap source. The example below is the default policy without `'unsafe-eval'`:

```abap
METHOD z2ui5_if_exit~set_config_http_get.
METHOD z2ui5_if_ui5_exit~set_config_http_get.

cs_config-src = `https://ui5.sap.com/resources/sap-ui-core.js`.
cs_config-theme = `sap_horizon`.
Expand Down Expand Up @@ -113,7 +113,7 @@ They live in `cs_config-t_security_header` and are set in the same
behind a proxy that already sets one of them can drop or change it:

```abap
METHOD z2ui5_if_exit~set_config_http_get.
METHOD z2ui5_if_ui5_exit~set_config_http_get.

" keep everything the framework set, override one entry
DELETE cs_config-t_security_header WHERE n = `Referrer-Policy`.
Expand All @@ -129,7 +129,7 @@ Every state-changing request in abap2UI5 is a POST, so the framework ships its o
**CSRF protection is active by default.** A fresh install rejects cross-origin POSTs without any configuration. If your endpoint must accept cross-origin POSTs (for example, behind a proxy setup where the origin legitimately differs), opt out in the [user exit](/advanced/extensibility/user_exits):

```abap
METHOD z2ui5_if_exit~set_config_http_post.
METHOD z2ui5_if_ui5_exit~set_config_http_post.

" escape hatch - only disable this if your endpoint must accept cross-origin POSTs
cs_config-check_csrf_active = abap_false.
Expand Down
10 changes: 5 additions & 5 deletions docs/configuration/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ outline: [2, 4]
---
# Setup

Every UI5 application has an `index.html` that bootstraps the framework, picks a theme, loads a UI5 version and so on. With abap2UI5 you don't maintain that file by hand — the framework generates it on every page load. To change what ends up in it, implement the `z2ui5_if_exit` interface in your own ABAP class:
Every UI5 application has an `index.html` that bootstraps the framework, picks a theme, loads a UI5 version and so on. With abap2UI5 you don't maintain that file by hand — the framework generates it on every page load. To change what ends up in it, implement the `z2ui5_if_ui5_exit` interface in your own ABAP class:

```abap
CLASS zcl_a2ui5_user_exit DEFINITION PUBLIC.

PUBLIC SECTION.
INTERFACES z2ui5_if_exit.
INTERFACES z2ui5_if_ui5_exit.

ENDCLASS.

CLASS zcl_a2ui5_user_exit IMPLEMENTATION.

METHOD z2ui5_if_exit~set_config_http_get.
METHOD z2ui5_if_ui5_exit~set_config_http_get.
" your configuration goes here
ENDMETHOD.

Expand All @@ -36,9 +36,9 @@ ENDCLASS.

Security-relevant headers and the Content Security Policy meta tag are configured separately — see [Security](/configuration/security).

The tab title is **not** on this list. The generated page always carries `<title>abap2UI5</title>`, and the title the user sees is set by the running app with the `set_title` frontend event — see [Title](/cookbook/browser_interaction/title). The field `cs_config-title` still exists on `cs_config` so that existing exits compile, but nothing reads it.
The tab title is **not** on this list. The generated page always carries `<title>abap2UI5</title>`, and the title the user sees is set by the running app with the `set_title` frontend event — see [Title](/cookbook/browser_interaction/title).

## See Also

- Official SAP documentation on [UI5 bootstrapping](https://sapui5.hana.ondemand.com/#/topic/91f2cebe7c8e4d289fd80a4f0c0bd2ca) and [configuration options](https://sapui5.hana.ondemand.com/#/topic/91f2d03b6f4d1014b6dd926db0e91070).
- The [User Exit](/advanced/extensibility/user_exits) page documents every hook on `z2ui5_if_exit`.
- The [User Exit](/advanced/extensibility/user_exits) page documents every hook on `z2ui5_if_ui5_exit`.
2 changes: 1 addition & 1 deletion docs/configuration/setup/bootstrap_attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ The UI5 bootstrap script tag in `index.html` accepts a long list of `data-sap-ui
To add an attribute — or override one of the defaults — append a row to `cs_config-t_add_config`. Each row contributes one `name='value'` pair to the script tag:

```abap
METHOD z2ui5_if_exit~set_config_http_get.
METHOD z2ui5_if_ui5_exit~set_config_http_get.

cs_config-t_add_config = VALUE #(
( n = `data-sap-ui-libs` v = `sap.m,sap.ui.table` )
Expand Down
2 changes: 1 addition & 1 deletion docs/configuration/setup/logon_language.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Most apps don't need this — the browser locale and the SAP logon language agre
You can also pin the UI5 locale via the bootstrap, instead of relying on a URL parameter:

```abap
METHOD z2ui5_if_exit~set_config_http_get.
METHOD z2ui5_if_ui5_exit~set_config_http_get.

cs_config-t_add_config = VALUE #(
( n = `data-sap-ui-language` v = `en` ) ).
Expand Down
2 changes: 1 addition & 1 deletion docs/configuration/setup/style_css.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ outline: [2, 4]
UI5 supports app-specific CSS in addition to the theme. abap2UI5 injects whatever string you assign to `cs_config-styles_css` directly into a `<style>` block in the page `<head>`, so any selector you write is applied to your application.

```abap
METHOD z2ui5_if_exit~set_config_http_get.
METHOD z2ui5_if_ui5_exit~set_config_http_get.

cs_config-styles_css =
|body \{ background-color: #f5f5f5; \}| &&
Expand Down
2 changes: 1 addition & 1 deletion docs/configuration/setup/theme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ outline: [2, 4]
The theme defines the look and feel of every UI5 control — colours, fonts, paddings, spacings. In a hand-written `index.html` it is set via the `data-sap-ui-theme` attribute on the bootstrap script. In abap2UI5 you set it from ABAP:

```abap
METHOD z2ui5_if_exit~set_config_http_get.
METHOD z2ui5_if_ui5_exit~set_config_http_get.

cs_config-theme = `sap_horizon_dark`.

Expand Down
2 changes: 1 addition & 1 deletion docs/configuration/setup/ui5_bootstrapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Bootstrapping is the process of loading the UI5 runtime into the browser. abap2U
## Pick a Bootstrap Source

```abap
METHOD z2ui5_if_exit~set_config_http_get.
METHOD z2ui5_if_ui5_exit~set_config_http_get.

cs_config-src = `https://ui5.sap.com/1.116.0/resources/sap-ui-core.js`.

Expand Down
15 changes: 13 additions & 2 deletions docs/cookbook/browser_interaction/focus.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,17 @@ This is useful for guided data entry, barcode scanning, or any flow where the ne
After processing an event, call `client->follow_up_action( )` with `cs_event-set_focus` and the id of the input to focus next. (The value bindings on the inputs are omitted here to keep the focus logic clear — see [Barcode Scanning](/cookbook/device_capabilities/barcode_scanning) for the same form with bound inputs.)

```abap
METHOD z2ui5_if_app~main.
CLASS z2ui5_cl_sample_focus DEFINITION PUBLIC.

PUBLIC SECTION.
INTERFACES z2ui5_if_app.

PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.

CLASS z2ui5_cl_sample_focus IMPLEMENTATION.
METHOD z2ui5_if_app~main.

IF client->check_on_navigated( ).
DATA(view) = z2ui5_cl_ui5_view_builder=>factory(
Expand Down Expand Up @@ -68,7 +78,8 @@ METHOD z2ui5_if_app~main.

ENDIF.

ENDMETHOD.
ENDMETHOD.
ENDCLASS.
```

After the user presses Enter in `id1`, the backend fires `set_focus` for `id2` and the cursor moves to the second input. The same pattern works for any chain of fields.
Expand Down
Loading