/////////////////////////////////////////////////////////////////////////// // Copyright © 2014 - 2018 Esri. All Rights Reserved. // // Licensed under the Apache License Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /////////////////////////////////////////////////////////////////////////// define([ 'dojo/_base/declare', 'dojo/_base/lang', 'dojo/_base/array', 'dojo/Deferred', 'dojo/DeferredList', 'jimu/utils', 'esri/request', 'esri/geometry/webMercatorUtils', 'esri/geometry/Polygon', 'esri/geometry/Polyline', 'jimu/portalUtils', 'jimu/tokenUtils', 'jimu/dijit/Message' ], function (declare, lang, array, Deferred, DeferredList, utils, esriRequest, webMercatorUtils, Polygon, Polyline, portalUtils, tokenUtils, Message) { var Snapshot = declare('Snapshot', null, { _portal: null, _portalUrl: "", _layerArray: [], _originMapId: "", _originAppId: "", _credential: null, name: "", appendTimeStamp: null, baseMap: null, tags: "", description: "", shareWith: null, logo: "", time: null, //options //shareWith: {everyone: bool, org: bool, groups: "comma seperated list of group IDs"}, // shareWith is expected to follow "share item (as item owner)" props // http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Share_Item_as_item_owner/02r30000007s000000/ //folderOptions: folderOptions will be passed to CreateFolder in the _createFolder function // http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Create_Folder/02r300000074000000/ //mapTitle: str, //mapExtent: {}, //data: [{ // graphics: [], // renderer: , // infoTemplate: , // fields: [], // tags: [], // description: str, // name: str, // visibleOnStartup: bool, // appendTimeStamp: bool, // typeIdField: str, // types: [], // minScale: int, // maxScale: int //}] constructor: function (appConfig, map) { this.map = map; this.appConfig = appConfig; this._originAppId = appConfig.appId; this._originMapId = map.itemId; this._mapItemInfo = map.itemInfo; this._portalUrl = appConfig.portalUrl; this._portal = portalUtils.getPortal(this._portalUrl); this._baseUrl = this._portalUrl + 'sharing/rest/'; this.nls = lang.mixin({}, window.jimuNls.drawBox, window.jimuNls.snapshot); }, createSnapShot: function (options) { this.ids = []; this.layerArray = []; this.time = this._getDateString(Date.now()); var _name = options.appendTimeStamp && options.name ? options.name + "_" + this.time : options.name; this.name = _name || this._mapItemInfo.item.title + "_" + this.time; //if no name is specified in options always append timestamp to avoid duplicate name issues this.extent = options.mapExtent || this.map.extent; this.logo = options.logo || this.appConfig.logo; this.mapName = options.mapTitle || this.name; this.shareWith = options.shareWith || { everyone: false, org: false, groups: "" }; var folderOptions = options.folderOptions; //make sure the required ones have a value folderOptions.name = options.folderOptions.name || this.name; folderOptions.title = options.folderOptions.title || this.name; folderOptions.description = options.folderOptions.description || this.name; //reverse to preserve inital order as we will push to another array later var data = options.data.reverse(); return this._createSnapshot(folderOptions, data); }, _createSnapshot: function (folderOptions, data) { var def = new Deferred(); this._portal.getUser() .then(lang.hitch(this, this._processUser), function (err) { def.reject(err); }) .then(lang.hitch(this, this._createFolder, folderOptions), function (err) { def.reject(err); }) .then(lang.hitch(this, this._createItems, data), function (err) { def.reject(err); }) .then(lang.hitch(this, this._addLayers), function (err) { def.reject(err); }) .then(lang.hitch(this, this._createMap, this._mapItemInfo), function (err) { def.reject(err); }) .then(lang.hitch(this, this._processMap), function (err) { def.reject(err); }) .then(lang.hitch(this, this._shareItems), function (err) { def.reject(err); }) .then(lang.hitch(this, this._showMessage), function(err) { def.reject(err); }) .then(function() { def.resolve(); }); return def; }, _processUser: function (user) { var def = new Deferred(); this.user = user; this.groups = user.groups; def.resolve(); return def; }, _createFolder: function (folderOptions) { var def = new Deferred(); var args = { url: this._baseUrl + 'content/users/' + this.user.username + '/createFolder', content: lang.mixin({ f: 'json' }, folderOptions), handleAs: 'json', callbackParamName: 'callback' }; if (this._isValidCredential()) { args.content.token = this._credential.token; } esriRequest(args, { usePost: true }).then(lang.hitch(this, function (response) { if (response.success) { this.folder = response.folder; if (this.folder && this.folder.id) { this.ids.push(this.folder.id); } def.resolve(response.folder); } else { console.log(response); def.reject(response); } }), lang.hitch(this, function (err) { def.reject(err); })); return def; }, _createItems: function (data) { var def = new Deferred(); var defArray = []; array.forEach(data, lang.hitch(this, function (dataItem) { if (dataItem.graphics && dataItem.graphics.length > 0) { defArray.push(this._createLayerItem(dataItem)); } })); var itemList = []; var defList = new DeferredList(defArray); defList.then(lang.hitch(this, function (defResults) { for (var r = 0; r < defResults.length; r++) { var featureSet = defResults[r][1]; itemList.push(featureSet); } def.resolve(itemList); }), lang.hitch(this, function (err) { def.reject(err); })); return def; }, _addLayers: function (items) { var def = new Deferred(); var defArray = []; for (var i = 0; i < items.length; i++) { defArray.push(this.user.addItem(items[i], this.folder.id)); } var layerList = []; var defList = new DeferredList(defArray); defList.then(lang.hitch(this, function (defResults) { for (var r = 0; r < defResults.length; r++) { var featureSet = defResults[r][1]; if (featureSet.success) { layerList.push(featureSet.id); this.ids.push(featureSet.id); } } def.resolve(layerList); }), lang.hitch(this, function (err) { def.reject(err); })); return def; }, _createMap: function (mapItemInfo, layers) { var itemData = mapItemInfo.itemData; var title = this.name; var baseMapLayers = []; for (var i = 0; i < itemData.baseMap.baseMapLayers.length; i++) { var bml = itemData.baseMap.baseMapLayers[i]; baseMapLayers.push({ "id": bml.id, "layerType": bml.layerType, "url": bml.url, "visibility": bml.visibility, "opacity": bml.opacity, "title": bml.title, "styleUrl": bml.styleUrl, "itemId": bml.itemId }); } var baseMap = { "baseMapLayers": baseMapLayers }; var operationalLayers = []; for (var j = 0; j < this.layerArray.length; j++) { var l = this.layerArray[j]; operationalLayers.push({ id: l.layer.id, layerType: "ArcGISFeatureLayer", visibility: l.layer.visible, opacity: l.layer.opacity, title: l.label, type: "Feature Collection", itemId: layers[j] }); } //TODO think through this var ext1 = webMercatorUtils.webMercatorToGeographic(this.extent); var webMap = { title: title, type: "Web Map", item: title, extent: ext1.xmin + "," + ext1.ymin + "," + ext1.xmax + "," + ext1.ymax, text: JSON.stringify({ "operationalLayers": operationalLayers, "baseMap": baseMap, "spatialReference": this.map.spatialReference, "version": mapItemInfo && mapItemInfo.itemData && mapItemInfo.itemData.version ? mapItemInfo.itemData.version : "2.4" }), tags: this.name + "," + this.nls.snapshot_append, wabType: "HTML" }; return this.user.addItem(webMap, this.folder.id); }, _processMap: function (r) { var def = new Deferred(); if (r.id) { this.ids.push(r.id); } if (r.success) { def.resolve(r.id); } else { def.reject('fail'); } return def; }, _shareItems: function (mapId) { var def = new Deferred(); var args = { url: this._baseUrl + 'content/users/' + this.user.username + '/shareItems', content: { f: 'json', everyone: this.shareWith.everyone, org: this.shareWith.org, items: this.ids.join(), groups: this.shareWith.groups, confirmItemControl: this._validateGroupItemControl(this.shareWith.groups) }, handleAs: 'json', callbackParamName: 'callback' }; if (this._isValidCredential()) { args.content.token = this._credential.token; } esriRequest(args, { usePost: true }).then(lang.hitch(this, function (response) { if (response.results && response.results.length > 0) { def.resolve(this._portalUrl + 'home/webmap/viewer.html?webmap=' + mapId); } else { def.reject("fail"); } }), lang.hitch(this, function (err) { def.reject(err); })); return def; }, _validateGroupItemControl: function (groupIds) { var _groupIds = groupIds.split(','); var _groups = this.groups.filter(function (group) { var capabilities = group.capabilities || []; return _groupIds.indexOf(group.id) > -1 && capabilities.indexOf("updateitemcontrol") > -1; }); return _groups.length > 0; }, _showMessage: function (r) { var def = new Deferred(); if (r === 'fail') { new Message({ message: this.nls.snapshot_failed }); def.reject(r); } else { new Message({ message: '' + this.nls.snapshot_complete + '' }); def.resolve('success'); } return def; }, _getDateString: function (time) { var date = new Date(time); var _off = date.getTimezoneOffset(); return utils.fieldFormatter.getFormattedDate(date, { dateFormat: 'shortDateShortTime' }) + " " + this.nls.utc + (_off < 0 ? "+" + (Math.abs(_off) / 60) : "-" + (_off / 60)); }, _checkCredential: function () { var isValid = tokenUtils.isValidCredential(this._credential); if (!isValid) { this._clearCredential(); } return isValid; }, _isValidCredential: function () { this._updateCredential(); return this._checkCredential(); }, _updateCredential: function () { if (!this._checkCredential()) { this._credential = tokenUtils.getPortalCredential(this._portalUrl); } }, _clearCredential: function () { this._credential = null; }, _createLayerItem: function (dataItem) { var def = new Deferred(); var layerDetailsDefault = { description: dataItem.name, name: dataItem.name, tags: [dataItem.name] }; var t = this._createLayer(dataItem.graphics, lang.mixin({}, layerDetailsDefault, dataItem)); def.resolve(t); return def; }, /* jshint loopfunc:true */ _createLayer: function (graphics, li) { var gl = { 'point': "esriGeometryPoint", 'polyline': "esriGeometryPolyline", 'polygon': "esriGeometryPolygon" }; var nls = this.nls; var time = this.time; var g = graphics[0]; var gt = gl[typeof (g.geometry) !== 'undefined' ? g.geometry.type : g.type]; var symbol = g.symbol ? g.symbol.toJson() : ""; var features = []; var fields = [{ name: "ObjectID", alias: "ObjectID", type: "esriFieldTypeOID" }, { name: nls.snapshot_append, alias: nls.snapshot_append, type: "esriFieldTypeString" }]; if (li.fields && li.fields.length > 0) { array.forEach(li.fields, function(field) { fields.push({ name: field.name, alias: field.alias, type: field.type, domain: field.domain }); }); } //Feature Collections do not support multi-part var i = 0; array.forEach(graphics, function (g) { var _parts; switch (gt) { case "esriGeometryPolyline": _parts = g.geometry.paths; break; case "esriGeometryPolygon": _parts = g.geometry.rings; break; case "esriGeometryPoint": _parts = [g.geometry]; break; } var _i = 0; var newGeom; array.forEach(_parts, function (p) { switch (gt) { case "esriGeometryPolyline": newGeom = new Polyline(p); newGeom.spatialReference = g.geometry.spatialReference; break; case "esriGeometryPolygon": newGeom = new Polygon(p); newGeom.spatialReference = g.geometry.spatialReference; break; case "esriGeometryPoint": newGeom = p; break; } var f = { attributes: { ObjectID: i + _i }, geometry: newGeom }; f.attributes[nls.snapshot_append] = time; if (li.fields && li.fields.length > 0) { array.forEach(li.fields, function (field) { f.attributes[field.name] = g.attributes[field.name]; }); } features.push(f); _i += 1; }); i += 1; }); var extent = { xmin: this.extent.xmin, ymin: this.extent.ymin, xmax: this.extent.xmax, ymax: this.extent.ymax, spatialReference: this.extent.spatialReference }; var renderer = li.renderer && li.renderer.toJson ? li.renderer.toJson() : li.renderer ? JSON.stringify(li.renderer) : { type: "simple", label: '', description: '', symbol: symbol }; this.layerArray.push({ layer: { id: li.name, label: li.name, opacity: 1, visible: li.visibleOnStartup }, label: li.name }); return { title: li.name, type: "Feature Collection", tags: li.tags, description: li.description, extent: extent, name: li.name, text: JSON.stringify({ layers: [{ layerDefinition: { name: li.name, geometryType: gt, objectIdField: "ObjectID", typeIdField: li.typeIdField, types: li.types, type: "Feature Layer", extent: extent, drawingInfo: { renderer: renderer }, fields: fields, minScale: li.minScale, maxScale: li.maxScale }, popupInfo: li.infoTemplate && li.infoTemplate.info ? li.infoTemplate.info : li.infoTemplate ? li.infoTemplate : undefined, featureSet: { features: features, geometryType: gt } }] }), f: "json" }; } }); return Snapshot; });