@esri/solutions-components 0.7.18 → 0.7.19

Sign up to get free protection for your applications and to get access to all the features.
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) {