diff --git a/SAMPLES.md b/SAMPLES.md index d5bfdfa..517065a 100644 --- a/SAMPLES.md +++ b/SAMPLES.md @@ -3,7 +3,7 @@ # The sample catalogue -Every app in this repository — 45 of them — with what it shows and a +Every app in this repository — 46 of them — with what it shows and a link to its source. This is the [overview app](src/z2ui5_cl_smps_app_000.clas.abap) as a page you can read here, before installing anything. @@ -104,6 +104,7 @@ type who does not know it exists. `Ctrl+F` on this page uses them. | Sample | Class | |---|---| | Build the URL of a Launchpad App
Builds the URL of a launchpad app from semantic object, action and parameters - through cl_lsapi_manager where the system has it, as an intent URL of its own where it does not
launchpad fiori flp url intent semantic object action link cl_lsapi_manager open_new_tab | [`Z2UI5_CL_SMPS_APP_025`](src/09/z2ui5_cl_smps_app_025.clas.abap) | +| Smart Link Popover with getLinks
a list of products whose ids are smart links - a press asks the launchpad which apps the user may open for the product and lists them in a popover
launchpad fiori flp smart link popover getlinks intent semantic object cross_app_nav_get_links | [`Z2UI5_CL_SMPS_APP_026`](src/09/z2ui5_cl_smps_app_026.clas.abap) | | Read Startup Parameters
what the tile passed in - client->get( )-t_comp_params
launchpad fiori flp startup parameters intent | [`Z2UI5_CL_SMPS_APP_481`](src/09/z2ui5_cl_smps_app_481.clas.abap) | | Set Shell Title
follow_up_action( cs_event-set_title_launchpad )
launchpad fiori flp shell title follow_up_action | [`Z2UI5_CL_SMPS_APP_482`](src/09/z2ui5_cl_smps_app_482.clas.abap) | | Cross-App Navigation Sender
hands two values over to another tile
launchpad fiori flp cross app navigation sender intent | [`Z2UI5_CL_SMPS_APP_483`](src/09/z2ui5_cl_smps_app_483.clas.abap) | diff --git a/catalogue-derived.json b/catalogue-derived.json index 3d437f4..b4c97ff 100644 --- a/catalogue-derived.json +++ b/catalogue-derived.json @@ -58,6 +58,7 @@ "sap.m.QuickViewPage", "sap.m.ToggleButton", "z2ui5.cc.Websocket", + "sap.m.StandardListItem", "sap.m.CheckBox", "sap.m.Select", "sap.ui.core.Item", @@ -70,8 +71,8 @@ "sap.m.TextArea" ], "counts": { - "samples": 45, - "controls": 60, + "samples": 46, + "controls": 61, "noChain": 0 }, "samples": [ @@ -88,19 +89,20 @@ {"class":"Z2UI5_CL_SMPS_APP_010","minUi5":"1.71","needs":[],"controls":[1,2,3,39,40,22,37,6,7,10,11,12,13,18,41,15,17,38],"controlCount":55}, {"class":"Z2UI5_CL_SMPS_APP_011","minUi5":"1.71","needs":[],"controls":[1,2,3,22,37,5,7,10,11,12,13,18,41,17,38],"controlCount":33}, {"class":"Z2UI5_CL_SMPS_APP_012","minUi5":"1.71","needs":[],"controls":[1,2,3,7,10,11,12,13,18,41,17],"controlCount":18}, - {"class":"Z2UI5_CL_SMPS_APP_013","minUi5":"1.71","needs":[],"controls":[1,50,22,37,5,23,7,51,10,41,52,17,38],"controlCount":28}, + {"class":"Z2UI5_CL_SMPS_APP_013","minUi5":"1.71","needs":[],"controls":[1,51,22,37,5,23,7,52,10,41,53,17,38],"controlCount":28}, {"class":"Z2UI5_CL_SMPS_APP_014","minUi5":"1.71","needs":[],"controls":[1,43,44,22,45,5,7,10,14,17],"controlCount":11}, - {"class":"Z2UI5_CL_SMPS_APP_015","minUi5":"1.71","needs":[],"controls":[1,2,3,22,37,5,53,7,8,10,11,12,14,17],"controlCount":38}, - {"class":"Z2UI5_CL_SMPS_APP_016","minUi5":"1.71","needs":[],"controls":[1,2,3,31,22,37,5,7,10,11,12,13,18,41,17,38,54],"controlCount":35}, - {"class":"Z2UI5_CL_SMPS_APP_017","minUi5":"1.71","needs":[],"controls":[1,2,3,31,37,5,6,7,10,55,11,12,13,18,41,17],"controlCount":31}, - {"class":"Z2UI5_CL_SMPS_APP_018","minUi5":"1.71","needs":[],"controls":[1,2,3,40,31,22,37,5,7,56,57,10,58,11,12,59,13,18,41,15,17,38],"controlCount":50}, + {"class":"Z2UI5_CL_SMPS_APP_015","minUi5":"1.71","needs":[],"controls":[1,2,3,22,37,5,54,7,8,10,11,12,14,17],"controlCount":38}, + {"class":"Z2UI5_CL_SMPS_APP_016","minUi5":"1.71","needs":[],"controls":[1,2,3,31,22,37,5,7,10,11,12,13,18,41,17,38,55],"controlCount":35}, + {"class":"Z2UI5_CL_SMPS_APP_017","minUi5":"1.71","needs":[],"controls":[1,2,3,31,37,5,6,7,10,56,11,12,13,18,41,17],"controlCount":31}, + {"class":"Z2UI5_CL_SMPS_APP_018","minUi5":"1.71","needs":[],"controls":[1,2,3,40,31,22,37,5,7,57,58,10,59,11,12,60,13,18,41,15,17,38],"controlCount":50}, {"class":"Z2UI5_CL_SMPS_APP_019","minUi5":"1.71","needs":[],"controls":[1,22,37,5,23,7,10,12,41,17,38],"controlCount":15}, {"class":"Z2UI5_CL_SMPS_APP_020","minUi5":"1.71","needs":[],"controls":[1,2,3,31,5,7,10,11,12,13,18,41,17],"controlCount":25}, - {"class":"Z2UI5_CL_SMPS_APP_021","minUi5":"1.71","needs":[],"controls":[1,2,3,31,5,7,10,11,12,17,54],"controlCount":27}, + {"class":"Z2UI5_CL_SMPS_APP_021","minUi5":"1.71","needs":[],"controls":[1,2,3,31,5,7,10,11,12,17,55],"controlCount":27}, {"class":"Z2UI5_CL_SMPS_APP_022","minUi5":"1.71","needs":[],"controls":[1,2,3,22,5,7,10,11,12,13,18,41,17],"controlCount":22}, - {"class":"Z2UI5_CL_SMPS_APP_023","minUi5":"1.71","needs":[],"controls":[1,22,37,5,23,7,10,12,59,41,17,38],"controlCount":18}, - {"class":"Z2UI5_CL_SMPS_APP_024","minUi5":"1.71","needs":[],"controls":[1,2,3,37,5,6,23,7,10,11,12,59,41,17,38],"controlCount":22}, + {"class":"Z2UI5_CL_SMPS_APP_023","minUi5":"1.71","needs":[],"controls":[1,22,37,5,23,7,10,12,60,41,17,38],"controlCount":18}, + {"class":"Z2UI5_CL_SMPS_APP_024","minUi5":"1.71","needs":[],"controls":[1,2,3,37,5,6,23,7,10,11,12,60,41,17,38],"controlCount":22}, {"class":"Z2UI5_CL_SMPS_APP_025","minUi5":"1.71","needs":[],"controls":[1,2,3,22,37,5,23,7,10,11,12,13,18,41,17,38],"controlCount":31}, + {"class":"Z2UI5_CL_SMPS_APP_026","minUi5":"1.71","needs":[],"controls":[2,3,22,37,4,45,5,7,9,10,50,11,12,13,18,15,17,38],"controlCount":24}, {"class":"Z2UI5_CL_SMPS_APP_313","minUi5":"1.71","needs":[],"controls":[7,10,19,20,21,17],"controlCount":6}, {"class":"Z2UI5_CL_SMPS_APP_314","minUi5":"1.71","needs":[],"controls":[2,3,22,7,10,11,12,13,18,17],"controlCount":31}, {"class":"Z2UI5_CL_SMPS_APP_315","minUi5":"1.71","needs":[],"controls":[2,3,7,10,11,12,13,18,17],"controlCount":35}, diff --git a/catalogue.json b/catalogue.json index bf7cbc0..e999e32 100644 --- a/catalogue.json +++ b/catalogue.json @@ -820,6 +820,32 @@ "branch": "09-launchpad", "setup": "src/09/README.md" }, + { + "class": "Z2UI5_CL_SMPS_APP_026", + "path": "src/09/z2ui5_cl_smps_app_026.clas.abap", + "package": "src/09", + "technology": "Launchpad", + "title": "Smart Link Popover with getLinks", + "summary": "a list of products whose ids are smart links - a press asks the launchpad which apps the user may open for the product and lists them in a popover", + "keywords": [ + "launchpad", + "fiori", + "flp", + "smart", + "link", + "popover", + "getlinks", + "intent", + "semantic", + "object", + "cross_app_nav_get_links" + ], + "runsOn": "Cloud + Standard ≥ 7.40 SP08", + "cloud": true, + "needs": "a Fiori Launchpad with a tile pointing at abap2UI5", + "branch": "09-launchpad", + "setup": "src/09/README.md" + }, { "class": "Z2UI5_CL_SMPS_APP_481", "path": "src/09/z2ui5_cl_smps_app_481.clas.abap", diff --git a/src/09/README.md b/src/09/README.md index 6b5f102..1b2f5d8 100644 --- a/src/09/README.md +++ b/src/09/README.md @@ -10,7 +10,7 @@ reaches the other tiles of the launchpad — your own and SAP's alike. Nothing about the app changes for that. It stays the same class with the same `main( )`; the framework recognises the launchpad on its own and tells the app through `client->get( )-check_launchpad_active`. So one app runs in both worlds, and -the four samples here show what the launchpad adds when it is the one you are in. +the samples here show what the launchpad adds when it is the one you are in. ## What you need @@ -31,7 +31,7 @@ The target mapping's URL is the abap2UI5 ICF node plus the app to start: The framework detects the launchpad from that context (`scenario=LAUNCHPAD` in the query, or `/ui2/flp` / `test/flpSandbox` in the path) and sets -`check_launchpad_active`. `481` to `483` check the flag and tell you with a message +`check_launchpad_active`. `481` to `483` and `026` check the flag and tell you with a message box when they were started standalone — where they then have no shell to talk to; `484`, the receiver, shows the flag in its form and hides its two navigation buttons instead. @@ -45,6 +45,7 @@ buttons instead. | [`483`](z2ui5_cl_smps_app_483.clas.abap) | cross-app navigation, **sender** — hands two values over to another tile | | [`484`](z2ui5_cl_smps_app_484.clas.abap) | cross-app navigation, **receiver** — reads them back out of its startup parameters | | [`025`](z2ui5_cl_smps_app_025.clas.abap) | build the URL of a launchpad app from semantic object, action and parameters — `cl_lsapi_manager` where the system has it, an intent URL of its own where it does not. Runs standalone too | +| [`026`](z2ui5_cl_smps_app_026.clas.abap) | a **smart link popover** — asks the launchpad which apps the user may open for a product and lists them next to the pressed link — `follow_up_action( cs_event-cross_app_nav_get_links )` | Start any of them with `?app_start=z2ui5_cl_smps_app_` — from a tile, that is what the target mapping's URL carries. The overview app @@ -83,6 +84,33 @@ Both literals sit in the classes, so use these two names or change them there. T *back to the previous app* button in either sample needs no configuration at all — `cs_event-cross_app_nav_to_prev_app` goes back through the shell's own history. +## Asking the launchpad which apps there are + +`483` names its target. A Fiori elements list does not: its smart links ask the +launchpad which apps the user may open for the object — the answer depends on the +user's roles and catalogs, so only the frontend has it. `026` asks the same +question with the frontend action `cs_event-cross_app_nav_get_links` (target, +intent parameters, the event that receives the answer): + +```abap +client->follow_up_action( + val = client->cs_event-cross_app_nav_get_links + t_arg = VALUE #( ( `{"semanticObject":"Z2UI5_CL_LP_SAMPLE_04"}` ) + ( `{"PRODUCT":"102343333","QUANTITY":"500"}` ) + ( `LINKS_READ` ) ) ). +``` + +`LINKS_READ` then arrives with a JSON array, one object per intent — `intent` +(the hash), `text`, `subTitle` — which the sample lists in a popover next to the +pressed link. A press on an entry navigates there with `cross_app_nav_to_ext` and +`{"shellHash":""}` as target. + +It needs no configuration of its own: its default semantic object is the one of +the receiver `484`, so with the target mapping of the pair above the popover lists +the receiver, and the receiver shows the product and quantity of the pressed row. +Type another semantic object to see what the launchpad offers for it; one without +target mapping gives an empty list. Needs abap2UI5 newer than 1.148.0. + ## Where to go next - [`01` OData](../01/README.md) — back to the beginning: the app talking to a diff --git a/src/09/z2ui5_cl_smps_app_026.clas.abap b/src/09/z2ui5_cl_smps_app_026.clas.abap new file mode 100644 index 0000000..035150a --- /dev/null +++ b/src/09/z2ui5_cl_smps_app_026.clas.abap @@ -0,0 +1,372 @@ +" @keywords launchpad fiori flp smart link popover getlinks intent semantic object cross_app_nav_get_links +" @summary a list of products whose ids are smart links - a press asks the launchpad which apps the user may open for the product and lists them in a popover +"!

Launchpad - Smart Link Popover with getLinks

+"! A Fiori elements list shows a key as a smart link: a press opens a +"! popover with every app the user may open for the object, each called +"! with the row's keys. Which apps those are depends on the user's roles +"! and catalogs, so only the launchpad knows - the backend asks it with +"! the frontend action cs_event-cross_app_nav_get_links: +"! +"! client->follow_up_action( +"! val = client->cs_event-cross_app_nav_get_links +"! t_arg = VALUE #( ( `{"semanticObject":"Z2UI5_CL_LP_SAMPLE_04"}` ) +"! ( `{"PRODUCT":"102343333","QUANTITY":"500"}` ) +"! ( `LINKS_READ` ) ) ). +"! +"! The answer arrives as the event LINKS_READ, its argument a JSON array +"! with one object per intent - intent (the hash), text, subTitle. The +"! sample lists them in a popover next to the pressed link, and a press on +"! an entry navigates there with cs_event-cross_app_nav_to_ext and the +"! hash as shellHash target. +"! +"! Needs abap2UI5 newer than 1.148.0 (cross_app_nav_get_links) and a +"! launchpad. The default semantic object is the one of the receiver +"! z2ui5_cl_smps_app_484, so the target mapping the package README sets up +"! for it is all the sample needs - the popover then lists the receiver, +"! which shows the product and quantity of the pressed row. +CLASS z2ui5_cl_smps_app_026 DEFINITION PUBLIC. + + PUBLIC SECTION. + INTERFACES z2ui5_if_app. + + TYPES: + BEGIN OF ty_s_product, + product TYPE string, + name TYPE string, + quantity TYPE string, + END OF ty_s_product. + TYPES ty_t_product TYPE STANDARD TABLE OF ty_s_product WITH EMPTY KEY. + + TYPES: + BEGIN OF ty_s_link, + intent TYPE string, + text TYPE string, + sub_title TYPE string, + END OF ty_s_link. + TYPES ty_t_link TYPE STANDARD TABLE OF ty_s_link WITH EMPTY KEY. + + DATA semantic_object TYPE string. + DATA t_products TYPE ty_t_product. + + "! the intents of the last answer + DATA t_links TYPE ty_t_link. + + PROTECTED SECTION. + DATA client TYPE REF TO z2ui5_if_client. + + "! the row the intents were asked for + DATA s_product TYPE ty_s_product. + + "! the id of the pressed link - the popover opens next to it + DATA anchor TYPE string. + + METHODS on_event. + METHODS on_event_links. + METHODS on_event_links_read. + METHODS on_event_navigate. + + METHODS view_display. + METHODS popover_display. + + PRIVATE SECTION. + + "! reads the string value behind marker, searching from offset - which + "! is moved behind the value, or set to -1 when there is none + METHODS json_read_string + IMPORTING + json TYPE string + marker TYPE string + EXPORTING + result TYPE string + CHANGING + offset TYPE i. + + METHODS json_escape + IMPORTING + val TYPE string + RETURNING + VALUE(result) TYPE string. + +ENDCLASS. + + +CLASS z2ui5_cl_smps_app_026 IMPLEMENTATION. + + METHOD z2ui5_if_app~main. + + me->client = client. + IF client->check_on_init( ). + + semantic_object = `Z2UI5_CL_LP_SAMPLE_04`. + t_products = VALUE #( ( product = `102343333` name = `Notebook Basic 15` quantity = `500` ) + ( product = `102343334` name = `Notebook Basic 17` quantity = `25` ) + ( product = `102343335` name = `Ergo Screen E-I` quantity = `3` ) ). + + IF client->get( )-check_launchpad_active = abap_false. + client->message_box_display( `No Launchpad Active, Sample not working!` ). + ENDIF. + view_display( ). + ELSEIF client->check_on_navigated( ). + view_display( ). + ELSEIF client->check_on_event( ). + on_event( ). + ENDIF. + + ENDMETHOD. + + + METHOD on_event. + + CASE client->get_event( ). + WHEN `LINKS`. + on_event_links( ). + WHEN `LINKS_READ`. + " raised by the frontend once getLinks has answered - named in the + " third argument of cross_app_nav_get_links in on_event_links( ) + on_event_links_read( ). + WHEN `NAVIGATE`. + on_event_navigate( ). + ENDCASE. + + ENDMETHOD. + + + METHOD on_event_links. + + " the pressed link and its row - the popover opens next to the link + " once the launchpad has answered, in the roundtrip of LINKS_READ + anchor = client->get_event_arg( ). + s_product = VALUE #( product = client->get_event_arg( 2 ) + name = client->get_event_arg( 3 ) + quantity = client->get_event_arg( 4 ) ). + + " target, intent parameters, the event that receives the answer - the + " parameters are the keys the target mappings expect, so an intent that + " needs one the row does not have is not offered + client->follow_up_action( + val = client->cs_event-cross_app_nav_get_links + t_arg = VALUE #( + ( |\{"semanticObject":"{ json_escape( semantic_object ) }"\}| ) + ( |\{"PRODUCT":"{ json_escape( s_product-product ) }",| && + |"QUANTITY":"{ json_escape( s_product-quantity ) }"\}| ) + ( `LINKS_READ` ) ) ). + + ENDMETHOD. + + + METHOD on_event_links_read. + + " [{"intent":"#SO-action?PRODUCT=...","text":"...","subTitle":"...", + " "semanticObject":"SO","action":"action","params":{...}}, ...] + " - written by the framework, one object per intent and intent always + " its first key, so the walk takes the three strings it shows in order + " and leaves the split parts alone + DATA(json) = client->get_event_arg( ). + DATA(offset) = 0. + DATA s_link TYPE ty_s_link. + + CLEAR t_links. + DO. + CLEAR s_link. + json_read_string( EXPORTING json = json + marker = `{"intent":"` + IMPORTING result = s_link-intent + CHANGING offset = offset ). + IF offset < 0. + EXIT. + ENDIF. + json_read_string( EXPORTING json = json + marker = `"text":"` + IMPORTING result = s_link-text + CHANGING offset = offset ). + IF offset < 0. + EXIT. + ENDIF. + json_read_string( EXPORTING json = json + marker = `"subTitle":"` + IMPORTING result = s_link-sub_title + CHANGING offset = offset ). + IF offset < 0. + EXIT. + ENDIF. + INSERT s_link INTO TABLE t_links. + ENDDO. + + popover_display( ). + + ENDMETHOD. + + + METHOD on_event_navigate. + + " the hash exactly as getLinks returned it - hrefForExternal takes a + " shellHash target as it is, parameters included + DATA(intent) = client->get_event_arg( ). + + client->popover_destroy( ). + client->follow_up_action( + val = client->cs_event-cross_app_nav_to_ext + t_arg = VALUE #( ( |\{"shellHash":"{ json_escape( intent ) }"\}| ) ) ). + + ENDMETHOD. + + + METHOD json_read_string. + + CLEAR result. + DATA(start) = find( val = json sub = marker off = offset ). + IF start < 0. + offset = -1. + RETURN. + ENDIF. + + DATA(pos) = start + strlen( marker ). + DATA(length) = strlen( json ). + + " walked rather than cut at the next quote: a quote inside the value + " stands in the JSON as \" and would end it early + WHILE pos < length. + DATA(char) = substring( val = json off = pos len = 1 ). + pos = pos + 1. + + IF char = `"`. + offset = pos. + RETURN. + ENDIF. + + IF char <> `\`. + result = result && char. + CONTINUE. + ENDIF. + + " an escape - a backslash at the very end is a truncated payload + IF pos >= length. + EXIT. + ENDIF. + DATA(escaped) = substring( val = json off = pos len = 1 ). + pos = pos + 1. + + CASE escaped. + WHEN `n`. + result = result && |\n|. + WHEN `t`. + result = result && |\t|. + WHEN OTHERS. + " `"`, `\` and `/` stand for themselves + result = result && escaped. + ENDCASE. + ENDWHILE. + + " no closing quote + offset = -1. + + ENDMETHOD. + + + METHOD json_escape. + + result = replace( val = val sub = `\` with = `\\` occ = 0 ). + result = replace( val = result sub = `"` with = `\"` occ = 0 ). + + ENDMETHOD. + + + METHOD view_display. + + DATA(view) = z2ui5_cl_ui5_view_builder=>factory( + )->ele( n = `View` ns = `mvc` + )->a( n = `displayBlock` v = `true` + )->a( n = `height` v = `100%` + )->a( n = `xmlns` v = `sap.m` + )->a( n = `xmlns:mvc` v = `sap.ui.core.mvc` + )->a( n = `xmlns:form` v = `sap.ui.layout.form` ). + DATA(page) = view->ele( `Shell` + )->ele( `Page` + )->a( n = `title` v = `abap2UI5 - Launchpad - Smart Link Popover with getLinks` + )->a( n = `showNavButton` b = client->check_app_prev_stack( ) + )->a( n = `navButtonPress` v = client->_event_nav_app_leave( ) + )->a( n = `showHeader` b = xsdbool( client->get( )-check_launchpad_active = abap_false ) ). + + page->tag( `MessageStrip` + )->a( n = `text` v = `Press a product: follow_up_action( cs_event-cross_app_nav_get_links ) asks the ` && + `launchpad which apps the user may open for the semantic object with the row's ` && + `PRODUCT and QUANTITY, and the popover lists what it answers - a press on an entry ` && + `navigates there with cs_event-cross_app_nav_to_ext. Only works inside a launchpad; ` && + `with the target mapping of z2ui5_cl_smps_app_484 the receiver is in the list.` + )->a( n = `type` v = `Information` + )->a( n = `showIcon` b = abap_true + )->a( n = `class` v = `sapUiSmallMargin` ). + + page->ele( n = `SimpleForm` ns = `form` + )->a( n = `title` v = `The links of` + )->a( n = `editable` b = abap_true + )->ele( n = `content` ns = `form` + )->tag( `Label` + )->a( n = `text` v = `Semantic Object` + )->tag( `Input` + )->a( n = `value` v = client->_bind( semantic_object ) ). + + DATA(table) = page->ele( `Table` + )->a( n = `items` v = client->_bind( t_products ) ). + table->ele( `headerToolbar` + )->ele( `Toolbar` + )->tag( `Title` + )->a( n = `text` v = `Products` ). + table->ele( `columns` + )->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `Product` + )->end( + )->ele( `Column` + )->tag( `Text` + )->a( n = `text` v = `Name` + )->end( + )->ele( `Column` + )->a( n = `hAlign` v = `End` + )->tag( `Text` + )->a( n = `text` v = `Quantity` ). + table->ele( `items` + )->ele( `ColumnListItem` + )->ele( `cells` + )->tag( `Link` + )->a( n = `text` v = `{PRODUCT}` + )->a( n = `press` v = client->_event( val = `LINKS` + t_arg = VALUE #( ( `${$source>/id}` ) + ( `${PRODUCT}` ) + ( `${NAME}` ) + ( `${QUANTITY}` ) ) ) + )->tag( `Text` + )->a( n = `text` v = `{NAME}` + )->tag( `Text` + )->a( n = `text` v = `{QUANTITY}` ). + + client->view_display( view->stringify( ) ). + + ENDMETHOD. + + + METHOD popover_display. + + DATA(popover) = z2ui5_cl_ui5_view_builder=>factory( + )->ele( n = `FragmentDefinition` ns = `core` + )->a( n = `xmlns` v = `sap.m` + )->a( n = `xmlns:core` v = `sap.ui.core` ). + DATA(list) = popover->ele( `Popover` + )->a( n = `title` t = |{ s_product-name } ({ s_product-product })| + )->a( n = `placement` v = `Auto` + )->a( n = `contentWidth` v = `20rem` + )->ele( `List` + )->a( n = `items` v = client->_bind( t_links ) + )->a( n = `noDataText` t = |The launchpad offers you no app for { semantic_object }.| ). + list->ele( `StandardListItem` + )->a( n = `title` v = `{TEXT}` + )->a( n = `description` v = `{SUB_TITLE}` + )->a( n = `type` v = `Navigation` + )->a( n = `press` v = client->_event( val = `NAVIGATE` + arg = `${INTENT}` ) ). + + client->popover_display( xml = popover->stringify( ) by_id = anchor ). + + ENDMETHOD. + +ENDCLASS. diff --git a/src/09/z2ui5_cl_smps_app_026.clas.xml b/src/09/z2ui5_cl_smps_app_026.clas.xml new file mode 100644 index 0000000..b270a5e --- /dev/null +++ b/src/09/z2ui5_cl_smps_app_026.clas.xml @@ -0,0 +1,16 @@ + + + + + + Z2UI5_CL_SMPS_APP_026 + E + Launchpad - Smart Link Popover with getLinks + 1 + X + X + X + + + + diff --git a/src/z2ui5_cl_smps_app_000.clas.abap b/src/z2ui5_cl_smps_app_000.clas.abap index c1d83e9..609dc01 100644 --- a/src/z2ui5_cl_smps_app_000.clas.abap +++ b/src/z2ui5_cl_smps_app_000.clas.abap @@ -1056,7 +1056,11 @@ CLASS z2ui5_cl_smps_app_000 IMPLEMENTATION. ( sample( no = `025` title = `Build the URL of a launchpad app` detail = `Builds the URL of a launchpad app from semantic object, action and parameters - through cl_lsapi_manager where the system has it, as an intent URL of its own where it does not` - classname = `Z2UI5_CL_SMPS_APP_025` ) ) ). + classname = `Z2UI5_CL_SMPS_APP_025` ) ) + ( sample( no = `026` + title = `Smart link popover with getLinks` + detail = `a list of products whose ids are smart links - a press asks the launchpad which apps the user may open for the product and lists them in a popover` + classname = `Z2UI5_CL_SMPS_APP_026` ) ) ). t_ai = VALUE #( ( sample( no = `013`