@esri/solutions-components 0.7.18 → 0.7.19

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/cjs/calcite-alert_3.cjs.entry.js +93 -6
  2. package/dist/cjs/calcite-combobox_6.cjs.entry.js +1 -1
  3. package/dist/cjs/calcite-shell-panel_14.cjs.entry.js +1 -1
  4. package/dist/cjs/card-manager_3.cjs.entry.js +12 -5
  5. package/dist/cjs/crowdsource-manager.cjs.entry.js +4 -3
  6. package/dist/cjs/{downloadUtils-8f50633d.js → downloadUtils-9a13c6ac.js} +19 -14
  7. package/dist/cjs/{index.es-140aa937.js → index.es-284a020c.js} +2 -2
  8. package/dist/cjs/map-select-tools_3.cjs.entry.js +2 -2
  9. package/dist/cjs/{mapViewUtils-569e9644.js → mapViewUtils-8aa325de.js} +4 -1
  10. package/dist/cjs/public-notification.cjs.entry.js +2 -2
  11. package/dist/cjs/solution-contents_3.cjs.entry.js +4 -4
  12. package/dist/collection/components/crowdsource-manager/crowdsource-manager.css +4 -1
  13. package/dist/collection/components/crowdsource-manager/crowdsource-manager.js +3 -2
  14. package/dist/collection/components/edit-card/edit-card.js +1 -2
  15. package/dist/collection/components/info-card/info-card.js +3 -3
  16. package/dist/collection/components/layer-table/layer-table.css +4 -0
  17. package/dist/collection/components/layer-table/layer-table.js +9 -2
  18. package/dist/collection/components/solution-item-sharing/solution-item-sharing.js +1 -1
  19. package/dist/collection/components/solution-spatial-ref/solution-spatial-ref.js +4 -4
  20. package/dist/collection/utils/downloadUtils.js +17 -12
  21. package/dist/collection/utils/downloadUtils.ts +20 -12
  22. package/dist/collection/utils/interfaces.ts +5 -0
  23. package/dist/collection/utils/popupUtils.js +94 -0
  24. package/dist/collection/utils/popupUtils.ts +104 -0
  25. package/dist/collection/utils/queryUtils.js +4 -1
  26. package/dist/collection/utils/queryUtils.ts +5 -1
  27. package/dist/components/crowdsource-manager.js +4 -3
  28. package/dist/components/downloadUtils.js +17 -12
  29. package/dist/components/edit-card2.js +1 -2
  30. package/dist/components/info-card2.js +91 -3
  31. package/dist/components/layer-table2.js +10 -3
  32. package/dist/components/queryUtils.js +4 -1
  33. package/dist/components/solution-item-sharing2.js +1 -1
  34. package/dist/components/solution-spatial-ref2.js +4 -4
  35. package/dist/esm/calcite-alert_3.entry.js +93 -6
  36. package/dist/esm/calcite-combobox_6.entry.js +1 -1
  37. package/dist/esm/calcite-shell-panel_14.entry.js +1 -1
  38. package/dist/esm/card-manager_3.entry.js +12 -5
  39. package/dist/esm/crowdsource-manager.entry.js +4 -3
  40. package/dist/esm/{downloadUtils-9dee8bc0.js → downloadUtils-a4bbdb1d.js} +19 -14
  41. package/dist/esm/{index.es-54e86c8e.js → index.es-48fdb288.js} +2 -2
  42. package/dist/esm/map-select-tools_3.entry.js +2 -2
  43. package/dist/esm/{mapViewUtils-066602d5.js → mapViewUtils-8fe70944.js} +4 -1
  44. package/dist/esm/public-notification.entry.js +2 -2
  45. package/dist/esm/solution-contents_3.entry.js +4 -4
  46. package/dist/solutions-components/{p-d0c4572d.entry.js → p-1d56804c.entry.js} +18 -2
  47. package/dist/solutions-components/p-24b3ad7d.entry.js +6 -0
  48. package/dist/solutions-components/{p-6656c53e.entry.js → p-2abc02a1.entry.js} +1 -1
  49. package/dist/solutions-components/{p-825c045a.entry.js → p-2ddd9cf8.entry.js} +1 -1
  50. package/dist/solutions-components/{p-e8011829.entry.js → p-48a5ae32.entry.js} +1 -1
  51. package/dist/solutions-components/{p-dfdb8411.js → p-72dbfa77.js} +1 -1
  52. package/dist/solutions-components/{p-683cded6.entry.js → p-b1422b00.entry.js} +1 -1
  53. package/dist/solutions-components/p-b5d1b979.js +36 -0
  54. package/dist/solutions-components/{p-e405f393.entry.js → p-cf24ce53.entry.js} +1 -1
  55. package/dist/solutions-components/{p-1bdd64a0.js → p-d4afcf86.js} +4 -4
  56. package/dist/solutions-components/{p-f486c86d.entry.js → p-fdb1ace8.entry.js} +1 -1
  57. package/dist/solutions-components/solutions-components.css +1 -1
  58. package/dist/solutions-components/solutions-components.esm.js +1 -1
  59. package/dist/solutions-components/utils/downloadUtils.ts +20 -12
  60. package/dist/solutions-components/utils/interfaces.ts +5 -0
  61. package/dist/solutions-components/utils/popupUtils.ts +104 -0
  62. package/dist/solutions-components/utils/queryUtils.ts +5 -1
  63. package/dist/types/components/info-card/info-card.d.ts +5 -0
  64. package/dist/types/utils/downloadUtils.d.ts +3 -3
  65. package/dist/types/utils/interfaces.d.ts +4 -0
  66. package/dist/types/utils/popupUtils.d.ts +46 -0
  67. package/dist/types/utils/queryUtils.d.ts +1 -1
  68. package/package.json +1 -1
  69. package/dist/solutions-components/p-531d91d6.js +0 -36
  70. package/dist/solutions-components/p-8ca5d651.entry.js +0 -6
