From 72d57a4f3c47222f3041f795dd85a395c112b507 Mon Sep 17 00:00:00 2001 From: John Hauck Date: Tue, 15 Oct 2024 15:09:12 -0600 Subject: [PATCH] add share --- src/assets/t9n/map-card/resources.json | 3 +- src/assets/t9n/map-card/resources_en.json | 3 +- src/components.d.ts | 24 ++++ .../crowdsource-manager.tsx | 3 + src/components/crowdsource-manager/readme.md | 9 +- src/components/map-card/map-card.tsx | 110 +++++++++++++++++- src/components/map-card/readme.md | 9 ++ 7 files changed, 154 insertions(+), 7 deletions(-) diff --git a/src/assets/t9n/map-card/resources.json b/src/assets/t9n/map-card/resources.json index 37bc54aab..ed50e6915 100644 --- a/src/assets/t9n/map-card/resources.json +++ b/src/assets/t9n/map-card/resources.json @@ -5,5 +5,6 @@ "zoom": "Zoom", "refresh": "Refresh", "editMultiple": "Edit multiple", - "clearSelection": "Clear selection" + "clearSelection": "Clear selection", + "share": "Share" } diff --git a/src/assets/t9n/map-card/resources_en.json b/src/assets/t9n/map-card/resources_en.json index 37bc54aab..ed50e6915 100644 --- a/src/assets/t9n/map-card/resources_en.json +++ b/src/assets/t9n/map-card/resources_en.json @@ -5,5 +5,6 @@ "zoom": "Zoom", "refresh": "Refresh", "editMultiple": "Edit multiple", - "clearSelection": "Clear selection" + "clearSelection": "Clear selection", + "share": "Share" } diff --git a/src/components.d.ts b/src/components.d.ts index b8522a3e0..3e576545d 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -935,6 +935,10 @@ export namespace Components { * boolean: when true the search widget will be available */ "enableSearch": boolean; + /** + * boolean: when true the share widget will be available + */ + "enableShare": boolean; /** * boolean: when true map tools will be displayed within a single expand/collapse widget when false widgets will be loaded individually into expand widgets */ @@ -1003,6 +1007,14 @@ export namespace Components { * __esri.FeatureLayer: Selected layer */ "selectedLayer": __esri.FeatureLayer; + /** + * boolean: When true the share options will include embed option + */ + "shareIncludeEmbed": boolean; + /** + * boolean: When true the share options will include social media sharing + */ + "shareIncludeSocial": boolean; /** * boolean: When true the map widget tools will have no margin between them. When false the map widget tools will have a margin between them. */ @@ -3608,6 +3620,10 @@ declare namespace LocalJSX { * boolean: when true the search widget will be available */ "enableSearch"?: boolean; + /** + * boolean: when true the share widget will be available + */ + "enableShare"?: boolean; /** * boolean: when true map tools will be displayed within a single expand/collapse widget when false widgets will be loaded individually into expand widgets */ @@ -3688,6 +3704,14 @@ declare namespace LocalJSX { * __esri.FeatureLayer: Selected layer */ "selectedLayer"?: __esri.FeatureLayer; + /** + * boolean: When true the share options will include embed option + */ + "shareIncludeEmbed"?: boolean; + /** + * boolean: When true the share options will include social media sharing + */ + "shareIncludeSocial"?: boolean; /** * boolean: When true the map widget tools will have no margin between them. When false the map widget tools will have a margin between them. */ diff --git a/src/components/crowdsource-manager/crowdsource-manager.tsx b/src/components/crowdsource-manager/crowdsource-manager.tsx index 2dd6c9ca4..17907f2d5 100644 --- a/src/components/crowdsource-manager/crowdsource-manager.tsx +++ b/src/components/crowdsource-manager/crowdsource-manager.tsx @@ -829,6 +829,7 @@ export class CrowdsourceManager { enableHome={this.enableHome} enableLegend={this.enableLegend} enableSearch={this.enableSearch} + enableShare={this.enableShare} enableSingleExpand={true} hidden={!this._isPortraitMobile && isTableLayout} homeZoomIndex={3} @@ -846,6 +847,8 @@ export class CrowdsourceManager { ref={(el) => this._mapCard = el} selectedFeaturesIds={this._layerTable?.selectedIds} selectedLayer={this._layer} + shareIncludeEmbed={this.shareIncludeEmbed} + shareIncludeSocial={this.shareIncludeSocial} stackTools={true} theme={this.theme} toolOrder={["legend", "search", "fullscreen", "basemap", "floorfilter"]} diff --git a/src/components/crowdsource-manager/readme.md b/src/components/crowdsource-manager/readme.md index 3f6dd5b79..24691b97f 100644 --- a/src/components/crowdsource-manager/readme.md +++ b/src/components/crowdsource-manager/readme.md @@ -119,6 +119,7 @@ graph TD; map-card --> calcite-dropdown-group map-card --> calcite-dropdown-item map-card --> calcite-loader + map-card --> instant-apps-social-share map-card --> calcite-tooltip map-tools --> basemap-gallery map-tools --> map-search @@ -167,6 +168,10 @@ graph TD; calcite-combobox-item --> calcite-icon calcite-chip --> calcite-icon calcite-dropdown-item --> calcite-icon + instant-apps-social-share --> calcite-popover + instant-apps-social-share --> calcite-button + instant-apps-social-share --> calcite-icon + instant-apps-social-share --> calcite-action card-manager --> calcite-shell card-manager --> info-card card-manager --> calcite-flow-item @@ -208,10 +213,6 @@ graph TD; layer-table --> delete-button layer-table --> calcite-modal layer-table --> instant-apps-filter-list - instant-apps-social-share --> calcite-popover - instant-apps-social-share --> calcite-button - instant-apps-social-share --> calcite-icon - instant-apps-social-share --> calcite-action instant-apps-filter-list --> calcite-panel instant-apps-filter-list --> calcite-loader instant-apps-filter-list --> calcite-checkbox diff --git a/src/components/map-card/map-card.tsx b/src/components/map-card/map-card.tsx index 4a8ba4f36..01809f7ca 100644 --- a/src/components/map-card/map-card.tsx +++ b/src/components/map-card/map-card.tsx @@ -21,6 +21,7 @@ import { IBasemapConfig, IMapChange, IMapInfo, ISearchConfiguration, IToolInfo, import { joinAppProxies } from "templates-common-library-esm/functionality/proxy"; import { getLocaleComponentStrings } from "../../utils/locale"; import { getFeatureLayerView, goToSelection } from "../../utils/mapViewUtils"; +import "@esri/instant-apps-components/dist/components/instant-apps-social-share"; // TODO navigation and accessability isn't right for the map list // tab does not go into the list when it's open @@ -84,6 +85,11 @@ export class MapCard { */ @Prop() enableFullscreen: boolean; + /** + * boolean: when true the share widget will be available + */ + @Prop() enableShare = false; + /** * boolean: when true map tools will be displayed within a single expand/collapse widget * when false widgets will be loaded individually into expand widgets @@ -176,6 +182,16 @@ export class MapCard { */ @Prop() isMapLayout: boolean; + /** + * boolean: When true the share options will include embed option + */ + @Prop() shareIncludeEmbed: boolean; + + /** + * boolean: When true the share options will include social media sharing + */ + @Prop() shareIncludeSocial: boolean; + /** * number[]: A list of ids that are currently selected */ @@ -329,6 +345,11 @@ export class MapCard { */ protected _resizeObserver: ResizeObserver; + /** + * HTMLInstantAppsSocialShareElement: Element to support app sharing to social media + */ + protected _shareNode: HTMLInstantAppsSocialShareElement; + /** * HTMLCalciteDropdownElement: Dropdown the will support show/hide of table columns */ @@ -373,6 +394,28 @@ export class MapCard { this._initHome(); } + /** + * Update the toolbar when the share button is enabled/disabled + */ + @Watch("enableShare") + enableShareWatchHandler(): void { + // this should be caught by component did render and is when I test locally + // however have had reported case where it is not somehow on devext so adding explicit check here + if (this._toolbar) { + this._updateToolbar(); + } + } + + /** + * watch for changes in map view and get the first layer + */ + @Watch("mapView") + async mapViewWatchHandler(): Promise { + if (this.mapView) { + this._updateShareUrl(); + } + } + /** * watch for changes in layer view and verify if it has editing enabled */ @@ -388,6 +431,7 @@ export class MapCard { */ @Watch("selectedFeaturesIds") async selectedFeaturesIdsWatchHandler(): Promise { + this._updateShareUrl(); this._validateEnabledActions(); } @@ -421,6 +465,7 @@ export class MapCard { @Method() async resetFilter(): Promise { this._filterActive = false; + this._updateShareUrl(); } /** @@ -429,6 +474,7 @@ export class MapCard { @Method() async updateFilterState(): Promise { this._filterActive = this._definitionExpression !== this.selectedLayer.definitionExpression; + this._updateShareUrl(); } /** @@ -529,6 +575,7 @@ export class MapCard { {this._getActionBar()} {/* dropdown actions */} {!this.isMobile && this.isMapLayout && this._getDropdown("more-table-options")} + {this.enableShare && !this.isMobile ? this._getShare("share") : undefined} {/* added calcite progress below header actions to match bottom-border with the split/table view */} @@ -684,7 +731,7 @@ export class MapCard { return prev; }, 0); - const skipControls = ["solutions-more", "solutions-map-layer-picker-container", "map-picker"]; + const skipControls = ["solutions-more", "solutions-map-layer-picker-container", "map-picker", "solutions-action-share"]; if (controlsWidth > toolbarWidth) { if (this._toolbarSizeInfos.length > 0) { const controlsThatFit = [...this._toolbarSizeInfos].reverse().reduce((prev, cur) => { @@ -910,6 +957,67 @@ export class MapCard { ) : undefined; } + /** + * Get an action and tooltip for share + * + * @param icon string the name of the icon to display, will also be used in its id + * + * @returns VNode The node representing the DOM element that will contain the action + */ + protected _getShare( + icon: string + ): VNode { + return ( + + ) + } + + /** + * Called each time the values that are used for custom url params change + */ + _updateShareUrl(): void { + const url = this._shareNode?.shareUrl; + if (!url) { + return; + } + const urlObj = new URL(url); + + //set the additional search params + if (this._loadedId) { + urlObj.searchParams.set("webmap", this._loadedId); + } else { + urlObj.searchParams.delete("webmap"); + } + + if (this.selectedLayer?.id) { + urlObj.searchParams.set("layer", this.selectedLayer.id); + } else { + urlObj.searchParams.delete("layer"); + } + + if (this.selectedFeaturesIds?.length > 0) { + urlObj.searchParams.set("oid", this.selectedFeaturesIds.join(",")); + } else { + urlObj.searchParams.delete("oid"); + } + + this._shareNode.shareUrl = urlObj.href; + } + /** * Open show/hide dropdown * @protected diff --git a/src/components/map-card/readme.md b/src/components/map-card/readme.md index 1d744c30e..9441f87a2 100644 --- a/src/components/map-card/readme.md +++ b/src/components/map-card/readme.md @@ -19,6 +19,7 @@ | `enableHome` | `enable-home` | boolean: when true the home widget will be available | `boolean` | `undefined` | | `enableLegend` | `enable-legend` | boolean: when true the legend widget will be available | `boolean` | `undefined` | | `enableSearch` | `enable-search` | boolean: when true the search widget will be available | `boolean` | `undefined` | +| `enableShare` | `enable-share` | boolean: when true the share widget will be available | `boolean` | `false` | | `enableSingleExpand` | `enable-single-expand` | boolean: when true map tools will be displayed within a single expand/collapse widget when false widgets will be loaded individually into expand widgets | `boolean` | `true` | | `hidden` | `hidden` | boolean: When true the map display will be hidden | `boolean` | `undefined` | | `homeZoomIndex` | `home-zoom-index` | number: The placement index of the home and zoom components. This index shows where to place the component relative to other components. For example a value of 0 would place it topmost when position is top-*, leftmost for bottom-left and right most for bottom-right. | `number` | `3` | @@ -35,6 +36,8 @@ | `onlyShowUpdatableLayers` | `only-show-updatable-layers` | boolean: When true only editable layers that support the update capability will be available | `boolean` | `undefined` | | `selectedFeaturesIds` | -- | number[]: A list of ids that are currently selected | `number[]` | `undefined` | | `selectedLayer` | -- | __esri.FeatureLayer: Selected layer | `FeatureLayer` | `undefined` | +| `shareIncludeEmbed` | `share-include-embed` | boolean: When true the share options will include embed option | `boolean` | `undefined` | +| `shareIncludeSocial` | `share-include-social` | boolean: When true the share options will include social media sharing | `boolean` | `undefined` | | `stackTools` | `stack-tools` | boolean: When true the map widget tools will have no margin between them. When false the map widget tools will have a margin between them. | `boolean` | `true` | | `theme` | `theme` | theme: "light" \| "dark" theme to be used | `"dark" \| "light"` | `undefined` | | `toolOrder` | -- | Valid tools: "legend", "search", "fullscreen", "basemap", "floorfilter" | `string[]` | `undefined` | @@ -103,6 +106,7 @@ Type: `Promise` - calcite-dropdown-group - calcite-dropdown-item - calcite-loader +- instant-apps-social-share - calcite-tooltip ### Graph @@ -119,6 +123,7 @@ graph TD; map-card --> calcite-dropdown-group map-card --> calcite-dropdown-item map-card --> calcite-loader + map-card --> instant-apps-social-share map-card --> calcite-tooltip map-tools --> basemap-gallery map-tools --> map-search @@ -176,6 +181,10 @@ graph TD; calcite-combobox-item --> calcite-icon calcite-chip --> calcite-icon calcite-dropdown-item --> calcite-icon + instant-apps-social-share --> calcite-popover + instant-apps-social-share --> calcite-button + instant-apps-social-share --> calcite-icon + instant-apps-social-share --> calcite-action crowdsource-manager --> map-card style map-card fill:#f9f,stroke:#333,stroke-width:4px ```