@sap-ux/preview-middleware 0.8.7 → 0.10.0

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.
@@ -0,0 +1,103 @@
1
+ import type View from 'sap/ui/core/mvc/View';
2
+ import type UI5Element from 'sap/ui/core/Element';
3
+ import type RuntimeAuthoring from 'sap/ui/rta/RuntimeAuthoring';
4
+ import AddXMLAtExtensionPoint from 'sap/ui/rta/plugin/AddXMLAtExtensionPoint';
5
+ import CommandFactory from 'sap/ui/rta/command/CommandFactory';
6
+
7
+ import { ExternalAction, addExtensionPoint } from '@sap-ux-private/control-property-editor-common';
8
+
9
+ import { Deferred, createDeferred } from './utils';
10
+
11
+ import { SubscribeFunction } from '../cpe/types';
12
+ import { DialogNames, handler } from './init-dialogs';
13
+
14
+ type ActionService = {
15
+ execute: (controlId: string, actionId: string) => void;
16
+ };
17
+
18
+ type DeferredExtPointData = {
19
+ fragmentPath: string;
20
+ extensionPointName: string | undefined;
21
+ };
22
+
23
+ export interface ExtensionPointData {
24
+ name: string;
25
+ deffered: Deferred<DeferredExtPointData>;
26
+ index?: number;
27
+ view?: View;
28
+ createdControls?: [];
29
+ fragmentId?: string;
30
+ aggregation?: string[];
31
+ aggregationName?: string;
32
+ defaultContent?: string[];
33
+ targetControl?: UI5Element;
34
+ }
35
+
36
+ export default class ExtensionPointService {
37
+ private readonly actionId = 'CTX_ADDXML_AT_EXTENSIONPOINT';
38
+
39
+ /**
40
+ * @param rta Runtime Authoring
41
+ */
42
+ constructor(private readonly rta: RuntimeAuthoring) {}
43
+
44
+ /**
45
+ * Initializes communication with CPE, and the extension point plugin.
46
+ *
47
+ * @param subscribe Handles actions from CPE
48
+ */
49
+ public init(subscribe: SubscribeFunction) {
50
+ this.initPlugin();
51
+ subscribe(async (action: ExternalAction): Promise<void> => {
52
+ if (addExtensionPoint.match(action)) {
53
+ try {
54
+ const { controlId } = action.payload;
55
+
56
+ const service = await this.rta.getService<ActionService>('action');
57
+
58
+ service.execute(controlId, this.actionId);
59
+ } catch (e) {
60
+ throw new Error(`Failed to execute service with actionId: ${this.actionId}`);
61
+ }
62
+ }
63
+ });
64
+ }
65
+
66
+ /**
67
+ * Initializes Add XML at Extension Point plugin and adds it to the default RTA plugins.
68
+ */
69
+ public initPlugin() {
70
+ const flexSettings = this.rta.getFlexSettings();
71
+ const commandFactory = new CommandFactory({
72
+ flexSettings
73
+ });
74
+
75
+ const plugin = new AddXMLAtExtensionPoint({
76
+ commandFactory,
77
+ fragmentHandler: async (overlay: UI5Element, info: ExtensionPointData[]) =>
78
+ await this.fragmentHandler(overlay, info[0])
79
+ });
80
+
81
+ const defaultPlugins = this.rta.getDefaultPlugins();
82
+ defaultPlugins.addXMLAtExtensionPoint = plugin;
83
+ this.rta.setPlugins(defaultPlugins);
84
+ }
85
+
86
+ /**
87
+ * Handler function for AddXMLAtExtensionPoint plugin.
88
+ *
89
+ * @param overlay UI5 Element overlay
90
+ * @param info Extension point data from the plugin
91
+ * @returns Deffered extension point data that is provided to the plugin
92
+ */
93
+ public async fragmentHandler(overlay: UI5Element, info: ExtensionPointData): Promise<DeferredExtPointData> {
94
+ let deffered = createDeferred<DeferredExtPointData>();
95
+
96
+ await handler(overlay, this.rta, DialogNames.ADD_FRAGMENT_AT_EXTENSION_POINT, {
97
+ name: info.name,
98
+ deffered
99
+ } as ExtensionPointData);
100
+
101
+ return deffered.promise;
102
+ }
103
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- sap.ui.define(["sap/ui/core/mvc/XMLView", "./controllers/AddFragment.controller", "./controllers/ControllerExtension.controller"], function (XMLView, __AddFragment, __ControllerExtension) {
3
+ sap.ui.define(["sap/ui/core/mvc/XMLView", "./controllers/AddFragment.controller", "./controllers/ControllerExtension.controller", "./controllers/ExtensionPoint.controller"], function (XMLView, __AddFragment, __ControllerExtension, __ExtensionPoint) {
4
4
  "use strict";
5
5
 
6
6
  function _interopRequireDefault(obj) {
@@ -8,9 +8,11 @@ sap.ui.define(["sap/ui/core/mvc/XMLView", "./controllers/AddFragment.controller"
8
8
  }
9
9
  const AddFragment = _interopRequireDefault(__AddFragment);
10
10
  const ControllerExtension = _interopRequireDefault(__ControllerExtension);
11
+ const ExtensionPoint = _interopRequireDefault(__ExtensionPoint);
11
12
  var DialogNames = /*#__PURE__*/function (DialogNames) {
12
13
  DialogNames["ADD_FRAGMENT"] = "AddFragment";
13
14
  DialogNames["CONTROLLER_EXTENSION"] = "ControllerExtension";
15
+ DialogNames["ADD_FRAGMENT_AT_EXTENSION_POINT"] = "ExtensionPoint";
14
16
  return DialogNames;
15
17
  }(DialogNames || {});
16
18
  /**
@@ -40,12 +42,26 @@ sap.ui.define(["sap/ui/core/mvc/XMLView", "./controllers/AddFragment.controller"
40
42
  * @param overlays Control overlays
41
43
  * @param rta Runtime Authoring
42
44
  * @param dialogName Dialog name
45
+ * @param extensionPointData Control ID
43
46
  */
44
- async function handler(overlays, rta, dialogName) {
45
- const controller = dialogName === DialogNames.ADD_FRAGMENT ? new AddFragment(`open.ux.preview.client.adp.controllers.${dialogName}`, overlays, rta) : new ControllerExtension(`open.ux.preview.client.adp.controllers.${dialogName}`, overlays, rta);
47
+ async function handler(overlays, rta, dialogName, extensionPointData) {
48
+ let controller;
49
+ switch (dialogName) {
50
+ case DialogNames.ADD_FRAGMENT:
51
+ controller = new AddFragment(`open.ux.preview.client.adp.controllers.${dialogName}`, overlays, rta);
52
+ break;
53
+ case DialogNames.CONTROLLER_EXTENSION:
54
+ controller = new ControllerExtension(`open.ux.preview.client.adp.controllers.${dialogName}`, overlays, rta);
55
+ break;
56
+ case DialogNames.ADD_FRAGMENT_AT_EXTENSION_POINT:
57
+ controller = new ExtensionPoint(`open.ux.preview.client.adp.controllers.${dialogName}`, overlays, rta, extensionPointData);
58
+ break;
59
+ }
60
+ const id = dialogName === DialogNames.ADD_FRAGMENT_AT_EXTENSION_POINT ? `dialog--${dialogName}` : undefined;
46
61
  await XMLView.create({
47
62
  viewName: `open.ux.preview.client.adp.ui.${dialogName}`,
48
- controller
63
+ controller,
64
+ id
49
65
  });
50
66
  }
51
67
  var __exports = {
@@ -7,12 +7,17 @@ import type RuntimeAuthoring from 'sap/ui/rta/RuntimeAuthoring';
7
7
 
8
8
  import AddFragment from './controllers/AddFragment.controller';
9
9
  import ControllerExtension from './controllers/ControllerExtension.controller';
10
+ import { ExtensionPointData } from './extension-point';
11
+ import ExtensionPoint from './controllers/ExtensionPoint.controller';
10
12
 
11
13
  export const enum DialogNames {
12
14
  ADD_FRAGMENT = 'AddFragment',
13
- CONTROLLER_EXTENSION = 'ControllerExtension'
15
+ CONTROLLER_EXTENSION = 'ControllerExtension',
16
+ ADD_FRAGMENT_AT_EXTENSION_POINT = 'ExtensionPoint'
14
17
  }
15
18
 
19
+ type Controller = AddFragment | ControllerExtension | ExtensionPoint;
20
+
16
21
  /**
17
22
  * Adds a new item to the context menu
18
23
  *
@@ -42,15 +47,38 @@ export const initDialogs = (rta: RuntimeAuthoring): void => {
42
47
  * @param overlays Control overlays
43
48
  * @param rta Runtime Authoring
44
49
  * @param dialogName Dialog name
50
+ * @param extensionPointData Control ID
45
51
  */
46
- export async function handler(overlays: UI5Element, rta: RuntimeAuthoring, dialogName: DialogNames): Promise<void> {
47
- const controller =
48
- dialogName === DialogNames.ADD_FRAGMENT
49
- ? new AddFragment(`open.ux.preview.client.adp.controllers.${dialogName}`, overlays, rta)
50
- : new ControllerExtension(`open.ux.preview.client.adp.controllers.${dialogName}`, overlays, rta);
52
+ export async function handler(
53
+ overlays: UI5Element,
54
+ rta: RuntimeAuthoring,
55
+ dialogName: DialogNames,
56
+ extensionPointData?: ExtensionPointData
57
+ ): Promise<void> {
58
+ let controller: Controller;
59
+
60
+ switch (dialogName) {
61
+ case DialogNames.ADD_FRAGMENT:
62
+ controller = new AddFragment(`open.ux.preview.client.adp.controllers.${dialogName}`, overlays, rta);
63
+ break;
64
+ case DialogNames.CONTROLLER_EXTENSION:
65
+ controller = new ControllerExtension(`open.ux.preview.client.adp.controllers.${dialogName}`, overlays, rta);
66
+ break;
67
+ case DialogNames.ADD_FRAGMENT_AT_EXTENSION_POINT:
68
+ controller = new ExtensionPoint(
69
+ `open.ux.preview.client.adp.controllers.${dialogName}`,
70
+ overlays,
71
+ rta,
72
+ extensionPointData!
73
+ );
74
+ break;
75
+ }
76
+
77
+ const id = dialogName === DialogNames.ADD_FRAGMENT_AT_EXTENSION_POINT ? `dialog--${dialogName}` : undefined;
51
78
 
52
79
  await XMLView.create({
53
80
  viewName: `open.ux.preview.client.adp.ui.${dialogName}`,
54
- controller
81
+ controller,
82
+ id
55
83
  });
56
84
  }
@@ -1,20 +1,38 @@
1
- "use strict";
2
-
3
- sap.ui.define(["sap/base/Log", "../cpe/init", "./init-dialogs"], function (log, __init, ___init_dialogs) {
4
- "use strict";
5
-
6
- function _interopRequireDefault(obj) {
7
- return obj && obj.__esModule && typeof obj.default !== "undefined" ? obj.default : obj;
8
- }
9
- const init = _interopRequireDefault(__init);
10
- const initDialogs = ___init_dialogs["initDialogs"];
11
- var __exports = function (rta) {
12
- // initialize fragment content menu entry
13
- initDialogs(rta);
14
- // also initialize the editor
15
- init(rta);
16
- log.debug('ADP init executed.');
17
- };
18
- return __exports;
19
- });
20
- //# sourceMappingURL=init.js.map
1
+ 'use strict';
2
+ sap.ui.define([
3
+ 'sap/base/Log',
4
+ '../cpe/init',
5
+ './init-dialogs',
6
+ 'open/ux/preview/client/thirdparty/@sap-ux-private/control-property-editor-common',
7
+ './extension-point'
8
+ ], function (log, __init, ___init_dialogs, ___sap_ux_private_control_property_editor_common, __ExtensionPointService) {
9
+ 'use strict';
10
+ function _interopRequireDefault(obj) {
11
+ return obj && obj.__esModule && typeof obj.default !== 'undefined' ? obj.default : obj;
12
+ }
13
+ const init = _interopRequireDefault(__init);
14
+ const initDialogs = ___init_dialogs['initDialogs'];
15
+ const startPostMessageCommunication = ___sap_ux_private_control_property_editor_common['startPostMessageCommunication'];
16
+ const ExtensionPointService = _interopRequireDefault(__ExtensionPointService);
17
+ var __exports = function (rta) {
18
+ const extPointService = new ExtensionPointService(rta);
19
+ const actionHandlers = [];
20
+ function subscribe(handler) {
21
+ actionHandlers.push(handler);
22
+ }
23
+ startPostMessageCommunication(window.parent, async function onAction(action) {
24
+ for (const handler of actionHandlers) {
25
+ try {
26
+ await handler(action);
27
+ } catch (error) {
28
+ log.error('Handler Failed: ', error);
29
+ }
30
+ }
31
+ });
32
+ initDialogs(rta);
33
+ extPointService.init(subscribe);
34
+ init(rta);
35
+ log.debug('ADP init executed.');
36
+ };
37
+ return __exports;
38
+ });
@@ -3,10 +3,34 @@ import type RuntimeAuthoring from 'sap/ui/rta/RuntimeAuthoring';
3
3
 
4
4
  import init from '../cpe/init';
5
5
  import { initDialogs } from './init-dialogs';
6
+ import { ExternalAction, startPostMessageCommunication } from '@sap-ux-private/control-property-editor-common';
7
+ import { ActionHandler } from '../cpe/types';
8
+ import ExtensionPointService from './extension-point';
6
9
 
7
10
  export default function (rta: RuntimeAuthoring) {
11
+ const extPointService = new ExtensionPointService(rta);
12
+ const actionHandlers: ActionHandler[] = [];
13
+ /**
14
+ *
15
+ * @param handler action handler
16
+ */
17
+ function subscribe(handler: ActionHandler): void {
18
+ actionHandlers.push(handler);
19
+ }
20
+
21
+ startPostMessageCommunication<ExternalAction>(window.parent, async function onAction(action) {
22
+ for (const handler of actionHandlers) {
23
+ try {
24
+ await handler(action);
25
+ } catch (error) {
26
+ log.error('Handler Failed: ', error);
27
+ }
28
+ }
29
+ });
8
30
  // initialize fragment content menu entry
9
31
  initDialogs(rta);
32
+ // initialize extension point service
33
+ extPointService.init(subscribe);
10
34
  // also initialize the editor
11
35
  init(rta);
12
36
  log.debug('ADP init executed.');
@@ -0,0 +1,40 @@
1
+ <mvc:View xmlns:mvc="sap.ui.core.mvc"
2
+ xmlns="sap.m"
3
+ xmlns:core="sap.ui.core"
4
+ xmlns:f="sap.ui.layout.form">
5
+ <Dialog id="addFragmentAtExtPointDialog" title="Add XML Fragment at Extension Point" contentWidth="500px" class="sapUiRTABorder">
6
+ <content>
7
+ <f:SimpleForm id="addFragmentAtExtPointDialog_Form"
8
+ editable="true"
9
+ layout="ResponsiveGridLayout"
10
+ labelSpanS="4"
11
+ singleContainerFullSize="false">
12
+ <f:content>
13
+ <Label text="Extension Point" />
14
+ <Text text="{/extensionPointName}" />
15
+ <Label text="Fragment Name" />
16
+ <Input
17
+ description=".fragment.xml"
18
+ value="{/newFragmentName}"
19
+ liveChange="onFragmentNameInputChange">
20
+ </Input>
21
+ </f:content>
22
+ </f:SimpleForm>
23
+ </content>
24
+ <beginButton>
25
+ <Button
26
+ id="createDialogBtn"
27
+ text="Create"
28
+ press="onCreateBtnPress"
29
+ enabled="false"
30
+ type="Emphasized" />
31
+ </beginButton>
32
+ <endButton>
33
+ <Button
34
+ id="closeDialogBtn"
35
+ text="Cancel"
36
+ press="handleDialogClose"
37
+ type="Reject" />
38
+ </endButton>
39
+ </Dialog>
40
+ </mvc:View>
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+
3
+ sap.ui.define([], function () {
4
+ "use strict";
5
+
6
+ /**
7
+ * Defers the resolution of the promise, stores resolve/reject functions so that they can be accessed at a later stage.
8
+ *
9
+ * @description A Deferred object contains an unresolved promise along with the functions to resolve or reject that promise.
10
+ *
11
+ * @returns {Deferred} Deferred object
12
+ */
13
+ function createDeferred() {
14
+ let resolve = null;
15
+ let reject = null;
16
+ const promise = new Promise((res, rej) => {
17
+ resolve = res;
18
+ reject = rej;
19
+ });
20
+ if (resolve === null || reject === null) {
21
+ throw new Error('Failed to initialize resolve and reject functions.');
22
+ }
23
+ return {
24
+ promise,
25
+ resolve,
26
+ reject
27
+ };
28
+ }
29
+ var __exports = {
30
+ __esModule: true
31
+ };
32
+ __exports.createDeferred = createDeferred;
33
+ return __exports;
34
+ });
35
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1,28 @@
1
+ export interface Deferred<T> {
2
+ promise: Promise<T>;
3
+ resolve: (value: T | PromiseLike<T>) => void;
4
+ reject: (reason?: unknown) => void;
5
+ }
6
+
7
+ /**
8
+ * Defers the resolution of the promise, stores resolve/reject functions so that they can be accessed at a later stage.
9
+ *
10
+ * @description A Deferred object contains an unresolved promise along with the functions to resolve or reject that promise.
11
+ *
12
+ * @returns {Deferred} Deferred object
13
+ */
14
+ export function createDeferred<T>(): Deferred<T> {
15
+ let resolve: Deferred<T>['resolve'] | null = null;
16
+ let reject: Deferred<T>['reject'] | null = null;
17
+
18
+ const promise = new Promise<T>((res, rej) => {
19
+ resolve = res;
20
+ reject = rej;
21
+ });
22
+
23
+ if (resolve === null || reject === null) {
24
+ throw new Error('Failed to initialize resolve and reject functions.');
25
+ }
26
+
27
+ return { promise, resolve, reject };
28
+ }
@@ -75,6 +75,9 @@ sap.ui.define([
75
75
  ].every(item => item === undefined || item === null)) {
76
76
  throw new Error('Invalid change, missing new value in the change file');
77
77
  }
78
+ if (change.changeType !== 'propertyChange' && change.changeType !== 'propertyBindingChange') {
79
+ throw new Error('Unknown Change Type');
80
+ }
78
81
  return {
79
82
  type: 'saved',
80
83
  kind: 'valid',
@@ -83,14 +86,16 @@ sap.ui.define([
83
86
  propertyName: change.content.property,
84
87
  value: change.content.newValue ?? change.content.newBinding,
85
88
  timestamp: new Date(change.creation).getTime(),
86
- controlName: change.selector.type.split('.').pop()
89
+ controlName: change.selector.type ? change.selector.type.split('.').pop() : '',
90
+ changeType: change.changeType
87
91
  };
88
92
  } catch (error) {
89
93
  if (change.fileName) {
90
94
  const unknownChange = {
91
95
  type: 'saved',
92
96
  kind: 'unknown',
93
- fileName: change.fileName
97
+ fileName: change.fileName,
98
+ controlId: change.selector?.id
94
99
  };
95
100
  if (change.creation) {
96
101
  unknownChange.timestamp = new Date(change.creation).getTime();
@@ -121,41 +126,62 @@ sap.ui.define([
121
126
  const allCommands = stack.getCommands();
122
127
  const executedCommands = stack.getAllExecutedCommands();
123
128
  const inactiveCommandCount = allCommands.length - executedCommands.length;
124
- const activeChanges = allCommands.map((command, i) => {
125
- let result;
129
+ let activeChanges = [];
130
+ allCommands.forEach((command, i) => {
126
131
  try {
127
- const selector = command.getProperty('selector');
128
- const changeType = command.getProperty('changeType');
129
- let value = '';
130
- switch (changeType) {
131
- case 'propertyChange':
132
- value = command.getProperty('newValue');
133
- break;
134
- case 'propertyBindingChange':
135
- value = command.getProperty('newBinding');
136
- break;
137
- default:
138
- throw new Error(`Invalid changeType ${ changeType }`);
132
+ if (typeof command.getCommands === 'function') {
133
+ const subCommands = command.getCommands();
134
+ subCommands.forEach(command => {
135
+ activeChanges.push(this.prepareChangeType(command, inactiveCommandCount, i));
136
+ });
137
+ } else {
138
+ activeChanges.push(this.prepareChangeType(command, inactiveCommandCount, i));
139
139
  }
140
- result = {
141
- type: 'pending',
142
- controlId: selector.id,
143
- propertyName: command.getProperty('propertyName'),
144
- isActive: i >= inactiveCommandCount,
145
- value,
146
- controlName: command.getElement().getMetadata().getName().split('.').pop() ?? ''
147
- };
148
140
  } catch (error) {
149
- Log.error('Failed: ', error);
141
+ Log.error('CPE: Change creation Failed', error);
150
142
  }
151
- return result;
152
- }).filter(change => !!change);
143
+ });
144
+ activeChanges = activeChanges.filter(change => !!change);
153
145
  sendAction(changeStackModified({
154
146
  saved: this.savedChanges,
155
147
  pending: activeChanges
156
148
  }));
157
149
  };
158
150
  }
151
+ prepareChangeType(command, inactiveCommandCount, index) {
152
+ let result;
153
+ let value = '';
154
+ const selector = command.getSelector();
155
+ const changeType = command.getChangeType();
156
+ switch (changeType) {
157
+ case 'propertyChange':
158
+ value = command.getProperty('newValue');
159
+ break;
160
+ case 'propertyBindingChange':
161
+ value = command.getProperty('newBinding');
162
+ break;
163
+ }
164
+ if (changeType === 'propertyChange' || changeType === 'propertyBindingChange') {
165
+ result = {
166
+ type: 'pending',
167
+ changeType,
168
+ controlId: selector.id,
169
+ propertyName: command.getProperty('propertyName'),
170
+ isActive: index >= inactiveCommandCount,
171
+ value,
172
+ controlName: command.getElement().getMetadata().getName().split('.').pop() ?? ''
173
+ };
174
+ } else {
175
+ result = {
176
+ type: 'pending',
177
+ controlId: selector.id,
178
+ changeType,
179
+ isActive: index >= inactiveCommandCount,
180
+ controlName: command.getElement().getMetadata().getName().split('.').pop() ?? ''
181
+ };
182
+ }
183
+ return result;
184
+ }
159
185
  }
160
186
  var __exports = { __esModule: true };
161
187
  __exports.ChangeService = ChangeService;