mirror of
https://github.com/a-nyx/maputnik-with-pmtiles.git
synced 2024-12-27 08:45:28 +01:00
Added more functional tests.
This commit is contained in:
parent
3d4cc34a08
commit
8d3ad6b1a1
19 changed files with 1085 additions and 91 deletions
832
src/components/App.jsx_json_modal
Normal file
832
src/components/App.jsx_json_modal
Normal file
|
@ -0,0 +1,832 @@
|
||||||
|
import autoBind from 'react-autobind';
|
||||||
|
import React from 'react'
|
||||||
|
import cloneDeep from 'lodash.clonedeep'
|
||||||
|
import clamp from 'lodash.clamp'
|
||||||
|
import get from 'lodash.get'
|
||||||
|
import {unset} from 'lodash'
|
||||||
|
import {arrayMove} from 'react-sortable-hoc'
|
||||||
|
import url from 'url'
|
||||||
|
|
||||||
|
import MapboxGlMap from './map/MapboxGlMap'
|
||||||
|
import OpenLayersMap from './map/OpenLayersMap'
|
||||||
|
import LayerList from './layers/LayerList'
|
||||||
|
import LayerEditor from './layers/LayerEditor'
|
||||||
|
import Toolbar from './Toolbar'
|
||||||
|
import AppLayout from './AppLayout'
|
||||||
|
import MessagePanel from './MessagePanel'
|
||||||
|
|
||||||
|
import SettingsModal from './modals/SettingsModal'
|
||||||
|
import ExportModal from './modals/ExportModal'
|
||||||
|
import SourcesModal from './modals/SourcesModal'
|
||||||
|
import OpenModal from './modals/OpenModal'
|
||||||
|
import ShortcutsModal from './modals/ShortcutsModal'
|
||||||
|
import SurveyModal from './modals/SurveyModal'
|
||||||
|
import DebugModal from './modals/DebugModal'
|
||||||
|
import JSONEditorModal from './modals/JSONEditorModal'
|
||||||
|
|
||||||
|
import { downloadGlyphsMetadata, downloadSpriteMetadata } from '../libs/metadata'
|
||||||
|
import {latest, validate} from '@mapbox/mapbox-gl-style-spec'
|
||||||
|
import style from '../libs/style'
|
||||||
|
import { initialStyleUrl, loadStyleUrl, removeStyleQuerystring } from '../libs/urlopen'
|
||||||
|
import { undoMessages, redoMessages } from '../libs/diffmessage'
|
||||||
|
import { StyleStore } from '../libs/stylestore'
|
||||||
|
import { ApiStyleStore } from '../libs/apistore'
|
||||||
|
import { RevisionStore } from '../libs/revisions'
|
||||||
|
import LayerWatcher from '../libs/layerwatcher'
|
||||||
|
import tokens from '../config/tokens.json'
|
||||||
|
import isEqual from 'lodash.isequal'
|
||||||
|
import Debug from '../libs/debug'
|
||||||
|
import queryUtil from '../libs/query-util'
|
||||||
|
|
||||||
|
import MapboxGl from 'mapbox-gl'
|
||||||
|
|
||||||
|
|
||||||
|
// Similar functionality as <https://github.com/mapbox/mapbox-gl-js/blob/7e30aadf5177486c2cfa14fe1790c60e217b5e56/src/util/mapbox.js>
|
||||||
|
function normalizeSourceURL (url, apiToken="") {
|
||||||
|
const matches = url.match(/^mapbox:\/\/(.*)/);
|
||||||
|
if (matches) {
|
||||||
|
// mapbox://mapbox.mapbox-streets-v7
|
||||||
|
return `https://api.mapbox.com/v4/${matches[1]}.json?secure&access_token=${apiToken}`
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFetchAccessToken(url, mapStyle) {
|
||||||
|
const matchesTilehosting = url.match(/\.tilehosting\.com/);
|
||||||
|
const matchesMaptiler = url.match(/\.maptiler\.com/);
|
||||||
|
const matchesThunderforest = url.match(/\.thunderforest\.com/);
|
||||||
|
if (matchesTilehosting || matchesMaptiler) {
|
||||||
|
const accessToken = style.getAccessToken("openmaptiles", mapStyle, {allowFallback: true})
|
||||||
|
if (accessToken) {
|
||||||
|
return url.replace('{key}', accessToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (matchesThunderforest) {
|
||||||
|
const accessToken = style.getAccessToken("thunderforest", mapStyle, {allowFallback: true})
|
||||||
|
if (accessToken) {
|
||||||
|
return url.replace('{key}', accessToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateRootSpec(spec, fieldName, newValues) {
|
||||||
|
return {
|
||||||
|
...spec,
|
||||||
|
$root: {
|
||||||
|
...spec.$root,
|
||||||
|
[fieldName]: {
|
||||||
|
...spec.$root[fieldName],
|
||||||
|
values: newValues
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class App extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
autoBind(this);
|
||||||
|
|
||||||
|
this.revisionStore = new RevisionStore()
|
||||||
|
const params = new URLSearchParams(window.location.search.substring(1))
|
||||||
|
let port = params.get("localport")
|
||||||
|
if (port == null && (window.location.port != 80 && window.location.port != 443)) {
|
||||||
|
port = window.location.port
|
||||||
|
}
|
||||||
|
this.styleStore = new ApiStyleStore({
|
||||||
|
onLocalStyleChange: mapStyle => this.onStyleChanged(mapStyle, {save: false}),
|
||||||
|
port: port,
|
||||||
|
host: params.get("localhost")
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const shortcuts = [
|
||||||
|
{
|
||||||
|
key: "j",
|
||||||
|
handler: () => {
|
||||||
|
this.toggleModal("json_editor");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "?",
|
||||||
|
handler: () => {
|
||||||
|
this.toggleModal("shortcuts");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "o",
|
||||||
|
handler: () => {
|
||||||
|
this.toggleModal("open");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "e",
|
||||||
|
handler: () => {
|
||||||
|
this.toggleModal("export");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "d",
|
||||||
|
handler: () => {
|
||||||
|
this.toggleModal("sources");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "s",
|
||||||
|
handler: () => {
|
||||||
|
this.toggleModal("settings");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "i",
|
||||||
|
handler: () => {
|
||||||
|
this.setMapState(
|
||||||
|
this.state.mapState === "map" ? "inspect" : "map"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "m",
|
||||||
|
handler: () => {
|
||||||
|
document.querySelector(".mapboxgl-canvas").focus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "!",
|
||||||
|
handler: () => {
|
||||||
|
this.toggleModal("debug");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
document.body.addEventListener("keyup", (e) => {
|
||||||
|
if(e.key === "Escape") {
|
||||||
|
e.target.blur();
|
||||||
|
document.body.focus();
|
||||||
|
}
|
||||||
|
else if(this.state.isOpen.shortcuts || document.activeElement === document.body) {
|
||||||
|
const shortcut = shortcuts.find((shortcut) => {
|
||||||
|
return (shortcut.key === e.key)
|
||||||
|
})
|
||||||
|
|
||||||
|
if(shortcut) {
|
||||||
|
this.setModal("shortcuts", false);
|
||||||
|
shortcut.handler(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const styleUrl = initialStyleUrl()
|
||||||
|
if(styleUrl && window.confirm("Load style from URL: " + styleUrl + " and discard current changes?")) {
|
||||||
|
this.styleStore = new StyleStore()
|
||||||
|
loadStyleUrl(styleUrl, mapStyle => this.onStyleChanged(mapStyle))
|
||||||
|
removeStyleQuerystring()
|
||||||
|
} else {
|
||||||
|
if(styleUrl) {
|
||||||
|
removeStyleQuerystring()
|
||||||
|
}
|
||||||
|
this.styleStore.init(err => {
|
||||||
|
if(err) {
|
||||||
|
console.log('Falling back to local storage for storing styles')
|
||||||
|
this.styleStore = new StyleStore()
|
||||||
|
}
|
||||||
|
this.styleStore.latestStyle(mapStyle => this.onStyleChanged(mapStyle))
|
||||||
|
|
||||||
|
if(Debug.enabled()) {
|
||||||
|
Debug.set("maputnik", "styleStore", this.styleStore);
|
||||||
|
Debug.set("maputnik", "revisionStore", this.revisionStore);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Debug.enabled()) {
|
||||||
|
Debug.set("maputnik", "revisionStore", this.revisionStore);
|
||||||
|
Debug.set("maputnik", "styleStore", this.styleStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryObj = url.parse(window.location.href, true).query;
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
errors: [],
|
||||||
|
infos: [],
|
||||||
|
mapStyle: style.emptyStyle,
|
||||||
|
selectedLayerIndex: 0,
|
||||||
|
sources: {},
|
||||||
|
vectorLayers: {},
|
||||||
|
mapState: "map",
|
||||||
|
spec: latest,
|
||||||
|
mapView: {
|
||||||
|
zoom: 0,
|
||||||
|
center: {
|
||||||
|
lng: 0,
|
||||||
|
lat: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isOpen: {
|
||||||
|
settings: false,
|
||||||
|
sources: false,
|
||||||
|
open: false,
|
||||||
|
shortcuts: false,
|
||||||
|
export: false,
|
||||||
|
// TODO: Disabled for now, this should be opened on the Nth visit to the editor
|
||||||
|
survey: false,
|
||||||
|
debug: false,
|
||||||
|
},
|
||||||
|
mapboxGlDebugOptions: {
|
||||||
|
showTileBoundaries: false,
|
||||||
|
showCollisionBoxes: false,
|
||||||
|
showOverdrawInspector: false,
|
||||||
|
},
|
||||||
|
openlayersDebugOptions: {
|
||||||
|
debugToolbox: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
this.layerWatcher = new LayerWatcher({
|
||||||
|
onVectorLayersChange: v => this.setState({ vectorLayers: v })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyPress = (e) => {
|
||||||
|
if(navigator.platform.toUpperCase().indexOf('MAC') >= 0) {
|
||||||
|
if(e.metaKey && e.shiftKey && e.keyCode === 90) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.onRedo(e);
|
||||||
|
}
|
||||||
|
else if(e.metaKey && e.keyCode === 90) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.onUndo(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(e.ctrlKey && e.keyCode === 90) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.onUndo(e);
|
||||||
|
}
|
||||||
|
else if(e.ctrlKey && e.keyCode === 89) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.onRedo(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
window.addEventListener("keydown", this.handleKeyPress);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener("keydown", this.handleKeyPress);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveStyle(snapshotStyle) {
|
||||||
|
this.styleStore.save(snapshotStyle)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFonts(urlTemplate) {
|
||||||
|
const metadata = this.state.mapStyle.metadata || {}
|
||||||
|
const accessToken = metadata['maputnik:openmaptiles_access_token'] || tokens.openmaptiles
|
||||||
|
|
||||||
|
let glyphUrl = (typeof urlTemplate === 'string')? urlTemplate.replace('{key}', accessToken): urlTemplate;
|
||||||
|
downloadGlyphsMetadata(glyphUrl, fonts => {
|
||||||
|
this.setState({ spec: updateRootSpec(this.state.spec, 'glyphs', fonts)})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
updateIcons(baseUrl) {
|
||||||
|
downloadSpriteMetadata(baseUrl, icons => {
|
||||||
|
this.setState({ spec: updateRootSpec(this.state.spec, 'sprite', icons)})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeMetadataProperty = (property, value) => {
|
||||||
|
// If we're changing renderer reset the map state.
|
||||||
|
if (
|
||||||
|
property === 'maputnik:renderer' &&
|
||||||
|
value !== get(this.state.mapStyle, ['metadata', 'maputnik:renderer'], 'mbgljs')
|
||||||
|
) {
|
||||||
|
this.setState({
|
||||||
|
mapState: 'map'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const changedStyle = {
|
||||||
|
...this.state.mapStyle,
|
||||||
|
metadata: {
|
||||||
|
...this.state.mapStyle.metadata,
|
||||||
|
[property]: value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.onStyleChanged(changedStyle)
|
||||||
|
}
|
||||||
|
|
||||||
|
onStyleChanged = (newStyle, opts={}) => {
|
||||||
|
opts = {
|
||||||
|
save: true,
|
||||||
|
addRevision: true,
|
||||||
|
...opts,
|
||||||
|
};
|
||||||
|
|
||||||
|
const errors = validate(newStyle, latest) || [];
|
||||||
|
|
||||||
|
// The validate function doesn't give us errors for duplicate error with
|
||||||
|
// empty string for layer.id, manually deal with that here.
|
||||||
|
const layerErrors = [];
|
||||||
|
if (newStyle && newStyle.layers) {
|
||||||
|
const foundLayers = new Map();
|
||||||
|
newStyle.layers.forEach((layer, index) => {
|
||||||
|
if (layer.id === "" && foundLayers.has(layer.id)) {
|
||||||
|
const message = `Duplicate layer: [empty string]`;
|
||||||
|
layerErrors.push({
|
||||||
|
message,
|
||||||
|
parsed: {
|
||||||
|
type: "layer",
|
||||||
|
data: {
|
||||||
|
index,
|
||||||
|
message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
foundLayers.set(layer.id, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const mappedErrors = errors.map(error => {
|
||||||
|
const layerMatch = error.message.match(/layers\[(\d+)\]\.(?:(\S+)\.)?(\S+): (.*)/);
|
||||||
|
if (layerMatch) {
|
||||||
|
const [matchStr, index, group, property, message] = layerMatch;
|
||||||
|
const key = (group && property) ? [group, property].join(".") : property;
|
||||||
|
return {
|
||||||
|
message: error.message,
|
||||||
|
parsed: {
|
||||||
|
type: "layer",
|
||||||
|
data: {
|
||||||
|
index,
|
||||||
|
key,
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return {
|
||||||
|
message: error.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}).concat(layerErrors);
|
||||||
|
|
||||||
|
let dirtyMapStyle = undefined;
|
||||||
|
if (errors.length > 0) {
|
||||||
|
dirtyMapStyle = cloneDeep(newStyle);
|
||||||
|
|
||||||
|
errors.forEach(error => {
|
||||||
|
const {message} = error;
|
||||||
|
if (message) {
|
||||||
|
try {
|
||||||
|
const objPath = message.split(":")[0];
|
||||||
|
// Errors can be deply nested for example 'layers[0].filter[1][1][0]' we only care upto the property 'layers[0].filter'
|
||||||
|
const unsetPath = objPath.match(/^\S+?\[\d+\]\.[^\[]+/)[0];
|
||||||
|
unset(dirtyMapStyle, unsetPath);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.warn(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(newStyle.glyphs !== this.state.mapStyle.glyphs) {
|
||||||
|
this.updateFonts(newStyle.glyphs)
|
||||||
|
}
|
||||||
|
if(newStyle.sprite !== this.state.mapStyle.sprite) {
|
||||||
|
this.updateIcons(newStyle.sprite)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.addRevision) {
|
||||||
|
this.revisionStore.addRevision(newStyle);
|
||||||
|
}
|
||||||
|
if (opts.save) {
|
||||||
|
this.saveStyle(newStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
mapStyle: newStyle,
|
||||||
|
dirtyMapStyle: dirtyMapStyle,
|
||||||
|
errors: mappedErrors,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.fetchSources();
|
||||||
|
}
|
||||||
|
|
||||||
|
onUndo = () => {
|
||||||
|
const activeStyle = this.revisionStore.undo()
|
||||||
|
|
||||||
|
const messages = undoMessages(this.state.mapStyle, activeStyle)
|
||||||
|
this.onStyleChanged(activeStyle, {addRevision: false});
|
||||||
|
this.setState({
|
||||||
|
infos: messages,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onRedo = () => {
|
||||||
|
const activeStyle = this.revisionStore.redo()
|
||||||
|
const messages = redoMessages(this.state.mapStyle, activeStyle)
|
||||||
|
this.onStyleChanged(activeStyle, {addRevision: false});
|
||||||
|
this.setState({
|
||||||
|
infos: messages,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMoveLayer = (move) => {
|
||||||
|
let { oldIndex, newIndex } = move;
|
||||||
|
let layers = this.state.mapStyle.layers;
|
||||||
|
oldIndex = clamp(oldIndex, 0, layers.length-1);
|
||||||
|
newIndex = clamp(newIndex, 0, layers.length-1);
|
||||||
|
if(oldIndex === newIndex) return;
|
||||||
|
|
||||||
|
if (oldIndex === this.state.selectedLayerIndex) {
|
||||||
|
this.setState({
|
||||||
|
selectedLayerIndex: newIndex
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
layers = layers.slice(0);
|
||||||
|
layers = arrayMove(layers, oldIndex, newIndex);
|
||||||
|
this.onLayersChange(layers);
|
||||||
|
}
|
||||||
|
|
||||||
|
onLayersChange = (changedLayers) => {
|
||||||
|
const changedStyle = {
|
||||||
|
...this.state.mapStyle,
|
||||||
|
layers: changedLayers
|
||||||
|
}
|
||||||
|
this.onStyleChanged(changedStyle)
|
||||||
|
}
|
||||||
|
|
||||||
|
onLayerDestroy = (index) => {
|
||||||
|
let layers = this.state.mapStyle.layers;
|
||||||
|
const remainingLayers = layers.slice(0);
|
||||||
|
remainingLayers.splice(index, 1);
|
||||||
|
this.onLayersChange(remainingLayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
onLayerCopy = (index) => {
|
||||||
|
let layers = this.state.mapStyle.layers;
|
||||||
|
const changedLayers = layers.slice(0)
|
||||||
|
|
||||||
|
const clonedLayer = cloneDeep(changedLayers[index])
|
||||||
|
clonedLayer.id = clonedLayer.id + "-copy"
|
||||||
|
changedLayers.splice(index, 0, clonedLayer)
|
||||||
|
this.onLayersChange(changedLayers)
|
||||||
|
}
|
||||||
|
|
||||||
|
onLayerVisibilityToggle = (index) => {
|
||||||
|
let layers = this.state.mapStyle.layers;
|
||||||
|
const changedLayers = layers.slice(0)
|
||||||
|
|
||||||
|
const layer = { ...changedLayers[index] }
|
||||||
|
const changedLayout = 'layout' in layer ? {...layer.layout} : {}
|
||||||
|
changedLayout.visibility = changedLayout.visibility === 'none' ? 'visible' : 'none'
|
||||||
|
|
||||||
|
layer.layout = changedLayout
|
||||||
|
changedLayers[index] = layer
|
||||||
|
this.onLayersChange(changedLayers)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onLayerIdChange = (index, oldId, newId) => {
|
||||||
|
const changedLayers = this.state.mapStyle.layers.slice(0)
|
||||||
|
changedLayers[index] = {
|
||||||
|
...changedLayers[index],
|
||||||
|
id: newId
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onLayersChange(changedLayers)
|
||||||
|
}
|
||||||
|
|
||||||
|
onLayerChanged = (index, layer) => {
|
||||||
|
const changedLayers = this.state.mapStyle.layers.slice(0)
|
||||||
|
changedLayers[index] = layer
|
||||||
|
|
||||||
|
this.onLayersChange(changedLayers)
|
||||||
|
}
|
||||||
|
|
||||||
|
setMapState = (newState) => {
|
||||||
|
this.setState({
|
||||||
|
mapState: newState
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
setDefaultValues = (styleObj) => {
|
||||||
|
const metadata = styleObj.metadata || {}
|
||||||
|
if(metadata['maputnik:renderer'] === undefined) {
|
||||||
|
const changedStyle = {
|
||||||
|
...styleObj,
|
||||||
|
metadata: {
|
||||||
|
...styleObj.metadata,
|
||||||
|
'maputnik:renderer': 'mbgljs'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changedStyle
|
||||||
|
} else {
|
||||||
|
return styleObj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openStyle = (styleObj) => {
|
||||||
|
styleObj = this.setDefaultValues(styleObj)
|
||||||
|
this.onStyleChanged(styleObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchSources() {
|
||||||
|
const sourceList = {...this.state.sources};
|
||||||
|
|
||||||
|
for(let [key, val] of Object.entries(this.state.mapStyle.sources)) {
|
||||||
|
if(sourceList.hasOwnProperty(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceList[key] = {
|
||||||
|
type: val.type,
|
||||||
|
layers: []
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!this.state.sources.hasOwnProperty(key) && val.type === "vector" && val.hasOwnProperty("url")) {
|
||||||
|
let url = val.url;
|
||||||
|
try {
|
||||||
|
url = normalizeSourceURL(url, MapboxGl.accessToken);
|
||||||
|
} catch(err) {
|
||||||
|
console.warn("Failed to normalizeSourceURL: ", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
url = setFetchAccessToken(url, this.state.mapStyle)
|
||||||
|
} catch(err) {
|
||||||
|
console.warn("Failed to setFetchAccessToken: ", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(url, {
|
||||||
|
mode: 'cors',
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then((json) => {
|
||||||
|
if(!json.hasOwnProperty("vector_layers")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new objects before setState
|
||||||
|
const sources = Object.assign({}, this.state.sources);
|
||||||
|
|
||||||
|
for(let layer of json.vector_layers) {
|
||||||
|
sources[key].layers.push(layer.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.debug("Updating source: "+key);
|
||||||
|
this.setState({
|
||||||
|
sources: sources
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Failed to process sources for '%s'", url, err);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isEqual(this.state.sources, sourceList)) {
|
||||||
|
console.debug("Setting sources");
|
||||||
|
this.setState({
|
||||||
|
sources: sourceList
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_getRenderer () {
|
||||||
|
const metadata = this.state.mapStyle.metadata || {};
|
||||||
|
return metadata['maputnik:renderer'] || 'mbgljs';
|
||||||
|
}
|
||||||
|
|
||||||
|
onMapChange = (mapView) => {
|
||||||
|
this.setState({
|
||||||
|
mapView,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
mapRenderer() {
|
||||||
|
const {mapStyle, dirtyMapStyle} = this.state;
|
||||||
|
const metadata = this.state.mapStyle.metadata || {};
|
||||||
|
|
||||||
|
const mapProps = {
|
||||||
|
mapStyle: (dirtyMapStyle || mapStyle),
|
||||||
|
replaceAccessTokens: (mapStyle) => {
|
||||||
|
return style.replaceAccessTokens(mapStyle, {
|
||||||
|
allowFallback: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onDataChange: (e) => {
|
||||||
|
this.layerWatcher.analyzeMap(e.map)
|
||||||
|
this.fetchSources();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderer = this._getRenderer();
|
||||||
|
|
||||||
|
let mapElement;
|
||||||
|
|
||||||
|
// Check if OL code has been loaded?
|
||||||
|
if(renderer === 'ol') {
|
||||||
|
mapElement = <OpenLayersMap
|
||||||
|
{...mapProps}
|
||||||
|
onChange={this.onMapChange}
|
||||||
|
debugToolbox={this.state.openlayersDebugOptions.debugToolbox}
|
||||||
|
onLayerSelect={this.onLayerSelect}
|
||||||
|
/>
|
||||||
|
} else {
|
||||||
|
mapElement = <MapboxGlMap {...mapProps}
|
||||||
|
onChange={this.onMapChange}
|
||||||
|
options={this.state.mapboxGlDebugOptions}
|
||||||
|
inspectModeEnabled={this.state.mapState === "inspect"}
|
||||||
|
highlightedLayer={this.state.mapStyle.layers[this.state.selectedLayerIndex]}
|
||||||
|
onLayerSelect={this.onLayerSelect} />
|
||||||
|
}
|
||||||
|
|
||||||
|
let filterName;
|
||||||
|
if(this.state.mapState.match(/^filter-/)) {
|
||||||
|
filterName = this.state.mapState.replace(/^filter-/, "");
|
||||||
|
}
|
||||||
|
const elementStyle = {};
|
||||||
|
if (filterName) {
|
||||||
|
elementStyle.filter = `url('#${filterName}')`;
|
||||||
|
};
|
||||||
|
|
||||||
|
return <div style={elementStyle} className="maputnik-map__container">
|
||||||
|
{mapElement}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
onLayerSelect = (index) => {
|
||||||
|
this.setState({ selectedLayerIndex: index })
|
||||||
|
}
|
||||||
|
|
||||||
|
setModal(modalName, value) {
|
||||||
|
if(modalName === 'survey' && value === false) {
|
||||||
|
localStorage.setItem('survey', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
isOpen: {
|
||||||
|
...this.state.isOpen,
|
||||||
|
[modalName]: value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleModal(modalName) {
|
||||||
|
this.setModal(modalName, !this.state.isOpen[modalName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeOpenlayersDebug = (key, value) => {
|
||||||
|
this.setState({
|
||||||
|
openlayersDebugOptions: {
|
||||||
|
...this.state.openlayersDebugOptions,
|
||||||
|
[key]: value,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeMaboxGlDebug = (key, value) => {
|
||||||
|
this.setState({
|
||||||
|
mapboxGlDebugOptions: {
|
||||||
|
...this.state.mapboxGlDebugOptions,
|
||||||
|
[key]: value,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const layers = this.state.mapStyle.layers || []
|
||||||
|
const selectedLayer = layers.length > 0 ? layers[this.state.selectedLayerIndex] : null
|
||||||
|
const metadata = this.state.mapStyle.metadata || {}
|
||||||
|
|
||||||
|
const toolbar = <Toolbar
|
||||||
|
renderer={this._getRenderer()}
|
||||||
|
mapState={this.state.mapState}
|
||||||
|
mapStyle={this.state.mapStyle}
|
||||||
|
inspectModeEnabled={this.state.mapState === "inspect"}
|
||||||
|
sources={this.state.sources}
|
||||||
|
onStyleChanged={this.onStyleChanged}
|
||||||
|
onStyleOpen={this.onStyleChanged}
|
||||||
|
onSetMapState={this.setMapState}
|
||||||
|
onToggleModal={this.toggleModal.bind(this)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
const layerList = <LayerList
|
||||||
|
onMoveLayer={this.onMoveLayer}
|
||||||
|
onLayerDestroy={this.onLayerDestroy}
|
||||||
|
onLayerCopy={this.onLayerCopy}
|
||||||
|
onLayerVisibilityToggle={this.onLayerVisibilityToggle}
|
||||||
|
onLayersChange={this.onLayersChange}
|
||||||
|
onLayerSelect={this.onLayerSelect}
|
||||||
|
selectedLayerIndex={this.state.selectedLayerIndex}
|
||||||
|
layers={layers}
|
||||||
|
sources={this.state.sources}
|
||||||
|
errors={this.state.errors}
|
||||||
|
/>
|
||||||
|
|
||||||
|
const layerEditor = selectedLayer ? <LayerEditor
|
||||||
|
key={selectedLayer.id}
|
||||||
|
layer={selectedLayer}
|
||||||
|
layerIndex={this.state.selectedLayerIndex}
|
||||||
|
isFirstLayer={this.state.selectedLayerIndex < 1}
|
||||||
|
isLastLayer={this.state.selectedLayerIndex === this.state.mapStyle.layers.length-1}
|
||||||
|
sources={this.state.sources}
|
||||||
|
vectorLayers={this.state.vectorLayers}
|
||||||
|
spec={this.state.spec}
|
||||||
|
onMoveLayer={this.onMoveLayer}
|
||||||
|
onLayerChanged={this.onLayerChanged}
|
||||||
|
onLayerDestroy={this.onLayerDestroy}
|
||||||
|
onLayerCopy={this.onLayerCopy}
|
||||||
|
onLayerVisibilityToggle={this.onLayerVisibilityToggle}
|
||||||
|
onLayerIdChange={this.onLayerIdChange}
|
||||||
|
errors={this.state.errors}
|
||||||
|
/> : null
|
||||||
|
|
||||||
|
const bottomPanel = (this.state.errors.length + this.state.infos.length) > 0 ? <MessagePanel
|
||||||
|
currentLayer={selectedLayer}
|
||||||
|
onLayerSelect={this.onLayerSelect}
|
||||||
|
mapStyle={this.state.mapStyle}
|
||||||
|
errors={this.state.errors}
|
||||||
|
infos={this.state.infos}
|
||||||
|
/> : null
|
||||||
|
|
||||||
|
|
||||||
|
const modals = <div>
|
||||||
|
<DebugModal
|
||||||
|
renderer={this._getRenderer()}
|
||||||
|
mapboxGlDebugOptions={this.state.mapboxGlDebugOptions}
|
||||||
|
openlayersDebugOptions={this.state.openlayersDebugOptions}
|
||||||
|
onChangeMaboxGlDebug={this.onChangeMaboxGlDebug}
|
||||||
|
onChangeOpenlayersDebug={this.onChangeOpenlayersDebug}
|
||||||
|
isOpen={this.state.isOpen.debug}
|
||||||
|
onOpenToggle={this.toggleModal.bind(this, 'debug')}
|
||||||
|
mapView={this.state.mapView}
|
||||||
|
/>
|
||||||
|
<ShortcutsModal
|
||||||
|
ref={(el) => this.shortcutEl = el}
|
||||||
|
isOpen={this.state.isOpen.shortcuts}
|
||||||
|
onOpenToggle={this.toggleModal.bind(this, 'shortcuts')}
|
||||||
|
/>
|
||||||
|
<SettingsModal
|
||||||
|
mapStyle={this.state.mapStyle}
|
||||||
|
onStyleChanged={this.onStyleChanged}
|
||||||
|
onChangeMetadataProperty={this.onChangeMetadataProperty}
|
||||||
|
isOpen={this.state.isOpen.settings}
|
||||||
|
onOpenToggle={this.toggleModal.bind(this, 'settings')}
|
||||||
|
openlayersDebugOptions={this.state.openlayersDebugOptions}
|
||||||
|
/>
|
||||||
|
<JSONEditorModal
|
||||||
|
title="JSON Editor"
|
||||||
|
mapStyle={this.state.mapStyle}
|
||||||
|
onStyleChanged={this.onStyleChanged}
|
||||||
|
isOpen={this.state.isOpen.json_editor}
|
||||||
|
onOpenToggle={this.toggleModal.bind(this, 'json_editor')}
|
||||||
|
/>
|
||||||
|
<ExportModal
|
||||||
|
mapStyle={this.state.mapStyle}
|
||||||
|
onStyleChanged={this.onStyleChanged}
|
||||||
|
isOpen={this.state.isOpen.export}
|
||||||
|
onOpenToggle={this.toggleModal.bind(this, 'export')}
|
||||||
|
/>
|
||||||
|
<OpenModal
|
||||||
|
isOpen={this.state.isOpen.open}
|
||||||
|
onStyleOpen={this.openStyle}
|
||||||
|
onOpenToggle={this.toggleModal.bind(this, 'open')}
|
||||||
|
/>
|
||||||
|
<SourcesModal
|
||||||
|
mapStyle={this.state.mapStyle}
|
||||||
|
onStyleChanged={this.onStyleChanged}
|
||||||
|
isOpen={this.state.isOpen.sources}
|
||||||
|
onOpenToggle={this.toggleModal.bind(this, 'sources')}
|
||||||
|
/>
|
||||||
|
<SurveyModal
|
||||||
|
isOpen={this.state.isOpen.survey}
|
||||||
|
onOpenToggle={this.toggleModal.bind(this, 'survey')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
return <AppLayout
|
||||||
|
toolbar={toolbar}
|
||||||
|
layerList={layerList}
|
||||||
|
layerEditor={layerEditor}
|
||||||
|
map={this.mapRenderer()}
|
||||||
|
bottom={bottomPanel}
|
||||||
|
modals={modals}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
}
|
|
@ -185,18 +185,21 @@ export default class Toolbar extends React.Component {
|
||||||
>
|
>
|
||||||
{/* Keyboard accessible quick links */}
|
{/* Keyboard accessible quick links */}
|
||||||
<button
|
<button
|
||||||
|
data-wd-key="root:skip:layer-list"
|
||||||
className="maputnik-toolbar-skip"
|
className="maputnik-toolbar-skip"
|
||||||
onClick={e => this.onSkip("layer-list")}
|
onClick={e => this.onSkip("layer-list")}
|
||||||
>
|
>
|
||||||
Layers list
|
Layers list
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
|
data-wd-key="root:skip:layer-editor"
|
||||||
className="maputnik-toolbar-skip"
|
className="maputnik-toolbar-skip"
|
||||||
onClick={e => this.onSkip("layer-editor")}
|
onClick={e => this.onSkip("layer-editor")}
|
||||||
>
|
>
|
||||||
Layer editor
|
Layer editor
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
|
data-wd-key="root:skip:map-view"
|
||||||
className="maputnik-toolbar-skip"
|
className="maputnik-toolbar-skip"
|
||||||
onClick={e => this.onSkip("map")}
|
onClick={e => this.onSkip("map")}
|
||||||
>
|
>
|
||||||
|
|
|
@ -24,7 +24,7 @@ class DebugModal extends React.Component {
|
||||||
const osmLat = Number.parseFloat(mapView.center.lat).toFixed(5);
|
const osmLat = Number.parseFloat(mapView.center.lat).toFixed(5);
|
||||||
|
|
||||||
return <Modal
|
return <Modal
|
||||||
data-wd-key="debug-modal"
|
data-wd-key="modal:debug"
|
||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
onOpenToggle={this.props.onOpenToggle}
|
onOpenToggle={this.props.onOpenToggle}
|
||||||
title={'Debug'}
|
title={'Debug'}
|
||||||
|
|
|
@ -61,7 +61,7 @@ class ExportModal extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <Modal
|
return <Modal
|
||||||
data-wd-key="export-modal"
|
data-wd-key="modal:export"
|
||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
onOpenToggle={this.props.onOpenToggle}
|
onOpenToggle={this.props.onOpenToggle}
|
||||||
title={'Export Style'}
|
title={'Export Style'}
|
||||||
|
|
|
@ -20,7 +20,7 @@ class LoadingModal extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <Modal
|
return <Modal
|
||||||
data-wd-key="loading-modal"
|
data-wd-key="modal:loading"
|
||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
underlayClickExits={false}
|
underlayClickExits={false}
|
||||||
underlayProps={{
|
underlayProps={{
|
||||||
|
|
|
@ -191,7 +191,7 @@ class OpenModal extends React.Component {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Modal
|
<Modal
|
||||||
data-wd-key="open-modal"
|
data-wd-key="modal:open"
|
||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
onOpenToggle={() => this.onOpenToggle()}
|
onOpenToggle={() => this.onOpenToggle()}
|
||||||
title={'Open Style'}
|
title={'Open Style'}
|
||||||
|
@ -212,7 +212,7 @@ class OpenModal extends React.Component {
|
||||||
</p>
|
</p>
|
||||||
<form onSubmit={this.onSubmitUrl}>
|
<form onSubmit={this.onSubmitUrl}>
|
||||||
<UrlInput
|
<UrlInput
|
||||||
data-wd-key="open-modal.url.input"
|
data-wd-key="modal:open.url.input"
|
||||||
type="text"
|
type="text"
|
||||||
className="maputnik-input"
|
className="maputnik-input"
|
||||||
default="Enter URL..."
|
default="Enter URL..."
|
||||||
|
@ -222,7 +222,7 @@ class OpenModal extends React.Component {
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
data-wd-key="open-modal.url.button"
|
data-wd-key="modal:open.url.button"
|
||||||
type="submit"
|
type="submit"
|
||||||
className="maputnik-big-button"
|
className="maputnik-big-button"
|
||||||
disabled={this.state.styleUrl.length < 1}
|
disabled={this.state.styleUrl.length < 1}
|
||||||
|
|
|
@ -81,29 +81,29 @@ class SettingsModal extends React.Component {
|
||||||
const transition = this.props.mapStyle.transition || {};
|
const transition = this.props.mapStyle.transition || {};
|
||||||
|
|
||||||
return <Modal
|
return <Modal
|
||||||
data-wd-key="modal-settings"
|
data-wd-key="modal:settings"
|
||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
onOpenToggle={this.props.onOpenToggle}
|
onOpenToggle={this.props.onOpenToggle}
|
||||||
title={'Style Settings'}
|
title={'Style Settings'}
|
||||||
>
|
>
|
||||||
<div className="modal-settings">
|
<div className="modal:settings">
|
||||||
<InputBlock label={"Name"} fieldSpec={latest.$root.name}>
|
<InputBlock label={"Name"} fieldSpec={latest.$root.name}>
|
||||||
<StringInput {...inputProps}
|
<StringInput {...inputProps}
|
||||||
data-wd-key="modal-settings.name"
|
data-wd-key="modal:settings.name"
|
||||||
value={this.props.mapStyle.name}
|
value={this.props.mapStyle.name}
|
||||||
onChange={this.changeStyleProperty.bind(this, "name")}
|
onChange={this.changeStyleProperty.bind(this, "name")}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
<InputBlock label={"Owner"} fieldSpec={{doc: "Owner ID of the style. Used by Mapbox or future style APIs."}}>
|
<InputBlock label={"Owner"} fieldSpec={{doc: "Owner ID of the style. Used by Mapbox or future style APIs."}}>
|
||||||
<StringInput {...inputProps}
|
<StringInput {...inputProps}
|
||||||
data-wd-key="modal-settings.owner"
|
data-wd-key="modal:settings.owner"
|
||||||
value={this.props.mapStyle.owner}
|
value={this.props.mapStyle.owner}
|
||||||
onChange={this.changeStyleProperty.bind(this, "owner")}
|
onChange={this.changeStyleProperty.bind(this, "owner")}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
<InputBlock label={"Sprite URL"} fieldSpec={latest.$root.sprite}>
|
<InputBlock label={"Sprite URL"} fieldSpec={latest.$root.sprite}>
|
||||||
<UrlInput {...inputProps}
|
<UrlInput {...inputProps}
|
||||||
data-wd-key="modal-settings.sprite"
|
data-wd-key="modal:settings.sprite"
|
||||||
value={this.props.mapStyle.sprite}
|
value={this.props.mapStyle.sprite}
|
||||||
onChange={this.changeStyleProperty.bind(this, "sprite")}
|
onChange={this.changeStyleProperty.bind(this, "sprite")}
|
||||||
/>
|
/>
|
||||||
|
@ -111,7 +111,7 @@ class SettingsModal extends React.Component {
|
||||||
|
|
||||||
<InputBlock label={"Glyphs URL"} fieldSpec={latest.$root.glyphs}>
|
<InputBlock label={"Glyphs URL"} fieldSpec={latest.$root.glyphs}>
|
||||||
<UrlInput {...inputProps}
|
<UrlInput {...inputProps}
|
||||||
data-wd-key="modal-settings.glyphs"
|
data-wd-key="modal:settings.glyphs"
|
||||||
value={this.props.mapStyle.glyphs}
|
value={this.props.mapStyle.glyphs}
|
||||||
onChange={this.changeStyleProperty.bind(this, "glyphs")}
|
onChange={this.changeStyleProperty.bind(this, "glyphs")}
|
||||||
/>
|
/>
|
||||||
|
@ -122,7 +122,7 @@ class SettingsModal extends React.Component {
|
||||||
fieldSpec={fieldSpecAdditional.maputnik.mapbox_access_token}
|
fieldSpec={fieldSpecAdditional.maputnik.mapbox_access_token}
|
||||||
>
|
>
|
||||||
<StringInput {...inputProps}
|
<StringInput {...inputProps}
|
||||||
data-wd-key="modal-settings.maputnik:mapbox_access_token"
|
data-wd-key="modal:settings.maputnik:mapbox_access_token"
|
||||||
value={metadata['maputnik:mapbox_access_token']}
|
value={metadata['maputnik:mapbox_access_token']}
|
||||||
onChange={onChangeMetadataProperty.bind(this, "maputnik:mapbox_access_token")}
|
onChange={onChangeMetadataProperty.bind(this, "maputnik:mapbox_access_token")}
|
||||||
/>
|
/>
|
||||||
|
@ -133,7 +133,7 @@ class SettingsModal extends React.Component {
|
||||||
fieldSpec={fieldSpecAdditional.maputnik.maptiler_access_token}
|
fieldSpec={fieldSpecAdditional.maputnik.maptiler_access_token}
|
||||||
>
|
>
|
||||||
<StringInput {...inputProps}
|
<StringInput {...inputProps}
|
||||||
data-wd-key="modal-settings.maputnik:openmaptiles_access_token"
|
data-wd-key="modal:settings.maputnik:openmaptiles_access_token"
|
||||||
value={metadata['maputnik:openmaptiles_access_token']}
|
value={metadata['maputnik:openmaptiles_access_token']}
|
||||||
onChange={onChangeMetadataProperty.bind(this, "maputnik:openmaptiles_access_token")}
|
onChange={onChangeMetadataProperty.bind(this, "maputnik:openmaptiles_access_token")}
|
||||||
/>
|
/>
|
||||||
|
@ -144,7 +144,7 @@ class SettingsModal extends React.Component {
|
||||||
fieldSpec={fieldSpecAdditional.maputnik.thunderforest_access_token}
|
fieldSpec={fieldSpecAdditional.maputnik.thunderforest_access_token}
|
||||||
>
|
>
|
||||||
<StringInput {...inputProps}
|
<StringInput {...inputProps}
|
||||||
data-wd-key="modal-settings.maputnik:thunderforest_access_token"
|
data-wd-key="modal:settings.maputnik:thunderforest_access_token"
|
||||||
value={metadata['maputnik:thunderforest_access_token']}
|
value={metadata['maputnik:thunderforest_access_token']}
|
||||||
onChange={onChangeMetadataProperty.bind(this, "maputnik:thunderforest_access_token")}
|
onChange={onChangeMetadataProperty.bind(this, "maputnik:thunderforest_access_token")}
|
||||||
/>
|
/>
|
||||||
|
@ -250,7 +250,7 @@ class SettingsModal extends React.Component {
|
||||||
fieldSpec={fieldSpecAdditional.maputnik.style_renderer}
|
fieldSpec={fieldSpecAdditional.maputnik.style_renderer}
|
||||||
>
|
>
|
||||||
<SelectInput {...inputProps}
|
<SelectInput {...inputProps}
|
||||||
data-wd-key="modal-settings.maputnik:renderer"
|
data-wd-key="modal:settings.maputnik:renderer"
|
||||||
options={[
|
options={[
|
||||||
['mbgljs', 'MapboxGL JS'],
|
['mbgljs', 'MapboxGL JS'],
|
||||||
['ol', 'Open Layers (experimental)'],
|
['ol', 'Open Layers (experimental)'],
|
||||||
|
|
|
@ -100,7 +100,7 @@ class ShortcutsModal extends React.Component {
|
||||||
|
|
||||||
|
|
||||||
return <Modal
|
return <Modal
|
||||||
data-wd-key="shortcuts-modal"
|
data-wd-key="modal:shortcuts"
|
||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
onOpenToggle={this.props.onOpenToggle}
|
onOpenToggle={this.props.onOpenToggle}
|
||||||
title={'Shortcuts'}
|
title={'Shortcuts'}
|
||||||
|
|
|
@ -286,6 +286,7 @@ class SourcesModal extends React.Component {
|
||||||
|
|
||||||
const inputProps = { }
|
const inputProps = { }
|
||||||
return <Modal
|
return <Modal
|
||||||
|
data-wd-key="modal:sources"
|
||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
onOpenToggle={this.props.onOpenToggle}
|
onOpenToggle={this.props.onOpenToggle}
|
||||||
title={'Sources'}
|
title={'Sources'}
|
||||||
|
|
|
@ -20,7 +20,7 @@ class SurveyModal extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <Modal
|
return <Modal
|
||||||
data-wd-key="modal-survey"
|
data-wd-key="modal:survey"
|
||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
onOpenToggle={this.props.onOpenToggle}
|
onOpenToggle={this.props.onOpenToggle}
|
||||||
title="Maputnik Survey"
|
title="Maputnik Survey"
|
||||||
|
|
18
test/example-layer-style.json
Normal file
18
test/example-layer-style.json
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"id": "test-style",
|
||||||
|
"version": 8,
|
||||||
|
"name": "Test Style",
|
||||||
|
"metadata": {
|
||||||
|
"maputnik:renderer": "mbgljs"
|
||||||
|
},
|
||||||
|
"sources": {},
|
||||||
|
"glyphs": "https://example.local/fonts/{fontstack}/{range}.pbf",
|
||||||
|
"sprites": "https://example.local/fonts/{fontstack}/{range}.pbf",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"id": "background",
|
||||||
|
"type": "background"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
3
test/functional/accessibility/index.js
Normal file
3
test/functional/accessibility/index.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
describe("accessibility", function () {
|
||||||
|
require("./skip-links");
|
||||||
|
})
|
51
test/functional/accessibility/skip-links.js
Normal file
51
test/functional/accessibility/skip-links.js
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
var assert = require("assert");
|
||||||
|
var config = require("../../config/specs");
|
||||||
|
var helper = require("../helper");
|
||||||
|
var wd = require("../../wd-helper");
|
||||||
|
|
||||||
|
|
||||||
|
describe("skip links", function() {
|
||||||
|
beforeEach(function () {
|
||||||
|
browser.url(config.baseUrl+"?debug&style="+helper.getGeoServerUrl("example-layer-style.json"));
|
||||||
|
browser.acceptAlert();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("skip link to layer list", function() {
|
||||||
|
const selector = wd.$("root:skip:layer-list")
|
||||||
|
const elem = $(selector);
|
||||||
|
assert(elem.isExisting());
|
||||||
|
browser.keys(['Tab']);
|
||||||
|
assert(elem.isFocused());
|
||||||
|
elem.click();
|
||||||
|
|
||||||
|
const targetEl = $("#skip-target-layer-list");
|
||||||
|
assert(targetEl.isFocused());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("skip link to layer editor", function() {
|
||||||
|
const selector = wd.$("root:skip:layer-editor")
|
||||||
|
const elem = $(selector);
|
||||||
|
assert(elem.isExisting());
|
||||||
|
browser.keys(['Tab']);
|
||||||
|
browser.keys(['Tab']);
|
||||||
|
assert(elem.isFocused());
|
||||||
|
elem.click();
|
||||||
|
|
||||||
|
const targetEl = $("#skip-target-layer-editor");
|
||||||
|
assert(targetEl.isFocused());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("skip link to map view", function() {
|
||||||
|
const selector = wd.$("root:skip:map-view")
|
||||||
|
const elem = $(selector);
|
||||||
|
assert(elem.isExisting());
|
||||||
|
browser.keys(['Tab']);
|
||||||
|
browser.keys(['Tab']);
|
||||||
|
browser.keys(['Tab']);
|
||||||
|
assert(elem.isFocused());
|
||||||
|
elem.click();
|
||||||
|
|
||||||
|
const targetEl = $(".mapboxgl-canvas");
|
||||||
|
assert(targetEl.isFocused());
|
||||||
|
});
|
||||||
|
});
|
|
@ -3,7 +3,23 @@ var config = require("../../config/specs");
|
||||||
var helper = require("../helper");
|
var helper = require("../helper");
|
||||||
|
|
||||||
|
|
||||||
describe.skip("history", function() {
|
|
||||||
|
describe("history", function() {
|
||||||
|
let undoKeyCombo;
|
||||||
|
let undoKeyComboReset;
|
||||||
|
let redoKeyCombo;
|
||||||
|
let redoKeyComboReset;
|
||||||
|
|
||||||
|
before(function() {
|
||||||
|
const isMac = browser.execute(function() {
|
||||||
|
return navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
||||||
|
});
|
||||||
|
undoKeyCombo = ['Meta', 'z'];
|
||||||
|
undoKeyComboReset = ['Meta'];
|
||||||
|
redoKeyCombo = isMac ? ['Meta', 'Shift', 'z'] : ['Meta', 'y'];
|
||||||
|
redoKeyComboReset = isMac ? ['Meta', 'Shift'] : ['Meta'];
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See <https://github.com/webdriverio/webdriverio/issues/1126>
|
* See <https://github.com/webdriverio/webdriverio/issues/1126>
|
||||||
*/
|
*/
|
||||||
|
@ -13,7 +29,7 @@ describe.skip("history", function() {
|
||||||
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
||||||
"geojson:example"
|
"geojson:example"
|
||||||
]));
|
]));
|
||||||
browser.alertAccept();
|
browser.acceptAlert();
|
||||||
|
|
||||||
helper.modal.addLayer.open();
|
helper.modal.addLayer.open();
|
||||||
|
|
||||||
|
@ -51,9 +67,8 @@ describe.skip("history", function() {
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
browser
|
browser.keys(undoKeyCombo)
|
||||||
.keys(['Control', 'z'])
|
browser.keys(undoKeyComboReset);
|
||||||
.keys(['Control']);
|
|
||||||
styleObj = helper.getStyleStore(browser);
|
styleObj = helper.getStyleStore(browser);
|
||||||
assert.deepEqual(styleObj.layers, [
|
assert.deepEqual(styleObj.layers, [
|
||||||
{
|
{
|
||||||
|
@ -62,16 +77,14 @@ describe.skip("history", function() {
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
browser
|
browser.keys(undoKeyCombo)
|
||||||
.keys(['Control', 'z'])
|
browser.keys(undoKeyComboReset);
|
||||||
.keys(['Control']);
|
|
||||||
styleObj = helper.getStyleStore(browser);
|
styleObj = helper.getStyleStore(browser);
|
||||||
assert.deepEqual(styleObj.layers, [
|
assert.deepEqual(styleObj.layers, [
|
||||||
]);
|
]);
|
||||||
|
|
||||||
browser
|
browser.keys(redoKeyCombo)
|
||||||
.keys(['Control', 'y'])
|
browser.keys(redoKeyComboReset);
|
||||||
.keys(['Control']);
|
|
||||||
styleObj = helper.getStyleStore(browser);
|
styleObj = helper.getStyleStore(browser);
|
||||||
assert.deepEqual(styleObj.layers, [
|
assert.deepEqual(styleObj.layers, [
|
||||||
{
|
{
|
||||||
|
@ -80,9 +93,8 @@ describe.skip("history", function() {
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
browser
|
browser.keys(redoKeyCombo)
|
||||||
.keys(['Control', 'y'])
|
browser.keys(redoKeyComboReset);
|
||||||
.keys(['Control']);
|
|
||||||
styleObj = helper.getStyleStore(browser);
|
styleObj = helper.getStyleStore(browser);
|
||||||
assert.deepEqual(styleObj.layers, [
|
assert.deepEqual(styleObj.layers, [
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,6 +37,8 @@ describe('maputnik', function() {
|
||||||
require("./map");
|
require("./map");
|
||||||
require("./modals");
|
require("./modals");
|
||||||
require("./screenshots");
|
require("./screenshots");
|
||||||
|
require("./accessibility");
|
||||||
|
require("./keyboard");
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
58
test/functional/keyboard/index.js
Normal file
58
test/functional/keyboard/index.js
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
var assert = require("assert");
|
||||||
|
var config = require("../../config/specs");
|
||||||
|
var helper = require("../helper");
|
||||||
|
var wd = require("../../wd-helper");
|
||||||
|
|
||||||
|
|
||||||
|
describe("keyboard", function() {
|
||||||
|
describe("shortcuts", function() {
|
||||||
|
it("ESC should unfocus", function() {
|
||||||
|
const tmpTargetEl = $(wd.$("nav:inspect") + " select");
|
||||||
|
tmpTargetEl.click();
|
||||||
|
assert(tmpTargetEl.isFocused());
|
||||||
|
|
||||||
|
browser.keys(["Escape"]);
|
||||||
|
assert($("body").isFocused());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("'?' should show shortcuts modal", function() {
|
||||||
|
browser.keys(["?"]);
|
||||||
|
assert($(wd.$("modal:shortcuts")).isDisplayed());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("'o' should show open modal", function() {
|
||||||
|
browser.keys(["o"]);
|
||||||
|
assert($(wd.$("modal:open")).isDisplayed());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("'e' should show export modal", function() {
|
||||||
|
browser.keys(["e"]);
|
||||||
|
assert($(wd.$("modal:export")).isDisplayed());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("'d' should show sources modal", function() {
|
||||||
|
browser.keys(["d"]);
|
||||||
|
assert($(wd.$("modal:sources")).isDisplayed());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("'s' should show settings modal", function() {
|
||||||
|
browser.keys(["s"]);
|
||||||
|
assert($(wd.$("modal:settings")).isDisplayed());
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip("'i' should change map to inspect mode", function() {
|
||||||
|
// browser.keys(["i"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("'m' should focus map", function() {
|
||||||
|
browser.keys(["m"]);
|
||||||
|
$(".mapboxgl-canvas").isFocused();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("'!' should show debug modal", function() {
|
||||||
|
browser.keys(["!"]);
|
||||||
|
assert($(wd.$("modal:debug")).isDisplayed());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -115,12 +115,6 @@ describe("layers", function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("grouped", function() {
|
|
||||||
it("with underscore")
|
|
||||||
it("no without underscore")
|
|
||||||
it("double underscore only grouped once")
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("tooltips", function() {
|
describe("tooltips", function() {
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -130,20 +124,18 @@ describe("layers", function() {
|
||||||
|
|
||||||
describe('background', function () {
|
describe('background', function () {
|
||||||
|
|
||||||
it.skip("add", function() {
|
it("add", function() {
|
||||||
var id = helper.modal.addLayer.fill({
|
var id = helper.modal.addLayer.fill({
|
||||||
type: "background"
|
type: "background"
|
||||||
})
|
})
|
||||||
|
|
||||||
browser.waitUntil(function() {
|
var styleObj = helper.getStyleStore(browser);
|
||||||
var styleObj = helper.getStyleStore(browser);
|
assert.deepEqual(styleObj.layers, [
|
||||||
assert.deepEqual(styleObj.layers, [
|
{
|
||||||
{
|
"id": id,
|
||||||
"id": id,
|
"type": 'background'
|
||||||
"type": 'background'
|
}
|
||||||
}
|
]);
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("modify", function() {
|
describe("modify", function() {
|
||||||
|
@ -192,9 +184,6 @@ describe("layers", function() {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
// NOTE: This needs to be removed from the code
|
|
||||||
it("type");
|
|
||||||
|
|
||||||
it("min-zoom", function() {
|
it("min-zoom", function() {
|
||||||
var bgId = createBackground();
|
var bgId = createBackground();
|
||||||
|
|
||||||
|
@ -340,7 +329,7 @@ describe("layers", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fill', function () {
|
describe('fill', function () {
|
||||||
it.skip("add", function() {
|
it("add", function() {
|
||||||
// browser.debug();
|
// browser.debug();
|
||||||
|
|
||||||
var id = helper.modal.addLayer.fill({
|
var id = helper.modal.addLayer.fill({
|
||||||
|
@ -363,7 +352,7 @@ describe("layers", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('line', function () {
|
describe('line', function () {
|
||||||
it.skip("add", function() {
|
it("add", function() {
|
||||||
var id = helper.modal.addLayer.fill({
|
var id = helper.modal.addLayer.fill({
|
||||||
type: "line",
|
type: "line",
|
||||||
layer: "example"
|
layer: "example"
|
||||||
|
@ -386,7 +375,7 @@ describe("layers", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('symbol', function () {
|
describe('symbol', function () {
|
||||||
it.skip("add", function() {
|
it("add", function() {
|
||||||
var id = helper.modal.addLayer.fill({
|
var id = helper.modal.addLayer.fill({
|
||||||
type: "symbol",
|
type: "symbol",
|
||||||
layer: "example"
|
layer: "example"
|
||||||
|
@ -404,7 +393,7 @@ describe("layers", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('raster', function () {
|
describe('raster', function () {
|
||||||
it.skip("add", function() {
|
it("add", function() {
|
||||||
var id = helper.modal.addLayer.fill({
|
var id = helper.modal.addLayer.fill({
|
||||||
type: "raster",
|
type: "raster",
|
||||||
layer: "raster"
|
layer: "raster"
|
||||||
|
@ -422,7 +411,7 @@ describe("layers", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('circle', function () {
|
describe('circle', function () {
|
||||||
it.skip("add", function() {
|
it("add", function() {
|
||||||
var id = helper.modal.addLayer.fill({
|
var id = helper.modal.addLayer.fill({
|
||||||
type: "circle",
|
type: "circle",
|
||||||
layer: "example"
|
layer: "example"
|
||||||
|
@ -441,7 +430,7 @@ describe("layers", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fill extrusion', function () {
|
describe('fill extrusion', function () {
|
||||||
it.skip("add", function() {
|
it("add", function() {
|
||||||
var id = helper.modal.addLayer.fill({
|
var id = helper.modal.addLayer.fill({
|
||||||
type: "fill-extrusion",
|
type: "fill-extrusion",
|
||||||
layer: "example"
|
layer: "example"
|
||||||
|
@ -459,12 +448,12 @@ describe("layers", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe.skip("groups", function() {
|
describe("groups", function() {
|
||||||
it("simple", function() {
|
it("simple", function() {
|
||||||
browser.url(config.baseUrl+"?debug&style="+getStyleUrl([
|
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
||||||
"geojson:example"
|
"geojson:example"
|
||||||
]));
|
]));
|
||||||
browser.alertAccept();
|
browser.acceptAlert();
|
||||||
|
|
||||||
helper.modal.addLayer.open();
|
helper.modal.addLayer.open();
|
||||||
var aId = helper.modal.addLayer.fill({
|
var aId = helper.modal.addLayer.fill({
|
||||||
|
@ -480,21 +469,22 @@ describe("layers", function() {
|
||||||
|
|
||||||
helper.modal.addLayer.open();
|
helper.modal.addLayer.open();
|
||||||
var bId = helper.modal.addLayer.fill({
|
var bId = helper.modal.addLayer.fill({
|
||||||
id: "foo_baz",
|
id: "foo_bar_baz",
|
||||||
type: "background"
|
type: "background"
|
||||||
})
|
})
|
||||||
|
|
||||||
browser.waitForExist(wd.$("layer-list-group:foo-0"));
|
const groupEl = $(wd.$("layer-list-group:foo-0"));
|
||||||
|
groupEl.isDisplayed();
|
||||||
|
|
||||||
assert.equal(browser.isVisibleWithinViewport(wd.$("layer-list-item:foo")), false);
|
assert.equal($(wd.$("layer-list-item:foo")).isDisplayedInViewport(), true);
|
||||||
assert.equal(browser.isVisibleWithinViewport(wd.$("layer-list-item:foo_bar")), false);
|
assert.equal($(wd.$("layer-list-item:foo_bar")).isDisplayedInViewport(), false);
|
||||||
assert.equal(browser.isVisibleWithinViewport(wd.$("layer-list-item:foo_baz")), false);
|
assert.equal($(wd.$("layer-list-item:foo_bar_baz")).isDisplayedInViewport(), false);
|
||||||
|
|
||||||
browser.click(wd.$("layer-list-group:foo-0"));
|
groupEl.click();
|
||||||
|
|
||||||
assert.equal(browser.isVisibleWithinViewport(wd.$("layer-list-item:foo")), true);
|
assert.equal($(wd.$("layer-list-item:foo")).isDisplayedInViewport(), true);
|
||||||
assert.equal(browser.isVisibleWithinViewport(wd.$("layer-list-item:foo_bar")), true);
|
assert.equal($(wd.$("layer-list-item:foo_bar")).isDisplayedInViewport(), true);
|
||||||
assert.equal(browser.isVisibleWithinViewport(wd.$("layer-list-item:foo_baz")), true);
|
assert.equal($(wd.$("layer-list-item:foo_bar_baz")).isDisplayedInViewport(), true);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -41,7 +41,7 @@ describe("modals", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("close", function() {
|
it("close", function() {
|
||||||
closeModal("open-modal");
|
closeModal("modal:open");
|
||||||
});
|
});
|
||||||
|
|
||||||
// "chooseFile" command currently not available for wdio v5 https://github.com/webdriverio/webdriverio/pull/3632
|
// "chooseFile" command currently not available for wdio v5 https://github.com/webdriverio/webdriverio/pull/3632
|
||||||
|
@ -57,9 +57,9 @@ describe("modals", function() {
|
||||||
it("load from url", function() {
|
it("load from url", function() {
|
||||||
var styleFileUrl = helper.getGeoServerUrl("example-style.json");
|
var styleFileUrl = helper.getGeoServerUrl("example-style.json");
|
||||||
|
|
||||||
browser.setValueSafe(wd.$("open-modal.url.input"), styleFileUrl);
|
browser.setValueSafe(wd.$("modal:open.url.input"), styleFileUrl);
|
||||||
|
|
||||||
const selector = $(wd.$("open-modal.url.button"));
|
const selector = $(wd.$("modal:open.url.button"));
|
||||||
selector.click();
|
selector.click();
|
||||||
|
|
||||||
// Allow the network request to happen
|
// Allow the network request to happen
|
||||||
|
@ -74,6 +74,24 @@ describe("modals", function() {
|
||||||
it("gallery")
|
it("gallery")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("shortcuts", function() {
|
||||||
|
it("open/close", function() {
|
||||||
|
browser.url(config.baseUrl+"?debug");
|
||||||
|
|
||||||
|
const elem = $(".maputnik-toolbar-link");
|
||||||
|
elem.waitForExist();
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.keys(["?"]);
|
||||||
|
|
||||||
|
const modalEl = $(wd.$("modal:shortcuts"))
|
||||||
|
assert(modalEl.isDisplayed());
|
||||||
|
|
||||||
|
closeModal("modal:shortcuts");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
describe("export", function() {
|
describe("export", function() {
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
@ -89,14 +107,12 @@ describe("modals", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("close", function() {
|
it("close", function() {
|
||||||
closeModal("export-modal");
|
closeModal("modal:export");
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Work out how to download a file and check the contents
|
// TODO: Work out how to download a file and check the contents
|
||||||
it("download")
|
it("download")
|
||||||
|
|
||||||
// TODO: Work out how to mock the end git points
|
|
||||||
it("save to gist")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("sources", function() {
|
describe("sources", function() {
|
||||||
|
@ -131,8 +147,8 @@ describe("modals", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("name", function() {
|
it("name", function() {
|
||||||
browser.setValueSafe(wd.$("modal-settings.name"), "foobar")
|
browser.setValueSafe(wd.$("modal:settings.name"), "foobar")
|
||||||
const elem = $(wd.$("modal-settings.owner"));
|
const elem = $(wd.$("modal:settings.owner"));
|
||||||
elem.click();
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
@ -140,8 +156,8 @@ describe("modals", function() {
|
||||||
assert.equal(styleObj.name, "foobar");
|
assert.equal(styleObj.name, "foobar");
|
||||||
})
|
})
|
||||||
it("owner", function() {
|
it("owner", function() {
|
||||||
browser.setValueSafe(wd.$("modal-settings.owner"), "foobar")
|
browser.setValueSafe(wd.$("modal:settings.owner"), "foobar")
|
||||||
const elem = $(wd.$("modal-settings.name"));
|
const elem = $(wd.$("modal:settings.name"));
|
||||||
elem.click();
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
@ -149,8 +165,8 @@ describe("modals", function() {
|
||||||
assert.equal(styleObj.owner, "foobar");
|
assert.equal(styleObj.owner, "foobar");
|
||||||
})
|
})
|
||||||
it("sprite url", function() {
|
it("sprite url", function() {
|
||||||
browser.setValueSafe(wd.$("modal-settings.sprite"), "http://example.com")
|
browser.setValueSafe(wd.$("modal:settings.sprite"), "http://example.com")
|
||||||
const elem = $(wd.$("modal-settings.name"));
|
const elem = $(wd.$("modal:settings.name"));
|
||||||
elem.click();
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
@ -159,8 +175,8 @@ describe("modals", function() {
|
||||||
})
|
})
|
||||||
it("glyphs url", function() {
|
it("glyphs url", function() {
|
||||||
var glyphsUrl = "http://example.com/{fontstack}/{range}.pbf"
|
var glyphsUrl = "http://example.com/{fontstack}/{range}.pbf"
|
||||||
browser.setValueSafe(wd.$("modal-settings.glyphs"), glyphsUrl)
|
browser.setValueSafe(wd.$("modal:settings.glyphs"), glyphsUrl)
|
||||||
const elem = $(wd.$("modal-settings.name"));
|
const elem = $(wd.$("modal:settings.name"));
|
||||||
elem.click();
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
@ -170,8 +186,8 @@ describe("modals", function() {
|
||||||
|
|
||||||
it("mapbox access token", function() {
|
it("mapbox access token", function() {
|
||||||
var apiKey = "testing123";
|
var apiKey = "testing123";
|
||||||
browser.setValueSafe(wd.$("modal-settings.maputnik:mapbox_access_token"), apiKey);
|
browser.setValueSafe(wd.$("modal:settings.maputnik:mapbox_access_token"), apiKey);
|
||||||
const elem = $(wd.$("modal-settings.name"));
|
const elem = $(wd.$("modal:settings.name"));
|
||||||
elem.click();
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
@ -183,8 +199,8 @@ describe("modals", function() {
|
||||||
|
|
||||||
it("maptiler access token", function() {
|
it("maptiler access token", function() {
|
||||||
var apiKey = "testing123";
|
var apiKey = "testing123";
|
||||||
browser.setValueSafe(wd.$("modal-settings.maputnik:openmaptiles_access_token"), apiKey);
|
browser.setValueSafe(wd.$("modal:settings.maputnik:openmaptiles_access_token"), apiKey);
|
||||||
const elem = $(wd.$("modal-settings.name"));
|
const elem = $(wd.$("modal:settings.name"));
|
||||||
elem.click();
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
@ -194,8 +210,8 @@ describe("modals", function() {
|
||||||
|
|
||||||
it("thunderforest access token", function() {
|
it("thunderforest access token", function() {
|
||||||
var apiKey = "testing123";
|
var apiKey = "testing123";
|
||||||
browser.setValueSafe(wd.$("modal-settings.maputnik:thunderforest_access_token"), apiKey);
|
browser.setValueSafe(wd.$("modal:settings.maputnik:thunderforest_access_token"), apiKey);
|
||||||
const elem = $(wd.$("modal-settings.name"));
|
const elem = $(wd.$("modal:settings.name"));
|
||||||
elem.click();
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
@ -204,9 +220,9 @@ describe("modals", function() {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("style renderer", function() {
|
it("style renderer", function() {
|
||||||
const selector = $(wd.$("modal-settings.maputnik:renderer"));
|
const selector = $(wd.$("modal:settings.maputnik:renderer"));
|
||||||
selector.selectByAttribute('value', "ol");
|
selector.selectByAttribute('value', "ol");
|
||||||
const elem = $(wd.$("modal-settings.name"));
|
const elem = $(wd.$("modal:settings.name"));
|
||||||
elem.click();
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,14 @@ app.get("/styles/empty/:sources", function(req, res) {
|
||||||
res.send(json);
|
res.send(json);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.get("/example-layer-style.json", function(req, res) {
|
||||||
|
res.json(
|
||||||
|
JSON.parse(
|
||||||
|
fs.readFileSync(__dirname+"/example-layer-style.json").toString()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
|
||||||
app.get("/example-style.json", function(req, res) {
|
app.get("/example-style.json", function(req, res) {
|
||||||
res.json(
|
res.json(
|
||||||
JSON.parse(
|
JSON.parse(
|
||||||
|
|
Loading…
Reference in a new issue