@esri/solutions-components 0.4.0 → 0.4.1

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.
Files changed (70) hide show
  1. package/dist/assets/t9n/public-notification/resources.json +0 -2
  2. package/dist/assets/t9n/public-notification/resources_en.json +0 -2
  3. package/dist/cjs/calcite-input-message_5.cjs.entry.js +1342 -18
  4. package/dist/cjs/{calcite-input-message.calcite-notice.map-select-tools.pdf-download.refine-selection-da276a1c.js → downloadUtils-27dbd8b9.js} +205 -1383
  5. package/dist/cjs/{index.es-176629d8.js → index.es-40d341ed.js} +3 -13
  6. package/dist/cjs/layer-table.cjs.entry.js +5 -15
  7. package/dist/cjs/loader.cjs.js +1 -1
  8. package/dist/cjs/public-notification.cjs.entry.js +2 -2
  9. package/dist/cjs/solutions-components.cjs.js +1 -1
  10. package/dist/collection/components/layer-table/layer-table.js +4 -16
  11. package/dist/collection/components/map-search/map-search.js +1 -1
  12. package/dist/collection/components/map-select-tools/map-select-tools.js +42 -38
  13. package/dist/collection/components/pdf-download/pdf-download.js +9 -76
  14. package/dist/collection/components/public-notification/public-notification.js +3 -3
  15. package/dist/collection/components/refine-selection/refine-selection.js +1 -1
  16. package/dist/collection/utils/csvUtils.js +4 -0
  17. package/dist/collection/utils/csvUtils.ts +7 -0
  18. package/dist/collection/utils/downloadUtils.js +181 -0
  19. package/dist/collection/utils/downloadUtils.ts +235 -0
  20. package/dist/collection/utils/interfaces.ts +3 -2
  21. package/dist/collection/utils/pdfUtils.js +7 -0
  22. package/dist/collection/utils/pdfUtils.ts +13 -2
  23. package/dist/components/downloadUtils.js +2279 -0
  24. package/dist/components/index.es.js +1 -1
  25. package/dist/components/layer-table.js +5 -16
  26. package/dist/components/map-layer-picker2.js +1 -1
  27. package/dist/components/map-search.js +1 -1
  28. package/dist/components/map-select-tools2.js +44 -40
  29. package/dist/components/pdf-download2.js +10 -2124
  30. package/dist/components/public-notification.js +3 -3
  31. package/dist/components/queryUtils.js +1 -1
  32. package/dist/components/refine-selection-tools2.js +1 -1
  33. package/dist/components/refine-selection2.js +1 -1
  34. package/dist/esm/buffer-tools_6.entry.js +1 -1
  35. package/dist/esm/calcite-combobox_3.entry.js +1 -1
  36. package/dist/esm/calcite-input-message_5.entry.js +1341 -13
  37. package/dist/esm/{calcite-input-message.calcite-notice.map-select-tools.pdf-download.refine-selection-c6f63458.js → downloadUtils-76e38a94.js} +206 -1381
  38. package/dist/esm/{index.es-54a6f3a3.js → index.es-489f4f08.js} +2 -12
  39. package/dist/esm/layer-table.entry.js +6 -16
  40. package/dist/esm/loader.js +1 -1
  41. package/dist/esm/{mapViewUtils-63e118f8.js → mapViewUtils-02696ab6.js} +1 -1
  42. package/dist/esm/public-notification.entry.js +3 -3
  43. package/dist/esm/solutions-components.js +1 -1
  44. package/dist/solutions-components/{p-cc2e20c8.js → p-1bfd07e3.js} +1 -1
  45. package/dist/solutions-components/{p-117174e8.entry.js → p-335fce8c.entry.js} +1 -1
  46. package/dist/solutions-components/p-4ef94c6b.entry.js +6 -0
  47. package/dist/solutions-components/p-5d27b47d.entry.js +17 -0
  48. package/dist/solutions-components/p-92cb569a.entry.js +6 -0
  49. package/dist/solutions-components/{p-8a0c0935.entry.js → p-a3b60bc9.entry.js} +1 -1
  50. package/dist/solutions-components/{p-1e459361.js → p-bff8aa4e.js} +3 -3
  51. package/dist/solutions-components/p-caa7e7a7.js +437 -0
  52. package/dist/solutions-components/solutions-components.esm.js +1 -1
  53. package/dist/solutions-components/utils/csvUtils.ts +7 -0
  54. package/dist/solutions-components/utils/downloadUtils.ts +235 -0
  55. package/dist/solutions-components/utils/interfaces.ts +3 -2
  56. package/dist/solutions-components/utils/pdfUtils.ts +13 -2
  57. package/dist/types/components/map-select-tools/map-select-tools.d.ts +11 -5
  58. package/dist/types/components/pdf-download/pdf-download.d.ts +0 -18
  59. package/dist/types/utils/downloadUtils.d.ts +40 -0
  60. package/dist/types/utils/interfaces.d.ts +2 -3
  61. package/dist/types/utils/pdfUtils.d.ts +3 -1
  62. package/package.json +1 -1
  63. package/dist/cjs/csvUtils-3a56c6d8.js +0 -54
  64. package/dist/components/csvUtils.js +0 -52
  65. package/dist/esm/csvUtils-23b5418f.js +0 -52
  66. package/dist/solutions-components/p-3069e3b7.js +0 -21
  67. package/dist/solutions-components/p-6d28f991.entry.js +0 -6
  68. package/dist/solutions-components/p-80f5e33c.js +0 -416
  69. package/dist/solutions-components/p-8927862a.entry.js +0 -6
  70. 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 pdfUtils from "../../assets/data/labelFormats.json";
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;
@@ -51,8 +49,8 @@ export class PdfDownload {
51
49
  * @returns Promise resolving when function is done
52
50
  */
53
51
  async downloadCSV(ids, removeDuplicates, addColumnTitle = true) {
54
- const labels = await this._prepareLabels(ids, removeDuplicates, addColumnTitle);
55
- return exportCSV(labels);
52
+ return downloadUtils.downloadCSV(this.layerView.layer, ids, true, // formatUsingLayerPopup
53
+ removeDuplicates, addColumnTitle);
56
54
  }
57
55
  /**
58
56
  * Downloads pdf of mailing labels for the provided list of ids
@@ -62,9 +60,7 @@ export class PdfDownload {
62
60
  * @returns Promise resolving when function is done
63
61
  */
64
62
  async downloadPDF(ids, removeDuplicates) {
65
- const labels = await this._prepareLabels(ids, removeDuplicates);
66
- const labelPageDescription = this._labelInfoElement.selectedOption.value;
67
- return exportPDF(labels, labelPageDescription);
63
+ return downloadUtils.downloadPDF(this.layerView.layer, ids, removeDuplicates, this._labelInfoElement.selectedOption.value);
68
64
  }
69
65
  //--------------------------------------------------------------------------
70
66
  //
@@ -107,31 +103,6 @@ export class PdfDownload {
107
103
  ]);
