From 86caa6c6b0523942528137017d8e243d315f6191 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 24 Sep 2026 01:10:31 +0000 Subject: [PATCH] Release notes for 1.144.1, and the version the site names moves with it abap2UI5's changelog gate was red: 1.144.1 (2026-09-22) is in its changelog.txt and was missing here. The entry is written from the release itself (1.144.0..1.144.1): the hash_* / app_state_* families, check_queue_last / check_no_busy, a( t = ), message_box_display for any data, and the removals of #2746, #2748, #2752 and #2776. check:version moves with it - the bar's menu, the deprecations page's version sentence and the changelog heading. The twelve deprecation rows whose removal shipped in 1.144.1 say so instead of "next release"; the four of abap2UI5#2777 (the z2ui5 global and what hung on it) came after the tag and keep it. Two pre-existing reds against main go too: the API reference is regenerated (npm run generate:api), and the soft-keyboard page no longer names the removed constant, it links the deprecations page instead. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AMe1Asm5u394A6bEi2ZdK4 --- docs/.vitepress/theme/SiteMenu.vue | 2 +- .../browser_interaction/soft_keyboard.md | 12 ++-- docs/public/api/client-api.json | 60 +++++++------------ docs/resources/api.md | 27 +++------ docs/resources/changelog.md | 29 +++++++++ docs/resources/deprecations.md | 28 ++++----- 6 files changed, 82 insertions(+), 76 deletions(-) diff --git a/docs/.vitepress/theme/SiteMenu.vue b/docs/.vitepress/theme/SiteMenu.vue index 688aa9730..99780c2ec 100644 --- a/docs/.vitepress/theme/SiteMenu.vue +++ b/docs/.vitepress/theme/SiteMenu.vue @@ -24,7 +24,7 @@ const { isDark } = useData(); * four entries under it were already in this menu, so what was left of that * dropdown was the NUMBER, and this is where it went. Moving it means moving * the pattern in release.mjs with it. */ -const VERSION = "1.144.0"; +const VERSION = "1.144.1"; const extra = ref(null); diff --git a/docs/cookbook/browser_interaction/soft_keyboard.md b/docs/cookbook/browser_interaction/soft_keyboard.md index 2d099b479..5d9f206c6 100644 --- a/docs/cookbook/browser_interaction/soft_keyboard.md +++ b/docs/cookbook/browser_interaction/soft_keyboard.md @@ -71,12 +71,12 @@ keyboard just comes back. *is*. That is also why the mode survives a roundtrip without the app restoring anything. -::: warning cs_event-keyboard_set_mode is removed -Before 2026-09 this page taught a frontend action, -`client->follow_up_action( val = client->cs_event-keyboard_set_mode … )`, which -set the attribute directly on the DOM. It carried exactly the defect above and -**was removed from the framework**; an app that still calls it fails at compile -time. The migration is the control on this page: declare +::: warning The keyboard-mode frontend action is removed +Before 2026-09 this page taught a frontend action that set the attribute +directly on the DOM. It carried exactly the defect above and **was removed from +the framework in 1.144.1** (see [Deprecations](/resources/deprecations)); an +app that still calls it fails at compile time. The migration is the control on +this page: declare `xmlns:z2ui5="z2ui5.cc"`, build the field as `z2ui5:InputExt`, bind `inputMode` to a string attribute, and delete the action. ::: diff --git a/docs/public/api/client-api.json b/docs/public/api/client-api.json index cb445d4f9..2594f0282 100644 --- a/docs/public/api/client-api.json +++ b/docs/public/api/client-api.json @@ -447,7 +447,7 @@ "name": "t_arg", "type": "string_table", "optional": true, - "doc": "arguments sent with the event and read back with get_event_arg( n ) in the same order: a literal, a `${$source>/...}` or `${$parameters>/...}` client expression evaluated when the event fires, or `$event>...` for a field of the UI5 event itself." + "doc": "arguments sent with the event and read back with get_event_arg( n ) in the same order: a literal, a `${$source>/...}` or `${$parameters>/...}` client expression evaluated when the event fires, or `$event>...` for a field of the UI5 event itself. Two controller helpers reach what no binding path can, because a `${...}` addresses DATA and these address the live control tree: `$controller.textPath( ${$parameters>/item} )` - the ancestor-text breadcrumb of the control that fired; and `$controller.slotValue( 'POPUP', 'myId', 'getValue' )` - what a control in ANOTHER view slot currently holds. An id is local to the view or fragment it was written in, so a control in a dialog is not reachable otherwise; the slot keys are those of cs_view, and an empty one searches every open slot. The getter takes no arguments on purpose - to CALL a control use cs_event-control_by_id, which has a whitelist in front of it. Every miss (slot closed, id unknown, no such method, a getter that raises) is logged and sent as the empty string: an argument expression is evaluated while UI5 dispatches the handler, so one that throws loses the whole EVENT. `$controller.slotById( 'POPUP', 'myId' )` hands the control itself over for a null-tolerant reader such as textPath( ) - it answers null on a miss, which a method call on it would then throw over." }, { "name": "s_ctrl", @@ -542,8 +542,9 @@ "name": "follow_up_action", "group": "Events and frontend actions", "doc": [ - "Schedule a frontend action to run after the backend response has been processed. Two ways to call it: pass a frontend event as val (a cs_event-* constant, e.g. cs_event-set_title) with its arguments in t_arg and the framework builds the event call; or pass a raw JavaScript expression as val, without t_arg, to run it as it is. The families below take structured arguments; t_arg is POSITIONAL, and an empty argument between filled ones keeps its slot as ``.", - "Every one of them also works roundtrip-free when WIRED IN THE VIEW: write the same call where its result is consumed - `)->a( n = `press` v = client->follow_up_action( val = ... t_arg = ... ) )` - and the action runs in the browser without a server call.", + "Schedule a frontend action to run after the backend response has been processed: pass a frontend event as val (a cs_event-* constant, e.g. cs_event-set_title) with its arguments in t_arg, and the framework builds the event call as pure data. The families below take structured arguments; t_arg is POSITIONAL, and an empty argument between filled ones keeps its slot as ``.", + "A raw JavaScript expression as val (e.g. `sap.m.MessageToast.show('x')`) is not run - that form was removed. Its cs_event-* equivalents: control_global for the UI5 globals (MessageToast, MessageBox, BusyIndicator), control_by_id for a control method and hash_back for history.back( ). Frontend code of the app's own ships as a custom control in the customer frontend BSP (z2ui5_ccc).", + "Every cs_event-* action also works roundtrip-free when WIRED IN THE VIEW: write the same call where its result is consumed - `)->a( n = `press` v = client->follow_up_action( val = ... t_arg = ... ) )` - and the action runs in the browser without a server call.", "**cs_event-control_by_id** - call a method on a control resolved by id, t_arg = id, method, params: ``client->follow_up_action( val = client->cs_event-control_by_id t_arg = VALUE #( ( `tab` ) ( `setSelectedIndex` ) ( `0` ) ) )``. Any public control method works unless it is on the frontend denylist (methods that would break framework invariants). The named per-aggregation mutators are on the allowed side of that line - addItem, removeItem, removeAllItems, destroyContent - and only the GENERIC reflection variants that take the member name as an argument are denied (addAggregation, removeAllAggregation, setAssociation, ...). The view is passed as the separate view parameter (default cs_view-main resolves the id across all open views; pass cs_view-popup/popover/... to scope the lookup to that view). Two entries are NOT UI5 methods but frontend capabilities in method form: `css` sets ONE whitelisted CSS declaration on the control's own DOM node (t_arg = id, `css`, property, value) - for a value the control has no property for at all, e.g. the width of a sap.m.Page; prefer a bound property wherever one exists. `toggleBy` opens/closes a popup anchored to a control (t_arg = id, `toggleBy`, anchor id). An association setter (setSelectedSection, setSelectedItem) clears the association when its argument is EMPTY. Wherever an argument takes a CONTROL ID, it also takes an aggregation ITEM, addressed positionally as `//` (`carousel/pages/2`, 0-based). A control cloned from an aggregation template has no id the backend can spell - UI5 mints it from the template id, the parent id and the index, and the parent id carries the view prefix assigned at runtime - so this is the only way to reach one. It is the equivalent of the UI5 controller idiom `oCarousel.setActivePage( oCarousel.getPages()[ i ] )`. A plain id (no slashes) resolves exactly as before.", "**cs_event-control_global** - call a whitelisted method on a global object (MESSAGE_TOAST, MESSAGE_BOX, BUSY_INDICATOR, THEMING, POPUP, INVISIBLE_MESSAGE, FORMATTING, ICON_POOL), t_arg = object, method, params: ``client->follow_up_action( val = client->cs_event-control_global t_arg = VALUE #( ( `BUSY_INDICATOR` ) ( `show` ) ( `0` ) ) )``. POPUP-setWithinArea confines every popup to the control whose id is passed (sap.ui.core.Popup.setWithinArea, needs UI5 >= 1.89) instead of to the window; an EMPTY argument releases the restriction again. INVISIBLE_MESSAGE-announce reads a text out to a screen reader without rendering it (sap.ui.core.InvisibleMessage, needs UI5 >= 1.78): t_arg = text, mode (Polite, default, or Assertive). It is a singleton, so there is no control id - this is the only way to announce a change the backend made. FORMATTING-setCustomCurrencies registers currency codes the standard sap.ui.model.type.Currency does not know, or overrides their digit count (sap/base/i18n/Formatting, needs UI5 >= 1.120): t_arg = JSON object, e.g. {\"BGN4\":{\"digits\":4}}. It REPLACES the whole registration - addCustomCurrencies MERGES codes into it instead (t_arg = the same map). Reaching for the wrong one is silent: an app that registers currencies as it loads more data and calls setCustomCurrencies drops what it registered before, and the symptom is a wrong digit count in a table, never an error. What this reaches is the FORMATTING configuration, not a control that has already formatted: a control caching its NumberFormat at init( ) - among them sap.ui.unified.Currency - keeps the digit count it was built with, because it implements no localization-change hook. A BOUND sap.ui.model.type.Currency does implement one and re-formats. ICON_POOL-registerFont makes an icon collection outside the default SAP-icons font resolvable - sap.tnt's SAP-icons-TNT is the common one: t_arg = fontFamily, fontURI, e.g. `SAP-icons-TNT` / `sap/tnt/themes/base/fonts/`. A normal UI5 app does this in its Component's init; an abap2UI5 app has no Component of its own, and IconPool is a module SINGLETON rather than a control, so no other wire reaches it. Without the registration a sap-icon://SAP-icons-TNT/... URI renders NO GLYPH and logs nothing. The fontURI is a module path in every real use and is resolved through sap.ui.require.toUrl, so the registration survives a different mount point; an absolute URL is passed through. Issue it from the init branch - the same collection is registered only once per session, so a repeat call costs nothing.", "**cs_event-smart_variant_init** - run the initialise( ) handshake sap.ui.comp variant management needs (a controller would call oSmartVariantManagement.initialise( fnCallback, oPersonalizableControl )), t_arg = SmartVariantManagement id, personalizable control id (optional, default: the first control that registered itself): ``client->follow_up_action( val = client->cs_event-smart_variant_init t_arg = VALUE #( ( `pageVariant` ) ) )``. Without it the control keeps no personalizable control, saving a view fails inside sap.ui.fl and stored variants are never loaded. The action waits for that registration, which the smart controls do once their OData metadata has loaded.", @@ -558,7 +559,7 @@ { "name": "val", "type": "string", - "doc": "the frontend event - a cs_event-* constant - or a raw JavaScript expression when t_arg is not supplied." + "doc": "the frontend event - a cs_event-* constant." }, { "name": "view", @@ -635,9 +636,7 @@ "constants": [ { "name": "cs_device", - "doc": [ - "The values get( )-s_device carries, as constants to compare against: what system, browser, os and orientation say about the client, e.g. `IF client->get( )-s_device-system = client->cs_device-system-phone.`" - ], + "doc": [], "members": [ { "name": "system", @@ -742,9 +741,7 @@ }, { "name": "cs_event", - "doc": [ - "Every frontend event a wire or follow_up_action( ) can name: what the browser does when the response arrives (set_title, scroll_to, download_b64_file, clipboard_copy, ...) or when the wired control fires (the control_by_id / control_global / binding_call family), the smart-control handshakes, the hash family, and - at the end - obsolete spellings kept so old apps compile. follow_up_action( ) documents the families that take structured arguments; the rest take the argument their name suggests, one sample each in the cookbook." - ], + "doc": [], "members": [ { "name": "popup_close", @@ -757,24 +754,24 @@ "value": "POPOVER_CLOSE" }, { - "name": "set_size_limit", + "name": "cross_app_nav_to_ext", "type": "string", - "value": "SET_SIZE_LIMIT" + "value": "CROSS_APP_NAV_TO_EXT" }, { - "name": "set_odata_model", + "name": "cross_app_nav_to_prev_app", "type": "string", - "value": "SET_ODATA_MODEL" + "value": "CROSS_APP_NAV_TO_PREV_APP" }, { - "name": "cross_app_nav_to_ext", + "name": "set_size_limit", "type": "string", - "value": "CROSS_APP_NAV_TO_EXT" + "value": "SET_SIZE_LIMIT" }, { - "name": "cross_app_nav_to_prev_app", + "name": "set_odata_model", "type": "string", - "value": "CROSS_APP_NAV_TO_PREV_APP" + "value": "SET_ODATA_MODEL" }, { "name": "clipboard_copy", @@ -786,6 +783,11 @@ "type": "string", "value": "SET_TITLE" }, + { + "name": "set_title_launchpad", + "type": "string", + "value": "SET_TITLE_LAUNCHPAD" + }, { "name": "set_favicon", "type": "string", @@ -816,11 +818,6 @@ "type": "string", "value": "SYSTEM_LOGOUT" }, - { - "name": "keyboard_set_mode", - "type": "string", - "value": "KEYBOARD_SET_MODE" - }, { "name": "keyboard_shortcut", "type": "string", @@ -836,11 +833,6 @@ "type": "string", "value": "LOCATION_RELOAD" }, - { - "name": "set_title_launchpad", - "type": "string", - "value": "SET_TITLE_LAUNCHPAD" - }, { "name": "download_b64_file", "type": "string", @@ -935,9 +927,7 @@ }, { "name": "cs_view", - "doc": [ - "The five slots the frontend renders into: the main view, the two nested views, the popup and the popover. The `view` parameter of follow_up_action( ) and _event_client( ) names the slot a control id is resolved in, and a keyboard shortcut can be scoped to one." - ], + "doc": [], "members": [ { "name": "main", @@ -993,9 +983,7 @@ "types": [ { "name": "ty_s_name_value", - "doc": [ - "A name-value pair, both strings - the shape of a launchpad startup parameter in get( )-t_comp_params (n = the parameter name the tile passed, v = its first value)." - ], + "doc": [], "members": [ { "name": "n", @@ -1009,9 +997,7 @@ }, { "name": "ty_t_name_value", - "doc": [ - "The table of name-value pairs get( )-t_comp_params carries." - ], + "doc": [], "definition": "STANDARD TABLE OF ty_s_name_value WITH EMPTY KEY" }, { diff --git a/docs/resources/api.md b/docs/resources/api.md index ada5dfd98..1e45205e9 100644 --- a/docs/resources/api.md +++ b/docs/resources/api.md @@ -179,7 +179,7 @@ Register a backend event and return the handler expression for a view attribute | Parameter | Type | Default | Description | |---|---|---|---| | `val` | `clike` | *optional* | the event name the handler checks with check_on_event( `SAVE` ) - upper case by convention, unique within the app. | -| `t_arg` | `string_table` | *optional* | arguments sent with the event and read back with get_event_arg( n ) in the same order: a literal, a `${$source>/...}` or `${$parameters>/...}` client expression evaluated when the event fires, or `$event>...` for a field of the UI5 event itself. | +| `t_arg` | `string_table` | *optional* | arguments sent with the event and read back with get_event_arg( n ) in the same order: a literal, a `${$source>/...}` or `${$parameters>/...}` client expression evaluated when the event fires, or `$event>...` for a field of the UI5 event itself. Two controller helpers reach what no binding path can, because a `${...}` addresses DATA and these address the live control tree: `$controller.textPath( ${$parameters>/item} )` - the ancestor-text breadcrumb of the control that fired; and `$controller.slotValue( 'POPUP', 'myId', 'getValue' )` - what a control in ANOTHER view slot currently holds. An id is local to the view or fragment it was written in, so a control in a dialog is not reachable otherwise; the slot keys are those of cs_view, and an empty one searches every open slot. The getter takes no arguments on purpose - to CALL a control use cs_event-control_by_id, which has a whitelist in front of it. Every miss (slot closed, id unknown, no such method, a getter that raises) is logged and sent as the empty string: an argument expression is evaluated while UI5 dispatches the handler, so one that throws loses the whole EVENT. `$controller.slotById( 'POPUP', 'myId' )` hands the control itself over for a null-tolerant reader such as textPath( ) - it answers null on a miss, which a method call on it would then throw over. | | `s_ctrl` | `ty_s_event_control` | *optional* | the per-wire options (ty_s_event_control): keep the last firing until the running roundtrip has landed, cancel the control's default, quote every argument as a literal, leave the global busy indicator down. | | `arg` | `clike` | *optional* | the ONE-VALUE spelling of t_arg: `arg = x` is exactly `t_arg = VALUE #( ( x ) )`, byte for byte, and the handler reads it back with the same `get_event_arg( )`. It exists because the single argument is what most wires carry - a row key, a `${$source>/...}`, one event parameter - and there the table constructor is longer than the value inside it. From two values on, t_arg is the right parameter and stays it; arg deliberately does not grow into arg2/arg3, which would only put the positional numbering the table already spells out back into the parameter names. Passing both APPENDS arg behind the t_arg rows - a defined composition, not a guess between two readings. An argument that starts with `$` or `{` (or an .eB( expression) is written RAW, as live UI5 expression syntax - that is how `${$source>/KEY}` reaches the handler as the row's value. Data that may start with those characters (text a user typed, a key from a foreign system) is therefore evaluated, not passed: set s_ctrl-check_arg_literal to have every argument of the wire quoted as a string instead. | @@ -189,9 +189,11 @@ Returns `string`. ### `follow_up_action` -Schedule a frontend action to run after the backend response has been processed. Two ways to call it: pass a frontend event as val (a cs_event-* constant, e.g. cs_event-set_title) with its arguments in t_arg and the framework builds the event call; or pass a raw JavaScript expression as val, without t_arg, to run it as it is. The families below take structured arguments; t_arg is POSITIONAL, and an empty argument between filled ones keeps its slot as ``. +Schedule a frontend action to run after the backend response has been processed: pass a frontend event as val (a cs_event-* constant, e.g. cs_event-set_title) with its arguments in t_arg, and the framework builds the event call as pure data. The families below take structured arguments; t_arg is POSITIONAL, and an empty argument between filled ones keeps its slot as ``. -Every one of them also works roundtrip-free when WIRED IN THE VIEW: write the same call where its result is consumed - `)->a( n = `press` v = client->follow_up_action( val = ... t_arg = ... ) )` - and the action runs in the browser without a server call. +A raw JavaScript expression as val (e.g. `sap.m.MessageToast.show('x')`) is not run - that form was removed. Its cs_event-* equivalents: control_global for the UI5 globals (MessageToast, MessageBox, BusyIndicator), control_by_id for a control method and hash_back for history.back( ). Frontend code of the app's own ships as a custom control in the customer frontend BSP (z2ui5_ccc). + +Every cs_event-* action also works roundtrip-free when WIRED IN THE VIEW: write the same call where its result is consumed - `)->a( n = `press` v = client->follow_up_action( val = ... t_arg = ... ) )` - and the action runs in the browser without a server call. **cs_event-control_by_id** - call a method on a control resolved by id, t_arg = id, method, params: ``client->follow_up_action( val = client->cs_event-control_by_id t_arg = VALUE #( ( `tab` ) ( `setSelectedIndex` ) ( `0` ) ) )``. Any public control method works unless it is on the frontend denylist (methods that would break framework invariants). The named per-aggregation mutators are on the allowed side of that line - addItem, removeItem, removeAllItems, destroyContent - and only the GENERIC reflection variants that take the member name as an argument are denied (addAggregation, removeAllAggregation, setAssociation, ...). The view is passed as the separate view parameter (default cs_view-main resolves the id across all open views; pass cs_view-popup/popover/... to scope the lookup to that view). Two entries are NOT UI5 methods but frontend capabilities in method form: `css` sets ONE whitelisted CSS declaration on the control's own DOM node (t_arg = id, `css`, property, value) - for a value the control has no property for at all, e.g. the width of a sap.m.Page; prefer a bound property wherever one exists. `toggleBy` opens/closes a popup anchored to a control (t_arg = id, `toggleBy`, anchor id). An association setter (setSelectedSection, setSelectedItem) clears the association when its argument is EMPTY. Wherever an argument takes a CONTROL ID, it also takes an aggregation ITEM, addressed positionally as `//` (`carousel/pages/2`, 0-based). A control cloned from an aggregation template has no id the backend can spell - UI5 mints it from the template id, the parent id and the index, and the parent id carries the view prefix assigned at runtime - so this is the only way to reach one. It is the equivalent of the UI5 controller idiom `oCarousel.setActivePage( oCarousel.getPages()[ i ] )`. A plain id (no slashes) resolves exactly as before. @@ -213,7 +215,7 @@ Every one of them also works roundtrip-free when WIRED IN THE VIEW: write the sa | Parameter | Type | Default | Description | |---|---|---|---| -| `val` | `string` | | the frontend event - a cs_event-* constant - or a raw JavaScript expression when t_arg is not supplied. | +| `val` | `string` | | the frontend event - a cs_event-* constant. | | `view` | `clike` | `cs_view-main` | the view slot the action's control id is resolved in: cs_view-main, the default, searches every open view; cs_view-popup, -popover, -nested, -nested2 scope the lookup to that slot. | | `t_arg` | `string_table` | *optional* | the positional arguments of the event - each family above says what they are; an empty argument between filled ones keeps its slot as ``. | @@ -387,8 +389,6 @@ about the device, `cs_nav_mode` the routing modes. ### `cs_device` -The values get( )-s_device carries, as constants to compare against: what system, browser, os and orientation say about the client, e.g. `IF client->get( )-s_device-system = client->cs_device-system-phone.` - | Constant | Value | |---|---| | `cs_device-system-phone` | `phone` | @@ -409,29 +409,26 @@ The values get( )-s_device carries, as constants to compare against: what system ### `cs_event` -Every frontend event a wire or follow_up_action( ) can name: what the browser does when the response arrives (set_title, scroll_to, download_b64_file, clipboard_copy, ...) or when the wired control fires (the control_by_id / control_global / binding_call family), the smart-control handshakes, the hash family, and - at the end - obsolete spellings kept so old apps compile. follow_up_action( ) documents the families that take structured arguments; the rest take the argument their name suggests, one sample each in the cookbook. - | Constant | Value | | |---|---|---| | `cs_event-popup_close` | `POPUP_CLOSE` | | | `cs_event-popover_close` | `POPOVER_CLOSE` | | -| `cs_event-set_size_limit` | `SET_SIZE_LIMIT` | | -| `cs_event-set_odata_model` | `SET_ODATA_MODEL` | | | `cs_event-cross_app_nav_to_ext` | `CROSS_APP_NAV_TO_EXT` | | | `cs_event-cross_app_nav_to_prev_app` | `CROSS_APP_NAV_TO_PREV_APP` | | +| `cs_event-set_size_limit` | `SET_SIZE_LIMIT` | | +| `cs_event-set_odata_model` | `SET_ODATA_MODEL` | | | `cs_event-clipboard_copy` | `CLIPBOARD_COPY` | | | `cs_event-set_title` | `SET_TITLE` | | +| `cs_event-set_title_launchpad` | `SET_TITLE_LAUNCHPAD` | | | `cs_event-set_favicon` | `SET_FAVICON` | | | `cs_event-set_focus` | `SET_FOCUS` | | | `cs_event-scroll_to` | `SCROLL_TO` | | | `cs_event-scroll_into_view` | `SCROLL_INTO_VIEW` | | | `cs_event-start_timer` | `START_TIMER` | | | `cs_event-system_logout` | `SYSTEM_LOGOUT` | | -| `cs_event-keyboard_set_mode` | `KEYBOARD_SET_MODE` | | | `cs_event-keyboard_shortcut` | `KEYBOARD_SHORTCUT` | | | `cs_event-open_new_tab` | `OPEN_NEW_TAB` | | | `cs_event-location_reload` | `LOCATION_RELOAD` | | -| `cs_event-set_title_launchpad` | `SET_TITLE_LAUNCHPAD` | | | `cs_event-download_b64_file` | `DOWNLOAD_B64_FILE` | | | `cs_event-urlhelper` | `URLHELPER` | | | `cs_event-store_data` | `STORE_DATA` | | @@ -451,8 +448,6 @@ Every frontend event a wire or follow_up_action( ) can name: what the browser do ### `cs_view` -The five slots the frontend renders into: the main view, the two nested views, the popup and the popover. The `view` parameter of follow_up_action( ) and _event_client( ) names the slot a control id is resolved in, and a keyboard shortcut can be scoped to one. - | Constant | Value | |---|---| | `cs_view-main` | `MAIN` | @@ -475,8 +470,6 @@ Hash-based app routing modes, switched on with follow_up_action( cs_event-hash_r ### `ty_s_name_value` -A name-value pair, both strings - the shape of a launchpad startup parameter in get( )-t_comp_params (n = the parameter name the tile passed, v = its first value). - | Field | Type | |---|---| | `n` | `string` | @@ -484,8 +477,6 @@ A name-value pair, both strings - the shape of a launchpad startup parameter in ### `ty_t_name_value` -The table of name-value pairs get( )-t_comp_params carries. - Defined as `STANDARD TABLE OF ty_s_name_value WITH EMPTY KEY`. ### `ty_s_model_skip` diff --git a/docs/resources/changelog.md b/docs/resources/changelog.md index dab4b2bee..817f2a255 100644 --- a/docs/resources/changelog.md +++ b/docs/resources/changelog.md @@ -7,6 +7,35 @@ description: The abap2UI5 release notes - every release with its changes, newest See [Deprecations](/resources/deprecations) for what is superseded but still shipping, and for the full removal list with migration notes. +## 1.144.1 +2026-09-22 +- Added app-owned hash routing: `client->hash_set( )` / `hash_replace( )` write the URL fragment (a pushed or a replaced history entry), `cs_event-hash_back` steps back with an optional fallback hash, `cs_event-hash_attach_changed` raises a backend event on a hash change the app did not make, and `cs_event-hash_routing` sets the routing mode. `app_state_set_active( )` keeps the id of the current app state in the URL, and `app_state_get_href( )` hands that share link to ABAP +- Added `s_ctrl-check_queue_last` on `_event( )`: an event fired while a round-trip is in flight is kept and sent after it, the last one wins — the flag for a live wire such as a search field. `s_ctrl-check_no_busy` keeps the busy overlay down on such a wire, so it no longer flashes over the field being typed into +- Added `a( t = … )` on the view builder: text passed as `t` renders literally, a brace or a backslash in it is shown instead of parsed as a binding. Use it for data and user input in a view attribute; `v` keeps the binding vocabulary +- `message_box_display( )` shows any data, not only messages — a table, a nested structure, a tree, an object, a number — and a box with details shows them open instead of behind a *Show details* link. Messages (BAPIRET2, T100, RAP, exceptions, …) are still recognized first and set severity and title +- `STORE_DATA` reads a model-path payload, so a handler can write browser storage too, not only a view wire +- `CONTROL_BY_ID` resolves the argument of `setCurrentStep` to a control, so a `Wizard` step can be set by id +- A misused view builder chain raises an exception the app can catch, instead of producing a broken view +- Performance: the view builder concatenates once per render, a conditional GET of the shell page is answered before the page is built, the XML templating preprocessor runs only for a view that uses templating, and several things the engine computed on every request are computed once +- The default response headers no longer include `Cross-Origin-Opener-Policy` — on a plain-HTTP system the browser ignored it and logged a console error on every start +- Hosting outside an SAP system: seams for the draft store and the environment, and the transpiled framework ships as the npm package `@abap2ui5/runtime`; every release carries the backend already built (`backend-.tar.gz`) +- The start page no longer loses its second roundtrip, and the OData model is loaded only when an app uses it +- Many smaller fixes from code reviews of the ABAP and the frontend core + +**Removed** +- BREAKING: the `view` parameter of `_bind( )` / `_bind_edit( )` — it had done nothing for a long time; delete it +- BREAKING: `set_push_state( )` / `cs_event-set_push_state`, `set_app_state_active( )` / `cs_event-set_app_state_active` and `cs_event-set_nav_routing` — renamed to `hash_set( )`, `app_state_set_active( )` and `cs_event-hash_routing` above; the wire values are unchanged +- BREAKING: `cs_event-clipboard_app_state` → `app_state_get_href( )` + `cs_event-clipboard_copy` +- BREAKING: `cs_event-wizard_set_next_step` → two `control_by_id` calls +- BREAKING: `cs_event-keyboard_set_mode` → the bound `inputMode` property of `z2ui5.cc.InputExt`, which survives a re-render +- BREAKING: `cs_event-nav_container_to` and its `nest_` / `nest2_` / `popup_` / `popover_` variants → `cs_event-control_by_id` with method `to` +- BREAKING: `cs_event-image_editor_popup_close` +- BREAKING: `_event( s_ctrl-check_allow_multi_req )` → `s_ctrl-check_queue_last` +- BREAKING: the pure UI5 options of `message_toast_display( )` and `message_box_display( )` (width, docking, animation and the like) — set them on the control through `cs_event-control_global` +- BREAKING: the released DDIC structure `Z2UI5_T_02` — name a type your own system has + +See [Deprecations](/resources/deprecations) for the migration of each. + ## 1.144.0 2026-08-30 - Added `client->_event( arg = … )`, the one-value spelling of `t_arg`. `arg = x` is exactly `t_arg = VALUE #( ( x ) )` — the client folds it into the same table, so the wire and `get_event_arg( )` are unchanged — and it exists because most event wires carry a single value (a row key, a `${$source>/…}`, one event parameter), where the table constructor is longer than the value inside it. Passing both appends `arg` behind the `t_arg` rows. From two values on, `t_arg` stays the right parameter: there is deliberately no `arg2`/`arg3` diff --git a/docs/resources/deprecations.md b/docs/resources/deprecations.md index 8ff49fdf2..9b5b49335 100644 --- a/docs/resources/deprecations.md +++ b/docs/resources/deprecations.md @@ -40,7 +40,7 @@ What it cannot decide it leaves alone and reports, so a run is safe to repeat. ## Version status -The released version is **1.144.0**. Entries marked *next release* are already +The released version is **1.144.1**. Entries marked *next release* are already on `main` but not in a release yet — they matter if you pull `main`, and they tell you what is coming if you do not. @@ -50,11 +50,11 @@ tell you what is coming if you do not. | `_event_client( )` | `follow_up_action( )` | 1.143.0 | | `_bind_edit( )` | `_bind( )` | 1.142.0 | | `_bind( custom_mapper = … custom_filter = … )` | `omit_initial` / `omit_initial_paths` / `json`, or shape it in ABAP | 1.143.0 | -| `_bind( view = … )` | omit the parameter | **removed**, *next release* | -| `cs_event-keyboard_set_mode` | the bound `inputMode` property of `z2ui5.cc.InputExt` — see [Soft Keyboard](../cookbook/browser_interaction/soft_keyboard) | **removed**, *next release* | -| `cs_event-nav_container_to` and its `nest_` / `nest2_` / `popup_` / `popover_` variants | `cs_event-control_by_id` with method `to`, the slot as the `view` parameter | **removed**, *next release* | -| the DDIC structure `Z2UI5_T_02` | name a type your own system has | **removed**, *next release* | -| `cs_event-image_editor_popup_close` | `_event( arg = `$controller.slotValue('POPUP','myEditor','getImagePngDataURL')` )` plus the app's own `popup_destroy( )` | **removed**, *next release* | +| `_bind( view = … )` | omit the parameter | **removed**, 1.144.1 | +| `cs_event-keyboard_set_mode` | the bound `inputMode` property of `z2ui5.cc.InputExt` — see [Soft Keyboard](../cookbook/browser_interaction/soft_keyboard) | **removed**, 1.144.1 | +| `cs_event-nav_container_to` and its `nest_` / `nest2_` / `popup_` / `popover_` variants | `cs_event-control_by_id` with method `to`, the slot as the `view` parameter | **removed**, 1.144.1 | +| the DDIC structure `Z2UI5_T_02` | name a type your own system has | **removed**, 1.144.1 | +| `cs_event-image_editor_popup_close` | `_event( arg = `$controller.slotValue('POPUP','myEditor','getImagePngDataURL')` )` plus the app's own `popup_destroy( )` | **removed**, 1.144.1 | | `z2ui5_if_app~check_sticky` / `check_initialized` | `set_session_stateful( )` / `check_on_init( )` | **removed**, 1.143.0 | | `set_nav_back( )` / `set_nav_routing( )` | `follow_up_action( )` | **removed**, 1.143.0 | | `cs_event-nav_to_route` | `nav_app_call( )` | **removed**, 1.143.0 | @@ -62,7 +62,7 @@ tell you what is coming if you do not. | `client->get( )-viewname` | delete the read | **removed**, 1.143.0 | | `Formatter.round2DP` and four siblings | compute it in ABAP | **removed**, 1.143.0 | | `z2ui5_cl_util_api*`, `z2ui5_cl_pop_bal` | `z2ui5_cl_util` / `z2ui5_cl_util_ext` | **removed**, 1.142.0 | -| `cs_event-wizard_set_next_step` | two `control_by_id` calls | **removed**, *next release* | +| `cs_event-wizard_set_next_step` | two `control_by_id` calls | **removed**, 1.144.1 | | `z2ui5_cl_xml_view` | `z2ui5_cl_ui5_view_builder` | 1.143.0 | | built-in popups | the [popups add-on](https://github.com/abap2UI5-addons/popups) | 1.142.0 | | `z2ui5.Util`, `z2ui5.Formatter`, module `z2ui5/Util` | `core:require` of `z2ui5/model/formatter` | **removed**, *next release* | @@ -72,12 +72,12 @@ tell you what is coming if you do not. | `cs_config-title` | `cs_event-set_title` | 1.144.0 | | `z2ui5_if_types=>…` | the same type on the object that uses it | 1.144.0 | | `z2ui5_if_exit` | `z2ui5_if_ui5_exit` | 1.144.0 | -| `set_push_state( )`, `cs_event-set_push_state` | `hash_set( )`, `cs_event-hash_set` | **removed**, *next release* | -| `set_app_state_active( )`, `cs_event-set_app_state_active` | `app_state_set_active( )`, `cs_event-app_state_set_active` | **removed**, *next release* | -| `cs_event-set_nav_routing` | `cs_event-hash_routing` | **removed**, *next release* | -| `cs_event-clipboard_app_state` | `app_state_get_href( )` + `cs_event-clipboard_copy` | **removed**, *next release* | -| `_event( s_ctrl-check_allow_multi_req )` | `s_ctrl-check_queue_last` | **removed**, *next release* | -| the UI5 options of `message_toast_display( )` / `message_box_display( )` | set them on the control, through `cs_event-control_global` | **removed**, *next release* | +| `set_push_state( )`, `cs_event-set_push_state` | `hash_set( )`, `cs_event-hash_set` | **removed**, 1.144.1 | +| `set_app_state_active( )`, `cs_event-set_app_state_active` | `app_state_set_active( )`, `cs_event-app_state_set_active` | **removed**, 1.144.1 | +| `cs_event-set_nav_routing` | `cs_event-hash_routing` | **removed**, 1.144.1 | +| `cs_event-clipboard_app_state` | `app_state_get_href( )` + `cs_event-clipboard_copy` | **removed**, 1.144.1 | +| `_event( s_ctrl-check_allow_multi_req )` | `s_ctrl-check_queue_last` | **removed**, 1.144.1 | +| the UI5 options of `message_toast_display( )` / `message_box_display( )` | set them on the control, through `cs_event-control_global` | **removed**, 1.144.1 | ## Obsolete: still compiles @@ -581,7 +581,7 @@ a raw string does nothing. ### The URL API is `hash_*` and `app_state_*` now - + One naming rule for everything that touches the URL, taken from UI5's own: `nav_*` keeps meaning real navigation between apps, `hash_*` is the URL