@open-rap/compiler 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +21 -2
- package/dist/agent/server.d.ts +35 -0
- package/dist/agent/server.js +408 -0
- package/dist/agent/server.js.map +1 -0
- package/dist/authoring/abapgit.d.ts +38 -0
- package/dist/authoring/abapgit.js +242 -0
- package/dist/authoring/abapgit.js.map +1 -0
- package/dist/authoring/catalog.d.ts +48 -0
- package/dist/authoring/catalog.js +117 -0
- package/dist/authoring/catalog.js.map +1 -0
- package/dist/authoring/floorplan.d.ts +28 -0
- package/dist/authoring/floorplan.js +31 -0
- package/dist/authoring/floorplan.js.map +1 -0
- package/dist/authoring/generate.d.ts +57 -0
- package/dist/authoring/generate.js +630 -0
- package/dist/authoring/generate.js.map +1 -0
- package/dist/authoring/mcp.d.ts +15 -0
- package/dist/authoring/mcp.js +52 -0
- package/dist/authoring/mcp.js.map +1 -0
- package/dist/authoring/new.d.ts +35 -0
- package/dist/authoring/new.js +389 -0
- package/dist/authoring/new.js.map +1 -0
- package/dist/bdef/ast.d.ts +249 -0
- package/dist/bdef/ast.js +3 -0
- package/dist/bdef/ast.js.map +1 -0
- package/dist/bdef/lexer.d.ts +105 -0
- package/dist/bdef/lexer.js +148 -0
- package/dist/bdef/lexer.js.map +1 -0
- package/dist/bdef/parser.d.ts +22 -0
- package/dist/bdef/parser.js +1012 -0
- package/dist/bdef/parser.js.map +1 -0
- package/dist/build.d.ts +26 -0
- package/dist/build.js +62 -0
- package/dist/build.js.map +1 -0
- package/dist/cds/adapter.d.ts +91 -0
- package/dist/cds/adapter.js +381 -0
- package/dist/cds/adapter.js.map +1 -0
- package/dist/cds/expression-ast.d.ts +65 -0
- package/dist/cds/expression-ast.js +330 -0
- package/dist/cds/expression-ast.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.js +485 -0
- package/dist/cli.js.map +1 -0
- package/dist/dcl/parser.d.ts +59 -0
- package/dist/dcl/parser.js +338 -0
- package/dist/dcl/parser.js.map +1 -0
- package/dist/ddic/catalog.d.ts +17 -0
- package/dist/ddic/catalog.js +211 -0
- package/dist/ddic/catalog.js.map +1 -0
- package/dist/ddic/cds-types.d.ts +47 -0
- package/dist/ddic/cds-types.js +131 -0
- package/dist/ddic/cds-types.js.map +1 -0
- package/dist/ddic/table-source.d.ts +70 -0
- package/dist/ddic/table-source.js +500 -0
- package/dist/ddic/table-source.js.map +1 -0
- package/dist/ddic/xml.d.ts +65 -0
- package/dist/ddic/xml.js +201 -0
- package/dist/ddic/xml.js.map +1 -0
- package/dist/dev.d.ts +128 -0
- package/dist/dev.js +434 -0
- package/dist/dev.js.map +1 -0
- package/dist/diagnostics.d.ts +33 -0
- package/dist/diagnostics.js +53 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/gen/abap/derived-types.d.ts +26 -0
- package/dist/gen/abap/derived-types.js +323 -0
- package/dist/gen/abap/derived-types.js.map +1 -0
- package/dist/gen/abap/eml.d.ts +118 -0
- package/dist/gen/abap/eml.js +362 -0
- package/dist/gen/abap/eml.js.map +1 -0
- package/dist/gen/abap/enums.d.ts +13 -0
- package/dist/gen/abap/enums.js +74 -0
- package/dist/gen/abap/enums.js.map +1 -0
- package/dist/gen/abap/framework-http.d.ts +14 -0
- package/dist/gen/abap/framework-http.js +1049 -0
- package/dist/gen/abap/framework-http.js.map +1 -0
- package/dist/gen/abap/framework-query.d.ts +14 -0
- package/dist/gen/abap/framework-query.js +225 -0
- package/dist/gen/abap/framework-query.js.map +1 -0
- package/dist/gen/abap/framework-utils.d.ts +29 -0
- package/dist/gen/abap/framework-utils.js +3707 -0
- package/dist/gen/abap/framework-utils.js.map +1 -0
- package/dist/gen/abap/framework.d.ts +12 -0
- package/dist/gen/abap/framework.js +480 -0
- package/dist/gen/abap/framework.js.map +1 -0
- package/dist/gen/abap/generate.d.ts +40 -0
- package/dist/gen/abap/generate.js +238 -0
- package/dist/gen/abap/generate.js.map +1 -0
- package/dist/gen/abap/rewrite.d.ts +82 -0
- package/dist/gen/abap/rewrite.js +957 -0
- package/dist/gen/abap/rewrite.js.map +1 -0
- package/dist/gen/abap/shadow.d.ts +25 -0
- package/dist/gen/abap/shadow.js +175 -0
- package/dist/gen/abap/shadow.js.map +1 -0
- package/dist/gen/abap/tokens.d.ts +33 -0
- package/dist/gen/abap/tokens.js +87 -0
- package/dist/gen/abap/tokens.js.map +1 -0
- package/dist/gen/app/index.d.ts +25 -0
- package/dist/gen/app/index.js +322 -0
- package/dist/gen/app/index.js.map +1 -0
- package/dist/gen/csdl.d.ts +11 -0
- package/dist/gen/csdl.js +562 -0
- package/dist/gen/csdl.js.map +1 -0
- package/dist/gen/deploy.d.ts +12 -0
- package/dist/gen/deploy.js +53 -0
- package/dist/gen/deploy.js.map +1 -0
- package/dist/gen/docs/index.d.ts +35 -0
- package/dist/gen/docs/index.js +267 -0
- package/dist/gen/docs/index.js.map +1 -0
- package/dist/gen/docs/markdown.d.ts +23 -0
- package/dist/gen/docs/markdown.js +187 -0
- package/dist/gen/docs/markdown.js.map +1 -0
- package/dist/gen/docs/site.d.ts +17 -0
- package/dist/gen/docs/site.js +106 -0
- package/dist/gen/docs/site.js.map +1 -0
- package/dist/gen/keycloak.d.ts +21 -0
- package/dist/gen/keycloak.js +90 -0
- package/dist/gen/keycloak.js.map +1 -0
- package/dist/gen/launchpad/index.d.ts +48 -0
- package/dist/gen/launchpad/index.js +302 -0
- package/dist/gen/launchpad/index.js.map +1 -0
- package/dist/gen/launchpad/ui.d.ts +14 -0
- package/dist/gen/launchpad/ui.js +350 -0
- package/dist/gen/launchpad/ui.js.map +1 -0
- package/dist/gen/mcp.d.ts +23 -0
- package/dist/gen/mcp.js +244 -0
- package/dist/gen/mcp.js.map +1 -0
- package/dist/gen/sql-expressions.d.ts +12 -0
- package/dist/gen/sql-expressions.js +136 -0
- package/dist/gen/sql-expressions.js.map +1 -0
- package/dist/gen/sql.d.ts +38 -0
- package/dist/gen/sql.js +612 -0
- package/dist/gen/sql.js.map +1 -0
- package/dist/gen/ui/index.d.ts +7 -0
- package/dist/gen/ui/index.js +27 -0
- package/dist/gen/ui/index.js.map +1 -0
- package/dist/gen/ui/layout.d.ts +230 -0
- package/dist/gen/ui/layout.js +511 -0
- package/dist/gen/ui/layout.js.map +1 -0
- package/dist/gen/ui/static.d.ts +55 -0
- package/dist/gen/ui/static.js +2901 -0
- package/dist/gen/ui/static.js.map +1 -0
- package/dist/gen/ui/views.d.ts +10 -0
- package/dist/gen/ui/views.js +511 -0
- package/dist/gen/ui/views.js.map +1 -0
- package/dist/gen/vendor.d.ts +23 -0
- package/dist/gen/vendor.js +68 -0
- package/dist/gen/vendor.js.map +1 -0
- package/dist/gen/xml.d.ts +9 -0
- package/dist/gen/xml.js +42 -0
- package/dist/gen/xml.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/input/project.d.ts +50 -0
- package/dist/input/project.js +128 -0
- package/dist/input/project.js.map +1 -0
- package/dist/ir/access-controls.d.ts +11 -0
- package/dist/ir/access-controls.js +148 -0
- package/dist/ir/access-controls.js.map +1 -0
- package/dist/ir/authorizations.d.ts +25 -0
- package/dist/ir/authorizations.js +178 -0
- package/dist/ir/authorizations.js.map +1 -0
- package/dist/ir/behaviors.d.ts +16 -0
- package/dist/ir/behaviors.js +548 -0
- package/dist/ir/behaviors.js.map +1 -0
- package/dist/ir/builder.d.ts +20 -0
- package/dist/ir/builder.js +505 -0
- package/dist/ir/builder.js.map +1 -0
- package/dist/ir/config.d.ts +25 -0
- package/dist/ir/config.js +130 -0
- package/dist/ir/config.js.map +1 -0
- package/dist/ir/dictionary.d.ts +54 -0
- package/dist/ir/dictionary.js +328 -0
- package/dist/ir/dictionary.js.map +1 -0
- package/dist/ir/entities.d.ts +58 -0
- package/dist/ir/entities.js +676 -0
- package/dist/ir/entities.js.map +1 -0
- package/dist/ir/expressions.d.ts +33 -0
- package/dist/ir/expressions.js +327 -0
- package/dist/ir/expressions.js.map +1 -0
- package/dist/ir/handlers.d.ts +63 -0
- package/dist/ir/handlers.js +398 -0
- package/dist/ir/handlers.js.map +1 -0
- package/dist/ir/number-ranges.d.ts +24 -0
- package/dist/ir/number-ranges.js +74 -0
- package/dist/ir/number-ranges.js.map +1 -0
- package/dist/ir/seed.d.ts +23 -0
- package/dist/ir/seed.js +78 -0
- package/dist/ir/seed.js.map +1 -0
- package/dist/ir/service.d.ts +21 -0
- package/dist/ir/service.js +96 -0
- package/dist/ir/service.js.map +1 -0
- package/dist/launchpad/config.d.ts +47 -0
- package/dist/launchpad/config.js +321 -0
- package/dist/launchpad/config.js.map +1 -0
- package/dist/launchpad/workspace.d.ts +48 -0
- package/dist/launchpad/workspace.js +166 -0
- package/dist/launchpad/workspace.js.map +1 -0
- package/dist/srvd/parser.d.ts +36 -0
- package/dist/srvd/parser.js +193 -0
- package/dist/srvd/parser.js.map +1 -0
- package/dist/standard/data.d.ts +18 -0
- package/dist/standard/data.js +534 -0
- package/dist/standard/data.js.map +1 -0
- package/dist/standard/index.d.ts +36 -0
- package/dist/standard/index.js +507 -0
- package/dist/standard/index.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +4 -0
- package/dist/version.js.map +1 -0
- package/docs/AGENTS.md +79 -0
- package/docs/ANNOTATIONS.md +76 -0
- package/docs/DECISIONS.md +1554 -0
- package/docs/DEPLOYMENT.md +113 -0
- package/docs/DIAGNOSTICS.md +116 -0
- package/docs/FEATURES.md +287 -0
- package/docs/GUIDE.md +560 -0
- package/docs/KNOWN_GAPS.md +216 -0
- package/docs/MCP.md +84 -0
- package/docs/PLAN.md +690 -0
- package/docs/README.md +148 -0
- package/docs/REMOTE_APIS.md +121 -0
- package/docs/ROADMAP.md +35 -0
- package/docs/UTILITIES.md +95 -0
- package/package.json +49 -3
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fixed files of the generated UI: bootstrap, component, manifest, and the generic
|
|
3
|
+
* controllers of the List Report and the Object Page, driven by `model/layout.json`.
|
|
4
|
+
* Plain OpenUI5 1.136 (sap.m, sap.f, sap.uxap, sap.ui.layout), ODataModel V4.
|
|
5
|
+
*/
|
|
6
|
+
import type { UiLayout } from "./layout.js";
|
|
7
|
+
export declare function indexHtml(layout: UiLayout): string;
|
|
8
|
+
/**
|
|
9
|
+
* The content of the shell page sits between the shell bar and the bottom of the window: the
|
|
10
|
+
* inline `height: 100%` that sap.m.App writes on its ancestors would push it one shell bar below
|
|
11
|
+
* the window, and the document would scroll as well as the page.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SHELL_STYLE = ".raptShell > section { height: auto !important; }\n";
|
|
14
|
+
/** Filter bar of the list report: fields and buttons aligned on the bottom of the inputs. */
|
|
15
|
+
export declare const STYLE = ".raptShell > section { height: auto !important; }\n.raptFilterBar { column-gap: 1rem; row-gap: 0.5rem; }\n.raptFilterBar .raptFilterItem { margin: 0; }\n.raptFilterBar .raptFilterButtons { margin-left: auto; align-items: flex-end; }\n.raptChartArea { padding: 0 0 1rem 0; }\n.raptChart { width: 100%; box-sizing: border-box; padding: 0.5rem 0; }\n.raptChart svg { display: block; }\n.raptChartLabel { font-family: var(--sapFontFamily); font-size: 11px; fill: var(--sapContent_LabelColor, #556b82); }\n.raptChartGrid { stroke: var(--sapList_BorderColor, #e5e5e5); stroke-width: 1; }\n.raptChartItem { cursor: pointer; opacity: 0.9; }\n.raptChartItem:hover { opacity: 1; }\n.raptChartSelected { stroke: var(--sapContent_FocusColor, #0070f2); stroke-width: 3; opacity: 1; }\n.raptChartHole { fill: var(--sapTile_Background, #fff); }\n.raptChartEmpty { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--sapContent_LabelColor); }\n.raptCards { gap: 1rem; padding-top: 1rem; }\n.raptCards .raptCard { max-width: 100%; }\n";
|
|
16
|
+
export declare function manifest(layout: UiLayout): string;
|
|
17
|
+
/**
|
|
18
|
+
* The root view: the pages of the application in an App; above them the shell bar of the
|
|
19
|
+
* launchpad (D37) when the application is served behind one (home, user, logout).
|
|
20
|
+
*/
|
|
21
|
+
export declare const APP_VIEW = "<mvc:View controllerName=\"rapt.app.controller.App\" xmlns:mvc=\"sap.ui.core.mvc\" xmlns=\"sap.m\" xmlns:f=\"sap.f\" displayBlock=\"true\" height=\"100%\">\n <Page id=\"shell\" showHeader=\"{= !!${ui>/shell} }\" enableScrolling=\"false\" class=\"raptShell\">\n <customHeader>\n <f:ShellBar id=\"shellBar\" title=\"{ui>/shell/title}\" secondTitle=\"{ui>/shell/launchpad}\" homeIcon=\"{ui>/shell/logo}\" homeIconTooltip=\"Home\" homeIconPressed=\".onHome\" avatarPressed=\".onAvatarPressed\">\n <f:profile>\n <Avatar id=\"avatar\" initials=\"{ui>/shell/user/initials}\" tooltip=\"{ui>/shell/user/name}\"/>\n </f:profile>\n </f:ShellBar>\n </customHeader>\n <content>\n <App id=\"app\"/>\n </content>\n </Page>\n</mvc:View>\n";
|
|
22
|
+
export declare const APP_CONTROLLER = "sap.ui.define([\n \"sap/ui/core/mvc/Controller\",\n \"sap/m/ResponsivePopover\",\n \"sap/m/VBox\",\n \"sap/m/Text\",\n \"sap/m/Button\"\n], function (Controller, ResponsivePopover, VBox, Text, Button) {\n \"use strict\";\n\n /** The shell bar of the launchpad the application is served behind (D37). */\n return Controller.extend(\"rapt.app.controller.App\", {\n onHome: function () {\n window.location.assign(this.getView().getModel(\"ui\").getProperty(\"/shell/home\") || \"/\");\n },\n\n onAvatarPressed: function (oEvent) {\n if (!this._oUserMenu) {\n var oShell = this.getView().getModel(\"ui\").getProperty(\"/shell\");\n var aItems = [];\n if (oShell.user.id !== oShell.user.name) {\n aItems.push(new Text({ text: oShell.user.id }));\n }\n if (!oShell.logout) {\n aItems.push(new Text({ text: \"Development user (no login)\" }));\n }\n this._oUserMenu = new ResponsivePopover(this.createId(\"userMenu\"), { title: oShell.user.name, placement: \"Bottom\", contentMinWidth: \"12rem\" });\n if (aItems.length > 0) {\n this._oUserMenu.addContent(new VBox({ items: aItems }).addStyleClass(\"sapUiSmallMargin\"));\n }\n if (oShell.logout) {\n this._oUserMenu.setBeginButton(new Button(this.createId(\"logout\"), {\n text: \"Sign Out\",\n icon: \"sap-icon://log\",\n press: function () {\n window.location.assign(oShell.logout);\n }\n }));\n }\n this.getView().addDependent(this._oUserMenu);\n }\n this._oUserMenu.openBy(oEvent.getParameter(\"avatar\"));\n }\n });\n});\n";
|
|
23
|
+
export declare const COMPONENT = "sap.ui.define([\n \"sap/ui/core/UIComponent\",\n \"sap/ui/model/json/JSONModel\",\n \"sap/ui/core/Messaging\"\n], function (UIComponent, JSONModel, Messaging) {\n \"use strict\";\n\n return UIComponent.extend(\"rapt.app.Component\", {\n metadata: { manifest: \"json\", interfaces: [\"sap.ui.core.IAsyncContentCreation\"] },\n\n init: function () {\n UIComponent.prototype.init.apply(this, arguments);\n var oUi = new JSONModel({ editMode: false, createMode: false, draft: false, busy: false, tableSelected: false, childSelected: false, permissions: {}, user: undefined, collab: { users: [] } });\n var that = this;\n this._aUserCallbacks = [];\n this.setModel(oUi, \"ui\");\n this.setModel(Messaging.getMessageModel(), \"message\");\n // the creations the user may perform (global authorization): Create is hidden otherwise\n var sService = this.getManifestEntry(\"/sap.app/dataSources/mainService/uri\");\n fetch(sService + \"$permissions\", { credentials: \"same-origin\", headers: { accept: \"application/json\" } })\n .then(function (oResponse) { return oResponse.ok ? oResponse.json() : {}; })\n .then(function (oPermissions) {\n oUi.setProperty(\"/permissions\", oPermissions);\n // the user, for the draft markers (D58)\n oUi.setProperty(\"/user\", oPermissions.$user || \"\");\n that._fireUser();\n })\n .catch(function () { /* the permissions stay unknown: every button is shown */ oUi.setProperty(\"/user\", \"\"); that._fireUser(); });\n // behind a launchpad (D37): its shell bar above the pages; standalone, the request fails\n var sTitle = this.getManifestEntry(\"/sap.app/title\");\n fetch(\"/launchpad/config\", { credentials: \"same-origin\", headers: { accept: \"application/json\" } })\n .then(function (oResponse) { return oResponse.ok ? oResponse.json() : undefined; })\n .then(function (oLaunchpad) {\n if (oLaunchpad && oLaunchpad.user) {\n oUi.setProperty(\"/shell\", { title: sTitle, launchpad: oLaunchpad.title, home: oLaunchpad.home || \"/\", logo: oLaunchpad.logo || \"\", user: oLaunchpad.user, logout: oLaunchpad.logout || \"\" });\n }\n })\n .catch(function () { /* not behind a launchpad */ });\n this.getRouter().initialize();\n },\n\n /** Calls back with the user once known (from $permissions). */\n whenUser: function (fnCallback) {\n var sUser = this.getModel(\"ui\").getProperty(\"/user\");\n if (sUser !== undefined) {\n fnCallback(sUser);\n } else {\n this._aUserCallbacks.push(fnCallback);\n }\n },\n\n _fireUser: function () {\n var sUser = this.getModel(\"ui\").getProperty(\"/user\");\n (this._aUserCallbacks || []).splice(0).forEach(function (fn) { fn(sUser); });\n },\n\n /** A change was saved: the lists show it when the user comes back to them. */\n markStale: function () {\n this._iVersion = (this._iVersion || 0) + 1;\n },\n\n /** Whether the list of an entity set must be refreshed (a change since it was last shown). */\n takeStale: function (sSet) {\n this._mSeen = this._mSeen || {};\n var bStale = (this._mSeen[sSet] || 0) !== (this._iVersion || 0);\n this._mSeen[sSet] = this._iVersion || 0;\n return bStale;\n },\n\n /** The transient context of an instance being created (List Report \u2192 Object Page). */\n setTransient: function (oContext) {\n this._oTransient = oContext;\n },\n\n getTransient: function () {\n return this._oTransient;\n }\n });\n});\n";
|
|
24
|
+
/** Helpers shared by the controllers: layout lookups, key predicates, actions. */
|
|
25
|
+
export declare const SUPPORT = "sap.ui.define([\n \"sap/m/Dialog\",\n \"sap/m/Button\",\n \"sap/m/Label\",\n \"sap/m/Input\",\n \"sap/m/DatePicker\",\n \"sap/m/CheckBox\",\n \"sap/ui/layout/form/SimpleForm\",\n \"sap/ui/core/Messaging\",\n \"sap/m/TableSelectDialog\",\n \"sap/m/Column\",\n \"sap/m/ColumnListItem\",\n \"sap/m/Text\",\n \"sap/ui/model/Filter\",\n \"sap/m/Select\",\n \"sap/ui/core/Item\"\n], function (Dialog, Button, Label, Input, DatePicker, CheckBox, SimpleForm, Messaging, TableSelectDialog, Column, ColumnListItem, Text, Filter, Select, Item) {\n \"use strict\";\n\n function pad(n) {\n return String(n).padStart(2, \"0\");\n }\n\n var support = {\n page: function (oController, sSet) {\n return oController.getOwnerComponent().getModel(\"layout\").getProperty(\"/pages\").find(function (p) {\n return p.set === sSet;\n });\n },\n\n action: function (oPage, sName, aActions) {\n return (aActions || oPage.actions).find(function (a) {\n return a.name === sName;\n });\n },\n\n /** The key of an instance as written in the URL: `3f25\u2026` or `A='x',B=1`. */\n keyOf: function (sPath) {\n var iOpen = sPath.lastIndexOf(\"(\");\n return sPath.slice(iOpen + 1, sPath.length - 1);\n },\n\n keyPredicate: function (oPage, oData) {\n var aKeys = oPage.keys.map(function (sKey) {\n var vValue = oData[sKey];\n var sEdm = oPage.fields[sKey] ? oPage.fields[sKey].edm : \"Edm.String\";\n var sText = sEdm === \"Edm.String\" ? \"'\" + String(vValue).replace(/'/g, \"''\") + \"'\" : String(vValue);\n return { key: sKey, text: sText };\n });\n return aKeys.length === 1 ? aKeys[0].text : aKeys.map(function (k) { return k.key + \"=\" + k.text; }).join(\",\");\n },\n\n dateText: function (oDate) {\n return oDate.getFullYear() + \"-\" + pad(oDate.getMonth() + 1) + \"-\" + pad(oDate.getDate());\n },\n\n /** Asks for the parameters of an action; resolves null when cancelled. */\n askParameters: function (oView, oAction) {\n if (oAction.parameters.length === 0) {\n return Promise.resolve({});\n }\n return new Promise(function (resolve) {\n var aControls = [];\n var aContent = [];\n oAction.parameters.forEach(function (oParameter) {\n var oControl;\n if (oParameter.kind === \"date\") {\n oControl = new DatePicker({ valueFormat: \"yyyy-MM-dd\" });\n } else if (oParameter.kind === \"boolean\") {\n oControl = new CheckBox();\n } else if (oParameter.kind === \"enum\") {\n oControl = new Select({ forceSelection: true, items: oParameter.options.map(function (o) { return new Item({ key: o.key, text: o.text }); }) });\n } else if (oParameter.valueHelp) {\n oControl = new Input({ showValueHelp: true });\n oControl.attachValueHelpRequest(function () {\n var oInput = this;\n support.valueHelp(oView, oParameter.valueHelp, false).then(function (aValues) {\n if (aValues.length > 0) {\n oInput.setValue(aValues[0]);\n }\n });\n }, oControl);\n } else {\n oControl = new Input({ type: oParameter.kind === \"integer\" || oParameter.kind === \"decimal\" ? \"Number\" : \"Text\" });\n }\n aControls.push({ parameter: oParameter, control: oControl });\n aContent.push(new Label({ text: oParameter.label, labelFor: oControl }), oControl);\n });\n var oDialog = new Dialog({\n title: oAction.label,\n content: [new SimpleForm({ editable: true, content: aContent })],\n beginButton: new Button({\n text: oAction.label,\n type: \"Emphasized\",\n press: function () {\n var oValues = {};\n aControls.forEach(function (o) {\n var p = o.parameter;\n if (p.kind === \"boolean\") {\n oValues[p.name] = o.control.getSelected();\n } else if (p.kind === \"enum\") {\n oValues[p.name] = o.control.getSelectedKey();\n } else if (p.kind === \"integer\") {\n oValues[p.name] = o.control.getValue() === \"\" ? 0 : Number(o.control.getValue());\n } else {\n oValues[p.name] = o.control.getValue();\n }\n });\n oDialog.close();\n resolve(oValues);\n }\n }),\n endButton: new Button({\n text: \"Cancel\",\n press: function () {\n oDialog.close();\n resolve(null);\n }\n }),\n afterClose: function () {\n oDialog.destroy();\n }\n });\n oView.addDependent(oDialog);\n oDialog.open();\n });\n },\n\n /** Calls an action (or a function); resolves its return value context, or null when cancelled. */\n invoke: function (oView, oPage, oAction, oContext) {\n return support.askParameters(oView, oAction).then(function (oValues) {\n if (oValues === null) {\n return null;\n }\n Messaging.removeAllMessages();\n var oModel = oView.getModel();\n var oOperation = oAction.static\n ? oModel.bindContext(\"/\" + oPage.set + \"/\" + oAction.qualified + \"(...)\")\n : oModel.bindContext(oAction.qualified + \"(...)\", oContext, { $$inheritExpandSelect: true });\n Object.keys(oValues).forEach(function (sName) {\n oOperation.setParameter(sName, oValues[sName]);\n });\n return oOperation.invoke();\n });\n },\n\n /** The descriptions of the values of a value help (text entity), by value: { EUR: \"Euro\" }. */\n valueHelpTexts: function (oView, oHelp) {\n if (!oHelp.text) {\n return Promise.resolve({});\n }\n var sService = oView.getModel().getServiceUrl();\n var sLanguage = (navigator.language || \"en\").slice(0, 2).toUpperCase();\n var sKey = { EN: \"E\", DE: \"D\", FR: \"F\", ES: \"S\", IT: \"I\", PT: \"P\", NL: \"N\", JA: \"J\", ZH: \"1\", RU: \"R\", PL: \"L\" }[sLanguage] || \"E\";\n var oText = oHelp.text;\n var sFilter = oText.language ? \"&$filter=\" + encodeURIComponent(oText.language + \" eq '\" + sKey + \"' or \" + oText.language + \" eq 'E'\") : \"\";\n return fetch(sService + oText.set + \"?$select=\" + [oText.key, oText.element].concat(oText.language ? [oText.language] : []).join(\",\") + sFilter, {\n credentials: \"same-origin\",\n headers: { accept: \"application/json\" }\n }).then(function (oResponse) {\n return oResponse.ok ? oResponse.json() : { value: [] };\n }).then(function (oData) {\n var mTexts = {};\n (oData.value || []).forEach(function (oRow) {\n var sValue = String(oRow[oText.key]);\n if (mTexts[sValue] === undefined || (oText.language && oRow[oText.language] === sKey)) {\n mTexts[sValue] = oRow[oText.element];\n }\n });\n return mTexts;\n }).catch(function () {\n return {};\n });\n },\n\n /**\n * Opens the value help of a field; resolves the chosen values (none when cancelled). With the\n * context of the instance, the bindings of usage filter restrict the list, and the chosen rows\n * are given as second argument (results of the additional bindings).\n */\n valueHelp: function (oView, oHelp, bMulti, oContext) {\n return support.valueHelpTexts(oView, oHelp).then(function (mTexts) {\n return support._valueHelpDialog(oView, oHelp, bMulti, mTexts, oContext);\n });\n },\n\n /** The filters of the additional bindings of usage filter, from the values of the instance. */\n valueHelpFilters: function (oHelp, oContext) {\n if (!oContext || !oHelp.bindings) {\n return [];\n }\n return oHelp.bindings.filter(function (b) {\n var vValue = oContext.getProperty(b.local);\n return b.usage !== \"result\" && vValue !== undefined && vValue !== null && vValue !== \"\";\n }).map(function (b) {\n return new Filter(b.element, \"EQ\", oContext.getProperty(b.local));\n });\n },\n\n /** Copies the elements of a chosen row to the local elements (additional bindings of usage result). */\n applyValueHelpResults: function (oHelp, oContext, oRow) {\n (oHelp.bindings || []).forEach(function (b) {\n if (b.usage !== \"filter\" && oRow && oRow[b.element] !== undefined) {\n oContext.setProperty(b.local, oRow[b.element]);\n }\n });\n },\n\n /**\n * Checks a typed value against the value help (useForValidation) and fills the additional\n * bindings of usage result; resolves false when the value is not in the list.\n */\n checkValueHelp: function (oView, oHelp, oContext, sValue) {\n if (sValue === \"\" || sValue === null || sValue === undefined) {\n return Promise.resolve(true);\n }\n var aConditions = [oHelp.element + \" eq '\" + String(sValue).replace(/'/g, \"''\") + \"'\"];\n support.valueHelpFilters(oHelp, oContext).forEach(function (oFilter) {\n aConditions.push(oFilter.getPath() + \" eq '\" + String(oFilter.getValue1()).replace(/'/g, \"''\") + \"'\");\n });\n return fetch(oView.getModel().getServiceUrl() + oHelp.set + \"?$top=1&$filter=\" + encodeURIComponent(aConditions.join(\" and \")), {\n credentials: \"same-origin\",\n headers: { accept: \"application/json\" }\n }).then(function (oResponse) {\n return oResponse.ok ? oResponse.json() : { value: [] };\n }).then(function (oData) {\n var oRow = (oData.value || [])[0];\n if (oRow) {\n support.applyValueHelpResults(oHelp, oContext, oRow);\n }\n return oRow !== undefined;\n }).catch(function () {\n return true;\n });\n },\n\n /** The columns of a value help: its elements, and the description of the text entity after the value. */\n valueHelpColumns: function (oHelp, mTexts) {\n var aColumns = oHelp.columns.slice();\n if (Object.keys(mTexts).length > 0) {\n aColumns.splice(1, 0, { property: oHelp.element, label: oHelp.text.label, string: false, text: true });\n }\n return aColumns;\n },\n\n /** The binding of the rows of a value help: the elements of the columns and of the additional bindings. */\n valueHelpItems: function (oHelp, aColumns, mTexts, aBase) {\n return {\n path: \"/\" + oHelp.set,\n parameters: { $count: true, $select: aColumns.filter(function (c) { return !c.text; }).map(function (c) { return c.property; }).concat((oHelp.bindings || []).map(function (b) { return b.element; })).filter(function (p, i, a) { return a.indexOf(p) === i; }).join(\",\") },\n filters: aBase.length === 0 ? undefined : new Filter({ filters: aBase, and: true }),\n template: new ColumnListItem({\n cells: aColumns.map(function (c) {\n return c.text\n ? new Text({ text: { path: c.property, formatter: function (v) { return mTexts[v] || \"\"; } } })\n : new Text({ text: \"{\" + c.property + \"}\" });\n })\n })\n };\n },\n\n /** The filter of a search in a value help: a text column or a description contains the value. */\n valueHelpSearch: function (oHelp, mTexts, sSearch, aBase) {\n var sValue = (sSearch || \"\").trim();\n var aFilters = oHelp.columns.filter(function (c) { return c.string; }).map(function (c) {\n return new Filter({ path: c.property, operator: \"Contains\", value1: sValue, caseSensitive: false });\n });\n // values whose description matches\n var sLower = sValue.toLowerCase();\n Object.keys(mTexts).filter(function (k) {\n return String(mTexts[k]).toLowerCase().indexOf(sLower) >= 0;\n }).slice(0, 30).forEach(function (k) {\n aFilters.push(new Filter(oHelp.element, \"EQ\", k));\n });\n var aAll = aBase.slice();\n if (sValue !== \"\" && aFilters.length > 0) {\n aAll.push(new Filter({ filters: aFilters, and: false }));\n }\n return aAll.length === 0 ? [] : new Filter({ filters: aAll, and: true });\n },\n\n _valueHelpDialog: function (oView, oHelp, bMulti, mTexts, oContext) {\n var aColumns = support.valueHelpColumns(oHelp, mTexts);\n return new Promise(function (resolve) {\n var bDone = false;\n var aBase = support.valueHelpFilters(oHelp, oContext);\n var done = function (aValues, aRows) {\n if (!bDone) {\n bDone = true;\n resolve(aValues);\n if (aRows && aRows.length > 0 && oContext) {\n support.applyValueHelpResults(oHelp, oContext, aRows[0]);\n }\n }\n };\n var oDialog = new TableSelectDialog({\n title: oHelp.label,\n multiSelect: bMulti,\n growing: true,\n growingThreshold: 50,\n columns: aColumns.map(function (c) {\n return new Column({ header: new Text({ text: c.label }) });\n }),\n search: function (oEvent) {\n oEvent.getSource().getBinding(\"items\").filter(support.valueHelpSearch(oHelp, mTexts, oEvent.getParameter(\"value\"), aBase));\n },\n confirm: function (oEvent) {\n var aItems = oEvent.getParameter(\"selectedItems\") || [];\n done(aItems.map(function (oItem) {\n return String(oItem.getBindingContext().getProperty(oHelp.element));\n }), aItems.map(function (oItem) {\n return oItem.getBindingContext().getObject();\n }));\n },\n cancel: function () {\n done([]);\n },\n afterClose: function () {\n done([]);\n oDialog.destroy();\n }\n });\n oDialog.bindAggregation(\"items\", support.valueHelpItems(oHelp, aColumns, mTexts, aBase));\n oView.addDependent(oDialog);\n oDialog.open();\n });\n },\n\n errorText: function (oError) {\n var aMessages = Messaging.getMessageModel().getData().filter(function (m) {\n return m.getType() === \"Error\";\n });\n if (aMessages.length > 0) {\n return aMessages.map(function (m) { return m.getMessage(); }).join(\"\\n\");\n }\n return oError && oError.message ? oError.message : \"The request failed\";\n }\n };\n return support;\n});\n";
|
|
26
|
+
/**
|
|
27
|
+
* The conditions of the filter fields (D51, D68), written as in SAP Fiori elements: `=x`, `!=x`,
|
|
28
|
+
* `>x`, `>=x`, `<x`, `<=x`, `a...b`, `*x*`, `x*`, `*x`, `<empty>`, and the exclusions `!(…)`; a
|
|
29
|
+
* value alone is "contains" for a free text, "equal" otherwise. The operators of a field depend on
|
|
30
|
+
* its type and on `@Consumption.filter.selectionType`. Pure functions (no control): unit tested in
|
|
31
|
+
* Node.js with a stub of `sap.ui.define`.
|
|
32
|
+
*/
|
|
33
|
+
export declare const FILTERS = "sap.ui.define([\n \"sap/ui/model/Filter\",\n \"sap/ui/model/FilterOperator\",\n \"sap/ui/core/format/DateFormat\"\n], function (Filter, FilterOperator, DateFormat) {\n \"use strict\";\n\n var NUMERIC = { integer: true, decimal: true, amount: true };\n var DAYS = { date: true, datetime: true };\n var PREFIXES = [[\"!=\", \"NE\"], [\">=\", \"GE\"], [\"<=\", \"LE\"], [\">\", \"GT\"], [\"<\", \"LT\"], [\"=\", \"EQ\"]];\n var SIGNS = { EQ: \"=\", NE: \"!=\", GT: \">\", GE: \">=\", LT: \"<\", LE: \"<=\" };\n var EMPTY = \"<empty>\";\n /** The operators of \"Define Conditions\"; an exclusion names the operator it negates. */\n var OPERATORS = {\n EQ: { text: \"equal to\", values: 1 },\n Contains: { text: \"contains\", values: 1 },\n StartsWith: { text: \"starts with\", values: 1 },\n EndsWith: { text: \"ends with\", values: 1 },\n BT: { text: \"between\", values: 2 },\n LT: { text: \"less than\", values: 1 },\n LE: { text: \"less than or equal to\", values: 1 },\n GT: { text: \"greater than\", values: 1 },\n GE: { text: \"greater than or equal to\", values: 1 },\n Empty: { text: \"empty\", values: 0 },\n NE: { text: \"not equal to\", values: 1, exclude: \"EQ\" },\n NotContains: { text: \"does not contain\", values: 1, exclude: \"Contains\" },\n NotStartsWith: { text: \"does not start with\", values: 1, exclude: \"StartsWith\" },\n NotEndsWith: { text: \"does not end with\", values: 1, exclude: \"EndsWith\" },\n NB: { text: \"not between\", values: 2, exclude: \"BT\" },\n NOTLT: { text: \"not less than\", values: 1, exclude: \"LT\" },\n NOTLE: { text: \"not less than or equal to\", values: 1, exclude: \"LE\" },\n NOTGT: { text: \"not greater than\", values: 1, exclude: \"GT\" },\n NOTGE: { text: \"not greater than or equal to\", values: 1, exclude: \"GE\" },\n NotEmpty: { text: \"not empty\", values: 0, exclude: \"Empty\" }\n };\n var COMPARISONS = [\"EQ\", \"BT\", \"LT\", \"LE\", \"GT\", \"GE\"];\n var PATTERNS = { Contains: true, StartsWith: true, EndsWith: true, NotContains: true, NotStartsWith: true, NotEndsWith: true };\n /** The exclusions of comparisons as the opposite comparison: not less than 5 is 5 or more. */\n var OPPOSITE = { NOTLT: \"GE\", NOTLE: \"GT\", NOTGT: \"LE\", NOTGE: \"LT\" };\n\n function negation(sOp) {\n return Object.keys(OPERATORS).find(function (k) { return OPERATORS[k].exclude === sOp; });\n }\n\n function pad(n) {\n return String(n).padStart(2, \"0\");\n }\n\n /** A date typed or picked: ISO (yyyy-MM-dd), or in the format of the locale. */\n function day(sValue) {\n var aIso = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(sValue);\n if (aIso) {\n var oDate = new Date(Date.UTC(Number(aIso[1]), Number(aIso[2]) - 1, Number(aIso[3])));\n return oDate.getUTCMonth() === Number(aIso[2]) - 1 && oDate.getUTCDate() === Number(aIso[3]) ? sValue : null;\n }\n if (!DateFormat) {\n return null;\n }\n var oParsed = [\"medium\", \"short\", \"long\"].map(function (sStyle) {\n return DateFormat.getDateInstance({ style: sStyle }).parse(sValue);\n }).find(function (o) { return o && !isNaN(o.getTime()); });\n return oParsed ? oParsed.getFullYear() + \"-\" + pad(oParsed.getMonth() + 1) + \"-\" + pad(oParsed.getDate()) : null;\n }\n\n /** The value of a condition as kept in the token key: dates in ISO, times as HH:mm:ss; null when invalid. */\n function normalize(oField, sValue) {\n var s = String(sValue === null || sValue === undefined ? \"\" : sValue).trim();\n if (DAYS[oField.kind]) {\n return s === \"\" ? null : day(s);\n }\n if (oField.kind === \"time\") {\n var aTime = /^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/.exec(s);\n return aTime && Number(aTime[1]) < 24 && Number(aTime[2]) < 60 ? pad(aTime[1]) + \":\" + aTime[2] + \":\" + (aTime[3] || \"00\") : null;\n }\n return valid(oField, s) ? s : null;\n }\n\n function valid(oField, sValue) {\n if (sValue === \"\") {\n return false;\n }\n if (NUMERIC[oField.kind]) {\n return /^[-+]?\\d*[.,]?\\d+$/.test(sValue);\n }\n if (oField.kind === \"digits\") {\n return /^\\d+$/.test(sValue) && (!oField.maxLength || sValue.length <= oField.maxLength);\n }\n if (oField.kind === \"uuid\") {\n return /^[0-9a-fA-F-]+$/.test(sValue);\n }\n return true;\n }\n\n var filters = {\n /** The operators allowed for a field: its type, then `@Consumption.filter.selectionType` (FilterExpressionRestrictions). */\n operators: function (oField) {\n var aInclude;\n if (oField.kind === \"boolean\" || oField.kind === \"enum\") {\n return [\"EQ\"];\n }\n if (oField.kind === \"uuid\") {\n aInclude = [\"EQ\"];\n } else if (oField.kind === \"text\") {\n aInclude = [\"EQ\", \"Contains\", \"StartsWith\", \"EndsWith\", \"BT\", \"LT\", \"LE\", \"GT\", \"GE\", \"Empty\"];\n } else if (DAYS[oField.kind] || oField.kind === \"time\") {\n aInclude = COMPARISONS.concat([\"Empty\"]);\n } else {\n aInclude = COMPARISONS.slice();\n }\n var sAllowed = oField.filter && oField.filter.expressions;\n if (sAllowed === \"SingleValue\") {\n return [\"EQ\"];\n }\n if (sAllowed === \"SingleRange\" || sAllowed === \"MultiRange\") {\n aInclude = aInclude.filter(function (op) { return COMPARISONS.indexOf(op) >= 0; });\n }\n // one range: no exclusion\n return sAllowed === \"SingleRange\" ? aInclude : aInclude.concat(aInclude.map(negation).filter(Boolean));\n },\n\n /** The label of an operator (\"equal to\"), and the number of its values (0, 1 or 2). */\n label: function (sOp) {\n return OPERATORS[sOp] ? OPERATORS[sOp].text : sOp;\n },\n\n valueCount: function (sOp) {\n return OPERATORS[sOp] ? OPERATORS[sOp].values : 1;\n },\n\n /** An exclusion: and'ed with the other conditions of the field (the included ones are or'ed). */\n isExclude: function (sOp) {\n return !!(OPERATORS[sOp] && OPERATORS[sOp].exclude);\n },\n\n /** The operator of a value typed alone: \"contains\" for a free text, \"equal to\" for a key or a value help. */\n defaultOperator: function (oField) {\n return oField.kind === \"text\" && !oField.key && !oField.valueHelp && filters.operators(oField).indexOf(\"Contains\") >= 0 ? \"Contains\" : \"EQ\";\n },\n\n /** The condition of an operator and its values (the rows of \"Define Conditions\"); null when not valid for the field. */\n condition: function (oField, sOp, aValues) {\n if (!OPERATORS[sOp] || filters.operators(oField).indexOf(sOp) < 0) {\n return null;\n }\n var aNormalized = (aValues || []).slice(0, OPERATORS[sOp].values).map(function (v) { return normalize(oField, v); });\n if (aNormalized.length < OPERATORS[sOp].values || aNormalized.some(function (v) { return v === null; })) {\n return null;\n }\n return { op: sOp, values: aNormalized };\n },\n\n /** The condition of a text typed in a filter field (or of a token key); null when it is not valid for the field. */\n parse: function (oField, sText) {\n var oRead = filters._read(oField, String(sText).trim());\n return oRead ? filters.condition(oField, oRead.op, oRead.values) : null;\n },\n\n _read: function (oField, sValue) {\n if (sValue === \"\") {\n return null;\n }\n if (sValue === EMPTY) {\n return { op: \"Empty\", values: [] };\n }\n if (sValue.indexOf(\"!(\") === 0 && sValue[sValue.length - 1] === \")\") {\n var oInner = filters._read(oField, sValue.slice(2, -1).trim());\n var sNot = oInner && negation(oInner.op);\n return sNot ? { op: sNot, values: oInner.values } : null;\n }\n var iRange = sValue.indexOf(\"...\");\n var aDays = DAYS[oField.kind] && iRange < 0 ? sValue.split(\" - \") : [];\n if (iRange > 0 && !/^[!<>=]/.test(sValue)) {\n return { op: \"BT\", values: [sValue.slice(0, iRange).trim(), sValue.slice(iRange + 3).trim()] };\n }\n if (aDays.length === 2) {\n return { op: \"BT\", values: [aDays[0].trim(), aDays[1].trim()] };\n }\n var aPrefix = PREFIXES.find(function (p) { return sValue.indexOf(p[0]) === 0; });\n if (aPrefix) {\n return { op: aPrefix[1], values: [sValue.slice(aPrefix[0].length).trim()] };\n }\n if (oField.kind === \"text\" && sValue.length > 1 && sValue[0] === \"*\" && sValue[sValue.length - 1] === \"*\") {\n return { op: \"Contains\", values: [sValue.slice(1, -1)] };\n }\n if (oField.kind === \"text\" && sValue.length > 1 && sValue[sValue.length - 1] === \"*\") {\n return { op: \"StartsWith\", values: [sValue.slice(0, -1)] };\n }\n if (oField.kind === \"text\" && sValue.length > 1 && sValue[0] === \"*\") {\n return { op: \"EndsWith\", values: [sValue.slice(1)] };\n }\n return { op: filters.defaultOperator(oField), values: [sValue] };\n },\n\n /** The text of a condition, kept as the key of its token (parsed back by parse). */\n text: function (oCondition) {\n var v = oCondition.values;\n switch (oCondition.op) {\n case \"Empty\": return EMPTY;\n case \"BT\": return v[0] + \"...\" + v[1];\n case \"Contains\": return \"*\" + v[0] + \"*\";\n case \"StartsWith\": return v[0] + \"*\";\n case \"EndsWith\": return \"*\" + v[0];\n default:\n if (SIGNS[oCondition.op]) {\n return SIGNS[oCondition.op] + v[0];\n }\n return \"!(\" + filters.text({ op: OPERATORS[oCondition.op].exclude, values: v }) + \")\";\n }\n },\n\n /**\n * The text shown in the token, as SAP Fiori elements: \"equal to\" without its sign (with the\n * description of a value help: \"Euro (EUR)\"), exclusions as `!(\u2026)`, dates in the format of the locale.\n */\n display: function (oField, oCondition, sDescription) {\n var aValues = oCondition.values.map(function (v) { return filters.format(oField, v); });\n if (oCondition.op === \"EQ\") {\n return sDescription ? sDescription + \" (\" + aValues[0] + \")\" : aValues[0];\n }\n if (oCondition.op === \"NE\") {\n return \"!(=\" + aValues[0] + \")\";\n }\n return filters.text({ op: oCondition.op, values: aValues });\n },\n\n /** A value as shown to the user (a date in the medium format of the locale). */\n format: function (oField, sValue) {\n if (DAYS[oField.kind] && DateFormat && /^\\d{4}-\\d{2}-\\d{2}$/.test(sValue)) {\n var a = sValue.split(\"-\");\n return DateFormat.getDateInstance({ style: \"medium\" }).format(new Date(Number(a[0]), Number(a[1]) - 1, Number(a[2])));\n }\n return sValue;\n },\n\n /** The value sent to the service: NUMC with its leading zeros, decimal point. */\n value: function (oField, sValue) {\n if (oField.kind === \"digits\" && oField.maxLength && /^\\d+$/.test(sValue)) {\n return sValue.padStart(oField.maxLength, \"0\");\n }\n if (NUMERIC[oField.kind]) {\n return sValue.replace(\",\", \".\").replace(/^\\+/, \"\");\n }\n if (oField.kind === \"uuid\") {\n return sValue.toLowerCase();\n }\n return sValue;\n },\n\n /** The filter of a condition. */\n filter: function (oField, oCondition) {\n var v = oCondition.values.map(function (s) { return filters.value(oField, s); });\n var sPath = oField.property;\n var sOp = OPPOSITE[oCondition.op] || oCondition.op;\n if (sOp === \"Empty\" || sOp === \"NotEmpty\") {\n // a text is empty when initial ('') or null; another type when null\n var bNot = sOp === \"NotEmpty\";\n var oNull = new Filter(sPath, bNot ? FilterOperator.NE : FilterOperator.EQ, null);\n return oField.edm === \"Edm.String\" ? new Filter({ filters: [new Filter(sPath, bNot ? FilterOperator.NE : FilterOperator.EQ, \"\"), oNull], and: bNot }) : oNull;\n }\n if (oField.kind === \"datetime\") {\n return filters._days(sPath, sOp, v);\n }\n if (sOp === \"BT\" || sOp === \"NB\") {\n return new Filter({ path: sPath, operator: FilterOperator[sOp], value1: v[0], value2: v[1] });\n }\n if (PATTERNS[sOp]) {\n return new Filter({ path: sPath, operator: FilterOperator[sOp], value1: v[0], caseSensitive: false });\n }\n return new Filter({ path: sPath, operator: FilterOperator[sOp], value1: v[0], caseSensitive: oField.kind === \"text\" ? true : undefined });\n },\n\n /** A condition on the days of a date-time (Edm.DateTimeOffset): whole days, UTC. */\n _days: function (sPath, sOp, v) {\n var start = function (s) { return s + \"T00:00:00Z\"; };\n var next = function (s) {\n var oNext = new Date(s + \"T00:00:00Z\");\n oNext.setUTCDate(oNext.getUTCDate() + 1);\n return oNext.toISOString().slice(0, 10) + \"T00:00:00Z\";\n };\n var range = function (sFrom, sTo, bNot) {\n return new Filter({\n filters: [\n new Filter(sPath, bNot ? FilterOperator.LT : FilterOperator.GE, start(sFrom)),\n new Filter(sPath, bNot ? FilterOperator.GE : FilterOperator.LT, next(sTo))\n ],\n and: !bNot\n });\n };\n switch (sOp) {\n case \"EQ\": return range(v[0], v[0], false);\n case \"NE\": return range(v[0], v[0], true);\n case \"BT\": return range(v[0], v[1], false);\n case \"NB\": return range(v[0], v[1], true);\n case \"LT\": return new Filter(sPath, FilterOperator.LT, start(v[0]));\n case \"LE\": return new Filter(sPath, FilterOperator.LT, next(v[0]));\n case \"GT\": return new Filter(sPath, FilterOperator.GE, next(v[0]));\n default: return new Filter(sPath, FilterOperator.GE, start(v[0]));\n }\n },\n\n /** The filter of the conditions of one field: included values or'ed, exclusions and'ed. */\n fieldFilter: function (oField, aConditions) {\n var aInclude = [];\n var aExclude = [];\n aConditions.forEach(function (c) {\n (filters.isExclude(c.op) ? aExclude : aInclude).push(filters.filter(oField, c));\n });\n var aParts = [];\n if (aInclude.length === 1) {\n aParts.push(aInclude[0]);\n } else if (aInclude.length > 1) {\n aParts.push(new Filter({ filters: aInclude, and: false }));\n }\n aParts = aParts.concat(aExclude);\n if (aParts.length === 0) {\n return null;\n }\n return aParts.length === 1 ? aParts[0] : new Filter({ filters: aParts, and: true });\n },\n\n /**\n * A filter as an OData $filter expression (the chart of the Analytical List Page and the counts\n * of the worklist tabs send their own requests). mFields: property \u2192 field of the layout.\n */\n toOData: function (oFilter, mFields) {\n if (!oFilter) {\n return \"\";\n }\n var aInner = oFilter.aFilters || (oFilter.getFilters && oFilter.getFilters()) || (oFilter.spec && oFilter.spec.filters);\n if (aInner && aInner.length) {\n var bAnd = oFilter.bAnd !== undefined ? oFilter.bAnd : oFilter.spec ? !!oFilter.spec.and : !!(oFilter.isAnd && oFilter.isAnd());\n return \"(\" + aInner.map(function (f) { return filters.toOData(f, mFields); }).join(bAnd ? \" and \" : \" or \") + \")\";\n }\n var sPath = oFilter.sPath || (oFilter.spec && oFilter.spec.path);\n var sOp = oFilter.sOperator || (oFilter.spec && oFilter.spec.operator);\n var v1 = oFilter.oValue1 !== undefined ? oFilter.oValue1 : oFilter.spec && oFilter.spec.value1;\n var v2 = oFilter.oValue2 !== undefined ? oFilter.oValue2 : oFilter.spec && oFilter.spec.value2;\n var bCaseInsensitive = oFilter.bCaseSensitive === false || (oFilter.spec && oFilter.spec.caseSensitive === false);\n var oField = (mFields && mFields[sPath]) || { edm: \"Edm.String\" };\n var literal = function (v) {\n if (v === null || v === undefined) { return \"null\"; }\n if (oField.edm === \"Edm.String\") { return \"'\" + String(v).replace(/'/g, \"''\") + \"'\"; }\n return String(v);\n };\n var sLeft = bCaseInsensitive ? \"tolower(\" + sPath + \")\" : sPath;\n var lit = function (v) { return bCaseInsensitive ? \"tolower(\" + literal(v) + \")\" : literal(v); };\n switch (sOp) {\n case \"BT\": return \"(\" + sPath + \" ge \" + literal(v1) + \" and \" + sPath + \" le \" + literal(v2) + \")\";\n case \"NB\": return \"(\" + sPath + \" lt \" + literal(v1) + \" or \" + sPath + \" gt \" + literal(v2) + \")\";\n case \"Contains\": return \"contains(\" + sLeft + \",\" + lit(v1) + \")\";\n case \"StartsWith\": return \"startswith(\" + sLeft + \",\" + lit(v1) + \")\";\n case \"EndsWith\": return \"endswith(\" + sLeft + \",\" + lit(v1) + \")\";\n case \"NotContains\": return \"not contains(\" + sLeft + \",\" + lit(v1) + \")\";\n case \"NotStartsWith\": return \"not startswith(\" + sLeft + \",\" + lit(v1) + \")\";\n case \"NotEndsWith\": return \"not endswith(\" + sLeft + \",\" + lit(v1) + \")\";\n default: return sPath + \" \" + String(sOp).toLowerCase() + \" \" + literal(v1);\n }\n }\n };\n return filters;\n});\n";
|
|
34
|
+
/**
|
|
35
|
+
* The value help of a filter field (D68), as in SAP Fiori elements, built from sap.m (the value
|
|
36
|
+
* help dialog of sap.ui.comp / sap.ui.mdc is SAPUI5 only): "Search and Select" lists the values of
|
|
37
|
+
* the value help, "Define Conditions" has one operator and its values per row, and the selected
|
|
38
|
+
* items and conditions are tokens below.
|
|
39
|
+
*/
|
|
40
|
+
export declare const CONDITIONS = "sap.ui.define([\n \"sap/m/Dialog\",\n \"sap/m/Button\",\n \"sap/m/IconTabBar\",\n \"sap/m/IconTabFilter\",\n \"sap/m/VBox\",\n \"sap/m/HBox\",\n \"sap/m/FlexItemData\",\n \"sap/m/Select\",\n \"sap/ui/core/Item\",\n \"sap/m/Input\",\n \"sap/m/DatePicker\",\n \"sap/m/TimePicker\",\n \"sap/m/SearchField\",\n \"sap/m/Table\",\n \"sap/m/Column\",\n \"sap/m/Text\",\n \"sap/m/Title\",\n \"sap/m/Tokenizer\",\n \"sap/m/Token\",\n \"sap/m/ScrollContainer\",\n \"sap/ui/model/json/JSONModel\",\n \"rapt/app/controller/support\",\n \"rapt/app/controller/filters\"\n], function (Dialog, Button, IconTabBar, IconTabFilter, VBox, HBox, FlexItemData, Select, Item, Input, DatePicker, TimePicker, SearchField, Table, Column, Text, Title, Tokenizer, Token, ScrollContainer, JSONModel, support, filters) {\n \"use strict\";\n\n function blank(sOp) {\n return { op: sOp, v1: \"\", v2: \"\", error: false };\n }\n\n function dialog(oView, oField, aInitial, mTexts) {\n var oHelp = oField.valueHelp;\n var aOperators = filters.operators(oField);\n var bSingle = !!(oField.filter && oField.filter.single);\n var bSelect = !!oHelp;\n var bDefine = !(bSelect && aOperators.length === 1);\n var sDefault = filters.defaultOperator(oField);\n var oModel = new JSONModel({ items: [], rows: [] });\n var aItems = [];\n var aRows = [];\n aInitial.forEach(function (c) {\n if (bSelect && c.condition.op === \"EQ\") {\n aItems.push({ value: c.condition.values[0], text: c.text });\n } else if (bDefine) {\n aRows.push({ op: c.condition.op, v1: c.condition.values[0] || \"\", v2: c.condition.values[1] || \"\", error: false });\n }\n });\n if (bDefine && aRows.length === 0) {\n aRows.push(blank(sDefault));\n }\n oModel.setData({ items: aItems, rows: aRows });\n\n var isBlank = function (r) {\n return filters.valueCount(r.op) > 0 && String(r.v1 || \"\").trim() === \"\" && String(r.v2 || \"\").trim() === \"\";\n };\n var rowCondition = function (r) {\n return isBlank(r) ? null : filters.condition(oField, r.op, [r.v1, r.v2]);\n };\n var itemText = function (sValue) {\n return filters.display(oField, { op: \"EQ\", values: [sValue] }, mTexts[sValue]);\n };\n\n return new Promise(function (resolve) {\n var bDone = false;\n var done = function (aResult) {\n if (!bDone) {\n bDone = true;\n resolve(aResult);\n }\n };\n var oTable;\n var oTokenizer;\n var oTitle;\n\n /** Selects the rows of the table that are chosen items. */\n var syncSelection = function () {\n if (!oTable) {\n return;\n }\n var aValues = oModel.getProperty(\"/items\").map(function (it) { return filters.value(oField, String(it.value)); });\n oTable.getItems().forEach(function (oItem) {\n var oContext = oItem.getBindingContext();\n if (oContext) {\n oItem.setSelected(aValues.indexOf(filters.value(oField, String(oContext.getProperty(oHelp.element)))) >= 0);\n }\n });\n };\n\n /** The tokens of the chosen items and of the valid conditions. */\n var refresh = function () {\n var aCurrentRows = oModel.getProperty(\"/rows\");\n if (bSingle && aCurrentRows.some(rowCondition) && oModel.getProperty(\"/items\").length > 0) {\n oModel.setProperty(\"/items\", []);\n syncSelection();\n }\n oTokenizer.destroyTokens();\n oModel.getProperty(\"/items\").forEach(function (it, i) {\n oTokenizer.addToken(new Token({ key: \"i\" + i, text: it.text }));\n });\n aCurrentRows.forEach(function (r, i) {\n var oCondition = rowCondition(r);\n if (oCondition || isBlank(r)) {\n oModel.setProperty(\"/rows/\" + i + \"/error\", false);\n }\n if (oCondition) {\n oTokenizer.addToken(new Token({ key: \"r\" + i, text: filters.display(oField, oCondition) }));\n }\n });\n oTitle.setText(\"Selected Items and Conditions (\" + oTokenizer.getTokens().length + \")\");\n };\n\n var removeRow = function (i) {\n var aList = oModel.getProperty(\"/rows\").slice();\n aList.splice(i, 1);\n if (aList.length === 0) {\n aList.push(blank(sDefault));\n }\n oModel.setProperty(\"/rows\", aList);\n };\n\n var valueControl = function (sProperty, bSecond, oContext) {\n var oControl;\n if (oField.kind === \"date\" || oField.kind === \"datetime\") {\n oControl = new DatePicker({ valueFormat: \"yyyy-MM-dd\", value: \"{cond>\" + sProperty + \"}\" });\n } else if (oField.kind === \"time\") {\n oControl = new TimePicker({ valueFormat: \"HH:mm:ss\", value: \"{cond>\" + sProperty + \"}\" });\n } else {\n oControl = new Input({\n value: \"{cond>\" + sProperty + \"}\",\n showValueHelp: bSelect,\n valueHelpRequest: function () {\n support.valueHelp(oView, oHelp, false).then(function (aValues) {\n if (aValues.length > 0) {\n oModel.setProperty(oContext.getPath() + \"/\" + sProperty, aValues[0]);\n refresh();\n }\n });\n }\n });\n }\n oControl.bindProperty(\"visible\", { path: \"cond>op\", formatter: function (sOp) { return filters.valueCount(sOp) > (bSecond ? 1 : 0); } });\n oControl.bindProperty(\"valueState\", { path: \"cond>error\", formatter: function (bError) { return bError ? \"Error\" : \"None\"; } });\n oControl.setValueStateText(\"Enter a valid value\");\n oControl.setLayoutData(new FlexItemData({ growFactor: 1, baseSize: \"0\" }));\n return oControl.addStyleClass(\"raptConditionValue\");\n };\n\n var oRows = new VBox(oView.createId(\"conditionsRows\"), {\n items: {\n path: \"cond>/rows\",\n factory: function (sId, oContext) {\n return new HBox(sId, {\n alignItems: \"Center\",\n items: [\n new Select({\n width: \"15rem\",\n selectedKey: \"{cond>op}\",\n items: aOperators.map(function (op) { return new Item({ key: op, text: filters.label(op) }); }),\n change: refresh\n }).addStyleClass(\"raptConditionOperator\"),\n new HBox({\n layoutData: new FlexItemData({ growFactor: 1, baseSize: \"0\" }),\n items: [valueControl(\"v1\", false, oContext), valueControl(\"v2\", true, oContext)]\n }),\n new Button({\n icon: \"sap-icon://decline\",\n type: \"Transparent\",\n tooltip: \"Remove Condition\",\n press: function () {\n removeRow(Number(oContext.getPath().split(\"/\").pop()));\n refresh();\n }\n })\n ]\n }).addStyleClass(\"raptConditionRow\");\n }\n }\n });\n var oAdd = new Button(oView.createId(\"conditionsAdd\"), {\n text: \"Add\",\n icon: \"sap-icon://add\",\n visible: !bSingle,\n press: function () {\n oModel.setProperty(\"/rows\", oModel.getProperty(\"/rows\").concat([blank(sDefault)]));\n }\n });\n // with a value help, the tabs scroll and the tokens stay visible below them\n var scroll = function (oContent) {\n return bSelect ? new ScrollContainer({ height: \"22rem\", vertical: true, horizontal: false, content: [oContent] }) : oContent;\n };\n var oDefine = scroll(new VBox({ items: [oRows, new HBox({ justifyContent: \"End\", items: [oAdd] })] }).addStyleClass(\"sapUiTinyMarginTop\"));\n var oSearch;\n\n var oSelect;\n if (bSelect) {\n var aColumns = support.valueHelpColumns(oHelp, mTexts);\n oTable = new Table(oView.createId(\"conditionsTable\"), {\n mode: bSingle ? \"SingleSelectLeft\" : \"MultiSelect\",\n includeItemInSelection: true,\n growing: true,\n growingThreshold: 20,\n columns: aColumns.map(function (c) { return new Column({ header: new Text({ text: c.label }) }); }),\n updateFinished: syncSelection,\n selectionChange: function (oEvent) {\n var bSelected = oEvent.getParameter(\"selected\");\n var aList = bSingle && bSelected ? [] : oModel.getProperty(\"/items\").slice();\n (oEvent.getParameter(\"listItems\") || []).forEach(function (oItem) {\n var sValue = String(oItem.getBindingContext().getProperty(oHelp.element));\n var iIndex = aList.findIndex(function (it) { return filters.value(oField, String(it.value)) === filters.value(oField, sValue); });\n if (bSelected && iIndex < 0) {\n aList.push({ value: sValue, text: itemText(sValue) });\n } else if (!bSelected && iIndex >= 0) {\n aList.splice(iIndex, 1);\n }\n });\n oModel.setProperty(\"/items\", aList);\n if (bSingle && bSelected && bDefine) {\n oModel.setProperty(\"/rows\", [blank(sDefault)]);\n }\n refresh();\n }\n });\n oTable.bindAggregation(\"items\", support.valueHelpItems(oHelp, aColumns, mTexts, []));\n oSearch = new SearchField(oView.createId(\"conditionsSearch\"), {\n width: \"100%\",\n search: function (oEvent) {\n oTable.getBinding(\"items\").filter(support.valueHelpSearch(oHelp, mTexts, oEvent.getParameter(\"query\"), []));\n }\n });\n oSelect = new VBox({ items: [oSearch.addStyleClass(\"sapUiTinyMarginTop\"), scroll(oTable)] });\n }\n\n var oMain = oSelect && bDefine\n ? new IconTabBar(oView.createId(\"conditionsTabs\"), {\n expandable: false,\n selectedKey: aItems.length === 0 && aInitial.length > 0 ? \"define\" : \"select\",\n items: [\n new IconTabFilter({ key: \"select\", text: \"Search and Select\", content: [oSelect] }),\n new IconTabFilter({ key: \"define\", text: \"Define Conditions\", content: [oDefine] })\n ]\n }).addStyleClass(\"sapUiNoContentPadding\")\n : oSelect || oDefine;\n oTitle = new Title({ text: \"\", level: \"H6\" }).addStyleClass(\"sapUiSmallMarginTop sapUiTinyMarginBottom\");\n oTokenizer = new Tokenizer(oView.createId(\"conditionsTokens\"), {\n width: \"100%\",\n renderMode: \"Loose\",\n tokenDelete: function (oEvent) {\n var aKeys = (oEvent.getParameter(\"tokens\") || []).map(function (t) { return t.getKey(); });\n var aRowIndexes = [];\n oModel.setProperty(\"/items\", oModel.getProperty(\"/items\").filter(function (_it, i) { return aKeys.indexOf(\"i\" + i) < 0; }));\n aKeys.forEach(function (k) {\n if (k[0] === \"r\") {\n aRowIndexes.push(Number(k.slice(1)));\n }\n });\n aRowIndexes.sort(function (a, b) { return b - a; }).forEach(removeRow);\n syncSelection();\n refresh();\n }\n });\n\n var oDialog = new Dialog(oView.createId(\"conditions\"), {\n title: oField.label,\n contentWidth: bSelect ? \"60rem\" : \"46rem\",\n initialFocus: oSearch,\n resizable: true,\n draggable: true,\n content: [new VBox({ items: [oMain, oTitle, oTokenizer] }).addStyleClass(\"sapUiSmallMargin\")],\n beginButton: new Button(oView.createId(\"conditionsOk\"), {\n text: \"OK\",\n type: \"Emphasized\",\n press: function () {\n var bError = false;\n var aConditions = [];\n oModel.getProperty(\"/rows\").forEach(function (r, i) {\n var oCondition = rowCondition(r);\n var bWrong = !oCondition && !isBlank(r);\n oModel.setProperty(\"/rows/\" + i + \"/error\", bWrong);\n bError = bError || bWrong;\n if (oCondition) {\n aConditions.push({ condition: oCondition, text: filters.display(oField, oCondition) });\n }\n });\n if (bError) {\n if (oMain.setSelectedKey) {\n oMain.setSelectedKey(\"define\");\n }\n return;\n }\n var aResult = oModel.getProperty(\"/items\").map(function (it) {\n return { condition: { op: \"EQ\", values: [it.value] }, text: it.text };\n }).concat(aConditions).filter(function (c, i, a) {\n return a.findIndex(function (o) { return filters.text(o.condition) === filters.text(c.condition); }) === i;\n });\n done(bSingle ? aResult.slice(-1) : aResult);\n oDialog.close();\n }\n }),\n endButton: new Button(oView.createId(\"conditionsCancel\"), {\n text: \"Cancel\",\n press: function () {\n oDialog.close();\n }\n }),\n afterClose: function () {\n done(null);\n oDialog.destroy();\n }\n });\n oDialog.setModel(oModel, \"cond\");\n oModel.attachPropertyChange(refresh);\n oView.addDependent(oDialog);\n refresh();\n oDialog.open();\n });\n }\n\n return {\n /**\n * Opens the value help of a filter field. aConditions: the current conditions, [{ condition,\n * text }]; resolves the new ones, or null when cancelled.\n */\n open: function (oView, oField, aConditions) {\n var oTexts = oField.valueHelp ? support.valueHelpTexts(oView, oField.valueHelp) : Promise.resolve({});\n return oTexts.then(function (mTexts) {\n return dialog(oView, oField, aConditions, mTexts);\n });\n }\n };\n});\n";
|
|
41
|
+
/**
|
|
42
|
+
* A chart of the Analytical List Page and of the cards (D53): an SVG drawn by the control itself —
|
|
43
|
+
* columns, bars, line, pie, donut — from the groups of a `$apply` (OpenUI5 has no chart library:
|
|
44
|
+
* sap.viz exists in SAPUI5 only). Clicking a column selects its dimension value (event select).
|
|
45
|
+
*/
|
|
46
|
+
export declare const CHART = "sap.ui.define([\"sap/ui/core/Control\"], function (Control) {\n \"use strict\";\n\n var COLORS = [\"var(--sapChart_OrderedColor_1, #168eff)\", \"var(--sapChart_OrderedColor_2, #c87b00)\", \"var(--sapChart_OrderedColor_3, #75980b)\", \"var(--sapChart_OrderedColor_4, #df1278)\", \"var(--sapChart_OrderedColor_5, #8b47d7)\", \"var(--sapChart_OrderedColor_6, #049f9a)\"];\n\n function esc(s) {\n return String(s).replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\");\n }\n\n function fmt(n) {\n var a = Math.abs(n);\n if (a >= 1e9) { return (n / 1e9).toFixed(1) + \"B\"; }\n if (a >= 1e6) { return (n / 1e6).toFixed(1) + \"M\"; }\n if (a >= 1e4) { return (n / 1e3).toFixed(1) + \"K\"; }\n return Math.round(n * 100) / 100 + \"\";\n }\n\n return Control.extend(\"rapt.app.controller.Chart\", {\n metadata: {\n properties: {\n type: { type: \"string\", defaultValue: \"column\" },\n height: { type: \"sap.ui.core.CSSSize\", defaultValue: \"16rem\" },\n selected: { type: \"string\", defaultValue: \"\" },\n noDataText: { type: \"string\", defaultValue: \"No data\" }\n },\n events: { select: { parameters: { value: { type: \"string\" } } } }\n },\n\n /** aRows: [{ key, label, values: [number\u2026] }]; aMeasures: [label\u2026]. */\n setData: function (aRows, aMeasures) {\n this._aRows = aRows || [];\n this._aMeasures = aMeasures || [];\n this.invalidate();\n return this;\n },\n\n getData: function () {\n return this._aRows || [];\n },\n\n renderer: {\n apiVersion: 2,\n render: function (rm, oChart) {\n rm.openStart(\"div\", oChart);\n rm.class(\"raptChart\");\n rm.style(\"height\", oChart.getHeight());\n rm.openEnd();\n rm.unsafeHtml(oChart._svg());\n rm.close(\"div\");\n }\n },\n\n _svg: function () {\n var aRows = this._aRows || [];\n var aMeasures = this._aMeasures || [];\n var sType = this.getType();\n var sSelected = this.getSelected();\n if (aRows.length === 0) {\n return \"<div class='raptChartEmpty'>\" + esc(this.getNoDataText()) + \"</div>\";\n }\n var W = 640, H = 260, L = 56, B = 48, T = 12, R = 12;\n var aParts = [\"<svg viewBox='0 0 \" + W + \" \" + H + \"' width='100%' height='100%' preserveAspectRatio='xMidYMid meet' role='img'>\"];\n var legend = aMeasures.length > 1 ? aMeasures.map(function (m, i) {\n return \"<rect x='\" + (L + i * 140) + \"' y='\" + (H - 14) + \"' width='10' height='10' fill='\" + COLORS[i % COLORS.length] + \"'/><text x='\" + (L + i * 140 + 14) + \"' y='\" + (H - 5) + \"' class='raptChartLabel'>\" + esc(m) + \"</text>\";\n }).join(\"\") : \"\";\n if (sType === \"pie\" || sType === \"donut\") {\n var total = aRows.reduce(function (t, r) { return t + Math.max(0, r.values[0] || 0); }, 0) || 1;\n var cx = 150, cy = H / 2, r = 100, a0 = -Math.PI / 2;\n aRows.forEach(function (row, i) {\n var v = Math.max(0, row.values[0] || 0);\n var a1 = a0 + (v / total) * Math.PI * 2;\n var large = a1 - a0 > Math.PI ? 1 : 0;\n var x0 = cx + r * Math.cos(a0), y0 = cy + r * Math.sin(a0), x1 = cx + r * Math.cos(a1), y1 = cy + r * Math.sin(a1);\n var path = aRows.length === 1 ? \"M\" + (cx - r) + \",\" + cy + \"a\" + r + \",\" + r + \" 0 1,0 \" + (2 * r) + \",0a\" + r + \",\" + r + \" 0 1,0 \" + (-2 * r) + \",0\" : \"M\" + cx + \",\" + cy + \"L\" + x0 + \",\" + y0 + \"A\" + r + \",\" + r + \" 0 \" + large + \",1 \" + x1 + \",\" + y1 + \"Z\";\n aParts.push(\"<path d='\" + path + \"' fill='\" + COLORS[i % COLORS.length] + \"' data-value='\" + esc(row.key) + \"' class='raptChartItem\" + (sSelected === row.key ? \" raptChartSelected\" : \"\") + \"'><title>\" + esc(row.label) + \": \" + esc(fmt(v)) + \"</title></path>\");\n aParts.push(\"<rect x='300' y='\" + (20 + i * 22) + \"' width='12' height='12' fill='\" + COLORS[i % COLORS.length] + \"'/><text x='318' y='\" + (31 + i * 22) + \"' class='raptChartLabel'>\" + esc(row.label) + \" (\" + esc(fmt(v)) + \")</text>\");\n a0 = a1;\n });\n if (sType === \"donut\") {\n aParts.push(\"<circle cx='\" + cx + \"' cy='\" + cy + \"' r='55' class='raptChartHole'/>\");\n }\n aParts.push(\"</svg>\");\n return aParts.join(\"\");\n }\n var max = 0, min = 0;\n aRows.forEach(function (row) {\n row.values.forEach(function (v) { max = Math.max(max, v || 0); min = Math.min(min, v || 0); });\n });\n if (max === min) { max = min + 1; }\n var plotW = W - L - R, plotH = H - T - B;\n var horizontal = sType === \"bar\";\n var scale = function (v) { return (v - min) / (max - min); };\n // axis and grid\n for (var g = 0; g <= 4; g++) {\n var gv = min + (max - min) * g / 4;\n if (horizontal) {\n var gx = L + plotW * g / 4;\n aParts.push(\"<line x1='\" + gx + \"' y1='\" + T + \"' x2='\" + gx + \"' y2='\" + (T + plotH) + \"' class='raptChartGrid'/><text x='\" + gx + \"' y='\" + (T + plotH + 14) + \"' text-anchor='middle' class='raptChartLabel'>\" + esc(fmt(gv)) + \"</text>\");\n } else {\n var gy = T + plotH - plotH * g / 4;\n aParts.push(\"<line x1='\" + L + \"' y1='\" + gy + \"' x2='\" + (L + plotW) + \"' y2='\" + gy + \"' class='raptChartGrid'/><text x='\" + (L - 6) + \"' y='\" + (gy + 4) + \"' text-anchor='end' class='raptChartLabel'>\" + esc(fmt(gv)) + \"</text>\");\n }\n }\n var n = aRows.length, m = Math.max(1, aMeasures.length);\n var band = (horizontal ? plotH : plotW) / n;\n if (sType === \"line\") {\n for (var k = 0; k < m; k++) {\n var pts = aRows.map(function (row, i) { return (L + band * (i + 0.5)) + \",\" + (T + plotH - plotH * scale(row.values[k] || 0)); });\n aParts.push(\"<polyline points='\" + pts.join(\" \") + \"' fill='none' stroke='\" + COLORS[k % COLORS.length] + \"' stroke-width='2'/>\");\n aRows.forEach(function (row, i) {\n aParts.push(\"<circle cx='\" + (L + band * (i + 0.5)) + \"' cy='\" + (T + plotH - plotH * scale(row.values[k] || 0)) + \"' r='5' fill='\" + COLORS[k % COLORS.length] + \"' data-value='\" + esc(row.key) + \"' class='raptChartItem\" + (sSelected === row.key ? \" raptChartSelected\" : \"\") + \"'><title>\" + esc(row.label) + \": \" + esc(fmt(row.values[k] || 0)) + \"</title></circle>\");\n });\n }\n } else {\n var bar = band * 0.7 / m;\n aRows.forEach(function (row, i) {\n for (var k = 0; k < m; k++) {\n var v = row.values[k] || 0;\n var size = (horizontal ? plotW : plotH) * Math.abs(scale(v) - scale(0));\n var start = band * i + band * 0.15 + bar * k;\n var cls = \"raptChartItem\" + (sSelected === row.key ? \" raptChartSelected\" : \"\");\n var tip = \"<title>\" + esc(row.label) + (m > 1 ? \" \u2013 \" + esc(aMeasures[k]) : \"\") + \": \" + esc(fmt(v)) + \"</title>\";\n if (horizontal) {\n aParts.push(\"<rect x='\" + (L + plotW * Math.min(scale(v), scale(0))) + \"' y='\" + (T + start) + \"' width='\" + size + \"' height='\" + bar + \"' fill='\" + COLORS[k % COLORS.length] + \"' data-value='\" + esc(row.key) + \"' class='\" + cls + \"'>\" + tip + \"</rect>\");\n } else {\n aParts.push(\"<rect x='\" + (L + start) + \"' y='\" + (T + plotH - plotH * Math.max(scale(v), scale(0))) + \"' width='\" + bar + \"' height='\" + size + \"' fill='\" + COLORS[k % COLORS.length] + \"' data-value='\" + esc(row.key) + \"' class='\" + cls + \"'>\" + tip + \"</rect>\");\n }\n }\n });\n }\n // category labels\n aRows.forEach(function (row, i) {\n var label = String(row.label).length > 14 ? String(row.label).slice(0, 13) + \"\u2026\" : String(row.label);\n if (horizontal) {\n aParts.push(\"<text x='\" + (L - 6) + \"' y='\" + (T + band * (i + 0.5) + 4) + \"' text-anchor='end' class='raptChartLabel'>\" + esc(label) + \"</text>\");\n } else {\n aParts.push(\"<text x='\" + (L + band * (i + 0.5)) + \"' y='\" + (T + plotH + 16) + \"' text-anchor='middle' class='raptChartLabel'>\" + esc(label) + \"</text>\");\n }\n });\n aParts.push(legend);\n aParts.push(\"</svg>\");\n return aParts.join(\"\");\n },\n\n onclick: function (oEvent) {\n var oTarget = oEvent.target && oEvent.target.closest ? oEvent.target.closest(\"[data-value]\") : null;\n if (!oTarget) {\n return;\n }\n var sValue = oTarget.getAttribute(\"data-value\");\n this.setSelected(this.getSelected() === sValue ? \"\" : sValue);\n this.fireSelect({ value: this.getSelected() });\n }\n });\n});\n";
|
|
47
|
+
/** The Overview Page (D53): counts of the list cards, data of the chart and KPI cards, navigation. */
|
|
48
|
+
export declare const OVERVIEW_CONTROLLER = "sap.ui.define([\n \"sap/ui/core/mvc/Controller\",\n \"sap/ui/model/json/JSONModel\",\n \"sap/ui/core/format/NumberFormat\",\n \"rapt/app/controller/support\"\n], function (Controller, JSONModel, NumberFormat, support) {\n \"use strict\";\n\n var oNumber = NumberFormat.getFloatInstance({ style: \"short\", maxFractionDigits: 1 });\n\n return Controller.extend(\"rapt.app.controller.Overview\", {\n onInit: function () {\n this._oOvp = new JSONModel({ counts: {}, kpi: {} });\n this.getView().setModel(this._oOvp, \"ovp\");\n this._bFirst = true;\n this.getOwnerComponent().getRouter().getRoute(\"Overview\").attachPatternMatched(this._onMatched, this);\n },\n\n _cards: function () {\n return this.getOwnerComponent().getModel(\"layout\").getProperty(\"/overview/cards\") || [];\n },\n\n _service: function () {\n return this.getOwnerComponent().getManifestEntry(\"/sap.app/dataSources/mainService/uri\");\n },\n\n _onMatched: function () {\n var that = this;\n var bStale = this.getOwnerComponent().takeStale(\"Overview\");\n this._cards().forEach(function (oCard) {\n if (oCard.type === \"chart\") {\n that._loadChart(oCard);\n } else if (oCard.type === \"kpi\") {\n that._loadKpi(oCard);\n } else if (bStale && !that._bFirst) {\n var oControl = that.byId(oCard.id + (oCard.type === \"list\" ? \"_list\" : \"_table\"));\n if (oControl && oControl.getBinding(\"items\")) {\n oControl.getBinding(\"items\").refresh();\n }\n }\n });\n this._bFirst = false;\n },\n\n _get: function (oCard, sQuery) {\n return fetch(this._service() + oCard.set + \"?\" + sQuery, { credentials: \"same-origin\", headers: { accept: \"application/json\" } })\n .then(function (r) { return r.ok ? r.json() : { value: [] }; });\n },\n\n _loadChart: function (oCard) {\n var oSpec = oCard.chart;\n var oChart = this.byId(oCard.id + \"_chart\");\n var sApply = (oCard.filter ? \"filter(\" + oCard.filter + \")/\" : \"\") + \"groupby((\" + oSpec.dimension.property + \"),aggregate(\" + oSpec.measures.map(function (m) {\n return m.property + \" with \" + m.aggregation + \" as \" + m.property;\n }).join(\",\") + \"))\";\n this._get(oCard, \"$apply=\" + encodeURIComponent(sApply) + \"&$orderby=\" + encodeURIComponent(oSpec.dimension.property) + \"&$top=20\").then(function (oData) {\n oChart.setData((oData.value || []).map(function (row) {\n var v = row[oSpec.dimension.property];\n return { key: v === null ? \"\" : String(v), label: v === null || v === \"\" ? \"(empty)\" : String(v), values: oSpec.measures.map(function (m) { return Number(row[m.property]) || 0; }) };\n }), oSpec.measures.map(function (m) { return m.label; }));\n });\n },\n\n /** A KPI: the aggregate of a measure (per currency or unit when it has one), or the count. */\n _loadKpi: function (oCard) {\n var oKpi = oCard.kpi;\n var that = this;\n var sAggregate = oKpi.aggregation === \"count\" || !oKpi.property ? \"$count as Value\" : oKpi.property + \" with \" + oKpi.aggregation + \" as Value\";\n var sApply = (oCard.filter ? \"filter(\" + oCard.filter + \")/\" : \"\") + (oKpi.unit ? \"groupby((\" + oKpi.unit + \"),aggregate(\" + sAggregate + \"))\" : \"aggregate(\" + sAggregate + \")\");\n this._get(oCard, \"$apply=\" + encodeURIComponent(sApply) + (oKpi.unit ? \"&$orderby=Value%20desc\" : \"\")).then(function (oData) {\n var aRows = oData.value || [];\n var oFirst = aRows[0] || { Value: 0 };\n that._oOvp.setProperty(\"/kpi/\" + oCard.id, {\n number: oNumber.format(Number(oFirst.Value) || 0),\n unit: oKpi.unit ? (oFirst[oKpi.unit] || \"\") : \"\",\n details: oKpi.label + (oKpi.aggregation === \"count\" ? \"\" : \" (\" + oKpi.aggregation + \")\"),\n text: aRows.length > 1 ? aRows.slice(1, 4).map(function (r) { return oNumber.format(Number(r.Value) || 0) + \" \" + (r[oKpi.unit] || \"\"); }).join(\" \u00B7 \") : \"\"\n });\n });\n },\n\n _card: function (oControl) {\n var oParent = oControl;\n while (oParent && !(oParent.data && oParent.data(\"card\"))) {\n oParent = oParent.getParent();\n }\n var sId = oParent ? oParent.data(\"card\") : \"\";\n return this._cards().find(function (c) { return c.id === sId; });\n },\n\n onCardUpdated: function (oEvent) {\n var oCard = this._card(oEvent.getSource());\n var oBinding = oEvent.getSource().getBinding(\"items\");\n if (oCard && oBinding && oBinding.isLengthFinal()) {\n this._oOvp.setProperty(\"/counts/\" + oCard.id, oEvent.getParameter(\"total\") + \"\");\n }\n },\n\n onCardHeader: function (oEvent) {\n var oCard = this._card(oEvent.getSource());\n if (oCard && oCard.navigable) {\n this.getOwnerComponent().getRouter().navTo(oCard.set + \"List\");\n }\n },\n\n onCardChartSelect: function (oEvent) {\n this.onCardHeader(oEvent);\n },\n\n onCardItem: function (oEvent) {\n var oCard = this._card(oEvent.getSource());\n var oContext = oEvent.getSource().getBindingContext();\n if (oCard && oContext) {\n this.getOwnerComponent().getRouter().navTo(oCard.set + \"Object\", { key: support.keyOf(oContext.getPath()) });\n }\n }\n });\n});\n";
|
|
49
|
+
export declare const LIST_CONTROLLER = "sap.ui.define([\n \"sap/ui/core/mvc/Controller\",\n \"sap/ui/model/Filter\",\n \"sap/ui/model/Sorter\",\n \"sap/ui/model/json/JSONModel\",\n \"sap/m/MessageBox\",\n \"sap/m/MessageToast\",\n \"sap/m/Token\",\n \"sap/m/SelectDialog\",\n \"sap/m/StandardListItem\",\n \"sap/m/p13n/Popup\",\n \"sap/m/p13n/SelectionPanel\",\n \"sap/m/p13n/SortPanel\",\n \"rapt/app/controller/support\",\n \"rapt/app/controller/filters\",\n \"rapt/app/controller/conditions\",\n \"rapt/app/controller/variants\"\n], function (Controller, Filter, Sorter, JSONModel, MessageBox, MessageToast, Token, SelectDialog, StandardListItem, P13nPopup, SelectionPanel, SortPanel, support, filters, conditions, variants) {\n \"use strict\";\n\n function id(sName) {\n return sName.replace(/[^A-Za-z0-9_]/g, \"_\");\n }\n\n var STANDARD = \"standard\";\n\n return Controller.extend(\"rapt.app.controller.List\", {\n onInit: function () {\n this._sSet = this.byId(\"page\").data(\"set\");\n var oPage = this._page();\n var oVisible = {};\n oPage.list.filterFields.forEach(function (f) {\n oVisible[f.property] = oPage.list.selectionFields.some(function (s) { return s.property === f.property; });\n });\n this._oLr = new JSONModel({ visible: oVisible, columns: {}, sort: [], active: 0, summary: \"Filtered By: None\", tableTitle: oPage.typeNamePlural, count: undefined, variant: STANDARD, defaultVariant: STANDARD, modified: false, variants: [{ key: STANDARD, title: oPage.typeNamePlural, author: \"\", changeable: false, favorite: true }], view: \"both\", chartSelection: \"\", tab: \"all\", tabCounts: {} });\n this._aFilters = [];\n this.getView().setModel(this._oLr, \"lr\");\n this._oStandard = this._state();\n if (oPage.draft) {\n // the draft condition needs the user (D58)\n var oList = this;\n this.getOwnerComponent().whenUser(function () {\n // once the table is bound to the model\n var fnApply = function () {\n if (oList.byId(\"table\").getBinding(\"items\")) {\n oList._applyTableFilters();\n } else {\n setTimeout(fnApply, 50);\n }\n };\n fnApply();\n });\n }\n // the default values of the filters (@Consumption.filter.defaultValue, D57)\n var bDefaults = false;\n oPage.list.filterFields.forEach(function (f) {\n if (f.filter && f.filter.defaultValue !== undefined) {\n bDefaults = true;\n this._oStandard.filters[f.property] = f.kind === \"boolean\" || f.kind === \"enum\" ? f.filter.defaultValue : [\"=\" + f.filter.defaultValue];\n if (this._oStandard.visible.indexOf(f.property) < 0) {\n this._oStandard.visible.push(f.property);\n }\n }\n }, this);\n this._bFilterDefaults = bDefaults;\n // the bindings of other pages do not see the changes of this one: refresh when coming back\n var oRouter = this.getOwnerComponent().getRouter();\n var oRoute = oRouter.getRoute(this._sSet + \"List\");\n if (oRoute) {\n oRoute.attachPatternMatched(this._onListMatched, this);\n }\n var that = this;\n // the chart of an Analytical List Page, the counts of the tabs of a worklist (D53)\n this._loadChart();\n this._loadTabCounts();\n this._oStore = variants.store(this.getOwnerComponent(), this._sSet + \"List\");\n this._oStore.load().then(function (oData) {\n var aItems = [that._oLr.getProperty(\"/variants/0\")].concat(oData.items.map(function (v) {\n return { key: v.key, title: v.title, author: \"\", changeable: true, favorite: v.favorite !== false, content: v.content };\n }));\n that._oLr.setProperty(\"/variants\", aItems);\n var sDefault = aItems.some(function (v) { return v.key === oData.defaultKey; }) ? oData.defaultKey : STANDARD;\n that._oLr.setProperty(\"/defaultVariant\", sDefault);\n if (sDefault !== STANDARD || that._bFilterDefaults) {\n that._selectVariant(sDefault);\n }\n });\n },\n\n _page: function () {\n return support.page(this, this._sSet);\n },\n\n _onListMatched: function () {\n if (this.getOwnerComponent().takeStale(this._sSet)) {\n this._loadChart();\n this._loadTabCounts();\n this.byId(\"table\").getBinding(\"items\").refresh();\n this.byId(\"table\").removeSelections(true);\n this.getView().getModel(\"ui\").setProperty(\"/tableSelected\", false);\n }\n },\n\n _field: function (sProperty) {\n return this._page().list.filterFields.find(function (f) { return f.property === sProperty; });\n },\n\n /** The filters, the search, the visible filters and columns, the sort order: a variant. */\n _state: function () {\n var oState = { filters: {}, search: \"\", visible: [], hidden: [], sort: this._oLr.getProperty(\"/sort\").slice() };\n var oVisible = this._oLr.getProperty(\"/visible\");\n var oColumns = this._oLr.getProperty(\"/columns\");\n this._page().list.filterFields.forEach(function (oField) {\n if (oVisible[oField.property]) {\n oState.visible.push(oField.property);\n }\n var oControl = this.byId(\"filter_\" + id(oField.property));\n if (!oControl) {\n return;\n }\n if (oField.kind === \"boolean\" || oField.kind === \"enum\") {\n if (oControl.getSelectedKey() !== \"\") {\n oState.filters[oField.property] = oControl.getSelectedKey();\n }\n } else if (oControl.getTokens().length > 0) {\n // the conditions as texts (=x, *x*, a...b, !(\u2026)): the keys of the tokens (D68)\n oState.filters[oField.property] = oControl.getTokens().map(function (t) { return t.getKey(); });\n }\n }, this);\n Object.keys(oColumns).forEach(function (sProperty) {\n if (oColumns[sProperty] === false) {\n oState.hidden.push(sProperty);\n }\n });\n if (this.byId(\"search\")) {\n oState.search = this.byId(\"search\").getValue();\n }\n return oState;\n },\n\n _applyState: function (oState) {\n var oVisible = {};\n var oColumns = {};\n this._page().list.filterFields.forEach(function (oField) {\n oVisible[oField.property] = oState.visible.indexOf(oField.property) >= 0;\n var oControl = this.byId(\"filter_\" + id(oField.property));\n var vValue = oState.filters[oField.property];\n if (!oControl) {\n return;\n }\n if (oField.kind === \"boolean\" || oField.kind === \"enum\") {\n oControl.setSelectedKey(vValue || \"\");\n } else {\n if (vValue && !Array.isArray(vValue)) {\n // a date range of a variant saved before D68: { from, to }\n vValue = vValue.from ? [vValue.to ? vValue.from + \"...\" + vValue.to : \"=\" + vValue.from] : [];\n }\n oControl.setValue(\"\");\n oControl.setValueState(\"None\");\n oControl.setTokens((vValue || []).map(function (sText) {\n var oCondition = filters.parse(oField, sText);\n return oCondition ? this._token(oField, oCondition) : null;\n }, this).filter(Boolean));\n this._describe(oControl, oField);\n }\n }, this);\n oState.hidden.forEach(function (sProperty) { oColumns[sProperty] = false; });\n this._oLr.setProperty(\"/visible\", oVisible);\n this._oLr.setProperty(\"/columns\", oColumns);\n this._oLr.setProperty(\"/sort\", oState.sort.slice());\n if (this.byId(\"search\")) {\n this.byId(\"search\").setValue(oState.search || \"\");\n }\n this._applySort();\n this.onSearch();\n this._oLr.setProperty(\"/modified\", false);\n },\n\n _applySort: function () {\n var oBinding = this.byId(\"table\").getBinding(\"items\");\n oBinding.sort(this._oLr.getProperty(\"/sort\").map(function (s) { return new Sorter(s.key, s.descending); }));\n },\n\n /** Turns the text typed in a filter field into a token (condition). */\n _commitText: function (oControl) {\n var sText = oControl.getValue();\n if (sText.trim() === \"\") {\n oControl.setValueState(\"None\");\n return true;\n }\n var oCondition = filters.parse(this._field(oControl.data(\"property\")), sText);\n if (!oCondition) {\n oControl.setValueState(\"Error\");\n oControl.setValueStateText(\"Enter a valid value or condition (=, !=, >, >=, <, <=, a...b, *x*)\");\n return false;\n }\n var oField = this._field(oControl.data(\"property\"));\n var sKey = filters.text(oCondition);\n if (oField.filter && oField.filter.single) {\n oControl.removeAllTokens();\n }\n if (!oControl.getTokens().some(function (t) { return t.getKey() === sKey; })) {\n oControl.addToken(this._token(oField, oCondition));\n this._describe(oControl, oField);\n }\n oControl.setValue(\"\");\n oControl.setValueState(\"None\");\n return true;\n },\n\n /** The token of a condition: its text as key (parsed by onSearch, kept in variants), shown as in SAP Fiori elements. */\n _token: function (oField, oCondition, sText) {\n return new Token({ key: filters.text(oCondition), text: sText || filters.display(oField, oCondition) });\n },\n\n /** Shows the descriptions of the values of a value help in the \"equal to\" tokens: \"Euro (EUR)\". */\n _describe: function (oControl, oField) {\n if (!oField.valueHelp || !oField.valueHelp.text) {\n return;\n }\n this._mTexts = this._mTexts || {};\n if (!this._mTexts[oField.property]) {\n this._mTexts[oField.property] = support.valueHelpTexts(this.getView(), oField.valueHelp);\n }\n this._mTexts[oField.property].then(function (mTexts) {\n oControl.getTokens().forEach(function (t) {\n var oCondition = filters.parse(oField, t.getKey());\n if (oCondition && oCondition.op === \"EQ\" && mTexts[oCondition.values[0]] !== undefined) {\n t.setText(filters.display(oField, oCondition, mTexts[oCondition.values[0]]));\n }\n });\n });\n },\n\n onFilterSubmit: function (oEvent) {\n if (this._commitText(oEvent.getSource())) {\n this.onSearch();\n }\n },\n\n onFilterChange: function () {\n this._oLr.setProperty(\"/modified\", true);\n this._summarize();\n },\n\n onSearch: function () {\n var oPage = this._page();\n var aFilters = [];\n var bValid = true;\n oPage.list.filterFields.forEach(function (oField) {\n var oControl = this.byId(\"filter_\" + id(oField.property));\n if (!oControl) {\n return;\n }\n var oFilter = null;\n // a mandatory filter (@Consumption.filter.mandatory, D57)\n if (oField.filter && oField.filter.mandatory) {\n var bEmpty = oControl.getTokens ? oControl.getTokens().length === 0 && oControl.getValue() === \"\" : oControl.getSelectedKey() === \"\";\n oControl.setValueState(bEmpty ? \"Error\" : \"None\");\n if (bEmpty) {\n oControl.setValueStateText(\"Fill in this filter\");\n bValid = false;\n }\n }\n if (oField.kind === \"boolean\") {\n var sKey = oControl.getSelectedKey();\n oFilter = sKey === \"\" ? null : new Filter(oField.property, \"EQ\", sKey === \"true\");\n } else if (oField.kind === \"enum\") {\n var sMember = oControl.getSelectedKey();\n oFilter = sMember === \"\" ? null : new Filter(oField.property, \"EQ\", sMember);\n } else {\n bValid = this._commitText(oControl) && bValid;\n var aConditions = oControl.getTokens().map(function (t) { return filters.parse(oField, t.getKey()); }).filter(Boolean);\n oFilter = filters.fieldFilter(oField, aConditions);\n }\n if (oFilter) {\n aFilters.push(oFilter);\n }\n }, this);\n if (!bValid) {\n return;\n }\n var oBinding = this.byId(\"table\").getBinding(\"items\");\n if (oPage.list.searchable && this.byId(\"search\")) {\n var sSearch = this.byId(\"search\").getValue().trim();\n oBinding.changeParameters({ $search: sSearch === \"\" ? undefined : sSearch });\n }\n this._aFilters = aFilters;\n this._applyTableFilters();\n this._loadChart();\n this._loadTabCounts();\n this._summarize();\n },\n\n /** The filters of the filter bar, and the value selected in the chart (Analytical List Page). */\n _applyTableFilters: function () {\n var aFilters = this._aFilters.slice();\n var oChart = this._page().charts[0];\n var sSelection = this._oLr.getProperty(\"/chartSelection\");\n if (this._page().floorplan === \"analyticalListPage\" && oChart && sSelection !== \"\") {\n aFilters.push(new Filter(oChart.dimension.property, \"EQ\", sSelection));\n }\n // the members of an enumeration type (D55): OpenUI5 does not write their literals, they go\n // to the $filter parameter of the binding (with the draft condition of the list)\n var oPage = this._page();\n var aEnum = [];\n aFilters = aFilters.filter(function (oFilter) {\n var oField = (oPage.fields || {})[oFilter.getPath()];\n if (oField && oField.kind === \"enum\" && !oFilter.getFilters()) {\n aEnum.push(oFilter.getPath() + \" eq '\" + String(oFilter.getValue1()).replace(/'/g, \"''\") + \"'\");\n return false;\n }\n return true;\n });\n var oBinding = this.byId(\"table\").getBinding(\"items\");\n if (!oBinding) {\n return;\n }\n var sDraft = this._draftClause();\n if (aEnum.length > 0 || this._bEnumFilter || sDraft !== \"\") {\n var aClauses = (sDraft === \"\" ? [] : [\"(\" + sDraft + \")\"]).concat(aEnum);\n var sFilter = aClauses.length > 0 ? aClauses.join(\" and \") : undefined;\n if (sFilter !== this._sParameterFilter) {\n this._sParameterFilter = sFilter;\n oBinding.changeParameters({ $filter: sFilter });\n }\n this._bEnumFilter = aEnum.length > 0;\n }\n oBinding.filter(aFilters.length > 0 ? new Filter({ filters: aFilters, and: true }) : []);\n },\n\n /**\n * The draft condition of the list (D58), as Fiori Elements: all (the own drafts, and the\n * active instances without an own draft), own drafts, locked by another user, no changes.\n */\n _draftClause: function () {\n if (!this._page().draft) {\n return \"\";\n }\n var sMe = String(this.getOwnerComponent().getModel(\"ui\").getProperty(\"/user\") || \"\").replace(/'/g, \"''\");\n var oStatus = this.byId(\"filter_EditingStatus\");\n var sStatus = oStatus ? oStatus.getSelectedKey() : \"\";\n if (sStatus === \"own\") {\n return \"IsActiveEntity eq false\";\n }\n if (sStatus === \"locked\") {\n return \"IsActiveEntity eq true and HasDraftEntity eq true\" + (sMe ? \" and DraftAdministrativeData/InProcessByUser ne '\" + sMe + \"'\" : \"\");\n }\n if (sStatus === \"unchanged\") {\n return \"IsActiveEntity eq true and HasDraftEntity eq false\";\n }\n return sMe ? \"IsActiveEntity eq false or HasDraftEntity eq false or DraftAdministrativeData/InProcessByUser ne '\" + sMe + \"'\" : \"IsActiveEntity eq true or HasActiveEntity eq false\";\n },\n\n _service: function () {\n return this.getOwnerComponent().getManifestEntry(\"/sap.app/dataSources/mainService/uri\");\n },\n\n /** The $filter of the filter bar, for the requests of the chart and of the tab counts. */\n _odataFilter: function (sExtra) {\n var sFilter = this._aFilters.length > 0 ? filters.toOData(new Filter({ filters: this._aFilters, and: true }), this._page().fields) : \"\";\n return [sFilter, sExtra].filter(Boolean).join(\" and \");\n },\n\n _searchParameter: function () {\n var oSearch = this.byId(\"search\");\n var sSearch = oSearch ? oSearch.getValue().trim() : \"\";\n return sSearch === \"\" ? \"\" : \"&$search=\" + encodeURIComponent(sSearch);\n },\n\n /** The chart of the Analytical List Page: the groups of its dimension ($apply). */\n _loadChart: function () {\n var oPage = this._page();\n var oSpec = oPage.charts[0];\n var oChart = this.byId(\"chart\");\n if (oPage.floorplan !== \"analyticalListPage\" || !oSpec || !oChart) {\n return;\n }\n var sFilter = this._odataFilter();\n var sApply = (sFilter ? \"filter(\" + sFilter + \")/\" : \"\") + \"groupby((\" + oSpec.dimension.property + \"),aggregate(\" + oSpec.measures.map(function (m) {\n return m.property + \" with \" + m.aggregation + \" as \" + m.property;\n }).join(\",\") + \"))\";\n var that = this;\n fetch(this._service() + this._sSet + \"?$apply=\" + encodeURIComponent(sApply) + \"&$orderby=\" + encodeURIComponent(oSpec.dimension.property) + \"&$top=50\" + this._searchParameter(), { credentials: \"same-origin\", headers: { accept: \"application/json\" } })\n .then(function (r) { return r.ok ? r.json() : { value: [] }; })\n .then(function (oData) {\n oChart.setData((oData.value || []).map(function (row) {\n var v = row[oSpec.dimension.property];\n return { key: v === null ? \"\" : String(v), label: v === null || v === \"\" ? \"(empty)\" : String(v), values: oSpec.measures.map(function (m) { return Number(row[m.property]) || 0; }) };\n }), oSpec.measures.map(function (m) { return m.label; }));\n that._oChartRows = oData.value || [];\n })\n .catch(function () { oChart.setData([], []); });\n },\n\n onChartSelect: function (oEvent) {\n this._oLr.setProperty(\"/chartSelection\", oEvent.getParameter(\"value\"));\n this._applyTableFilters();\n },\n\n onViewSwitch: function (oEvent) {\n this._oLr.setProperty(\"/view\", oEvent.getParameter(\"item\").getKey());\n },\n\n /** Worklist: a tab is a selection variant (@UI.selectionVariant), its filter a parameter of the list. */\n onWorklistTab: function (oEvent) {\n var sKey = oEvent.getParameter(\"key\");\n var oVariant = this._page().selectionVariants.find(function (v) { return v.key === sKey; });\n this._oLr.setProperty(\"/tab\", sKey);\n var sDraft = this._draftClause();\n var sFilter = [sDraft, oVariant && oVariant.filter ? oVariant.filter : \"\"].filter(Boolean).map(function (f) { return \"(\" + f + \")\"; }).join(\" and \");\n this.byId(\"table\").getBinding(\"items\").changeParameters({ $filter: sFilter || undefined });\n },\n\n _loadTabCounts: function () {\n var oPage = this._page();\n if (oPage.floorplan !== \"worklist\" || oPage.selectionVariants.length === 0) {\n return;\n }\n var that = this;\n var aTabs = [{ key: \"all\" }].concat(oPage.selectionVariants);\n aTabs.forEach(function (oTab) {\n var sFilter = that._odataFilter(oTab.filter ? \"(\" + oTab.filter + \")\" : \"\");\n fetch(that._service() + that._sSet + \"/$count\" + (sFilter ? \"?$filter=\" + encodeURIComponent(sFilter) : \"?\") + that._searchParameter(), { credentials: \"same-origin\" })\n .then(function (r) { return r.ok ? r.text() : \"\"; })\n .then(function (sCount) { that._oLr.setProperty(\"/tabCounts/\" + oTab.key, sCount.trim()); })\n .catch(function () { /* no count */ });\n });\n },\n\n /** \"Filtered By: \u2026\" in the collapsed header, the count of \"Adapt Filters (n)\". */\n _summarize: function () {\n var oState = this._state();\n var aLabels = [];\n Object.keys(oState.filters).forEach(function (sProperty) {\n var oField = this._field(sProperty);\n var vValue = oState.filters[sProperty];\n aLabels.push(oField.label + (Array.isArray(vValue) && vValue.length > 1 ? \" (\" + vValue.length + \")\" : \"\"));\n }, this);\n if (oState.search && oState.search.trim() !== \"\") {\n aLabels.unshift(\"Search\");\n }\n this._oLr.setProperty(\"/active\", aLabels.length);\n this._oLr.setProperty(\"/summary\", \"Filtered By: \" + (aLabels.length === 0 ? \"None\" : aLabels.join(\", \")));\n },\n\n onClearFilters: function () {\n if (this.byId(\"filter_EditingStatus\")) {\n this.byId(\"filter_EditingStatus\").setSelectedKey(\"\");\n }\n var oState = this._state();\n oState.filters = {};\n oState.search = \"\";\n this._applyState(oState);\n this._oLr.setProperty(\"/modified\", true);\n },\n\n onAdaptFilters: function () {\n var that = this;\n var oVisible = this._oLr.getProperty(\"/visible\");\n var oDialog = new SelectDialog({\n title: \"Adapt Filters\",\n multiSelect: true,\n rememberSelections: false,\n items: this._page().list.filterFields.map(function (f) {\n return new StandardListItem({ title: f.label, description: f.property, selected: oVisible[f.property] === true });\n }),\n search: function (oEvent) {\n var sValue = (oEvent.getParameter(\"value\") || \"\").toLowerCase();\n oEvent.getSource().getItems().forEach(function (oItem) {\n oItem.setVisible(oItem.getTitle().toLowerCase().indexOf(sValue) >= 0);\n });\n },\n confirm: function (oEvent) {\n var aSelected = (oEvent.getParameter(\"selectedItems\") || []).map(function (oItem) { return oItem.getDescription(); });\n var oNew = {};\n that._page().list.filterFields.forEach(function (f) {\n oNew[f.property] = aSelected.indexOf(f.property) >= 0;\n });\n var oState = that._state();\n oState.visible = aSelected;\n // a hidden filter does not filter\n Object.keys(oState.filters).forEach(function (sProperty) {\n if (!oNew[sProperty]) {\n delete oState.filters[sProperty];\n }\n });\n that._applyState(oState);\n that._oLr.setProperty(\"/modified\", true);\n },\n afterClose: function () {\n oDialog.destroy();\n }\n });\n this.getView().addDependent(oDialog);\n oDialog.open();\n },\n\n onTableSettings: function (oEvent) {\n var that = this;\n var oTable = this._page().list.table;\n var oColumns = this._oLr.getProperty(\"/columns\");\n var aSort = this._oLr.getProperty(\"/sort\");\n var oSelection = new SelectionPanel({ title: \"Columns\", showHeader: true, enableCount: true, enableReorder: false });\n oSelection.setP13nData(oTable.columns.map(function (c) {\n return { key: c.property, label: c.label, visible: oColumns[c.property] !== false };\n }));\n var oSort = new SortPanel({ title: \"Sort\" });\n oSort.setP13nData(oTable.columns.map(function (c) {\n var oSorted = aSort.find(function (s) { return s.key === c.property; });\n return { key: c.property, label: c.label, sorted: !!oSorted, descending: oSorted ? oSorted.descending : false };\n }));\n var oPopup = new P13nPopup({\n title: \"View Settings\",\n panels: [oSelection, oSort],\n close: function (oClose) {\n if (oClose.getParameter(\"reason\") === \"Ok\") {\n var oNew = {};\n oSelection.getP13nData().forEach(function (o) {\n if (!o.visible) {\n oNew[o.key] = false;\n }\n });\n that._oLr.setProperty(\"/columns\", oNew);\n that._oLr.setProperty(\"/sort\", oSort.getP13nData().filter(function (o) { return o.sorted; }).map(function (o) {\n return { key: o.key, descending: !!o.descending };\n }));\n that._applySort();\n that._oLr.setProperty(\"/modified\", true);\n }\n oPopup.destroy();\n }\n });\n this.getView().addDependent(oPopup);\n oPopup.open(oEvent.getSource());\n },\n\n /** The value help of a filter field: \"Search and Select\" (value help) and \"Define Conditions\" (D68). */\n onFilterValueHelp: function (oEvent) {\n var oControl = oEvent.getSource();\n var oField = this._field(oControl.data(\"property\"));\n var that = this;\n if (!this._commitText(oControl)) {\n oControl.setValue(\"\");\n oControl.setValueState(\"None\");\n }\n var aCurrent = oControl.getTokens().map(function (t) {\n var oCondition = filters.parse(oField, t.getKey());\n return oCondition ? { condition: oCondition, text: t.getText() } : null;\n }).filter(Boolean);\n conditions.open(this.getView(), oField, aCurrent).then(function (aConditions) {\n if (!aConditions) {\n return;\n }\n oControl.setTokens(aConditions.map(function (c) { return that._token(oField, c.condition, c.text); }));\n oControl.setValueState(\"None\");\n that.onFilterChange();\n });\n },\n\n _items: function () {\n return this._oLr.getProperty(\"/variants\");\n },\n\n _selectVariant: function (sKey) {\n var oItem = this._items().find(function (v) { return v.key === sKey; });\n this._oLr.setProperty(\"/variant\", oItem ? sKey : STANDARD);\n this._applyState(oItem && oItem.content ? oItem.content : this._oStandard);\n },\n\n onVariantSelect: function (oEvent) {\n this._selectVariant(oEvent.getParameter(\"key\"));\n },\n\n _persist: function () {\n var sDefault = this._oLr.getProperty(\"/defaultVariant\");\n this._oStore.save({\n defaultKey: sDefault,\n items: this._items().filter(function (v) { return v.key !== STANDARD; }).map(function (v) {\n return { key: v.key, title: v.title, favorite: v.favorite, content: v.content };\n })\n }).catch(function () {\n MessageToast.show(\"The view could not be saved\");\n });\n },\n\n onVariantSave: function (oEvent) {\n var sKey = oEvent.getParameter(\"key\") || (\"v\" + Date.now());\n var aItems = this._items().slice();\n var oContent = this._state();\n if (oEvent.getParameter(\"overwrite\")) {\n aItems = aItems.map(function (v) { return v.key === sKey ? Object.assign({}, v, { content: oContent }) : v; });\n } else {\n aItems.push({ key: sKey, title: oEvent.getParameter(\"name\"), author: \"\", changeable: true, favorite: true, content: oContent });\n }\n this._oLr.setProperty(\"/variants\", aItems);\n if (oEvent.getParameter(\"def\")) {\n this._oLr.setProperty(\"/defaultVariant\", sKey);\n }\n this._oLr.setProperty(\"/variant\", sKey);\n this._oLr.setProperty(\"/modified\", false);\n this._persist();\n },\n\n onVariantManage: function (oEvent) {\n var aDeleted = oEvent.getParameter(\"deleted\") || [];\n var aRenamed = oEvent.getParameter(\"renamed\") || [];\n var aFavorites = oEvent.getParameter(\"fav\") || [];\n var aItems = this._items().filter(function (v) { return aDeleted.indexOf(v.key) < 0; }).map(function (v) {\n var oRename = aRenamed.find(function (r) { return r.key === v.key; });\n var oFavorite = aFavorites.find(function (f) { return f.key === v.key; });\n return Object.assign({}, v, oRename ? { title: oRename.name } : {}, oFavorite ? { favorite: oFavorite.visible } : {});\n });\n this._oLr.setProperty(\"/variants\", aItems);\n var sDefault = oEvent.getParameter(\"def\");\n if (sDefault !== undefined) {\n this._oLr.setProperty(\"/defaultVariant\", sDefault);\n }\n if (aDeleted.indexOf(this._oLr.getProperty(\"/defaultVariant\")) >= 0) {\n this._oLr.setProperty(\"/defaultVariant\", STANDARD);\n }\n if (aDeleted.indexOf(this._oLr.getProperty(\"/variant\")) >= 0) {\n this._selectVariant(STANDARD);\n }\n this._persist();\n },\n\n onUpdateFinished: function (oEvent) {\n var iTotal = oEvent.getParameter(\"total\");\n var sPlural = this.byId(\"tableTitle\").data(\"plural\");\n var oBinding = this.byId(\"table\").getBinding(\"items\");\n var bKnown = oBinding && oBinding.isLengthFinal();\n this._oLr.setProperty(\"/tableTitle\", bKnown ? sPlural + \" (\" + iTotal + \")\" : sPlural);\n },\n\n onSelectionChange: function () {\n this.getView().getModel(\"ui\").setProperty(\"/tableSelected\", !!this.byId(\"table\").getSelectedItem());\n },\n\n onItemPress: function (oEvent) {\n var oContext = oEvent.getSource().getBindingContext();\n this.getOwnerComponent().getRouter().navTo(this._sSet + \"Object\", { key: support.keyOf(oContext.getPath()) });\n },\n\n onCreate: function () {\n var oModel = this.getView().getModel();\n var that = this;\n if (this._page().draft) {\n // draft (D54): a new draft at once, then its object page in edit mode\n var oDraft = oModel.bindList(\"/\" + this._sSet, undefined, undefined, undefined, { $$updateGroupId: \"$auto\" }).create({});\n oDraft.created().then(function () {\n that.getOwnerComponent().markStale();\n that.getOwnerComponent().getRouter().navTo(that._sSet + \"Object\", { key: support.keyOf(oDraft.getPath()) });\n }, function (oError) {\n MessageBox.error(support.errorText(oError));\n });\n return;\n }\n var oBinding = oModel.bindList(\"/\" + this._sSet, undefined, undefined, undefined, { $$updateGroupId: \"changes\" });\n this.getOwnerComponent().setTransient(oBinding.create({}));\n this.getOwnerComponent().getRouter().navTo(this._sSet + \"New\");\n },\n\n onDelete: function () {\n var oItem = this.byId(\"table\").getSelectedItem();\n if (!oItem) {\n return;\n }\n var oContext = oItem.getBindingContext();\n var that = this;\n MessageBox.confirm(\"Delete this object?\", {\n onClose: function (sAction) {\n if (sAction !== MessageBox.Action.OK) {\n return;\n }\n oContext.delete(\"$auto\").then(function () {\n that.getView().getModel(\"ui\").setProperty(\"/tableSelected\", false);\n MessageToast.show(\"Object deleted\");\n }, function (oError) {\n MessageBox.error(support.errorText(oError));\n });\n }\n });\n },\n\n onAction: function (oEvent) {\n var oButton = oEvent.getSource();\n var oPage = this._page();\n var oAction = support.action(oPage, oButton.data(\"action\"), oPage.list.table.actions);\n var oItem = this.byId(\"table\").getSelectedItem();\n var oContext = oItem ? oItem.getBindingContext() : undefined;\n var that = this;\n if (!oAction || (!oAction.static && !oContext)) {\n return;\n }\n support.invoke(this.getView(), oPage, oAction, oContext).then(function (oResult) {\n if (oResult === null) {\n return;\n }\n MessageToast.show(oAction.label + \": done\");\n that.byId(\"table\").getBinding(\"items\").refresh();\n if ((oAction.factory || oAction.static) && oResult && oAction.returnsEntity) {\n that.getOwnerComponent().getRouter().navTo(that._sSet + \"Object\", { key: support.keyPredicate(oPage, oResult.getObject()) });\n }\n }, function (oError) {\n MessageBox.error(support.errorText(oError));\n });\n }\n });\n});\n";
|
|
50
|
+
/**
|
|
51
|
+
* The views (variants) of a user: saved by the service (`$variants`, a table of the database,
|
|
52
|
+
* per user), in the local storage of the browser when the service does not keep them.
|
|
53
|
+
*/
|
|
54
|
+
export declare const VARIANTS = "sap.ui.define([], function () {\n \"use strict\";\n\n function local(sKey) {\n return {\n load: function () {\n try {\n return Promise.resolve(JSON.parse(window.localStorage.getItem(sKey) || \"null\") || { items: [] });\n } catch (e) {\n return Promise.resolve({ items: [] });\n }\n },\n save: function (oData) {\n try {\n window.localStorage.setItem(sKey, JSON.stringify(oData));\n } catch (e) {\n return Promise.reject(e);\n }\n return Promise.resolve();\n }\n };\n }\n\n return {\n store: function (oComponent, sPage) {\n var sService = oComponent.getManifestEntry(\"/sap.app/dataSources/mainService/uri\");\n var sUrl = sService + \"$variants?page=\" + encodeURIComponent(sPage);\n var oLocal = local(\"rapt.variants.\" + sService + sPage);\n var bServer = true;\n return {\n load: function () {\n return fetch(sUrl, { credentials: \"same-origin\", headers: { accept: \"application/json\" } }).then(function (oResponse) {\n if (!oResponse.ok) {\n throw new Error(String(oResponse.status));\n }\n return oResponse.json();\n }).then(function (oData) {\n return { items: oData.items || [], defaultKey: oData.defaultKey };\n }).catch(function () {\n bServer = false;\n return oLocal.load();\n });\n },\n save: function (oData) {\n if (!bServer) {\n return oLocal.save(oData);\n }\n return fetch(sService, { method: \"HEAD\", credentials: \"same-origin\", headers: { \"X-CSRF-Token\": \"Fetch\" } }).then(function (oHead) {\n return fetch(sUrl, {\n method: \"PUT\",\n credentials: \"same-origin\",\n headers: { \"content-type\": \"application/json\", \"X-CSRF-Token\": oHead.headers.get(\"X-CSRF-Token\") || \"\" },\n body: JSON.stringify(oData)\n });\n }).then(function (oResponse) {\n if (!oResponse.ok) {\n throw new Error(String(oResponse.status));\n }\n });\n }\n };\n }\n };\n});\n";
|
|
55
|
+
export declare const OBJECT_CONTROLLER = "sap.ui.define([\n \"sap/ui/core/mvc/Controller\",\n \"sap/ui/core/Messaging\",\n \"sap/m/MessageBox\",\n \"sap/m/MessageToast\",\n \"sap/m/MessagePopover\",\n \"sap/m/MessageItem\",\n \"sap/ui/core/routing/History\",\n \"rapt/app/controller/support\",\n \"sap/m/Dialog\",\n \"sap/m/Button\",\n \"sap/m/Input\",\n \"sap/m/Label\",\n \"sap/m/VBox\"\n], function (Controller, Messaging, MessageBox, MessageToast, MessagePopover, MessageItem, History, support, Dialog, Button, Input, Label, VBox) {\n \"use strict\";\n\n return Controller.extend(\"rapt.app.controller.Object\", {\n onInit: function () {\n this._sSet = this.byId(\"page\").data(\"set\");\n var oRouter = this.getOwnerComponent().getRouter();\n oRouter.getRoute(this._sSet + \"Object\").attachPatternMatched(this._onObjectMatched, this);\n var oNew = oRouter.getRoute(this._sSet + \"New\");\n if (oNew) {\n oNew.attachPatternMatched(this._onNewMatched, this);\n }\n // form entry (D53): the start page creates, again and again\n var oFormEntry = oRouter.getRoute(this._sSet + \"FormEntry\");\n if (oFormEntry) {\n oFormEntry.attachPatternMatched(this._onFormEntryMatched, this);\n }\n },\n\n _page: function () {\n return support.page(this, this._sSet);\n },\n\n _ui: function () {\n return this.getView().getModel(\"ui\");\n },\n\n _mode: function (bEdit, bCreate) {\n this._ui().setProperty(\"/editMode\", bEdit);\n this._ui().setProperty(\"/createMode\", bCreate);\n this._ui().setProperty(\"/childSelected\", false);\n },\n\n /** Collaborative draft (D59): the users of the draft, the changes of the others (polling). */\n _startCollab: function () {\n var that = this;\n this._loadCollabUsers();\n this._iCollab = setInterval(function () {\n var oModel = that.getView().getModel();\n if (!that._ui().getProperty(\"/draft\") || oModel.hasPendingChanges()) {\n return;\n }\n var oBinding = that.getView().getElementBinding();\n if (oBinding) {\n oBinding.refresh();\n }\n that._loadCollabUsers();\n }, 5000);\n },\n\n _stopCollab: function () {\n if (this._iCollab) {\n clearInterval(this._iCollab);\n this._iCollab = undefined;\n }\n },\n\n _loadCollabUsers: function () {\n var oContext = this.getView().getBindingContext();\n var oUi = this._ui();\n var sService = this.getOwnerComponent().getManifestEntry(\"/sap.app/dataSources/mainService/uri\");\n if (!oContext) {\n return;\n }\n oContext.requestProperty(\"DraftUUID\").then(function (sUuid) {\n if (!sUuid) {\n return undefined;\n }\n return fetch(sService + \"DraftAdministrativeUser?$orderby=UserID&$filter=\" + encodeURIComponent(\"DraftUUID eq \" + sUuid), { credentials: \"same-origin\", headers: { accept: \"application/json\" } })\n .then(function (r) { return r.ok ? r.json() : { value: [] }; })\n .then(function (oData) {\n oUi.setProperty(\"/collab/users\", (oData.value || []).map(function (u) {\n return { UserID: u.UserID, initials: String(u.UserID).slice(0, 2).toUpperCase(), owner: u.UserAccessRole === \"O\" };\n }));\n });\n }).catch(function () { /* the list stays as it was */ });\n },\n\n /** Invites a user to the collaborative draft: the action Share (D59). */\n onInvite: function () {\n var that = this;\n var oInput = new Input({ placeholder: \"User ID\", width: \"100%\" });\n var oDialog = new Dialog({\n title: \"Invite Users\",\n content: [new VBox({ items: [new Label({ text: \"User\", labelFor: oInput }), oInput] }).addStyleClass(\"sapUiSmallMargin\")],\n beginButton: new Button({\n text: \"Invite\",\n type: \"Emphasized\",\n press: function () {\n var sUser = oInput.getValue().trim();\n oDialog.close();\n if (sUser === \"\") {\n return;\n }\n that._draftAction(\"Share\", { Users: [{ UserID: sUser, UserAccessRole: \"E\" }], ShareAll: false }).then(function () {\n MessageToast.show(sUser.toUpperCase() + \" can now edit the draft\");\n that._loadCollabUsers();\n }, function (oError) {\n MessageBox.error(support.errorText(oError));\n });\n }\n }),\n endButton: new Button({ text: \"Cancel\", press: function () { oDialog.close(); } }),\n afterClose: function () { oDialog.destroy(); }\n });\n this.getView().addDependent(oDialog);\n oDialog.open();\n },\n\n _onObjectMatched: function (oEvent) {\n // changes left behind (back button in edit mode) must not be sent with the next save\n this.getView().getModel().resetChanges(\"changes\");\n this._mode(false, false);\n Messaging.removeAllMessages();\n var sKey = oEvent.getParameter(\"arguments\").key;\n // a draft (D54): edited at once, each change saved in the draft\n var bDraft = /IsActiveEntity=false/.test(sKey);\n this._ui().setProperty(\"/draft\", bDraft);\n this.getView().bindElement({\n path: \"/\" + this._sSet + \"(\" + sKey + \")\",\n parameters: { $$updateGroupId: bDraft ? \"$auto\" : \"changes\" }\n });\n this._stopCollab();\n if (bDraft) {\n // each change is saved in the draft: \"Saving draft...\" then \"Draft saved\" (D58)\n var oIndicator = this.byId(\"draftStatus\");\n var oBinding = this.getView().getElementBinding();\n if (oIndicator && oBinding && !oBinding._raptIndicator) {\n oBinding._raptIndicator = true;\n oBinding.attachPatchSent(function () { oIndicator.showDraftSaving(); });\n oBinding.attachPatchCompleted(function (oPatch) {\n if (oPatch.getParameter(\"success\")) {\n oIndicator.showDraftSaved();\n } else {\n oIndicator.clearDraftState();\n }\n });\n }\n if (this.byId(\"collab\")) {\n this._startCollab();\n }\n }\n if (bDraft) {\n // a new draft (no active instance) is a creation: its keys may still be entered\n var that = this;\n var sService = this.getOwnerComponent().getManifestEntry(\"/sap.app/dataSources/mainService/uri\");\n this._bHasActive = true;\n fetch(sService + this._sSet + \"(\" + sKey + \")?$select=HasActiveEntity\", { credentials: \"same-origin\", headers: { accept: \"application/json\" } })\n .then(function (r) { return r.ok ? r.json() : { HasActiveEntity: true }; })\n .then(function (oData) {\n that._bHasActive = oData.HasActiveEntity !== false;\n that._mode(true, !that._bHasActive);\n }, function () {\n that._mode(true, false);\n });\n }\n },\n\n /** Runs an action of the draft on the bound instance; resolves the context it returns. */\n _draftAction: function (sName, oParameters) {\n var oView = this.getView();\n var oNamespace = oView.getModel(\"layout\").getProperty(\"/namespace\");\n // Share returns nothing: no inherited $expand / $select (D59)\n var oAction = oView.getModel().bindContext(oNamespace + \".\" + sName + \"(...)\", oView.getBindingContext(), sName === \"Share\" ? {} : { $$inheritExpandSelect: true });\n Object.keys(oParameters || {}).forEach(function (sParameter) {\n oAction.setParameter(sParameter, oParameters[sParameter]);\n });\n return oAction.invoke(\"$auto\");\n },\n\n _onFormEntryMatched: function () {\n this._bFormEntry = true;\n this._newTransient();\n this._onNewMatched();\n },\n\n /** A new instance to create, when none was prepared (form entry, link to \u2026/new). */\n _newTransient: function () {\n var oBinding = this.getView().getModel().bindList(\"/\" + this._sSet, undefined, undefined, undefined, { $$updateGroupId: \"changes\" });\n this.getOwnerComponent().setTransient(oBinding.create({}));\n },\n\n _onNewMatched: function (oEvent) {\n if (oEvent) {\n this._bFormEntry = false;\n }\n if (!this.getOwnerComponent().getTransient()) {\n this._newTransient();\n }\n var oContext = this.getOwnerComponent().getTransient();\n Messaging.removeAllMessages();\n this.getView().unbindElement();\n this.getView().setBindingContext(oContext);\n this._mode(true, true);\n },\n\n _back: function () {\n if (History.getInstance().getPreviousHash() !== undefined) {\n window.history.go(-1);\n } else {\n this.getOwnerComponent().getRouter().navTo(this.getOwnerComponent().getModel(\"layout\").getProperty(\"/start\") + \"List\", {}, true);\n }\n },\n\n /** Leaves the page, after a confirmation when changes are not saved. */\n _leave: function (fnLeave) {\n var oModel = this.getView().getModel();\n var that = this;\n if (this._ui().getProperty(\"/draft\")) {\n // leaving a draft, as Fiori Elements: keep it for later, or discard it (D58)\n var oContext = this.getView().getBindingContext();\n MessageBox.show(\"Do you want to keep the draft of your changes?\", {\n title: \"Leave Page\",\n actions: [\"Keep Draft\", \"Discard Draft\", MessageBox.Action.CANCEL],\n emphasizedAction: \"Keep Draft\",\n onClose: function (sAction) {\n if (sAction === \"Keep Draft\") {\n that._stopCollab();\n that.getOwnerComponent().markStale();\n fnLeave();\n } else if (sAction === \"Discard Draft\" && oContext) {\n oContext.delete(\"$auto\").then(function () {\n that._stopCollab();\n that.getOwnerComponent().markStale();\n MessageToast.show(\"Draft discarded\");\n fnLeave();\n }, function (oError) {\n MessageBox.error(support.errorText(oError));\n });\n }\n }\n });\n return;\n }\n if (!this._ui().getProperty(\"/editMode\") || !oModel.hasPendingChanges(\"changes\")) {\n fnLeave();\n return;\n }\n MessageBox.confirm(\"Discard the changes?\", {\n onClose: function (sAction) {\n if (sAction === MessageBox.Action.OK) {\n oModel.resetChanges(\"changes\");\n that.getOwnerComponent().setTransient(undefined);\n that._mode(false, false);\n fnLeave();\n }\n }\n });\n },\n\n onNavList: function () {\n var oRouter = this.getOwnerComponent().getRouter();\n var sStart = this.getOwnerComponent().getModel(\"layout\").getProperty(\"/start\");\n this._leave(function () {\n oRouter.navTo(sStart + \"List\", {}, false);\n });\n },\n\n onNavBack: function () {\n var that = this;\n this._leave(function () {\n that._back();\n });\n },\n\n onValueHelp: function (oEvent) {\n var oInput = oEvent.getSource();\n var sProperty = oInput.data(\"property\");\n var oField = this._page().fields[sProperty] || this._childField(oInput, sProperty);\n if (!oField || !oField.valueHelp) {\n return;\n }\n var oContext = oInput.getBindingContext();\n support.valueHelp(this.getView(), oField.valueHelp, false, oContext).then(function (aValues) {\n if (aValues.length > 0) {\n oContext.setProperty(sProperty, aValues[0]);\n oInput.setValueState(\"None\");\n }\n });\n },\n\n /** A value typed or chosen in a field with a value help: validation, additional bindings. */\n onValueHelpChange: function (oEvent) {\n var oControl = oEvent.getSource();\n var sProperty = oControl.data(\"property\");\n var oField = this._page().fields[sProperty] || this._childField(oControl, sProperty);\n var oContext = oControl.getBindingContext();\n if (!oField || !oField.valueHelp || !oContext) {\n return;\n }\n var oHelp = oField.valueHelp;\n var oItem = oEvent.getParameter(\"selectedItem\") || (oControl.getSelectedItem && oControl.getSelectedItem());\n if (oItem) {\n // drop-down list: the row of the chosen item\n support.applyValueHelpResults(oHelp, oContext, oItem.getBindingContext().getObject());\n oControl.setValueState(\"None\");\n return;\n }\n var sValue = oControl.getValue ? oControl.getValue() : \"\";\n support.checkValueHelp(this.getView(), oHelp, oContext, sValue).then(function (bFound) {\n if (!bFound && oHelp.validation) {\n oControl.setValueState(\"Error\");\n oControl.setValueStateText(\"Enter a valid value: \" + sValue + \" is not in \" + oHelp.label);\n } else {\n oControl.setValueState(\"None\");\n }\n });\n },\n\n /** The field of a child table (the input is in a row of a table of the page). */\n _childField: function (oInput, sProperty) {\n var oParent = oInput.getParent();\n while (oParent && !(oParent.data && oParent.data(\"set\"))) {\n oParent = oParent.getParent();\n }\n var oPage = oParent ? support.page(this, oParent.data(\"set\")) : undefined;\n return oPage ? oPage.fields[sProperty] : undefined;\n },\n\n onEdit: function () {\n Messaging.removeAllMessages();\n if (this._page().draft) {\n // draft (D54): Edit opens the draft of the instance\n var that = this;\n this._ui().setProperty(\"/busy\", true);\n this._draftAction(\"Edit\", { PreserveChanges: false }).then(function (oDraft) {\n that._ui().setProperty(\"/busy\", false);\n that.getOwnerComponent().markStale();\n that.getOwnerComponent().getRouter().navTo(that._sSet + \"Object\", { key: support.keyOf(oDraft.getPath()) }, true);\n }, function (oError) {\n that._ui().setProperty(\"/busy\", false);\n MessageBox.error(support.errorText(oError));\n });\n return;\n }\n this._mode(true, false);\n },\n\n onSave: function () {\n if (this._ui().getProperty(\"/draft\")) {\n this._activate();\n return;\n }\n var oView = this.getView();\n var oModel = oView.getModel();\n var oUi = this._ui();\n var that = this;\n var bCreate = oUi.getProperty(\"/createMode\");\n var oContext = oView.getBindingContext();\n Messaging.removeAllMessages();\n oUi.setProperty(\"/busy\", true);\n oModel.submitBatch(\"changes\").then(function () {\n oUi.setProperty(\"/busy\", false);\n if (oModel.hasPendingChanges(\"changes\")) {\n MessageBox.error(support.errorText());\n return;\n }\n that.getOwnerComponent().markStale();\n if (bCreate) {\n return oContext.created().then(function () {\n that.getOwnerComponent().setTransient(undefined);\n if (that._bFormEntry) {\n // form entry: a new, empty form\n MessageToast.show(\"Object created\");\n that._newTransient();\n that._onNewMatched();\n return;\n }\n that._mode(false, false);\n MessageToast.show(\"Object created\");\n that.getOwnerComponent().getRouter().navTo(that._sSet + \"Object\", { key: support.keyOf(oContext.getPath()) }, true);\n });\n }\n that._mode(false, false);\n MessageToast.show(\"Changes saved\");\n }, function (oError) {\n oUi.setProperty(\"/busy\", false);\n MessageBox.error(support.errorText(oError));\n });\n },\n\n /** Save of a draft: Activate, then the active instance (D54). */\n _activate: function () {\n var that = this;\n var oUi = this._ui();\n Messaging.removeAllMessages();\n oUi.setProperty(\"/busy\", true);\n this.getView().getModel().submitBatch(\"$auto\").then(function () {\n return that._draftAction(\"Activate\");\n }).then(function (oActive) {\n oUi.setProperty(\"/busy\", false);\n that.getOwnerComponent().markStale();\n MessageToast.show(oUi.getProperty(\"/createMode\") ? \"Object created\" : \"Changes saved\");\n that.getOwnerComponent().getRouter().navTo(that._sSet + \"Object\", { key: support.keyOf(oActive.getPath()) }, true);\n }, function (oError) {\n oUi.setProperty(\"/busy\", false);\n MessageBox.error(support.errorText(oError));\n });\n },\n\n onCancel: function () {\n if (this._ui().getProperty(\"/draft\")) {\n // draft (D54): Discard, back to the active instance (or the list)\n var that = this;\n var oContext = this.getView().getBindingContext();\n MessageBox.confirm(that._bHasActive ? \"Discard all changes?\" : \"Discard this draft?\", {\n title: \"Discard Draft\",\n actions: [\"Discard\", MessageBox.Action.CANCEL],\n emphasizedAction: \"Discard\",\n onClose: function (sAction) {\n if (sAction !== \"Discard\") {\n return;\n }\n that._stopCollab();\n var bHasActive = that._bHasActive;\n var sActive = support.keyOf(oContext.getPath()).replace(\"IsActiveEntity=false\", \"IsActiveEntity=true\");\n // DELETE of the draft root discards the draft (D54)\n oContext.delete(\"$auto\").then(function () {\n that.getOwnerComponent().markStale();\n MessageToast.show(\"Draft discarded\");\n if (bHasActive) {\n that.getOwnerComponent().getRouter().navTo(that._sSet + \"Object\", { key: sActive }, true);\n } else {\n that._back();\n }\n }, function (oError) {\n MessageBox.error(support.errorText(oError));\n });\n }\n });\n return;\n }\n var bCreate = this._ui().getProperty(\"/createMode\");\n this.getView().getModel().resetChanges(\"changes\");\n Messaging.removeAllMessages();\n this._mode(false, false);\n if (bCreate && this._bFormEntry) {\n this._newTransient();\n this._onNewMatched();\n } else if (bCreate) {\n this.getOwnerComponent().setTransient(undefined);\n this._back();\n }\n },\n\n onDelete: function () {\n var oContext = this.getView().getBindingContext();\n var that = this;\n MessageBox.confirm(\"Delete this object?\", {\n onClose: function (sAction) {\n if (sAction !== MessageBox.Action.OK) {\n return;\n }\n oContext.delete(\"$auto\").then(function () {\n that.getOwnerComponent().markStale();\n MessageToast.show(\"Object deleted\");\n that._back();\n }, function (oError) {\n MessageBox.error(support.errorText(oError));\n });\n }\n });\n },\n\n onAction: function (oEvent) {\n var oPage = this._page();\n var oAction = support.action(oPage, oEvent.getSource().data(\"action\"));\n var oContext = this.getView().getBindingContext();\n var that = this;\n if (!oAction) {\n return;\n }\n support.invoke(this.getView(), oPage, oAction, oContext).then(function (oResult) {\n if (oResult === null) {\n return;\n }\n MessageToast.show(oAction.label + \": done\");\n that.getOwnerComponent().markStale();\n if (oAction.factory && oResult && oAction.returnsEntity) {\n that.getOwnerComponent().getRouter().navTo(that._sSet + \"Object\", { key: support.keyPredicate(oPage, oResult.getObject()) });\n return;\n }\n that.getView().getElementBinding().refresh();\n }, function (oError) {\n MessageBox.error(support.errorText(oError));\n });\n },\n\n onCreateChild: function (oEvent) {\n var oTable = this.byId(oEvent.getSource().data(\"table\"));\n oTable.getBinding(\"items\").create({}, true);\n },\n\n onDeleteChild: function (oEvent) {\n var oTable = this.byId(oEvent.getSource().data(\"table\"));\n var oItem = oTable.getSelectedItem();\n if (oItem) {\n oItem.getBindingContext().delete(this._ui().getProperty(\"/draft\") ? \"$auto\" : \"changes\");\n this._ui().setProperty(\"/childSelected\", false);\n }\n },\n\n onChildSelectionChange: function (oEvent) {\n this._ui().setProperty(\"/childSelected\", !!oEvent.getSource().getSelectedItem());\n },\n\n onChildPress: function (oEvent) {\n if (this._ui().getProperty(\"/editMode\")) {\n return;\n }\n var oItem = oEvent.getSource();\n var sSet = oItem.getParent().data(\"set\");\n this.getOwnerComponent().getRouter().navTo(sSet + \"Object\", { key: support.keyOf(oItem.getBindingContext().getPath()) });\n },\n\n onMessages: function (oEvent) {\n if (!this._oPopover) {\n this._oPopover = new MessagePopover({\n items: { path: \"message>/\", template: new MessageItem({ type: \"{message>type}\", title: \"{message>message}\", subtitle: \"{message>additionalText}\" }) }\n });\n this.getView().addDependent(this._oPopover);\n }\n this._oPopover.toggle(oEvent.getSource());\n }\n });\n});\n";
|