Skip to content

Commit

Permalink
Merge pull request #3637 from MV88/align_master_21-03-19
Browse files Browse the repository at this point in the history
Align master 21 03 19 on  c125_annotations branch
  • Loading branch information
MV88 authored Mar 22, 2019
2 parents 1f45a3f + 13b511b commit 323c2e3
Show file tree
Hide file tree
Showing 30 changed files with 542 additions and 26 deletions.
7 changes: 6 additions & 1 deletion docs/developer-guide/maps-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,12 @@ i.e.
"title": "Open Street Map",
"name": "mapnik",
"group": "background",
"visibility": false
"visibility": false,
"credits": { // optional
"imageUrl": "somePic.png", // URL for the image to put in attribution
"link": "http://someURL.org", // URL where attribution have to link to
"title": "text to render" // title to show (as image title or as text)
}
}
```

Expand Down
38 changes: 36 additions & 2 deletions web/client/api/WMS.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const xml2js = require('xml2js');

const capabilitiesCache = {};

const {isArray, castArray} = require('lodash');
const {isArray, castArray, get} = require('lodash');

const parseUrl = (url) => {
const parsed = urlUtil.parse(url, true);
Expand All @@ -29,6 +29,39 @@ const parseUrl = (url) => {
}));
};

/**
* Extract `credits` property from layer's Attribution
* (Web Map Service Implementation Specification OGC 01-068r3 - 7.1.4.5.9 )
* @param {object} attribution Attribution object of WMS Capabilities (parsed with xml2js default format)
* @return {object} an object to place in `credits` attribute of layer with the structure in the example.
* @example
* {
* title: "content of <Title></Title>",
* imageUrl: "url of the image linked as LogoURL",
* link: "http://some.site.of.reference",
* logo: { // more info about the logo
* format: "image/png",
* width: "200",
* height: "100"
* }
* }
*
*/
const extractCredits = attribution => {
const title = attribution && attribution.Title;
const logo = attribution.LogoURL && {
...(get(attribution, 'LogoURL.$') || {}),
format: get(attribution, 'LogoURL.Format') // e.g. image/png
};
const link = get(attribution, 'OnlineResource.$["xlink:href"]');
return {
title,
logo,
imageUrl: get(attribution, 'LogoURL.OnlineResource.$["xlink:href"]'),
link
};
};

const _ = require('lodash');

const flatLayers = (root) => {
Expand All @@ -44,6 +77,7 @@ const searchAndPaginate = (json = {}, startPosition, maxRecords, text) => {
const service = (json.WMS_Capabilities || json.WMT_MS_Capabilities || {}).Service;
const onlineResource = getOnlineResource(root);
const SRSList = root.Layer && (root.Layer.SRS || root.Layer.CRS) || [];
const credits = root.Layer && root.Layer.Attribution && extractCredits(root.Layer.Attribution);
const layersObj = flatLayers(root);
const layers = isArray(layersObj) ? layersObj : [layersObj];
const filteredLayers = layers
Expand All @@ -55,7 +89,7 @@ const searchAndPaginate = (json = {}, startPosition, maxRecords, text) => {
service,
records: filteredLayers
.filter((layer, index) => index >= startPosition - 1 && index < startPosition - 1 + maxRecords)
.map((layer) => assign({}, layer, {onlineResource, SRS: SRSList}))
.map((layer) => assign({}, layer, { onlineResource, SRS: SRSList, credits: layer.Attribution ? extractCredits(layer.Attribution) : credits}))
};
};

Expand Down
16 changes: 16 additions & 0 deletions web/client/api/__tests__/WMS-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,22 @@ describe('Test correctness of the WMS APIs', () => {
}
});
});
it('GetRecords attribution creates the credits object', (done) => {
// note: maxRecords = 2 because of strange pagination system. Need to restore this when fixed
API.getRecords('base/web/client/test-resources/wms/attribution.xml', 0, 2, '').then((result) => {
try {
expect(result).toExist();
expect(result.service).toExist();
expect(result.numberOfRecordsMatched).toBe(2);
expect(result.records[0]).toExist();
expect(result.records[0].credits).toExist();
expect(result.records[0].credits.imageUrl).toBe('logo.png');
done();
} catch (ex) {
done(ex);
}
});
});
it('GetRecords 1.1.1', (done) => {
API.getRecords('base/web/client/test-resources/wms/GetCapabilities-1.1.1.xml', 0, 1, '').then((result) => {
try {
Expand Down
22 changes: 22 additions & 0 deletions web/client/components/map/cesium/__tests__/Layer-test-chrome.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,28 @@ describe('Cesium layer', () => {
expect(map.imageryLayers._layers[0]._imageryProvider._tileProvider._subdomains.length).toBe(1);
expect(map.imageryLayers._layers[0]._imageryProvider.proxy.proxy).toExist();
});
it('wms layer with credits', () => {
var options = {
"type": "wms",
"visibility": true,
"name": "nurc:Arc_Sample",
"group": "Meteo",
"format": "image/png",
"url": "http://demo.geo-solutions.it/geoserver/wms",
credits: {
imageUrl: "test.png",
title: "test"
}
};
// create layers
var layer = ReactDOM.render(
<CesiumLayer type="wms"
options={options} map={map}/>, document.getElementById("container"));

expect(layer).toExist();
expect(map.imageryLayers.length).toBe(1);
expect(map.imageryLayers._layers[0].imageryProvider.credit).toExist();
});
it('creates a wms layer with caching for Cesium map', () => {
var options = {
"type": "wms",
Expand Down
3 changes: 3 additions & 0 deletions web/client/components/map/cesium/plugins/WMSLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,12 @@ function wmsToCesiumOptions(options) {
if (proxyUrl) {
proxy = ProxyUtils.needProxy(options.url) && proxyUrl;
}
const cr = options.credits;
const credit = cr ? new Cesium.Credit(cr.text || cr.title, cr.imageUrl, cr.link) : options.attribution;
// NOTE: can we use opacity to manage visibility?
return assign({
url: "{s}",
credit,
subdomains: getURLs(isArray(options.url) ? options.url : [options.url]),
proxy: proxy && new WMSProxy(proxy) || new NoProxy(),
layers: options.name,
Expand Down
21 changes: 21 additions & 0 deletions web/client/components/map/leaflet/__tests__/Layer-test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,27 @@ describe('Leaflet layer', () => {
map.eachLayer((l) => elevationFunc = l.getElevation);
expect(elevationFunc).toExist();
});
it('creates a wms layer with credits', () => {
const CREDITS1 = {
title: "test"
};
var options = {
"type": "wms",
"visibility": true,
"name": "nurc:Arc_Sample",
"group": "Meteo",
"format": "image/png",
"url": "http://sample.server/geoserver/wms",
credits: CREDITS1
};
// create layers
var layer = ReactDOM.render(
<LeafLetLayer type="wms"
options={options} map={map} />, document.getElementById("container"));
expect(layer).toExist();
// count layers
map.eachLayer( l => expect(l.getAttribution()).toBe(CREDITS1.title));
});

it('creates a wmts layer for leaflet map', () => {
var options = {
Expand Down
4 changes: 3 additions & 1 deletion web/client/components/map/leaflet/plugins/WMSLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const objectAssign = require('object-assign');
const {isArray, isNil} = require('lodash');
const SecurityUtils = require('../../../../utils/SecurityUtils');
const ElevationUtils = require('../../../../utils/ElevationUtils');
const { creditsToAttribution } = require('../../../../utils/LayersUtils');

require('leaflet.nontiledlayer');

L.NonTiledLayer.WMSCustom = L.NonTiledLayer.WMS.extend({
Expand Down Expand Up @@ -156,12 +158,12 @@ const removeNulls = (obj = {}) => {
}, {});
};


function wmsToLeafletOptions(options) {
var opacity = options.opacity !== undefined ? options.opacity : 1;
const params = optionsToVendorParams(options);
// NOTE: can we use opacity to manage visibility?
const result = objectAssign({}, options.baseParams, {
attribution: options.credits && creditsToAttribution(options.credits),
layers: options.name,
styles: options.style || "",
format: options.format || 'image/png',
Expand Down
82 changes: 82 additions & 0 deletions web/client/components/map/openlayers/__tests__/Layer-test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,63 @@ describe('Openlayers layer', () => {
// count layers
expect(map.getLayers().getLength()).toBe(1);
expect(map.getLayers().item(0).getSource().urls.length).toBe(1);
expect(map.getLayers().item(0).getSource().getAttributions()).toNotExist();
});

it('wms layer attribution with credits - create and update layer', () => {
const TEXT1 = "some attribution";
const TEXT2 = "some other attibution";
const CREDITS1 = {
imageUrl: "test.jpg",
title: "test"
};

var options = {
"type": "wms",
"visibility": true,
"name": "nurc:Arc_Sample",
"group": "Meteo",
credits: {
title: TEXT1
},
"format": "image/png",
"url": "http://sample.server/geoserver/wms"
};
// create layers
var layer = ReactDOM.render(
<OpenlayersLayer type="wms"
options={options} map={map} />, document.getElementById("container"));


expect(layer).toExist();
// check creation
expect(map.getLayers().getLength()).toBe(1);
expect(map.getLayers().item(0).getSource().urls.length).toBe(1);
expect(map.getLayers().item(0).getSource().getAttributions()).toExist();
expect(map.getLayers().item(0).getSource().getAttributions()[0].getHTML()).toBe(TEXT1);
// check remove
ReactDOM.render(
<OpenlayersLayer type="wms"
options={{...options, credits: undefined}} map={map} />, document.getElementById("container"));
expect(map.getLayers().item(0).getSource().getAttributions()).toNotExist();
// check update
ReactDOM.render(
<OpenlayersLayer type="wms"
options={{ ...options, credits: {title: TEXT2} }} map={map} />, document.getElementById("container"));
expect(map.getLayers().item(0).getSource().getAttributions()).toExist();
expect(map.getLayers().item(0).getSource().getAttributions()[0].getHTML()).toBe(TEXT2);
// check content update
ReactDOM.render(
<OpenlayersLayer type="wms"
options={options} map={map} />, document.getElementById("container"));
expect(map.getLayers().item(0).getSource().getAttributions()).toExist();
expect(map.getLayers().item(0).getSource().getAttributions()[0].getHTML()).toBe(TEXT1);
// check complex contents
ReactDOM.render(
<OpenlayersLayer type="wms"
options={{...options, credits: CREDITS1}} map={map} />, document.getElementById("container"));
expect(map.getLayers().item(0).getSource().getAttributions()).toExist();
expect(map.getLayers().item(0).getSource().getAttributions()[0].getHTML()).toBe('<img src="test.jpg" title="test">');
});

it('creates a wms elevation layer for openlayers map', () => {
Expand Down Expand Up @@ -309,6 +366,31 @@ describe('Openlayers layer', () => {
// count layers
expect(map.getLayers().getLength()).toBe(1);
expect(map.getLayers().item(0).getSource().getUrl()).toExist();
expect(map.getLayers().item(0).getSource().getAttributions()).toNotExist();
});
it('creates a single tile credits', () => {
var options = {
"type": "wms",
"visibility": true,
"name": "nurc:Arc_Sample",
"group": "Meteo",
"format": "image/png",
"credits": {
title: "some attribution"
},
"singleTile": true,
"url": "http://sample.server/geoserver/wms"
};
// create layers
var layer = ReactDOM.render(
<OpenlayersLayer type="wms"
options={options} map={map} />, document.getElementById("container"));

expect(layer).toExist();
// count layers
expect(map.getLayers().getLength()).toBe(1);
expect(map.getLayers().item(0).getSource().getUrl()).toExist();
expect(map.getLayers().item(0).getSource().getAttributions()).toExist();
});

it('creates a single tile wms layer for openlayers map ratio', (done) => {
Expand Down
19 changes: 17 additions & 2 deletions web/client/components/map/openlayers/plugins/WMSLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ const {isNil} = require('lodash');
const objectAssign = require('object-assign');
const CoordinatesUtils = require('../../../../utils/CoordinatesUtils');
const ProxyUtils = require('../../../../utils/ProxyUtils');
const {isArray} = require('lodash');
const { isArray, castArray } = require('lodash');
const {optionsToVendorParams} = require('../../../../utils/VendorParamsUtils');
const SecurityUtils = require('../../../../utils/SecurityUtils');
const { creditsToAttribution } = require('../../../../utils/LayersUtils');

const mapUtils = require('../../../../utils/MapUtils');
const ElevationUtils = require('../../../../utils/ElevationUtils');
/**
Expand Down Expand Up @@ -112,6 +114,7 @@ function getElevation(pos) {
return <Message msgId="elevationLoadingError" />;
}
}
const toOLAttributions = credits => credits && creditsToAttribution(credits) ? castArray(creditsToAttribution(credits)) : undefined;

Layers.registerType('wms', {
create: (options, map) => {
Expand All @@ -125,6 +128,7 @@ Layers.registerType('wms', {
zIndex: options.zIndex,
source: new ol.source.ImageWMS({
url: urls[0],
attributions: toOLAttributions(options.credits),
params: queryParameters,
ratio: options.ratio || 1
})
Expand All @@ -133,6 +137,7 @@ Layers.registerType('wms', {
const mapSrs = map && map.getView() && map.getView().getProjection() && map.getView().getProjection().getCode() || 'EPSG:3857';
const extent = ol.proj.get(CoordinatesUtils.normalizeSRS(options.srs || mapSrs, options.allowedSRS)).getExtent();
const sourceOptions = addTileLoadFunction({
attributions: toOLAttributions(options.credits),
urls: urls,
params: queryParameters,
tileGrid: new ol.tilegrid.TileGrid({
Expand Down Expand Up @@ -193,7 +198,15 @@ Layers.registerType('wms', {
});
}, {})));
}
if (oldOptions.singleTile !== newOptions.singleTile || oldOptions.securityToken !== newOptions.securityToken || oldOptions.ratio !== newOptions.ratio) {
if (oldOptions.credits !== newOptions.credits && newOptions.credits) {
layer.getSource().setAttributions(toOLAttributions(newOptions.credits));
}
if (oldOptions.singleTile !== newOptions.singleTile
|| oldOptions.securityToken !== newOptions.securityToken
|| oldOptions.ratio !== newOptions.ratio
// no way to remove attribution when credits are removed, so have re-create the layer is needed. Seems to be solved in OL v5.3.0, due to the ol commit 9b8232f65b391d5d381d7a99a7cd070fc36696e9 (https://github.com/openlayers/openlayers/pull/7329)
|| oldOptions.credits !== newOptions.credits && !newOptions.credits
) {
// this forces cache empty, required when auth permission changed to avoid caching when unauthorized
// Moved here to avoid the layer disappearing during animations
if (changed) {
Expand All @@ -212,6 +225,7 @@ Layers.registerType('wms', {
visible: newOptions.visibility !== false,
zIndex: newOptions.zIndex,
source: new ol.source.ImageWMS({
attributions: toOLAttributions(newOptions.credits),
url: urls[0],
params: queryParameters,
ratio: newOptions.ratio || 1
Expand All @@ -226,6 +240,7 @@ Layers.registerType('wms', {
visible: newOptions.visibility !== false,
zIndex: newOptions.zIndex,
source: new ol.source.TileWMS(objectAssign({
attributions: toOLAttributions(newOptions.credits),
urls: urls,
params: queryParameters,
tileGrid: new ol.tilegrid.TileGrid({
Expand Down
2 changes: 1 addition & 1 deletion web/client/components/share/SharePanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class SharePanel extends React.Component {
</Tabs>);

let sharePanel =
(<Dialog id="share-panel-dialog" className="modal-dialog modal-content share-win">
(<Dialog id="share-panel-dialog" className="modal-dialog modal-content share-win" style={{zIndex: 1993}}>
<span role="header">
<span className="share-panel-title">
<Message msgId="share.title"/>
Expand Down
2 changes: 1 addition & 1 deletion web/client/examples/rasterstyler/assets/css/viewer.css
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ html, body, #container, .fill {
display:none;
visibility: hidden;
}
.leaflet-control-attribution a:first-child{
.leaflet-control-attribution > a:first-child{
display:none;
visibility: hidden;
}
Expand Down
2 changes: 1 addition & 1 deletion web/client/examples/styler/assets/css/viewer.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ html, body, #container, .fill {
display:none;
visibility: hidden;
}
.leaflet-control-attribution a:first-child{
.leaflet-control-attribution > a:first-child{
display:none;
visibility: hidden;
}
Expand Down
Loading

0 comments on commit 323c2e3

Please sign in to comment.