@esri/solutions-components 0.4.0 → 0.4.2
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/assets/t9n/map-select-tools/resources.json +1 -1
- package/dist/assets/t9n/map-select-tools/resources_en.json +1 -1
- package/dist/assets/t9n/public-notification/resources.json +5 -5
- package/dist/assets/t9n/public-notification/resources_en.json +5 -5
- package/dist/assets/t9n/refine-selection/resources.json +3 -3
- package/dist/assets/t9n/refine-selection/resources_en.json +3 -3
- package/dist/cjs/calcite-input-message_5.cjs.entry.js +1344 -18
- package/dist/cjs/{calcite-input-message.calcite-notice.map-select-tools.pdf-download.refine-selection-da276a1c.js → downloadUtils-99981c6b.js} +278 -1383
- package/dist/cjs/{index.es-176629d8.js → index.es-53f3bc97.js} +3 -13
- package/dist/cjs/layer-table.cjs.entry.js +5 -15
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/public-notification.cjs.entry.js +25 -10
- package/dist/cjs/solutions-components.cjs.js +1 -1
- package/dist/collection/components/layer-table/layer-table.js +4 -16
- package/dist/collection/components/map-search/map-search.js +1 -1
- package/dist/collection/components/map-select-tools/map-select-tools.js +43 -39
- package/dist/collection/components/pdf-download/pdf-download.js +33 -80
- package/dist/collection/components/public-notification/public-notification.js +26 -11
- package/dist/collection/components/refine-selection/refine-selection.js +1 -1
- package/dist/collection/utils/csvUtils.js +4 -0
- package/dist/collection/utils/csvUtils.ts +7 -0
- package/dist/collection/utils/downloadUtils.js +254 -0
- package/dist/collection/utils/downloadUtils.ts +344 -0
- package/dist/collection/utils/interfaces.ts +3 -2
- package/dist/collection/utils/pdfUtils.js +7 -0
- package/dist/collection/utils/pdfUtils.ts +13 -2
- package/dist/components/downloadUtils.js +2352 -0
- package/dist/components/index.es.js +1 -1
- package/dist/components/layer-table.js +5 -16
- package/dist/components/map-layer-picker2.js +1 -1
- package/dist/components/map-search.js +1 -1
- package/dist/components/map-select-tools2.js +45 -41
- package/dist/components/pdf-download2.js +14 -2126
- package/dist/components/public-notification.js +26 -11
- package/dist/components/queryUtils.js +1 -1
- package/dist/components/refine-selection-tools2.js +1 -1
- package/dist/components/refine-selection2.js +1 -1
- package/dist/esm/buffer-tools_6.entry.js +1 -1
- package/dist/esm/calcite-combobox_3.entry.js +1 -1
- package/dist/esm/calcite-input-message_5.entry.js +1343 -13
- package/dist/esm/{calcite-input-message.calcite-notice.map-select-tools.pdf-download.refine-selection-c6f63458.js → downloadUtils-4bb47330.js} +279 -1381
- package/dist/esm/{index.es-54a6f3a3.js → index.es-4424d2f7.js} +2 -12
- package/dist/esm/layer-table.entry.js +6 -16
- package/dist/esm/loader.js +1 -1
- package/dist/esm/{mapViewUtils-63e118f8.js → mapViewUtils-02696ab6.js} +1 -1
- package/dist/esm/public-notification.entry.js +26 -11
- package/dist/esm/solutions-components.js +1 -1
- package/dist/solutions-components/p-0aed9b0d.js +437 -0
- package/dist/solutions-components/p-0d3b0fa0.entry.js +17 -0
- package/dist/solutions-components/{p-cc2e20c8.js → p-1bfd07e3.js} +1 -1
- package/dist/solutions-components/{p-117174e8.entry.js → p-335fce8c.entry.js} +1 -1
- package/dist/solutions-components/{p-1e459361.js → p-50117f71.js} +3 -3
- package/dist/solutions-components/p-5e4dfbe4.entry.js +6 -0
- package/dist/solutions-components/{p-8a0c0935.entry.js → p-a3b60bc9.entry.js} +1 -1
- package/dist/solutions-components/p-ec7f7804.entry.js +6 -0
- package/dist/solutions-components/solutions-components.esm.js +1 -1
- package/dist/solutions-components/utils/csvUtils.ts +7 -0
- package/dist/solutions-components/utils/downloadUtils.ts +344 -0
- package/dist/solutions-components/utils/interfaces.ts +3 -2
- package/dist/solutions-components/utils/pdfUtils.ts +13 -2
- package/dist/types/components/map-select-tools/map-select-tools.d.ts +12 -6
- package/dist/types/components/pdf-download/pdf-download.d.ts +4 -20
- package/dist/types/components/public-notification/public-notification.d.ts +9 -1
- package/dist/types/components.d.ts +4 -2
- package/dist/types/utils/downloadUtils.d.ts +42 -0
- package/dist/types/utils/interfaces.d.ts +2 -3
- package/dist/types/utils/pdfUtils.d.ts +3 -1
- package/package.json +1 -1
- package/dist/cjs/csvUtils-3a56c6d8.js +0 -54
- package/dist/components/csvUtils.js +0 -52
- package/dist/esm/csvUtils-23b5418f.js +0 -52
- package/dist/solutions-components/p-3069e3b7.js +0 -21
- package/dist/solutions-components/p-6d28f991.entry.js +0 -6
- package/dist/solutions-components/p-80f5e33c.js +0 -416
- package/dist/solutions-components/p-8927862a.entry.js +0 -6
- package/dist/solutions-components/p-e69c58e5.entry.js +0 -6
|
@@ -19,13 +19,11 @@
|
|
|
19
19
|
* limitations under the License.
|
|
20
20
|
*/
|
|
21
21
|
import "@esri/calcite-components";
|
|
22
|
-
import * as
|
|
22
|
+
import * as pdfLabelFormats from "../../assets/data/labelFormats.json";
|
|
23
|
+
import * as downloadUtils from "../../utils/downloadUtils";
|
|
23
24
|
import { loadModules } from "../../utils/loadModules";
|
|
24
25
|
import { Host, h } from "@stencil/core";
|
|
25
|
-
import { exportCSV } from "../../utils/csvUtils";
|
|
26
|
-
import { exportPDF } from "../../utils/pdfUtils";
|
|
27
26
|
import { getLocaleComponentStrings } from "../../utils/locale";
|
|
28
|
-
import { queryFeaturesByID } from "../../utils/queryUtils";
|
|
29
27
|
export class PdfDownload {
|
|
30
28
|
constructor() {
|
|
31
29
|
this.disabled = false;
|
|
@@ -45,26 +43,26 @@ export class PdfDownload {
|
|
|
45
43
|
/**
|
|
46
44
|
* Downloads csv of mailing labels for the provided list of ids
|
|
47
45
|
*
|
|
46
|
+
* @param selectionSetNames Names of the selection sets used to provide ids
|
|
48
47
|
* @param ids List of ids to download
|
|
49
48
|
* @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
|
|
50
49
|
* @param addColumnTitle Indicates if column headings should be included in output
|
|
51
50
|
* @returns Promise resolving when function is done
|
|
52
51
|
*/
|
|
53
|
-
async downloadCSV(ids, removeDuplicates, addColumnTitle = true) {
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
async downloadCSV(selectionSetNames, ids, removeDuplicates, addColumnTitle = true) {
|
|
53
|
+
return downloadUtils.downloadCSV(selectionSetNames, this.layerView.layer, ids, true, // formatUsingLayerPopup
|
|
54
|
+
removeDuplicates, addColumnTitle);
|
|
56
55
|
}
|
|
57
56
|
/**
|
|
58
57
|
* Downloads pdf of mailing labels for the provided list of ids
|
|
59
58
|
*
|
|
59
|
+
* @param selectionSetNames Names of the selection sets used to provide ids
|
|
60
60
|
* @param ids List of ids to download
|
|
61
61
|
* @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
|
|
62
62
|
* @returns Promise resolving when function is done
|
|
63
63
|
*/
|
|
64
|
-
async downloadPDF(ids, removeDuplicates) {
|
|
65
|
-
|
|
66
|
-
const labelPageDescription = this._labelInfoElement.selectedOption.value;
|
|
67
|
-
return exportPDF(labels, labelPageDescription);
|
|
64
|
+
async downloadPDF(selectionSetNames, ids, removeDuplicates) {
|
|
65
|
+
return downloadUtils.downloadPDF(selectionSetNames, this.layerView.layer, ids, removeDuplicates, this._labelInfoElement.selectedOption.value);
|
|
68
66
|
}
|
|
69
67
|
//--------------------------------------------------------------------------
|
|
70
68
|
//
|
|
@@ -107,31 +105,6 @@ export class PdfDownload {
|
|
|
107
105
|
]);
|
|
108
106
|
this._intl = intl;
|
|
109
107
|
}
|
|
110
|
-
/**
|
|
111
|
-
* Converts the text of a custom popup into a multiline label specification; conversion splits text into
|
|
112
|
-
* lines on <br>s, and removes HTML tags. It does not handle Arcade and related records.
|
|
113
|
-
*
|
|
114
|
-
* @param popupInfo Layer's popupInfo structure containing description, fieldInfos, and expressionInfos, e.g.,
|
|
115
|
-
* "<div style='text-align: left;'>{NAME}<br />{STREET}<br />{CITY}, {STATE} {ZIP} <br /></div>"
|
|
116
|
-
* @return Label spec
|
|
117
|
-
*/
|
|
118
|
-
_convertPopupToLabelSpec(popupInfo) {
|
|
119
|
-
// Replace <br>, <br/> with |
|
|
120
|
-
popupInfo = popupInfo.replace(/<br\s*\/?>/gi, "|");
|
|
121
|
-
// Remove remaining HTML tags, replace 0xA0 that popup uses for spaces, replace some char representations,
|
|
122
|
-
// and split the label back into individual lines
|
|
123
|
-
let labelSpec = popupInfo
|
|
124
|
-
.replace(/<[\s.]*[^<>]*\/?>/gi, "")
|
|
125
|
-
.replace(/\xA0/gi, " ")
|
|
126
|
-
.replace(/</gi, "<")
|
|
127
|
-
.replace(/>/gi, ">")
|
|
128
|
-
.replace(/ /gi, " ")
|
|
129
|
-
.split("|");
|
|
130
|
-
// Trim lines and remove empties
|
|
131
|
-
labelSpec = labelSpec.map(line => line.trim()).filter(line => line.length > 0);
|
|
132
|
-
return labelSpec;
|
|
133
|
-
}
|
|
134
|
-
;
|
|
135
108
|
/**
|
|
136
109
|
* Gets the formatted pdf export size text
|
|
137
110
|
*
|
|
@@ -154,47 +127,6 @@ export class PdfDownload {
|
|
|
154
127
|
const translations = await getLocaleComponentStrings(this.el);
|
|
155
128
|
this._translations = translations[0];
|
|
156
129
|
}
|
|
157
|
-
/**
|
|
158
|
-
* Creates labels from items.
|
|
159
|
-
*
|
|
160
|
-
* @param ids List of ids to download
|
|
161
|
-
* @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
|
|
162
|
-
* @param includeHeaderNames Add the label format at the front of the list of generated labels
|
|
163
|
-
* @returns Promise resolving when function is done
|
|
164
|
-
*/
|
|
165
|
-
async _prepareLabels(ids, removeDuplicates, includeHeaderNames = false) {
|
|
166
|
-
// Get the attributes of the features to export
|
|
167
|
-
const featureSet = await queryFeaturesByID(ids, this.layerView.layer);
|
|
168
|
-
const featuresAttrs = featureSet.features.map(f => f.attributes);
|
|
169
|
-
// What data fields are used in the labels?
|
|
170
|
-
// Example labelFormat: ['{NAME}', '{STREET}', '{CITY}, {STATE} {ZIP}']
|
|
171
|
-
const labelFormat = this._convertPopupToLabelSpec(this.layerView.layer.popupTemplate.content[0].text);
|
|
172
|
-
// Convert attributes into an array of labels
|
|
173
|
-
let labels = featuresAttrs.map(featureAttributes => {
|
|
174
|
-
const label = [];
|
|
175
|
-
labelFormat.forEach(labelLineTemplate => {
|
|
176
|
-
const labelLine = this._intl.substitute(labelLineTemplate, featureAttributes).trim();
|
|
177
|
-
if (labelLine.length > 0) {
|
|
178
|
-
label.push(labelLine);
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
return label;
|
|
182
|
-
})
|
|
183
|
-
// Remove empty labels
|
|
184
|
-
.filter(label => label.length > 0);
|
|
185
|
-
// Remove duplicates
|
|
186
|
-
if (removeDuplicates) {
|
|
187
|
-
const labelsAsStrings = labels.map(label => JSON.stringify(label));
|
|
188
|
-
const uniqueLabels = new Set(labelsAsStrings);
|
|
189
|
-
labels = Array.from(uniqueLabels, labelString => JSON.parse(labelString));
|
|
190
|
-
}
|
|
191
|
-
// Add header names
|
|
192
|
-
if (includeHeaderNames) {
|
|
193
|
-
const headerNames = labelFormat.map(labelFormatLine => labelFormatLine.replace(/\{/g, "").replace(/\}/g, ""));
|
|
194
|
-
labels.unshift(headerNames);
|
|
195
|
-
}
|
|
196
|
-
return Promise.resolve(labels);
|
|
197
|
-
}
|
|
198
130
|
/**
|
|
199
131
|
* Renders the pdf export size options
|
|
200
132
|
*
|
|
@@ -203,7 +135,7 @@ export class PdfDownload {
|
|
|
203
135
|
* @protected
|
|
204
136
|
*/
|
|
205
137
|
_renderItems() {
|
|
206
|
-
const s =
|
|
138
|
+
const s = pdfLabelFormats;
|
|
207
139
|
const sortedPdfIndo = (s.default || s).sort((a, b) => {
|
|
208
140
|
const _a = parseInt(a.descriptionPDF.labelsPerPageDisplay, 10);
|
|
209
141
|
const _b = parseInt(b.descriptionPDF.labelsPerPageDisplay, 10);
|
|
@@ -275,8 +207,14 @@ export class PdfDownload {
|
|
|
275
207
|
return {
|
|
276
208
|
"downloadCSV": {
|
|
277
209
|
"complexType": {
|
|
278
|
-
"signature": "(ids: number[], removeDuplicates: boolean, addColumnTitle?: boolean) => Promise<void>",
|
|
210
|
+
"signature": "(selectionSetNames: string[], ids: number[], removeDuplicates: boolean, addColumnTitle?: boolean) => Promise<void>",
|
|
279
211
|
"parameters": [{
|
|
212
|
+
"tags": [{
|
|
213
|
+
"name": "param",
|
|
214
|
+
"text": "selectionSetNames Names of the selection sets used to provide ids"
|
|
215
|
+
}],
|
|
216
|
+
"text": "Names of the selection sets used to provide ids"
|
|
217
|
+
}, {
|
|
280
218
|
"tags": [{
|
|
281
219
|
"name": "param",
|
|
282
220
|
"text": "ids List of ids to download"
|
|
@@ -305,6 +243,9 @@ export class PdfDownload {
|
|
|
305
243
|
"docs": {
|
|
306
244
|
"text": "Downloads csv of mailing labels for the provided list of ids",
|
|
307
245
|
"tags": [{
|
|
246
|
+
"name": "param",
|
|
247
|
+
"text": "selectionSetNames Names of the selection sets used to provide ids"
|
|
248
|
+
}, {
|
|
308
249
|
"name": "param",
|
|
309
250
|
"text": "ids List of ids to download"
|
|
310
251
|
}, {
|
|
@@ -321,8 +262,14 @@ export class PdfDownload {
|
|
|
321
262
|
},
|
|
322
263
|
"downloadPDF": {
|
|
323
264
|
"complexType": {
|
|
324
|
-
"signature": "(ids: number[], removeDuplicates: boolean) => Promise<void>",
|
|
265
|
+
"signature": "(selectionSetNames: string[], ids: number[], removeDuplicates: boolean) => Promise<void>",
|
|
325
266
|
"parameters": [{
|
|
267
|
+
"tags": [{
|
|
268
|
+
"name": "param",
|
|
269
|
+
"text": "selectionSetNames Names of the selection sets used to provide ids"
|
|
270
|
+
}],
|
|
271
|
+
"text": "Names of the selection sets used to provide ids"
|
|
272
|
+
}, {
|
|
326
273
|
"tags": [{
|
|
327
274
|
"name": "param",
|
|
328
275
|
"text": "ids List of ids to download"
|
|
@@ -338,6 +285,9 @@ export class PdfDownload {
|
|
|
338
285
|
"references": {
|
|
339
286
|
"Promise": {
|
|
340
287
|
"location": "global"
|
|
288
|
+
},
|
|
289
|
+
"downloadUtils": {
|
|
290
|
+
"location": "global"
|
|
341
291
|
}
|
|
342
292
|
},
|
|
343
293
|
"return": "Promise<void>"
|
|
@@ -345,6 +295,9 @@ export class PdfDownload {
|
|
|
345
295
|
"docs": {
|
|
346
296
|
"text": "Downloads pdf of mailing labels for the provided list of ids",
|
|
347
297
|
"tags": [{
|
|
298
|
+
"name": "param",
|
|
299
|
+
"text": "selectionSetNames Names of the selection sets used to provide ids"
|
|
300
|
+
}, {
|
|
348
301
|
"name": "param",
|
|
349
302
|
"text": "ids List of ids to download"
|
|
350
303
|
}, {
|
|
@@ -82,7 +82,8 @@ export class PublicNotification {
|
|
|
82
82
|
console.log(oldValue);
|
|
83
83
|
if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
|
|
84
84
|
console.log("Emit event from parent");
|
|
85
|
-
this.
|
|
85
|
+
this.searchConfiguration = Object.assign({}, newValue);
|
|
86
|
+
this.searchConfigurationChange.emit(this.searchConfiguration);
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
/**
|
|
@@ -152,8 +153,7 @@ export class PublicNotification {
|
|
|
152
153
|
* Renders the component.
|
|
153
154
|
*/
|
|
154
155
|
render() {
|
|
155
|
-
|
|
156
|
-
return (h(Host, null, h("calcite-shell", null, h("calcite-action-bar", { class: "border-bottom-1 action-bar-size", "expand-disabled": true, layout: "horizontal", slot: "header" }, this._getActionGroup("list-check", false, EPageType.LIST, this._translations.myLists), this.showRefineSelection ? this._getActionGroup("test-data", !hasSelections, EPageType.REFINE, this._translations.refineSelection) : undefined, this._getActionGroup("file-pdf", !hasSelections, EPageType.PDF, this._translations.downloadPDF), this._getActionGroup("file-csv", !hasSelections, EPageType.CSV, this._translations.downloadCSV)), this._getPage(this._pageType))));
|
|
156
|
+
return (h(Host, null, h("calcite-shell", null, h("calcite-action-bar", { class: "border-bottom-1 action-bar-size", "expand-disabled": true, layout: "horizontal", slot: "header" }, this._getActionGroup("list-check", EPageType.LIST, this._translations.myLists), this.showRefineSelection ? this._getActionGroup("test-data", EPageType.REFINE, this._translations.refineSelection) : undefined, this._getActionGroup("file-pdf", EPageType.PDF, this._translations.downloadPDF), this._getActionGroup("file-csv", EPageType.CSV, this._translations.downloadCSV)), this._getPage(this._pageType))));
|
|
157
157
|
}
|
|
158
158
|
//--------------------------------------------------------------------------
|
|
159
159
|
//
|
|
@@ -183,9 +183,9 @@ export class PublicNotification {
|
|
|
183
183
|
*
|
|
184
184
|
* @protected
|
|
185
185
|
*/
|
|
186
|
-
_getActionGroup(icon,
|
|
186
|
+
_getActionGroup(icon, pageType, tip) {
|
|
187
187
|
const groupClass = this.showRefineSelection ? "action-center w-1-4" : "action-center w-1-3";
|
|
188
|
-
return (h("calcite-action-group", { class: groupClass, layout: "horizontal" }, h("calcite-action", { active: this._pageType === pageType, alignment: "center", class: "width-full height-full", compact: false,
|
|
188
|
+
return (h("calcite-action-group", { class: groupClass, layout: "horizontal" }, h("calcite-action", { active: this._pageType === pageType, alignment: "center", class: "width-full height-full", compact: false, icon: icon, id: icon, onClick: () => { this._setPageType(pageType); }, text: "" }), h("calcite-tooltip", { label: "", placement: "bottom", "reference-element": icon }, h("span", null, tip))));
|
|
189
189
|
}
|
|
190
190
|
/**
|
|
191
191
|
* Navigate to the defined page type
|
|
@@ -299,6 +299,16 @@ export class PublicNotification {
|
|
|
299
299
|
this._layerSelectionChangeEvt.detail[0] : "";
|
|
300
300
|
await this._updateAddresseeLayer(id);
|
|
301
301
|
}
|
|
302
|
+
/**
|
|
303
|
+
* Check if any selection sets exist.
|
|
304
|
+
*
|
|
305
|
+
* @returns true if selection sets exist
|
|
306
|
+
*
|
|
307
|
+
* @protected
|
|
308
|
+
*/
|
|
309
|
+
_hasSelections() {
|
|
310
|
+
return this._selectionSets.length > 0;
|
|
311
|
+
}
|
|
302
312
|
/**
|
|
303
313
|
* Create the Select page that shows the selection workflows
|
|
304
314
|
*
|
|
@@ -316,7 +326,7 @@ export class PublicNotification {
|
|
|
316
326
|
this._selectionWorkflowType === EWorkflowType.SKETCH ? sketchTip : searchTip;
|
|
317
327
|
const nameLabelClass = this.customLabelEnabled ? "" : "display-none";
|
|
318
328
|
return (h("calcite-panel", null, this._getLabel(this._translations.stepTwoFull.replace("{{layer}}", (_a = this.addresseeLayer) === null || _a === void 0 ? void 0 : _a.layer.title)), this._getNotice(noticeText), h("div", { class: "padding-top-sides-1" }, h("map-select-tools", { bufferColor: this.bufferColor, bufferOutlineColor: this.bufferOutlineColor, class: "font-bold", defaultBufferDistance: this.defaultBufferDistance, defaultBufferUnit: this.defaultBufferUnit, enabledLayerIds: this.selectionLayerIds, isUpdate: !!this._activeSelection, mapView: this.mapView, onSelectionSetChange: (evt) => this._updateForSelection(evt), onWorkflowTypeChange: (evt) => this._updateForWorkflowType(evt), ref: (el) => { this._selectTools = el; }, searchConfiguration: this.searchConfiguration, selectLayerView: this.addresseeLayer, selectionSet: this._activeSelection, showBufferTools: this.showSearchSettings })), h("div", { class: "padding-sides-1 padding-bottom-1", style: { "align-items": "end", "display": "flex" } }, h("calcite-icon", { class: "info-blue padding-end-1-2", icon: "feature-layer", scale: "s" }), h("calcite-input-message", { active: true, class: "info-blue", scale: "m" }, this.noResultText && this._numSelected === 0 ? this.noResultText :
|
|
319
|
-
this._translations.selectedAddresses.replace("{{n}}", this._numSelected.toString()).replace("{{layer}}", ((_b = this.addresseeLayer) === null || _b === void 0 ? void 0 : _b.layer.title) || ""))), h("div", { class: "padding-sides-1 " + nameLabelClass }, h("calcite-label", { class: "font-bold" }, "
|
|
329
|
+
this._translations.selectedAddresses.replace("{{n}}", this._numSelected.toString()).replace("{{layer}}", ((_b = this.addresseeLayer) === null || _b === void 0 ? void 0 : _b.layer.title) || ""))), h("div", { class: "padding-sides-1 " + nameLabelClass }, h("calcite-label", { class: "font-bold" }, "List name", h("calcite-input", { onInput: () => {
|
|
320
330
|
this.labelChange.emit(this._labelName.value);
|
|
321
331
|
}, placeholder: "Insert label here...", ref: (el) => { this._labelName = el; }, value: this._customLabel || "" }))), this._getPageNavButtons(this._translations.done, this._numSelected === 0, () => { void this._saveSelection(); }, this._translations.cancel, false, () => { void this._home(); })));
|
|
322
332
|
}
|
|
@@ -327,7 +337,9 @@ export class PublicNotification {
|
|
|
327
337
|
* @protected
|
|
328
338
|
*/
|
|
329
339
|
_getRefinePage() {
|
|
330
|
-
|
|
340
|
+
const hasSelections = this._hasSelections();
|
|
341
|
+
return (h("calcite-panel", null, this._getLabel(this._translations.refineSelection), hasSelections ? (h("div", null, this._getNotice(this._translations.refineTip, "padding-sides-1"), h("refine-selection", { addresseeLayer: this.addresseeLayer, enabledLayerIds: this.selectionLayerIds, mapView: this.mapView, selectionSets: this._selectionSets }))) :
|
|
342
|
+
this._getNotice(this._translations.refineTipNoSelections, "padding-sides-1")));
|
|
331
343
|
}
|
|
332
344
|
/**
|
|
333
345
|
* Create the PDF download page that shows the download options
|
|
@@ -358,7 +370,8 @@ export class PublicNotification {
|
|
|
358
370
|
*/
|
|
359
371
|
_getDownloadPage(type) {
|
|
360
372
|
const isPdf = type === EExportType.PDF;
|
|
361
|
-
|
|
373
|
+
const hasSelections = this._hasSelections();
|
|
374
|
+
return (h("calcite-panel", null, h("div", null, h("div", { class: "padding-top-sides-1" }, h("calcite-label", { class: "font-bold" }, isPdf ? this._translations.downloadPDF : this._translations.downloadCSV)), hasSelections ? (h("div", null, h("calcite-label", null, this._translations.notifications), this._getSelectionLists(), h("div", { class: "margin-side-1 padding-top-1 border-bottom" }), h("div", { class: "padding-top-sides-1" }, h("calcite-label", { layout: "inline" }, h("calcite-checkbox", { disabled: !this._downloadActive, ref: (el) => { this._removeDuplicates = el; } }), this._translations.removeDuplicate)), h("div", { class: isPdf ? "" : "display-none" }, this._getLabel(this._translations.selectPDFLabelOption, false), h("div", { class: "padding-sides-1" }, h("pdf-download", { disabled: !this._downloadActive, layerView: this.addresseeLayer, ref: (el) => { this._downloadTools = el; } }))), h("div", { class: "padding-1 display-flex" }, h("calcite-button", { disabled: !this._downloadActive, onClick: isPdf ? () => this._downloadPDF() : () => this._downloadCSV(), width: "full" }, isPdf ? this._translations.downloadPDF : this._translations.downloadCSV)))) : (this._getNotice(this._translations.downloadNoLists, "padding-sides-1 padding-bottom-1")))));
|
|
362
375
|
}
|
|
363
376
|
/**
|
|
364
377
|
* Create the stacked navigation buttons for a page
|
|
@@ -441,7 +454,8 @@ export class PublicNotification {
|
|
|
441
454
|
*/
|
|
442
455
|
_downloadPDF() {
|
|
443
456
|
const ids = utils.getSelectionIds(this._getDownloadSelectionSets());
|
|
444
|
-
|
|
457
|
+
const selectionSetNames = this._selectionSets.map(set => set.label);
|
|
458
|
+
void this._downloadTools.downloadPDF(selectionSetNames, ids, this._removeDuplicates.checked);
|
|
445
459
|
}
|
|
446
460
|
/**
|
|
447
461
|
* Download all selection sets as CSV
|
|
@@ -450,7 +464,8 @@ export class PublicNotification {
|
|
|
450
464
|
*/
|
|
451
465
|
_downloadCSV() {
|
|
452
466
|
const ids = utils.getSelectionIds(this._getDownloadSelectionSets());
|
|
453
|
-
|
|
467
|
+
const selectionSetNames = this._selectionSets.map(set => set.label);
|
|
468
|
+
void this._downloadTools.downloadCSV(selectionSetNames, ids, this._removeDuplicates.checked);
|
|
454
469
|
}
|
|
455
470
|
/**
|
|
456
471
|
* Get all enabled selection sets
|
|
@@ -897,7 +912,7 @@ export class PublicNotification {
|
|
|
897
912
|
},
|
|
898
913
|
"searchConfiguration": {
|
|
899
914
|
"type": "unknown",
|
|
900
|
-
"mutable":
|
|
915
|
+
"mutable": true,
|
|
901
916
|
"complexType": {
|
|
902
917
|
"original": "ISearchConfiguration",
|
|
903
918
|
"resolved": "ISearchConfiguration",
|
|
@@ -118,7 +118,7 @@ export class RefineSelection {
|
|
|
118
118
|
const refineSet = this._getRefineSelectionSet(this.selectionSets);
|
|
119
119
|
const numAdded = (refineSet === null || refineSet === void 0 ? void 0 : refineSet.refineIds.addIds.length) || 0;
|
|
120
120
|
const numRemoved = (refineSet === null || refineSet === void 0 ? void 0 : refineSet.refineIds.removeIds.length) || 0;
|
|
121
|
-
return [(h("calcite-list-item", { label: this._translations.featuresAdded.replace("{{n}}", numAdded.toString()) })), (h("calcite-list-item", { label: this._translations.featuresRemoved.replace("{{n}}", numRemoved.toString()) })), (h("calcite-list-item", { label: this._translations.totalSelected.replace("{{n}}", total.toString()) }))];
|
|
121
|
+
return [(h("calcite-list-item", { label: this._translations.featuresAdded.replace("{{n}}", numAdded.toString()), "non-interactive": true })), (h("calcite-list-item", { label: this._translations.featuresRemoved.replace("{{n}}", numRemoved.toString()), "non-interactive": true })), (h("calcite-list-item", { label: this._translations.totalSelected.replace("{{n}}", total.toString()), "non-interactive": true }))];
|
|
122
122
|
}
|
|
123
123
|
/**
|
|
124
124
|
* Fetch the refine selection set
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* See the License for the specific language governing permissions and
|
|
19
19
|
* limitations under the License.
|
|
20
20
|
*/
|
|
21
|
+
//#region Public functions
|
|
21
22
|
/**
|
|
22
23
|
* Export a csv of the attributes from the features that match the provided ids
|
|
23
24
|
*
|
|
@@ -29,6 +30,8 @@ export function exportCSV(labels) {
|
|
|
29
30
|
const outputLines = labels.map(label => Object.values(label).map(v => `"${v}"`).join(",") + "\r\n");
|
|
30
31
|
_downloadCSVFile(outputLines, `notify-${Date.now().toString()}`);
|
|
31
32
|
}
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region Private functions
|
|
32
35
|
/**
|
|
33
36
|
* Download the CSV file
|
|
34
37
|
*
|
|
@@ -48,3 +51,4 @@ function _downloadCSVFile(outputLines, fileTitle) {
|
|
|
48
51
|
document.body.removeChild(link);
|
|
49
52
|
}
|
|
50
53
|
}
|
|
54
|
+
//#endregion
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
//#region Public functions
|
|
18
|
+
|
|
17
19
|
/**
|
|
18
20
|
* Export a csv of the attributes from the features that match the provided ids
|
|
19
21
|
*
|
|
@@ -29,6 +31,9 @@ export function exportCSV(
|
|
|
29
31
|
_downloadCSVFile(outputLines, `notify-${Date.now().toString()}`);
|
|
30
32
|
}
|
|
31
33
|
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region Private functions
|
|
36
|
+
|
|
32
37
|
/**
|
|
33
38
|
* Download the CSV file
|
|
34
39
|
*
|
|
@@ -51,3 +56,5 @@ function _downloadCSVFile(
|
|
|
51
56
|
document.body.removeChild(link);
|
|
52
57
|
}
|
|
53
58
|
}
|
|
59
|
+
|
|
60
|
+
//#endregion
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright 2022 Esri
|
|
3
|
+
* Licensed under the Apache License, Version 2.0
|
|
4
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
5
|
+
*/
|
|
6
|
+
/** @license
|
|
7
|
+
* Copyright 2022 Esri
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
//#region Declarations
|
|
22
|
+
import { exportCSV } from "./csvUtils";
|
|
23
|
+
import { exportPDF } from "./pdfUtils";
|
|
24
|
+
import { loadModules } from "./loadModules";
|
|
25
|
+
import { queryFeaturesByID } from "./queryUtils";
|
|
26
|
+
export { ILabel } from "./pdfUtils";
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region Public functions
|
|
29
|
+
/**
|
|
30
|
+
* Downloads csv of mailing labels for the provided list of ids
|
|
31
|
+
*
|
|
32
|
+
* @param selectionSetNames Names of the selection sets used to provide ids
|
|
33
|
+
* @param layer Layer providing features and attributes for download
|
|
34
|
+
* @param ids List of ids to download
|
|
35
|
+
* @param formatUsingLayerPopup When true, the layer's popup is used to choose attributes for each column; when false,
|
|
36
|
+
* all attributes are exported
|
|
37
|
+
* @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
|
|
38
|
+
* @param addColumnTitle Indicates if column headings should be included in output
|
|
39
|
+
* @returns Promise resolving when function is done
|
|
40
|
+
*/
|
|
41
|
+
export async function downloadCSV(selectionSetNames, layer, ids, formatUsingLayerPopup, removeDuplicates = false, addColumnTitle = false) {
|
|
42
|
+
console.log("downloadCSV using selectionSetNames " + JSON.stringify(selectionSetNames)); //???
|
|
43
|
+
const labels = await _prepareLabels(layer, ids, removeDuplicates, formatUsingLayerPopup, addColumnTitle);
|
|
44
|
+
exportCSV(labels);
|
|
45
|
+
return Promise.resolve();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Downloads csv of mailing labels for the provided list of ids
|
|
49
|
+
*
|
|
50
|
+
* @param selectionSetNames Names of the selection sets used to provide ids
|
|
51
|
+
* @param layer Layer providing features and attributes for download
|
|
52
|
+
* @param ids List of ids to download
|
|
53
|
+
* @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
|
|
54
|
+
* @param labelPageDescription Provides PDF page layout info
|
|
55
|
+
* @returns Promise resolving when function is done
|
|
56
|
+
*/
|
|
57
|
+
export async function downloadPDF(selectionSetNames, layer, ids, removeDuplicates, labelPageDescription) {
|
|
58
|
+
console.log("downloadPDF using selectionSetNames " + JSON.stringify(selectionSetNames)); //???
|
|
59
|
+
const labels = await _prepareLabels(layer, ids, removeDuplicates);
|
|
60
|
+
exportPDF(labels, labelPageDescription);
|
|
61
|
+
return Promise.resolve();
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region Private functions
|
|
65
|
+
/**
|
|
66
|
+
* Converts a set of fieldInfos into template lines.
|
|
67
|
+
*
|
|
68
|
+
* @param fieldInfos Layer's fieldInfos structure
|
|
69
|
+
* @param bypassFieldVisiblity Indicates if the configured fieldInfo visibility property should be ignored
|
|
70
|
+
* @return Label spec
|
|
71
|
+
*/
|
|
72
|
+
function _convertPopupFieldsToLabelSpec(fieldInfos, bypassFieldVisiblity = false) {
|
|
73
|
+
const labelSpec = [];
|
|
74
|
+
// Every visible attribute is used
|
|
75
|
+
fieldInfos.forEach(fieldInfo => {
|
|
76
|
+
if (fieldInfo.visible || bypassFieldVisiblity) {
|
|
77
|
+
labelSpec.push(`{${fieldInfo.fieldName}}`);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
return labelSpec;
|
|
81
|
+
}
|
|
82
|
+
;
|
|
83
|
+
/**
|
|
84
|
+
* Converts the text of a custom popup into a multiline label specification; conversion splits text into
|
|
85
|
+
* lines on <br>s, and removes HTML tags. It does not handle Arcade and related records.
|
|
86
|
+
*
|
|
87
|
+
* @param popupInfo Layer's popupInfo structure containing description, fieldInfos, and expressionInfos, e.g.,
|
|
88
|
+
* "<div style='text-align: left;'>{NAME}<br />{STREET}<br />{CITY}, {STATE} {ZIP} <br /></div>"
|
|
89
|
+
* @return Label spec
|
|
90
|
+
*/
|
|
91
|
+
function _convertPopupTextToLabelSpec(popupInfo) {
|
|
92
|
+
// Replace <br>, <br/> with |
|
|
93
|
+
popupInfo = popupInfo.replace(/<br\s*\/?>/gi, "|");
|
|
94
|
+
// Remove remaining HTML tags, replace 0xA0 that popup uses for spaces, replace some char representations,
|
|
95
|
+
// and split the label back into individual lines
|
|
96
|
+
let labelSpec = popupInfo
|
|
97
|
+
.replace(/<[\s.]*[^<>]*\/?>/gi, "")
|
|
98
|
+
.replace(/\xA0/gi, " ")
|
|
99
|
+
.replace(/</gi, "<")
|
|
100
|
+
.replace(/>/gi, ">")
|
|
101
|
+
.replace(/ /gi, " ")
|
|
102
|
+
.split("|");
|
|
103
|
+
// Trim lines and remove empties
|
|
104
|
+
labelSpec = labelSpec.map(line => line.trim()).filter(line => line.length > 0);
|
|
105
|
+
return labelSpec;
|
|
106
|
+
}
|
|
107
|
+
;
|
|
108
|
+
/**
|
|
109
|
+
* Extracts Arcade expressions from the lines of a label format and creates an Arcade executor for each
|
|
110
|
+
* referenced expression name.
|
|
111
|
+
*
|
|
112
|
+
* @param labelFormat Label to examine
|
|
113
|
+
* @param layer Layer from which to fetch features
|
|
114
|
+
* @return Promise resolving to a set of executors keyed using the expression name
|
|
115
|
+
*/
|
|
116
|
+
async function _createArcadeExecutors(labelFormat, layer) {
|
|
117
|
+
const arcadeExecutors = {};
|
|
118
|
+
// Are any Arcade expressions in the layer?
|
|
119
|
+
if (!Array.isArray(layer.popupTemplate.expressionInfos) || layer.popupTemplate.expressionInfos.length === 0) {
|
|
120
|
+
return Promise.resolve(arcadeExecutors);
|
|
121
|
+
}
|
|
122
|
+
// Are there any Arcade expressions in the label format?
|
|
123
|
+
const arcadeExpressionRegExp = /\{expression\/\w+\}/g;
|
|
124
|
+
const arcadeExpressionsMatches = labelFormat.join("|").match(arcadeExpressionRegExp);
|
|
125
|
+
if (!arcadeExpressionsMatches) {
|
|
126
|
+
return Promise.resolve(arcadeExecutors);
|
|
127
|
+
}
|
|
128
|
+
// Generate an Arcade executor for each match
|
|
129
|
+
const [arcade] = await loadModules(["esri/arcade"]);
|
|
130
|
+
const labelingProfile = arcade.createArcadeProfile("popup");
|
|
131
|
+
const createArcadeExecutorPromises = {};
|
|
132
|
+
arcadeExpressionsMatches.forEach((match) => {
|
|
133
|
+
const expressionName = match.substring(match.indexOf("/") + 1, match.length - 1);
|
|
134
|
+
(layer.popupTemplate.expressionInfos || []).forEach(expressionInfo => {
|
|
135
|
+
if (expressionInfo.name === expressionName) {
|
|
136
|
+
createArcadeExecutorPromises[expressionName] =
|
|
137
|
+
arcade.createArcadeExecutor(expressionInfo.expression, labelingProfile);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
const promises = Object.values(createArcadeExecutorPromises);
|
|
142
|
+
return Promise.all(promises)
|
|
143
|
+
.then(executors => {
|
|
144
|
+
const expressionNames = Object.keys(createArcadeExecutorPromises);
|
|
145
|
+
for (let i = 0; i < expressionNames.length; ++i) {
|
|
146
|
+
arcadeExecutors[expressionNames[i]] = executors[i].valueOf();
|
|
147
|
+
}
|
|
148
|
+
return arcadeExecutors;
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Creates labels from items.
|
|
153
|
+
*
|
|
154
|
+
* @param layer Layer from which to fetch features
|
|
155
|
+
* @param ids List of ids to download
|
|
156
|
+
* @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
|
|
157
|
+
* @param formatUsingLayerPopup When true, the layer's popup is used to choose attributes for each column; when false,
|
|
158
|
+
* all attributes are exported
|
|
159
|
+
* @param includeHeaderNames Add the label format at the front of the list of generated labels
|
|
160
|
+
* @returns Promise resolving when function is done
|
|
161
|
+
*/
|
|
162
|
+
async function _prepareLabels(layer, ids, removeDuplicates = true, formatUsingLayerPopup = true, includeHeaderNames = false) {
|
|
163
|
+
var _a, _b, _c, _d;
|
|
164
|
+
const [intl] = await loadModules(["esri/intl"]);
|
|
165
|
+
// Get the features to export
|
|
166
|
+
const featureSet = await queryFeaturesByID(ids, layer);
|
|
167
|
+
// Get the label formatting, if any
|
|
168
|
+
let labelFormat;
|
|
169
|
+
let arcadeExecutors = {};
|
|
170
|
+
if (layer.popupEnabled) {
|
|
171
|
+
// What data fields are used in the labels?
|
|
172
|
+
// Example labelFormat: ['{NAME}', '{STREET}', '{CITY}, {STATE} {ZIP}']
|
|
173
|
+
if (formatUsingLayerPopup && ((_b = (_a = layer.popupTemplate) === null || _a === void 0 ? void 0 : _a.content[0]) === null || _b === void 0 ? void 0 : _b.type) === "fields") {
|
|
174
|
+
labelFormat = _convertPopupFieldsToLabelSpec(layer.popupTemplate.fieldInfos);
|
|
175
|
+
// If popup is configured with "no attribute information", then no fields will visible
|
|
176
|
+
if (labelFormat.length === 0) {
|
|
177
|
+
// Can we use the popup title?
|
|
178
|
+
// eslint-disable-next-line unicorn/prefer-ternary
|
|
179
|
+
if (typeof layer.popupTemplate.title === "string") {
|
|
180
|
+
labelFormat = [layer.popupTemplate.title];
|
|
181
|
+
// Otherwise revert to using attributes
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
labelFormat = _convertPopupFieldsToLabelSpec(layer.popupTemplate.fieldInfos, true);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
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") {
|
|
189
|
+
labelFormat = _convertPopupTextToLabelSpec(layer.popupTemplate.content[0].text);
|
|
190
|
+
// Do we need any Arcade executors?
|
|
191
|
+
arcadeExecutors = await _createArcadeExecutors(labelFormat, layer);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Apply the label format
|
|
195
|
+
let labels;
|
|
196
|
+
// eslint-disable-next-line unicorn/prefer-ternary
|
|
197
|
+
if (labelFormat) {
|
|
198
|
+
const arcadeExpressionRegExp = /\{expression\/\w+\}/g;
|
|
199
|
+
// Convert attributes into an array of labels
|
|
200
|
+
labels = featureSet.features.map(feature => {
|
|
201
|
+
const label = [];
|
|
202
|
+
labelFormat.forEach(labelLineTemplate => {
|
|
203
|
+
let labelLine = labelLineTemplate;
|
|
204
|
+
// Replace Arcade expressions
|
|
205
|
+
const arcadeExpressionsMatches = labelLine.match(arcadeExpressionRegExp);
|
|
206
|
+
if (arcadeExpressionsMatches) {
|
|
207
|
+
arcadeExpressionsMatches.forEach((match) => {
|
|
208
|
+
const expressionName = match.substring(match.indexOf("/") + 1, match.length - 1);
|
|
209
|
+
const replacement = arcadeExecutors[expressionName].execute({ "$feature": feature });
|
|
210
|
+
labelLine = labelLine.replace(match, replacement);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
// Replace fields; must be done after Arcade check because `substitute` will discard Arcade expressions!
|
|
214
|
+
labelLine = intl.substitute(labelLine, feature.attributes).trim();
|
|
215
|
+
if (labelLine.length > 0) {
|
|
216
|
+
label.push(labelLine);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
return label;
|
|
220
|
+
})
|
|
221
|
+
// Remove empty labels
|
|
222
|
+
.filter(label => label.length > 0);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
// Export all attributes
|
|
226
|
+
labels = featureSet.features.map(feature => {
|
|
227
|
+
return Object.values(feature.attributes).map(attribute => `${attribute}`);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
// Remove duplicates
|
|
231
|
+
if (removeDuplicates) {
|
|
232
|
+
const labelsAsStrings = labels.map(label => JSON.stringify(label));
|
|
233
|
+
const uniqueLabels = new Set(labelsAsStrings);
|
|
234
|
+
labels = Array.from(uniqueLabels, labelString => JSON.parse(labelString));
|
|
235
|
+
}
|
|
236
|
+
// Add header names
|
|
237
|
+
if (includeHeaderNames) {
|
|
238
|
+
let headerNames = [];
|
|
239
|
+
if (labelFormat) {
|
|
240
|
+
headerNames = labelFormat.map(labelFormatLine => labelFormatLine.replace(/\{/g, "").replace(/\}/g, ""));
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
const featuresAttrs = featureSet.features[0].attributes;
|
|
244
|
+
Object.keys(featuresAttrs).forEach(k => {
|
|
245
|
+
if (featuresAttrs[0].hasOwnProperty(k)) {
|
|
246
|
+
headerNames.push(k);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
labels.unshift(headerNames);
|
|
251
|
+
}
|
|
252
|
+
return Promise.resolve(labels);
|
|
253
|
+
}
|
|
254
|
+
//#endregion
|