@searchspring/snap-url-manager 0.20.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/LICENSE +21 -0
- package/README.md +228 -0
- package/dist/cjs/Translators/Noop/NoopTranslator.d.ts +10 -0
- package/dist/cjs/Translators/Noop/NoopTranslator.d.ts.map +1 -0
- package/dist/cjs/Translators/Noop/NoopTranslator.js +25 -0
- package/dist/cjs/Translators/QueryString/QueryStringTranslator.d.ts +35 -0
- package/dist/cjs/Translators/QueryString/QueryStringTranslator.d.ts.map +1 -0
- package/dist/cjs/Translators/QueryString/QueryStringTranslator.js +267 -0
- package/dist/cjs/Translators/Url/UrlTranslator.d.ts +67 -0
- package/dist/cjs/Translators/Url/UrlTranslator.d.ts.map +1 -0
- package/dist/cjs/Translators/Url/UrlTranslator.js +466 -0
- package/dist/cjs/Translators/index.d.ts +4 -0
- package/dist/cjs/Translators/index.d.ts.map +1 -0
- package/dist/cjs/Translators/index.js +15 -0
- package/dist/cjs/UrlManager/UrlManager.d.ts +50 -0
- package/dist/cjs/UrlManager/UrlManager.d.ts.map +1 -0
- package/dist/cjs/UrlManager/UrlManager.js +301 -0
- package/dist/cjs/UrlManager/typecheck.d.ts +5 -0
- package/dist/cjs/UrlManager/typecheck.d.ts.map +1 -0
- package/dist/cjs/UrlManager/typecheck.js +75 -0
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +15 -0
- package/dist/cjs/linkers/index.d.ts +2 -0
- package/dist/cjs/linkers/index.d.ts.map +1 -0
- package/dist/cjs/linkers/index.js +13 -0
- package/dist/cjs/linkers/react/react.d.ts +8 -0
- package/dist/cjs/linkers/react/react.d.ts.map +1 -0
- package/dist/cjs/linkers/react/react.js +15 -0
- package/dist/cjs/types.d.ts +47 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +13 -0
- package/dist/esm/Translators/Noop/NoopTranslator.d.ts +10 -0
- package/dist/esm/Translators/Noop/NoopTranslator.d.ts.map +1 -0
- package/dist/esm/Translators/Noop/NoopTranslator.js +20 -0
- package/dist/esm/Translators/QueryString/QueryStringTranslator.d.ts +35 -0
- package/dist/esm/Translators/QueryString/QueryStringTranslator.d.ts.map +1 -0
- package/dist/esm/Translators/QueryString/QueryStringTranslator.js +260 -0
- package/dist/esm/Translators/Url/UrlTranslator.d.ts +67 -0
- package/dist/esm/Translators/Url/UrlTranslator.d.ts.map +1 -0
- package/dist/esm/Translators/Url/UrlTranslator.js +448 -0
- package/dist/esm/Translators/index.d.ts +4 -0
- package/dist/esm/Translators/index.d.ts.map +1 -0
- package/dist/esm/Translators/index.js +3 -0
- package/dist/esm/UrlManager/UrlManager.d.ts +50 -0
- package/dist/esm/UrlManager/UrlManager.d.ts.map +1 -0
- package/dist/esm/UrlManager/UrlManager.js +256 -0
- package/dist/esm/UrlManager/typecheck.d.ts +5 -0
- package/dist/esm/UrlManager/typecheck.d.ts.map +1 -0
- package/dist/esm/UrlManager/typecheck.js +66 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/linkers/index.d.ts +2 -0
- package/dist/esm/linkers/index.d.ts.map +1 -0
- package/dist/esm/linkers/index.js +1 -0
- package/dist/esm/linkers/react/react.d.ts +8 -0
- package/dist/esm/linkers/react/react.d.ts.map +1 -0
- package/dist/esm/linkers/react/react.js +11 -0
- package/dist/esm/types.d.ts +47 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +10 -0
- package/package.json +31 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import deepmerge from 'deepmerge';
|
|
2
|
+
import { RangeValueProperties, ParamLocationType } from '../../types';
|
|
3
|
+
const defaultConfig = {
|
|
4
|
+
urlRoot: '',
|
|
5
|
+
settings: {
|
|
6
|
+
corePrefix: '',
|
|
7
|
+
customType: ParamLocationType.HASH,
|
|
8
|
+
rootParams: true,
|
|
9
|
+
},
|
|
10
|
+
parameters: {
|
|
11
|
+
core: {
|
|
12
|
+
query: { name: 'q', type: ParamLocationType.QUERY },
|
|
13
|
+
oq: { name: 'oq', type: ParamLocationType.QUERY },
|
|
14
|
+
rq: { name: 'rq', type: ParamLocationType.QUERY },
|
|
15
|
+
tag: { name: 'tag', type: ParamLocationType.QUERY },
|
|
16
|
+
page: { name: 'page', type: ParamLocationType.QUERY },
|
|
17
|
+
pageSize: { name: 'pageSize', type: ParamLocationType.HASH },
|
|
18
|
+
sort: { name: 'sort', type: ParamLocationType.HASH },
|
|
19
|
+
filter: { name: 'filter', type: ParamLocationType.HASH },
|
|
20
|
+
},
|
|
21
|
+
custom: {},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
const CORE_FIELDS = ['query', 'oq', 'rq', 'tag', 'page', 'pageSize', 'sort', 'filter'];
|
|
25
|
+
export class UrlTranslator {
|
|
26
|
+
constructor(config = {}) {
|
|
27
|
+
this.reverseMapping = {};
|
|
28
|
+
this.config = deepmerge(defaultConfig, config);
|
|
29
|
+
Object.keys(this.config.parameters.core).forEach((param) => {
|
|
30
|
+
// param prefix
|
|
31
|
+
if (this.config.settings.corePrefix) {
|
|
32
|
+
this.config.parameters.core[param].name = this.config.settings.corePrefix + this.config.parameters.core[param].name;
|
|
33
|
+
}
|
|
34
|
+
// global type override
|
|
35
|
+
const paramType = this.config.settings.coreType;
|
|
36
|
+
if (paramType && Object.values(ParamLocationType).includes(paramType)) {
|
|
37
|
+
this.config.parameters.core[param].type = (config?.parameters?.core && config?.parameters?.core[param]?.type) || paramType;
|
|
38
|
+
}
|
|
39
|
+
// create reverse mapping for quick lookup later
|
|
40
|
+
this.reverseMapping[this.config.parameters.core[param].name] = param;
|
|
41
|
+
});
|
|
42
|
+
const implicit = this.config.settings.customType;
|
|
43
|
+
if (implicit && !Object.values(ParamLocationType).includes(implicit)) {
|
|
44
|
+
// invalid type specified - falling back to hash as implicit type
|
|
45
|
+
this.config.settings.customType = ParamLocationType.HASH;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
bindExternalEvents(update) {
|
|
49
|
+
window.addEventListener('popstate', update);
|
|
50
|
+
}
|
|
51
|
+
getCurrentUrl() {
|
|
52
|
+
return window.location.search + window.location.hash;
|
|
53
|
+
}
|
|
54
|
+
getConfig() {
|
|
55
|
+
return deepmerge({}, this.config);
|
|
56
|
+
}
|
|
57
|
+
deserialize(url) {
|
|
58
|
+
const params = this.parseUrlParams(url);
|
|
59
|
+
return this.paramsToState(params);
|
|
60
|
+
}
|
|
61
|
+
parseUrlParams(url) {
|
|
62
|
+
const queryString = url.includes('?') ? (url.split('?').pop() || '').split('#').shift() || '' : '';
|
|
63
|
+
const hashString = url.includes('#') ? url.substring(url.indexOf('#') + 1) || '' : '';
|
|
64
|
+
return [...this.parseHashString(hashString), ...this.parseQueryString(queryString)];
|
|
65
|
+
}
|
|
66
|
+
parseQueryString(queryString) {
|
|
67
|
+
const justQueryString = queryString.split('?').pop() || '';
|
|
68
|
+
return justQueryString
|
|
69
|
+
.split('&')
|
|
70
|
+
.filter((v) => v)
|
|
71
|
+
.map((kvPair) => {
|
|
72
|
+
const [key, value] = kvPair.split('=').map((v) => decodeURIComponent(v.replace(/\+/g, ' ')));
|
|
73
|
+
return { key: key.split('.'), value, type: ParamLocationType.QUERY };
|
|
74
|
+
})
|
|
75
|
+
.filter((param) => {
|
|
76
|
+
// remove core fields that do not contain a value
|
|
77
|
+
const isCoreField = this.reverseMapping[param.key[0]];
|
|
78
|
+
return !isCoreField || (isCoreField && param.value);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
parseHashString(hashString) {
|
|
82
|
+
const params = [];
|
|
83
|
+
const justHashString = hashString.split('#').join('/') || '';
|
|
84
|
+
justHashString
|
|
85
|
+
.split('/')
|
|
86
|
+
.filter((v) => v)
|
|
87
|
+
.map((hashEntries) => {
|
|
88
|
+
return hashEntries.split(':').map((v) => decodeHashComponent(v));
|
|
89
|
+
})
|
|
90
|
+
.filter((param) => {
|
|
91
|
+
// remove core fields that do not contain a value
|
|
92
|
+
const [key, value] = param;
|
|
93
|
+
const isCoreField = this.reverseMapping[key];
|
|
94
|
+
return !isCoreField || (isCoreField && value);
|
|
95
|
+
})
|
|
96
|
+
.forEach((decodedHashEntries) => {
|
|
97
|
+
if (decodedHashEntries.length == 1) {
|
|
98
|
+
params.push({ key: [decodedHashEntries[0]], value: undefined, type: ParamLocationType.HASH });
|
|
99
|
+
}
|
|
100
|
+
else if (decodedHashEntries.length && decodedHashEntries.length <= 3) {
|
|
101
|
+
const [value, ...keys] = decodedHashEntries.reverse();
|
|
102
|
+
params.push({ key: keys.reverse(), value, type: ParamLocationType.HASH });
|
|
103
|
+
}
|
|
104
|
+
else if (decodedHashEntries.length && decodedHashEntries.length == 4) {
|
|
105
|
+
// range filter
|
|
106
|
+
const [path0, path1, low, high] = decodedHashEntries;
|
|
107
|
+
params.push({ key: [path0, path1, 'low'], value: low, type: ParamLocationType.HASH });
|
|
108
|
+
params.push({ key: [path0, path1, 'high'], value: high, type: ParamLocationType.HASH });
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
return params;
|
|
112
|
+
}
|
|
113
|
+
// parse params into state
|
|
114
|
+
paramsToState(params) {
|
|
115
|
+
const coreOtherParams = [], coreFilterParams = [], coreSortParams = [], otherParams = [];
|
|
116
|
+
params?.forEach((param) => {
|
|
117
|
+
const coreStateKey = this.reverseMapping[param.key[0]];
|
|
118
|
+
const coreConfig = this.config.parameters.core[coreStateKey];
|
|
119
|
+
const customStateKey = this.config.parameters.custom[param.key[0]];
|
|
120
|
+
if (coreStateKey) {
|
|
121
|
+
// core state
|
|
122
|
+
switch (coreStateKey) {
|
|
123
|
+
case 'filter': {
|
|
124
|
+
if (coreConfig.type == param.type)
|
|
125
|
+
coreFilterParams.push(param);
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
case 'sort': {
|
|
129
|
+
if (coreConfig.type == param.type)
|
|
130
|
+
coreSortParams.push(param);
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
default: {
|
|
134
|
+
if (coreConfig.type == param.type)
|
|
135
|
+
coreOtherParams.push(param);
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else if (!CORE_FIELDS.includes(param.key[0])) {
|
|
141
|
+
// custom state
|
|
142
|
+
if (!customStateKey) {
|
|
143
|
+
// unrecognized state - store in custom config map (as implicit type)
|
|
144
|
+
this.config.parameters.custom[param.key[0]] = {
|
|
145
|
+
type: param.type || this.config.settings.customType,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
otherParams.push(param);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
return {
|
|
152
|
+
...this.parseCoreOther(coreOtherParams),
|
|
153
|
+
...this.parseCoreFilter(coreFilterParams),
|
|
154
|
+
...this.parseCoreSort(coreSortParams),
|
|
155
|
+
...this.parseOther(otherParams),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
parseCoreOther(otherParams) {
|
|
159
|
+
const state = {};
|
|
160
|
+
const numberTypeParams = ['page', 'pageSize'];
|
|
161
|
+
if (!otherParams) {
|
|
162
|
+
return {};
|
|
163
|
+
}
|
|
164
|
+
otherParams.forEach((param) => {
|
|
165
|
+
const coreKey = this.reverseMapping[param.key[0]];
|
|
166
|
+
if (numberTypeParams.includes(coreKey)) {
|
|
167
|
+
const numValue = Number(param.value);
|
|
168
|
+
if (coreKey == 'page' && numValue > 1) {
|
|
169
|
+
state[coreKey] = numValue;
|
|
170
|
+
}
|
|
171
|
+
else if (coreKey != 'page') {
|
|
172
|
+
state[coreKey] = numValue;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
state[coreKey] = param.value;
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
return state;
|
|
180
|
+
}
|
|
181
|
+
parseCoreFilter(filterParams) {
|
|
182
|
+
const valueFilterParams = filterParams.filter((p) => p.key.length == 2);
|
|
183
|
+
const rangeFilterParams = filterParams.filter((p) => p.key.length == 3);
|
|
184
|
+
const valueFilters = valueFilterParams.reduce((state, param) => {
|
|
185
|
+
const currentValue = (state.filter || {})[param.key[1]] || [];
|
|
186
|
+
return {
|
|
187
|
+
filter: {
|
|
188
|
+
...state.filter,
|
|
189
|
+
[param.key[1]]: [...(Array.isArray(currentValue) ? currentValue : [currentValue]), param.value],
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}, {});
|
|
193
|
+
const rangeFilters = rangeFilterParams.reduce((state, param, index) => {
|
|
194
|
+
// ranges should come in pairs!
|
|
195
|
+
// use index to build pairs, ignore non pairs
|
|
196
|
+
// build set as encountered - only return full sets (low + high)
|
|
197
|
+
let newState = state;
|
|
198
|
+
const nextRangeParam = rangeFilterParams[index + 1];
|
|
199
|
+
if (index % 2 == 0 &&
|
|
200
|
+
nextRangeParam &&
|
|
201
|
+
nextRangeParam.key[1] == param.key[1] &&
|
|
202
|
+
param.key[2] == RangeValueProperties.LOW &&
|
|
203
|
+
nextRangeParam.key[2] == RangeValueProperties.HIGH) {
|
|
204
|
+
const currentValue = (state.filter || {})[param.key[1]] || [];
|
|
205
|
+
newState = {
|
|
206
|
+
filter: {
|
|
207
|
+
...state.filter,
|
|
208
|
+
[param.key[1]]: [
|
|
209
|
+
...(Array.isArray(currentValue) ? currentValue : [currentValue]),
|
|
210
|
+
{
|
|
211
|
+
[RangeValueProperties.LOW]: isNaN(+param.value) ? null : +param.value,
|
|
212
|
+
[RangeValueProperties.HIGH]: isNaN(+nextRangeParam.value) ? null : +nextRangeParam.value,
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return newState;
|
|
219
|
+
}, {});
|
|
220
|
+
return {
|
|
221
|
+
...(valueFilters.filter || rangeFilters.filter
|
|
222
|
+
? {
|
|
223
|
+
filter: {
|
|
224
|
+
...valueFilters.filter,
|
|
225
|
+
...rangeFilters.filter,
|
|
226
|
+
},
|
|
227
|
+
}
|
|
228
|
+
: {}),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
parseCoreSort(sortParams) {
|
|
232
|
+
if (!sortParams.length) {
|
|
233
|
+
return {};
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
sort: sortParams.map((param) => ({
|
|
237
|
+
field: param.key[1],
|
|
238
|
+
direction: param.value,
|
|
239
|
+
})),
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
parseOther(otherParams) {
|
|
243
|
+
const state = {};
|
|
244
|
+
otherParams.forEach((param) => {
|
|
245
|
+
let node = state;
|
|
246
|
+
param.key.forEach((key, i) => {
|
|
247
|
+
const isLast = i == param.key.length - 1;
|
|
248
|
+
if (isLast) {
|
|
249
|
+
node[key] = node[key] || [];
|
|
250
|
+
param.value && node[key].push(param.value);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
node[key] = node[key] || {};
|
|
254
|
+
node = node[key];
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
return state;
|
|
259
|
+
}
|
|
260
|
+
serialize(state) {
|
|
261
|
+
const root = this.config.urlRoot.includes('?')
|
|
262
|
+
? this.config.urlRoot.split('?')[0]
|
|
263
|
+
: this.config.urlRoot.includes('#')
|
|
264
|
+
? this.config.urlRoot.split('#')[0]
|
|
265
|
+
: this.config.urlRoot;
|
|
266
|
+
const rootUrlParams = this.config.settings.rootParams ? this.parseUrlParams(this.config.urlRoot) : [];
|
|
267
|
+
const stateParams = this.stateToParams(state);
|
|
268
|
+
const params = [...rootUrlParams, ...stateParams];
|
|
269
|
+
const queryParams = params.filter((p) => p.type == ParamLocationType.QUERY);
|
|
270
|
+
const hashParams = params.filter((p) => p.type == ParamLocationType.HASH);
|
|
271
|
+
const paramString = (queryParams.length
|
|
272
|
+
? '?' +
|
|
273
|
+
queryParams
|
|
274
|
+
.map((param) => {
|
|
275
|
+
const keyString = encodeURIComponent(param.key.join('.'));
|
|
276
|
+
const valueString = param.value ? '=' + encodeURIComponent(param.value) : '';
|
|
277
|
+
return keyString + valueString;
|
|
278
|
+
})
|
|
279
|
+
.join('&')
|
|
280
|
+
: this.config.urlRoot
|
|
281
|
+
? ''
|
|
282
|
+
: window.location.pathname) +
|
|
283
|
+
(hashParams.length
|
|
284
|
+
? '#/' +
|
|
285
|
+
hashParams
|
|
286
|
+
.map((param) => {
|
|
287
|
+
const keyString = param.key.map((k) => encodeHashComponent(k)).join(':');
|
|
288
|
+
const valueString = param.value ? ':' + encodeHashComponent(param.value) : '';
|
|
289
|
+
return keyString + valueString;
|
|
290
|
+
})
|
|
291
|
+
.join('/')
|
|
292
|
+
: '');
|
|
293
|
+
return `${root}${paramString}`;
|
|
294
|
+
}
|
|
295
|
+
// encode state into params
|
|
296
|
+
stateToParams(state) {
|
|
297
|
+
return [
|
|
298
|
+
...this.encodeCoreOther(state, ['filter', 'sort']),
|
|
299
|
+
...this.encodeCoreFilters(state),
|
|
300
|
+
...this.encodeCoreSorts(state),
|
|
301
|
+
...this.encodeOther(state),
|
|
302
|
+
];
|
|
303
|
+
}
|
|
304
|
+
encodeCoreFilters(state) {
|
|
305
|
+
const filterConfig = this.config.parameters.core.filter;
|
|
306
|
+
if (!state.filter || !filterConfig) {
|
|
307
|
+
return [];
|
|
308
|
+
}
|
|
309
|
+
return Object.keys(state.filter).flatMap((key) => {
|
|
310
|
+
if (!state.filter || !state.filter[key]) {
|
|
311
|
+
return [];
|
|
312
|
+
}
|
|
313
|
+
const filter = state.filter[key];
|
|
314
|
+
return (filter instanceof Array ? filter : [filter]).flatMap((value) => {
|
|
315
|
+
if (typeof value == 'string' || typeof value == 'number' || typeof value == 'boolean') {
|
|
316
|
+
return [
|
|
317
|
+
{
|
|
318
|
+
key: [filterConfig.name, key],
|
|
319
|
+
value: '' + value,
|
|
320
|
+
type: filterConfig.type,
|
|
321
|
+
},
|
|
322
|
+
];
|
|
323
|
+
}
|
|
324
|
+
else if (typeof value == 'object' &&
|
|
325
|
+
typeof value[RangeValueProperties.LOW] != 'undefined' &&
|
|
326
|
+
typeof value[RangeValueProperties.HIGH] != 'undefined') {
|
|
327
|
+
if (filterConfig.type == ParamLocationType.QUERY) {
|
|
328
|
+
return [
|
|
329
|
+
{
|
|
330
|
+
key: [filterConfig.name, key, RangeValueProperties.LOW],
|
|
331
|
+
value: '' + (value[RangeValueProperties.LOW] ?? '*'),
|
|
332
|
+
type: filterConfig.type,
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
key: [filterConfig.name, key, RangeValueProperties.HIGH],
|
|
336
|
+
value: '' + (value[RangeValueProperties.HIGH] ?? '*'),
|
|
337
|
+
type: filterConfig.type,
|
|
338
|
+
},
|
|
339
|
+
];
|
|
340
|
+
}
|
|
341
|
+
else if (filterConfig.type == ParamLocationType.HASH) {
|
|
342
|
+
return [
|
|
343
|
+
{
|
|
344
|
+
key: [filterConfig.name, key, '' + (value[RangeValueProperties.LOW] ?? '*')],
|
|
345
|
+
value: '' + (value[RangeValueProperties.HIGH] ?? '*'),
|
|
346
|
+
type: filterConfig.type,
|
|
347
|
+
},
|
|
348
|
+
];
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return [];
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
encodeCoreSorts(state) {
|
|
356
|
+
const sortConfig = this.config.parameters.core.sort;
|
|
357
|
+
if (!state.sort || !sortConfig) {
|
|
358
|
+
return [];
|
|
359
|
+
}
|
|
360
|
+
return (state.sort instanceof Array ? state.sort : [state.sort]).map((sort) => {
|
|
361
|
+
return {
|
|
362
|
+
key: [sortConfig.name, sort.field],
|
|
363
|
+
value: sort.direction,
|
|
364
|
+
type: sortConfig.type,
|
|
365
|
+
};
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
encodeCoreOther(state, except) {
|
|
369
|
+
const params = [];
|
|
370
|
+
Object.keys(state)
|
|
371
|
+
// sorting to determine order of params in URL
|
|
372
|
+
.sort(function (a, b) {
|
|
373
|
+
return CORE_FIELDS.indexOf(a) - CORE_FIELDS.indexOf(b);
|
|
374
|
+
})
|
|
375
|
+
.map((param) => {
|
|
376
|
+
if (CORE_FIELDS.includes(param) && !except.includes(param)) {
|
|
377
|
+
const paramConfig = this.config.parameters.core[param];
|
|
378
|
+
if (param == 'page' && state[param] == 1) {
|
|
379
|
+
// do not include page 1
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
params.push({ key: [paramConfig.name], value: '' + state[param], type: paramConfig.type });
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
return params;
|
|
387
|
+
}
|
|
388
|
+
encodeOther(state) {
|
|
389
|
+
let params = [];
|
|
390
|
+
const addRecursive = (obj, currentPath) => {
|
|
391
|
+
Object.keys(obj).forEach((key) => {
|
|
392
|
+
if (currentPath.length == 0 && CORE_FIELDS.includes(key)) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
const value = obj[key];
|
|
396
|
+
if (value instanceof Array) {
|
|
397
|
+
const customConfig = this.config.parameters.custom[currentPath[0] || key];
|
|
398
|
+
const type = customConfig?.type || this.config.settings.customType;
|
|
399
|
+
if (value.length) {
|
|
400
|
+
params = params.concat(value.map((v) => {
|
|
401
|
+
return { key: [...currentPath, key], value: v, type };
|
|
402
|
+
}));
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
params = params.concat({ key: [...currentPath, key], value: undefined, type });
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
else if (typeof value == 'object' && Object.keys(value).length) {
|
|
409
|
+
addRecursive(value, [...currentPath, key]);
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
const customConfig = this.config.parameters.custom[currentPath[0] || key];
|
|
413
|
+
const type = customConfig?.type || this.config.settings.customType;
|
|
414
|
+
const stringValue = (typeof value == 'object' ? undefined : value);
|
|
415
|
+
params = params.concat([{ key: [...currentPath, key], value: stringValue, type }]);
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
};
|
|
419
|
+
addRecursive(state, []);
|
|
420
|
+
return params;
|
|
421
|
+
}
|
|
422
|
+
go(url, config) {
|
|
423
|
+
const currentUrl = this.getCurrentUrl();
|
|
424
|
+
if (url != currentUrl) {
|
|
425
|
+
if (config?.history == 'replace') {
|
|
426
|
+
history.replaceState(null, '', url);
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
history.pushState(null, '', url);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
function decodeHashComponent(string) {
|
|
435
|
+
if (typeof string == 'string') {
|
|
436
|
+
string = string.replace(/%2425/g, '$$25');
|
|
437
|
+
string = string.replace(/\$25/g, '%');
|
|
438
|
+
string = decodeURIComponent(string);
|
|
439
|
+
}
|
|
440
|
+
return string;
|
|
441
|
+
}
|
|
442
|
+
function encodeHashComponent(string) {
|
|
443
|
+
if (typeof string == 'string') {
|
|
444
|
+
string = encodeURIComponent(string);
|
|
445
|
+
string = string.replace(/%/g, '$$25');
|
|
446
|
+
}
|
|
447
|
+
return string;
|
|
448
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/Translators/index.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAC;AACpD,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Translator, UrlState } from '../types';
|
|
2
|
+
import type { ImmutableObject } from 'seamless-immutable';
|
|
3
|
+
declare type omission = {
|
|
4
|
+
path: Array<string>;
|
|
5
|
+
values?: Array<any>;
|
|
6
|
+
};
|
|
7
|
+
declare class WatcherPool {
|
|
8
|
+
private callbacks;
|
|
9
|
+
constructor();
|
|
10
|
+
subscribe(cb: () => void): () => (() => void)[];
|
|
11
|
+
notify(): void;
|
|
12
|
+
}
|
|
13
|
+
export declare class UrlManager {
|
|
14
|
+
linker?: (urlManager: UrlManager) => Record<string, unknown>;
|
|
15
|
+
private omissions;
|
|
16
|
+
detached?: {
|
|
17
|
+
url: string;
|
|
18
|
+
};
|
|
19
|
+
private translator;
|
|
20
|
+
private urlState;
|
|
21
|
+
private globalState;
|
|
22
|
+
private localState;
|
|
23
|
+
private mergedState;
|
|
24
|
+
private prevState?;
|
|
25
|
+
private watcherPool;
|
|
26
|
+
constructor(translator: Translator, linker?: (urlManager: UrlManager) => Record<string, unknown>, globalState?: UrlState | ImmutableObject<UrlState>, localState?: UrlState | ImmutableObject<UrlState>, watcherPool?: WatcherPool, omissions?: Array<omission>, detached?: {
|
|
27
|
+
url: string;
|
|
28
|
+
});
|
|
29
|
+
private without;
|
|
30
|
+
private getTranslatorUrl;
|
|
31
|
+
refresh(): void;
|
|
32
|
+
get state(): ImmutableObject<UrlState>;
|
|
33
|
+
private unpackPathAndState;
|
|
34
|
+
set(...args: Array<unknown>): UrlManager;
|
|
35
|
+
merge(...args: Array<unknown>): UrlManager;
|
|
36
|
+
remove(_path: Array<string> | string, values?: Array<any> | any): UrlManager;
|
|
37
|
+
reset(): UrlManager;
|
|
38
|
+
withConfig(config: Record<string, unknown> | ((config: Record<string, unknown>) => Record<string, unknown>)): UrlManager;
|
|
39
|
+
withGlobals(globals: UrlState | ImmutableObject<UrlState>): UrlManager;
|
|
40
|
+
getTranslatorConfig(): Record<string, unknown>;
|
|
41
|
+
get href(): string;
|
|
42
|
+
go(config?: {
|
|
43
|
+
[any: string]: unknown;
|
|
44
|
+
}): void;
|
|
45
|
+
detach(reset?: boolean): UrlManager;
|
|
46
|
+
get link(): Record<string, any>;
|
|
47
|
+
subscribe(cb: (prev: ImmutableObject<UrlState>, next?: ImmutableObject<UrlState>) => void): () => void;
|
|
48
|
+
}
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=UrlManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UrlManager.d.ts","sourceRoot":"","sources":["../../../src/UrlManager/UrlManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAGhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,aAAK,QAAQ,GAAG;IACf,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACpB,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;CACpB,CAAC;AAEF,cAAM,WAAW;IAChB,OAAO,CAAC,SAAS,CAAyB;;IAM1C,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI;IAMxB,MAAM;CAGN;AAED,qBAAa,UAAU;IAcd,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAInE,OAAO,CAAC,SAAS;IACV,QAAQ,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE;IAlBlC,OAAO,CAAC,UAAU,CAAa;IAE/B,OAAO,CAAC,QAAQ,CAAyE;IACzF,OAAO,CAAC,WAAW,CAAyE;IAC5F,OAAO,CAAC,UAAU,CAAyE;IAC3F,OAAO,CAAC,WAAW,CAAyE;IAE5F,OAAO,CAAC,SAAS,CAAC,CAA4B;IAE9C,OAAO,CAAC,WAAW,CAAc;gBAGhC,UAAU,EAAE,UAAU,EACf,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnE,WAAW,CAAC,EAAE,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,EAClD,UAAU,CAAC,EAAE,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,EACjD,WAAW,CAAC,EAAE,WAAW,EACjB,SAAS,GAAE,KAAK,CAAC,QAAQ,CAAM,EAChC,QAAQ,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE;IAwBlC,OAAO,CAAC,OAAO;IAkDf,OAAO,CAAC,gBAAgB;IAQxB,OAAO,IAAI,IAAI;IAiBf,IAAI,KAAK,IAAI,eAAe,CAAC,QAAQ,CAAC,CAErC;IAED,OAAO,CAAC,kBAAkB;IAQ1B,GAAG,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,UAAU;IAWxC,KAAK,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,UAAU;IAgC1C,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,UAAU;IAU5E,KAAK,IAAI,UAAU;IAYnB,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,UAAU;IAgBxH,WAAW,CAAC,OAAO,EAAE,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,GAAG,UAAU;IAItE,mBAAmB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAI9C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,EAAE,CAAC,MAAM,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,GAAG,IAAI;IAU7C,MAAM,CAAC,KAAK,UAAQ,GAAG,UAAU;IAMjC,IAAI,IAAI,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAM9B;IAED,SAAS,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,eAAe,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,EAAE,eAAe,CAAC,QAAQ,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI;CAQtG"}
|