@esri/solutions-components 0.5.3 → 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/cjs/calcite-input-text_5.cjs.entry.js +36 -36
- package/dist/cjs/calcite-shell-panel_14.cjs.entry.js +1 -1
- package/dist/cjs/solution-configuration.cjs.entry.js +1 -1
- package/dist/cjs/solution-contents_3.cjs.entry.js +1 -1
- package/dist/cjs/{solution-store-70002b57.js → solution-store-ca4639d5.js} +3 -3
- package/dist/collection/components/add-record-modal/test/add-record-modal.e2e.js +24 -0
- package/dist/collection/components/add-record-modal/test/add-record-modal.spec.js +32 -0
- package/dist/collection/components/buffer-tools/test/buffer-tools.e2e.js +24 -0
- package/dist/collection/components/buffer-tools/test/buffer-tools.spec.js +157 -0
- package/dist/collection/components/card-manager/test/card-manager.e2e.js +24 -0
- package/dist/collection/components/card-manager/test/card-manager.spec.js +32 -0
- package/dist/collection/components/comment-card/test/comment-card.e2e.js +24 -0
- package/dist/collection/components/comment-card/test/comment-card.spec.js +32 -0
- package/dist/collection/components/crowdsource-manager/test/crowdsource-manager.e2e.js +24 -0
- package/dist/collection/components/crowdsource-manager/test/crowdsource-manager.spec.js +32 -0
- package/dist/collection/components/crowdsource-reporter/test/crowdsource-reporter.e2e.js +24 -0
- package/dist/collection/components/crowdsource-reporter/test/crowdsource-reporter.spec.js +32 -0
- package/dist/collection/components/deduct-calculator/test/deduct-calculator.e2e.js +24 -0
- package/dist/collection/components/deduct-calculator/test/deduct-calculator.spec.js +32 -0
- package/dist/collection/components/edit-record-modal/test/edit-record-modal.e2e.js +24 -0
- package/dist/collection/components/edit-record-modal/test/edit-record-modal.spec.js +32 -0
- package/dist/collection/components/info-card/test/info-card.e2e.js +24 -0
- package/dist/collection/components/info-card/test/info-card.spec.js +32 -0
- package/dist/collection/components/json-editor/test/json-editor.e2e.js +31 -0
- package/dist/collection/components/json-editor/test/json-editor.spec.js +60 -0
- package/dist/collection/components/layer-table/test/layer-table.e2e.js +24 -0
- package/dist/collection/components/layer-table/test/layer-table.spec.js +32 -0
- package/dist/collection/components/list-item/test/list-item.e2e.js +24 -0
- package/dist/collection/components/list-item/test/list-item.spec.js +32 -0
- package/dist/collection/components/map-card/test/map-card.e2e.js +24 -0
- package/dist/collection/components/map-card/test/map-card.spec.js +32 -0
- package/dist/collection/components/map-draw-tools/test/map-draw-tools.e2e.js +24 -0
- package/dist/collection/components/map-draw-tools/test/map-draw-tools.spec.js +32 -0
- package/dist/collection/components/map-layer-picker/test/map-layer-picker.e2e.js +24 -0
- package/dist/collection/components/map-layer-picker/test/map-layer-picker.spec.js +109 -0
- package/dist/collection/components/map-search/test/map-search.e2e.js +24 -0
- package/dist/collection/components/map-search/test/map-search.spec.js +53 -0
- package/dist/collection/components/map-select-tools/map-select-tools.js +36 -36
- package/dist/collection/components/map-select-tools/test/map-select-tools.e2e.js +24 -0
- package/dist/collection/components/map-select-tools/test/map-select-tools.spec.js +349 -0
- package/dist/collection/components/media-card/test/media-card.e2e.js +24 -0
- package/dist/collection/components/media-card/test/media-card.spec.js +32 -0
- package/dist/collection/components/pci-calculator/test/pci-calculator.e2e.js +24 -0
- package/dist/collection/components/pci-calculator/test/pci-calculator.spec.js +32 -0
- package/dist/collection/components/pdf-download/test/pdf-download.e2e.js +71 -0
- package/dist/collection/components/pdf-download/test/pdf-download.spec.js +104 -0
- package/dist/collection/components/public-notification/test/public-notification.e2e.js +95 -0
- package/dist/collection/components/public-notification/test/public-notification.spec.js +149 -0
- package/dist/collection/components/refine-selection/refine-selection.css +85 -85
- package/dist/collection/components/solution-configuration/test/solution-configuration.e2e.js +31 -0
- package/dist/collection/components/solution-configuration/test/solution-configuration.spec.js +114 -0
- package/dist/collection/components/solution-contents/test/solution-contents.e2e.js +89 -0
- package/dist/collection/components/solution-contents/test/solution-contents.spec.js +138 -0
- package/dist/collection/components/solution-item/test/solution-item.e2e.js +31 -0
- package/dist/collection/components/solution-item/test/solution-item.spec.js +72 -0
- package/dist/collection/components/solution-item-details/test/solution-item-details.e2e.js +31 -0
- package/dist/collection/components/solution-item-details/test/solution-item-details.spec.js +137 -0
- package/dist/collection/components/solution-item-icon/test/solution-item-icon.e2e.js +24 -0
- package/dist/collection/components/solution-item-icon/test/solution-item-icon.spec.js +34 -0
- package/dist/collection/components/solution-item-sharing/test/solution-item-sharing.e2e.js +31 -0
- package/dist/collection/components/solution-item-sharing/test/solution-item-sharing.spec.js +49 -0
- package/dist/collection/components/solution-organization-variables/test/solution-organization-variables.e2e.js +31 -0
- package/dist/collection/components/solution-organization-variables/test/solution-organization-variables.spec.js +60 -0
- package/dist/collection/components/solution-resource-item/test/solution-resource-item.e2e.js +31 -0
- package/dist/collection/components/solution-resource-item/test/solution-resource-item.spec.js +50 -0
- package/dist/collection/components/solution-spatial-ref/test/solution-spatial-ref.e2e.js +31 -0
- package/dist/collection/components/solution-spatial-ref/test/solution-spatial-ref.spec.js +170 -0
- package/dist/collection/components/solution-template-data/test/solution-template-data.e2e.js +31 -0
- package/dist/collection/components/solution-template-data/test/solution-template-data.spec.js +55 -0
- package/dist/collection/components/solution-variables/test/solution-variables.e2e.js +31 -0
- package/dist/collection/components/solution-variables/test/solution-variables.spec.js +126 -0
- package/dist/collection/utils/publicNotificationUtils.js +45 -0
- package/dist/collection/utils/templates.e2e.js +25 -0
- package/dist/collection/utils/test/csvUtils.spec.js +46 -0
- package/dist/collection/utils/test/downloadUtils.spec.js +102 -0
- package/dist/collection/utils/test/pciUtils.spec.js +297 -0
- package/dist/collection/utils/test/solution-store.spec.js +439 -0
- package/dist/components/map-select-tools2.js +36 -36
- package/dist/components/solution-store.js +3 -3
- package/dist/esm/calcite-input-text_5.entry.js +36 -36
- package/dist/esm/calcite-shell-panel_14.entry.js +1 -1
- package/dist/esm/solution-configuration.entry.js +1 -1
- package/dist/esm/solution-contents_3.entry.js +1 -1
- package/dist/esm/{solution-store-5d068b07.js → solution-store-70f874f8.js} +3 -3
- package/dist/solutions-components/{p-41802f6b.entry.js → p-16dfb254.entry.js} +1 -1
- package/dist/solutions-components/{p-4769a2a5.entry.js → p-5ed755a2.entry.js} +1 -1
- package/dist/solutions-components/{p-826a814d.js → p-78719506.js} +2 -2
- package/dist/solutions-components/{p-9f620303.entry.js → p-b4b19fd3.entry.js} +1 -1
- package/dist/solutions-components/{p-24fe6e1c.entry.js → p-d5d5942d.entry.js} +1 -1
- package/dist/solutions-components/solutions-components.esm.js +1 -1
- package/dist/solutions-components/utils/common.js +291 -0
- package/dist/solutions-components/utils/csvDownload.js +36 -0
- package/dist/solutions-components/utils/csvUtils.js +32 -0
- package/dist/solutions-components/utils/downloadUtils.js +386 -0
- package/dist/solutions-components/utils/interfaces.js +56 -0
- package/dist/solutions-components/utils/languageUtil.js +85 -0
- package/dist/solutions-components/utils/loadModules.js +20 -0
- package/dist/solutions-components/utils/locale.js +56 -0
- package/dist/solutions-components/utils/mapViewUtils.js +140 -0
- package/dist/solutions-components/utils/pciUtils.js +837 -0
- package/dist/solutions-components/utils/pdfUtils.js +62 -0
- package/dist/solutions-components/utils/publicNotificationStore.js +38 -0
- package/dist/solutions-components/utils/publicNotificationUtils.js +45 -0
- package/dist/solutions-components/utils/queryUtils.js +148 -0
- package/dist/solutions-components/utils/solution-store.js +579 -0
- package/dist/solutions-components/utils/templates.e2e.js +25 -0
- package/dist/solutions-components/utils/templates.js +341 -0
- package/dist/solutions-components/utils/test/csvUtils.spec.js +46 -0
- package/dist/solutions-components/utils/test/downloadUtils.spec.js +102 -0
- package/dist/solutions-components/utils/test/mocks/jsApi.js +74 -0
- package/dist/solutions-components/utils/test/pciUtils.spec.js +297 -0
- package/dist/solutions-components/utils/test/solution-store.spec.js +439 -0
- package/dist/solutions-components/utils/test/testUtils.js +135 -0
- package/dist/solutions-components/utils/types.js +14 -0
- package/dist/solutions-components_commit.txt +7 -0
- package/package.json +7 -7
@@ -0,0 +1,386 @@
|
|
1
|
+
/** @license
|
2
|
+
* Copyright 2022 Esri
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
*/
|
16
|
+
//#region Declarations
|
17
|
+
import { exportCSV } from "./csvUtils";
|
18
|
+
import { exportPDF } from "./pdfUtils";
|
19
|
+
import { loadModules } from "./loadModules";
|
20
|
+
import { queryFeaturesByID } from "./queryUtils";
|
21
|
+
export { ILabel } from "./pdfUtils";
|
22
|
+
const lineSeparatorChar = "|";
|
23
|
+
//#endregion
|
24
|
+
//#region Public functions
|
25
|
+
/**
|
26
|
+
* Downloads csv of mailing labels for the provided list of ids
|
27
|
+
*
|
28
|
+
* @param selectionSetNames Names of the selection sets used to provide ids
|
29
|
+
* @param layer Layer providing features and attributes for download
|
30
|
+
* @param ids List of ids to download
|
31
|
+
* @param formatUsingLayerPopup When true, the layer's popup is used to choose attributes for each column; when false,
|
32
|
+
* all attributes are exported
|
33
|
+
* @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
|
34
|
+
* @param addColumnTitle Indicates if column headings should be included in output
|
35
|
+
* @returns Promise resolving when function is done
|
36
|
+
*/
|
37
|
+
export async function downloadCSV(selectionSetNames, layer, ids, formatUsingLayerPopup, removeDuplicates = false, addColumnTitle = false) {
|
38
|
+
const labels = await _prepareLabels(layer, ids, removeDuplicates, formatUsingLayerPopup, addColumnTitle);
|
39
|
+
exportCSV(_createFilename(selectionSetNames), labels);
|
40
|
+
return Promise.resolve();
|
41
|
+
}
|
42
|
+
/**
|
43
|
+
* Downloads csv of mailing labels for the provided list of ids
|
44
|
+
*
|
45
|
+
* @param selectionSetNames Names of the selection sets used to provide ids
|
46
|
+
* @param layer Layer providing features and attributes for download
|
47
|
+
* @param ids List of ids to download
|
48
|
+
* @param labelPageDescription Provides PDF page layout info
|
49
|
+
* @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
|
50
|
+
* @param includeMap When true, the first page of the output is a map showing the selection area
|
51
|
+
* @param includeTitle When true, a title is included on every page
|
52
|
+
* @param title Title for each page when `includeTitle` is true
|
53
|
+
* @returns Promise resolving when function is done
|
54
|
+
*/
|
55
|
+
export async function downloadPDF(selectionSetNames, layer, ids, labelPageDescription, removeDuplicates = false, includeMap = false, includeTitle = false, title = "") {
|
56
|
+
let labels = await _prepareLabels(layer, ids, removeDuplicates);
|
57
|
+
labels =
|
58
|
+
// Remove empty lines in labels
|
59
|
+
labels.map(labelLines => labelLines.filter(line => line.length > 0))
|
60
|
+
// Remove empty labels
|
61
|
+
.filter(label => label.length > 0);
|
62
|
+
exportPDF(_createFilename(selectionSetNames), labels, labelPageDescription, includeMap, includeTitle, title);
|
63
|
+
return Promise.resolve();
|
64
|
+
}
|
65
|
+
//#endregion
|
66
|
+
//#region Private functions
|
67
|
+
/**
|
68
|
+
* Converts a set of fieldInfos into template lines.
|
69
|
+
*
|
70
|
+
* @param fieldInfos Layer's fieldInfos structure
|
71
|
+
* @param bypassFieldVisiblity Indicates if the configured fieldInfo visibility property should be ignored
|
72
|
+
* @return Label spec with lines separated by `lineSeparatorChar`
|
73
|
+
*/
|
74
|
+
export function _convertPopupFieldsToLabelSpec(fieldInfos, bypassFieldVisiblity = false) {
|
75
|
+
const labelSpec = [];
|
76
|
+
// Every visible attribute is used
|
77
|
+
fieldInfos.forEach(fieldInfo => {
|
78
|
+
if (fieldInfo.visible || bypassFieldVisiblity) {
|
79
|
+
labelSpec.push(`{${fieldInfo.fieldName}}`);
|
80
|
+
}
|
81
|
+
});
|
82
|
+
return labelSpec.join(lineSeparatorChar);
|
83
|
+
}
|
84
|
+
;
|
85
|
+
/**
|
86
|
+
* Converts the text of a custom popup into a multiline label specification; conversion splits text into
|
87
|
+
* lines on <br>s, and removes HTML tags. It does not handle Arcade and related records.
|
88
|
+
*
|
89
|
+
* @param popupInfo Layer's popupInfo structure containing description, fieldInfos, and expressionInfos, e.g.,
|
90
|
+
* "<div style='text-align: left;'>{NAME}<br />{STREET}<br />{CITY}, {STATE} {ZIP} <br /></div>"
|
91
|
+
* @return Label spec with lines separated by `lineSeparatorChar`
|
92
|
+
*/
|
93
|
+
export function _convertPopupTextToLabelSpec(popupInfo) {
|
94
|
+
// Replace <br> variants with the line separator character
|
95
|
+
popupInfo = popupInfo.replace(/<br\s*\/?>/gi, lineSeparatorChar);
|
96
|
+
// Replace <p> variants with the line separator character, except in the first position
|
97
|
+
popupInfo = popupInfo.replace(/<p[^>]*>/gi, lineSeparatorChar).trim().replace(/^\|/, "");
|
98
|
+
// Remove </p>
|
99
|
+
popupInfo = popupInfo.replace(/<\/p>/gi, "");
|
100
|
+
// Replace \n with the line separator character
|
101
|
+
popupInfo = popupInfo.replace(/\n/gi, "|");
|
102
|
+
// Remove remaining HTML tags, replace 0xA0 that popup uses for spaces, and replace some char representations
|
103
|
+
let labelSpec = popupInfo
|
104
|
+
.replace(/<[\s.]*[^<>]*\/?>/gi, "")
|
105
|
+
.replace(/\xA0/gi, " ")
|
106
|
+
.replace(/</gi, "<")
|
107
|
+
.replace(/>/gi, ">")
|
108
|
+
.replace(/ /gi, " ");
|
109
|
+
// Trim each line
|
110
|
+
labelSpec = labelSpec.replace(/\s*\|\s*/g, "|");
|
111
|
+
// Remove empty lines
|
112
|
+
while (labelSpec.match(/\|\|/)) {
|
113
|
+
labelSpec = labelSpec.replace(/\|\|/, "|");
|
114
|
+
}
|
115
|
+
// Remove leading and trailing line feeds
|
116
|
+
labelSpec = labelSpec.replace(/^\|/, "");
|
117
|
+
labelSpec = labelSpec.replace(/\|$/, "");
|
118
|
+
return labelSpec.trim();
|
119
|
+
}
|
120
|
+
;
|
121
|
+
/**
|
122
|
+
* Extracts Arcade expressions from the lines of a label format and creates an Arcade executor for each
|
123
|
+
* referenced expression name.
|
124
|
+
*
|
125
|
+
* @param labelFormat Label to examine
|
126
|
+
* @param layer Layer from which to fetch features
|
127
|
+
* @return Promise resolving to a set of executors keyed using the expression name
|
128
|
+
*/
|
129
|
+
async function _createArcadeExecutors(labelFormat, layer) {
|
130
|
+
const arcadeExecutors = {};
|
131
|
+
// Are any Arcade expressions in the layer?
|
132
|
+
if (!Array.isArray(layer.popupTemplate.expressionInfos) || layer.popupTemplate.expressionInfos.length === 0) {
|
133
|
+
return Promise.resolve(arcadeExecutors);
|
134
|
+
}
|
135
|
+
// Are there any Arcade expressions in the label format?
|
136
|
+
const arcadeExpressionRegExp = /\{expression\/\w+\}/g;
|
137
|
+
const arcadeExpressionsMatches = labelFormat.match(arcadeExpressionRegExp);
|
138
|
+
if (!arcadeExpressionsMatches) {
|
139
|
+
return Promise.resolve(arcadeExecutors);
|
140
|
+
}
|
141
|
+
// Generate an Arcade executor for each match
|
142
|
+
const [arcade] = await loadModules(["esri/arcade"]);
|
143
|
+
const labelingProfile = {
|
144
|
+
variables: [
|
145
|
+
{
|
146
|
+
name: "$feature",
|
147
|
+
type: "feature"
|
148
|
+
},
|
149
|
+
{
|
150
|
+
name: "$layer",
|
151
|
+
type: "featureSet"
|
152
|
+
},
|
153
|
+
{
|
154
|
+
name: "$datastore",
|
155
|
+
type: "featureSetCollection"
|
156
|
+
},
|
157
|
+
{
|
158
|
+
name: "$map",
|
159
|
+
type: "featureSetCollection"
|
160
|
+
}
|
161
|
+
]
|
162
|
+
};
|
163
|
+
const createArcadeExecutorPromises = {};
|
164
|
+
arcadeExpressionsMatches.forEach((match) => {
|
165
|
+
const expressionName = match.substring(match.indexOf("/") + 1, match.length - 1);
|
166
|
+
(layer.popupTemplate.expressionInfos || []).forEach(expressionInfo => {
|
167
|
+
if (expressionInfo.name === expressionName) {
|
168
|
+
createArcadeExecutorPromises[expressionName] =
|
169
|
+
arcade.createArcadeExecutor(expressionInfo.expression, labelingProfile);
|
170
|
+
}
|
171
|
+
});
|
172
|
+
});
|
173
|
+
const promises = Object.values(createArcadeExecutorPromises);
|
174
|
+
return Promise.all(promises)
|
175
|
+
.then(executors => {
|
176
|
+
const expressionNames = Object.keys(createArcadeExecutorPromises);
|
177
|
+
for (let i = 0; i < expressionNames.length; ++i) {
|
178
|
+
arcadeExecutors[expressionNames[i]] = executors[i].valueOf();
|
179
|
+
}
|
180
|
+
return arcadeExecutors;
|
181
|
+
});
|
182
|
+
}
|
183
|
+
/**
|
184
|
+
* Creates a title from a list of selection set names.
|
185
|
+
*
|
186
|
+
* @param selectionSetNames Names to use in title
|
187
|
+
* @return Title composed of the selectionSetNames separated by commas; if there are no
|
188
|
+
* selection set names supplied, "download" is returned
|
189
|
+
*/
|
190
|
+
export function _createFilename(selectionSetNames) {
|
191
|
+
// Windows doesn't permit the characters \/:*?"<>|
|
192
|
+
const title = selectionSetNames.length > 0 ? selectionSetNames.join(", ") : "download";
|
193
|
+
return title;
|
194
|
+
}
|
195
|
+
/**
|
196
|
+
* Prepares an attribute's value by applying domain and type information.
|
197
|
+
*
|
198
|
+
* @param attributeValue Value of attribute
|
199
|
+
* @param attributeType Type of attribute
|
200
|
+
* @param attributeDomain Domain info for attribute, if any
|
201
|
+
* @param attributeFormat Format info for attribute, if any
|
202
|
+
* @param intl esri/intl
|
203
|
+
* @return Attribute value modified appropriate to domain and type
|
204
|
+
*/
|
205
|
+
function _prepareAttributeValue(attributeValue, attributeType, attributeDomain, attributeFormat, intl) {
|
206
|
+
if (attributeDomain && attributeDomain.type === "coded-value") {
|
207
|
+
// "coded-value" domain field
|
208
|
+
const value = attributeDomain.getName(attributeValue);
|
209
|
+
return value;
|
210
|
+
}
|
211
|
+
else {
|
212
|
+
// Non-domain field or unsupported domain type
|
213
|
+
let value = attributeValue;
|
214
|
+
switch (attributeType) {
|
215
|
+
case "date":
|
216
|
+
if (attributeFormat === null || attributeFormat === void 0 ? void 0 : attributeFormat.dateFormat) {
|
217
|
+
const dateFormatIntlOptions = intl.convertDateFormatToIntlOptions(attributeFormat.dateFormat);
|
218
|
+
value = intl.formatDate(value, dateFormatIntlOptions);
|
219
|
+
}
|
220
|
+
else {
|
221
|
+
value = intl.formatDate(value);
|
222
|
+
}
|
223
|
+
// Format date produces odd characters for the space between the time and the AM/PM text,
|
224
|
+
// e.g., "12/31/1969, 4:00 PM"
|
225
|
+
value = value.replace(/\xe2\x80\xaf/g, "");
|
226
|
+
break;
|
227
|
+
case "double":
|
228
|
+
case "integer":
|
229
|
+
case "long":
|
230
|
+
case "small-integer":
|
231
|
+
if (attributeFormat) {
|
232
|
+
const numberFormatIntlOptions = intl.convertNumberFormatToIntlOptions(attributeFormat);
|
233
|
+
value = intl.formatNumber(value, numberFormatIntlOptions);
|
234
|
+
}
|
235
|
+
else {
|
236
|
+
value = intl.formatNumber(value);
|
237
|
+
}
|
238
|
+
break;
|
239
|
+
}
|
240
|
+
return value;
|
241
|
+
}
|
242
|
+
}
|
243
|
+
/**
|
244
|
+
* Creates labels from items.
|
245
|
+
*
|
246
|
+
* @param layer Layer from which to fetch features
|
247
|
+
* @param ids List of ids to download
|
248
|
+
* @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
|
249
|
+
* @param formatUsingLayerPopup When true, the layer's popup is used to choose attributes for each column; when false,
|
250
|
+
* all attributes are exported
|
251
|
+
* @param includeHeaderNames Add the label format at the front of the list of generated labels
|
252
|
+
* @returns Promise resolving when function is done
|
253
|
+
*/
|
254
|
+
async function _prepareLabels(layer, ids, removeDuplicates = true, formatUsingLayerPopup = true, includeHeaderNames = false) {
|
255
|
+
var _a, _b, _c, _d;
|
256
|
+
const [intl] = await loadModules(["esri/intl"]);
|
257
|
+
// Get the features to export
|
258
|
+
const featureSet = await queryFeaturesByID(ids, layer);
|
259
|
+
let features = featureSet.features;
|
260
|
+
if (!removeDuplicates && ids.length > features.length) {
|
261
|
+
const oidField = layer.objectIdField;
|
262
|
+
features = featureSet.features.reduce((prev, cur) => {
|
263
|
+
const id = cur.attributes[oidField];
|
264
|
+
// remove the first instance of the id
|
265
|
+
const i = ids.indexOf(id);
|
266
|
+
if (i > -1) {
|
267
|
+
ids = ids.splice(i, 1);
|
268
|
+
}
|
269
|
+
// add the first instance of the feature to the new array
|
270
|
+
prev.push(cur);
|
271
|
+
// test for any duplicates
|
272
|
+
if (ids.indexOf(id) > -1) {
|
273
|
+
// could be more than once..
|
274
|
+
const _ids = ids.filter(_id => _id !== id);
|
275
|
+
const num = ids.length - _ids.length;
|
276
|
+
for (let _i = 0; _i < num; _i++) {
|
277
|
+
prev.push(cur);
|
278
|
+
}
|
279
|
+
ids = _ids;
|
280
|
+
}
|
281
|
+
return prev;
|
282
|
+
}, []);
|
283
|
+
}
|
284
|
+
// Get field data types. Do we have any domain-based fields?
|
285
|
+
const attributeTypes = {};
|
286
|
+
const attributeDomains = {};
|
287
|
+
layer.fields.forEach(field => {
|
288
|
+
attributeTypes[field.name] = field.type;
|
289
|
+
attributeDomains[field.name] = field.domain;
|
290
|
+
});
|
291
|
+
const attributeFormats = {};
|
292
|
+
// Get the label formatting, if any
|
293
|
+
let labelFormat;
|
294
|
+
let arcadeExecutors = {};
|
295
|
+
if (layer.popupEnabled) {
|
296
|
+
layer.popupTemplate.fieldInfos.forEach(
|
297
|
+
// Extract any format info that we have
|
298
|
+
fieldInfo => {
|
299
|
+
if (fieldInfo.format) {
|
300
|
+
attributeFormats[fieldInfo.fieldName] = fieldInfo.format;
|
301
|
+
}
|
302
|
+
});
|
303
|
+
// What data fields are used in the labels?
|
304
|
+
// Example labelFormat: ['{NAME}', '{STREET}', '{CITY}, {STATE} {ZIP}']
|
305
|
+
if (formatUsingLayerPopup && ((_b = (_a = layer.popupTemplate) === null || _a === void 0 ? void 0 : _a.content[0]) === null || _b === void 0 ? void 0 : _b.type) === "fields") {
|
306
|
+
labelFormat = _convertPopupFieldsToLabelSpec(layer.popupTemplate.fieldInfos);
|
307
|
+
// If popup is configured with "no attribute information", then no fields will visible
|
308
|
+
if (labelFormat.length === 0) {
|
309
|
+
// Can we use the popup title?
|
310
|
+
// eslint-disable-next-line unicorn/prefer-ternary
|
311
|
+
if (typeof layer.popupTemplate.title === "string") {
|
312
|
+
labelFormat = layer.popupTemplate.title;
|
313
|
+
// Otherwise revert to using attributes
|
314
|
+
}
|
315
|
+
else {
|
316
|
+
labelFormat = _convertPopupFieldsToLabelSpec(layer.popupTemplate.fieldInfos, true);
|
317
|
+
}
|
318
|
+
}
|
319
|
+
}
|
320
|
+
else if (formatUsingLayerPopup && ((_d = (_c = layer.popupTemplate) === null || _c === void 0 ? void 0 : _c.content[0]) === null || _d === void 0 ? void 0 : _d.type) === "text") {
|
321
|
+
labelFormat = _convertPopupTextToLabelSpec(layer.popupTemplate.content[0].text);
|
322
|
+
// Do we need any Arcade executors?
|
323
|
+
arcadeExecutors = await _createArcadeExecutors(labelFormat, layer);
|
324
|
+
}
|
325
|
+
}
|
326
|
+
// Apply the label format
|
327
|
+
let labels;
|
328
|
+
// eslint-disable-next-line unicorn/prefer-ternary
|
329
|
+
if (labelFormat) {
|
330
|
+
const arcadeExpressionRegExp = /\{expression\/\w+\}/g;
|
331
|
+
const attributeRegExp = /\{\w+\}/g;
|
332
|
+
// Find the label fields that we need to replace with values
|
333
|
+
const arcadeExpressionMatches = labelFormat.match(arcadeExpressionRegExp);
|
334
|
+
const attributeMatches = labelFormat.match(attributeRegExp);
|
335
|
+
// Convert feature attributes into an array of labels
|
336
|
+
labels = features.map(feature => {
|
337
|
+
let labelPrep = labelFormat;
|
338
|
+
// Replace Arcade expressions
|
339
|
+
if (arcadeExpressionMatches) {
|
340
|
+
arcadeExpressionMatches.forEach((match) => {
|
341
|
+
const expressionName = match.substring(match.indexOf("/") + 1, match.length - 1);
|
342
|
+
const value = arcadeExecutors[expressionName].execute({ "$feature": feature });
|
343
|
+
labelPrep = labelPrep.replace(match, value);
|
344
|
+
});
|
345
|
+
}
|
346
|
+
// Replace non-Arcade fields
|
347
|
+
if (attributeMatches) {
|
348
|
+
attributeMatches.forEach((match) => {
|
349
|
+
const attributeName = match.substring(1, match.length - 1);
|
350
|
+
const value = _prepareAttributeValue(feature.attributes[attributeName], attributeTypes[attributeName], attributeDomains[attributeName], attributeFormats[attributeName], intl);
|
351
|
+
labelPrep = labelPrep.replace(match, value);
|
352
|
+
});
|
353
|
+
}
|
354
|
+
// Split label into lines
|
355
|
+
let label = labelPrep.split(lineSeparatorChar);
|
356
|
+
// Trim lines
|
357
|
+
label = label.map(line => line.trim());
|
358
|
+
return label;
|
359
|
+
});
|
360
|
+
}
|
361
|
+
else {
|
362
|
+
// Export all attributes
|
363
|
+
labels = features.map(feature => {
|
364
|
+
return Object.keys(feature.attributes).map((attributeName) => {
|
365
|
+
const value = _prepareAttributeValue(feature.attributes[attributeName], attributeTypes[attributeName], attributeDomains[attributeName], null, intl);
|
366
|
+
return `${value}`;
|
367
|
+
});
|
368
|
+
});
|
369
|
+
}
|
370
|
+
// Add header names
|
371
|
+
if (includeHeaderNames) {
|
372
|
+
let headerNames = [];
|
373
|
+
if (labelFormat) {
|
374
|
+
headerNames = labelFormat.replace(/\{/g, "").replace(/\}/g, "").split(lineSeparatorChar);
|
375
|
+
}
|
376
|
+
else {
|
377
|
+
const featuresAttrs = features[0].attributes;
|
378
|
+
Object.keys(featuresAttrs).forEach(k => {
|
379
|
+
headerNames.push(k);
|
380
|
+
});
|
381
|
+
}
|
382
|
+
labels.unshift(headerNames);
|
383
|
+
}
|
384
|
+
return Promise.resolve(labels);
|
385
|
+
}
|
386
|
+
//#endregion
|
@@ -0,0 +1,56 @@
|
|
1
|
+
/** @license
|
2
|
+
* Copyright 2022 Esri
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
*/
|
16
|
+
export var ELayoutMode;
|
17
|
+
(function (ELayoutMode) {
|
18
|
+
ELayoutMode["GRID"] = "GRID";
|
19
|
+
ELayoutMode["HORIZONTAL"] = "HORIZONTAL";
|
20
|
+
ELayoutMode["VERTICAL"] = "VERTICAL";
|
21
|
+
})(ELayoutMode || (ELayoutMode = {}));
|
22
|
+
/**
|
23
|
+
* Resource update types
|
24
|
+
*/
|
25
|
+
export var EUpdateType;
|
26
|
+
(function (EUpdateType) {
|
27
|
+
EUpdateType[EUpdateType["Add"] = 0] = "Add";
|
28
|
+
EUpdateType[EUpdateType["Update"] = 1] = "Update";
|
29
|
+
EUpdateType[EUpdateType["Remove"] = 2] = "Remove";
|
30
|
+
EUpdateType[EUpdateType["None"] = 3] = "None";
|
31
|
+
EUpdateType[EUpdateType["Obsolete"] = 4] = "Obsolete";
|
32
|
+
})(EUpdateType || (EUpdateType = {}));
|
33
|
+
export var EPageType;
|
34
|
+
(function (EPageType) {
|
35
|
+
EPageType[EPageType["LIST"] = 0] = "LIST";
|
36
|
+
EPageType[EPageType["SELECT"] = 1] = "SELECT";
|
37
|
+
EPageType[EPageType["EXPORT"] = 2] = "EXPORT";
|
38
|
+
})(EPageType || (EPageType = {}));
|
39
|
+
export var ESelectionType;
|
40
|
+
(function (ESelectionType) {
|
41
|
+
ESelectionType["POINT"] = "POINT";
|
42
|
+
ESelectionType["LINE"] = "LINE";
|
43
|
+
ESelectionType["POLY"] = "POLY";
|
44
|
+
ESelectionType["RECT"] = "RECT";
|
45
|
+
})(ESelectionType || (ESelectionType = {}));
|
46
|
+
export var EExpandType;
|
47
|
+
(function (EExpandType) {
|
48
|
+
EExpandType["EXPAND"] = "EXPAND";
|
49
|
+
EExpandType["COLLAPSE"] = "COLLAPSE";
|
50
|
+
})(EExpandType || (EExpandType = {}));
|
51
|
+
export var EWorkflowType;
|
52
|
+
(function (EWorkflowType) {
|
53
|
+
EWorkflowType["SEARCH"] = "SEARCH";
|
54
|
+
EWorkflowType["SELECT"] = "SELECT";
|
55
|
+
EWorkflowType["SKETCH"] = "SKETCH";
|
56
|
+
})(EWorkflowType || (EWorkflowType = {}));
|
@@ -0,0 +1,85 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2022 Esri
|
3
|
+
* All rights reserved.
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
* Unless required by applicable law or agreed to in writing, software
|
9
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
10
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
11
|
+
* See the License for the specific language governing permissions and
|
12
|
+
* limitations under the License.
|
13
|
+
*/
|
14
|
+
import { loadModules } from "./loadModules";
|
15
|
+
export const languageMap = new Map([
|
16
|
+
["ar", "ar"],
|
17
|
+
["bg", "bg"],
|
18
|
+
["bs", "bs"],
|
19
|
+
["ca", "ca"],
|
20
|
+
["cs", "cs"],
|
21
|
+
["da", "da"],
|
22
|
+
["de", "de"],
|
23
|
+
["el", "el"],
|
24
|
+
["en", "en"],
|
25
|
+
["es", "es"],
|
26
|
+
["et", "et"],
|
27
|
+
["fi", "fi"],
|
28
|
+
["fr", "fr"],
|
29
|
+
["he", "he"],
|
30
|
+
["hr", "hr"],
|
31
|
+
["hu", "hu"],
|
32
|
+
["id", "id"],
|
33
|
+
["it", "it"],
|
34
|
+
["ja", "ja"],
|
35
|
+
["ko", "ko"],
|
36
|
+
["lt", "lt"],
|
37
|
+
["lv", "lv"],
|
38
|
+
["nb", "nb"],
|
39
|
+
["nl", "nl"],
|
40
|
+
["pl", "pl"],
|
41
|
+
["pt-br", "pt-BR"],
|
42
|
+
["pt-pt", "pt-PT"],
|
43
|
+
["ro", "ro"],
|
44
|
+
["ru", "ru"],
|
45
|
+
["sk", "sk"],
|
46
|
+
["sl", "sl"],
|
47
|
+
["sr", "sr"],
|
48
|
+
["sv", "sv"],
|
49
|
+
["th", "th"],
|
50
|
+
["tr", "tr"],
|
51
|
+
["uk", "uk"],
|
52
|
+
["vi", "vi"],
|
53
|
+
["zh-cn", "zh-CN"],
|
54
|
+
["zh-hk", "zh-HK"],
|
55
|
+
["zh-tw", "zh-TW"],
|
56
|
+
]);
|
57
|
+
// rtl
|
58
|
+
export function getElementDir(el) {
|
59
|
+
return getElementProp(el, "dir", "ltr");
|
60
|
+
}
|
61
|
+
function getElementProp(el, prop, value) {
|
62
|
+
const closestWithProp = el.closest(`[${prop}]`);
|
63
|
+
return closestWithProp ? closestWithProp.getAttribute(prop) : value;
|
64
|
+
}
|
65
|
+
// css
|
66
|
+
export const CSS_UTILITY = {
|
67
|
+
rtl: "arcgis--rtl",
|
68
|
+
};
|
69
|
+
export async function formatNumber(number, options) {
|
70
|
+
const { api = 4, type = "decimal", places = 2 } = options || {};
|
71
|
+
if (api === 4) {
|
72
|
+
const [intl] = await loadModules(["esri/intl"]);
|
73
|
+
const numberFormatIntlOptions = intl.convertNumberFormatToIntlOptions({
|
74
|
+
places,
|
75
|
+
type,
|
76
|
+
digitSeparator: true,
|
77
|
+
});
|
78
|
+
return intl.formatNumber(number, numberFormatIntlOptions);
|
79
|
+
}
|
80
|
+
const [dojoNumber] = await loadModules(["dojo/number"]);
|
81
|
+
return dojoNumber.format(number, {
|
82
|
+
type,
|
83
|
+
places,
|
84
|
+
});
|
85
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
/** @license
|
2
|
+
* Copyright 2022 Esri
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
*/
|
16
|
+
import { loadModules as _loadModules } from "esri-loader";
|
17
|
+
export const loadModules = async (moduleNames, options) => {
|
18
|
+
const mods = await _loadModules(moduleNames, options);
|
19
|
+
return mods.map((mod) => (mod.__esModule && mod.default ? mod.default : mod));
|
20
|
+
};
|
@@ -0,0 +1,56 @@
|
|
1
|
+
/** @license
|
2
|
+
* Copyright 2022 Esri
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* You may obtain a copy of the License at
|
7
|
+
*
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
*
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
* See the License for the specific language governing permissions and
|
14
|
+
* limitations under the License.
|
15
|
+
*/
|
16
|
+
// https://medium.com/stencil-tricks/implementing-internationalisation-i18n-with-stencil-5e6559554117
|
17
|
+
import { languageMap } from "./languageUtil";
|
18
|
+
import { getAssetPath } from "@stencil/core";
|
19
|
+
export function getComponentClosestLanguage(element) {
|
20
|
+
var _a, _b, _c;
|
21
|
+
const closestElement = (_a = (element.closest("[lang]"))) !== null && _a !== void 0 ? _a : (_c = (_b = element.shadowRoot) === null || _b === void 0 ? void 0 : _b.ownerDocument) === null || _c === void 0 ? void 0 : _c.documentElement;
|
22
|
+
// language set by the calling application or browser. defaults to english.
|
23
|
+
const lang = ((closestElement === null || closestElement === void 0 ? void 0 : closestElement.lang) || (navigator === null || navigator === void 0 ? void 0 : navigator.language) || "en").toLowerCase();
|
24
|
+
if (languageMap.has(lang)) {
|
25
|
+
return languageMap.get(lang);
|
26
|
+
}
|
27
|
+
else {
|
28
|
+
// "ru-RU" maps to "ru" use case
|
29
|
+
return languageMap.has(lang.slice(0, 2)) ? languageMap.get(lang.slice(0, 2)) : "en";
|
30
|
+
}
|
31
|
+
}
|
32
|
+
function fetchLocaleStringsForComponent(componentName, locale) {
|
33
|
+
return new Promise((resolve, reject) => {
|
34
|
+
fetch(getAssetPath(`../assets/t9n/${componentName}/resources_${locale}.json`)).then(result => {
|
35
|
+
if (result.ok) {
|
36
|
+
resolve(result.json());
|
37
|
+
}
|
38
|
+
else {
|
39
|
+
reject();
|
40
|
+
}
|
41
|
+
}, () => reject());
|
42
|
+
});
|
43
|
+
}
|
44
|
+
export async function getLocaleComponentStrings(element) {
|
45
|
+
const componentName = element.tagName.toLowerCase();
|
46
|
+
const componentLanguage = getComponentClosestLanguage(element);
|
47
|
+
let strings;
|
48
|
+
try {
|
49
|
+
strings = await fetchLocaleStringsForComponent(componentName, componentLanguage);
|
50
|
+
}
|
51
|
+
catch (e) {
|
52
|
+
console.warn(`no locale for ${componentName} (${componentLanguage}) loading default locale en.`);
|
53
|
+
strings = await fetchLocaleStringsForComponent(componentName, "en");
|
54
|
+
}
|
55
|
+
return [strings, componentLanguage];
|
56
|
+
}
|