diff --git a/contribs/gmf/apps/desktop_alt/Controller.js b/contribs/gmf/apps/desktop_alt/Controller.js index 62c65f8bd20..342d3070319 100644 --- a/contribs/gmf/apps/desktop_alt/Controller.js +++ b/contribs/gmf/apps/desktop_alt/Controller.js @@ -161,7 +161,7 @@ class Controller extends AbstractDesktopController { * @param {JQueryEventObject} event keydown event. */ onKeydown(event) { - if (event.ctrlKey && event.key === 'p') { + if (event && event.ctrlKey && event.key === 'p') { this.printPanelActive = true; event.preventDefault(); } diff --git a/contribs/gmf/src/controllers/AbstractAppController.js b/contribs/gmf/src/controllers/AbstractAppController.js index 8df7b200a73..6d074a4c78f 100644 --- a/contribs/gmf/src/controllers/AbstractAppController.js +++ b/contribs/gmf/src/controllers/AbstractAppController.js @@ -235,7 +235,7 @@ export function AbstractAppController(config, map, $scope, $injector) { if (!themeName) { throw new Error('Missing themeName'); } - this.gmfThemeManager.updateCurrentTheme(themeName, previousThemeName); + this.gmfThemeManager.updateCurrentTheme(themeName, previousThemeName, true); } this.setDefaultBackground_(null); this.updateHasEditableLayers_(); @@ -711,7 +711,7 @@ AbstractAppController.prototype.initLanguage = function() { const browserLanguage = /** @type {string|undefined} */ (this.getBrowserLanguage(Object.keys(this.langUrls))); const urlLanguage = /** @type {string|undefined} */ - (this.stateManager.getInitialValue('lang')); + (this.stateManager.getInitialStringValue('lang')); if (urlLanguage !== undefined && urlLanguage in this.langUrls) { this.switchLanguage(urlLanguage); diff --git a/contribs/gmf/src/datasource/ExternalDataSourcesManager.js b/contribs/gmf/src/datasource/ExternalDataSourcesManager.js index 4168221d5fa..a3029075cef 100644 --- a/contribs/gmf/src/datasource/ExternalDataSourcesManager.js +++ b/contribs/gmf/src/datasource/ExternalDataSourcesManager.js @@ -355,7 +355,7 @@ export class ExternalDatSourcesManager { id: id, name: layer.Title, ogcImageType: ogcImageType, - ogcLayers: [{ + wmsLayers: [{ name: layer.Name, queryable: queryable }], diff --git a/contribs/gmf/src/datasource/Manager.js b/contribs/gmf/src/datasource/Manager.js index 6764ee8567b..bd6407dcd1d 100644 --- a/contribs/gmf/src/datasource/Manager.js +++ b/contribs/gmf/src/datasource/Manager.js @@ -462,7 +462,8 @@ export class DatasourceManager { const ogcType = gmfLayer.type; let maxResolution = 0; let minResolution = 0; - let ogcLayers; + let wmsLayers; + let wfsLayers; let ogcServer; let wmtsLayer; let wmtsUrl; @@ -482,7 +483,13 @@ export class DatasourceManager { // OGC Layers const layers = meta.queryLayers || meta.wmsLayers; if (layers) { - ogcLayers = layers.split(',').map((layer) => { + wmsLayers = layers.split(',').map((layer) => { + return { + name: layer, + queryable: true + }; + }); + wfsLayers = layers.split(',').map((layer) => { return { maxResolution: maxResolution, minResolution: minResolution, @@ -506,7 +513,20 @@ export class DatasourceManager { minResolution = gmfLayerWMS.minResolutionHint; // OGC Layers - ogcLayers = gmfLayerWMS.childLayers.map((childLayer) => { + let queryable = false; + for (const wfslayer of gmfLayerWMS.childLayers) { + if (wfslayer.queryable) { + queryable = true; + break; + } + } + wmsLayers = gmfLayerWMS.layers.split(',').map((childLayer) => { + return { + name: childLayer, + queryable: queryable, + }; + }); + wfsLayers = gmfLayerWMS.childLayers.map((childLayer) => { return { maxResolution: childLayer.maxResolutionHint, minResolution: childLayer.minResolutionHint, @@ -601,8 +621,11 @@ export class DatasourceManager { if (ogcImageType) { options.ogcImageType = ogcImageType; } - if (ogcLayers) { - options.ogcLayers = ogcLayers; + if (wmsLayers) { + options.wmsLayers = wmsLayers; + } + if (wfsLayers) { + options.wfsLayers = wfsLayers; } if (ogcServerType) { options.ogcServerType = ogcServerType; diff --git a/contribs/gmf/src/datasource/OGC.js b/contribs/gmf/src/datasource/OGC.js index 9a7b887afd0..806f8946f0d 100644 --- a/contribs/gmf/src/datasource/OGC.js +++ b/contribs/gmf/src/datasource/OGC.js @@ -27,8 +27,10 @@ import ngeoDatasourceOGC from 'ngeo/datasource/OGC.js'; * @property {boolean} [filtrable] Whether the data source is filtrable or not. * @property {string} [geometryName] The name of the geometry attribute. * @property {string} [ogcImageType] The type of images to fetch by queries by the (WMS) or (WMTS). - * @property {Array} [ogcLayers] A list of layer definitions that - * are used by (WMS) and (WFS) queries. + * @property {Array} [wmsLayers] A list of layer definitions that are used by WMS queries. + * These are **not** used by the (WMTS) queries (the wmtsLayers is used by WMTS queries). + * @property {Array} [wfsLayers] A list of layer definitions that + * are used by WFS queries. * These are **not** used by the (WMTS) queries (the wmtsLayers is used by WMTS queries). * @property {string} [ogcServerType] The type of OGC server. * @property {string} [ogcType] The type data source. Can be: 'WMS' or 'WMTS'. diff --git a/contribs/gmf/src/datasource/WFSAliases.js b/contribs/gmf/src/datasource/WFSAliases.js index f024cacedf7..7d74cb2cd62 100644 --- a/contribs/gmf/src/datasource/WFSAliases.js +++ b/contribs/gmf/src/datasource/WFSAliases.js @@ -37,7 +37,7 @@ export class DatasourceWFSAlias { // Only QGIS Server supports WFS aliases if (dataSource.ogcServerType === ServerType.QGISSERVER && dataSource.wfsUrl_ && - dataSource.getOGCLayerNames().length == 1 && + dataSource.getWFSLayerNames().length == 1 && !dataSource.attributes) { // Trigger an additional WFS DescribeFeatureType request to get // datasource attributes, including aliases. diff --git a/contribs/gmf/src/filters/filterselectorComponent.js b/contribs/gmf/src/filters/filterselectorComponent.js index 358059bb41a..aabb1648275 100644 --- a/contribs/gmf/src/filters/filterselectorComponent.js +++ b/contribs/gmf/src/filters/filterselectorComponent.js @@ -489,7 +489,7 @@ class FilterSelectorController { * * 1) have its name in the list of filtrable layer node names * 2) support WFS - * 3) have only one ogcLayers defined + * 3) have only one wfsLayers defined * 4) the ogcLayer must be queryable * * If 1) is true but not any of the others, then the server has not been @@ -527,14 +527,14 @@ class FilterSelectorController { } // (3) The DS must have only one ogcLayer - if (!dataSource.ogcLayers || !dataSource.ogcLayers.length) { + if (!dataSource.wfsLayers || !dataSource.wfsLayers.length) { msgs.push(gettext.getString( - 'The data source must have only 1 ogcLayer defined.' + 'The data source must have only 1 wfsLayer defined.' )); - } else if (!dataSource.ogcLayers[0].queryable) { + } else if (!dataSource.wfsLayers[0].queryable) { // (4) The ogcLayer must be queryable msgs.push(gettext.getString( - 'The ogcLayer within the data source must be queryable.' + 'The wfsLayer within the data source must be queryable.' )); } diff --git a/contribs/gmf/src/index.js b/contribs/gmf/src/index.js index 0df2b7aa8f9..1430a622d85 100644 --- a/contribs/gmf/src/index.js +++ b/contribs/gmf/src/index.js @@ -25,6 +25,7 @@ export const COORDINATES_LAYER_NAME = 'gmfCoordinatesLayerName'; */ export const PermalinkParam = { BG_LAYER: 'baselayer_ref', + BG_LAYER_OPACITY: 'baselayer_opacity', EXTERNAL_DATASOURCES_NAMES: 'eds_n', EXTERNAL_DATASOURCES_URLS: 'eds_u', FEATURES: 'rl_features', diff --git a/contribs/gmf/src/layertree/TreeManager.js b/contribs/gmf/src/layertree/TreeManager.js index 2dd33347e49..8fdb35ee954 100644 --- a/contribs/gmf/src/layertree/TreeManager.js +++ b/contribs/gmf/src/layertree/TreeManager.js @@ -179,7 +179,7 @@ LayertreeTreeManager.prototype.setFirstLevelGroups = function(firstLevelGroups) * group. * @param {boolean=} opt_add if true, force to use the 'add' mode this time. * @param {boolean=} opt_silent if true notifyCantAddGroups_ is not called. - * @return{boolean} True if the group has been added. False otherwise. + * @return {boolean} True if the group has been added. False otherwise. */ LayertreeTreeManager.prototype.addFirstLevelGroups = function(firstLevelGroups, opt_add, opt_silent) { /** @type {import('gmf/themes.js').GmfGroup[]} */ diff --git a/contribs/gmf/src/permalink/Permalink.js b/contribs/gmf/src/permalink/Permalink.js index 2b45c8b34ab..8a6e07d5f99 100644 --- a/contribs/gmf/src/permalink/Permalink.js +++ b/contribs/gmf/src/permalink/Permalink.js @@ -536,7 +536,8 @@ export function PermalinkService( this.ngeoBackgroundLayerMgr_, 'change', this.handleBackgroundLayerManagerChange_, - this); + this + ); } // visibility @@ -890,7 +891,6 @@ PermalinkService.prototype.setMap = function(map) { this.registerMap_(map, null); } } - }; @@ -996,8 +996,7 @@ PermalinkService.prototype.unregisterMap_ = function() { /** - * Get the background layer object to use to initialize the map from the - * state manager. + * Get the background layer object to use to initialize the map from the state manager. * @param {Array} layers Array of background layer objects. * @return {?import("ol/layer/Base.js").default} Background layer. */ @@ -1014,6 +1013,16 @@ PermalinkService.prototype.getBackgroundLayer = function(layers) { }; +/** + * Get the background layer opacity to use to initialize the map from the state manager. + * @return {?number} Opacity. + */ +PermalinkService.prototype.getBackgroundLayerOpacity = function() { + const opacity_ = this.ngeoStateManager_.getInitialNumberValue(PermalinkParam.BG_LAYER_OPACITY); + return opacity_ === undefined ? null : opacity_ / 100; +}; + + /** * Called when the background layer changes. Update the state using the * background layer label, i.e. its name. @@ -1037,6 +1046,31 @@ PermalinkService.prototype.handleBackgroundLayerManagerChange_ = function() { const object = {}; object[PermalinkParam.BG_LAYER] = layerName; this.ngeoStateManager_.updateState(object); + + const backgroundLayer = this.ngeoBackgroundLayerMgr_.getOpacityBgLayer(this.map_); + if (backgroundLayer) { + const opacity = this.getBackgroundLayerOpacity(); + if (opacity !== null) { + backgroundLayer.setOpacity(opacity); + } else { + const opacity = backgroundLayer.getOpacity(); + /** @type {Object} */ + const object = {}; + object[PermalinkParam.BG_LAYER_OPACITY] = `${opacity * 100}`; + this.ngeoStateManager_.updateState(object); + } + olEvents.listen( + backgroundLayer, + 'change:opacity', + () => { + const opacity = backgroundLayer.getOpacity(); + /** @type {Object} */ + const object = {}; + object[PermalinkParam.BG_LAYER_OPACITY] = `${opacity * 100}`; + this.ngeoStateManager_.updateState(object); + } + ); + } }; @@ -1476,9 +1510,9 @@ PermalinkService.prototype.initExternalDataSources_ = function() { const promises = []; - const layerNamesString = this.ngeoStateManager_.getInitialValue( + const layerNamesString = this.ngeoStateManager_.getInitialStringValue( PermalinkParam.EXTERNAL_DATASOURCES_NAMES); - const urlsString = this.ngeoStateManager_.getInitialValue( + const urlsString = this.ngeoStateManager_.getInitialStringValue( PermalinkParam.EXTERNAL_DATASOURCES_URLS); if (layerNamesString && urlsString) { @@ -1724,7 +1758,7 @@ PermalinkService.prototype.setExternalDataSourcesState_ = function() { // External WMS data sources always have only one OGC layer name, // as they are created using a single Capability Layer object that // has only 1 layer name - const layerName = wmsDataSource.getOGCLayerNames()[0]; + const layerName = wmsDataSource.getWFSLayerNames()[0]; wmsGroupLayerNames.push(layerName); } } diff --git a/contribs/gmf/src/query/window.scss b/contribs/gmf/src/query/window.scss index 354fb48c39e..096ccc1515f 100644 --- a/contribs/gmf/src/query/window.scss +++ b/contribs/gmf/src/query/window.scss @@ -62,7 +62,6 @@ div.ngeo-displaywindow { flex-direction: column; width: 100%; height: 100%; - padding: $app-margin; text-align: left; white-space: nowrap; overflow: hidden; @@ -76,6 +75,14 @@ div.ngeo-displaywindow { .content-template-container { overflow: auto; } + .header { + padding: $app-margin $app-margin 0 $app-margin; + } + .details { + padding: 0 $app-margin $app-margin $app-margin; + // small margin so that the scrollbar and the window resize are not in conflict. + margin-right: $half-app-margin; + } } } .animation-container-detailed { diff --git a/contribs/gmf/src/query/windowComponent.html b/contribs/gmf/src/query/windowComponent.html index 34798247d5b..d99fcd089d8 100644 --- a/contribs/gmf/src/query/windowComponent.html +++ b/contribs/gmf/src/query/windowComponent.html @@ -34,7 +34,7 @@ ng-animate-swap="ctrl.animate" class="slide-animation gmf-animatable"> -
+

{{ctrl.source.label | translate}}

diff --git a/contribs/gmf/src/query/windowComponent.js b/contribs/gmf/src/query/windowComponent.js index 2fa83853a11..e1e7f4d6bb3 100644 --- a/contribs/gmf/src/query/windowComponent.js +++ b/contribs/gmf/src/query/windowComponent.js @@ -324,14 +324,15 @@ QueryWindowController.prototype.$onInit = function() { } highlightFeaturesOverlay.setStyle(highlightFeatureStyle); + const windowContainer = this.element_.find('.gmf-displayquerywindow .windowcontainer'); if (this.desktop) { - this.element_.find('.gmf-displayquerywindow .windowcontainer').draggable({ - 'cancel': 'input,textarea,button,select,option,tr', - 'containment': this.draggableContainment + windowContainer.draggable({ + handle: '.header', + containment: this.draggableContainment }); - this.element_.find('.gmf-displayquerywindow .windowcontainer').resizable({ - 'minHeight': 240, - 'minWidth': 240 + windowContainer.resizable({ + minHeight: 240, + minWidth: 240 }); } }; diff --git a/contribs/gmf/src/theme/Manager.js b/contribs/gmf/src/theme/Manager.js index 4af3b5289f3..84ffea8b20a 100644 --- a/contribs/gmf/src/theme/Manager.js +++ b/contribs/gmf/src/theme/Manager.js @@ -119,15 +119,16 @@ ThemeManagerService.prototype.isLoading = function() { /** * @param {string} themeName wanted theme name. * @param {string} fallbackThemeName fallback theme name. + * @param {boolean=} opt_silent if true notifyCantAddGroups_ is not called. * @export */ -ThemeManagerService.prototype.updateCurrentTheme = function(themeName, fallbackThemeName) { +ThemeManagerService.prototype.updateCurrentTheme = function(themeName, fallbackThemeName, opt_silent) { this.gmfThemes_.getThemesObject().then((themes) => { if (!themeName && this.modeFlush) { // In flush mode load current theme private groups const fallbackTheme = findThemeByName(themes, fallbackThemeName); if (fallbackTheme) { - this.gmfTreeManager_.addFirstLevelGroups(fallbackTheme.children, false, false); + this.gmfTreeManager_.addFirstLevelGroups(fallbackTheme.children, false, opt_silent); } } if (themeName) { diff --git a/examples/bboxquery.js b/examples/bboxquery.js index cde4f12a5c4..842a3ea86c7 100644 --- a/examples/bboxquery.js +++ b/examples/bboxquery.js @@ -136,7 +136,11 @@ function MainController($scope, ngeoDataSources) { visible: true, wfsFeatureNS: MAPSERVER_WFS_FEATURE_NS, wfsUrl: MAPSERVER_PROXY, - ogcLayers: [{ + wmsLayers: [{ + name: 'bus_stop', + queryable: true + }], + wfsLayers: [{ name: 'bus_stop', queryable: true }] @@ -148,7 +152,11 @@ function MainController($scope, ngeoDataSources) { visible: true, wfsFeatureNS: MAPSERVER_WFS_FEATURE_NS, wfsUrl: MAPSERVER_PROXY, - ogcLayers: [{ + wmsLayers: [{ + name: 'information', + queryable: true + }], + wfsLayers: [{ name: 'information', queryable: true }] diff --git a/examples/mapquery.js b/examples/mapquery.js index a943d883ffc..b2c239f4980 100644 --- a/examples/mapquery.js +++ b/examples/mapquery.js @@ -147,7 +147,11 @@ function MainController($scope, ngeoDataSources, ngeoToolActivateMgr) { name: 'bus_stop', visible: true, wmsUrl: MAPSERVER_PROXY, - ogcLayers: [{ + wmsLayers: [{ + name: 'bus_stop', + queryable: true + }], + wfsLayers: [{ name: 'bus_stop', queryable: true }] @@ -158,7 +162,11 @@ function MainController($scope, ngeoDataSources, ngeoToolActivateMgr) { name: 'information', visible: true, wmsUrl: MAPSERVER_PROXY, - ogcLayers: [{ + wmsLayers: [{ + name: 'information', + queryable: true + }], + wfsLayers: [{ name: 'information', queryable: true }] diff --git a/src/datasource/Helper.js b/src/datasource/Helper.js index 94beb149714..2f72bb0bea2 100644 --- a/src/datasource/Helper.js +++ b/src/datasource/Helper.js @@ -96,7 +96,7 @@ export class DatasourceHelper { this.ngeoQuerent_.wfsDescribeFeatureType(dataSource).then((featureType_) => { // We know, at this point, that there's only one definition that // was returned. Just to be sure, let's do a bunch of assertions. - const ogcLayerName = dataSource.getOGCLayerNames()[0]; + const ogcLayerName = dataSource.getWFSLayerNames()[0]; console.assert(typeof ogcLayerName == 'string', 'The data source should have only one ogcLayer.'); const featureType = /** @type {Object} */(/** @type {unknown} */(featureType_)); for (const element of featureType.element) { diff --git a/src/datasource/OGC.js b/src/datasource/OGC.js index 2392c719bb9..34feeec0c1b 100644 --- a/src/datasource/OGC.js +++ b/src/datasource/OGC.js @@ -99,8 +99,9 @@ export const WMSInfoFormat = { * @property {boolean} [filtrable] Whether the data source is filtrable or not. * @property {string} [geometryName] The name of the geometry attribute. * @property {string} [ogcImageType] The type of images to fetch by queries by the (WMS) or (WMTS). - * @property {OGCLayer[]} [ogcLayers] A list of layer definitions that are used by (WMS) and (WFS) - * queries. + * @property {WMSLayer[]} [wmsLayers] A list of layer definitions that are used by WMS queries. + * These are **not** used by the (WMTS) queries (the wmtsLayers is used by WMTS queries). + * @property {WFSLayer[]} [wfsLayers] A list of layer definitions that are used by WFS queries. * These are **not** used by the (WMTS) queries (the wmtsLayers is used by WMTS queries). * @property {string} [ogcServerType] The type of OGC server. * @property {string} [ogcType] The type data source. Can be: 'WMS' or 'WMTS'. @@ -142,7 +143,16 @@ export const WMSInfoFormat = { /** * The definition of a single layer (WMS) and/or featureType (WFS). * - * @typedef {Object} OGCLayer + * @typedef {Object} WMSLayer + * @property {string} name The layer name (WMS) and/or feature type name (WFS) + * @property {boolean} [queryable] Whether the the layer is queryable or not. Defaults to `false`. + */ + + +/** + * The definition of a single layer (WMS) and/or featureType (WFS). + * + * @typedef {Object} WFSLayer * @property {number} [maxResolution] The maximum resolution the layer should be rendered (when visible). * @property {number} [minResolution] The minimum resolution the layer should be rendered (when visible). * @property {string} name The layer name (WMS) and/or feature type name (WFS) @@ -280,13 +290,22 @@ class OGC extends ngeoDatasourceDataSource { this.ogcImageType_ = options.ogcImageType || 'image/png'; /** - * A list of layer definitions that are used by (WMS) and (WFS) queries. + * A list of layer definitions that are used by WMS queries. + * These are **not** used by the (WMTS) queries (the wmtsLayers is used + * by WMTS queries). + * @type {?Array} + * @private + */ + this.wmsLayers_ = options.wmsLayers || null; + + /** + * A list of layer definitions that are used by WFS queries. * These are **not** used by the (WMTS) queries (the wmtsLayers is used * by WMTS queries). - * @type {?OGCLayer[]} + * @type {?WFSLayer[]} * @private */ - this.ogcLayers_ = options.ogcLayers || null; + this.wfsLayers_ = options.wfsLayers || null; /** * The type of OGC server making the requests. @@ -430,17 +449,30 @@ class OGC extends ngeoDatasourceDataSource { // === Calculated properties === // Get queryable ogc layer names - const layers = []; - if (this.queryable && this.ogcLayers) { - for (const ogcLayer of this.ogcLayers) { - if (ogcLayer.queryable) { - layers.push(ogcLayer.name); + const wfsLayers = []; + if (this.queryable && this.wfsLayers) { + for (const wfsLayer of this.wfsLayers) { + if (wfsLayer.queryable) { + wfsLayers.push(wfsLayer.name); + } + } + } + const wmsLayers = []; + if (this.queryable) { + for (const wmsLayer of (this.wmsLayers || [])) { + if (wmsLayer.queryable) { + wmsLayers.push(wmsLayer.name); + } + } + for (const wfsLayer of this.wfsLayers || []) { + if (wfsLayer.queryable) { + wmsLayers.push(wfsLayer.name); } } } let wfsFormat = null; - if (this.supportsWFS && layers.length) { + if (this.supportsWFS && wfsLayers.length) { let format; if (this.wfsOutputFormat_ === WFSOutputFormat.GML3) { format = new olFormatGML3(); @@ -452,7 +484,7 @@ class OGC extends ngeoDatasourceDataSource { console.assert(format); wfsFormat = new olFormatWFS({ featureNS: this.wfsFeatureNS, - featureType: layers, + featureType: wfsLayers, gmlFormat: format }); } @@ -464,10 +496,10 @@ class OGC extends ngeoDatasourceDataSource { this.wfsFormat_ = wfsFormat; let wmsFormat = null; - if (this.supportsWMS && layers.length) { + if (this.supportsWMS && wmsLayers.length) { if (this.wmsInfoFormat === WMSInfoFormat.GML) { wmsFormat = new olFormatWMSGetFeatureInfo({ - layers + layers: wmsLayers }); } // Todo, support more formats for WMS @@ -577,10 +609,17 @@ class OGC extends ngeoDatasourceDataSource { } /** - * @return {?OGCLayer[]} OGC layers + * @return {?WMSLayer[]} WMS layers */ - get ogcLayers() { - return this.ogcLayers_; + get wmsLayers() { + return this.wmsLayers_; + } + + /** + * @return {?Array} TFS layers + */ + get wfsLayers() { + return this.wfsLayers_; } /** @@ -769,15 +808,17 @@ class OGC extends ngeoDatasourceDataSource { */ get queryable() { let queryable = false; - const supportsOGCQueries = this.supportsWMS || this.supportsWFS; - if (supportsOGCQueries && this.ogcLayers) { - for (const ogcLayer of this.ogcLayers) { - if (ogcLayer.queryable === true) { + if (this.supportsWFS && this.wfsLayers) { + for (const wfsLayer of this.wfsLayers) { + if (wfsLayer.queryable === true) { queryable = true; break; } } } + if (this.supportsWMS && this.wmsLayers && this.wmsLayers.length > 0) { + queryable = true; + } return queryable; } @@ -804,9 +845,9 @@ class OGC extends ngeoDatasourceDataSource { get supportsAttributes() { return this.attributes !== null || ( this.supportsWFS && - this.ogcLayers !== null && - this.ogcLayers.length === 1 && - this.ogcLayers[0].queryable === true + this.wfsLayers !== null && + this.wfsLayers.length === 1 && + this.wfsLayers[0].queryable === true ); } @@ -881,31 +922,52 @@ class OGC extends ngeoDatasourceDataSource { * @return {boolean} At least one OGC layer is in range. */ isAnyOGCLayerInRange(res, queryableOnly = false) { - return !!(this.getInRangeOGCLayerNames(res, queryableOnly).length); + return !!(this.getInRangeWFSLayerNames(res, queryableOnly).length); + } + + /** + * Returns the list of WMS layer names. + * @param {boolean} queryableOnly Whether to additionally check if the + * WMS layer is queryable as well or not. Defaults to `false`. + * @return {Array} The WMS layer names. + */ + getWMSLayerNames(queryableOnly = false) { + + const layerNames = []; + + if (this.wmsLayers) { + for (const wmsLayer of this.wmsLayers) { + if (!queryableOnly || wmsLayer.queryable) { + layerNames.push(wmsLayer.name); + } + } + } + + return layerNames; } /** - * Returns a list of OGC layer names that are in range of a given resolution. - * If there's no OGC layers defined, an empty array is returned. + * Returns a list of WFS layer names that are in range of a given resolution. + * If there's no WFS layers defined, an empty array is returned. * @param {number} res Resolution. * @param {boolean} queryableOnly Whether to additionally check if the - * OGC layer is queryable as well or not. Defaults to `false`. - * @return {string[]} The OGC layer names that are in range. + * WFS layer is queryable as well or not. Defaults to `false`. + * @return {string[]} The WFS layer names that are in range. */ - getInRangeOGCLayerNames(res, queryableOnly = false) { + getInRangeWFSLayerNames(res, queryableOnly = false) { const layerNames = []; - if (this.ogcLayers) { - for (const ogcLayer of this.ogcLayers) { - const maxRes = ogcLayer.maxResolution; - const minRes = ogcLayer.minResolution; + if (this.wfsLayers) { + for (const wfsLayer of this.wfsLayers) { + const maxRes = wfsLayer.maxResolution; + const minRes = wfsLayer.minResolution; const inMinRange = minRes === undefined || res >= minRes; const inMaxRange = maxRes === undefined || res <= maxRes; const inRange = inMinRange && inMaxRange; - if (inRange && (!queryableOnly || ogcLayer.queryable)) { - layerNames.push(ogcLayer.name); + if (inRange && (!queryableOnly || wfsLayer.queryable)) { + layerNames.push(wfsLayer.name); } } } @@ -914,19 +976,19 @@ class OGC extends ngeoDatasourceDataSource { } /** - * Returns the list of OGC layer names. + * Returns the list of WFS layer names. * @param {boolean} queryableOnly Whether to additionally check if the - * OGC layer is queryable as well or not. Defaults to `false`. - * @return {string[]} The OGC layer names. + * WFS layer is queryable as well or not. Defaults to `false`. + * @return {string[]} The WFS layer names. */ - getOGCLayerNames(queryableOnly = false) { + getWFSLayerNames(queryableOnly = false) { const layerNames = []; - if (this.ogcLayers) { - for (const ogcLayer of this.ogcLayers) { - if (!queryableOnly || ogcLayer.queryable) { - layerNames.push(ogcLayer.name); + if (this.wfsLayers) { + for (const wfsLayer of this.wfsLayers) { + if (!queryableOnly || wfsLayer.queryable) { + layerNames.push(wfsLayer.name); } } } @@ -935,13 +997,13 @@ class OGC extends ngeoDatasourceDataSource { } /** - * Returns the filtrable OGC layer name. This methods asserts that + * Returns the filtrable WFS layer name. This methods asserts that * the name exists and is filtrable. - * @return {string} OGC layer name. + * @return {string} WFS layer name. */ - getFiltrableOGCLayerName() { + getFiltrableWFSLayerName() { console.assert(this.filtrable); - const layerNames = this.getOGCLayerNames(); + const layerNames = this.getWFSLayerNames(); console.assert(layerNames.length === 1); return layerNames[0]; } diff --git a/src/datasource/WMSGroup.js b/src/datasource/WMSGroup.js index 199d73baa96..73136911158 100644 --- a/src/datasource/WMSGroup.js +++ b/src/datasource/WMSGroup.js @@ -172,7 +172,7 @@ export default class extends ngeoDatasourceOGCGroup { // (1) Collect layer names from data sources in the group for (const dataSource of this.dataSources) { if (dataSource instanceof ngeoDatasourceOGC && dataSource.visible) { - layerNames = layerNames.concat(dataSource.getOGCLayerNames()); + layerNames = layerNames.concat(dataSource.getWFSLayerNames()); } } diff --git a/src/map/LayerHelper.js b/src/map/LayerHelper.js index 2058384f9a4..28754089500 100644 --- a/src/map/LayerHelper.js +++ b/src/map/LayerHelper.js @@ -127,7 +127,7 @@ LayerHelper.prototype.createBasicWMSLayerFromDataSource = function( throw new Error('Missing url'); } - const layerNames = dataSource.getOGCLayerNames().join(','); + const layerNames = dataSource.getWFSLayerNames().join(','); const serverType = dataSource.ogcServerType; const imageType = dataSource.ogcImageType; diff --git a/src/misc/filters.js b/src/misc/filters.js index f978be5d311..0acf3b0d9cd 100644 --- a/src/misc/filters.js +++ b/src/misc/filters.js @@ -561,14 +561,16 @@ module.constant('ngeoStringToHtmlReplacements', StringToHtmlReplacements); /** * A filter used to remove the CDATA prefix and postfix. * - * @return {function(string): string} Result string + * @return {function(string): string|void} Result string * @ngdoc filter * @ngname ngeoDuration * @hidden */ const removeCDATA = function() { return function(input) { - return input.replace(//, '$1'); + if (input && input.replace) { + return input.replace(//, '$1'); + } }; }; diff --git a/src/query/Querent.js b/src/query/Querent.js index af23f7a0e95..7349a7e58a9 100644 --- a/src/query/Querent.js +++ b/src/query/Querent.js @@ -260,13 +260,13 @@ export class Querent { throw new Error('Missing WFS URL'); } - const ogcLayerNames = dataSource.getOGCLayerNames(); + const wfsLayerNames = dataSource.getWFSLayerNames(); const url = olUriAppendParams(dataSource.wfsUrl, { 'REQUEST': 'DescribeFeatureType', 'SERVICE': 'WFS', 'VERSION': '2.0.0', - 'TYPENAME': ogcLayerNames + 'TYPENAME': wfsLayerNames }); return this.http_.get(url).then((response) => { @@ -444,7 +444,7 @@ export class Querent { * The type will be stocked in the properties of the features as * "ngeo_feature_type_". * @param {ngeoDatasourceOGC} dataSource used to read the features. - * @param {Document|Node|Object|string} data the response data. + * @param {Document|Element|string} data the response data. * @param {boolean} wfs Whether the query was WFS or WMS. * @return {Array} returned features with a type in each features. * @private @@ -602,8 +602,7 @@ export class Querent { } // (b) Add queryable layer names in featureTypes array - featureTypes = featureTypes.concat( - dataSource.getInRangeOGCLayerNames(resolution, true)); + featureTypes = featureTypes.concat(dataSource.getInRangeWFSLayerNames(resolution, true)); // (c) Add filter, if any. If the case, then only one data source // is expected to be used for this request. @@ -805,8 +804,7 @@ export class Querent { } // (b) Add queryable layer names in featureTypes array - LAYERS = LAYERS.concat( - dataSource.getInRangeOGCLayerNames(resolution, true)); + LAYERS = LAYERS.concat(dataSource.getWMSLayerNames(true)); // (c) Manage active dimensions, which are added directly to the // query parameters. Note that this occurs only ONCE, i.e. @@ -823,7 +821,7 @@ export class Querent { // data source only. if (dataSource.filterRules && dataSource.filterRules.length) { console.assert(dataSources.length === 1); - filtrableLayerName = dataSource.getFiltrableOGCLayerName(); + filtrableLayerName = dataSource.getFiltrableWFSLayerName(); filterString = this.ngeoRuleHelper_.createFilterString({ dataSource: dataSource, srsName: projCode diff --git a/src/statemanager/Service.js b/src/statemanager/Service.js index 0afd33ecc40..4d00f9c7552 100644 --- a/src/statemanager/Service.js +++ b/src/statemanager/Service.js @@ -105,26 +105,13 @@ export class StatemanagerService { return this.useLocalStorage_; } - /** - * Get the state value for `key`. - * @param {string} key State key. - * @return {string|undefined} State value. - */ - getInitialValue(key) { - return this.initialState[key]; - } - /** * Get the state value for `key`. * @param {string} key State key. * @return {string|undefined} State value. */ getInitialStringValue(key) { - const value = this.initialState[key]; - if (value === undefined) { - return undefined; - } - return value; + return this.initialState[key]; } /**