@sap-ux/preview-middleware 0.6.2 → 0.7.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.
- package/dist/base/flp.d.ts +1 -0
- package/dist/base/flp.js +49 -8
- package/dist/client/adp/controllers/AddFragment.controller.js +1 -27
- package/dist/client/adp/controllers/AddFragment.controller.ts +2 -24
- package/dist/client/cpe/changes/flex-change.js +46 -0
- package/dist/client/cpe/changes/flex-change.ts +49 -0
- package/dist/client/cpe/changes/index.js +12 -0
- package/dist/client/cpe/changes/index.ts +1 -0
- package/dist/client/cpe/changes/service.js +164 -0
- package/dist/client/cpe/changes/service.ts +264 -0
- package/dist/client/cpe/control-data.js +201 -0
- package/dist/client/cpe/control-data.ts +304 -0
- package/dist/client/cpe/documentation.js +166 -0
- package/dist/client/cpe/documentation.ts +166 -0
- package/dist/client/cpe/facade.js +95 -0
- package/dist/client/cpe/facade.ts +95 -0
- package/dist/client/cpe/init.js +62 -12
- package/dist/client/cpe/init.ts +70 -5
- package/dist/client/cpe/logger.js +32 -0
- package/dist/client/cpe/logger.ts +26 -0
- package/dist/client/cpe/outline/index.js +26 -0
- package/dist/client/cpe/outline/index.ts +34 -0
- package/dist/client/cpe/outline/nodes.js +58 -0
- package/dist/client/cpe/outline/nodes.ts +52 -0
- package/dist/client/cpe/outline/utils.js +38 -0
- package/dist/client/cpe/outline/utils.ts +29 -0
- package/dist/client/cpe/selection.js +169 -0
- package/dist/client/cpe/selection.ts +237 -0
- package/dist/client/cpe/types.js +6 -0
- package/dist/client/cpe/types.ts +53 -0
- package/dist/client/cpe/utils.js +50 -0
- package/dist/client/cpe/utils.ts +62 -0
- package/dist/client/flp/WorkspaceConnector.js +65 -0
- package/dist/client/flp/WorkspaceConnector.ts +66 -0
- package/dist/client/thirdparty/@sap-ux-private/control-property-editor-common.js +272 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/ui5/middleware.js +20 -1
- package/package.json +4 -3
- package/templates/flp/editor.html +11 -15
- package/templates/flp/sandbox.html +2 -1
- package/templates/flp/workspaceConnector.js +0 -76
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
sap.ui.define([
|
|
3
|
+
'open/ux/preview/client/thirdparty/@sap-ux-private/control-property-editor-common',
|
|
4
|
+
'./control-data',
|
|
5
|
+
'./utils',
|
|
6
|
+
'sap/base/Log',
|
|
7
|
+
'./documentation'
|
|
8
|
+
], function (___sap_ux_private_control_property_editor_common, ___control_data, ___utils, Log, ___documentation) {
|
|
9
|
+
'use strict';
|
|
10
|
+
const controlSelected = ___sap_ux_private_control_property_editor_common['controlSelected'];
|
|
11
|
+
const propertyChanged = ___sap_ux_private_control_property_editor_common['propertyChanged'];
|
|
12
|
+
const selectControl = ___sap_ux_private_control_property_editor_common['selectControl'];
|
|
13
|
+
const reportTelemetry = ___sap_ux_private_control_property_editor_common['reportTelemetry'];
|
|
14
|
+
const buildControlData = ___control_data['buildControlData'];
|
|
15
|
+
const getRuntimeControl = ___utils['getRuntimeControl'];
|
|
16
|
+
const getDocumentation = ___documentation['getDocumentation'];
|
|
17
|
+
function propertyChangeId(controlId, propertyName) {
|
|
18
|
+
return [
|
|
19
|
+
controlId,
|
|
20
|
+
propertyName
|
|
21
|
+
].join(',');
|
|
22
|
+
}
|
|
23
|
+
function getPropertyDocument(property, ui5Type, document) {
|
|
24
|
+
return document?.[property.name] ? document[property.name] : {
|
|
25
|
+
defaultValue: property.defaultValue ?? '-',
|
|
26
|
+
description: '',
|
|
27
|
+
propertyName: property.name,
|
|
28
|
+
type: ui5Type ?? '-',
|
|
29
|
+
propertyType: ui5Type ?? '-'
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async function addDocumentationForProperties(control, controlData) {
|
|
33
|
+
try {
|
|
34
|
+
const controlMetadata = control.getMetadata();
|
|
35
|
+
const allProperties = controlMetadata.getAllProperties();
|
|
36
|
+
const selectedControlName = controlMetadata.getName();
|
|
37
|
+
const selContLibName = controlMetadata.getLibraryName();
|
|
38
|
+
const document = await getDocumentation(selectedControlName, selContLibName);
|
|
39
|
+
controlData.properties.forEach(controlProp => {
|
|
40
|
+
const property = allProperties[controlProp.name];
|
|
41
|
+
controlProp.documentation = getPropertyDocument(property, controlProp.ui5Type, document);
|
|
42
|
+
});
|
|
43
|
+
} catch (e) {
|
|
44
|
+
Log.error('Document loading failed', e);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
class SelectionService {
|
|
48
|
+
appliedChangeCache = new Map();
|
|
49
|
+
activeChangeHandlers = new Set();
|
|
50
|
+
constructor(rta, ui5) {
|
|
51
|
+
this.rta = rta;
|
|
52
|
+
this.ui5 = ui5;
|
|
53
|
+
}
|
|
54
|
+
async init(sendAction, subscribe) {
|
|
55
|
+
const eventOrigin = new Set();
|
|
56
|
+
const onselectionChange = this.createOnSelectionChangeHandler(sendAction, eventOrigin);
|
|
57
|
+
this.rta.attachSelectionChange(event => {
|
|
58
|
+
onselectionChange(event).catch(error => Log.error('Event interrupted: ', error));
|
|
59
|
+
});
|
|
60
|
+
subscribe(async action => {
|
|
61
|
+
if (selectControl.match(action)) {
|
|
62
|
+
const id = action.payload;
|
|
63
|
+
const control = this.ui5.getControlById(id);
|
|
64
|
+
if (!control) {
|
|
65
|
+
const component = this.ui5.getComponent(id);
|
|
66
|
+
if (component) {
|
|
67
|
+
const controlData = buildControlData(component);
|
|
68
|
+
await addDocumentationForProperties(component, controlData);
|
|
69
|
+
const controlSelectedAction = controlSelected(controlData);
|
|
70
|
+
sendAction(controlSelectedAction);
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
eventOrigin.add('outline');
|
|
75
|
+
let controlOverlay = this.ui5.getOverlay(control);
|
|
76
|
+
const selectedOverlayControls = this.rta.getSelection() ?? [];
|
|
77
|
+
for (const selectedOverlayControl of selectedOverlayControls) {
|
|
78
|
+
selectedOverlayControl.setSelected(false);
|
|
79
|
+
}
|
|
80
|
+
if (!controlOverlay?.getDomRef()) {
|
|
81
|
+
controlOverlay = this.ui5.getClosestOverlayFor(control);
|
|
82
|
+
}
|
|
83
|
+
if (controlOverlay?.isSelectable()) {
|
|
84
|
+
controlOverlay.setSelected(true);
|
|
85
|
+
} else {
|
|
86
|
+
const controlData = buildControlData(control);
|
|
87
|
+
await addDocumentationForProperties(control, controlData);
|
|
88
|
+
const controlSelectedAction = controlSelected(controlData);
|
|
89
|
+
sendAction(controlSelectedAction);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
applyControlPropertyChange(controlId, propertyName) {
|
|
95
|
+
const changeId = propertyChangeId(controlId, propertyName);
|
|
96
|
+
this.appliedChangeCache.set(changeId, Date.now());
|
|
97
|
+
}
|
|
98
|
+
createOnSelectionChangeHandler(sendAction, eventOrigin) {
|
|
99
|
+
return async event => {
|
|
100
|
+
const selection = event.getParameter('selection');
|
|
101
|
+
for (const dispose of this.activeChangeHandlers) {
|
|
102
|
+
dispose();
|
|
103
|
+
}
|
|
104
|
+
this.activeChangeHandlers.clear();
|
|
105
|
+
if (Array.isArray(selection) && selection.length === 1) {
|
|
106
|
+
const overlayControl = this.ui5.getControlById(selection[0].getId());
|
|
107
|
+
if (overlayControl) {
|
|
108
|
+
const runtimeControl = getRuntimeControl(overlayControl);
|
|
109
|
+
const controlName = runtimeControl.getMetadata().getName();
|
|
110
|
+
this.handlePropertyChanges(runtimeControl, sendAction);
|
|
111
|
+
try {
|
|
112
|
+
const isOutline = eventOrigin.has('outline');
|
|
113
|
+
const name = controlName.toLowerCase().startsWith('sap') ? controlName : 'Other Control Types';
|
|
114
|
+
if (isOutline) {
|
|
115
|
+
reportTelemetry({
|
|
116
|
+
category: 'Outline Selection',
|
|
117
|
+
controlName: name
|
|
118
|
+
});
|
|
119
|
+
} else {
|
|
120
|
+
reportTelemetry({
|
|
121
|
+
category: 'Overlay Selection',
|
|
122
|
+
controlName: name
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
Log.error('Failed to report telemetry', error);
|
|
127
|
+
} finally {
|
|
128
|
+
const controlData = buildControlData(runtimeControl, overlayControl);
|
|
129
|
+
await addDocumentationForProperties(runtimeControl, controlData);
|
|
130
|
+
const action = controlSelected(controlData);
|
|
131
|
+
sendAction(action);
|
|
132
|
+
eventOrigin.delete('outline');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
handlePropertyChanges(runtimeControl, sendAction) {
|
|
139
|
+
const handler = e => {
|
|
140
|
+
const propertyName = e.getParameter('name');
|
|
141
|
+
const controlId = e.getParameter('id');
|
|
142
|
+
const changeId = propertyChangeId(controlId, propertyName);
|
|
143
|
+
const timestamp = this.appliedChangeCache.get(changeId);
|
|
144
|
+
if (timestamp) {
|
|
145
|
+
this.appliedChangeCache.delete(changeId);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const info = runtimeControl.getBindingInfo(propertyName);
|
|
149
|
+
const newValue = info?.path ?? e.getParameter('newValue');
|
|
150
|
+
const change = propertyChanged({
|
|
151
|
+
controlId,
|
|
152
|
+
propertyName,
|
|
153
|
+
newValue
|
|
154
|
+
});
|
|
155
|
+
sendAction(change);
|
|
156
|
+
};
|
|
157
|
+
runtimeControl.attachEvent('_change', handler);
|
|
158
|
+
this.activeChangeHandlers.add(() => {
|
|
159
|
+
try {
|
|
160
|
+
runtimeControl.detachEvent('_change', handler);
|
|
161
|
+
} catch {
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
var __exports = { __esModule: true };
|
|
167
|
+
__exports.SelectionService = SelectionService;
|
|
168
|
+
return __exports;
|
|
169
|
+
});
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import type { Control, ExternalAction } from '@sap-ux-private/control-property-editor-common';
|
|
2
|
+
import {
|
|
3
|
+
controlSelected,
|
|
4
|
+
propertyChanged,
|
|
5
|
+
selectControl,
|
|
6
|
+
reportTelemetry,
|
|
7
|
+
Properties
|
|
8
|
+
} from '@sap-ux-private/control-property-editor-common';
|
|
9
|
+
import { buildControlData } from './control-data';
|
|
10
|
+
import { getRuntimeControl, ManagedObjectMetadataProperties, PropertiesInfo } from './utils';
|
|
11
|
+
import type { ActionSenderFunction, Service, SubscribeFunction, UI5Facade } from './types';
|
|
12
|
+
|
|
13
|
+
import type Event from 'sap/ui/base/Event';
|
|
14
|
+
import type ElementOverlay from 'sap/ui/dt/ElementOverlay';
|
|
15
|
+
import type ManagedObject from 'sap/ui/base/ManagedObject';
|
|
16
|
+
import type { SelectionChangeEvent } from 'sap/ui/rta/RuntimeAuthoring';
|
|
17
|
+
import type RuntimeAuthoring from 'sap/ui/rta/RuntimeAuthoring';
|
|
18
|
+
import Log from 'sap/base/Log';
|
|
19
|
+
import { getDocumentation } from './documentation';
|
|
20
|
+
|
|
21
|
+
export interface PropertyChangeParams {
|
|
22
|
+
name: string;
|
|
23
|
+
id: string;
|
|
24
|
+
newValue: string;
|
|
25
|
+
}
|
|
26
|
+
export type PropertyChangeEvent = Event<PropertyChangeParams>;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Change id is a combination of controlId and propertyName.
|
|
30
|
+
*
|
|
31
|
+
* @param controlId unique identifier for a control.
|
|
32
|
+
* @param propertyName name of the control property.
|
|
33
|
+
* @returns string
|
|
34
|
+
*/
|
|
35
|
+
function propertyChangeId(controlId: string, propertyName: string): string {
|
|
36
|
+
return [controlId, propertyName].join(',');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Return document of a property.
|
|
41
|
+
*
|
|
42
|
+
* @param property - control metadata props.
|
|
43
|
+
* @param ui5Type - ui5 type
|
|
44
|
+
* @param document - property that is ignored during design time
|
|
45
|
+
* @returns PropertiesInfo
|
|
46
|
+
*/
|
|
47
|
+
function getPropertyDocument(
|
|
48
|
+
property: ManagedObjectMetadataProperties,
|
|
49
|
+
ui5Type?: string,
|
|
50
|
+
document?: Properties
|
|
51
|
+
): PropertiesInfo {
|
|
52
|
+
return document?.[property.name]
|
|
53
|
+
? document[property.name]
|
|
54
|
+
: ({
|
|
55
|
+
defaultValue: (property.defaultValue as string) ?? '-',
|
|
56
|
+
description: '',
|
|
57
|
+
propertyName: property.name,
|
|
58
|
+
type: ui5Type ?? '-',
|
|
59
|
+
propertyType: ui5Type ?? '-'
|
|
60
|
+
} as PropertiesInfo);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function addDocumentationForProperties(control: ManagedObject, controlData: Control): Promise<void> {
|
|
64
|
+
try {
|
|
65
|
+
const controlMetadata = control.getMetadata();
|
|
66
|
+
const allProperties = controlMetadata.getAllProperties() as unknown as {
|
|
67
|
+
[name: string]: ManagedObjectMetadataProperties;
|
|
68
|
+
};
|
|
69
|
+
const selectedControlName = controlMetadata.getName();
|
|
70
|
+
const selContLibName = controlMetadata.getLibraryName();
|
|
71
|
+
// Add the control's properties
|
|
72
|
+
const document = await getDocumentation(selectedControlName, selContLibName);
|
|
73
|
+
controlData.properties.forEach((controlProp) => {
|
|
74
|
+
const property = allProperties[controlProp.name];
|
|
75
|
+
controlProp.documentation = getPropertyDocument(property, controlProp.ui5Type, document);
|
|
76
|
+
});
|
|
77
|
+
} catch (e) {
|
|
78
|
+
Log.error('Document loading failed', e);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
*
|
|
84
|
+
*/
|
|
85
|
+
export class SelectionService implements Service {
|
|
86
|
+
private appliedChangeCache = new Map<string, number>();
|
|
87
|
+
private activeChangeHandlers = new Set<() => void>();
|
|
88
|
+
/**
|
|
89
|
+
*
|
|
90
|
+
* @param rta - rta object.
|
|
91
|
+
* @param ui5 - facade for ui5 framework methods
|
|
92
|
+
*/
|
|
93
|
+
constructor(private readonly rta: RuntimeAuthoring, private readonly ui5: UI5Facade) {}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Initialize selection service.
|
|
97
|
+
*
|
|
98
|
+
* @param sendAction action sender function
|
|
99
|
+
* @param subscribe subscriber function
|
|
100
|
+
*/
|
|
101
|
+
public async init(sendAction: ActionSenderFunction, subscribe: SubscribeFunction): Promise<void> {
|
|
102
|
+
const eventOrigin: Set<string> = new Set();
|
|
103
|
+
const onselectionChange = this.createOnSelectionChangeHandler(sendAction, eventOrigin);
|
|
104
|
+
this.rta.attachSelectionChange((event) => {
|
|
105
|
+
onselectionChange(event).catch((error) => Log.error('Event interrupted: ', error));
|
|
106
|
+
});
|
|
107
|
+
subscribe(async (action: ExternalAction): Promise<void> => {
|
|
108
|
+
if (selectControl.match(action)) {
|
|
109
|
+
const id = action.payload;
|
|
110
|
+
const control = this.ui5.getControlById(id);
|
|
111
|
+
if (!control) {
|
|
112
|
+
const component = this.ui5.getComponent(id);
|
|
113
|
+
if (component) {
|
|
114
|
+
const controlData = buildControlData(component);
|
|
115
|
+
|
|
116
|
+
// add document
|
|
117
|
+
await addDocumentationForProperties(component, controlData);
|
|
118
|
+
const controlSelectedAction = controlSelected(controlData);
|
|
119
|
+
sendAction(controlSelectedAction);
|
|
120
|
+
}
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
eventOrigin.add('outline');
|
|
124
|
+
let controlOverlay = this.ui5.getOverlay(control);
|
|
125
|
+
const selectedOverlayControls = this.rta.getSelection() ?? [];
|
|
126
|
+
//remove previous selection
|
|
127
|
+
for (const selectedOverlayControl of selectedOverlayControls) {
|
|
128
|
+
selectedOverlayControl.setSelected(false); //deselect previously selected control
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (!controlOverlay?.getDomRef()) {
|
|
132
|
+
//look for closest control in order to highlight in UI the (without firing the selection event)
|
|
133
|
+
controlOverlay = this.ui5.getClosestOverlayFor(control);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (controlOverlay?.isSelectable()) {
|
|
137
|
+
controlOverlay.setSelected(true); //highlight without firing event only if the layer is selectable
|
|
138
|
+
} else {
|
|
139
|
+
const controlData = buildControlData(control);
|
|
140
|
+
await addDocumentationForProperties(control, controlData);
|
|
141
|
+
const controlSelectedAction = controlSelected(controlData);
|
|
142
|
+
sendAction(controlSelectedAction);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
*
|
|
150
|
+
* @param controlId unique identifier for a control
|
|
151
|
+
* @param propertyName name of the control property.
|
|
152
|
+
*/
|
|
153
|
+
public applyControlPropertyChange(controlId: string, propertyName: string): void {
|
|
154
|
+
const changeId = propertyChangeId(controlId, propertyName);
|
|
155
|
+
this.appliedChangeCache.set(changeId, Date.now());
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Create handler for onSelectionChange.
|
|
160
|
+
*
|
|
161
|
+
* @param sendAction sending action method
|
|
162
|
+
* @param eventOrigin origin of the event.
|
|
163
|
+
* @returns (event: Event) => Promise<void>
|
|
164
|
+
*/
|
|
165
|
+
private createOnSelectionChangeHandler(
|
|
166
|
+
sendAction: (action: ExternalAction) => void,
|
|
167
|
+
eventOrigin: Set<string>
|
|
168
|
+
): (event: SelectionChangeEvent) => Promise<void> {
|
|
169
|
+
return async (event: SelectionChangeEvent): Promise<void> => {
|
|
170
|
+
const selection = event.getParameter('selection');
|
|
171
|
+
for (const dispose of this.activeChangeHandlers) {
|
|
172
|
+
dispose();
|
|
173
|
+
}
|
|
174
|
+
this.activeChangeHandlers.clear();
|
|
175
|
+
if (Array.isArray(selection) && selection.length === 1) {
|
|
176
|
+
const overlayControl = this.ui5.getControlById<ElementOverlay>(selection[0].getId());
|
|
177
|
+
if (overlayControl) {
|
|
178
|
+
const runtimeControl = getRuntimeControl(overlayControl);
|
|
179
|
+
const controlName = runtimeControl.getMetadata().getName();
|
|
180
|
+
this.handlePropertyChanges(runtimeControl, sendAction);
|
|
181
|
+
try {
|
|
182
|
+
const isOutline = eventOrigin.has('outline');
|
|
183
|
+
const name = controlName.toLowerCase().startsWith('sap') ? controlName : 'Other Control Types';
|
|
184
|
+
if (isOutline) {
|
|
185
|
+
reportTelemetry({ category: 'Outline Selection', controlName: name });
|
|
186
|
+
} else {
|
|
187
|
+
reportTelemetry({ category: 'Overlay Selection', controlName: name });
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
Log.error('Failed to report telemetry', error);
|
|
191
|
+
} finally {
|
|
192
|
+
const controlData = buildControlData(runtimeControl, overlayControl);
|
|
193
|
+
await addDocumentationForProperties(runtimeControl, controlData);
|
|
194
|
+
const action = controlSelected(controlData);
|
|
195
|
+
sendAction(action);
|
|
196
|
+
eventOrigin.delete('outline');
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
*
|
|
205
|
+
* @param runtimeControl sap/ui/base/ManagedObject
|
|
206
|
+
* @param sendAction send action method.
|
|
207
|
+
*/
|
|
208
|
+
private handlePropertyChanges(runtimeControl: ManagedObject, sendAction: (action: ExternalAction) => void): void {
|
|
209
|
+
const handler = (e: PropertyChangeEvent) => {
|
|
210
|
+
const propertyName = e.getParameter('name');
|
|
211
|
+
const controlId = e.getParameter('id');
|
|
212
|
+
const changeId = propertyChangeId(controlId, propertyName);
|
|
213
|
+
const timestamp = this.appliedChangeCache.get(changeId);
|
|
214
|
+
if (timestamp) {
|
|
215
|
+
// Change originated from control property editor, we do not need to notify it
|
|
216
|
+
this.appliedChangeCache.delete(changeId);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const info: { path?: string } = runtimeControl.getBindingInfo(propertyName);
|
|
220
|
+
const newValue = info?.path ?? e.getParameter('newValue');
|
|
221
|
+
const change = propertyChanged({
|
|
222
|
+
controlId,
|
|
223
|
+
propertyName,
|
|
224
|
+
newValue
|
|
225
|
+
});
|
|
226
|
+
sendAction(change);
|
|
227
|
+
};
|
|
228
|
+
runtimeControl.attachEvent('_change', handler);
|
|
229
|
+
this.activeChangeHandlers.add(() => {
|
|
230
|
+
try {
|
|
231
|
+
runtimeControl.detachEvent('_change', handler);
|
|
232
|
+
} catch {
|
|
233
|
+
// control has already been cleaned up, nothing to do here
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ExternalAction, IconDetails } from '@sap-ux-private/control-property-editor-common';
|
|
2
|
+
import type RuntimeAuthoring from 'sap/ui/rta/RuntimeAuthoring';
|
|
3
|
+
import type Element from 'sap/ui/core/Element';
|
|
4
|
+
import type { ID } from 'sap/ui/core/library';
|
|
5
|
+
import type ElementOverlay from 'sap/ui/dt/ElementOverlay';
|
|
6
|
+
import type Component from 'sap/ui/core/Component';
|
|
7
|
+
|
|
8
|
+
export interface UI5AdaptationOptions {
|
|
9
|
+
rta: RuntimeAuthoring;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type PrimitiveTypes = 'boolean' | 'enum' | 'float' | 'string' | 'any';
|
|
13
|
+
export type PropertyValue = boolean | object | number | string;
|
|
14
|
+
|
|
15
|
+
export interface UI5ControlProperty {
|
|
16
|
+
defaultValue: unknown;
|
|
17
|
+
enumValues: { [key: string]: string } | null;
|
|
18
|
+
isArray: boolean;
|
|
19
|
+
isDeprecated: boolean;
|
|
20
|
+
isEnabled: boolean;
|
|
21
|
+
isIcon: boolean;
|
|
22
|
+
name: string;
|
|
23
|
+
primitiveType: string;
|
|
24
|
+
ui5Type: string | null;
|
|
25
|
+
value: PropertyValue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface UI5ControlData {
|
|
29
|
+
allowIndexForDefaultAggregation: boolean;
|
|
30
|
+
defaultAggregation: string;
|
|
31
|
+
id: string;
|
|
32
|
+
properties: UI5ControlProperty[];
|
|
33
|
+
selectedControlChildren: string[];
|
|
34
|
+
selectedControlName: string;
|
|
35
|
+
targetAggregation: string[];
|
|
36
|
+
type: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type ActionHandler = (action: ExternalAction) => Promise<void>;
|
|
40
|
+
export type ActionSenderFunction = (action: ExternalAction) => void;
|
|
41
|
+
export type SubscribeFunction = (handler: ActionHandler) => void;
|
|
42
|
+
|
|
43
|
+
export interface Service {
|
|
44
|
+
init(sendAction: ActionSenderFunction, subscribe: SubscribeFunction): void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface UI5Facade {
|
|
48
|
+
getControlById: <T extends Element>(id: ID) => T | undefined;
|
|
49
|
+
getIcons: () => IconDetails[];
|
|
50
|
+
getComponent: <T extends Component>(id: ID) => T | undefined;
|
|
51
|
+
getOverlay: <T extends ElementOverlay>(control: Element) => T | undefined;
|
|
52
|
+
getClosestOverlayFor: <T extends ElementOverlay>(control: Element) => T | undefined;
|
|
53
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
sap.ui.define([], function () {
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get runtime control.
|
|
8
|
+
*
|
|
9
|
+
* @param overlayControl - element overlay.
|
|
10
|
+
* @returns ManagedObject
|
|
11
|
+
*/
|
|
12
|
+
function getRuntimeControl(overlayControl) {
|
|
13
|
+
let runtimeControl;
|
|
14
|
+
if (overlayControl.getElementInstance) {
|
|
15
|
+
runtimeControl = overlayControl.getElementInstance();
|
|
16
|
+
} else {
|
|
17
|
+
runtimeControl = overlayControl.getElement();
|
|
18
|
+
}
|
|
19
|
+
return runtimeControl;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get library of a control name.
|
|
24
|
+
*
|
|
25
|
+
* @param controlName - name of the ui5 control eg: sap.m.Button.
|
|
26
|
+
* @returns Promise<string>
|
|
27
|
+
*/
|
|
28
|
+
async function getLibrary(controlName) {
|
|
29
|
+
return new Promise(resolve => {
|
|
30
|
+
const controlPath = controlName.replace(/\./g, '/');
|
|
31
|
+
sap.ui.require([controlPath], control => {
|
|
32
|
+
const contMetadata = control.getMetadata();
|
|
33
|
+
// getLibraryName method does not exist on events
|
|
34
|
+
if (contMetadata?.getLibraryName) {
|
|
35
|
+
const contLibName = contMetadata.getLibraryName();
|
|
36
|
+
resolve(contLibName);
|
|
37
|
+
} else {
|
|
38
|
+
resolve(''); // return empty for events
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
var __exports = {
|
|
44
|
+
__esModule: true
|
|
45
|
+
};
|
|
46
|
+
__exports.getRuntimeControl = getRuntimeControl;
|
|
47
|
+
__exports.getLibrary = getLibrary;
|
|
48
|
+
return __exports;
|
|
49
|
+
});
|
|
50
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type ManagedObject from 'sap/ui/base/ManagedObject';
|
|
2
|
+
import type Control from 'sap/ui/core/Control';
|
|
3
|
+
import type ElementOverlay from 'sap/ui/dt/ElementOverlay';
|
|
4
|
+
import DataType from 'sap/ui/base/DataType';
|
|
5
|
+
|
|
6
|
+
export interface PropertiesInfo {
|
|
7
|
+
defaultValue: string;
|
|
8
|
+
description: string;
|
|
9
|
+
propertyName: string;
|
|
10
|
+
type: string;
|
|
11
|
+
propertyType: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
export interface Properties {
|
|
14
|
+
[key: string]: PropertiesInfo;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ManagedObjectMetadataProperties {
|
|
18
|
+
name: string;
|
|
19
|
+
defaultValue: string | null;
|
|
20
|
+
deprecated: boolean;
|
|
21
|
+
getType: () => DataType;
|
|
22
|
+
getName: () => string;
|
|
23
|
+
getDefaultValue: () => unknown;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get runtime control.
|
|
28
|
+
*
|
|
29
|
+
* @param overlayControl - element overlay.
|
|
30
|
+
* @returns ManagedObject
|
|
31
|
+
*/
|
|
32
|
+
export function getRuntimeControl(overlayControl: ElementOverlay): ManagedObject {
|
|
33
|
+
let runtimeControl;
|
|
34
|
+
if (overlayControl.getElementInstance) {
|
|
35
|
+
runtimeControl = overlayControl.getElementInstance();
|
|
36
|
+
} else {
|
|
37
|
+
runtimeControl = overlayControl.getElement();
|
|
38
|
+
}
|
|
39
|
+
return runtimeControl;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get library of a control name.
|
|
44
|
+
*
|
|
45
|
+
* @param controlName - name of the ui5 control eg: sap.m.Button.
|
|
46
|
+
* @returns Promise<string>
|
|
47
|
+
*/
|
|
48
|
+
export async function getLibrary(controlName: string): Promise<string> {
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
const controlPath = controlName.replace(/\./g, '/');
|
|
51
|
+
sap.ui.require([controlPath], (control: Control) => {
|
|
52
|
+
const contMetadata = control.getMetadata();
|
|
53
|
+
// getLibraryName method does not exist on events
|
|
54
|
+
if (contMetadata?.getLibraryName) {
|
|
55
|
+
const contLibName = contMetadata.getLibraryName();
|
|
56
|
+
resolve(contLibName);
|
|
57
|
+
} else {
|
|
58
|
+
resolve(''); // return empty for events
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
sap.ui.define(["sap/base/util/merge", "sap/ui/fl/write/api/connectors/ObjectStorageConnector", "sap/ui/fl/Layer", "sap/ui/VersionInfo"], function (merge, ObjectStorageConnector, Layer, VersionInfo) {
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
const path = '/preview/api/changes';
|
|
7
|
+
const connector = merge({}, ObjectStorageConnector, {
|
|
8
|
+
layers: [Layer.VENDOR, Layer.CUSTOMER_BASE],
|
|
9
|
+
storage: {
|
|
10
|
+
_itemsStoredAsObjects: true,
|
|
11
|
+
setItem: function (_key, change) {
|
|
12
|
+
return fetch(path, {
|
|
13
|
+
method: 'POST',
|
|
14
|
+
body: JSON.stringify(change, null, 2),
|
|
15
|
+
headers: {
|
|
16
|
+
'content-type': 'application/json'
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
removeItem: function (key) {
|
|
21
|
+
return fetch(path, {
|
|
22
|
+
method: 'DELETE',
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
fileName: key
|
|
25
|
+
}),
|
|
26
|
+
headers: {
|
|
27
|
+
'content-type': 'application/json'
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
clear: function () {
|
|
32
|
+
// not implemented
|
|
33
|
+
},
|
|
34
|
+
getItem: function (_key) {
|
|
35
|
+
// not implemented
|
|
36
|
+
},
|
|
37
|
+
getItems: async function () {
|
|
38
|
+
const response = await fetch(path, {
|
|
39
|
+
method: 'GET',
|
|
40
|
+
headers: {
|
|
41
|
+
'content-type': 'application/json'
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const changes = await response.json();
|
|
45
|
+
return changes;
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
loadFeatures: async function () {
|
|
49
|
+
const features = await ObjectStorageConnector.loadFeatures();
|
|
50
|
+
const ui5Version = await VersionInfo.load();
|
|
51
|
+
const [majorVersion, minorVersion] = ui5Version.version.split('.').map(v => parseInt(v, 10));
|
|
52
|
+
features.isVariantAdaptationEnabled = majorVersion >= 1 && minorVersion >= 90;
|
|
53
|
+
const bootstrapConfig = document.getElementById('sap-ui-bootstrap');
|
|
54
|
+
if (bootstrapConfig) {
|
|
55
|
+
const settings = bootstrapConfig.getAttribute('data-open-ux-preview-flex-settings');
|
|
56
|
+
if (settings && JSON.parse(settings).developerMode) {
|
|
57
|
+
features.isVariantAdaptationEnabled = false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return features;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return connector;
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=WorkspaceConnector.js.map
|