@shopgate/pwa-core 7.30.0-alpha.7 → 7.30.0-alpha.8
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/classes/AppCommand/index.js +115 -11
- package/classes/AppCommand/spec.js +260 -6
- package/classes/AppCommandRequest/index.js +129 -20
- package/classes/AppPermissionsRequest/AppPermissionsRequest.js +45 -7
- package/classes/AppPermissionsRequest/GetAppPermissionsRequest.js +48 -9
- package/classes/AppPermissionsRequest/RequestAppPermissionsRequest.js +54 -9
- package/classes/Bridge/index.js +34 -4
- package/classes/Bridge/spec.js +24 -1
- package/classes/BrightnessRequest/index.js +59 -10
- package/classes/BrightnessRequest/spec.js +111 -6
- package/classes/BrowserConnector/index.js +180 -26
- package/classes/Conditioner/index.js +74 -8
- package/classes/Conditioner/spec.js +75 -1
- package/classes/DataRequest/index.js +116 -13
- package/classes/DevServerBridge/index.js +86 -9
- package/classes/DevServerBridge/spec.js +231 -14
- package/classes/ErrorManager/index.js +144 -20
- package/classes/ErrorManager/spec.js +244 -2
- package/classes/Event/index.js +101 -15
- package/classes/HttpRequest/index.js +182 -21
- package/classes/PipelineDependencies/index.js +42 -6
- package/classes/PipelineDependencies/spec.js +46 -3
- package/classes/PipelineManager/index.js +517 -71
- package/classes/PipelineManager/spec.js +733 -15
- package/classes/PipelineRequest/index.js +167 -19
- package/classes/PipelineRequest/mock.js +118 -21
- package/classes/PipelineRequest/spec.js +333 -2
- package/classes/PipelineSequence/index.js +34 -6
- package/classes/Request/index.js +61 -13
- package/classes/RequestBuffer/index.js +43 -6
- package/classes/RequestManager/index.js +216 -33
- package/classes/RequestManager/spec.js +188 -1
- package/classes/Scanner/index.js +246 -67
- package/classes/ScannerEvent/index.js +23 -9
- package/classes/ScannerEventHandler/index.js +39 -16
- package/classes/ScannerEventListener/index.js +84 -24
- package/classes/ScannerManager/ScanProcessingError.js +11 -3
- package/classes/ScannerManager/index.js +133 -21
- package/classes/WebStorageRequest/index.js +76 -9
- package/commands/analyticsSetCustomValues.js +8 -2
- package/commands/appPermissions.js +10 -3
- package/commands/brightness.js +33 -5
- package/commands/broadcastEvent.js +8 -2
- package/commands/cleanTab.js +11 -3
- package/commands/closeInAppBrowser.js +22 -2
- package/commands/flushTab.js +8 -2
- package/commands/getWebStorageEntry.js +11 -2
- package/commands/hideMenuBar.js +8 -2
- package/commands/hideNavigationBar.js +8 -2
- package/commands/hideSplashScreen.js +8 -2
- package/commands/onload.js +13 -3
- package/commands/openAppSettings.js +8 -2
- package/commands/openPage.js +8 -2
- package/commands/openPageExtern.js +8 -2
- package/commands/performCommandsAfterDelay.js +11 -3
- package/commands/plotProjects.js +65 -7
- package/commands/popTabToRoot.js +11 -3
- package/commands/registerEvents.js +10 -2
- package/commands/scanner.js +76 -7
- package/commands/setCookie.js +8 -2
- package/commands/setDebugLoggingEnabled.js +8 -2
- package/commands/setScrollingEnabled.js +7 -2
- package/commands/setWebStorageEntry.js +8 -2
- package/commands/shareItem.js +18 -2
- package/commands/showNavigationBar.js +8 -2
- package/commands/showTab.js +13 -2
- package/commands/unifiedTracking.js +128 -30
- package/constants/AppCommands.js +6 -1
- package/constants/AppEvents.js +9 -1
- package/constants/AppPermissions.js +57 -13
- package/constants/Command.js +1 -1
- package/constants/ErrorHandleTypes.js +2 -1
- package/constants/ErrorManager.js +15 -1
- package/constants/Pipeline.js +52 -17
- package/constants/ProcessTypes.js +3 -1
- package/constants/RequestManagerModes.js +19 -7
- package/constants/RequestTypes.js +2 -1
- package/constants/Scanner.js +39 -10
- package/constants/Trilean.js +6 -1
- package/emitters/ui.js +2 -1
- package/helpers/index.js +66 -8
- package/helpers/logGroup.js +56 -8
- package/helpers/version.js +216 -22
- package/index.js +60 -5
- package/package.json +1 -1
|
@@ -1,44 +1,198 @@
|
|
|
1
|
-
|
|
1
|
+
import { logger } from "../../helpers";
|
|
2
|
+
import event from "../Event";
|
|
3
|
+
import { TYPE_TRUSTED } from "../../constants/Pipeline";
|
|
4
|
+
import * as requestTypes from "../../constants/RequestTypes";
|
|
5
|
+
import * as appCommands from "../../constants/AppCommands";
|
|
6
|
+
const appConfig = process.env.APP_CONFIG || {};
|
|
7
|
+
|
|
8
|
+
/**
|
|
2
9
|
* The BrowserConnector emulates the SGJavaScriptBridge within browser environments.
|
|
3
10
|
* It routes supported app commands to Shopgate Connect which can mimic the behavior of the app.
|
|
4
|
-
*/
|
|
11
|
+
*/
|
|
12
|
+
class BrowserConnector {
|
|
13
|
+
/**
|
|
5
14
|
* The constructor.
|
|
6
15
|
* @param {string} [ip=process.env.IP] The IP of the dev server.
|
|
7
16
|
* @param {number} [port=process.env.PORT] The port of the dev server.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
|
|
17
|
+
*/
|
|
18
|
+
constructor(ip = process.env.IP, port = process.env.PORT) {
|
|
19
|
+
/**
|
|
20
|
+
* Builds the GET query.
|
|
21
|
+
* @param {Object} input The input parameters.
|
|
22
|
+
* @return {string}
|
|
23
|
+
*/
|
|
24
|
+
this.buildQueryString = input => {
|
|
25
|
+
if (Object.keys(input).length === 0 || this.isPOST) {
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
28
|
+
const query = Object.keys(input).map(key => `${key}=${input[key]}`).join('&');
|
|
29
|
+
return `?${query}`;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Handles a response of the server.
|
|
33
|
+
* @param {Object} response The server response.
|
|
34
|
+
* @return {BrowserConnector}
|
|
35
|
+
*/
|
|
36
|
+
this.processResponse = response => {
|
|
37
|
+
const {
|
|
38
|
+
cmds = []
|
|
39
|
+
} = response || {};
|
|
40
|
+
if (cmds.length === 0) {
|
|
41
|
+
if (this.command.c === appCommands.COMMAND_SEND_PIPELINE_REQUEST) {
|
|
42
|
+
event.call(`pipelineResponse:${this.command.p.serial}`, [response.error || null, this.command.p.serial, !response.error ? response : undefined]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Process the response commands.
|
|
47
|
+
cmds.forEach(command => {
|
|
48
|
+
const name = command.c;
|
|
49
|
+
const params = command.p;
|
|
50
|
+
let args = [];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The server returns a response command for a request command.
|
|
54
|
+
* If the native app receives such a command, it calls a related event within the
|
|
55
|
+
* webviews. Here the response parameters are sorted in the specified order for
|
|
56
|
+
* the different response events.
|
|
57
|
+
*/
|
|
58
|
+
if (name === 'pipelineResponse') {
|
|
59
|
+
args = [params.error, params.serial, params.output];
|
|
60
|
+
} else if (name === 'httpResponse') {
|
|
61
|
+
args = [params.error, params.serial, params.response];
|
|
62
|
+
} else if (name === 'dataResponse') {
|
|
63
|
+
args = [params.serial, params.status, params.body, params.bodyContentType];
|
|
64
|
+
} else if (name === 'webStorageResponse') {
|
|
65
|
+
args = [params.serial, params.age, params.value];
|
|
66
|
+
}
|
|
67
|
+
event.call(name, args);
|
|
68
|
+
});
|
|
69
|
+
return this;
|
|
70
|
+
};
|
|
71
|
+
this.ip = ip;
|
|
72
|
+
this.port = port;
|
|
73
|
+
this.supportedCommands = [appCommands.COMMAND_SEND_PIPELINE_REQUEST, appCommands.COMMAND_SEND_HTTP_REQUEST, appCommands.COMMAND_SEND_DATA_REQUEST, appCommands.COMMAND_GET_WEBSTORAGE_ENTRY];
|
|
74
|
+
this.appConfig = appConfig;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
11
77
|
* @return {string}
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
78
|
+
*/
|
|
79
|
+
get requestType() {
|
|
80
|
+
if (!this.isPipelineRequest) {
|
|
81
|
+
return requestTypes.REQUEST_TYPE_POST;
|
|
82
|
+
}
|
|
83
|
+
const segments = this.command.p.name.split('.');
|
|
84
|
+
if (segments[2].startsWith('get')) {
|
|
85
|
+
return requestTypes.REQUEST_TYPE_GET;
|
|
86
|
+
}
|
|
87
|
+
return requestTypes.REQUEST_TYPE_POST;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
25
91
|
* @return {boolean}
|
|
26
|
-
*/
|
|
92
|
+
*/
|
|
93
|
+
get isGET() {
|
|
94
|
+
return this.requestType === requestTypes.REQUEST_TYPE_GET;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
27
98
|
* @return {boolean}
|
|
28
|
-
*/
|
|
99
|
+
*/
|
|
100
|
+
get isPOST() {
|
|
101
|
+
return this.requestType === requestTypes.REQUEST_TYPE_POST;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
29
105
|
* @return {string}
|
|
30
|
-
*/
|
|
106
|
+
*/
|
|
107
|
+
get connectUrl() {
|
|
108
|
+
const {
|
|
109
|
+
apiUrl = ''
|
|
110
|
+
} = this.appConfig;
|
|
111
|
+
const {
|
|
112
|
+
name,
|
|
113
|
+
type,
|
|
114
|
+
input
|
|
115
|
+
} = this.command.p;
|
|
116
|
+
const queryString = this.buildQueryString(input);
|
|
117
|
+
if (type && type === TYPE_TRUSTED) {
|
|
118
|
+
return `${apiUrl}app/trustedPipelines/${name}${queryString}`;
|
|
119
|
+
}
|
|
120
|
+
return `${apiUrl}app/pipelines/${name}${queryString}`;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
31
124
|
* @return {boolean}
|
|
32
|
-
*/
|
|
125
|
+
*/
|
|
126
|
+
get isPipelineRequest() {
|
|
127
|
+
return this.command.c === appCommands.COMMAND_SEND_PIPELINE_REQUEST;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
33
131
|
* @return {string}
|
|
34
|
-
*/
|
|
132
|
+
*/
|
|
133
|
+
get suffix() {
|
|
134
|
+
if (this.command.c === appCommands.COMMAND_GET_WEBSTORAGE_ENTRY) {
|
|
135
|
+
return 'web_storage';
|
|
136
|
+
}
|
|
137
|
+
if (this.command.c === appCommands.COMMAND_SEND_HTTP_REQUEST) {
|
|
138
|
+
return 'http_request';
|
|
139
|
+
}
|
|
140
|
+
return '';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
35
144
|
* @return {string}
|
|
36
|
-
*/
|
|
145
|
+
*/
|
|
146
|
+
get localURL() {
|
|
147
|
+
return `http://${this.ip}:${this.port}/${this.suffix}`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
37
151
|
* @param {string} libVersion The library version.
|
|
38
152
|
* @returns {string}
|
|
39
|
-
*/
|
|
153
|
+
*/
|
|
154
|
+
getRequestBody(libVersion) {
|
|
155
|
+
if (this.isPipelineRequest) {
|
|
156
|
+
const {
|
|
157
|
+
p
|
|
158
|
+
} = this.command;
|
|
159
|
+
const {
|
|
160
|
+
input
|
|
161
|
+
} = p;
|
|
162
|
+
return JSON.stringify(input);
|
|
163
|
+
}
|
|
164
|
+
return JSON.stringify({
|
|
165
|
+
cmds: [this.command],
|
|
166
|
+
ver: libVersion
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
40
171
|
* Dispatches a single command to the dev server.
|
|
41
172
|
* @param {Object} command The command to dispatch.
|
|
42
173
|
* @param {string} libVersion The lib version for the command.
|
|
43
174
|
* @return {BrowserConnector}
|
|
44
|
-
*/
|
|
175
|
+
*/
|
|
176
|
+
dispatchCommandForVersion(command, libVersion) {
|
|
177
|
+
this.command = command;
|
|
178
|
+
const {
|
|
179
|
+
c: name
|
|
180
|
+
} = this.command || {};
|
|
181
|
+
if (this.supportedCommands.includes(name)) {
|
|
182
|
+
const URL = this.isPipelineRequest ? this.connectUrl : this.localURL;
|
|
183
|
+
const options = {
|
|
184
|
+
method: this.requestType,
|
|
185
|
+
credentials: 'include',
|
|
186
|
+
headers: new Headers({
|
|
187
|
+
'Content-Type': 'application/json'
|
|
188
|
+
}),
|
|
189
|
+
...(this.isPOST && {
|
|
190
|
+
body: this.getRequestBody(libVersion)
|
|
191
|
+
})
|
|
192
|
+
};
|
|
193
|
+
fetch(URL, options).then(response => response.json()).then(this.processResponse).catch(err => err && logger.error(err));
|
|
194
|
+
}
|
|
195
|
+
return this;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
export default BrowserConnector;
|
|
@@ -1,20 +1,86 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { logger } from "../../helpers";
|
|
2
|
+
|
|
3
|
+
/**
|
|
2
4
|
* Creates an action handler API.
|
|
3
|
-
*/
|
|
5
|
+
*/
|
|
6
|
+
class Conditioner {
|
|
7
|
+
/**
|
|
4
8
|
* @param {Map} conditions conditions
|
|
5
|
-
*/
|
|
9
|
+
*/
|
|
10
|
+
constructor(conditions) {
|
|
11
|
+
this.conditions = conditions || new Map();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
6
15
|
* @param {string} name The name of the registered conditioner.
|
|
7
16
|
* @param {Function} conditioner The registered conditioner.
|
|
8
17
|
* @param {number} priority conditioner priority
|
|
9
18
|
* @return {Conditioner}
|
|
10
|
-
*/
|
|
19
|
+
*/
|
|
20
|
+
addConditioner(name, conditioner, priority = 1) {
|
|
21
|
+
if (typeof conditioner !== 'function') {
|
|
22
|
+
throw new Error(`Conditioners need to be of type function. Received: '${typeof conditioner}'`);
|
|
23
|
+
}
|
|
24
|
+
this.conditions.set(name, {
|
|
25
|
+
priority,
|
|
26
|
+
conditioner
|
|
27
|
+
});
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
11
32
|
* @param {string} name The name of the registered conditioner.
|
|
12
33
|
* @return {Conditioner}
|
|
13
|
-
*/
|
|
34
|
+
*/
|
|
35
|
+
removeConditioner(name) {
|
|
36
|
+
if (!this.conditions.has(name)) {
|
|
37
|
+
logger.warn(`Couldn't remove conditioner. '${name}' no found.`);
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
this.conditions.delete(name);
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
14
45
|
* @param {string} name The name of the conditioner to eliminate.
|
|
15
46
|
* @return {Conditioner} new instance with cloned conditions
|
|
16
|
-
*/
|
|
47
|
+
*/
|
|
48
|
+
without(name) {
|
|
49
|
+
const clonedConditions = new Map(this.conditions);
|
|
50
|
+
if (clonedConditions.has(name)) {
|
|
51
|
+
clonedConditions.delete(name);
|
|
52
|
+
}
|
|
53
|
+
return new Conditioner(clonedConditions);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
17
57
|
* Resolves if all conditions are fulfilled.
|
|
18
58
|
* @return {Promise}
|
|
19
|
-
*/
|
|
20
|
-
|
|
59
|
+
*/
|
|
60
|
+
check() {
|
|
61
|
+
return new Promise(async (resolve, reject) => {
|
|
62
|
+
const sorted = Array.from(this.conditions.values()).sort((a, b) => {
|
|
63
|
+
if (a.priority === b.priority) {
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
return a.priority < b.priority ? -1 : 1;
|
|
67
|
+
});
|
|
68
|
+
try {
|
|
69
|
+
for (let i = 0; i < sorted.length; i += 1) {
|
|
70
|
+
const condition = sorted[i];
|
|
71
|
+
|
|
72
|
+
// eslint-disable-next-line no-await-in-loop
|
|
73
|
+
const conditionResult = await condition.conditioner();
|
|
74
|
+
if (conditionResult === false) {
|
|
75
|
+
logger.warn('conditioner failed', i, condition, this.conditions);
|
|
76
|
+
return resolve(false);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return resolve(true);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
return reject(error);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export default Conditioner;
|
|
@@ -1 +1,75 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Conditioner from "./index";
|
|
2
|
+
import { logger } from "../../helpers";
|
|
3
|
+
jest.mock("../../helpers", () => ({
|
|
4
|
+
logger: {
|
|
5
|
+
warn: jest.fn()
|
|
6
|
+
}
|
|
7
|
+
}));
|
|
8
|
+
describe('Conditioner', () => {
|
|
9
|
+
let conditioner;
|
|
10
|
+
let cond1;
|
|
11
|
+
let cond2;
|
|
12
|
+
let cond3;
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
jest.clearAllMocks();
|
|
15
|
+
conditioner = new Conditioner();
|
|
16
|
+
cond1 = jest.fn().mockReturnValue(true);
|
|
17
|
+
cond2 = jest.fn().mockReturnValue(true);
|
|
18
|
+
cond3 = jest.fn().mockReturnValue(true);
|
|
19
|
+
});
|
|
20
|
+
it('should fail on first sorted condition', async () => {
|
|
21
|
+
cond3.mockReturnValue(false);
|
|
22
|
+
conditioner.addConditioner(1, cond1);
|
|
23
|
+
conditioner.addConditioner(2, cond2, -1);
|
|
24
|
+
conditioner.addConditioner(3, cond3, -2);
|
|
25
|
+
expect(await conditioner.check()).toBeFalsy();
|
|
26
|
+
expect(cond3).toBeCalledTimes(1);
|
|
27
|
+
expect(cond1).toBeCalledTimes(0);
|
|
28
|
+
expect(cond2).toBeCalledTimes(0);
|
|
29
|
+
expect(logger.warn).toBeCalledTimes(1);
|
|
30
|
+
});
|
|
31
|
+
it('should fail on first promisified sorted condition', async () => {
|
|
32
|
+
expect.assertions(5);
|
|
33
|
+
cond3.mockResolvedValue(false);
|
|
34
|
+
conditioner.addConditioner(1, cond1);
|
|
35
|
+
conditioner.addConditioner(2, cond2, -1);
|
|
36
|
+
conditioner.addConditioner(2, cond3, -2);
|
|
37
|
+
expect(await conditioner.check()).toBeFalsy();
|
|
38
|
+
expect(cond3).toBeCalledTimes(1);
|
|
39
|
+
expect(cond1).toBeCalledTimes(0);
|
|
40
|
+
expect(cond2).toBeCalledTimes(0);
|
|
41
|
+
expect(logger.warn).toBeCalledTimes(1);
|
|
42
|
+
});
|
|
43
|
+
it('should fail on second promisified sorted condition', async () => {
|
|
44
|
+
expect.assertions(5);
|
|
45
|
+
cond3.mockResolvedValue(false);
|
|
46
|
+
conditioner.addConditioner(1, cond1);
|
|
47
|
+
conditioner.addConditioner(2, cond2, -10);
|
|
48
|
+
conditioner.addConditioner(2, cond3, -2);
|
|
49
|
+
expect(await conditioner.check()).toBeFalsy();
|
|
50
|
+
expect(cond3).toBeCalledTimes(1);
|
|
51
|
+
expect(cond1).toBeCalledTimes(0);
|
|
52
|
+
expect(cond2).toBeCalledTimes(0);
|
|
53
|
+
expect(logger.warn).toBeCalledTimes(1);
|
|
54
|
+
});
|
|
55
|
+
it('should resolve true', async () => {
|
|
56
|
+
conditioner.addConditioner(1, cond1);
|
|
57
|
+
conditioner.addConditioner(2, cond2);
|
|
58
|
+
conditioner.addConditioner(3, cond3);
|
|
59
|
+
expect(await conditioner.check()).toBeTruthy();
|
|
60
|
+
expect(cond1).toBeCalledTimes(1);
|
|
61
|
+
expect(cond2).toBeCalledTimes(1);
|
|
62
|
+
expect(cond3).toBeCalledTimes(1);
|
|
63
|
+
expect(logger.warn).toBeCalledTimes(0);
|
|
64
|
+
});
|
|
65
|
+
it('should return cloned conditioner', async () => {
|
|
66
|
+
conditioner.addConditioner('one', cond1);
|
|
67
|
+
conditioner.addConditioner('two', cond2);
|
|
68
|
+
const newConditioner = conditioner.without('one');
|
|
69
|
+
expect(newConditioner).not.toBe(conditioner);
|
|
70
|
+
expect(newConditioner.conditions).not.toBe(conditioner.conditions);
|
|
71
|
+
expect(newConditioner.conditions.has('one')).toBeFalsy();
|
|
72
|
+
expect(newConditioner.conditions.has('two')).toBeTruthy();
|
|
73
|
+
expect(logger.warn).toBeCalledTimes(0);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -1,39 +1,142 @@
|
|
|
1
|
-
|
|
1
|
+
import event from "../Event";
|
|
2
|
+
import AppCommand from "../AppCommand";
|
|
3
|
+
import Request from "../Request";
|
|
4
|
+
import requestBuffer from "../RequestBuffer";
|
|
5
|
+
import { logger, ajaxUrl } from "../../helpers";
|
|
6
|
+
|
|
7
|
+
/**
|
|
2
8
|
* The DataRequest class. It is the interface to the legacy system.
|
|
3
|
-
*/
|
|
9
|
+
*/
|
|
10
|
+
class DataRequest extends Request {
|
|
11
|
+
/**
|
|
4
12
|
* Initializes the DataRequest object
|
|
5
13
|
* @param {string} src The source url
|
|
6
|
-
*/
|
|
14
|
+
*/
|
|
15
|
+
constructor(src) {
|
|
16
|
+
super();
|
|
17
|
+
this.src = src;
|
|
18
|
+
this.payload = {};
|
|
19
|
+
this.noCache = true;
|
|
20
|
+
this.createSerial(this.src);
|
|
21
|
+
this.createEventCallbackName('dataResponse');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
7
25
|
* Sets the payload for the DataRequest
|
|
8
26
|
* @param {Object|string} [payload={}] The payload to send with the request
|
|
9
27
|
* @returns {DataRequest}
|
|
10
|
-
*/
|
|
28
|
+
*/
|
|
29
|
+
setPayload(payload = {}) {
|
|
30
|
+
this.payload = payload;
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
11
35
|
* Decides if the response of the DataRequest will be cached
|
|
12
36
|
* @param {boolean} [noCache=true] If set to `true`, then the DataResponse will not be cached
|
|
13
37
|
* @returns {DataRequest} The DataRequest
|
|
14
|
-
*/
|
|
38
|
+
*/
|
|
39
|
+
setNoCache(noCache = true) {
|
|
40
|
+
this.noCache = noCache;
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
15
45
|
* Determines the correct content type for the request payload.
|
|
16
46
|
* @return {string} The content type
|
|
17
|
-
*/
|
|
47
|
+
*/
|
|
48
|
+
getContentType() {
|
|
49
|
+
let contentType = 'text/plain';
|
|
50
|
+
if (typeof this.payload === 'object' || typeof this.payload === 'string' && this.payload.search(/_method=POST/) === 0) {
|
|
51
|
+
contentType = 'application/x-www-form-urlencoded; charset=UTF-8';
|
|
52
|
+
}
|
|
53
|
+
return contentType;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
18
57
|
* Creates the data request body from the payload.
|
|
19
58
|
* @return {string} The request body
|
|
20
|
-
*/
|
|
59
|
+
*/
|
|
60
|
+
getRequestBody() {
|
|
61
|
+
/**
|
|
21
62
|
* Serializes a JavaScript object for a data request body.
|
|
22
63
|
* @param {Object} obj The object that shall be serialized.
|
|
23
64
|
* @param {string} [prefix] An optional prefix for the object keys.
|
|
24
65
|
* @return {string} The serialized object.
|
|
25
|
-
*/
|
|
66
|
+
*/
|
|
67
|
+
const serializeObject = (obj, prefix) => {
|
|
68
|
+
const result = [];
|
|
69
|
+
Object.keys(obj).forEach(propName => {
|
|
70
|
+
const key = prefix ? `${prefix}[${propName}]` : propName;
|
|
71
|
+
const value = obj[propName];
|
|
72
|
+
let tmp;
|
|
73
|
+
if (typeof value === 'object') {
|
|
74
|
+
tmp = serializeObject(value, key);
|
|
75
|
+
} else {
|
|
76
|
+
tmp = `${window.encodeURIComponent(key)}=${window.encodeURIComponent(value)}`;
|
|
77
|
+
}
|
|
78
|
+
result.push(tmp);
|
|
79
|
+
});
|
|
80
|
+
return result.join('&');
|
|
81
|
+
};
|
|
82
|
+
let body = '';
|
|
83
|
+
if (this.payload) {
|
|
84
|
+
if (typeof this.payload === 'object') {
|
|
85
|
+
body = serializeObject(this.payload);
|
|
86
|
+
} else if (typeof this.payload === 'string') {
|
|
87
|
+
body = this.payload;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return body;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
26
94
|
* Dispatches the data request.
|
|
27
95
|
* @param {Function} resolve The resolve() callback of the request promise.
|
|
28
96
|
* @param {Function} reject The reject() callback of the request promise.
|
|
29
|
-
*/
|
|
30
|
-
|
|
97
|
+
*/
|
|
98
|
+
onDispatch(resolve, reject) {
|
|
99
|
+
// Add the request to the buffer.
|
|
100
|
+
requestBuffer.add(this, this.serial);
|
|
101
|
+
const requestCallbackName = this.getEventCallbackName();
|
|
102
|
+
|
|
103
|
+
/**
|
|
31
104
|
* The request event callback for the response call.
|
|
32
105
|
* @param {string} serial The serial that was used to identify the DataRequest callback..
|
|
33
106
|
* @param {number} status The request status.
|
|
34
107
|
* @param {string} body The response body.
|
|
35
108
|
* @param {string} bodyContentType The type of data within the response body.
|
|
36
109
|
* @return {Object}
|
|
37
|
-
*/
|
|
38
|
-
|
|
39
|
-
|
|
110
|
+
*/
|
|
111
|
+
const requestCallback = (serial, status, body, bodyContentType) => {
|
|
112
|
+
event.removeCallback(requestCallbackName, requestCallback);
|
|
113
|
+
requestBuffer.remove(serial);
|
|
114
|
+
if (status !== 200) {
|
|
115
|
+
return reject(status);
|
|
116
|
+
}
|
|
117
|
+
let responsePayload = body;
|
|
118
|
+
if (bodyContentType === 'application/json; charset=UTF-8') {
|
|
119
|
+
responsePayload = JSON.parse(responsePayload);
|
|
120
|
+
}
|
|
121
|
+
logger.log(`dataResponse: ${this.src}`, {
|
|
122
|
+
status,
|
|
123
|
+
responsePayload
|
|
124
|
+
});
|
|
125
|
+
return resolve(responsePayload);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// Apply the event callback.
|
|
129
|
+
event.addCallback(requestCallbackName, requestCallback);
|
|
130
|
+
|
|
131
|
+
// Send the DataRequest.
|
|
132
|
+
const command = new AppCommand();
|
|
133
|
+
command.setCommandName('sendDataRequest').dispatch({
|
|
134
|
+
src: ajaxUrl(this.src),
|
|
135
|
+
serial: this.serial,
|
|
136
|
+
body: this.getRequestBody(),
|
|
137
|
+
bodyContentType: this.getContentType(),
|
|
138
|
+
noCache: this.noCache
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export default DataRequest;
|