@@ -40,12 +40,12 @@ import { queryRelated } from "@esri/arcgis-rest-feature-layer";
40
40
  * @param includeHeaderNames Add the label format at the front of the list of generated labels
41
41
  * @returns selectionSetNames that will be used for export filenames
42
42
  */
43
- export async function consolidateLabels(webmap, exportInfos, formatUsingLayerPopup = true, includeHeaderNames = false, isCSVExport = false) {
43
+ export async function consolidateLabels(webmap, exportInfos, formatUsingLayerPopup = true, includeHeaderNames = false, isCSVExport = false, fields = []) {
44
44
  const labelRequests = [];
45
45
  Object.keys(exportInfos).forEach(k => {
46
46
  var _a;
47
47
  const labelInfo = exportInfos[k];
48
- labelRequests.push(_prepareLabels(webmap, ((_a = labelInfo.layerView) === null || _a === void 0 ? void 0 : _a.layer) || labelInfo.layer, labelInfo.ids, formatUsingLayerPopup, includeHeaderNames));
48
+ labelRequests.push(_prepareLabels(webmap, ((_a = labelInfo.layerView) === null || _a === void 0 ? void 0 : _a.layer) || labelInfo.layer, labelInfo.ids, formatUsingLayerPopup, includeHeaderNames, fields));
49
49
  if (isCSVExport) {
50
50
  // add the layer id as a temp value separator that we can use to split values for CSV export
51
51
  labelRequests.push(Promise.resolve([[k]]));
@@ -65,8 +65,8 @@ export async function consolidateLabels(webmap, exportInfos, formatUsingLayerPop
65
65
  * @param addColumnTitle Indicates if column headings should be included in output
66
66
  * @returns Promise resolving when function is done
67
67
  */
68
- export async function downloadCSV(webmap, exportInfos, formatUsingLayerPopup, removeDuplicates = false, addColumnTitle = false) {
69
- let labels = await consolidateLabels(webmap, exportInfos, formatUsingLayerPopup, addColumnTitle, true);
68
+ export async function downloadCSV(webmap, exportInfos, formatUsingLayerPopup, removeDuplicates = false, addColumnTitle = false, fields = []) {
69
+ let labels = await consolidateLabels(webmap, exportInfos, formatUsingLayerPopup, addColumnTitle, true, fields);
70
70
  labels = removeDuplicates ? removeDuplicateLabels(labels) : labels;
71
71
  const layerIds = Object.keys(exportInfos);
72
72
  let layerLabels = [];
@@ -605,7 +605,7 @@ export function _prepareAttributeValue(attributeValue, attributeType, attributeD
605
605
  * @param includeHeaderNames Add the label format at the front of the list of generated labels
606
606
  * @returns Promise resolving when function is done
607
607
  */
608
- export async function _prepareLabels(webmap, layer, ids, formatUsingLayerPopup = true, includeHeaderNames = false) {
608
+ export async function _prepareLabels(webmap, layer, ids, formatUsingLayerPopup = true, includeHeaderNames = false, fields = []) {
609
609
  // Get the label formatting, if any
610
610
  const labelFormatProps = await _getLabelFormat(webmap, layer, formatUsingLayerPopup);
611
611
  // Because the label may actually come from a related layer, we'll use the layer that comes back from _getLabelFormat.
@@ -664,7 +664,8 @@ export async function _prepareLabels(webmap, layer, ids, formatUsingLayerPopup =
664
664
  }
665
665
  else {
666
666
  // Get the features to export
667
- featureSet = await queryFeaturesByID(ids, featureLayer, [], false);
667
+ const outFields = fields.length > 0 ? fields : undefined;
668
+ featureSet = await queryFeaturesByID(ids, featureLayer, [], false, undefined, outFields);
668
669
  }
669
670
  // Get field data types. Do we have any domain-based fields?
670
671
  const attributeOrigNames = {};
@@ -672,17 +673,21 @@ export async function _prepareLabels(webmap, layer, ids, formatUsingLayerPopup =
672
673
  const attributeDomains = {};
673
674
  if (featureLayer.fields) {
674
675
  featureLayer.fields.forEach(field => {
675
- const lowercaseFieldname = field.name.toLowerCase();
676
- attributeOrigNames[lowercaseFieldname] = field.name;
677
- attributeDomains[lowercaseFieldname] = field.domain;
678
- attributeTypes[lowercaseFieldname] = field.type;
676
+ if (fields.indexOf(field.name.toLowerCase()) > -1) {
677
+ const lowercaseFieldname = field.name.toLowerCase();
678
+ attributeOrigNames[lowercaseFieldname] = field.name;
679
+ attributeDomains[lowercaseFieldname] = field.domain;
680
+ attributeTypes[lowercaseFieldname] = field.type;
681
+ }
679
682
  });
680
683
  }
681
684
  else {
682
685
  // Feature layer is missing fields, so get info from first feature
683
686
  Object.keys(featureSet[0]).forEach(fieldName => {
684
- const lowercaseFieldname = fieldName.toLowerCase();
685
- attributeOrigNames[lowercaseFieldname] = fieldName;
687
+ if (fields.indexOf(fieldName.toLowerCase()) > -1) {
688
+ const lowercaseFieldname = fieldName.toLowerCase();
689
+ attributeOrigNames[lowercaseFieldname] = fieldName;
690
+ }
686
691
  });
687
692
  }
688
693
  // Apply the label format
@@ -125,14 +125,15 @@ export async function consolidateLabels(
125
125
  exportInfos: IExportInfos,
126
126
  formatUsingLayerPopup = true,
127
127
  includeHeaderNames = false,
128
- isCSVExport = false
128
+ isCSVExport = false,
129
+ fields = []
129
130
  ): Promise<string[][]> {
130
131
  const labelRequests = [];
131
132
 
132
133
  Object.keys(exportInfos).forEach(k => {
133
134
  const labelInfo: IExportInfo = exportInfos[k];
134
135
  labelRequests.push(
135
- _prepareLabels(webmap, labelInfo.layerView?.layer || labelInfo.layer, labelInfo.ids, formatUsingLayerPopup, includeHeaderNames)
136
+ _prepareLabels(webmap, labelInfo.layerView?.layer || labelInfo.layer, labelInfo.ids, formatUsingLayerPopup, includeHeaderNames, fields)
136
137
  );
137
138
  if (isCSVExport) {
138
139
  // add the layer id as a temp value separator that we can use to split values for CSV export
@@ -160,9 +161,10 @@ export async function downloadCSV(
160
161
  exportInfos: IExportInfos,
161
162
  formatUsingLayerPopup: boolean,
162
163
  removeDuplicates = false,
163
- addColumnTitle = false
164
+ addColumnTitle = false,
165
+ fields = []
164
166
  ): Promise<void> {
165
- let labels = await consolidateLabels(webmap, exportInfos, formatUsingLayerPopup, addColumnTitle, true);
167
+ let labels = await consolidateLabels(webmap, exportInfos, formatUsingLayerPopup, addColumnTitle, true, fields);
166
168
  labels = removeDuplicates ? removeDuplicateLabels(labels) : labels;
167
169
 
168
170
  const layerIds = Object.keys(exportInfos);
@@ -838,7 +840,8 @@ export async function _prepareLabels(
838
840
  layer: __esri.FeatureLayer,
839
841
  ids: number[],
840
842
  formatUsingLayerPopup = true,
841
- includeHeaderNames = false
843
+ includeHeaderNames = false,
844
+ fields = []
842
845
  ): Promise<string[][]> {
843
846
  // Get the label formatting, if any
844
847
  const labelFormatProps: ILabelFormatProps = await _getLabelFormat(webmap, layer, formatUsingLayerPopup);
@@ -909,7 +912,8 @@ export async function _prepareLabels(
909
912
 
910
913
  } else {
911
914
  // Get the features to export
912
- featureSet = await queryFeaturesByID(ids, featureLayer, [], false);
915
+ const outFields = fields.length > 0 ? fields : undefined;
916
+ featureSet = await queryFeaturesByID(ids, featureLayer, [], false, undefined, outFields);
913
917
  }
914
918
 
915
919
  // Get field data types. Do we have any domain-based fields?
@@ -920,18 +924,22 @@ export async function _prepareLabels(
920
924
  if (featureLayer.fields) {
921
925
  featureLayer.fields.forEach(
922
926
  field => {
923
- const lowercaseFieldname = field.name.toLowerCase();
924
- attributeOrigNames[lowercaseFieldname] = field.name;
925
- attributeDomains[lowercaseFieldname] = field.domain;
926
- attributeTypes[lowercaseFieldname] = field.type;
927
+ if (fields.indexOf(field.name.toLowerCase()) > -1) {
928
+ const lowercaseFieldname = field.name.toLowerCase();
929
+ attributeOrigNames[lowercaseFieldname] = field.name;
930
+ attributeDomains[lowercaseFieldname] = field.domain;
931
+ attributeTypes[lowercaseFieldname] = field.type;
932
+ }
927
933
  }
928
934
  );
929
935
  } else {
930
936
  // Feature layer is missing fields, so get info from first feature
931
937
  Object.keys(featureSet[0]).forEach(
932
938
  fieldName => {
933
- const lowercaseFieldname = fieldName.toLowerCase();
934
- attributeOrigNames[lowercaseFieldname] = fieldName;
939
+ if (fields.indexOf(fieldName.toLowerCase()) > -1) {
940
+ const lowercaseFieldname = fieldName.toLowerCase();
941
+ attributeOrigNames[lowercaseFieldname] = fieldName;
942
+ }
935
943
  }
936
944
  )
937
945
  }
@@ -539,3 +539,8 @@ export interface ILayerAndTableIds {
539
539
  layerIds: string[];
540
540
  tableIds: string[];
541
541
  }
542
+
543
+ export interface IPopupUtils {
544
+ arcade: typeof import("esri/arcade");
545
+ getPopupTitle(graphic: __esri.Graphic): Promise<string>;
546
+ }
@@ -0,0 +1,94 @@
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
+ import { loadModules } from "./loadModules";
22
+ export class PopupUtils {
23
+ /**
24
+ * Get the popup title that honors arcade expressions
25
+ *
26
+ * @returns Promise resolving with the popup title
27
+ *
28
+ * @protected
29
+ */
30
+ async getPopupTitle(graphic) {
31
+ var _a, _b, _c;
32
+ if (!this.arcade) {
33
+ await this._initModules();
34
+ }
35
+ let attributes = {};
36
+ for (const [key, value] of Object.entries(graphic.attributes)) {
37
+ attributes = Object.assign(Object.assign({}, attributes), { [`{${key.toUpperCase()}}`]: value });
38
+ }
39
+ const layer = graphic.layer;
40
+ const popupTitle = this._removeTags((_a = layer === null || layer === void 0 ? void 0 : layer.popupTemplate) === null || _a === void 0 ? void 0 : _a.title);
41
+ if (popupTitle.includes("{expression/expr") && ((_b = layer === null || layer === void 0 ? void 0 : layer.popupTemplate) === null || _b === void 0 ? void 0 : _b.expressionInfos) != null) {
42
+ for (let i = 0; i < ((_c = layer.popupTemplate) === null || _c === void 0 ? void 0 : _c.expressionInfos.length); i++) {
43
+ const info = layer.popupTemplate.expressionInfos[i];
44
+ const profile = {
45
+ variables: [
46
+ {
47
+ name: "$feature",
48
+ type: "feature"
49
+ }
50
+ ]
51
+ };
52
+ try {
53
+ const arcadeExecutor = await this.arcade.createArcadeExecutor(info.expression, profile);
54
+ const arcadeTitle = arcadeExecutor.execute({ $feature: graphic });
55
+ if (arcadeTitle != null || arcadeTitle !== "") {
56
+ attributes[`{expression/${info.name}}`.toUpperCase()] = arcadeTitle;
57
+ }
58
+ }
59
+ catch (_d) {
60
+ continue;
61
+ }
62
+ }
63
+ }
64
+ return popupTitle === null || popupTitle === void 0 ? void 0 : popupTitle.replace(/{.*?}/g, (placeholder) => {
65
+ return attributes[placeholder.toUpperCase()] != null ? attributes[placeholder.toUpperCase()] : "";
66
+ });
67
+ }
68
+ /**
69
+ * Remove any tags from the title
70
+ *
71
+ * @returns title string without tags
72
+ *
73
+ * @protected
74
+ */
75
+ _removeTags(str) {
76
+ if (str == null || str === "") {
77
+ return "";
78
+ }
79
+ return str.toString().replace(/(<([^>]+)>)/gi, "");
80
+ }
81
+ /**
82
+ * Load esri javascript api modules
83
+ *
84
+ * @returns Promise resolving when function is done
85
+ *
86
+ * @protected
87
+ */
88
+ async _initModules() {
89
+ const [arcade] = await loadModules([
90
+ "esri/arcade"
91
+ ]);
92
+ this.arcade = arcade;
93
+ }
94
+ }
@@ -0,0 +1,104 @@
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
+ import { loadModules } from "./loadModules";
18
+
19
+ export class PopupUtils {
20
+
21
+ /**
22
+ * esri/arcade: https://developers.arcgis.com/javascript/latest/api-reference/esri-arcade.html
23
+ */
24
+ arcade: typeof import("esri/arcade");
25
+
26
+ /**
27
+ * Get the popup title that honors arcade expressions
28
+ *
29
+ * @returns Promise resolving with the popup title
30
+ *
31
+ * @protected
32
+ */
33
+ public async getPopupTitle(
34
+ graphic: __esri.Graphic
35
+ ): Promise<string> {
36
+ if (!this.arcade) {
37
+ await this._initModules()
38
+ }
39
+ let attributes = {};
40
+ for (const [key, value] of Object.entries(graphic.attributes)) {
41
+ attributes = {
42
+ ...attributes,
43
+ [`{${key.toUpperCase()}}`]: value
44
+ };
45
+ }
46
+ const layer = graphic.layer as __esri.FeatureLayer;
47
+ const popupTitle = this._removeTags(layer?.popupTemplate?.title as string);
48
+ if (popupTitle.includes("{expression/expr") && layer?.popupTemplate?.expressionInfos != null) {
49
+ for (let i = 0; i < layer.popupTemplate?.expressionInfos.length; i++) {
50
+ const info = layer.popupTemplate.expressionInfos[i];
51
+ const profile = {
52
+ variables: [
53
+ {
54
+ name: "$feature",
55
+ type: "feature"
56
+ }
57
+ ]
58
+ } as __esri.Profile;
59
+ try {
60
+ const arcadeExecutor = await this.arcade.createArcadeExecutor(info.expression, profile);
61
+ const arcadeTitle = arcadeExecutor.execute({ $feature: graphic });
62
+ if (arcadeTitle != null || arcadeTitle !== "") {
63
+ attributes[`{expression/${info.name}}`.toUpperCase()] = arcadeTitle;
64
+ }
65
+ } catch {
66
+ continue;
67
+ }
68
+ }
69
+ }
70
+
71
+ return popupTitle?.replace(/{.*?}/g, (placeholder: string) => {
72
+ return attributes[placeholder.toUpperCase()] != null ? (attributes[placeholder.toUpperCase()] as string) : "";
73
+ });
74
+ }
75
+
76
+ /**
77
+ * Remove any tags from the title
78
+ *
79
+ * @returns title string without tags
80
+ *
81
+ * @protected
82
+ */
83
+ protected _removeTags(str: string): string {
84
+ if (str == null || str === "") {
85
+ return "";
86
+ }
87
+ return str.toString().replace(/(<([^>]+)>)/gi, "");
88
+ }
89
+
90
+ /**
91
+ * Load esri javascript api modules
92
+ *
93
+ * @returns Promise resolving when function is done
94
+ *
95
+ * @protected
96
+ */
97
+ protected async _initModules(): Promise<void> {
98
+ const [arcade] = await loadModules([
99
+ "esri/arcade"
100
+ ]);
101
+ this.arcade = arcade;
102
+ }
103
+
104
+ }
@@ -102,7 +102,7 @@ export async function queryObjectIds(geometries, layer) {
102
102
  *
103
103
  * @returns Promise with the featureSet from the layer that match the provided ids
104
104
  */
105
- export async function queryFeaturesByID(ids, layer, graphics, returnGeometry, outSpatialReference) {
105
+ export async function queryFeaturesByID(ids, layer, graphics, returnGeometry, outSpatialReference, fields) {
106
106
  var _a;
107
107
  const num = (_a = layer.capabilities) === null || _a === void 0 ? void 0 : _a.query.maxRecordCount;
108
108
  const start = 0;
@@ -116,6 +116,9 @@ export async function queryFeaturesByID(ids, layer, graphics, returnGeometry, ou
116
116
  if (outSpatialReference) {
117
117
  q.outSpatialReference = outSpatialReference;
118
118
  }
119
+ if (fields) {
120
+ q.outFields = fields;
121
+ }
119
122
  const result = await layer.queryFeatures(q);
120
123
  graphics = graphics.concat(result.features);
121
124
  const remainingIds = ids.slice(num, ids.length);
@@ -126,7 +126,8 @@ export async function queryFeaturesByID(
126
126
  layer: __esri.FeatureLayer,
127
127
  graphics: __esri.Graphic[],
128
128
  returnGeometry: boolean,
129
- outSpatialReference?: __esri.SpatialReference
129
+ outSpatialReference?: __esri.SpatialReference,
130
+ fields?: string[]
130
131
  ): Promise<__esri.Graphic[]> {
131
132
  const num = layer.capabilities?.query.maxRecordCount;
132
133
  const start = 0;
@@ -141,6 +142,9 @@ export async function queryFeaturesByID(
141
142
  if (outSpatialReference) {
142
143
  q.outSpatialReference = outSpatialReference;
143
144
  }
145
+ if (fields) {
146
+ q.outFields = fields;
147
+ }
144
148
 
145
149
  const result = await layer.queryFeatures(q);
146
150
 
@@ -63,7 +63,7 @@ import { d as defineCustomElement$4 } from './map-picker2.js';
63
63
  import { d as defineCustomElement$3 } from './map-search2.js';
64
64
  import { d as defineCustomElement$2 } from './map-tools2.js';
65
65
 
66
- const crowdsourceManagerCss = ":host{display:block;--calcite-label-margin-bottom:0px;--solutions-theme-foreground-color:var(--calcite-color-foreground-1)}.padding-1-2{padding:0.5rem}.display-flex{display:flex}.width-full{width:100%}.width-1-2{position:relative;width:50%}.width-1-3{position:relative;width:33.33%}.width-2-3{position:relative;width:66.66%}.width-0{width:0}.height-full{height:100%}.height-1-2{position:relative;height:50%}.height-0{height:0}.toggle-node{width:51px;height:51px}.overflow-hidden{overflow:hidden}.flex-column{flex-direction:column}.border{border:1px solid var(--calcite-color-border-3)}.border-bottom{border-bottom:1px solid var(--calcite-color-border-3)}.border-sides{border-left:1px solid var(--calcite-color-border-3);border-right:1px solid var(--calcite-color-border-3)}.position-relative{position:relative}.height-50{height:50%}.adjusted-height-50{height:calc(50% - 25px)}.adjusted-height-100{height:calc(100% - 50px)}.adjusted-height-100-50{height:calc(100% - 50px)}.display-none{display:none}.height-53{height:53px}.position-absolute-53{position:absolute;top:53px}.display-grid{display:grid}.height-50-px{height:50px}.padding-inline-start-75{padding-inline-start:0.75rem}.align-items-center{align-items:center}.esri-floor-filter__close-levels-button{width:40px !important;height:40px !important}.esri-floor-filter__level-button{width:40px !important;height:40px !important}.esri-floor-filter__browse-button{width:40px !important;height:40px !important}.position-absolute-50{position:absolute;top:50px;bottom:0px;left:0px;right:0px}.position-absolute-0{position:absolute;top:0px;bottom:0px;left:0px;right:0px}.visibility-hidden{visibility:hidden;height:0px}";
66
+ const crowdsourceManagerCss = ":host{display:block;--calcite-label-margin-bottom:0px;--solutions-theme-foreground-color:var(--calcite-color-foreground-1)}.padding-1-2{padding:0.5rem}.display-flex{display:flex}.width-full{width:100%}.width-1-2{position:relative;width:50%}.width-1-3{position:relative;width:33.33%}.width-2-3{position:relative;width:66.66%}.width-0{width:0}.height-full{height:100%}.height-1-2{position:relative;height:50%}.height-0{height:0}.toggle-node{width:51px;height:51px}.overflow-hidden{overflow:hidden}.flex-column{flex-direction:column}.border{border:1px solid var(--calcite-color-border-3)}.border-bottom{border-bottom:1px solid var(--calcite-color-border-3)}.border-sides{border-left:1px solid var(--calcite-color-border-3);border-right:1px solid var(--calcite-color-border-3)}.position-relative{position:relative}.height-50{height:50%}.adjusted-height-50{height:calc(50% - 25px)}.adjusted-height-100{height:calc(100% - 50px)}.adjusted-height-100-50{height:calc(100% - 50px)}.display-none{display:none}.height-53{height:53px}.position-absolute-53{position:absolute;top:53px}.display-grid{display:grid}.height-50-px{height:50px}.padding-inline-start-75{padding-inline-start:0.75rem}.align-items-center{align-items:center}.esri-floor-filter__close-levels-button{width:40px !important;height:40px !important}.esri-floor-filter__level-button{width:40px !important;height:40px !important}.esri-floor-filter__browse-button{width:40px !important;height:40px !important}.position-absolute-50{position:absolute;top:50px;bottom:0px;left:0px;right:0px}.position-absolute-0{position:absolute;top:0px;bottom:0px;left:0px;right:0px}.visibility-hidden{visibility:hidden;height:0px}.position-fixed{position:fixed}";
67
67
 
68
68
  const CrowdsourceManager$1 = /*@__PURE__*/ proxyCustomElement(class CrowdsourceManager extends HTMLElement {
69
69
  constructor() {
@@ -313,7 +313,7 @@ const CrowdsourceManager$1 = /*@__PURE__*/ proxyCustomElement(class CrowdsourceM
313
313
  let sizeClass = "";
314
314
  switch (layoutMode) {
315
315
  case ELayoutMode.HORIZONTAL:
316
- sizeClass = `${this._isMobile && this._hideTable ? "height-full" : panelOpen ? "height-1-2" : "height-0"} width-full position-relative`;
316
+ sizeClass = `${this._isMobile && this.hideMap ? "height-0 " : panelOpen ? "height-1-2 display-grid" : "height-0"} width-full position-relative`;
317
317
  break;
318
318
  case ELayoutMode.GRID:
319
319
  sizeClass = this.classicGrid ? `${panelOpen ? "position-relative" : "position-absolute-53"} height-full width-full display-flex` :
@@ -413,7 +413,8 @@ const CrowdsourceManager$1 = /*@__PURE__*/ proxyCustomElement(class CrowdsourceM
413
413
  const popupNodeClass = !this._expandPopup ? "height-full" : ((_a = this.mapInfos) === null || _a === void 0 ? void 0 : _a.length) === 1 || this._isMobile ? "position-absolute-0" : "position-absolute-50";
414
414
  const headerClass = this._isMobile ? "display-none height-0" : "";
415
415
  const headerTheme = !this._isMobile ? "calcite-mode-dark" : "calcite-mode-light";
416
- return (h("div", { class: `${headerTheme} ${popupNodeClass}` }, h("calcite-panel", null, !this._isMobile ? (h("div", { class: `display-flex align-items-center ${headerClass}`, slot: "header-content" }, h("calcite-icon", { icon: "information", scale: "s" }), h("div", { class: "padding-inline-start-75" }, this._translations.information))) : undefined, h("calcite-action", { class: headerClass, disabled: this._tableOnly, icon: icon, id: id, onClick: () => this._togglePopup(), slot: "header-actions-end", text: "" }), !this._tableOnly ? h("calcite-tooltip", { class: themeClass, label: "", placement: "bottom", "reference-element": id }, h("span", null, tooltip)) : undefined, this._getCardNode())));
416
+ const containerClass = this._isMobile && this._hideTable && this.hideMap ? "position-fixed width-full height-full" : this._isMobile ? "display-none height-0" : "";
417
+ return (h("div", { class: `${headerTheme} ${popupNodeClass} ${containerClass}` }, h("calcite-panel", null, !this._isMobile ? (h("div", { class: `display-flex align-items-center ${headerClass}`, slot: "header-content" }, h("calcite-icon", { icon: "information", scale: "s" }), h("div", { class: "padding-inline-start-75" }, this._translations.information))) : undefined, h("calcite-action", { class: headerClass, disabled: this._tableOnly, icon: icon, id: id, onClick: () => this._togglePopup(), slot: "header-actions-end", text: "" }), !this._tableOnly ? h("calcite-tooltip", { class: themeClass, label: "", placement: "bottom", "reference-element": id }, h("span", null, tooltip)) : undefined, this._getCardNode())));
417
418
  }
418
419
  /**
419
420
  * Toggle the popup information
@@ -2360,12 +2360,12 @@ const lineSeparatorChar = "|";
2360
2360
  * @param includeHeaderNames Add the label format at the front of the list of generated labels
2361
2361
  * @returns selectionSetNames that will be used for export filenames
2362
2362
  */
2363
- async function consolidateLabels(webmap, exportInfos, formatUsingLayerPopup = true, includeHeaderNames = false, isCSVExport = false) {
2363
+ async function consolidateLabels(webmap, exportInfos, formatUsingLayerPopup = true, includeHeaderNames = false, isCSVExport = false, fields = []) {
2364
2364
  const labelRequests = [];
2365
2365
  Object.keys(exportInfos).forEach(k => {
2366
2366
  var _a;
2367
2367
  const labelInfo = exportInfos[k];
2368
- labelRequests.push(_prepareLabels(webmap, ((_a = labelInfo.layerView) === null || _a === void 0 ? void 0 : _a.layer) || labelInfo.layer, labelInfo.ids, formatUsingLayerPopup, includeHeaderNames));
2368
+ labelRequests.push(_prepareLabels(webmap, ((_a = labelInfo.layerView) === null || _a === void 0 ? void 0 : _a.layer) || labelInfo.layer, labelInfo.ids, formatUsingLayerPopup, includeHeaderNames, fields));
2369
2369
  if (isCSVExport) {
2370
2370
  // add the layer id as a temp value separator that we can use to split values for CSV export
2371
2371
  labelRequests.push(Promise.resolve([[k]]));
@@ -2385,8 +2385,8 @@ async function consolidateLabels(webmap, exportInfos, formatUsingLayerPopup = tr
2385
2385
  * @param addColumnTitle Indicates if column headings should be included in output
2386
2386
  * @returns Promise resolving when function is done
2387
2387
  */
2388
- async function downloadCSV(webmap, exportInfos, formatUsingLayerPopup, removeDuplicates = false, addColumnTitle = false) {
2389
- let labels = await consolidateLabels(webmap, exportInfos, formatUsingLayerPopup, addColumnTitle, true);
2388
+ async function downloadCSV(webmap, exportInfos, formatUsingLayerPopup, removeDuplicates = false, addColumnTitle = false, fields = []) {
2389
+ let labels = await consolidateLabels(webmap, exportInfos, formatUsingLayerPopup, addColumnTitle, true, fields);
2390
2390
  labels = removeDuplicates ? removeDuplicateLabels(labels) : labels;
2391
2391
  const layerIds = Object.keys(exportInfos);
2392
2392
  let layerLabels = [];
@@ -2922,7 +2922,7 @@ function _prepareAttributeValue(attributeValue, attributeType, attributeDomain,
2922
2922
  * @param includeHeaderNames Add the label format at the front of the list of generated labels
2923
2923
  * @returns Promise resolving when function is done
2924
2924
  */
2925
- async function _prepareLabels(webmap, layer, ids, formatUsingLayerPopup = true, includeHeaderNames = false) {
2925
+ async function _prepareLabels(webmap, layer, ids, formatUsingLayerPopup = true, includeHeaderNames = false, fields = []) {
2926
2926
  // Get the label formatting, if any
2927
2927
  const labelFormatProps = await _getLabelFormat(webmap, layer, formatUsingLayerPopup);
2928
2928
  // Because the label may actually come from a related layer, we'll use the layer that comes back from _getLabelFormat.
@@ -2981,7 +2981,8 @@ async function _prepareLabels(webmap, layer, ids, formatUsingLayerPopup = true,
2981
2981
  }
2982
2982
  else {
2983
2983
  // Get the features to export
2984
- featureSet = await queryFeaturesByID(ids, featureLayer, [], false);
2984
+ const outFields = fields.length > 0 ? fields : undefined;
2985
+ featureSet = await queryFeaturesByID(ids, featureLayer, [], false, undefined, outFields);
2985
2986
  }
2986
2987
  // Get field data types. Do we have any domain-based fields?
2987
2988
  const attributeOrigNames = {};
@@ -2989,17 +2990,21 @@ async function _prepareLabels(webmap, layer, ids, formatUsingLayerPopup = true,
2989
2990
  const attributeDomains = {};
2990
2991
  if (featureLayer.fields) {
2991
2992
  featureLayer.fields.forEach(field => {
2992
- const lowercaseFieldname = field.name.toLowerCase();
2993
- attributeOrigNames[lowercaseFieldname] = field.name;
2994
- attributeDomains[lowercaseFieldname] = field.domain;
2995
- attributeTypes[lowercaseFieldname] = field.type;
2993
+ if (fields.indexOf(field.name.toLowerCase()) > -1) {
2994
+ const lowercaseFieldname = field.name.toLowerCase();
2995
+ attributeOrigNames[lowercaseFieldname] = field.name;
2996
+ attributeDomains[lowercaseFieldname] = field.domain;
2997
+ attributeTypes[lowercaseFieldname] = field.type;
2998
+ }
2996
2999
  });
2997
3000
  }
2998
3001
  else {
2999
3002
  // Feature layer is missing fields, so get info from first feature
3000
3003
  Object.keys(featureSet[0]).forEach(fieldName => {
3001
- const lowercaseFieldname = fieldName.toLowerCase();
3002
- attributeOrigNames[lowercaseFieldname] = fieldName;
3004
+ if (fields.indexOf(fieldName.toLowerCase()) > -1) {
3005
+ const lowercaseFieldname = fieldName.toLowerCase();
3006
+ attributeOrigNames[lowercaseFieldname] = fieldName;
3007
+ }
3003
3008
  });
3004
3009
  }
3005
3010
  // Apply the label format
@@ -146,8 +146,7 @@ const EditCard = /*@__PURE__*/ proxyCustomElement(class EditCard extends HTMLEle
146
146
  view: this.mapView,
147
147
  layerInfos,
148
148
  visibleElements: {
149
- snappingControls: false,
150
- sketchTooltipControls: false
149
+ snappingControls: false
151
150
  },
152
151
  container
153
152
  });
@@ -21,6 +21,95 @@ import { d as defineCustomElement$3 } from './shell.js';
21
21
  import { d as defineCustomElement$2 } from './tooltip.js';
22
22
  import { d as defineCustomElement$1 } from './edit-card2.js';
23
23
 
24
+ /** @license
25
+ * Copyright 2022 Esri
26
+ *
27
+ * Licensed under the Apache License, Version 2.0 (the "License");
28
+ * you may not use this file except in compliance with the License.
29
+ * You may obtain a copy of the License at
30
+ *
31
+ * http://www.apache.org/licenses/LICENSE-2.0
32
+ *
33
+ * Unless required by applicable law or agreed to in writing, software
34
+ * distributed under the License is distributed on an "AS IS" BASIS,
35
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
36
+ * See the License for the specific language governing permissions and
37
+ * limitations under the License.
38
+ */
39
+ class PopupUtils {
40
+ /**
41
+ * Get the popup title that honors arcade expressions
42
+ *
43
+ * @returns Promise resolving with the popup title
44
+ *
45
+ * @protected
46
+ */
47
+ async getPopupTitle(graphic) {
48
+ var _a, _b, _c;
49
+ if (!this.arcade) {
50
+ await this._initModules();
51
+ }
52
+ let attributes = {};
53
+ for (const [key, value] of Object.entries(graphic.attributes)) {
54
+ attributes = Object.assign(Object.assign({}, attributes), { [`{${key.toUpperCase()}}`]: value });
55
+ }
56
+ const layer = graphic.layer;
57
+ const popupTitle = this._removeTags((_a = layer === null || layer === void 0 ? void 0 : layer.popupTemplate) === null || _a === void 0 ? void 0 : _a.title);
58
+ if (popupTitle.includes("{expression/expr") && ((_b = layer === null || layer === void 0 ? void 0 : layer.popupTemplate) === null || _b === void 0 ? void 0 : _b.expressionInfos) != null) {
59
+ for (let i = 0; i < ((_c = layer.popupTemplate) === null || _c === void 0 ? void 0 : _c.expressionInfos.length); i++) {
60
+ const info = layer.popupTemplate.expressionInfos[i];
61
+ const profile = {
62
+ variables: [
63
+ {
64
+ name: "$feature",
65
+ type: "feature"
66
+ }
67
+ ]
68
+ };
69
+ try {
70
+ const arcadeExecutor = await this.arcade.createArcadeExecutor(info.expression, profile);
71
+ const arcadeTitle = arcadeExecutor.execute({ $feature: graphic });
72
+ if (arcadeTitle != null || arcadeTitle !== "") {
73
+ attributes[`{expression/${info.name}}`.toUpperCase()] = arcadeTitle;
74
+ }
75
+ }
76
+ catch (_d) {
77
+ continue;
78
+ }
79
+ }
80
+ }
81
+ return popupTitle === null || popupTitle === void 0 ? void 0 : popupTitle.replace(/{.*?}/g, (placeholder) => {
82
+ return attributes[placeholder.toUpperCase()] != null ? attributes[placeholder.toUpperCase()] : "";
83
+ });
84
+ }
85
+ /**
86
+ * Remove any tags from the title
87
+ *
88
+ * @returns title string without tags
89
+ *
90
+ * @protected
91
+ */
92
+ _removeTags(str) {
93
+ if (str == null || str === "") {
94
+ return "";
95
+ }
96
+ return str.toString().replace(/(<([^>]+)>)/gi, "");
97
+ }
98
+ /**
99
+ * Load esri javascript api modules
100
+ *
101
+ * @returns Promise resolving when function is done
102
+ *
103
+ * @protected
104
+ */
105
+ async _initModules() {
106
+ const [arcade] = await loadModules([
107
+ "esri/arcade"
108
+ ]);
109
+ this.arcade = arcade;
110
+ }
111
+ }
112
+
24
113
  const infoCardCss = ":host{display:block;--calcite-label-margin-bottom:0}.padding-1-2{padding:0.5rem}.display-none{display:none !important}.display-flex{display:flex}.position-absolute{position:absolute;top:0;right:0;bottom:0;left:0;overflow:auto}.esri-features__footer{display:none !important}.button-container{justify-content:space-between;align-items:center}.top-border{border-top:1px solid var(--calcite-color-border-1)}.min-width-100{min-width:100px}.width-100{width:100%}.esri-features__container{padding:0.5rem !important;background-color:var(--calcite-color-foreground-1) !important;height:100% !important}.overflow-hidden{overflow:hidden}.height-40{height:40px}.padding-top-46{padding-top:46px}.end-border{border-inline-end:1px solid var(--calcite-color-border-1)}.font-bold{font-weight:bold}.visibility-hidden{visibility:hidden;height:0px}.padding-inline-start-1{padding-inline-start:1rem}";
25
114
 
26
115
  const InfoCard = /*@__PURE__*/ proxyCustomElement(class InfoCard extends HTMLElement {
@@ -57,6 +146,7 @@ const InfoCard = /*@__PURE__*/ proxyCustomElement(class InfoCard extends HTMLEle
57
146
  if (this.graphics.length > 0) {
58
147
  const featureLayer = (_a = this.graphics[0]) === null || _a === void 0 ? void 0 : _a.layer;
59
148
  this._editEnabled = featureLayer.editingEnabled && featureLayer.capabilities.operations.supportsUpdate;
149
+ this._mobileTitle = await this._popupUtils.getPopupTitle(this.graphics[0]);
60
150
  this._features.open({
61
151
  features: this.graphics
62
152
  });
@@ -120,6 +210,7 @@ const InfoCard = /*@__PURE__*/ proxyCustomElement(class InfoCard extends HTMLEle
120
210
  async componentWillLoad() {
121
211
  await this._initModules();
122
212
  await this._getTranslations();
213
+ this._popupUtils = new PopupUtils();
123
214
  }
124
215
  /**
125
216
  * Renders the component.
@@ -180,9 +271,6 @@ const InfoCard = /*@__PURE__*/ proxyCustomElement(class InfoCard extends HTMLEle
180
271
  this._showListView = isOpen;
181
272
  }
182
273
  });
183
- this.reactiveUtils.watch(() => this._features.viewModel.title, (title) => {
184
- this._mobileTitle = title;
185
- });
186
274
  if (this.zoomAndScrollToSelected) {
187
275
  this.reactiveUtils.watch(() => this._features.selectedFeatureIndex, (i) => {
188
276
  if (i > -1) {