108
104
  this._intl = intl;
109
105
  }
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(/&lt;/gi, "<")
127
- .replace(/&gt;/gi, ">")
128
- .replace(/&nbsp;/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
106
  /**
136
107
  * Gets the formatted pdf export size text
137
108
  *
@@ -154,47 +125,6 @@ export class PdfDownload {
154
125
  const translations = await getLocaleComponentStrings(this.el);
155
126
  this._translations = translations[0];
156
127
  }
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
128
  /**
199
129
  * Renders the pdf export size options
200
130
  *
@@ -203,7 +133,7 @@ export class PdfDownload {
203
133
  * @protected
204
134
  */
205
135
  _renderItems() {
206
- const s = pdfUtils;
136
+ const s = pdfLabelFormats;
207
137
  const sortedPdfIndo = (s.default || s).sort((a, b) => {
208
138
  const _a = parseInt(a.descriptionPDF.labelsPerPageDisplay, 10);
209
139
  const _b = parseInt(b.descriptionPDF.labelsPerPageDisplay, 10);
@@ -338,6 +268,9 @@ export class PdfDownload {
338
268
  "references": {
339
269
  "Promise": {
340
270
  "location": "global"
271
+ },
272
+ "downloadUtils": {
273
+ "location": "global"
341
274
  }
342
275
  },
343
276
  "return": "Promise<void>"
@@ -316,7 +316,7 @@ export class PublicNotification {
316
316
  this._selectionWorkflowType === EWorkflowType.SKETCH ? sketchTip : searchTip;
317
317
  const nameLabelClass = this.customLabelEnabled ? "" : "display-none";
318
318
  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" }, "Name label", h("calcite-input", { onInput: () => {
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" }, "List name", h("calcite-input", { onInput: () => {
320
320
  this.labelChange.emit(this._labelName.value);
321
321
  }, 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
322
  }
@@ -358,7 +358,7 @@ export class PublicNotification {
358
358
  */
359
359
  _getDownloadPage(type) {
360
360
  const isPdf = type === EExportType.PDF;
361
- return (h("calcite-panel", null, h("div", null, h("div", { class: "padding-top-sides-1" }, h("calcite-label", { class: "font-bold" }, isPdf ? this._translations.pdfDownloads : this._translations.csvDownloads), 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)))));
361
+ 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), 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)))));
362
362
  }
