Skip to content

Commit

Permalink
[Maps] Add attribution handling for TMS (config & UI-entry) and WMS (e…
Browse files Browse the repository at this point in the history
…lastic#44147)

* Add attribution for tms from config

* Add attribution entry fields & logic for tms from URL

* Set text and url fields invalid if both aren't present

* Don't return attribution unless both text and url defined

* Add wms inputs & handling

* Debounce input to prevent constantly generating new layers on keypress

* Remove unapplicable placeholder text on WMS attribution inputs
  • Loading branch information
Aaron Caldwell committed Aug 29, 2019
1 parent 235483d commit 1315724
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,17 +118,7 @@ export class EMSTMSSource extends AbstractTMSSource {
if (!markdown) {
return [];
}

return markdown.split('|').map((attribution) => {
attribution = attribution.trim();
//this assumes attribution is plain markdown link
const extractLink = /\[(.*)\]\((.*)\)/;
const result = extractLink.exec(attribution);
return {
label: result ? result[1] : null,
url: result ? result[2] : null
};
});
return this.convertMarkdownLinkToObjectArr(markdown);
}

async getUrlTemplate() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { CreateSourceEditor } from './create_source_editor';
import { getKibanaTileMap } from '../../../meta';
import { i18n } from '@kbn/i18n';
import { getDataSourceLabel } from '../../../../common/i18n_getters';
import _ from 'lodash';

export class KibanaTilemapSource extends AbstractTMSSource {

Expand Down Expand Up @@ -77,6 +78,13 @@ export class KibanaTilemapSource extends AbstractTMSSource {
return tilemap.url;
}

async getAttributions() {
const tilemap = getKibanaTileMap();
const markdown = _.get(tilemap, 'options.attribution', '');
const objArr = this.convertMarkdownLinkToObjectArr(markdown);
return objArr;
}

async getDisplayName() {
try {
return await this.getUrlTemplate();
Expand Down
14 changes: 14 additions & 0 deletions x-pack/legacy/plugins/maps/public/layers/sources/tms_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,18 @@ export class AbstractTMSSource extends AbstractSource {
async getUrlTemplate() {
throw new Error('Should implement TMSSource#getUrlTemplate');
}

convertMarkdownLinkToObjectArr(markdown) {
return markdown.split('|').map((attribution) => {
attribution = attribution.trim();
//this assumes attribution is plain markdown link
const extractLink = /\[(.*)\]\((.*)\)/;
const result = extractLink.exec(attribution);
return {
label: result ? result[1] : null,
url: result ? result[2] : null
};
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
EuiSpacer,
} from '@elastic/eui';
import { WmsClient } from './wms_client';
import _ from 'lodash';

const LAYERS_LABEL = i18n.translate('xpack.maps.source.wms.layersLabel', {
defaultMessage: 'Layers'
Expand All @@ -38,8 +39,9 @@ export class WMSCreateSourceEditor extends Component {
styleOptions: [],
selectedLayerOptions: [],
selectedStyleOptions: [],
attributionText: '',
attributionUrl: '',
}

componentDidMount() {
this._isMounted = true;
}
Expand All @@ -48,18 +50,26 @@ export class WMSCreateSourceEditor extends Component {
this._isMounted = false;
}

_previewIfPossible() {
_previewIfPossible = _.debounce(() => {
const {
serviceUrl,
layers,
styles
styles,
attributionText,
attributionUrl,
} = this.state;

const sourceConfig = (serviceUrl && layers)
? { serviceUrl, layers, styles }
? {
serviceUrl,
layers,
styles,
attributionText,
attributionUrl,
}
: null;
this.props.onSourceConfigChange(sourceConfig);
}
}, 2000);

_loadCapabilities = async () => {
if (!this.state.serviceUrl) {
Expand Down Expand Up @@ -137,6 +147,18 @@ export class WMSCreateSourceEditor extends Component {
}, this._previewIfPossible);
}

_handleWMSAttributionChange(attributionUpdate) {
const {
attributionText,
attributionUrl,
} = this.state;
this.setState(attributionUpdate, () => {
if (attributionText && attributionUrl) {
this._previewIfPossible();
}
});
}

_renderLayerAndStyleInputs() {
if (!this.state.hasAttemptedToLoadCapabilities || this.state.isLoadingCapabilities) {
return null;
Expand Down Expand Up @@ -226,6 +248,54 @@ export class WMSCreateSourceEditor extends Component {
);
}

_renderAttributionInputs() {
if (!this.state.layers) {
return;
}

const {
attributionText,
attributionUrl,
} = this.state;

return (
<Fragment>
<EuiFormRow
label="Attribution text"
isInvalid={attributionUrl !== '' && attributionText === ''}
error={[
i18n.translate('xpack.maps.source.wms.attributionText', {
defaultMessage:
'Attribution url must have accompanying text',
})
]}
>
<EuiFieldText
onChange={({ target }) =>
this._handleWMSAttributionChange({ attributionText: target.value })
}
/>
</EuiFormRow>
<EuiFormRow
label="Attribution link"
isInvalid={attributionText !== '' && attributionUrl === ''}
error={[
i18n.translate('xpack.maps.source.wms.attributionLink', {
defaultMessage:
'Attribution text must have an accompanying link',
})
]}
>
<EuiFieldText
onChange={({ target }) =>
this._handleWMSAttributionChange({ attributionUrl: target.value })
}
/>
</EuiFormRow>
</Fragment>
);
}

render() {
return (
<EuiForm>
Expand All @@ -244,6 +314,8 @@ export class WMSCreateSourceEditor extends Component {

{this._renderLayerAndStyleInputs()}

{this._renderAttributionInputs()}

</EuiForm>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ export class WMSSource extends AbstractTMSSource {
});
static icon = 'grid';

static createDescriptor({ serviceUrl, layers, styles }) {
static createDescriptor({ serviceUrl, layers, styles, attributionText, attributionUrl }) {
return {
type: WMSSource.type,
serviceUrl: serviceUrl,
layers: layers,
styles: styles
serviceUrl,
layers,
styles,
attributionText,
attributionUrl
};
}

Expand Down Expand Up @@ -84,6 +86,18 @@ export class WMSSource extends AbstractTMSSource {
return this._descriptor.serviceUrl;
}

getAttributions() {
const { attributionText, attributionUrl } = this._descriptor;
const attributionComplete = !!attributionText && !!attributionUrl;

return attributionComplete
? [{
url: attributionUrl,
label: attributionText
}]
: [];
}

getUrlTemplate() {
const client = new WmsClient({ serviceUrl: this._descriptor.serviceUrl });
return client.getUrlTemplate(this._descriptor.layers, this._descriptor.styles || '');
Expand Down
112 changes: 96 additions & 16 deletions x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';

import React, { Fragment } from 'react';
import {
EuiFieldText,
EuiFormRow,
Expand All @@ -15,6 +14,7 @@ import { AbstractTMSSource } from './tms_source';
import { TileLayer } from '../tile_layer';
import { i18n } from '@kbn/i18n';
import { getDataSourceLabel, getUrlLabel } from '../../../common/i18n_getters';
import _ from 'lodash';

export class XYZTMSSource extends AbstractTMSSource {

Expand All @@ -27,10 +27,12 @@ export class XYZTMSSource extends AbstractTMSSource {
});
static icon = 'grid';

static createDescriptor({ urlTemplate }) {
static createDescriptor({ urlTemplate, attributionText, attributionUrl }) {
return {
type: XYZTMSSource.type,
urlTemplate
urlTemplate,
attributionText,
attributionUrl
};
}

Expand Down Expand Up @@ -68,40 +70,118 @@ export class XYZTMSSource extends AbstractTMSSource {
return this._descriptor.urlTemplate;
}

getAttributions() {
const { attributionText, attributionUrl } = this._descriptor;
const attributionComplete = !!attributionText && !!attributionUrl;

return attributionComplete
? [{
url: attributionUrl,
label: attributionText
}]
: [];
}

getUrlTemplate() {
return this._descriptor.urlTemplate;
}
}


class XYZTMSEditor extends React.Component {
class XYZTMSEditor extends React.Component {

state = {
tmsInput: '',
tmsCanPreview: false
tmsCanPreview: false,
attributionText: '',
attributionUrl: '',
}

_sourceConfigChange = _.debounce(updatedSourceConfig => {
if (this.state.tmsCanPreview) {
this.props.onSourceConfigChange(updatedSourceConfig);
}
}, 2000);

_handleTMSInputChange(e) {
const url = e.target.value;

const canPreview = (url.indexOf('{x}') >= 0 && url.indexOf('{y}') >= 0 && url.indexOf('{z}') >= 0);
this.setState({
tmsInput: url,
tmsCanPreview: canPreview
});
}, () => this._sourceConfigChange({ urlTemplate: url }));
}

if (canPreview) {
this.props.onSourceConfigChange({ urlTemplate: url });
}
_handleTMSAttributionChange(attributionUpdate) {
this.setState(attributionUpdate, () => {
const {
attributionText,
attributionUrl,
tmsInput,
} = this.state;

if (tmsInput && attributionText && attributionUrl) {
this._sourceConfigChange({
urlTemplate: tmsInput,
attributionText,
attributionUrl
});
}
});
}

render() {
const {
attributionText,
attributionUrl,
} = this.state;

return (
<EuiFormRow label="Url">
<EuiFieldText
placeholder={'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'}
onChange={(e) => this._handleTMSInputChange(e)}
/>
</EuiFormRow>
<Fragment>
<EuiFormRow
label="Url"
>
<EuiFieldText
placeholder={'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'}
onChange={e => this._handleTMSInputChange(e)}
/>
</EuiFormRow>
<EuiFormRow
label="Attribution text"
isInvalid={attributionUrl !== '' && attributionText === ''}
error={[
i18n.translate('xpack.maps.xyztmssource.attributionText', {
defaultMessage:
'Attribution url must have accompanying text',
})
]}
>
<EuiFieldText
placeholder={'© OpenStreetMap contributors'}
onChange={({ target }) =>
this._handleTMSAttributionChange({ attributionText: target.value })
}
/>
</EuiFormRow>
<EuiFormRow
label="Attribution link"
isInvalid={attributionText !== '' && attributionUrl === ''}
error={[
i18n.translate('xpack.maps.xyztmssource.attributionLink', {
defaultMessage:
'Attribution text must have an accompanying link',
})
]}
>
<EuiFieldText
placeholder={'https://www.openstreetmap.org/copyright'}
onChange={({ target }) =>
this._handleTMSAttributionChange({ attributionUrl: target.value })
}
/>
</EuiFormRow>
</Fragment>
);
}
}

0 comments on commit 1315724

Please sign in to comment.