UNPKG

terriajs

Version:

Geospatial data visualization platform.

274 lines (229 loc) 10.3 kB
'use strict'; /*global require*/ var URI = require('urijs'); var clone = require('terriajs-cesium/Source/Core/clone'); var defined = require('terriajs-cesium/Source/Core/defined'); var defineProperties = require('terriajs-cesium/Source/Core/defineProperties'); var freezeObject = require('terriajs-cesium/Source/Core/freezeObject'); var knockout = require('terriajs-cesium/Source/ThirdParty/knockout'); var loadJson = require('../Core/loadJson'); var TerriaError = require('../Core/TerriaError'); var CatalogGroup = require('./CatalogGroup'); var inherit = require('../Core/inherit'); var proxyCatalogItemUrl = require('./proxyCatalogItemUrl'); var replaceUnderscores = require('../Core/replaceUnderscores'); var ArcGisFeatureServerCatalogGroup = require('./ArcGisFeatureServerCatalogGroup'); var ArcGisMapServerCatalogGroup = require('./ArcGisMapServerCatalogGroup'); /** * A {@link CatalogGroup} representing a collection of ArcGIS Services, * eg. http://www.ga.gov.au/gis/rest/services/ * * @alias ArcGisCatalogGroup * @constructor * @extends CatalogGroup * * @param {Terria} terria The Terria instance. */ var ArcGisCatalogGroup = function(terria) { CatalogGroup.call(this, terria, 'esri-group'); /** * Gets or sets the URL of the services. This property is observable. * @type {String} */ this.url = ''; /** * Gets or sets a description of the custodian of the data sources in this group. * This property is an HTML string that must be sanitized before display to the user. * This property is observable. * @type {String} */ this.dataCustodian = undefined; /** * Gets or sets a hash of names of blacklisted data layers. A layer that appears in this hash * will not be shown to the user. In this hash, the keys should be the Title of the layers to blacklist, * and the values should be "true". This property is observable. * @type {Object} */ this.blacklist = undefined; /** * Gets or sets a hash of properties that will be set on each child item. * For example, { 'treat404AsError': false } */ this.itemProperties = undefined; knockout.track(this, ['url', 'dataCustodian', 'blacklist', 'itemProperties']); }; inherit(CatalogGroup, ArcGisCatalogGroup); defineProperties(ArcGisCatalogGroup.prototype, { /** * Gets the type of data member represented by this instance. * @memberOf ArcGisCatalogGroup.prototype * @type {String} */ type : { get : function() { return 'esri-group'; } }, /** * Gets a human-readable name for this type of data source, such as 'Web Map Service (WMS)'. * @memberOf ArcGisCatalogGroup.prototype * @type {String} */ typeName : { get : function() { return 'ArcGIS Service Group'; } }, /** * Gets the set of functions used to serialize individual properties in {@link CatalogMember#serializeToJson}. * When a property name on the model matches the name of a property in the serializers object literal, * the value will be called as a function and passed a reference to the model, a reference to the destination * JSON object literal, and the name of the property. * @memberOf ArcGisCatalogGroup.prototype * @type {Object} */ serializers : { get : function() { return ArcGisCatalogGroup.defaultSerializers; } } }); /** * Gets or sets the set of default serializer functions to use in {@link CatalogMember#serializeToJson}. Types derived from this type * should expose this instance - cloned and modified if necesary - through their {@link CatalogMember#serializers} property. * @type {Object} */ ArcGisCatalogGroup.defaultSerializers = clone(CatalogGroup.defaultSerializers); ArcGisCatalogGroup.defaultSerializers.items = CatalogGroup.enabledShareableItemsSerializer; ArcGisCatalogGroup.defaultSerializers.isLoading = function(wmsGroup, json, propertyName, options) {}; freezeObject(ArcGisCatalogGroup.defaultSerializers); ArcGisCatalogGroup.prototype._getValuesThatInfluenceLoad = function() { return [this.url, this.blacklist]; }; ArcGisCatalogGroup.prototype._load = function() { // Allow ArcGisCatalogGroup to function like an ArcGisMapServerCatalogGroup or an ArcGisFeatureServerCatalogGroup. if (/\/MapServer\/?$/i.test(this.url)) { return ArcGisMapServerCatalogGroup.loadMapServer(this); } else if (/\/FeatureServer\/?$/i.test(this.url)) { return ArcGisFeatureServerCatalogGroup.loadFeatureServer(this); } else { return loadRest(this); } }; function loadRest(catalogGroup) { // Load as a generic REST endpoint. var serviceUrl = cleanAndProxyUrl(catalogGroup, catalogGroup.url) + '?f=json'; var terria = catalogGroup.terria; return loadJson(serviceUrl).then(function(serviceJson) { // Is this really a MapServer REST response? if (!serviceJson || (!serviceJson.folders && !serviceJson.services)) { throw new TerriaError({ title: 'Invalid ArcGIS Server', message: '\ An error occurred while invoking the ArcGIS REST service. The server\'s response does not appear to be a valid ArcGIS REST document. \ <p>If you entered the link manually, please verify that the link is correct.</p>\ <p>If you did not enter this link manually, this error may indicate that the group you opened is temporarily unavailable or there is a \ problem with your internet connection. Try opening the group again, and if the problem persists, please report it by \ sending an email to <a href="mailto:'+terria.supportEmail+'">'+terria.supportEmail+'</a>.</p>' }); } var basePath = getBasePath(catalogGroup); var i; var folders = serviceJson.folders; if (defined(folders)) { for (i = 0; i < folders.length; ++i) { createGroup(catalogGroup, basePath, folders[i]); } } var services = serviceJson.services; if (defined(services)) { for (i = 0; i < services.length; ++i) { createMapOrFeatureServer(catalogGroup, basePath, services[i]); } } }).otherwise(function(e) { throw new TerriaError({ sender: catalogGroup, title: 'Group is not available', message: '\ An error occurred while invoking the ArcGIS REST service. \ <p>If you entered the link manually, please verify that the link is correct.</p>\ <p>This error may also indicate that the server does not support <a href="http://enable-cors.org/" target="_blank">CORS</a>. If this is your \ server, verify that CORS is enabled and enable it if it is not. If you do not control the server, \ please contact the administrator of the server and ask them to enable CORS. Or, contact the '+terria.appName+' \ team by emailing <a href="mailto:'+terria.supportEmail+'">'+terria.supportEmail+'</a> \ and ask us to add this server to the list of non-CORS-supporting servers that may be proxied by '+terria.appName+' \ itself.</p>\ <p>If you did not enter this link manually, this error may indicate that the group you opened is temporarily unavailable or there is a \ problem with your internet connection. Try opening the group again, and if the problem persists, please report it by \ sending an email to <a href="mailto:'+terria.supportEmail+'">'+terria.supportEmail+'</a>.</p>' }); }); } function cleanAndProxyUrl(catalogGroup, url) { // Strip off the search portion of the URL var uri = new URI(url); uri.search(''); var cleanedUrl = uri.toString(); return proxyCatalogItemUrl(catalogGroup, cleanedUrl, '1d'); } function createGroup(catalogGroup, basePath, folderJson) { var localName = removePathFromName(basePath, folderJson); var newGroup = new ArcGisCatalogGroup(catalogGroup.terria); newGroup.name = replaceUnderscores(localName); newGroup.url = new URI(catalogGroup.url).segment(localName).toString(); newGroup.dataCustodian = catalogGroup.dataCustodian; newGroup.blacklist = catalogGroup.blacklist; if (defined(catalogGroup.itemProperties)) { newGroup.updateFromJson(catalogGroup.itemProperties); } catalogGroup.add(newGroup); return newGroup; } var validServerTypes = ['MapServer', 'FeatureServer']; function createMapOrFeatureServer(catalogGroup, basePath, serviceJson) { var serverTypeIndex = validServerTypes.indexOf(serviceJson.type); if (serverTypeIndex < 0 ) { return; } var localName = removePathFromName(basePath, serviceJson.name); var group; if (serverTypeIndex === 0) { group = new ArcGisMapServerCatalogGroup(catalogGroup.terria); } else { group = new ArcGisFeatureServerCatalogGroup(catalogGroup.terria); } group.name = replaceUnderscores(localName); group.url = new URI(catalogGroup.url).segment(localName).segment(serviceJson.type).toString(); group.dataCustodian = catalogGroup.dataCustodian; group.blacklist = catalogGroup.blacklist; if (defined(catalogGroup.itemProperties)) { for (var propertyName in catalogGroup.itemProperties) { if (catalogGroup.itemProperties.hasOwnProperty(propertyName)) { group[propertyName] = catalogGroup.itemProperties[propertyName]; } } } catalogGroup.add(group); return group; } function getBasePath(catalogGroup) { var match = /rest\/services\/(.*)/i.exec(catalogGroup.url); if (match && match.length > 1) { return match[1]; } else { return ''; } } function removePathFromName(basePath, name) { if (!basePath && basePath.length === 0) { return name; } var index = name.indexOf(basePath); if (index === 0) { return name.substring(basePath.length + 1); } else { return name; } } module.exports = ArcGisCatalogGroup;