@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
6 lines (5 loc) • 7.66 kB
JavaScript
/*
All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://js.arcgis.com/4.32/esri/copyright.txt for details.
*/
import{equals as e,difference as r,isSome as a}from"../../core/arrayUtils.js";import"../../core/has.js";import t from"../../core/Error.js";import{updateOrigins as o}from"../../core/accessorSupport/originUtils.js";import{save as s,getLayerJSON as n,saveAs as l,getPortalItem as i,addItem as c,ensureLayerConfig as u,ensureItemConfig as y,setCommonItemProperties as p,createErrorMessage as f}from"./utils.js";import{parse as m}from"../support/arcgisLayerUrl.js";import{fetchFeatureService as d,getLayerModuleType as h}from"../support/fetchService.js";import{isLayerWithFeatureLayerSource as w}from"../support/layerUtils.js";import{createForItemWrite as b}from"../../portal/support/jsonContext.js";import{getWGS84ExtentForItem as T,toggleTypeKeyword as v,typeKeyword as S,removeTypeKeyword as I}from"../../portal/support/portalItemUtils.js";const L="Feature Service",P="feature-layer-utils",E=`${P}-save`,g=`${P}-save-as`,O=`${P}-saveall`,x=`${P}-saveall-as`;function A(e){return{isValid:w(e)&&(!("dynamicDataSource"in e)||!e.dynamicDataSource),errorMessage:"Feature layer should be a layer or table in a map or feature service"}}function N(e,r){const a=b(e,"portal-item");return r?.isTable&&(a.layerContainerType="tables"),a}function $(e){const r=N(e),a=N(e);return a.layerContainerType="tables",{forLayers:r,forTables:a}}function j(e){const r=[],a=[];for(const{layer:t,layerJSON:o}of e)t.isTable?a.push(o):r.push(o);return{layers:r,tables:a}}function U(e){return j([e])}async function R(e,r){return/\/\d+\/?$/.test(e.url)?U(r[0]):J(r,e)}async function J(e,r){if(e.reverse(),!r)return j(e);const a=await F(r,e);for(const t of e)z(t.layer,t.layerJSON,a);return D(a,e),a}async function F(e,r){let a=await e.fetchData("json");if(_(a))return a;a||={},C(a);const{layer:{url:t,customParameters:o,apiKey:s}}=r[0];return await Y(a,{url:t??"",customParameters:o,apiKey:s},r.map((e=>e.layer.layerId))),a}function _(e){return!!(e&&Array.isArray(e.layers)&&Array.isArray(e.tables))}function C(e){e.layers||=[],e.tables||=[]}function D(e,r){const a=[],t=[];for(const{layer:o}of r){const{isTable:e,layerId:r}=o;e?t.push(r):a.push(r)}G(e.layers,a),G(e.tables,t)}function G(r,a){if(r.length<2)return;const t=[];for(const{id:e}of r)t.push(e);e(t.sort(M),a.slice().sort(M))&&r.sort(((e,r)=>{const t=a.indexOf(e.id),o=a.indexOf(r.id);return t<o?-1:t>o?1:0}))}function M(e,r){return e<r?-1:e>r?1:0}async function Y(e,r,a){const{url:t,customParameters:o,apiKey:s}=r,{serviceJSON:n,layersJSON:l}=await d(t,{customParameters:o,apiKey:s}),i=k(e.layers,n.layers,a),c=k(e.tables,n.tables,a);e.layers=i.itemResources,e.tables=c.itemResources;const u=[...i.added,...c.added],y=l?[...l.layers,...l.tables]:[];await B(e,u,t,y)}function k(e,a,t){const o=r(e,a,((e,r)=>e.id===r.id));e=e.filter((e=>!o.removed.some((r=>r.id===e.id))));const s=o.added;return s.forEach((({id:r})=>{e.push({id:r})})),{itemResources:e,added:s.filter((({id:e})=>!t.includes(e)))}}async function B(e,r,a,t){const o=await K(r),s=r.map((({id:e,type:r})=>new(o.get(r))({url:a,layerId:e,sourceJSON:t.find((({id:r})=>r===e))})));await Promise.allSettled(s.map((e=>e.load()))),s.forEach((r=>{const{layerId:a,loaded:t,defaultPopupTemplate:o}=r;if(!t||null==o)return;const s={id:a,popupInfo:o.toJSON()};"ArcGISFeatureLayer"!==r.operationalLayerType&&(s.layerType=r.operationalLayerType),z(r,s,e)}))}async function K(e){const r=[];e.forEach((({type:e})=>{switch(h(e)){case"CatalogLayer":r.push(import("../CatalogLayer.js").then((e=>e.default)));break;case"FeatureLayer":r.push(import("../FeatureLayer.js").then((e=>e.default)));break;case"OrientedImageryLayer":r.push(import("../OrientedImageryLayer.js").then((e=>e.default)))}}));const a=await Promise.all(r),t=new Map;return e.forEach((({type:e},r)=>{t.set(e,a[r])})),t}function z(e,r,a){e.isTable?V(a.tables,r):V(a.layers,r)}function V(e,r){const a=e.findIndex((({id:e})=>e===r.id));-1===a?e.push(r):e[a]=r}function q(e,r){if(!e.length)throw new t(`${r}:missing-parameters`,"'layers' array should contain at least one feature layer")}function H(e,r){const a=e.map((e=>e.portalItem.id));if(new Set(a).size>1)throw new t(`${r}:invalid-parameters`,"All layers in the 'layers' array should be loaded from the same portal item")}function Q(e,r){const a=e.map((e=>e.layerId));if(new Set(a).size!==a.length)throw new t(`${r}:invalid-parameters`,"'layers' array should contain only one instance each of layer or table in a feature service")}async function W(e){q(e,O),await Promise.all(e.map((e=>e.load())));for(const r of e)u(r,O,A),y({layer:r,itemType:L,errorNamePrefix:O});H(e,O),Q(e,O)}function X(e,r){let a=0,t=0,o=0;for(const{layerType:s}of[...r.layers,...r.tables])switch(s){case"OrientedImageryLayer":a++;break;case"SubtypeGroupLayer":t++;break;case"SubtypeGroupTable":o++}v(e,S.ORIENTED_IMAGERY_LAYER,a>0),v(e,S.SUBTYPE_GROUP_LAYER,t>0),v(e,S.SUBTYPE_GROUP_TABLE,o>0)}function Z(e,r,a){I(r,S.METADATA),v(r,S.MULTI_LAYER,e.length>1),v(r,S.SINGLE_LAYER,1===e.length),v(r,S.TABLE,a.tables.length>0&&0===a.layers.length),X(r,a)}async function ee(e,r,a){X(r,a)}async function re(e,r,a){const{url:t,layerId:o,title:s,fullExtent:n,isTable:l}=e,i=m(t);r.url=("FeatureServer"===i?.serverType?t:`${t}/${o}`)??null,r.title||=s,r.extent=null,l||null==n||(r.extent=await T(n)),Z([e],r,a)}function ae(e,r){for(const n of e){const a=n.parsedUrl.path,o=m(a),s=o?.url.path;if(!s)throw new t(`${r}:invalid-parameters`,f(n,`has unsupported url pattern: ${a}`),{layer:n});const l=o?.serverType;if("FeatureServer"!==l&&"MapServer"!==l)throw new t(`${r}:invalid-parameters`,f(n,`has unsupported server type: ${l}`),{layer:n});if("MapServer"===l&&e.length>1)throw new t(`${r}:invalid-parameters`,"Only one layer or table in a map service can be saved")}const a=m(e[0].parsedUrl.path),o=a?.url.path,s=e.every((e=>{const r=m(e.parsedUrl.path);return r?.url.path===o}));if(!s)throw new t(`${r}:invalid-parameters`,"'layers' array should only contain layers or tables that belong to the same feature service")}async function te(e){q(e,x),await Promise.all(e.map((e=>e.load())));for(const r of e)u(r,x,A);ae(e,x),Q(e,x)}function oe(e,r){X(e,r),p(e)}async function se(e,r,t){let o=0;for(const{isTable:a}of e)a||o++;const s=e[0].parsedUrl.path,n=m(s);if(r.url="FeatureServer"===n?.serverType?n.url.path:s,r.title||=n.title,r.extent=null,o>0){const t=e.map((e=>e.fullExtent)).filter(a).reduce(((e,r)=>e.clone().union(r)));t&&(r.extent=await T(t))}Z(e,r,t),p(r)}async function ne(e,r){return s({layer:e,itemType:L,validateLayer:A,createJSONContext:r=>N(r,e),createItemData:(e,r)=>R(r,[e]),errorNamePrefix:E,setItemProperties:ee},r)}async function le(e,r){await W(e);const a=e[0].portalItem,t=$(a),s=await Promise.all(e.map((e=>n(e,e.isTable?t.forTables:t.forLayers,r)))),l=await R(a,e.map(((e,r)=>({layer:e,layerJSON:s[r]}))));return oe(a,l),await a.update({data:l}),await Promise.all(e.slice(1).map((e=>e.portalItem.reload()))),o(t.forLayers),o(t.forTables),a.clone()}async function ie(e,r,a){return l({layer:e,itemType:L,validateLayer:A,createJSONContext:r=>N(r,e),createItemData:(e,r)=>Promise.resolve(U(e)),errorNamePrefix:g,newItem:r,setItemProperties:re},a)}async function ce(e,r,a){await te(e);const t=i({itemType:L,errorNamePrefix:x,newItem:r}),s=$(t),l=await Promise.all(e.map((e=>n(e,e.isTable?s.forTables:s.forLayers,a)))),u=await J(e.map(((e,r)=>({layer:e,layerJSON:l[r]}))));await se(e,t,u),await c(t,u,a);for(const o of e)o.portalItem=t.clone();return o(s.forLayers),o(s.forTables),t}export{ne as save,le as saveAll,ce as saveAllAs,ie as saveAs};