diff --git a/docs/advanced/addons.md b/docs/advanced/addons.md index 065aee9b..ae54d4c7 100644 --- a/docs/advanced/addons.md +++ b/docs/advanced/addons.md @@ -5,7 +5,7 @@ outline: [2, 4] abap2UI5 focuses on core capabilities — rendering views, handling events, and exchanging data. This keeps the framework lean and easy to maintain. The real strength lies in the ecosystem: **ready-to-use add-ons and community projects** that extend abap2UI5 for specific needs. -#### Available Add-ons +## Available Add-ons Browse the [abap2UI5-addons](https://github.com/abap2UI5-addons) organization to find what you need. Features include: - Layout variant handling, similar to classic SAP GUI selection screens or ALV reports @@ -13,7 +13,7 @@ Browse the [abap2UI5-addons](https://github.com/abap2UI5-addons) organization to - Integration with third-party libraries like Chart.js for richer charts - And many more -#### Open Source Projects +## Open Source Projects Other open-source projects use abap2UI5 — try them out: @@ -26,6 +26,6 @@ Other open-source projects use abap2UI5 — try them out: | [table-content-loader](https://github.com/abap2UI5-apps/table-content-loader) | Upload & download table content | | [table-maintenance](https://github.com/abap2UI5-addons/table-maintenance) | Table maintenance in your browser | -#### Contribution +## Contribution Built a feature or your own open-source project with abap2UI5? Contribute to existing repositories or start your own. Add your project here so others can find, use, and contribute to your work. diff --git a/docs/advanced/downporting.md b/docs/advanced/downporting.md index e0e98533..112f692a 100644 --- a/docs/advanced/downporting.md +++ b/docs/advanced/downporting.md @@ -5,7 +5,7 @@ outline: [2, 4] abap2UI5 works right away on ABAP 7.50 and later. On an earlier release, install the downported version, which supports R/3 NetWeaver 7.02 and later. -#### Branch +## Branch To install on an older system, use the `702` branch: | Branch | System | |-----------| ----------------------------| @@ -14,7 +14,7 @@ To install on an older system, use the `702` branch: Some sample projects and other repositories also ship a downported version. Check whether a `702` branch is available. -#### Installation +## Installation The installation on an old release follows the normal [installation](/configuration/installation) flow with two adjustments: 1. Pull the `702` branch with abapGit — abapGit itself is 7.02-compatible, so deployment to old ECC machines works the same way as everywhere else 2. Create the HTTP handler (SICF service) with the 7.02-compatible handler syntax instead of the modern snippet @@ -23,7 +23,7 @@ After that, call your HTTP handler from the browser and abap2UI5 is ready for us If you later want to reach these apps from the cloud, use the [RFC Connector](/advanced/rfc): it calls abap2UI5 apps on legacy systems via BTP destination and RFC, integrating them into Steampunk, S/4 Public Cloud, Fiori Launchpads, or SAP Mobile Start. The [HTTP Connector](/advanced/http) offers the same over HTTP. -#### How It Works +## How It Works The `702` branch is not maintained by hand — it is **generated** from `main` by an automated GitHub Actions workflow on every change. The pipeline runs [abaplint](https://abaplint.org)'s downport rule (`abaplint --fix` with a 7.02 target configuration), which rewrites modern syntax into 7.02-compatible equivalents, for example: - inline declarations `DATA(x) = ...` → separate `DATA` statements @@ -35,7 +35,7 @@ A few small compatibility fix-ups follow (e.g. replacing exception types that do The same mechanism runs in this project's CI (`npm run auto_downport`) to guarantee every change on `main` stays downportable. -#### Why abap2UI5 Is Downportable +## Why abap2UI5 Is Downportable Automatic syntax rewriting is only the last step. The codebase is compatible with everything from ABAP 7.02 up to the newest ABAP Cloud because of four design principles: **1. Only basic technology.** No OData services, CDS views, or new EML syntax — none of these exist on older ECCs. Conversely, no SAP GUI or other statements forbidden in ABAP Cloud. The only universally available technology is a plain HTTP service (defined via SICF on-premise, via Eclipse in the cloud), and that is all abap2UI5 needs for communication. @@ -48,5 +48,5 @@ Automatic syntax rewriting is only the last step. The codebase is compatible wit Keep these principles in mind if you want to set up your next abapGit project with compatibility for older releases. -#### Further Reading +## Further Reading Background article: [Running abap2UI5 on older R/3 Releases](https://www.linkedin.com/pulse/running-abap2ui5-older-r3-releases-downport-compatibility-abaplint-mjkle). diff --git a/docs/advanced/extensibility/custom_control.md b/docs/advanced/extensibility/custom_control.md index 97dd6678..f208534b 100644 --- a/docs/advanced/extensibility/custom_control.md +++ b/docs/advanced/extensibility/custom_control.md @@ -7,11 +7,11 @@ You can build your own UI5 custom controls and use them in abap2UI5 apps. First, set up your VS Code environment with the abap2UI5 frontend artifacts, following the [Frontend](/advanced/extensibility/frontend) page. -#### Frontend +## Frontend Write the JavaScript for your new custom control. Each custom control lives in its own file under [app/webapp/cc/](https://github.com/abap2UI5/abap2UI5/tree/main/app/webapp/cc) — copy an existing one (e.g. `Timer.js`) and adapt it to your needs. -#### Backend +## Backend Nothing. The current view builder has no method per control, so a custom control needs no backend counterpart — write the element and its properties diff --git a/docs/advanced/extensibility/frontend.md b/docs/advanced/extensibility/frontend.md index 67447748..dd7223d7 100644 --- a/docs/advanced/extensibility/frontend.md +++ b/docs/advanced/extensibility/frontend.md @@ -5,7 +5,7 @@ outline: [2, 4] The abap2UI5 frontend artifacts live in the `app` folder. To adjust them: -#### Setup +## Setup Open VS Code (or your editor of choice), then run in the terminal: ```sh git clone https://github.com/abap2UI5/abap2UI5 @@ -15,7 +15,7 @@ Next replace `<>` in the three config files — `ui5.yaml`, `ui5-local.y Frontend config files where the backend system URL must be replaced -#### Build & Test +## Build & Test If your HTTP service uses a different path, also replace `/sap/bc/z2ui5` with your endpoint in the manifest. Then run: ```sh npm i @@ -24,7 +24,7 @@ npm run start-noflp You'll see output like this: npm run start-noflp output showing the local dev server running -#### Before PR (Optional) +## Before PR (Optional) Convert the UI5 app to stringified ABAP: ```sh cd .. diff --git a/docs/advanced/fiori.md b/docs/advanced/fiori.md index fa8b25bf..6491255c 100644 --- a/docs/advanced/fiori.md +++ b/docs/advanced/fiori.md @@ -7,7 +7,7 @@ Extend the object page of a Fiori list report app with an abap2UI5 app. See the abap2UI5 app embedded in Fiori Elements object page -### Guide +## Guide 1. Register the FLP integration in the component.js: diff --git a/docs/advanced/http.md b/docs/advanced/http.md index f9bc7501..5e324da2 100644 --- a/docs/advanced/http.md +++ b/docs/advanced/http.md @@ -5,18 +5,18 @@ outline: [2, 4] The [abap2UI5 HTTP Connector](https://github.com/abap2UI5-addons/http-connector) calls abap2UI5 apps remotely over HTTP between two ABAP systems. It works similarly to the [RFC Connector](./rfc.md), but uses HTTP instead of RFC as the communication channel. -#### When to use +## When to use The HTTP Connector enables several useful cases: - Frontend/Backend Split: abap2UI5 apps live in the backend, but users access them through a separate frontend system - Legacy Systems (e.g., ECC): downport abap2UI5 to older systems and call it over HTTP from a newer system - Multi-System Landscapes: one entry point reaches abap2UI5 apps spread across multiple systems - Cross-Network Scenarios: HTTP is often easier to route through firewalls, reverse proxies, and gateways than RFC -#### Architecture +## Architecture The system that calls the app (the frontend system) ships with the UI5 library and bootstraps the UI. The system that runs the app (the backend system) doesn't need to host the UI5 runtime — it only exposes its abap2UI5 endpoint over HTTP. -#### Installation +## Installation _Prerequisite: Set up an SM59 HTTP destination pointing to the backend system (the system that runs the apps). Install abap2UI5 on both systems._ @@ -25,5 +25,5 @@ Steps: 2. In the HTTP handler, configure the destination to point to the backend system 3. In your browser, call the HTTP Connector's endpoint on the frontend system (the ICF service installed with the connector — analogous to `.../sap/bc/2ui5_rfc` for the RFC Connector) -#### Further Information +## Further Information For the latest details, source code, and updates, see the [HTTP Connector repository on GitHub](https://github.com/abap2UI5-addons/http-connector). diff --git a/docs/advanced/legacy_free.md b/docs/advanced/legacy_free.md index e642e4c3..3de89605 100644 --- a/docs/advanced/legacy_free.md +++ b/docs/advanced/legacy_free.md @@ -5,11 +5,11 @@ outline: [2, 4] The abap2UI5 frontend is also available as a **legacy-free** variant, bootstrapped from the new legacy-free distribution of OpenUI5 (`1.142.0-legacy-free`) — the build without `jQuery.sap.*`, synchronous APIs, and other deprecated globals. It is essentially a preview of the API surface that UI5 2.x will enforce. -### What is UI5 Legacy-Free? +## What is UI5 Legacy-Free? `*-legacy-free` is a parallel distribution of OpenUI5/SAPUI5 (starting with the 1.136.x line) that ships the same controls and APIs as the regular 1.x build, but with everything deprecated removed up front. In practice that means no `jQuery.sap.*`, no `sap.ui.getCore()`, no synchronous module loading (`sap.ui.requireSync`, sync XHR), no global view/controller factories, no jQuery bundled into the core, and none of the compatibility shims that 1.x kept around for backwards compatibility. -### Why It Matters for the Future +## Why It Matters for the Future UI5 2.x — the next major release line — will enforce exactly this surface. By developing against the legacy-free build today, the project gets several things at once: @@ -21,7 +21,7 @@ UI5 2.x — the next major release line — will enforce exactly this surface. B In short: the legacy-free build is the bridge between today's UI5 1.x ecosystem and tomorrow's UI5 2.x. Building the abap2UI5 frontend on it now means the framework is ready for 2.x the day it lands, instead of chasing it afterwards. -### Installation +## Installation The legacy-free frontend ships as the `v2` branches of the [frontend repository](https://github.com/abap2UI5/frontend). Pull the branch that matches your system into your ABAP system with [abapGit](https://abapgit.org) and activate — there is no separate build step: @@ -36,13 +36,13 @@ The v2 branches install the frontend under the same `z2ui5` name as the classic The former separate repository `abap2UI5/frontend-legacy-free` is obsolete. The legacy-free frontend is now maintained on the `*_v2` branches of the [frontend repository](https://github.com/abap2UI5/frontend), generated from the same single source as the classic variant. ::: -### Why Try the v2 Version? +## Why Try the v2 Version? - **Future-proof.** Apps already run on what UI5 2.x will require — no big-bang migration later. - **Smaller and faster.** No jQuery and no compatibility layers means a leaner core and quicker startup. - **Cleaner foundation.** Modern async patterns, no hidden globals, better alignment with current web standards. -### Learn More +## Learn More - [Available OpenUI5 versions](https://sdk.openui5.org/versionoverview.html) (incl. `*-legacy-free` builds) - [Explore SAPUI5/OpenUI5 1.136.x-legacy-free (SAP Community)](https://community.sap.com/t5/technology-blog-posts-by-sap/explore-sapui5-openui5-1-136-x-legacy-free/ba-p/14103271) diff --git a/docs/advanced/renaming.md b/docs/advanced/renaming.md index 72a9c8c7..768344dd 100644 --- a/docs/advanced/renaming.md +++ b/docs/advanced/renaming.md @@ -10,7 +10,7 @@ prefix, which is what makes several installations in one system possible. ## The `z2ui5` Namespace -#### Why a Prefix and Not a Package +### Why a Prefix and Not a Package ABAP has no package manager. Every object abapGit pulls is created **globally** in the system, so two installations cannot hide behind their package the way two npm modules hide behind `node_modules`. The only thing that keeps objects apart @@ -29,7 +29,7 @@ will overwrite yours. | Exception class | `z2ui5_cx_*` | `z2ui5_cx_ui5_util_error` | | DDIC table | `z2ui5_t_*` | `z2ui5_t_01` | -#### The Second Segment +### The Second Segment The scheme the abap2UI5 repositories share is `z2ui5___` — a name has one more part than the prefix suggests: @@ -97,7 +97,7 @@ segment. abaplint's own naming rule only checks the `Z2UI5_` prefix, so without that gate a new segment would drift in unnoticed. ::: -#### Package Layout +### Package Layout The prefix is flat, the packages are not. abapGit is configured with `FOLDER_LOGIC=PREFIX`, so the folders of a repository become the package hierarchy in your system. For the framework repository that is: @@ -112,7 +112,7 @@ hierarchy in your system. For the framework repository that is: The package a class sits in is the honest answer to "may I use this?": `src/02` yes, `src/01` no, `src/99` only if your app already does. -#### Name Length +### Name Length ABAP object names are limited to 30 characters, and abap2UI5 does not spend all of them: every object name in `src/` stays at **25 characters or less**. The remaining five are headroom for renaming — a namespace of up to 10 characters @@ -122,7 +122,7 @@ This is why the generated frontend classes carry compressed names like `z2ui5_cl_ui5f_scrfocus_js` rather than spelled-out ones: the generator caps them and fails rather than truncating silently. -#### The Frontend Namespace +### The Frontend Namespace `z2ui5` exists a second time — in the browser, as the UI5 module namespace. It is a **different namespace that happens to share the name**, and it is not an ABAP object at all: @@ -140,7 +140,7 @@ installation, renamed or not. That is deliberate: the frontend namespace lives inside one browser page, where only one abap2UI5 installation is ever loaded, so there is nothing for it to collide with. -#### Your Own Objects +### Your Own Objects Nothing about the framework's naming applies to your apps. An app is a class in your own namespace that implements `z2ui5_if_app`: @@ -166,7 +166,7 @@ requirements, like: abap2UI5 works with the abaplint renaming feature and supports namespaces up to 10 characters, e.g., `zabap2ui5`. -#### Why Rename? +### Why Rename? Because objects are global, a system can hold only **one** version of abap2UI5 — and every app in the system is forced to use it. Pulling the latest version can then break existing apps. Public API changes are kept to a minimum, but a @@ -178,7 +178,7 @@ and upgrade each installation at its own pace. At the app level, you simply implement the renamed app interface — e.g., `z2ui5_sd_if_app` or `z2411_if_app` instead of `z2ui5_if_app`. -#### How It Works +### How It Works [abaplint](https://abaplint.org) can rename ABAP artifacts across a whole repository: you define rename patterns (old name → new name, including regular expressions) in an abaplint configuration, and `abaplint --rename` rewrites every class, interface, and reference consistently, writing the result to an output folder: ```jsonc @@ -192,7 +192,7 @@ instead of `z2ui5_if_app`. The renamed copy is a complete, installable abapGit project under your own namespace — install it side by side with the original, pin it to a release, or ship it inside your product. The abap2UI5 CI runs this transformation on every change (`npm run rename`, workflow `test_rename.yaml`) to guarantee the codebase stays renameable. -#### Step-by-Step Guide +### Step-by-Step Guide Everything is already set up in the main repository: the on-demand GitHub Action `build_rename` renames all artifacts to a namespace of your choice and pushes the result as a ready-to-install branch. Renaming abap2UI5 takes just two steps: 1. **Fork** the [abap2UI5 repository](https://github.com/abap2UI5/abap2UI5) @@ -202,7 +202,7 @@ The workflow runs `abaplint --rename` with the checked-in configuration `.github To upgrade an installation later, sync your fork with upstream and re-run the workflow with the same name: the branch is updated to the current state (nothing is pushed when there are no content changes), and you simply pull again with abapGit. -#### What Renaming Does Not Cover +### What Renaming Does Not Cover abaplint rewrites object names and every reference the compiler can see. Three things fall outside that, and it is worth knowing them before you ship a renamed installation. @@ -236,9 +236,9 @@ such as `/ZZZ/` is a regular expression away in the abaplint configuration, but it is not what the workflow builds, and the namespace has to exist in the target system before you can import objects into it. -#### Renaming in Practice: ajson +### Renaming in Practice: ajson abap2UI5 itself relies on this feature: its JSON handling comes from the open-source project [ajson](https://github.com/sbcgua/ajson), which is integrated under the `z2ui5` namespace via renaming — so there are no collisions if you pull both abap2UI5 and ajson separately into the same system. A GitHub Action in the [mirror-ajson](https://github.com/abap2UI5/mirror-ajson) repository checks weekly for upstream changes and automatically creates a pull request with the latest ajson version renamed to `z2ui5`. abapGit bundles ajson under its own namespace the same way — renaming with abaplint also makes it possible to integrate open-source projects into each other. -#### Further Reading +### Further Reading - [Automagic standalone renaming of ABAP objects](https://community.sap.com/t5/application-development-blog-posts/automagic-standalone-renaming-of-abap-objects/ba-p/13499851) - [Renaming of ABAP Artifacts — The Power of abaplint and abapGit in ABAP Development](https://www.linkedin.com/pulse/renaming-abap-artifacts-power-abaplint-github-actions-development-kqede/) diff --git a/docs/advanced/rfc.md b/docs/advanced/rfc.md index eff0ffd3..b4e947dd 100644 --- a/docs/advanced/rfc.md +++ b/docs/advanced/rfc.md @@ -5,19 +5,19 @@ outline: [2, 4] The [abap2UI5 RFC Connector](https://github.com/abap2UI5-addons/rfc-connector) calls abap2UI5 apps remotely over RFC between two ABAP systems. This is handy in distributed system landscapes or with legacy systems that can't directly host UI5 frontend logic. -#### When to use +## When to use The RFC Connector enables several useful cases: - Frontend/Backend Split: abap2UI5 apps live in the backend, but users can only access the frontend server - Legacy Systems (e.g., ECC): downport abap2UI5 to older systems and call it from a newer system over RFC - Multi-System Landscapes: one entry point reaches abap2UI5 apps spread across multiple systems -#### Architecture +## Architecture The system that calls the app (the frontend system) ships with the UI5 library and bootstraps the UI. The system that runs the app (the backend system) doesn't need to host the UI5 runtime. abap2UI5 RFC Connector architecture across frontend and backend systems -#### Installation +## Installation _Prerequisite: Set up an SM59 destination to call the backend system (the system that runs the apps) over RFC. Install abap2UI5 on both systems._ @@ -26,12 +26,12 @@ Steps: 2. In the HTTP handler, replace the destination `NONE` with the RFC destination pointing to the backend system 3. In your browser, call the endpoint `.../sap/bc/2ui5_rfc` -#### UI5 Bootstrapping +## UI5 Bootstrapping The backend system that holds the abap2UI5 apps needs no UI5 libraries. The calling system bootstraps them automatically: UI5 bootstrap loaded from calling system while backend hosts the app logic -#### Multi-System Launchpad +## Multi-System Launchpad You can also use this approach to build a unified Fiori Launchpad that combines: - Apps installed on-stack (on the current system) - Apps called remotely over RFC from other systems diff --git a/docs/configuration/authorization.md b/docs/configuration/authorization.md index 52ebce0e..e1cc900a 100644 --- a/docs/configuration/authorization.md +++ b/docs/configuration/authorization.md @@ -5,10 +5,10 @@ outline: [2, 4] abap2UI5 gives you flexibility in managing authorization. It has no built-in authorization mechanism, so you can build your own solution at either the service or the app level. -### Service-Level +## Service-Level The easiest way to manage access to different apps is to add authorization checks in the HTTP handler. This approach restricts access to individual apps based on the `app_start` URL parameter, directly in the ICF service handler class. -#### Example: Restricting Access Based on URL Parameters +### Example: Restricting Access Based on URL Parameters In this example, we use the ICF handler class to control which apps users can access. The ``get_form_field( `app_start` )`` call reads the `app_start` URL parameter that names the abap2UI5 app class to launch (e.g. `...?app_start=my_app`). If the user requests an unauthorized app, the handler refuses access. ```abap CLASS z2ui5_cl_my_http_handler DEFINITION PUBLIC. @@ -35,7 +35,7 @@ CLASS z2ui5_cl_my_http_handler IMPLEMENTATION. ENDCLASS. ``` -#### Example: Authorization Objects in Service Handlers +### Example: Authorization Objects in Service Handlers You can also pair this with SAP authorization objects. The example below uses a custom authorization object `Z_APP_AUTH` with an `APP` field — define the object in transaction `SU21` and assign it to the matching roles on your system: ```abap CLASS z2ui5_cl_my_http_handler DEFINITION PUBLIC. @@ -67,10 +67,10 @@ ENDCLASS. ``` Create multiple HTTP endpoints for different users or departments to fine-tune access. -### App-Level +## App-Level Alternatively, handle authorization within individual app classes. This approach works well when you want each app to check user permissions before acting. -#### Example: Authorization Check in an App Class +### Example: Authorization Check in an App Class In this approach, each app checks the user's permissions, like traditional ABAP apps. ```abap diff --git a/docs/configuration/btp.md b/docs/configuration/btp.md index f124cc28..ac0626c0 100644 --- a/docs/configuration/btp.md +++ b/docs/configuration/btp.md @@ -11,9 +11,9 @@ Embed your abap2UI5 apps into BTP services like SAP Build Work Zone. The integra All app logic stays in ABAP — nothing app-specific is deployed to BTP. -### Configuration +## Configuration -#### Destination +### Destination Create this destination in your BTP subaccount (**Connectivity → Destinations**): @@ -28,7 +28,7 @@ Create this destination in your BTP subaccount (**Connectivity → Destinations* For on-premise systems without direct internet exposure, use Proxy Type `OnPremise` with the SAP Cloud Connector; for production, prefer a principal-propagation or SAMLAssertion setup over basic authentication. -#### Extra Properties +### Extra Properties SAP Build Work Zone needs these additional properties to route requests correctly to your ABAP backend: @@ -40,7 +40,7 @@ SAP Build Work Zone needs these additional properties to route requests correctl | WebIDEEnabled | `true` | Enables the destination for SAP Business Application Studio | | WebIDEUsage | `odata_abap,dev_abap` | Declares supported protocols for development tools | -#### Work Zone Setup +### Work Zone Setup 1. Subscribe to **SAP Build Work Zone** (standard edition is sufficient) in your subaccount and open the **Site Manager**. 2. Deploy the connector app from the [abap2UI5-addons](https://github.com/abap2UI5-addons) organization to your subaccount's HTML5 application repository. @@ -49,7 +49,7 @@ SAP Build Work Zone needs these additional properties to route requests correctl After that, the tile opens your abap2UI5 app inside the Work Zone shell; the same content is also picked up by [SAP Mobile Start](/configuration/mobile_start). -### Further Reading +## Further Reading The original article series with step-by-step screenshots: - [Installation & Configuration of BTP](https://www.linkedin.com/pulse/abap2ui5-integration-sap-business-technology-platform-13-installation-lf1re/) - [Setup SAP Build Work Zone](https://www.linkedin.com/pulse/abap2ui5-integration-sap-business-technology-platform-23-setup-ujdqe/) diff --git a/docs/configuration/installation.md b/docs/configuration/installation.md index aa955dc4..f9458577 100644 --- a/docs/configuration/installation.md +++ b/docs/configuration/installation.md @@ -6,20 +6,20 @@ abap2UI5 apps run directly via an HTTP service — the fastest and simplest setu But production use may need extra considerations across different system environments. -### S/4 Public Cloud +## S/4 Public Cloud In `S/4 Public Cloud`, the HTTP endpoint needs `S_DEVELOP` authorization, which makes it unfit for production. To make the app reachable for business users, install a separate frontend app and add an extra tile. See [S/4 Public Cloud](/configuration/s4_public_cloud) for details. -### S/4 Private Cloud +## S/4 Private Cloud In `S/4 Private Cloud`, you can make the HTTP endpoint reachable for business users and manage extra authorizations. To also use the SAP Fiori Launchpad, install an extra frontend app. See [Fiori Launchpad](/configuration/launchpad) for details. -### S/4 On-Premise +## S/4 On-Premise The setup in `S/4 On-Premise` matches `S/4 Private Cloud`. Follow the [Fiori Launchpad](/configuration/launchpad) guide. -### R/3 NetWeaver +## R/3 NetWeaver The setup matches `S/4 Private Cloud`. Depending on your release, you might also be able to add the apps to Launchpads. Follow the [Fiori Launchpad](/configuration/launchpad) guide. -### R/3 NetWeaver (<7.50) +## R/3 NetWeaver (<7.50) For R/3 NetWeaver versions below 7.50, install the downported version with syntax tweaks for earlier releases. abap2UI5 runs on releases as far back as 7.02. See [Downporting](/advanced/downporting) for details. -### BTP ABAP Environment +## BTP ABAP Environment The setup in `BTP ABAP Environment` matches `S/4 Public Cloud`. Follow the [S/4 Public Cloud](/configuration/s4_public_cloud) guide. diff --git a/docs/configuration/launchpad.md b/docs/configuration/launchpad.md index 7a10db7d..77e5e76a 100644 --- a/docs/configuration/launchpad.md +++ b/docs/configuration/launchpad.md @@ -5,11 +5,11 @@ outline: [2, 4] Embed your abap2UI5 apps into the SAP Fiori Launchpad (FLP) on S/4 On-Premise or Private Cloud. Each app appears as a regular tile; inside the Launchpad shell, abap2UI5 apps can set their title, read startup parameters, and participate in cross-app navigation like any other Fiori app. -### Installation +## Installation The Launchpad loads the abap2UI5 frontend from the UI5 ABAP repository of your system (as app `z2ui5`). Install the Launchpad connector from the [abap2UI5-addons](https://github.com/abap2UI5-addons) organization via abapGit — it ships the frontend app for the UI5 repository. After the import, check that the app index is up to date (see [Troubleshooting](#troubleshooting) below). -### Target Mapping +## Target Mapping Use these parameters for target mapping in your Launchpad configuration. abap2UI5 uses the app's class name as the Semantic Object so each app gets its own navigation target — replace `Z2UI5_CL_MY_APP` with your app class: - Semantic Object: `Z2UI5_CL_MY_APP` - Action: `display` @@ -17,11 +17,11 @@ Use these parameters for target mapping in your Launchpad configuration. abap2UI - ID: `z2ui5` - Parameter: `app_start / Z2UI5_CL_MY_APP` -### Launchpad Features +## Launchpad Features Inside your app, the client API gives you access to the Launchpad context. Runnable samples: `Z2UI5_CL_SMPS_APP_481` to `Z2UI5_CL_SMPS_APP_484` in the [samples-stack repository](https://github.com/abap2UI5/samples-stack) (package `src/09`). -#### Detect the Launchpad Context +### Detect the Launchpad Context `client->get( )-check_launchpad_active` tells you whether the app currently runs inside a Launchpad — useful to hide your own page header or to guard Launchpad-only features: ```abap @@ -30,7 +30,7 @@ IF client->get( )-check_launchpad_active = abap_false. ENDIF. ``` -#### Set the Tile Title Dynamically +### Set the Tile Title Dynamically Change the Launchpad shell title from ABAP at any time with the `set_title_launchpad` frontend event: ```abap @@ -39,7 +39,7 @@ client->follow_up_action( t_arg = VALUE #( ( `My Dynamic Title` ) ) ). ``` -#### Read Startup Parameters +### Read Startup Parameters Parameters from the target mapping (or the start URL) arrive as name/value pairs in `client->get( )-t_comp_params`: ```abap @@ -47,7 +47,7 @@ DATA(lt_params) = client->get( )-t_comp_params. DATA(lv_product) = VALUE #( lt_params[ n = `PRODUCT` ]-v OPTIONAL ). ``` -#### Cross App Navigation +### Cross App Navigation Handle view changes and popups through the abap2UI5 backend as usual. But for navigation *between* apps in a Launchpad, use the Launchpad's own cross-app navigation instead of a backend roundtrip — this keeps browser navigation and history working. Fire the `cross_app_nav_to_ext` event with the target intent (and optional parameters, here taken from a bound structure): ```abap @@ -68,10 +68,10 @@ To navigate back to the previous Launchpad app, use `cross_app_nav_to_prev_app`: )->a( n = `press` v = client->follow_up_action( client->cs_event-cross_app_nav_to_prev_app ) ``` -### Troubleshooting +## Troubleshooting Sometimes installation via abapGit causes cache-related issues. Here's how to clear them: -#### Cache Management +### Cache Management 1. Recalculate the app index of z2ui5 with report `/UI5/APP_INDEX_CALCULATE` ![App index calculation report selection screen](https://github.com/user-attachments/assets/50c505ab-c58e-46a6-999e-67c4e4cdb929) @@ -86,7 +86,7 @@ Sometimes installation via abapGit causes cache-related issues. Here's how to cl 4. Clear browser caches and hard reload -#### Manual Deployment +### Manual Deployment If clearing caches doesn't fix it, push the frontend app manually: 1. Download the webapp folder of the project. @@ -94,17 +94,17 @@ If clearing caches doesn't fix it, push the frontend app manually: 2. Use the SAP program `/UI5/UI5_REPOSITORY_LOAD` to push the app to the server. UI5 Repository Load program for manual frontend deployment -### Launchpad KPIs +## Launchpad KPIs Extend your Fiori Launchpad with Key Performance Indicators (KPIs) via the abap2UI5 Launchpad KPI add-on. [Repository](https://github.com/abap2UI5-addons/launchpad-kpi) -#### Functionality +### Functionality Launchpad KPI tiles showing dynamic count values
-#### Approach +### Approach The integration has three steps: implement a simple interface, the Launchpad calls a generic OData proxy service, and the proxy delegates to your ABAP class to compute the KPI count. (1/3) Implement the `z2ui5_if_lp_kpi` interface. The `count` method takes an optional `filter` string (from the OData `$filter` parameter) and returns the KPI as an integer: @@ -148,7 +148,7 @@ ENDCLASS. .../sap/opu/odata/sap/Z2UI5_PROXY_KPI_SRV/ENTITYCollection/$count?$filter=CLASS eq 'z2ui5_cl_lp_kpi_hello_world' ``` -### Further Reading +## Further Reading The original article series with additional screenshots: - [Installation & Configuration](https://www.linkedin.com/pulse/copy-abap2ui5-host-your-apps-sap-fiori-launchpad-abap2ui5-ocn2e/) - [Features: Title, Parameters, Navigation](https://www.linkedin.com/pulse/abap2ui5-host-your-apps-sap-fiori-launchpad-23-features-abap2ui5-upche/) diff --git a/docs/configuration/logout.md b/docs/configuration/logout.md index d3486a20..e3e23774 100644 --- a/docs/configuration/logout.md +++ b/docs/configuration/logout.md @@ -5,7 +5,7 @@ outline: [2, 4] A logout button isn't a single action. Depending on how an abap2UI5 app was started, the user may have one, two, or three SAP sessions open at the same time, and each lives in a different place. abap2UI5 ships a built-in client event, `system_logout`, that terminates whichever sessions exist for the current app. See sample `Z2UI5_CL_SMP_APP_361` for a working example. -### The Logout Event +## The Logout Event Fire the event from any controller method to log the user off: ```abap client->_event_client( client->cs_event-system_logout ). @@ -18,17 +18,17 @@ client->_event_client( t_arg = VALUE #( ( `/sap/public/bsp/sap/system/logoff.htm` ) ) ). ``` -### How It Works +## How It Works abap2UI5 can be launched in three ways. Each one creates a different combination of SAP sessions, so the same logout event has to do different things in each case. -#### Startup Contexts +### Startup Contexts | Context | Typical URL | Fiori Launchpad shell? | |---|---|---| | Fiori Launchpad tile | `…/sap/bc/ui2/flp#Z2UI5-display` | yes | | ICF HTTP handler (e.g. `Z2UI5_CL_HTTP_HANDLER`) | `…/sap/bc/` | no | | BSP application (`Z2UI5`, `Z2UI5_V2`) | `…/sap/bc/bsp/sap/z2ui5/index.html` | no | -#### Session Layers +### Session Layers Up to three independent SAP sessions can exist at once. Different cookies, different lifetimes, different ways to end them: - **Fiori Launchpad shell** — the launchpad UI running in the browser, accessed through `sap.ushell.Container`. Only exists if the app was opened from a tile. @@ -37,7 +37,7 @@ Up to three independent SAP sessions can exist at once. Different cookies, diffe The sessions are independent. Ending one does not end the others, and the client can only end sessions that the current page actually loaded. -#### What `system_logout` Does +### What `system_logout` Does The event terminates whichever layers the current startup context owns: | Started from | Launchpad shell | ICF / SSO | BSP context | @@ -46,10 +46,10 @@ The event terminates whichever layers the current startup context owns: | ICF handler URL | — | redirect to `/sap/public/bc/icf/logoff` | — | | BSP URL | — | redirect to `/sap/public/bc/icf/logoff` | hidden iframe to `?sap-sessioncmd=logoff` first | -### Customization +## Customization There are three ways to influence what happens on logout. Pick the one that matches your goal. -#### Custom Post-Logoff URL +### Custom Post-Logoff URL Pass any same-origin URL as `t_arg`. The browser navigates there once the SAP sessions are ended (see the second example in [The Logout Event](#the-logout-event)). Useful when you want a specific landing page — for instance, the standard BSP logoff confirmation page — without changing any system settings. @@ -57,7 +57,7 @@ Pass any same-origin URL as `t_arg`. The browser navigates there once the SAP se The URL must be same-origin. Cross-origin redirects are rejected. ::: -#### SICF Configuration +### SICF Configuration The endpoint `/sap/public/bc/icf/logoff` is part of the SAP system, not abap2UI5. What it shows or redirects to is configured in transaction `SICF` under **Service → Error Pages → Logoff Page**. Common patterns: | Goal | SICF setting | @@ -69,10 +69,10 @@ The endpoint `/sap/public/bc/icf/logoff` is part of the SAP system, not abap2UI5 This is a Basis task. If "I logged out and came right back into the launchpad" is the symptom, this setting is almost always the cause. -#### Run Inside the Fiori Launchpad +### Run Inside the Fiori Launchpad If the goal is the cleanest user experience — going through `Container.logout()` and the FLP's own logoff flow — launch the app as an FLP tile, not from a BSP or handler URL. There is no shell to log out from on a non-FLP URL. -### Single Sign-On +## Single Sign-On On any system with SSO (SAML, Kerberos, X.509, OIDC, …), the logout event ends the SAP sessions in the browser, but the Identity Provider session stays untouched. The next request to a protected SAP URL silently re-authenticates, and the user perceives "the logout didn't work." This is SAP NetWeaver behavior, not abap2UI5 behavior. A true "log out everywhere" needs one of the following: diff --git a/docs/configuration/mobile_start.md b/docs/configuration/mobile_start.md index afe9b923..c7599a2b 100644 --- a/docs/configuration/mobile_start.md +++ b/docs/configuration/mobile_start.md @@ -5,7 +5,7 @@ outline: [2, 4] SAP Mobile Start surfaces your abap2UI5 apps as tiles in SAP's native mobile entry-point app (iOS/Android). No extra abap2UI5 development is needed — Mobile Start mirrors the content of your SAP Build Work Zone site. -### Setup +## Setup 1. Complete the [BTP Build Work Zone](/configuration/btp) setup: destination to your ABAP system, deployed connector app, and the app added as Work Zone content. 2. Enable **SAP Mobile Start** for your Work Zone site (Site Settings) and connect the Mobile Start app on the device to the site — typically by scanning the QR code from the site's settings page. @@ -13,5 +13,5 @@ SAP Mobile Start surfaces your abap2UI5 apps as tiles in SAP's native mobile ent Since abap2UI5 views are responsive UI5 controls, most apps work on phones as they are — check layouts with narrow screens in mind (see the [Device Model](/cookbook/model/device_model) page for adapting views to the device). -### Further Reading +## Further Reading The original article with step-by-step screenshots: [Setup SAP Mobile Start](https://www.linkedin.com/pulse/abap2ui5-integration-sap-business-technology-platform-33-setup-uzure/). diff --git a/docs/configuration/performance.md b/docs/configuration/performance.md index 9ea98aa1..e466607f 100644 --- a/docs/configuration/performance.md +++ b/docs/configuration/performance.md @@ -9,7 +9,7 @@ abap2UI5 keeps frontend logic minimal: no business logic runs in the browser. Ev We've tested abap2UI5 with tables holding large numbers of entries and columns, so you can build your app with confidence — performance shouldn't be a concern. -### Call `view_display( )` once +## Call `view_display( )` once The biggest optimization is **not** rebuilding the view on every event: @@ -55,7 +55,7 @@ the call; nothing replaces it. ::: -### Suggestions +## 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. @@ -63,5 +63,5 @@ Want to tune your app further? A few tips: - 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. -### Performance Issues? +## Performance Issues? If you hit performance issues, build a sample and submit a pull request to the samples repository. We're glad to analyze it and see whether abap2UI5 can be made even faster. diff --git a/docs/configuration/productive_usage.md b/docs/configuration/productive_usage.md index 0abf0beb..74c6c5e8 100644 --- a/docs/configuration/productive_usage.md +++ b/docs/configuration/productive_usage.md @@ -5,8 +5,8 @@ outline: [2, 4] Technically, abap2UI5 is just an HTTP handler implementation — use it like any other HTTP service in production. -#### Stable Version +## Stable Version The project evolves all the time, so there's no fixed "stable" version. But we keep changes to the public APIs minimal to avoid frequent app refactoring. Pin to a [release](https://github.com/abap2UI5/abap2UI5/releases/) instead of tracking the main branch, and update regularly to keep refactoring effort low. -#### Renaming +## Renaming If you're starting new development but already have abap2UI5 apps in production and want to avoid update risk, install multiple instances of abap2UI5 with the [renaming feature](/advanced/renaming). This lets you keep developing safely without disrupting your existing production apps. diff --git a/docs/configuration/s4_public_cloud.md b/docs/configuration/s4_public_cloud.md index 83455ad8..a6e4ed5e 100644 --- a/docs/configuration/s4_public_cloud.md +++ b/docs/configuration/s4_public_cloud.md @@ -7,7 +7,7 @@ Use abap2UI5 for on-stack extension scenarios in S/4 Public Cloud. It uses only To install abap2UI5 on S/4 Public Cloud, follow these steps: -### 1. Install abap2UI5 with abapGit +## 1. Install abap2UI5 with abapGit S/4 Public Cloud supports only the ADT abapGit version. abap2UI5 contains only classes, interfaces, and tables, so you can pull it without issues. @@ -35,7 +35,7 @@ After a moment, the installation completes: Installation complete confirmation -### 2. Mass Activate the Imported Artifacts +## 2. Mass Activate the Imported Artifacts When installing repositories with ADT abapGit, all artifacts arrive inactive. Activate them manually. The simplest approach: create a dedicated inactive/active folder tree for the abap2UI5 project: @@ -61,7 +61,7 @@ Now you'll see that all artifacts are active: Fully activated abap2UI5 package -### 3. Set Up the HTTP Service +## 3. Set Up the HTTP Service Build an HTTP handler manually or use the cloud branch of the [frontend](https://github.com/abap2UI5/frontend) repository. @@ -69,7 +69,7 @@ Build an HTTP handler manually or use the cloud branch of the [frontend](https:/ For production, finish the frontend deployment and tile configuration in the steps below. -### 4. Deploy the UI5 App (Optional) +## 4. Deploy the UI5 App (Optional) Up to here the HTTP service is enough — you can open it and use abap2UI5 with a developer role. Deploying the app is what makes it reachable for **business users**, through a Launchpad tile. @@ -93,7 +93,7 @@ The `cloud` and `cloud_v2` branches ship `sap.app.dataSources.http.uri` as `/sap The on-premise branches (`standard`, `standard_v2`) use the SICF path `/sap/bc/z2ui5` instead. ::: -### 5. Give Business Users Access (Optional) +## 5. Give Business Users Access (Optional) Opening the HTTP service directly works because a developer has `S_DEVELOP`. A business user has not, so the app has to be reached through a tile — which means one chain of objects, each published locally before the next one can see it: diff --git a/docs/configuration/security.md b/docs/configuration/security.md index 0d0effbb..288348b3 100644 --- a/docs/configuration/security.md +++ b/docs/configuration/security.md @@ -4,30 +4,30 @@ outline: [2, 4] # Security abap2UI5 is a backend-centric framework. All logic and business data stay on the server; the frontend gets only the data it needs to render the view. -### HTTP Endpoint +## HTTP Endpoint The abap2UI5 framework runs as an HTTP handler. You build the HTTP handler and call the abap2UI5 API inside it. Users access abap2UI5 by calling the endpoint externally, with security managed like any other UI5 app. -### Authentication +## Authentication The ICF (Internet Communication Framework) node level handles authentication. You get full control over the ICF node configuration, including visibility settings, login procedures, and other security settings. -### Authorization +## Authorization As an app developer, you have full flexibility over authorization. Set it up at either the app level or the service node level. For details on setting up authorization for your endpoint, see the [Authorization](/configuration/authorization) page. -### Backend Code +## Backend Code abap2UI5 ships as custom code. Once installed, you own the code in full and can change it as needed. To stay compatible with future updates, avoid direct changes to the core codebase. -### Frontend Code +## Frontend Code The frontend is a Single-Page Application (SPA) built with SAPUI5 or OpenUI5. The HTTP endpoint delivers it on the first request, in line with standard practices for modern web apps. -### Business Logic +## Business Logic abap2UI5 never sends the app's business logic to the client. All business processes stay safely on the server, and sensitive data never reaches the frontend. -### Content-Security-Policy +## Content-Security-Policy To strengthen security, abap2UI5 uses a Content Security Policy (CSP) by default. CSP blocks attacks like cross-site scripting (XSS) and data injection by restricting which resources the browser can load. The default policy allows a fixed set of trusted sources — the SAP and OpenUI5 CDNs plus jsDelivr and cdnjs; the complete policy is shown below. It also carries hardening directives (`object-src 'none'`, `base-uri 'self'`, `frame-ancestors 'self'`) that block plugin content, pin `` to the app origin and forbid cross-origin framing. The default **does** contain `'unsafe-eval'`: the ui5loader of OpenUI5 `1.71` — the oldest supported release — still evaluates module source as a string, and without `'unsafe-eval'` a `1.71` bootstrap fails with a CSP `EvalError`. Modern UI5 releases load all modules without `eval()`, so if you pin a modern release you can tighten the policy — see [Hardening: Dropping `'unsafe-eval'`](#hardening-dropping-unsafe-eval) below. -#### Default CSP +### Default CSP By default, abap2UI5 uses the CSP below (defined in `z2ui5_cl_ui5_user_exit`): ```xml ``` -#### Customizing the CSP +### Customizing the CSP 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 @@ -51,7 +51,7 @@ METHOD z2ui5_if_exit~set_config_http_get. ENDMETHOD. ``` -#### Hardening: Dropping `'unsafe-eval'` +### Hardening: Dropping `'unsafe-eval'` `'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 @@ -95,7 +95,7 @@ not an allowed source of script: default-src 'self' 'unsafe-inline' data: ui5.sa Only tighten the policy when every system you deploy to bootstraps a modern release. ::: -### Cross-Site Request Forgery (CSRF) +## Cross-Site Request Forgery (CSRF) Every state-changing request in abap2UI5 is a POST, so the framework ships its own CSRF defense instead of relying on a fronting SAP ICF/CSRF layer that may or may not be there. The check compares the host authority of the request's `Origin` (or `Referer`) header against the `Host` header — a cross-origin POST is rejected with an error response before any app logic runs. **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): diff --git a/docs/configuration/transport.md b/docs/configuration/transport.md index aa86b9b7..ced8eb75 100644 --- a/docs/configuration/transport.md +++ b/docs/configuration/transport.md @@ -5,13 +5,13 @@ outline: [2, 4] Transport abap2UI5 to production like any other ABAP project. -#### Preparations +## Preparations For a smooth rollout, follow these steps: 1. Transport the abap2UI5 HTTP service and the framework first. 2. Activate the HTTP service explicitly if needed, and adjust the [UI5 bootstrap source](/configuration/setup/ui5_bootstrapping) if production should use a different UI5 version or delivery channel. 3. Test the "Hello World" app to confirm abap2UI5 works as expected. 4. Finally, transport your own apps. -#### Transport +## Transport Install the project via abapGit on your development system. Then use the standard transport process to deploy to production: ![Transport process from development to production via abapGit](/configuration/image-3.png){ width=80% } diff --git a/docs/configuration/troubleshooting.md b/docs/configuration/troubleshooting.md index 74f7bf49..d581d3bc 100644 --- a/docs/configuration/troubleshooting.md +++ b/docs/configuration/troubleshooting.md @@ -4,21 +4,21 @@ outline: [2, 4] # Debugging Since all logic runs in ABAP, you can debug everything in the ABAP environment. Set an external breakpoint, because abap2UI5 apps are called externally via HTTP. -### Backend +## Backend Set a breakpoint in your abap2UI5 app to debug the code. Check that the XML view builds correctly and that all events fire on the backend as expected. -### Frontend +## Frontend On the frontend, abap2UI5 behaves like a standard UI5 app, so the usual tools and debugging features work. -#### Developer Tools +### Developer Tools Press `Ctrl+F12` to open the built-in **Developer Tools** of abap2UI5: ![Developer Tools showing XML View and Data Model inspection](/configuration/debug.png) Tabs cover the whole roundtrip: **Error** and **Log**, the **System** info, the **Previous Request** and **Response**, the app's **Source Code**, and for every view slot (main, popup, popover, nested) the rendered **View** XML and its **Model** data. The footer offers **Logout**, **Restart**, a jump to **ADT**, and an **Export** that bundles everything — including the running app's ABAP class source — into one blob you can attach to a bug report. Error popups also carry a copy-to-clipboard button for the same purpose. -#### UI5 Inspector +### UI5 Inspector Another option: the SAP default debugging tool, the [UI5 Inspector](https://chromewebstore.google.com/detail/ui5-inspector/bebecogbafbighhaildooiibipcnbngo). -### Issues +## Issues If your code looks correct but you suspect a bug in the abap2UI5 framework, build a minimal sample that reproduces the bug and open an issue on the abap2UI5 repository — we'll investigate and fix it. diff --git a/docs/cookbook/browser_interaction/clipboard.md b/docs/cookbook/browser_interaction/clipboard.md index b95d33fb..87dc3e34 100644 --- a/docs/cookbook/browser_interaction/clipboard.md +++ b/docs/cookbook/browser_interaction/clipboard.md @@ -51,7 +51,7 @@ CLASS z2ui5_cl_sample_clipboard IMPLEMENTATION. ENDCLASS. ``` -#### Copy the App State URL +### Copy the App State URL To share the current app state instead of a custom string, use `clipboard_app_state` — see [App State, Share, Bookmark](../expert_more/app_state_share.md). diff --git a/docs/cookbook/browser_interaction/focus.md b/docs/cookbook/browser_interaction/focus.md index 8b68e6a0..f3132179 100644 --- a/docs/cookbook/browser_interaction/focus.md +++ b/docs/cookbook/browser_interaction/focus.md @@ -9,7 +9,7 @@ samples: Read which control currently holds the focus from the backend, or move the focus from the backend to a specific field — both work without any custom control. -#### Read the Current Focus +### Read the Current Focus `client->get( )-s_focus` tells you which control currently holds the focus and where the caret sits inside it. Useful when an action depends on the field the user was just editing. @@ -21,13 +21,13 @@ DATA(selection_start) = focus-selection_start. " caret start, in chars DATA(selection_end) = focus-selection_end. " caret end, in chars ``` -#### Set the Focus +### Set the Focus Set the input focus from the backend with the `set_focus` frontend event. Pass the target control's `id` as the first argument — the framework moves the cursor to that field after the next roundtrip. This is useful for guided data entry, barcode scanning, or any flow where the next field to focus depends on backend logic. -#### Basic Usage +### Basic Usage 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.) @@ -73,7 +73,7 @@ ENDMETHOD. 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. -#### Selection Range +### Selection Range To position the caret inside the field or pre-select a range, pass the start and end offsets as additional arguments: @@ -82,7 +82,7 @@ client->follow_up_action( val = client->cs_event-set_focus t_arg = VALUE #( ( `id1` ) ( `0` ) ( `5` ) ) ). ``` -#### Barcode Scanning +### Barcode Scanning Most barcode scanner devices emulate a keyboard. Combine `set_focus` with input fields to capture scans into the right field automatically — see [Barcode Scanning](../device_capabilities/barcode_scanning.md) for a full walkthrough. diff --git a/docs/cookbook/browser_interaction/scrolling.md b/docs/cookbook/browser_interaction/scrolling.md index 41c811d6..c0fc758e 100644 --- a/docs/cookbook/browser_interaction/scrolling.md +++ b/docs/cookbook/browser_interaction/scrolling.md @@ -13,7 +13,7 @@ Read the current scroll positions from the backend, or scroll a control programm Useful for jump-to-top buttons, restoring positions after navigation, or revealing a row after a backend search. -#### Read the Scroll Position +### Read the Scroll Position `client->get( )-s_scroll` reports the scroll positions of the page and any open dialogs at the moment the event was fired. Each container exposes the id of the scrollable element and its `x` / `y` offsets in pixels. `main` is the page's own scroll container, `nest` / `nest2` are the first and second [nested views](/cookbook/view/nested_views), and `popup` / `popover` are open dialogs. @@ -27,7 +27,7 @@ DATA(popup_y) = scroll-popup-y. " open popup DATA(popover_y) = scroll-popover-y. " open popover ``` -#### Scroll to a Position +### Scroll to a Position Pass the control id and the vertical position. Optionally also a horizontal position and a scroll behavior (`auto`, `smooth`, or `instant`): @@ -85,7 +85,7 @@ client->follow_up_action( val = client->cs_event-scroll_to t_arg = VALUE #( ( `id_page` ) ( `500` ) ( `0` ) ( `smooth` ) ) ). ``` -#### Scroll an Element into View +### Scroll an Element into View To reveal a specific control — e.g. a row after a search — use `scroll_into_view` with the target control's id: diff --git a/docs/cookbook/browser_interaction/soft_keyboard.md b/docs/cookbook/browser_interaction/soft_keyboard.md index e55b96ee..5931be22 100644 --- a/docs/cookbook/browser_interaction/soft_keyboard.md +++ b/docs/cookbook/browser_interaction/soft_keyboard.md @@ -5,7 +5,7 @@ samples: --- # Soft Keyboard -#### Hide Soft Keyboard +### Hide Soft Keyboard For UI5 input fields, the soft keyboard pops up automatically when an input receives focus. Sometimes — for example, in warehouses with small devices used mainly for barcode scanning — you don't want this behavior. diff --git a/docs/cookbook/browser_interaction/timer.md b/docs/cookbook/browser_interaction/timer.md index 475f391a..656fb8d6 100644 --- a/docs/cookbook/browser_interaction/timer.md +++ b/docs/cookbook/browser_interaction/timer.md @@ -18,7 +18,7 @@ client->follow_up_action( After 2 seconds the browser triggers a backend roundtrip with the event name `REFRESH`, which you handle via `check_on_event` like any other event. -#### Periodic Refresh +### Periodic Refresh To get a repeating timer, simply re-arm it at the end of each handler: @@ -66,7 +66,7 @@ ENDCLASS. The counter increments every 2 seconds. To stop the loop, simply don't re-arm the timer in the handler. -#### One-Shot Timer +### One-Shot Timer A single `start_timer` call fires once — perfect for a deferred action like opening a new tab after a short delay: @@ -80,7 +80,7 @@ WHEN client->check_on_event( `FIRE_OPEN_TAB` ). t_arg = VALUE #( ( `https://www.google.com/search?q=abap2ui5` ) ) ). ``` -#### Replacing a Pending Timer +### Replacing a Pending Timer There is one timer at a time. Calling `start_timer` again before the previous one fires replaces it — useful for a debounce, e.g. auto-saving an input field 500 ms after the last keystroke. diff --git a/docs/cookbook/browser_interaction/title.md b/docs/cookbook/browser_interaction/title.md index 7d4d3ddc..dc7c828f 100644 --- a/docs/cookbook/browser_interaction/title.md +++ b/docs/cookbook/browser_interaction/title.md @@ -8,7 +8,7 @@ samples: Set the text the browser shows in the tab and window title bar. -#### Standalone +### Standalone To change the title after the app is running — for example, to reflect the current record — call the `set_title` frontend event from the backend: @@ -41,7 +41,7 @@ METHOD z2ui5_if_app~main. ENDMETHOD. ``` -#### Launchpad +### Launchpad When the app runs inside an SAP Fiori Launchpad shell, use the dedicated `set_title_launchpad` event instead. It forwards the title to the shell's `ShellUIService` rather than setting `document.title`: diff --git a/docs/cookbook/browser_interaction/url_handling.md b/docs/cookbook/browser_interaction/url_handling.md index 63651e34..06bb9b7d 100644 --- a/docs/cookbook/browser_interaction/url_handling.md +++ b/docs/cookbook/browser_interaction/url_handling.md @@ -9,14 +9,14 @@ samples: Working with URLs is common — reading parameters from the current URL, opening links in new tabs, or managing browser history. -#### Read URL Parameters +### Read URL Parameters Read query parameters from the current URL via the config object: ```abap DATA(lv_search) = client->get( )-s_config-search. ``` -#### Open a New Tab +### Open a New Tab Open a URL in a new browser tab via a frontend event: ```abap DATA(lv_url) = `https://www.abap2UI5.org`. @@ -25,7 +25,7 @@ client->follow_up_action( t_arg = VALUE #( ( lv_url ) ) ). ``` -#### Browser History +### Browser History Two client methods control the browser history from the backend: Push a new history entry — the value is appended to the URL hash, so app state becomes bookmarkable and the browser back button steps through your pushed states: diff --git a/docs/cookbook/cheat_sheet.md b/docs/cookbook/cheat_sheet.md index 01e647ab..6c07068e 100644 --- a/docs/cookbook/cheat_sheet.md +++ b/docs/cookbook/cheat_sheet.md @@ -39,7 +39,7 @@ view->_generic( name = `Button` ns = `sap.m` ``` ::: -#### Next Steps +## Next Steps - [Overview](/cookbook/overview) — the full map of cookbook topics - [Common Failures](/cookbook/troubleshooting/common_failures) — symptoms and their usual causes diff --git a/docs/cookbook/device_capabilities/audio.md b/docs/cookbook/device_capabilities/audio.md index ad10d59a..3842022e 100644 --- a/docs/cookbook/device_capabilities/audio.md +++ b/docs/cookbook/device_capabilities/audio.md @@ -3,7 +3,7 @@ outline: [2, 4] --- # Audio -#### Play Sounds +## Play Sounds Audio feedback is handy in some scenarios. Fire the `play_audio` frontend event with the URL of a sound file — for example a `.wav` from the SAP MIME repository at `/SAP/PUBLIC/BC/ABAP/mime_demo/bam.wav`. diff --git a/docs/cookbook/device_capabilities/barcode_scanning.md b/docs/cookbook/device_capabilities/barcode_scanning.md index 8c1ef5d2..c404f083 100644 --- a/docs/cookbook/device_capabilities/barcode_scanning.md +++ b/docs/cookbook/device_capabilities/barcode_scanning.md @@ -11,7 +11,7 @@ Barcode scanning is common in enterprise apps. With abap2UI5, you can: This section walks through what you need to get started. -#### Scanning +## Scanning Since UI5 version 1.102, the `sap.ndc.BarcodeScannerButton` control is part of the UI5 library, making barcode scanning easy. Use it like any other UI5 control with abap2UI5. The example below shows the basic behavior — customize the handling once the scanning event fires: @@ -51,7 +51,7 @@ To see barcode scanning in action, check the `Z2UI5_CL_DEMO_APP_124` sample app. This feature works only with the UI5 framework, not with OpenUI5. ::: -#### Focus Handling +## Focus Handling Most scanner devices emulate a keyboard. In that case, add an input field and move the focus from the backend — the scanned data flows into the input as if typed. The example below moves focus from one field to the next after each Enter key press by firing the `set_focus` frontend event: @@ -110,7 +110,7 @@ CLASS z2ui5_cl_sample_focus IMPLEMENTATION. ENDCLASS. ``` -#### Play Sounds +## Play Sounds Audio feedback is handy in some scenarios. Fire the `play_audio` frontend event with the URL of a sound file — for example a `.wav` from the SAP MIME repository at `/SAP/PUBLIC/BC/ABAP/mime_demo/bam.wav`: @@ -165,5 +165,5 @@ ENDCLASS. ``` For a complete sound sample, see `Z2UI5_CL_SMPS_APP_487` in the [samples-stack repository](https://github.com/abap2UI5/samples-stack). -#### Render Barcodes +## Render Barcodes To also render barcodes, use bwip-js, which ships with the js-libraries add-on. See [Add-ons](/advanced/addons) for details. diff --git a/docs/cookbook/device_capabilities/info.md b/docs/cookbook/device_capabilities/info.md index d6dc826a..3234a976 100644 --- a/docs/cookbook/device_capabilities/info.md +++ b/docs/cookbook/device_capabilities/info.md @@ -8,19 +8,19 @@ samples: abap2UI5 ships the current frontend state with every roundtrip. Read it from `client->get( )` — no custom control, no extra event needed. The relevant sub-structures are `s_device`, `s_ui5`, `s_focus`, and `s_scroll`. -#### Device +### Device For reading device information via `client->get( )-s_device`, see [Device Model](../model/device_model.md). -#### UI5 +### UI5 For reading the runtime UI5 framework details via `client->get( )-s_ui5`, see [UI5 Versions](../../configuration/ui5_versions.md). -#### Focus +### Focus For reading the current focus via `client->get( )-s_focus`, see [Focus](../browser_interaction/focus.md). -#### Scroll +### Scroll For reading scroll positions via `client->get( )-s_scroll`, see [Scrolling](../browser_interaction/scrolling.md). diff --git a/docs/cookbook/device_capabilities/pdf.md b/docs/cookbook/device_capabilities/pdf.md index b5b82391..16a83e0a 100644 --- a/docs/cookbook/device_capabilities/pdf.md +++ b/docs/cookbook/device_capabilities/pdf.md @@ -7,7 +7,7 @@ samples: Render a PDF directly in your app — for printouts from Adobe Forms, SmartForms, archived documents from the Content Server, or anything else that produces an `xstring`. -#### Built-In Popup +### Built-In Popup The simplest path is the built-in popup `Z2UI5_CL_POP_PDF`. It expects the PDF as a `data:application/pdf;base64,...` URI and embeds it in an iframe: @@ -44,7 +44,7 @@ METHOD z2ui5_if_app~main. ENDMETHOD. ``` -#### Download Instead of Display +### Download Instead of Display To let the user save the PDF rather than view it inline, use the [file download](./upload_download.md) pattern: diff --git a/docs/cookbook/device_capabilities/spreadsheet.md b/docs/cookbook/device_capabilities/spreadsheet.md index 5b0d0740..053a2012 100644 --- a/docs/cookbook/device_capabilities/spreadsheet.md +++ b/docs/cookbook/device_capabilities/spreadsheet.md @@ -5,7 +5,7 @@ outline: [2, 4] abap2UI5 works with the XLSX APIs on your ABAP system to upload and download spreadsheets, converting between XLSX files and internal tables as needed. -#### Upload +## Upload Convert uploaded XLSX files into an internal table: @@ -92,7 +92,7 @@ ENDCLASS. ``` ::: -#### Download +## Download Convert an internal table to an XLSX file and download it to the frontend: @@ -201,7 +201,7 @@ ENDCLASS. The code snippets above aren't ABAP Cloud compatible. To make them cloud-compatible, replace the code in the `lcl_help` class with functions from the `XCO_CP_XLSX` APIs. ::: -#### abap2xlsx +## abap2xlsx Instead of the XLSX API above (which can change between releases), consider the open-source project [abap2xlsx](https://github.com/abap2xlsx/abap2xlsx). It offers reusable APIs for common XLSX operations and runs entirely within the ABAP stack. The example below uses abap2xlsx in the `lcl_help` class: ::: code-group @@ -297,5 +297,5 @@ ENDCLASS. ``` ::: -#### UI5 Control +## UI5 Control To export data directly on the frontend, SAP offers the sap.ui.export.Spreadsheet control for exporting table content. With some extra logic, you can use this control with abap2UI5 too. See the [Add-ons](/advanced/addons) page for a complete sample with the custom control. The coding effort may be higher than the file-based approach shown above. diff --git a/docs/cookbook/device_capabilities/upload_download.md b/docs/cookbook/device_capabilities/upload_download.md index 0b41ad92..82b1230e 100644 --- a/docs/cookbook/device_capabilities/upload_download.md +++ b/docs/cookbook/device_capabilities/upload_download.md @@ -8,7 +8,7 @@ samples: abap2UI5 handles file uploads and downloads by sending base64-encoded data over the binding. -#### Upload +### Upload ```abap CLASS z2ui5_cl_sample_upload DEFINITION PUBLIC. @@ -47,7 +47,7 @@ CLASS z2ui5_cl_sample_upload IMPLEMENTATION. ENDCLASS. ``` -#### Download +### Download See also `Z2UI5_CL_SMP_APP_186`: ```abap METHOD z2ui5_if_app~main. diff --git a/docs/cookbook/eml_cds_sql/abap_sql.md b/docs/cookbook/eml_cds_sql/abap_sql.md index da19649e..c5dc85a3 100644 --- a/docs/cookbook/eml_cds_sql/abap_sql.md +++ b/docs/cookbook/eml_cds_sql/abap_sql.md @@ -5,7 +5,7 @@ outline: [2, 4] ABAP SQL is the standard way to read and change data in the database directly from ABAP. In an abap2UI5 controller you can issue `SELECT`, `INSERT`, `UPDATE`, `DELETE`, and `MODIFY` statements the same way as in any ABAP program, and bind the result straight to a UI5 view. -### Read Data +## Read Data The example below selects flights from the `sflight` table and shows them in a UI5 table: ```abap @@ -78,7 +78,7 @@ CLASS z2ui5_cl_sample_sql IMPLEMENTATION. ENDCLASS. ``` -### Filter with a Search Field +## Filter with a Search Field Bind the search term with `_bind( )` and re-run the `SELECT` on every `SEARCH` event: ```abap @@ -108,7 +108,7 @@ METHOD load_data. ENDMETHOD. ``` -### Aggregations and Joins +## Aggregations and Joins Aggregations and joins work like in any ABAP report — the result table is then bound to the view: ```abap @@ -121,7 +121,7 @@ SELECT FROM sflight AS f UP TO 20 ROWS. ``` -### Change Data +## Change Data `INSERT`, `UPDATE`, `DELETE`, and `MODIFY` are issued from event handlers — wrap them in a transaction and commit explicitly: ```abap diff --git a/docs/cookbook/eml_cds_sql/cds.md b/docs/cookbook/eml_cds_sql/cds.md index ae729661..bc213aa1 100644 --- a/docs/cookbook/eml_cds_sql/cds.md +++ b/docs/cookbook/eml_cds_sql/cds.md @@ -5,7 +5,7 @@ outline: [2, 4] All examples in these docs work without CDS. On a recent ABAP release, you can also read data through CDS views in your abap2UI5 apps. -### ABAP CDS +## ABAP CDS ABAP Core Data Services (CDS) let you define structured views and read data straight from the database. The example below fetches sales orders from the `I_SalesOrder` view of the Virtual Data Model (VDM) and shows them in a UI5 table: ```abap CLASS z2ui5_cl_sample_cds DEFINITION PUBLIC. diff --git a/docs/cookbook/eml_cds_sql/draft_handling.md b/docs/cookbook/eml_cds_sql/draft_handling.md index 1f03fab3..fdd72b80 100644 --- a/docs/cookbook/eml_cds_sql/draft_handling.md +++ b/docs/cookbook/eml_cds_sql/draft_handling.md @@ -62,7 +62,7 @@ record │ (user edits) │ Everything on this page is built from just four EML operations. If you come from RAP, you will recognize them immediately — they are the standard draft actions every draft-enabled BO ships with. Read these once — the full app below is simply these four, wired to buttons. -#### 1. Open a Draft — `Edit` +### 1. Open a Draft — `Edit` Open (acquire) a draft for an existing active record. This takes the lock: ```abap MODIFY ENTITIES OF i_banktp @@ -76,7 +76,7 @@ MODIFY ENTITIES OF i_banktp COMMIT ENTITIES. ``` -#### 2. Read a Draft — `%is_draft = on` +### 2. Read a Draft — `%is_draft = on` Read the **draft** values (what the user is working on) instead of the active record. The only difference from a normal read is the `%is_draft` flag: ```abap READ ENTITIES OF i_banktp @@ -88,7 +88,7 @@ READ ENTITIES OF i_banktp RESULT DATA(drafts). ``` -#### 3. Activate a Draft — `Activate` +### 3. Activate a Draft — `Activate` Promote the draft to the active state. **This is the actual save** — the database row is updated: ```abap MODIFY ENTITIES OF i_banktp @@ -102,7 +102,7 @@ MODIFY ENTITIES OF i_banktp COMMIT ENTITIES. ``` -#### 4. Discard a Draft — `Discard` +### 4. Discard a Draft — `Discard` Throw the draft away and release the lock. The active record is untouched: ```abap MODIFY ENTITIES OF i_banktp @@ -255,7 +255,7 @@ The rest of this page builds that app step by step. It uses two modes: Toggling between the modes drives the entire draft lifecycle (acquire, resume, save, activate, discard). -#### 1. App Startup — Always Begin in View Mode +### 1. App Startup — Always Begin in View Mode On `on_init` the app reads the **active** record and renders it read-only. No draft is touched yet, so other users can still edit the same record. ```abap METHOD on_init. @@ -282,7 +282,7 @@ ENDMETHOD. ``` `%is_draft = if_abap_behv=>mk-off` makes the read return the **active** row, not any open draft. -#### 2. Entering Edit Mode — Check for an Existing Draft +### 2. Entering Edit Mode — Check for an Existing Draft When the user clicks **Switch to Edit Mode**, the app first looks in the BO's draft-shadow table (here `cabnk_bank_d`) joined with `sdraft_admin` to find out whether a draft already exists for this key — and who owns it. (Simplified here; the full snippet at the end of the page additionally reads the draft's timestamp.) ```abap METHOD check_existing_draft. @@ -329,7 +329,7 @@ Three branches: The shadow-table name (`cabnk_bank_d`) is BO-specific. To find it for your own BO, check the `draft table` keyword in its behavior definition. ::: -#### 3. Acquiring a Fresh Draft +### 3. Acquiring a Fresh Draft A new draft is created by the `Edit` action. `%param-preserve_changes = abap_true` tells RAP to keep any existing draft instead of overwriting it — defensive even though we already checked. ```abap METHOD draft_acquire. @@ -355,7 +355,7 @@ ENDMETHOD. ``` After a successful `Edit`, the lock is held by the RAP framework and a row exists in the draft-shadow table. `draft_open = abap_true` switches the view's inputs from read-only to editable. -#### 4. Resuming an Existing Draft +### 4. Resuming an Existing Draft If the user picks **Resume Draft**, the `Resume` action re-takes the lock on the existing draft without overwriting its contents. ```abap METHOD draft_resume. @@ -373,7 +373,7 @@ METHOD draft_resume. ENDMETHOD. ``` -#### 5. Reading the Draft into the App's Fields +### 5. Reading the Draft into the App's Fields Once a draft is open, read it with `%is_draft = if_abap_behv=>mk-on` so the inputs bind to draft values rather than the active record. ```abap METHOD draft_read. @@ -394,7 +394,7 @@ METHOD draft_read. ENDMETHOD. ``` -#### 6. Saving Typed Values Back to the Draft +### 6. Saving Typed Values Back to the Draft The fields are bound (`client->_bind( … )`), so user input lives in ABAP variables on the next roundtrip. To persist them in the draft, push them back with `UPDATE FIELDS`. ```abap METHOD save_current_to_draft. @@ -418,7 +418,7 @@ ENDMETHOD. ``` This helper is called before **Activate** and before exiting edit mode with **Keep Draft**, so nothing the user typed is silently dropped. -#### 7. Exiting Edit Mode — Compare Draft vs Active +### 7. Exiting Edit Mode — Compare Draft vs Active Switching back to VIEW asks: did the user actually change anything? If not, just discard the draft silently. If yes, show a popup so the user explicitly chooses Keep or Discard. ```abap METHOD has_changes_vs_active. @@ -439,7 +439,7 @@ ENDMETHOD. ``` `on_event_edit_toggle` uses this to decide between a silent discard and the **Keep Draft / Discard Draft** popup. Picking **Keep Draft** runs `save_current_to_draft( )` and leaves the draft on the server for later. Picking **Discard Draft** executes the `Discard` action, releasing the lock and reverting the inputs to the active record. -#### 8. Activating — Promote the Draft to Active +### 8. Activating — Promote the Draft to Active Activation is two steps: first save the currently typed values into the draft, then run the `Activate` action. On success the database row is updated and the app returns to VIEW mode. ```abap METHOD on_event_activate. @@ -469,7 +469,7 @@ METHOD on_event_activate. ENDMETHOD. ``` -#### 9. The Event Map and the View +### 9. The Event Map and the View The dispatcher in `z2ui5_if_app~main` wires UI events to the methods above: ```abap IF client->check_on_init( ) OR client->check_on_navigated( ). @@ -490,7 +490,7 @@ ENDIF. ``` The view itself is a single `simple_form` whose `editable` and per-input `enabled` flags follow `draft_open`. The primary button label and type flip between **Switch to Edit Mode** and **Switch to View Mode** based on `mode`, and **Activate** is only enabled while a draft is open. -#### Full Snippet +### Full Snippet ::: details Full working example — `z2ui5_cl_sample_draft` ```abap diff --git a/docs/cookbook/eml_cds_sql/eml.md b/docs/cookbook/eml_cds_sql/eml.md index bde53aba..2f3345ab 100644 --- a/docs/cookbook/eml_cds_sql/eml.md +++ b/docs/cookbook/eml_cds_sql/eml.md @@ -5,10 +5,10 @@ outline: [2, 4] All examples in these docs work without EML. But on a recent ABAP release, you can also use this feature in abap2UI5 apps. -### EML +## EML The Entity Manipulation Language simplifies work with RAP business objects by giving a consistent way to read, create, update, and delete entities. -#### Read +### Read Use `READ ENTITIES` to fetch sales orders and show them in a UI5 table: ```abap CLASS z2ui5_cl_sample_eml_read DEFINITION PUBLIC. @@ -73,7 +73,7 @@ CLASS z2ui5_cl_sample_eml_read IMPLEMENTATION. ENDCLASS. ``` -#### Modify +### Modify The example below creates a sales order with `MODIFY` inside an abap2UI5 app: ```abap @@ -110,7 +110,7 @@ Key Points: - EML calls in abap2UI5 apps run outside the RAP framework, so explicit transaction commits (COMMIT ENTITIES) are needed. - Restrictions inside the RAP framework, like disallowing direct calls to posting function modules or explicit commits, don't apply to abap2UI5 EML operations. You get more flexibility when handling commits and other actions. -### Failure Handling +## Failure Handling EML statements (`MODIFY ENTITIES`, `READ ENTITIES`, `COMMIT ENTITIES`) report problems through the `FAILED` and `REPORTED` structures rather than by raising exceptions. They can also raise classic ABAP exceptions for infrastructure-level failures. diff --git a/docs/cookbook/eml_cds_sql/fuzzy_search.md b/docs/cookbook/eml_cds_sql/fuzzy_search.md index ef65b2ae..507be7ff 100644 --- a/docs/cookbook/eml_cds_sql/fuzzy_search.md +++ b/docs/cookbook/eml_cds_sql/fuzzy_search.md @@ -7,7 +7,7 @@ On SAP HANA you can match strings tolerantly — typos, missing letters, transpo Wire it to a UI5 `search_field` in the table toolbar and you get an ALV-style search that forgives the user's typing. -#### Minimal Example +## Minimal Example ```abap CLASS z2ui5_cl_sample_fuzzy DEFINITION PUBLIC. @@ -119,7 +119,7 @@ ENDCLASS. Typing `Muller` matches `Müller`, `Hambrug` matches `Hamburg` — the lower the threshold, the more lenient (and the noisier) the result. -#### Tuning the Threshold +## Tuning the Threshold | Threshold | Behaviour | | --------- | ------------------------------------------------------ | @@ -129,7 +129,7 @@ Typing `Muller` matches `Müller`, `Hambrug` matches `Hamburg` — the lower the | `0.7` | Lenient — short words start matching unrelated rows | | `< 0.7` | Mostly noise on real data | -#### Multiple Columns +## Multiple Columns Pass a list of columns to search several fields at once — HANA returns the best score across them: @@ -137,7 +137,7 @@ Pass a list of columns to search several fields at once — HANA returns the bes WHERE contains( ( name1, ort01, stras ), @mv_search, 'FUZZY(0.8)' ) = 1 ``` -#### Returning the Score +## Returning the Score To order rows by relevance, expose the fuzzy score with `SCORE( )` and sort on it: diff --git a/docs/cookbook/eml_cds_sql/rap.md b/docs/cookbook/eml_cds_sql/rap.md index 496b1095..4d6a58f4 100644 --- a/docs/cookbook/eml_cds_sql/rap.md +++ b/docs/cookbook/eml_cds_sql/rap.md @@ -5,7 +5,7 @@ outline: [2, 4] abap2UI5 is OData/RAP-agnostic — it doesn't care where data lives. You keep all your RAP logic (validations, determinations, actions, draft tables); only the UI layer is different — instead of a Fiori Elements frontend, you build the view in ABAP. -### RAP is a Programming Model — abap2UI5 is Not +## RAP is a Programming Model — abap2UI5 is Not **RAP (RESTful Application Programming Model)** is a full-stack programming model. It prescribes how you design, expose, and consume business objects: you define entities with CDS views, declare their behavior in Behavior Definitions (BDEFs), implement handlers in Behavior Implementation classes, and expose everything as an OData V4 service consumed by a Fiori Elements frontend. Every layer is part of the model. @@ -13,7 +13,7 @@ abap2UI5 is OData/RAP-agnostic — it doesn't care where data lives. You keep al This distinction matters: RAP defines the architecture *around* your application. abap2UI5 only defines how the UI is built *inside* your ABAP class. -### abap2UI5 is Agnostic +## abap2UI5 is Agnostic Because abap2UI5 imposes no access layer, you pick whatever fits: @@ -28,7 +28,7 @@ Because abap2UI5 imposes no access layer, you pick whatever fits: Nothing is excluded. The abap2UI5 controller is a plain ABAP class — any statement that is valid in ABAP is valid there. -### Using RAP Functionality from Outside +## Using RAP Functionality from Outside When you call EML from inside the RAP framework (e.g., from a Behavior Implementation), the framework enforces its own rules: no explicit `COMMIT WORK`, no direct database modifications, controlled side effects. diff --git a/docs/cookbook/event_navigation/exception.md b/docs/cookbook/event_navigation/exception.md index c4eeefa0..affab964 100644 --- a/docs/cookbook/event_navigation/exception.md +++ b/docs/cookbook/event_navigation/exception.md @@ -8,7 +8,7 @@ samples: Beyond plain messages, abap2UI5 ships dedicated popups and fallbacks for handling exceptions and unexpected failures. -#### Error Popup +### Error Popup To display full details of your exception: ```abap METHOD z2ui5_if_app~main. @@ -22,7 +22,7 @@ METHOD z2ui5_if_app~main. ENDMETHOD. ``` -#### Uncaught Errors +### Uncaught Errors When your code doesn't catch exceptions, the framework catches them and displays the standard error popup. Try this: ```abap @@ -33,7 +33,7 @@ METHOD z2ui5_if_app~main. ENDMETHOD. ``` -#### Uncatchable Exceptions / Short Dumps +### Uncatchable Exceptions / Short Dumps What happens if your code raises uncatchable exceptions? The backend dumps, and the frontend shows its unified **fatal-error overlay**: a dialog that extracts and displays the server's error details, with a **Details** view, a **Copy** button for the error text and **Refresh / Logout** actions to restart. Processing halts until the user restarts the app from that dialog. Reserve this for unexpected cases: ```abap diff --git a/docs/cookbook/expert_more/email.md b/docs/cookbook/expert_more/email.md index 9648e17e..1e6ccb3b 100644 --- a/docs/cookbook/expert_more/email.md +++ b/docs/cookbook/expert_more/email.md @@ -5,7 +5,7 @@ outline: [2, 4] abap2UI5 has no e-mail control of its own — sending mail is plain ABAP via `cl_bcs_message` (or `cl_bcs` on older releases). The UI part is a normal event handler that gathers the form fields and calls the BCS API. -#### Plain Text Mail +## Plain Text Mail ```abap CLASS z2ui5_cl_sample_email DEFINITION PUBLIC. @@ -75,7 +75,7 @@ CLASS z2ui5_cl_sample_email IMPLEMENTATION. ENDCLASS. ``` -#### Attachment +## Attachment Reuse the [file upload](../device_capabilities/upload_download.md) flow to capture an attachment as base64, then hand it to `cl_bcs_message`: @@ -92,6 +92,6 @@ lo_mail->add_attachment( SAPconnect (`SCOT`) must be configured for the mail to actually leave the system. If you do not see anything in `SOST`, that is where to look first. ::: -#### Compatibility +## Compatibility `cl_bcs_message` is the modern API. On older releases or in ABAP Cloud check what is released for your platform — the structure of the example stays the same, only the API class changes. diff --git a/docs/cookbook/expert_more/follow_up_action.md b/docs/cookbook/expert_more/follow_up_action.md index bfb858d6..e632656f 100644 --- a/docs/cookbook/expert_more/follow_up_action.md +++ b/docs/cookbook/expert_more/follow_up_action.md @@ -114,7 +114,7 @@ call without the indirection. If the global is missing the frontend logs `Z2UI5: 'z2ui5.myFunction' is not a function` rather than failing silently. ::: -#### Why It Is a Security Risk +### Why It Is a Security Risk Custom JS works by sending a JavaScript string from the ABAP backend to the frontend, where it is injected into the DOM as an HTML `