diff --git a/config/webpack.production.config.js b/config/webpack.production.config.js
index c015f4a..a1e1e58 100644
--- a/config/webpack.production.config.js
+++ b/config/webpack.production.config.js
@@ -14,25 +14,6 @@ var OUTPATH = artifacts.pathSync("/build");
module.exports = {
entry: {
app: './src/index.jsx',
- vendor: [
- 'file-saver',
- 'mapbox-gl/dist/mapbox-gl.js',
- "lodash.clonedeep",
- "lodash.throttle",
- 'color',
- 'react',
- "react-dom",
- "react-color",
- "react-file-reader-input",
- "react-collapse",
- "react-height",
- "react-icon-base",
- "react-motion",
- "react-sortable-hoc",
- "request",
- //TODO: Icons raise multi vendor errors?
- //"react-icons",
- ]
},
output: {
path: OUTPATH,
@@ -55,7 +36,6 @@ module.exports = {
},
plugins: [
new webpack.NoEmitOnErrorsPlugin(),
- new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: '[chunkhash].vendor.js' }),
new WebpackCleanupPlugin(),
new webpack.DefinePlugin({
'process.env': {
diff --git a/package.json b/package.json
index 317bfc2..4aae8d0 100644
--- a/package.json
+++ b/package.json
@@ -10,8 +10,7 @@
"test-watch": "cross-env NODE_ENV=test wdio config/wdio.conf.js --watch",
"start": "webpack-dev-server --progress --profile --colors --config config/webpack.config.js",
"lint": "eslint --ext js --ext jsx {src,test}",
- "lint-styles": "stylelint 'src/styles/*.scss'",
- "nsp": "nsp check --reporter summary"
+ "lint-styles": "stylelint 'src/styles/*.scss'"
},
"repository": {
"type": "git",
@@ -27,7 +26,6 @@
"codemirror": "^5.37.0",
"color": "^3.0.0",
"file-saver": "^1.3.8",
- "github-api": "^3.0.0",
"jsonlint": "github:josdejong/jsonlint#85a19d7",
"lodash.capitalize": "^4.2.1",
"lodash.clamp": "^4.0.3",
@@ -37,28 +35,24 @@
"mapbox-gl": "^0.47.0",
"mapbox-gl-inspect": "^1.3.1",
"maputnik-design": "github:maputnik/design",
- "mousetrap": "^1.6.1",
"ol-mapbox-style": "^2.10.1",
"ol": "^4.6.5",
"prop-types": "^15.6.0",
"react": "^16.3.2",
- "react-addons-pure-render-mixin": "^15.6.2",
"react-aria-menubutton": "^5.1.1",
"react-aria-modal": "^2.12.1",
+ "react-autobind": "^1.0.6",
"react-autocomplete": "^1.7.2",
"react-codemirror2": "^4.2.1",
"react-collapse": "^4.0.3",
"react-color": "^2.14.1",
- "react-copy-to-clipboard": "^5.0.1",
"react-dom": "^16.3.2",
"react-file-reader-input": "^1.1.4",
- "react-height": "^3.0.0",
"react-icon-base": "^2.1.1",
"react-icons": "^2.2.7",
"react-motion": "^0.5.2",
"react-sortable-hoc": "^0.6.8",
"reconnecting-websocket": "^3.2.2",
- "request": "^2.85.0",
"url": "^0.11.0"
},
"jshintConfig": {
@@ -135,7 +129,7 @@
"mkdirp": "^0.5.1",
"mocha": "^5.1.1",
"node-sass": "^4.9.0",
- "nsp": "^3.1.0",
+ "raw-loader": "^0.5.1",
"react-hot-loader": "^3.1.1",
"sass-loader": "^7.0.1",
"selenium-standalone": "^6.14.0",
@@ -147,7 +141,6 @@
"uglifyjs-webpack-plugin": "^1.2.4",
"uuid": "^3.1.0",
"wdio-mocha-framework": "^0.5.13",
- "wdio-phantomjs-service": "^0.2.2",
"wdio-selenium-standalone-service": "0.0.10",
"wdio-spec-reporter": "^0.1.2",
"webdriverio": "^4.12.0",
diff --git a/src/components/App.jsx b/src/components/App.jsx
index e317f92..c1f3a9a 100644
--- a/src/components/App.jsx
+++ b/src/components/App.jsx
@@ -1,12 +1,11 @@
+import autoBind from 'react-autobind';
import React from 'react'
-import Mousetrap from 'mousetrap'
import cloneDeep from 'lodash.clonedeep'
import clamp from 'lodash.clamp'
import {arrayMove} from 'react-sortable-hoc'
import url from 'url'
import MapboxGlMap from './map/MapboxGlMap'
-import OpenLayers3Map from './map/OpenLayers3Map'
import LayerList from './layers/LayerList'
import LayerEditor from './layers/LayerEditor'
import Toolbar from './Toolbar'
@@ -54,6 +53,8 @@ function updateRootSpec(spec, fieldName, newValues) {
export default class App extends React.Component {
constructor(props) {
super(props)
+ autoBind(this);
+
this.revisionStore = new RevisionStore()
this.styleStore = new ApiStyleStore({
onLocalStyleChange: mapStyle => this.onStyleChanged(mapStyle, false)
@@ -187,14 +188,33 @@ export default class App extends React.Component {
})
}
+ handleKeyPress(e) {
+ if(navigator.platform.toUpperCase().indexOf('MAC') >= 0) {
+ if(e.metaKey && e.shiftKey && e.keyCode === 90) {
+ console.log("redo");
+ this.onRedo(e);
+ }
+ else if(e.metaKey && e.keyCode === 90) {
+ console.log("undo");
+ this.onUndo(e);
+ }
+ }
+ else {
+ if(e.ctrlKey && e.keyCode === 90) {
+ this.onUndo(e);
+ }
+ else if(e.ctrlKey && e.keyCode === 89) {
+ this.onRedo(e);
+ }
+ }
+ }
+
componentDidMount() {
- Mousetrap.bind(['mod+z'], this.onUndo.bind(this));
- Mousetrap.bind(['mod+y', 'mod+shift+z'], this.onRedo.bind(this));
+ window.addEventListener("keydown", this.handleKeyPress);
}
componentWillUnmount() {
- Mousetrap.unbind(['mod+z'], this.onUndo.bind(this));
- Mousetrap.unbind(['mod+y', 'mod+shift+z'], this.onRedo.bind(this));
+ window.removeEventListener("keydown", this.handleKeyPress);
}
saveStyle(snapshotStyle) {
@@ -371,7 +391,9 @@ export default class App extends React.Component {
console.warn("Failed to normalizeSourceURL: ", err);
}
- fetch(url)
+ fetch(url, {
+ mode: 'cors',
+ })
.then((response) => {
return response.json();
})
@@ -423,12 +445,12 @@ export default class App extends React.Component {
// Check if OL3 code has been loaded?
if(renderer === 'ol3') {
- mapElement =
+ mapElement =
TODO
} else {
mapElement =
+ onLayerSelect={this.onLayerSelect} />
}
const elementStyle = {};
diff --git a/src/components/modals/ExportModal.jsx b/src/components/modals/ExportModal.jsx
index f7d997a..394b168 100644
--- a/src/components/modals/ExportModal.jsx
+++ b/src/components/modals/ExportModal.jsx
@@ -11,206 +11,8 @@ import Modal from './Modal'
import MdFileDownload from 'react-icons/lib/md/file-download'
import TiClipboard from 'react-icons/lib/ti/clipboard'
import style from '../../libs/style'
-import GitHub from 'github-api'
-import { CopyToClipboard } from 'react-copy-to-clipboard'
-class Gist extends React.Component {
- static propTypes = {
- mapStyle: PropTypes.object.isRequired,
- onStyleChanged: PropTypes.func.isRequired,
- }
-
- constructor(props) {
- super(props);
- this.state = {
- preview: false,
- public: false,
- saving: false,
- latestGist: null,
- }
- }
-
- UNSAFE_componentWillReceiveProps(nextProps) {
- this.setState({
- ...this.state,
- preview: !!(nextProps.mapStyle.metadata || {})['maputnik:openmaptiles_access_token']
- })
- }
-
- onSave() {
- this.setState({
- ...this.state,
- saving: true
- });
-
- const preview = this.state.preview;
-
- const mapboxToken = (this.props.mapStyle.metadata || {})['maputnik:mapbox_access_token'];
-
- const mapStyleStr = preview ?
- styleSpec.format(stripAccessTokens(style.replaceAccessTokens(this.props.mapStyle))) :
- styleSpec.format(stripAccessTokens(this.props.mapStyle));
- const styleTitle = this.props.mapStyle.name || 'Style';
- const htmlStr = `
-
-
-
-
-
- `+styleTitle+` Preview
-
-
-
-
-
-
-
-
-
-`
- const files = {
- "style.json": {
- content: mapStyleStr
- }
- }
- if(preview) {
- files["index.html"] = {
- content: htmlStr
- }
- }
- const gh = new GitHub();
- let gist = gh.getGist(); // not a gist yet
- gist.create({
- public: this.state.public,
- description: styleTitle,
- files: files
- }).then(function({data}) {
- return gist.read();
- }).then(function({data}) {
- this.setState({
- ...this.state,
- latestGist: data,
- saving: false,
- });
- }.bind(this));
- }
-
- onPreviewChange(value) {
- this.setState({
- ...this.state,
- preview: value
- })
- }
-
- onPublicChange(value) {
- this.setState({
- ...this.state,
- public: value
- })
- }
-
- changeMetadataProperty(property, value) {
- const changedStyle = {
- ...this.props.mapStyle,
- metadata: {
- ...this.props.mapStyle.metadata,
- [property]: value
- }
- }
- this.props.onStyleChanged(changedStyle)
- }
-
- renderPreviewLink() {
- const gist = this.state.latestGist;
- const user = gist.user || 'anonymous';
- const preview = !!gist.files['index.html'];
- if(preview) {
- return Preview,{' '}
- }
- return null;
- }
-
- renderLatestGist() {
- const gist = this.state.latestGist;
- const saving = this.state.saving;
- if(saving) {
- return Saving...
- } else if(gist) {
- const user = gist.user || 'anonymous';
- const rawGistLink = "https://gist.githubusercontent.com/" + user + "/" + gist.id + "/raw/" + gist.history[0].version + "/style.json"
- const maputnikStyleLink = "https://maputnik.github.io/editor/?style=" + rawGistLink
- return
-
- Latest saved gist:{' '}
- {this.renderPreviewLink(this)}
- Source
-
-
-
- Share this style:
-
-
-
-
- }
- }
-
- render() {
- return
-
-
-
- Public gist
-
-
-
- Include preview
-
- {this.state.preview ?
-
- : null}
- {this.renderLatestGist()}
-
- }
-}
function stripAccessTokens(mapStyle) {
const changedMetadata = { ...mapStyle.metadata }
@@ -294,10 +96,6 @@ class ExportModal extends React.Component {
-
-
Save style
-
-
}
}
diff --git a/src/components/modals/OpenModal.jsx b/src/components/modals/OpenModal.jsx
index d9df74c..68d1576 100644
--- a/src/components/modals/OpenModal.jsx
+++ b/src/components/modals/OpenModal.jsx
@@ -4,7 +4,6 @@ import LoadingModal from './LoadingModal'
import Modal from './Modal'
import Button from '../Button'
import FileReaderInput from 'react-file-reader-input'
-import request from 'request'
import FileUploadIcon from 'react-icons/lib/md/file-upload'
import AddIcon from 'react-icons/lib/md/add-circle-outline'
@@ -77,30 +76,36 @@ class OpenModal extends React.Component {
onStyleSelect(styleUrl) {
this.clearError();
- const reqOpts = {
- url: styleUrl,
- withCredentials: false,
- }
-
- const activeRequest = request(reqOpts, (error, response, body) => {
+ const activeRequest = fetch(styleUrl, {
+ mode: 'cors',
+ credentials: "same-origin"
+ })
+ .then(function(response) {
+ return response.json();
+ })
+ .then((body) => {
this.setState({
activeRequest: null,
activeRequestUrl: null
});
- if (!error && response.statusCode == 200) {
- const mapStyle = style.ensureStyleValidity(JSON.parse(body))
- console.log('Loaded style ', mapStyle.id)
- this.props.onStyleOpen(mapStyle)
- this.onOpenToggle()
- } else {
- console.warn('Could not open the style URL', styleUrl)
- }
+ const mapStyle = style.ensureStyleValidity(body)
+ console.log('Loaded style ', mapStyle.id)
+ this.props.onStyleOpen(mapStyle)
+ this.onOpenToggle()
+ })
+ .catch((err) => {
+ this.setState({
+ activeRequest: null,
+ activeRequestUrl: null
+ });
+ console.error(err);
+ console.warn('Could not open the style URL', styleUrl)
})
this.setState({
activeRequest: activeRequest,
- activeRequestUrl: reqOpts.url
+ activeRequestUrl: styleUrl
})
}
diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx
index b7da0a1..f43d435 100644
--- a/src/components/modals/SettingsModal.jsx
+++ b/src/components/modals/SettingsModal.jsx
@@ -107,7 +107,7 @@ class SettingsModal extends React.Component {
data-wd-key="modal-settings.maputnik:renderer"
options={[
['mbgljs', 'MapboxGL JS'],
- ['ol3', 'Open Layers 3'],
+ // ['ol3', 'Open Layers 3'],
]}
value={metadata['maputnik:renderer'] || 'mbgljs'}
onChange={this.changeMetadataProperty.bind(this, 'maputnik:renderer')}
diff --git a/src/libs/accessibility.js b/src/libs/accessibility.js
index 095e953..23c1339 100644
--- a/src/libs/accessibility.js
+++ b/src/libs/accessibility.js
@@ -1,8 +1,8 @@
-import lodash from 'lodash'
+import throttle from 'lodash.throttle'
// Throttle for 3 seconds so when a user enables it they don't have to refresh the page.
-const reducedMotionEnabled = lodash.throttle(() => {
+const reducedMotionEnabled = throttle(() => {
return window.matchMedia("(prefers-reduced-motion: reduce)").matches
}, 3000);
diff --git a/src/libs/apistore.js b/src/libs/apistore.js
index 91fa7e2..aa114b2 100644
--- a/src/libs/apistore.js
+++ b/src/libs/apistore.js
@@ -1,4 +1,3 @@
-import request from 'request'
import style from './style.js'
import ReconnectingWebSocket from 'reconnecting-websocket'
@@ -14,15 +13,20 @@ export class ApiStyleStore {
}
init(cb) {
- request(localUrl + '/styles', (error, response, body) => {
- if (!error && body && response.statusCode == 200) {
- const styleIds = JSON.parse(body)
- this.latestStyleId = styleIds[0]
- this.notifyLocalChanges()
- cb(null)
- } else {
- cb(new Error('Can not connect to style API'))
- }
+ fetch(localUrl + '/styles', {
+ mode: 'cors',
+ })
+ .then(function(response) {
+ return response.json();
+ })
+ .then(function(body) {
+ const styleIds = body;
+ this.latestStyleId = styleIds[0]
+ this.notifyLocalChanges()
+ cb(null)
+ })
+ .catch(function() {
+ cb(new Error('Can not connect to style API'))
})
}
@@ -44,8 +48,14 @@ export class ApiStyleStore {
latestStyle(cb) {
if(this.latestStyleId) {
- request(localUrl + '/styles/' + this.latestStyleId, (error, response, body) => {
- cb(style.ensureStyleValidity(JSON.parse(body)))
+ fetch(localUrl + '/styles/' + this.latestStyleId, {
+ mode: 'cors',
+ })
+ .then(function(response) {
+ return response.json();
+ })
+ .then(function(body) {
+ cb(style.ensureStyleValidity(body))
})
} else {
throw new Error('No latest style available. You need to init the api backend first.')
@@ -55,11 +65,15 @@ export class ApiStyleStore {
// Save current style replacing previous version
save(mapStyle) {
const id = mapStyle.id
- request.put({
- url: localUrl + '/styles/' + id,
- json: true,
- body: mapStyle
- }, (error, response, body) => {
+ fetch(localUrl + '/styles/' + id, {
+ method: "PUT",
+ mode: 'cors',
+ headers: {
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ body: JSON.stringify(mapStyle)
+ })
+ .catch(function(error) {
if(error) console.error(error)
})
return mapStyle
diff --git a/src/libs/mapbox-rtl.js b/src/libs/mapbox-rtl.js
index f9dc199..84d9211 100644
--- a/src/libs/mapbox-rtl.js
+++ b/src/libs/mapbox-rtl.js
@@ -1,9 +1,9 @@
-import MapboxGl from 'mapbox-gl/dist/mapbox-gl.js'
+import MapboxGl from 'mapbox-gl'
// Load mapbox-gl-rtl-text using object urls without needing http://localhost for AJAX.
-const data = require("base64-loader?mimetype=text/javascript!@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.js");
+const data = require("raw-loader?mimetype=text/javascript!@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.js");
-const blob = new window.Blob([window.atob(data)]);
+const blob = new window.Blob([data]);
const objectUrl = window.URL.createObjectURL(blob, {
type: "text/javascript"
});
diff --git a/src/libs/metadata.js b/src/libs/metadata.js
index deac199..2e1fb24 100644
--- a/src/libs/metadata.js
+++ b/src/libs/metadata.js
@@ -1,22 +1,19 @@
-import request from 'request'
import npmurl from 'url'
function loadJSON(url, defaultValue, cb) {
- request({
- url: url,
- withCredentials: false,
- }, (error, response, body) => {
- if (!error && body && response.statusCode == 200) {
- try {
- cb(JSON.parse(body))
- } catch(err) {
- console.error(err)
- cb(defaultValue)
- }
- } else {
- console.warn('Can not metadata for ' + url)
- cb(defaultValue)
- }
+ fetch(url, {
+ mode: 'cors',
+ credentials: "same-origin"
+ })
+ .then(function(response) {
+ return response.json();
+ })
+ .then(function(body) {
+ cb(body)
+ })
+ .catch(function() {
+ console.warn('Can not metadata for ' + url)
+ cb(defaultValue)
})
}
diff --git a/src/libs/stylestore.js b/src/libs/stylestore.js
index c921d5c..b23c1e1 100644
--- a/src/libs/stylestore.js
+++ b/src/libs/stylestore.js
@@ -2,7 +2,6 @@ import { colorizeLayers } from './style.js'
import style from './style.js'
import { loadStyleUrl } from './urlopen'
import publicSources from '../config/styles.json'
-import request from 'request'
const storagePrefix = "maputnik"
const stylePrefix = 'style'
diff --git a/src/libs/urlopen.js b/src/libs/urlopen.js
index 93c550a..20b7aa3 100644
--- a/src/libs/urlopen.js
+++ b/src/libs/urlopen.js
@@ -1,4 +1,3 @@
-import request from 'request'
import url from 'url'
import style from './style.js'
@@ -9,34 +8,40 @@ export function initialStyleUrl() {
export function loadStyleUrl(styleUrl, cb) {
console.log('Loading style', styleUrl)
- request({
- url: styleUrl,
- withCredentials: false,
- }, (error, response, body) => {
- if (!error && response.statusCode == 200) {
- cb(style.ensureStyleValidity(JSON.parse(body)))
- } else {
- console.warn('Could not fetch default style', styleUrl)
- cb(style.emptyStyle)
- }
+ fetch(styleUrl, {
+ mode: 'cors',
+ credentials: "same-origin"
+ })
+ .then(function(response) {
+ return response.json();
+ })
+ .then(function(body) {
+ cb(style.ensureStyleValidity(body))
+ })
+ .catch(function() {
+ console.warn('Could not fetch default style', styleUrl)
+ cb(style.emptyStyle)
})
}
export function loadJSON(url, defaultValue, cb) {
- request({
- url: url,
- withCredentials: false,
- }, (error, response, body) => {
- if (!error && body && response.statusCode == 200) {
- try {
- cb(JSON.parse(body))
- } catch(err) {
- console.error(err)
- cb(defaultValue)
- }
- } else {
- console.error('Can not load JSON from ' + url)
+ fetch(url, {
+ mode: 'cors',
+ credentials: "same-origin"
+ })
+ .then(function(response) {
+ return response.json();
+ })
+ .then(function(body) {
+ try {
+ cb(body)
+ } catch(err) {
+ console.error(err)
cb(defaultValue)
}
})
+ .catch(function() {
+ console.error('Can not load JSON from ' + url)
+ cb(defaultValue)
+ })
}