363
363
  /**
364
364
  * Create the stacked navigation buttons for a page
@@ -897,7 +897,7 @@ export class PublicNotification {
897
897
  },
898
898
  "searchConfiguration": {
899
899
  "type": "unknown",
900
- "mutable": false,
900
+ "mutable": true,
901
901
  "complexType": {
902
902
  "original": "ISearchConfiguration",
903
903
  "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,181 @@
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 layer Layer providing features and attributes for download
33
+ * @param ids List of ids to download
34
+ * @param formatUsingLayerPopup When true, the layer's popup is used to choose attributes for each column; when false,
35
+ * all attributes are exported
36
+ * @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
37
+ * @param addColumnTitle Indicates if column headings should be included in output
38
+ * @returns Promise resolving when function is done
39
+ */
40
+ export async function downloadCSV(layer, ids, formatUsingLayerPopup, removeDuplicates = false, addColumnTitle = false) {
41
+ const labels = await _prepareLabels(layer, ids, removeDuplicates, formatUsingLayerPopup, addColumnTitle);
42
+ exportCSV(labels);
43
+ return Promise.resolve();
44
+ }
45
+ /**
46
+ * Downloads csv of mailing labels for the provided list of ids
47
+ *
48
+ * @param layer Layer providing features and attributes for download
49
+ * @param ids List of ids to download
50
+ * @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
51
+ * @param labelPageDescription Provides PDF page layout info
52
+ * @returns Promise resolving when function is done
53
+ */
54
+ export async function downloadPDF(layer, ids, removeDuplicates, labelPageDescription) {
55
+ const labels = await _prepareLabels(layer, ids, removeDuplicates);
56
+ exportPDF(labels, labelPageDescription);
57
+ return Promise.resolve();
58
+ }
59
+ //#endregion
60
+ //#region Private functions
61
+ /**
62
+ * Converts a set of fieldInfos into template lines.
63
+ *
64
+ * @param fieldInfos Layer's fieldInfos structure
65
+ * @return Label spec
66
+ */
67
+ function _convertPopupFieldsToLabelSpec(fieldInfos) {
68
+ const labelSpec = [];
69
+ // Every visible attribute is used
70
+ fieldInfos.forEach(fieldInfo => {
71
+ if (fieldInfo.visible) {
72
+ labelSpec.push(`{${fieldInfo.fieldName}}`);
73
+ }
74
+ });
75
+ return labelSpec;
76
+ }
77
+ ;
78
+ /**
79
+ * Converts the text of a custom popup into a multiline label specification; conversion splits text into
80
+ * lines on <br>s, and removes HTML tags. It does not handle Arcade and related records.
81
+ *
82
+ * @param popupInfo Layer's popupInfo structure containing description, fieldInfos, and expressionInfos, e.g.,
83
+ * "<div style='text-align: left;'>{NAME}<br />{STREET}<br />{CITY}, {STATE} {ZIP} <br /></div>"
84
+ * @return Label spec
85
+ */
86
+ function _convertPopupTextToLabelSpec(popupInfo) {
87
+ // Replace <br>, <br/> with |
88
+ popupInfo = popupInfo.replace(/<br\s*\/?>/gi, "|");
89
+ // Remove remaining HTML tags, replace 0xA0 that popup uses for spaces, replace some char representations,
90
+ // and split the label back into individual lines
91
+ let labelSpec = popupInfo
92
+ .replace(/<[\s.]*[^<>]*\/?>/gi, "")
93
+ .replace(/\xA0/gi, " ")
94
+ .replace(/&lt;/gi, "<")
95
+ .replace(/&gt;/gi, ">")
96
+ .replace(/&nbsp;/gi, " ")
97
+ .split("|");
98
+ // Trim lines and remove empties
99
+ labelSpec = labelSpec.map(line => line.trim()).filter(line => line.length > 0);
100
+ return labelSpec;
101
+ }
102
+ ;
103
+ /**
104
+ * Creates labels from items.
105
+ *
106
+ * @param layer Layer from which to fetch features
107
+ * @param ids List of ids to download
108
+ * @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
109
+ * @param formatUsingLayerPopup When true, the layer's popup is used to choose attributes for each column; when false,
110
+ * all attributes are exported
111
+ * @param includeHeaderNames Add the label format at the front of the list of generated labels
112
+ * @returns Promise resolving when function is done
113
+ */
114
+ async function _prepareLabels(layer, ids, removeDuplicates = true, formatUsingLayerPopup = true, includeHeaderNames = false) {
115
+ var _a, _b, _c, _d;
116
+ const [intl] = await loadModules([
117
+ "esri/intl"
118
+ ]);
119
+ // Get the attributes of the features to export
120
+ const featureSet = await queryFeaturesByID(ids, layer);
121
+ const featuresAttrs = featureSet.features.map(f => f.attributes);
122
+ // Get the label formatting, if any
123
+ let labelFormat;
124
+ if (layer.popupEnabled) {
125
+ // What data fields are used in the labels?
126
+ // Example labelFormat: ['{NAME}', '{STREET}', '{CITY}, {STATE} {ZIP}']
127
+ if (formatUsingLayerPopup && ((_b = (_a = layer.popupTemplate) === null || _a === void 0 ? void 0 : _a.content[0]) === null || _b === void 0 ? void 0 : _b.type) === "fields") {
128
+ labelFormat = _convertPopupFieldsToLabelSpec(layer.popupTemplate.fieldInfos);
129
+ }
130
+ 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") {
131
+ labelFormat = _convertPopupTextToLabelSpec(layer.popupTemplate.content[0].text);
132
+ }
133
+ }
134
+ // Apply the label format
135
+ let labels;
136
+ // eslint-disable-next-line unicorn/prefer-ternary
137
+ if (labelFormat) {
138
+ // Convert attributes into an array of labels
139
+ labels = featuresAttrs.map(featureAttributes => {
140
+ const label = [];
141
+ labelFormat.forEach(labelLineTemplate => {
142
+ const labelLine = intl.substitute(labelLineTemplate, featureAttributes).trim();
143
+ if (labelLine.length > 0) {
144
+ label.push(labelLine);
145
+ }
146
+ });
147
+ return label;
148
+ })
149
+ // Remove empty labels
150
+ .filter(label => label.length > 0);
151
+ }
152
+ else {
153
+ // Export all attributes
154
+ labels = featuresAttrs.map(featureAttributes => {
155
+ return Object.values(featureAttributes).map(attribute => `${attribute}`);
156
+ });
157
+ }
158
+ // Remove duplicates
159
+ if (removeDuplicates) {
160
+ const labelsAsStrings = labels.map(label => JSON.stringify(label));
161
+ const uniqueLabels = new Set(labelsAsStrings);
162
+ labels = Array.from(uniqueLabels, labelString => JSON.parse(labelString));
163
+ }
164
+ // Add header names
165
+ if (includeHeaderNames) {
166
+ let headerNames = [];
167
+ if (labelFormat) {
168
+ headerNames = labelFormat.map(labelFormatLine => labelFormatLine.replace(/\{/g, "").replace(/\}/g, ""));
169
+ }
170
+ else {
171
+ Object.keys(featuresAttrs[0]).forEach(k => {
172
+ if (featuresAttrs[0].hasOwnProperty(k)) {
173
+ headerNames.push(k);
174
+ }
175
+ });
176
+ }
177
+ labels.unshift(headerNames);
178
+ }
179
+ return Promise.resolve(labels);
180
+ }
181
+ //#endregion
@@ -0,0 +1,235 @@
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
+
17
+ //#region Declarations
18
+
19
+ import { exportCSV } from "./csvUtils";
20
+ import { ILabel, exportPDF } from "./pdfUtils";
21
+ import { loadModules } from "./loadModules";
22
+ import { queryFeaturesByID } from "./queryUtils";
23
+
24
+ export { ILabel } from "./pdfUtils";
25
+
26
+ //#endregion
27
+ //#region Public functions
28
+
29
+ /**
30
+ * Downloads csv of mailing labels for the provided list of ids
31
+ *
32
+ * @param layer Layer providing features and attributes for download
33
+ * @param ids List of ids to download
34
+ * @param formatUsingLayerPopup When true, the layer's popup is used to choose attributes for each column; when false,
35
+ * all attributes are exported
36
+ * @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
37
+ * @param addColumnTitle Indicates if column headings should be included in output
38
+ * @returns Promise resolving when function is done
39
+ */
40
+ export async function downloadCSV(
41
+ layer: __esri.FeatureLayer,
42
+ ids: number[],
43
+ formatUsingLayerPopup: boolean,
44
+ removeDuplicates = false,
45
+ addColumnTitle = false
46
+ ): Promise<void> {
47
+ const labels = await _prepareLabels(layer, ids, removeDuplicates, formatUsingLayerPopup, addColumnTitle);
48
+
49
+ exportCSV(labels);
50
+
51
+ return Promise.resolve();
52
+ }
53
+
54
+ /**
55
+ * Downloads csv of mailing labels for the provided list of ids
56
+ *
57
+ * @param layer Layer providing features and attributes for download
58
+ * @param ids List of ids to download
59
+ * @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
60
+ * @param labelPageDescription Provides PDF page layout info
61
+ * @returns Promise resolving when function is done
62
+ */
63
+ export async function downloadPDF(
64
+ layer: __esri.FeatureLayer,
65
+ ids: number[],
66
+ removeDuplicates: boolean,
67
+ labelPageDescription: ILabel
68
+ ): Promise<void> {
69
+ const labels = await _prepareLabels(layer, ids, removeDuplicates);
70
+
71
+ exportPDF(labels, labelPageDescription);
72
+
73
+ return Promise.resolve();
74
+ }
75
+
76
+ //#endregion
77
+ //#region Private functions
78
+
79
+ /**
80
+ * Converts a set of fieldInfos into template lines.
81
+ *
82
+ * @param fieldInfos Layer's fieldInfos structure
83
+ * @return Label spec
84
+ */
85
+ function _convertPopupFieldsToLabelSpec(
86
+ fieldInfos: __esri.FieldInfo[]
87
+ ): string[] {
88
+ const labelSpec: string[] = [];
89
+
90
+ // Every visible attribute is used
91
+ fieldInfos.forEach(
92
+ fieldInfo => {
93
+ if (fieldInfo.visible) {
94
+ labelSpec.push(`{${fieldInfo.fieldName}}`);
95
+ }
96
+ }
97
+ );
98
+
99
+ return labelSpec;
100
+ };
101
+
102
+ /**
103
+ * Converts the text of a custom popup into a multiline label specification; conversion splits text into
104
+ * lines on <br>s, and removes HTML tags. It does not handle Arcade and related records.
105
+ *
106
+ * @param popupInfo Layer's popupInfo structure containing description, fieldInfos, and expressionInfos, e.g.,
107
+ * "<div style='text-align: left;'>{NAME}<br />{STREET}<br />{CITY}, {STATE} {ZIP} <br /></div>"
108
+ * @return Label spec
109
+ */
110
+ function _convertPopupTextToLabelSpec(
111
+ popupInfo: string
112
+ ): string[] {
113
+ // Replace <br>, <br/> with |
114
+ popupInfo = popupInfo.replace(/<br\s*\/?>/gi, "|");
115
+
116
+ // Remove remaining HTML tags, replace 0xA0 that popup uses for spaces, replace some char representations,
117
+ // and split the label back into individual lines
118
+ let labelSpec = popupInfo
119
+ .replace(/<[\s.]*[^<>]*\/?>/gi, "")
120
+ .replace(/\xA0/gi, " ")
121
+ .replace(/&lt;/gi, "<")
122
+ .replace(/&gt;/gi, ">")
123
+ .replace(/&nbsp;/gi, " ")
124
+ .split("|");
125
+
126
+ // Trim lines and remove empties
127
+ labelSpec = labelSpec.map(line => line.trim()).filter(line => line.length > 0);
128
+
129
+ return labelSpec;
130
+ };
131
+
132
+ /**
133
+ * Creates labels from items.
134
+ *
135
+ * @param layer Layer from which to fetch features
136
+ * @param ids List of ids to download
137
+ * @param removeDuplicates When true a single label is generated when multiple featues have a shared address value
138
+ * @param formatUsingLayerPopup When true, the layer's popup is used to choose attributes for each column; when false,
139
+ * all attributes are exported
140
+ * @param includeHeaderNames Add the label format at the front of the list of generated labels
141
+ * @returns Promise resolving when function is done
142
+ */
143
+ async function _prepareLabels(
144
+ layer: __esri.FeatureLayer,
145
+ ids: number[],
146
+ removeDuplicates = true,
147
+ formatUsingLayerPopup = true,
148
+ includeHeaderNames = false
149
+ ): Promise<string[][]> {
150
+ const [intl] = await loadModules([
151
+ "esri/intl"
152
+ ]);
153
+
154
+ // Get the attributes of the features to export
155
+ const featureSet = await queryFeaturesByID(ids, layer);
156
+ const featuresAttrs = featureSet.features.map(f => f.attributes);
157
+
158
+ // Get the label formatting, if any
159
+ let labelFormat: string[];
160
+ if (layer.popupEnabled) {
161
+ // What data fields are used in the labels?
162
+ // Example labelFormat: ['{NAME}', '{STREET}', '{CITY}, {STATE} {ZIP}']
163
+ if (formatUsingLayerPopup && layer.popupTemplate?.content[0]?.type === "fields") {
164
+ labelFormat = _convertPopupFieldsToLabelSpec(layer.popupTemplate.fieldInfos);
165
+
166
+ } else if (formatUsingLayerPopup && layer.popupTemplate?.content[0]?.type === "text") {
167
+ labelFormat = _convertPopupTextToLabelSpec(layer.popupTemplate.content[0].text);
168
+
169
+ }
170
+ }
171
+
172
+ // Apply the label format
173
+ let labels: string[][];
174
+ // eslint-disable-next-line unicorn/prefer-ternary
175
+ if (labelFormat) {
176
+ // Convert attributes into an array of labels
177
+ labels = featuresAttrs.map(
178
+ featureAttributes => {
179
+ const label: string[] = [];
180
+ labelFormat.forEach(
181
+ labelLineTemplate => {
182
+ const labelLine = intl.substitute(labelLineTemplate, featureAttributes).trim();
183
+ if (labelLine.length > 0) {
184
+ label.push(labelLine);
185
+ }
186
+ }
187
+ )
188
+ return label;
189
+ }
190
+ )
191
+ // Remove empty labels
192
+ .filter(label => label.length > 0);
193
+
194
+ } else {
195
+ // Export all attributes
196
+ labels = featuresAttrs.map(
197
+ featureAttributes => {
198
+ return Object.values(featureAttributes).map(
199
+ attribute => `${attribute}`
200
+ );
201
+ }
202
+ );
203
+ }
204
+
205
+ // Remove duplicates
206
+ if (removeDuplicates) {
207
+ const labelsAsStrings: string[] = labels.map(label => JSON.stringify(label));
208
+ const uniqueLabels = new Set(labelsAsStrings);
209
+ labels = Array.from(uniqueLabels,
210
+ labelString => JSON.parse(labelString)
211
+ );
212
+ }
213
+
214
+ // Add header names
215
+ if (includeHeaderNames) {
216
+ let headerNames = [];
217
+
218
+ if (labelFormat) {
219
+ headerNames = labelFormat.map(labelFormatLine => labelFormatLine.replace(/\{/g, "").replace(/\}/g, ""));
220
+
221
+ } else {
222
+ Object.keys(featuresAttrs[0]).forEach(k => {
223
+ if (featuresAttrs[0].hasOwnProperty(k)) {
224
+ headerNames.push(k);
225
+ }
226
+ });
227
+ }
228
+
229
+ labels.unshift(headerNames);
230
+ }
231
+
232
+ return Promise.resolve(labels);
233
+ }
234
+
235
+ //#endregion
@@ -108,7 +108,7 @@ export interface ISearchConfiguration {
108
108
  sources: Array<ILocatorSourceConfigItem | ILayerSourceConfigItem>;
109
109
  }
110
110
 
111
- interface ISearchSourceConfigItem {
111
+ export interface ISearchSourceConfigItem {
112
112
  maxResults: number;
113
113
  maxSuggestions: number;
114
114
  minSuggestCharacters: number;
@@ -387,7 +387,8 @@ export interface ISelectionSet {
387
387
  refineIds: IRefineIds;
388
388
  redoStack?: IRefineOperation[];
389
389
  undoStack?: IRefineOperation[];
390
- skipGeomQuery?: boolean;
390
+ //skipGeomQuery?: boolean;
391
+ skipGeomOIDs?: number[];
391
392
  }
392
393
 
393
394
  export interface IRefineSelectionEvent {