mirror of
https://github.com/a-nyx/maputnik-with-pmtiles.git
synced 2024-12-29 09:20:26 +01:00
Merge branch 'master' into node_v12_test_runners
This commit is contained in:
commit
fbf828e202
23 changed files with 3115 additions and 1030 deletions
|
@ -52,14 +52,14 @@ jobs:
|
||||||
build-linux-node-v8:
|
build-linux-node-v8:
|
||||||
docker:
|
docker:
|
||||||
- image: node:8
|
- image: node:8
|
||||||
- image: selenium/standalone-chrome:3.8.1
|
|
||||||
working_directory: ~/repo-linux-node-v8
|
working_directory: ~/repo-linux-node-v8
|
||||||
steps: *wdio-steps
|
steps: *build-steps
|
||||||
build-linux-node-v10:
|
build-linux-node-v10:
|
||||||
docker:
|
docker:
|
||||||
- image: node:10
|
- image: node:10
|
||||||
|
- image: selenium/standalone-chrome:3.141.59
|
||||||
working_directory: ~/repo-linux-node-v10
|
working_directory: ~/repo-linux-node-v10
|
||||||
steps: *build-steps
|
steps: *wdio-steps
|
||||||
build-linux-node-v11:
|
build-linux-node-v11:
|
||||||
docker:
|
docker:
|
||||||
- image: node:11
|
- image: node:11
|
||||||
|
|
16
README.md
16
README.md
|
@ -9,10 +9,10 @@
|
||||||
[circleci]: https://circleci.com/gh/maputnik/editor/tree/master
|
[circleci]: https://circleci.com/gh/maputnik/editor/tree/master
|
||||||
[appveyor]: https://ci.appveyor.com/project/lukasmartinelli/editor
|
[appveyor]: https://ci.appveyor.com/project/lukasmartinelli/editor
|
||||||
[dm-prod]: https://david-dm.org/maputnik/editor
|
[dm-prod]: https://david-dm.org/maputnik/editor
|
||||||
[dm-dev]: https://david-dm.org/maputnik/editor#info=devDependencies
|
[dm-dev]: https://david-dm.org/maputnik/editor?type=dev
|
||||||
[license]: https://tldrlegal.com/license/mit-license
|
[license]: https://tldrlegal.com/license/mit-license
|
||||||
|
|
||||||
<img width="200" align="right" alt="Maputnik" src="src/img/maputnik.png" />
|
<img width="200" align="right" alt="Maputnik" src="https://cdn.jsdelivr.net/gh/maputnik/editor@1.5.0/src/img/maputnik.png" />
|
||||||
|
|
||||||
A free and open visual editor for the [Mapbox GL styles](https://www.mapbox.com/mapbox-gl-style-spec/)
|
A free and open visual editor for the [Mapbox GL styles](https://www.mapbox.com/mapbox-gl-style-spec/)
|
||||||
targeted at developers and map designers.
|
targeted at developers and map designers.
|
||||||
|
@ -118,13 +118,13 @@ Thanks to the supporters of the **[Kickstarter campaign](https://www.kickstarter
|
||||||
- [Terranodo](http://terranodo.io/)
|
- [Terranodo](http://terranodo.io/)
|
||||||
|
|
||||||
<a href="https://getwemap.com/">
|
<a href="https://getwemap.com/">
|
||||||
<img width="33%" alt="Wemap" style="display:inline" src="media/sponsors/wemap.jpg" />
|
<img width="33%" alt="Wemap" style="display:inline" src="https://cdn.jsdelivr.net/gh/maputnik/editor@1.5.0/media/sponsors/wemap.jpg" />
|
||||||
</a>
|
</a>
|
||||||
<a href="http://terranodo.io/">
|
<a href="http://terranodo.io/">
|
||||||
<img width="33%" alt="Terranodo" style="display:inline" src="media/sponsors/terranodo.png" />
|
<img width="33%" alt="Terranodo" style="display:inline" src="https://cdn.jsdelivr.net/gh/maputnik/editor@1.5.0/media/sponsors/terranodo.png" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.orbiconinformatik.dk/">
|
<a href="https://www.orbiconinformatik.dk/">
|
||||||
<img width="32%" alt="Terranodo" style="display:inline" src="media/sponsors/orbicon_informatik.png" />
|
<img width="32%" alt="Terranodo" style="display:inline" src="https://cdn.jsdelivr.net/gh/maputnik/editor@1.5.0/media/sponsors/orbicon_informatik.png" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
@ -136,13 +136,13 @@ Thanks to the supporters of the **[Kickstarter campaign](https://www.kickstarter
|
||||||
- [Dreipol](https://www.dreipol.ch/)
|
- [Dreipol](https://www.dreipol.ch/)
|
||||||
|
|
||||||
<a href="https://www.klokantech.com/">
|
<a href="https://www.klokantech.com/">
|
||||||
<img width="18%" alt="Klokan Technologies" style="display:inline-block" src="media/sponsors/klokantech.png" />
|
<img width="18%" alt="Klokan Technologies" style="display:inline-block" src="https://cdn.jsdelivr.net/gh/maputnik/editor@1.5.0/media/sponsors/klokantech.png" />
|
||||||
</a>
|
</a>
|
||||||
<a href="http://www.geofabrik.de/">
|
<a href="http://www.geofabrik.de/">
|
||||||
<img width="18%" alt="Geofabrik" style="display:inline-block" src="media/sponsors/geofabrik.png" />
|
<img width="18%" alt="Geofabrik" style="display:inline-block" src="https://cdn.jsdelivr.net/gh/maputnik/editor@1.5.0/media/sponsors/geofabrik.png" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.dreipol.ch/">
|
<a href="https://www.dreipol.ch/">
|
||||||
<img width="18%" alt="Dreipol" style="display:inline-block" src="media/sponsors/dreipol.png" />
|
<img width="18%" alt="Dreipol" style="display:inline-block" src="https://cdn.jsdelivr.net/gh/maputnik/editor@1.5.0/media/sponsors/dreipol.png" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
|
@ -10,53 +10,279 @@ var server;
|
||||||
var SCREENSHOT_PATH = artifacts.pathSync("screenshots");
|
var SCREENSHOT_PATH = artifacts.pathSync("screenshots");
|
||||||
|
|
||||||
exports.config = {
|
exports.config = {
|
||||||
specs: [
|
//
|
||||||
'./test/functional/index.js'
|
// ====================
|
||||||
],
|
// Runner Configuration
|
||||||
exclude: [
|
// ====================
|
||||||
],
|
//
|
||||||
maxInstances: 10,
|
// WebdriverIO allows it to run your tests in arbitrary locations (e.g. locally or
|
||||||
capabilities: [{
|
// on a remote machine).
|
||||||
maxInstances: 5,
|
runner: 'local',
|
||||||
browserName: 'chrome'
|
//
|
||||||
}],
|
// ==================
|
||||||
sync: true,
|
// Specify Test Files
|
||||||
logLevel: 'verbose',
|
// ==================
|
||||||
coloredLogs: true,
|
// Define which test specs should run. The pattern is relative to the directory
|
||||||
bail: 0,
|
// from which `wdio` was called. Notice that, if you are calling `wdio` from an
|
||||||
screenshotPath: SCREENSHOT_PATH,
|
// NPM script (see https://docs.npmjs.com/cli/run-script) then the current working
|
||||||
// Note: This is here because @orangemug currently runs Maputnik inside a docker container.
|
// directory is where your package.json resides, so `wdio` will be called from there.
|
||||||
host: process.env.DOCKER_HOST || "0.0.0.0",
|
//
|
||||||
baseUrl: 'http://localhost',
|
specs: [
|
||||||
waitforTimeout: 10000,
|
'./test/functional/index.js'
|
||||||
connectionRetryTimeout: 90000,
|
],
|
||||||
connectionRetryCount: 3,
|
// Patterns to exclude.
|
||||||
framework: 'mocha',
|
exclude: [
|
||||||
reporters: ['spec'],
|
// 'path/to/excluded/files'
|
||||||
mochaOpts: {
|
],
|
||||||
ui: 'bdd',
|
//
|
||||||
// Because we don't know how long the initial build will take...
|
// ============
|
||||||
timeout: 4*60*1000
|
// Capabilities
|
||||||
},
|
// ============
|
||||||
onPrepare: function (config, capabilities) {
|
// Define your capabilities here. WebdriverIO can run multiple capabilities at the same
|
||||||
return new Promise(function(resolve, reject) {
|
// time. Depending on the number of capabilities, WebdriverIO launches several test
|
||||||
var compiler = webpack(webpackConfig);
|
// sessions. Within your capabilities you can overwrite the spec and exclude options in
|
||||||
server = new WebpackDevServer(compiler, {
|
// order to group specific specs to a specific capability.
|
||||||
stats: {
|
//
|
||||||
colors: true
|
// First, you can define how many instances should be started at the same time. Let's
|
||||||
}
|
// say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have
|
||||||
});
|
// set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec
|
||||||
server.listen(testConfig.port, (isDocker() ? "0.0.0.0" : "localhost"), function(err) {
|
// files and you set maxInstances to 10, all spec files will get tested at the same time
|
||||||
if(err) {
|
// and 30 processes will get spawned. The property handles how many capabilities
|
||||||
reject(err);
|
// from the same test should run tests.
|
||||||
}
|
//
|
||||||
else {
|
maxInstances: 10,
|
||||||
resolve();
|
//
|
||||||
}
|
// If you have trouble getting all important capabilities together, check out the
|
||||||
});
|
// Sauce Labs platform configurator - a great tool to configure your capabilities:
|
||||||
})
|
// https://docs.saucelabs.com/reference/platforms-configurator
|
||||||
},
|
//
|
||||||
onComplete: function(exitCode) {
|
capabilities: [{
|
||||||
server.close()
|
// maxInstances can get overwritten per capability. So if you have an in-house Selenium
|
||||||
}
|
// grid with only 5 firefox instances available you can make sure that not more than
|
||||||
|
// 5 instances get started at a time.
|
||||||
|
maxInstances: 5,
|
||||||
|
//
|
||||||
|
browserName: 'chrome',
|
||||||
|
// If outputDir is provided WebdriverIO can capture driver session logs
|
||||||
|
// it is possible to configure which logTypes to include/exclude.
|
||||||
|
// excludeDriverLogs: ['*'], // pass '*' to exclude all driver session logs
|
||||||
|
// excludeDriverLogs: ['bugreport', 'server'],
|
||||||
|
}],
|
||||||
|
//
|
||||||
|
// ===================
|
||||||
|
// Test Configurations
|
||||||
|
// ===================
|
||||||
|
// Define all options that are relevant for the WebdriverIO instance here
|
||||||
|
//
|
||||||
|
// Level of logging verbosity: trace | debug | info | warn | error | silent
|
||||||
|
logLevel: 'info',
|
||||||
|
//
|
||||||
|
// Set specific log levels per logger
|
||||||
|
// loggers:
|
||||||
|
// - webdriver, webdriverio
|
||||||
|
// - @wdio/applitools-service, @wdio/browserstack-service, @wdio/devtools-service, @wdio/sauce-service
|
||||||
|
// - @wdio/mocha-framework, @wdio/jasmine-framework
|
||||||
|
// - @wdio/local-runner, @wdio/lambda-runner
|
||||||
|
// - @wdio/sumologic-reporter
|
||||||
|
// - @wdio/cli, @wdio/config, @wdio/sync, @wdio/utils
|
||||||
|
// Level of logging verbosity: trace | debug | info | warn | error | silent
|
||||||
|
// logLevels: {
|
||||||
|
// webdriver: 'debug',
|
||||||
|
// '@wdio/applitools-service': 'info'
|
||||||
|
// },
|
||||||
|
//
|
||||||
|
// If you only want to run your tests until a specific amount of tests have failed use
|
||||||
|
// bail (default is 0 - don't bail, run all tests).
|
||||||
|
bail: 0,
|
||||||
|
//
|
||||||
|
screenshotPath: SCREENSHOT_PATH,
|
||||||
|
// Note: This is here because @orangemug currently runs Maputnik inside a docker container.
|
||||||
|
host: process.env.DOCKER_HOST || "0.0.0.0",
|
||||||
|
// Set a base URL in order to shorten url command calls. If your `url` parameter starts
|
||||||
|
// with `/`, the base url gets prepended, not including the path portion of your baseUrl.
|
||||||
|
// If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url
|
||||||
|
// gets prepended directly.
|
||||||
|
baseUrl: 'http://localhost',
|
||||||
|
//
|
||||||
|
// Default timeout for all waitFor* commands.
|
||||||
|
waitforTimeout: 10000,
|
||||||
|
//
|
||||||
|
// Default timeout in milliseconds for request
|
||||||
|
// if Selenium Grid doesn't send response
|
||||||
|
connectionRetryTimeout: 90000,
|
||||||
|
//
|
||||||
|
// Default request retries count
|
||||||
|
connectionRetryCount: 3,
|
||||||
|
//
|
||||||
|
// Test runner services
|
||||||
|
// Services take over a specific job you don't want to take care of. They enhance
|
||||||
|
// your test setup with almost no effort. Unlike plugins, they don't add new
|
||||||
|
// commands. Instead, they hook themselves up into the test process.
|
||||||
|
services: ['selenium-standalone'],
|
||||||
|
//
|
||||||
|
// Framework you want to run your specs with.
|
||||||
|
// The following are supported: Mocha, Jasmine, and Cucumber
|
||||||
|
// see also: https://webdriver.io/docs/frameworks.html
|
||||||
|
//
|
||||||
|
// Make sure you have the wdio adapter package for the specific framework installed
|
||||||
|
// before running any tests.
|
||||||
|
framework: 'mocha',
|
||||||
|
//
|
||||||
|
// The number of times to retry the entire specfile when it fails as a whole
|
||||||
|
// specFileRetries: 1,
|
||||||
|
//
|
||||||
|
// Test reporter for stdout.
|
||||||
|
// The only one supported by default is 'dot'
|
||||||
|
// see also: https://webdriver.io/docs/dot-reporter.html
|
||||||
|
reporters: ['spec'],
|
||||||
|
|
||||||
|
//
|
||||||
|
// Options to be passed to Mocha.
|
||||||
|
// See the full list at http://mochajs.org/
|
||||||
|
mochaOpts: {
|
||||||
|
ui: 'bdd',
|
||||||
|
// Because we don't know how long the initial build will take...
|
||||||
|
timeout: 4*60*1000
|
||||||
|
},
|
||||||
|
onPrepare: function (config, capabilities) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
var compiler = webpack(webpackConfig);
|
||||||
|
server = new WebpackDevServer(compiler, {
|
||||||
|
stats: {
|
||||||
|
colors: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
server.listen(testConfig.port, (isDocker() ? "0.0.0.0" : "localhost"), function(err) {
|
||||||
|
if(err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onComplete: function(exitCode) {
|
||||||
|
server.close()
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// =====
|
||||||
|
// Hooks
|
||||||
|
// =====
|
||||||
|
// WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance
|
||||||
|
// it and to build services around it. You can either apply a single function or an array of
|
||||||
|
// methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got
|
||||||
|
// resolved to continue.
|
||||||
|
/**
|
||||||
|
* Gets executed once before all workers get launched.
|
||||||
|
* @param {Object} config wdio configuration object
|
||||||
|
* @param {Array.<Object>} capabilities list of capabilities details
|
||||||
|
*/
|
||||||
|
// onPrepare: function (config, capabilities) {
|
||||||
|
// },
|
||||||
|
/**
|
||||||
|
* Gets executed just before initialising the webdriver session and test framework. It allows you
|
||||||
|
* to manipulate configurations depending on the capability or spec.
|
||||||
|
* @param {Object} config wdio configuration object
|
||||||
|
* @param {Array.<Object>} capabilities list of capabilities details
|
||||||
|
* @param {Array.<String>} specs List of spec file paths that are to be run
|
||||||
|
*/
|
||||||
|
// beforeSession: function (config, capabilities, specs) {
|
||||||
|
// },
|
||||||
|
/**
|
||||||
|
* Gets executed before test execution begins. At this point you can access to all global
|
||||||
|
* variables like `browser`. It is the perfect place to define custom commands.
|
||||||
|
* @param {Array.<Object>} capabilities list of capabilities details
|
||||||
|
* @param {Array.<String>} specs List of spec file paths that are to be run
|
||||||
|
*/
|
||||||
|
// before: function (capabilities, specs) {
|
||||||
|
// },
|
||||||
|
/**
|
||||||
|
* Runs before a WebdriverIO command gets executed.
|
||||||
|
* @param {String} commandName hook command name
|
||||||
|
* @param {Array} args arguments that command would receive
|
||||||
|
*/
|
||||||
|
// beforeCommand: function (commandName, args) {
|
||||||
|
// },
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook that gets executed before the suite starts
|
||||||
|
* @param {Object} suite suite details
|
||||||
|
*/
|
||||||
|
// beforeSuite: function (suite) {
|
||||||
|
// },
|
||||||
|
/**
|
||||||
|
* Function to be executed before a test (in Mocha/Jasmine) or a step (in Cucumber) starts.
|
||||||
|
* @param {Object} test test details
|
||||||
|
*/
|
||||||
|
// beforeTest: function (test) {
|
||||||
|
// },
|
||||||
|
/**
|
||||||
|
* Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling
|
||||||
|
* beforeEach in Mocha)
|
||||||
|
*/
|
||||||
|
// beforeHook: function () {
|
||||||
|
// },
|
||||||
|
/**
|
||||||
|
* Hook that gets executed _after_ a hook within the suite starts (e.g. runs after calling
|
||||||
|
* afterEach in Mocha)
|
||||||
|
*/
|
||||||
|
// afterHook: function () {
|
||||||
|
// },
|
||||||
|
/**
|
||||||
|
* Function to be executed after a test (in Mocha/Jasmine) or a step (in Cucumber) starts.
|
||||||
|
* @param {Object} test test details
|
||||||
|
*/
|
||||||
|
// afterTest: function (test) {
|
||||||
|
// },
|
||||||
|
/**
|
||||||
|
* Hook that gets executed after the suite has ended
|
||||||
|
* @param {Object} suite suite details
|
||||||
|
*/
|
||||||
|
// afterSuite: function (suite) {
|
||||||
|
// },
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs after a WebdriverIO command gets executed
|
||||||
|
* @param {String} commandName hook command name
|
||||||
|
* @param {Array} args arguments that command would receive
|
||||||
|
* @param {Number} result 0 - command success, 1 - command error
|
||||||
|
* @param {Object} error error object if any
|
||||||
|
*/
|
||||||
|
// afterCommand: function (commandName, args, result, error) {
|
||||||
|
// },
|
||||||
|
/**
|
||||||
|
* Gets executed after all tests are done. You still have access to all global variables from
|
||||||
|
* the test.
|
||||||
|
* @param {Number} result 0 - test pass, 1 - test fail
|
||||||
|
* @param {Array.<Object>} capabilities list of capabilities details
|
||||||
|
* @param {Array.<String>} specs List of spec file paths that ran
|
||||||
|
*/
|
||||||
|
// after: function (result, capabilities, specs) {
|
||||||
|
// },
|
||||||
|
/**
|
||||||
|
* Gets executed right after terminating the webdriver session.
|
||||||
|
* @param {Object} config wdio configuration object
|
||||||
|
* @param {Array.<Object>} capabilities list of capabilities details
|
||||||
|
* @param {Array.<String>} specs List of spec file paths that ran
|
||||||
|
*/
|
||||||
|
// afterSession: function (config, capabilities, specs) {
|
||||||
|
// },
|
||||||
|
/**
|
||||||
|
* Gets executed after all workers got shut down and the process is about to exit. An error
|
||||||
|
* thrown in the onComplete hook will result in the test run failing.
|
||||||
|
* @param {Object} exitCode 0 - success, 1 - fail
|
||||||
|
* @param {Object} config wdio configuration object
|
||||||
|
* @param {Array.<Object>} capabilities list of capabilities details
|
||||||
|
* @param {<Object>} results object containing test results
|
||||||
|
*/
|
||||||
|
// onComplete: function(exitCode, config, capabilities, results) {
|
||||||
|
// },
|
||||||
|
/**
|
||||||
|
* Gets executed when a refresh happens.
|
||||||
|
* @param {String} oldSessionId session ID of the old session
|
||||||
|
* @param {String} newSessionId session ID of the new session
|
||||||
|
*/
|
||||||
|
//onReload: function(oldSessionId, newSessionId) {
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
2994
package-lock.json
generated
2994
package-lock.json
generated
File diff suppressed because it is too large
Load diff
25
package.json
25
package.json
|
@ -26,18 +26,20 @@
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"codemirror": "^5.40.2",
|
"codemirror": "^5.40.2",
|
||||||
"color": "^3.0.0",
|
"color": "^3.0.0",
|
||||||
|
"detect-browser": "^4.5.0",
|
||||||
"file-saver": "^1.3.8",
|
"file-saver": "^1.3.8",
|
||||||
"jsonlint": "github:josdejong/jsonlint#85a19d7",
|
"jsonlint": "github:josdejong/jsonlint#85a19d7",
|
||||||
"lodash.capitalize": "^4.2.1",
|
"lodash.capitalize": "^4.2.1",
|
||||||
"lodash.clamp": "^4.0.3",
|
"lodash.clamp": "^4.0.3",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
|
"lodash.get": "^4.4.2",
|
||||||
"lodash.isequal": "^4.5.0",
|
"lodash.isequal": "^4.5.0",
|
||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
"mapbox-gl": "^0.53.1",
|
"mapbox-gl": "^0.53.1",
|
||||||
"mapbox-gl-inspect": "^1.3.1",
|
"mapbox-gl-inspect": "^1.3.1",
|
||||||
"maputnik-design": "github:maputnik/design",
|
"maputnik-design": "github:maputnik/design",
|
||||||
"ol": "^5.2.0",
|
"ol": "^6.0.0-beta.8",
|
||||||
"ol-mapbox-style": "^3.1.0",
|
"ol-mapbox-style": "^5.0.0-beta.2",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.5.2",
|
"react": "^16.5.2",
|
||||||
"react-aria-menubutton": "^6.0.1",
|
"react-aria-menubutton": "^6.0.1",
|
||||||
|
@ -104,6 +106,12 @@
|
||||||
"@babel/preset-env": "^7.1.0",
|
"@babel/preset-env": "^7.1.0",
|
||||||
"@babel/preset-flow": "^7.0.0",
|
"@babel/preset-flow": "^7.0.0",
|
||||||
"@babel/preset-react": "^7.0.0",
|
"@babel/preset-react": "^7.0.0",
|
||||||
|
"@wdio/cli": "^5.10.4",
|
||||||
|
"@wdio/local-runner": "^5.10.4",
|
||||||
|
"@wdio/mocha-framework": "^5.10.1",
|
||||||
|
"@wdio/selenium-standalone-service": "^5.9.3",
|
||||||
|
"@wdio/spec-reporter": "^5.9.3",
|
||||||
|
"@wdio/sync": "^5.10.1",
|
||||||
"babel-eslint": "^10.0.1",
|
"babel-eslint": "^10.0.1",
|
||||||
"babel-loader": "8.0.4",
|
"babel-loader": "8.0.4",
|
||||||
"babel-plugin-istanbul": "^5.0.1",
|
"babel-plugin-istanbul": "^5.0.1",
|
||||||
|
@ -113,29 +121,26 @@
|
||||||
"css-loader": "^1.0.0",
|
"css-loader": "^1.0.0",
|
||||||
"eslint": "^5.6.1",
|
"eslint": "^5.6.1",
|
||||||
"eslint-plugin-react": "^7.11.1",
|
"eslint-plugin-react": "^7.11.1",
|
||||||
"express": "^4.16.3",
|
"express": "^4.17.1",
|
||||||
"file-loader": "^2.0.0",
|
"file-loader": "^2.0.0",
|
||||||
"html-webpack-plugin": "^3.2.0",
|
"html-webpack-plugin": "^3.2.0",
|
||||||
"is-docker": "^1.1.0",
|
"is-docker": "^2.0.0",
|
||||||
"istanbul": "^0.4.5",
|
"istanbul": "^0.4.5",
|
||||||
"istanbul-lib-coverage": "^2.0.1",
|
"istanbul-lib-coverage": "^2.0.1",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"mocha": "^5.2.0",
|
"mocha": "^6.1.4",
|
||||||
"node-sass": "^4.12.0",
|
"node-sass": "^4.12.0",
|
||||||
"raw-loader": "^0.5.1",
|
"raw-loader": "^0.5.1",
|
||||||
"react-hot-loader": "^4.3.11",
|
"react-hot-loader": "^4.3.11",
|
||||||
"sass-loader": "^7.1.0",
|
"sass-loader": "^7.1.0",
|
||||||
"selenium-standalone": "^6.15.3",
|
"selenium-standalone": "^6.16.0",
|
||||||
"style-loader": "^0.23.0",
|
"style-loader": "^0.23.0",
|
||||||
"stylelint": "^10.0.0",
|
"stylelint": "^10.0.0",
|
||||||
"stylelint-config-recommended-scss": "^3.2.0",
|
"stylelint-config-recommended-scss": "^3.2.0",
|
||||||
"stylelint-scss": "^3.5.4",
|
"stylelint-scss": "^3.5.4",
|
||||||
"transform-loader": "^0.2.4",
|
"transform-loader": "^0.2.4",
|
||||||
"uuid": "^3.3.2",
|
"uuid": "^3.3.2",
|
||||||
"wdio-mocha-framework": "^0.6.4",
|
"webdriverio": "^5.10.4",
|
||||||
"wdio-selenium-standalone-service": "0.0.10",
|
|
||||||
"wdio-spec-reporter": "^0.1.5",
|
|
||||||
"webdriverio": "^4.13.2",
|
|
||||||
"webpack": "^4.20.2",
|
"webpack": "^4.20.2",
|
||||||
"webpack-bundle-analyzer": "^3.0.2",
|
"webpack-bundle-analyzer": "^3.0.2",
|
||||||
"webpack-cleanup-plugin": "^0.5.1",
|
"webpack-cleanup-plugin": "^0.5.1",
|
||||||
|
|
|
@ -2,6 +2,7 @@ import autoBind from 'react-autobind';
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import cloneDeep from 'lodash.clonedeep'
|
import cloneDeep from 'lodash.clonedeep'
|
||||||
import clamp from 'lodash.clamp'
|
import clamp from 'lodash.clamp'
|
||||||
|
import get from 'lodash.get'
|
||||||
import {arrayMove} from 'react-sortable-hoc'
|
import {arrayMove} from 'react-sortable-hoc'
|
||||||
import url from 'url'
|
import url from 'url'
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ import SourcesModal from './modals/SourcesModal'
|
||||||
import OpenModal from './modals/OpenModal'
|
import OpenModal from './modals/OpenModal'
|
||||||
import ShortcutsModal from './modals/ShortcutsModal'
|
import ShortcutsModal from './modals/ShortcutsModal'
|
||||||
import SurveyModal from './modals/SurveyModal'
|
import SurveyModal from './modals/SurveyModal'
|
||||||
|
import DebugModal from './modals/DebugModal'
|
||||||
|
|
||||||
import { downloadGlyphsMetadata, downloadSpriteMetadata } from '../libs/metadata'
|
import { downloadGlyphsMetadata, downloadSpriteMetadata } from '../libs/metadata'
|
||||||
import {latest, validate} from '@mapbox/mapbox-gl-style-spec'
|
import {latest, validate} from '@mapbox/mapbox-gl-style-spec'
|
||||||
|
@ -139,6 +141,12 @@ export default class App extends React.Component {
|
||||||
document.querySelector(".mapboxgl-canvas").focus();
|
document.querySelector(".mapboxgl-canvas").focus();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "!",
|
||||||
|
handler: () => {
|
||||||
|
this.toggleModal("debug");
|
||||||
|
}
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
document.body.addEventListener("keyup", (e) => {
|
document.body.addEventListener("keyup", (e) => {
|
||||||
|
@ -203,12 +211,16 @@ export default class App extends React.Component {
|
||||||
open: false,
|
open: false,
|
||||||
shortcuts: false,
|
shortcuts: false,
|
||||||
export: false,
|
export: false,
|
||||||
survey: localStorage.hasOwnProperty('survey') ? false : true
|
survey: localStorage.hasOwnProperty('survey') ? false : true,
|
||||||
|
debug: false,
|
||||||
},
|
},
|
||||||
mapOptions: {
|
mapboxGlDebugOptions: {
|
||||||
showTileBoundaries: queryUtil.asBool(queryObj, "show-tile-boundaries"),
|
showTileBoundaries: false,
|
||||||
showCollisionBoxes: queryUtil.asBool(queryObj, "show-collision-boxes"),
|
showCollisionBoxes: false,
|
||||||
showOverdrawInspector: queryUtil.asBool(queryObj, "show-overdraw-inspector")
|
showOverdrawInspector: false,
|
||||||
|
},
|
||||||
|
openlayersDebugOptions: {
|
||||||
|
debugToolbox: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,20 +229,24 @@ export default class App extends React.Component {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleKeyPress(e) {
|
handleKeyPress = (e) => {
|
||||||
if(navigator.platform.toUpperCase().indexOf('MAC') >= 0) {
|
if(navigator.platform.toUpperCase().indexOf('MAC') >= 0) {
|
||||||
if(e.metaKey && e.shiftKey && e.keyCode === 90) {
|
if(e.metaKey && e.shiftKey && e.keyCode === 90) {
|
||||||
|
e.preventDefault();
|
||||||
this.onRedo(e);
|
this.onRedo(e);
|
||||||
}
|
}
|
||||||
else if(e.metaKey && e.keyCode === 90) {
|
else if(e.metaKey && e.keyCode === 90) {
|
||||||
|
e.preventDefault();
|
||||||
this.onUndo(e);
|
this.onUndo(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(e.ctrlKey && e.keyCode === 90) {
|
if(e.ctrlKey && e.keyCode === 90) {
|
||||||
|
e.preventDefault();
|
||||||
this.onUndo(e);
|
this.onUndo(e);
|
||||||
}
|
}
|
||||||
else if(e.ctrlKey && e.keyCode === 89) {
|
else if(e.ctrlKey && e.keyCode === 89) {
|
||||||
|
e.preventDefault();
|
||||||
this.onRedo(e);
|
this.onRedo(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,6 +280,27 @@ export default class App extends React.Component {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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, save=true) => {
|
onStyleChanged = (newStyle, save=true) => {
|
||||||
|
|
||||||
const errors = validate(newStyle, latest)
|
const errors = validate(newStyle, latest)
|
||||||
|
@ -397,6 +434,27 @@ export default class App extends React.Component {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
fetchSources() {
|
||||||
const sourceList = {...this.state.sources};
|
const sourceList = {...this.state.sources};
|
||||||
|
|
||||||
|
@ -461,18 +519,23 @@ export default class App extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getRenderer () {
|
||||||
|
const metadata = this.state.mapStyle.metadata || {};
|
||||||
|
return metadata['maputnik:renderer'] || 'mbgljs';
|
||||||
|
}
|
||||||
|
|
||||||
mapRenderer() {
|
mapRenderer() {
|
||||||
|
const metadata = this.state.mapStyle.metadata || {};
|
||||||
|
|
||||||
const mapProps = {
|
const mapProps = {
|
||||||
mapStyle: style.replaceAccessTokens(this.state.mapStyle, {allowFallback: true}),
|
mapStyle: style.replaceAccessTokens(this.state.mapStyle, {allowFallback: true}),
|
||||||
options: this.state.mapOptions,
|
|
||||||
onDataChange: (e) => {
|
onDataChange: (e) => {
|
||||||
this.layerWatcher.analyzeMap(e.map)
|
this.layerWatcher.analyzeMap(e.map)
|
||||||
this.fetchSources();
|
this.fetchSources();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const metadata = this.state.mapStyle.metadata || {}
|
const renderer = this._getRenderer();
|
||||||
const renderer = metadata['maputnik:renderer'] || 'mbgljs'
|
|
||||||
|
|
||||||
let mapElement;
|
let mapElement;
|
||||||
|
|
||||||
|
@ -480,9 +543,12 @@ export default class App extends React.Component {
|
||||||
if(renderer === 'ol') {
|
if(renderer === 'ol') {
|
||||||
mapElement = <OpenLayersMap
|
mapElement = <OpenLayersMap
|
||||||
{...mapProps}
|
{...mapProps}
|
||||||
|
debugToolbox={this.state.openlayersDebugOptions.debugToolbox}
|
||||||
|
onLayerSelect={this.onLayerSelect}
|
||||||
/>
|
/>
|
||||||
} else {
|
} else {
|
||||||
mapElement = <MapboxGlMap {...mapProps}
|
mapElement = <MapboxGlMap {...mapProps}
|
||||||
|
options={this.state.mapboxGlDebugOptions}
|
||||||
inspectModeEnabled={this.state.mapState === "inspect"}
|
inspectModeEnabled={this.state.mapState === "inspect"}
|
||||||
highlightedLayer={this.state.mapStyle.layers[this.state.selectedLayerIndex]}
|
highlightedLayer={this.state.mapStyle.layers[this.state.selectedLayerIndex]}
|
||||||
onLayerSelect={this.onLayerSelect} />
|
onLayerSelect={this.onLayerSelect} />
|
||||||
|
@ -524,12 +590,31 @@ export default class App extends React.Component {
|
||||||
this.setModal(modalName, !this.state.isOpen[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() {
|
render() {
|
||||||
const layers = this.state.mapStyle.layers || []
|
const layers = this.state.mapStyle.layers || []
|
||||||
const selectedLayer = layers.length > 0 ? layers[this.state.selectedLayerIndex] : null
|
const selectedLayer = layers.length > 0 ? layers[this.state.selectedLayerIndex] : null
|
||||||
const metadata = this.state.mapStyle.metadata || {}
|
const metadata = this.state.mapStyle.metadata || {}
|
||||||
|
|
||||||
const toolbar = <Toolbar
|
const toolbar = <Toolbar
|
||||||
|
renderer={this._getRenderer()}
|
||||||
mapState={this.state.mapState}
|
mapState={this.state.mapState}
|
||||||
mapStyle={this.state.mapStyle}
|
mapStyle={this.state.mapStyle}
|
||||||
inspectModeEnabled={this.state.mapState === "inspect"}
|
inspectModeEnabled={this.state.mapState === "inspect"}
|
||||||
|
@ -575,6 +660,15 @@ export default class App extends React.Component {
|
||||||
|
|
||||||
|
|
||||||
const modals = <div>
|
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')}
|
||||||
|
/>
|
||||||
<ShortcutsModal
|
<ShortcutsModal
|
||||||
ref={(el) => this.shortcutEl = el}
|
ref={(el) => this.shortcutEl = el}
|
||||||
isOpen={this.state.isOpen.shortcuts}
|
isOpen={this.state.isOpen.shortcuts}
|
||||||
|
@ -583,8 +677,10 @@ export default class App extends React.Component {
|
||||||
<SettingsModal
|
<SettingsModal
|
||||||
mapStyle={this.state.mapStyle}
|
mapStyle={this.state.mapStyle}
|
||||||
onStyleChanged={this.onStyleChanged}
|
onStyleChanged={this.onStyleChanged}
|
||||||
|
onChangeMetadataProperty={this.onChangeMetadataProperty}
|
||||||
isOpen={this.state.isOpen.settings}
|
isOpen={this.state.isOpen.settings}
|
||||||
onOpenToggle={this.toggleModal.bind(this, 'settings')}
|
onOpenToggle={this.toggleModal.bind(this, 'settings')}
|
||||||
|
openlayersDebugOptions={this.state.openlayersDebugOptions}
|
||||||
/>
|
/>
|
||||||
<ExportModal
|
<ExportModal
|
||||||
mapStyle={this.state.mapStyle}
|
mapStyle={this.state.mapStyle}
|
||||||
|
@ -594,7 +690,7 @@ export default class App extends React.Component {
|
||||||
/>
|
/>
|
||||||
<OpenModal
|
<OpenModal
|
||||||
isOpen={this.state.isOpen.open}
|
isOpen={this.state.isOpen.open}
|
||||||
onStyleOpen={this.onStyleChanged}
|
onStyleOpen={this.openStyle}
|
||||||
onOpenToggle={this.toggleModal.bind(this, 'open')}
|
onOpenToggle={this.toggleModal.bind(this, 'open')}
|
||||||
/>
|
/>
|
||||||
<SourcesModal
|
<SourcesModal
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
import {detect} from 'detect-browser';
|
||||||
|
|
||||||
import {MdFileDownload, MdOpenInBrowser, MdSettings, MdLayers, MdHelpOutline, MdFindInPage, MdAssignmentTurnedIn} from 'react-icons/md'
|
import {MdFileDownload, MdOpenInBrowser, MdSettings, MdLayers, MdHelpOutline, MdFindInPage, MdAssignmentTurnedIn} from 'react-icons/md'
|
||||||
|
|
||||||
|
@ -9,6 +10,11 @@ import logoImage from 'maputnik-design/logos/logo-color.svg'
|
||||||
import pkgJson from '../../package.json'
|
import pkgJson from '../../package.json'
|
||||||
|
|
||||||
|
|
||||||
|
// This is required because of <https://stackoverflow.com/a/49846426>, there isn't another way to detect support that I'm aware of.
|
||||||
|
const browser = detect();
|
||||||
|
const colorAccessibilityFiltersEnabled = ['chrome', 'firefox'].indexOf(browser.name) > -1;
|
||||||
|
|
||||||
|
|
||||||
class IconText extends React.Component {
|
class IconText extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
|
@ -108,6 +114,7 @@ export default class Toolbar extends React.Component {
|
||||||
onToggleModal: PropTypes.func,
|
onToggleModal: PropTypes.func,
|
||||||
onSetMapState: PropTypes.func,
|
onSetMapState: PropTypes.func,
|
||||||
mapState: PropTypes.string,
|
mapState: PropTypes.string,
|
||||||
|
renderer: PropTypes.string,
|
||||||
}
|
}
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
|
@ -133,22 +140,27 @@ export default class Toolbar extends React.Component {
|
||||||
{
|
{
|
||||||
id: "inspect",
|
id: "inspect",
|
||||||
title: "Inspect",
|
title: "Inspect",
|
||||||
|
disabled: this.props.renderer !== 'mbgljs',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "filter-deuteranopia",
|
id: "filter-deuteranopia",
|
||||||
title: "Map (deuteranopia)",
|
title: "Map (deuteranopia)",
|
||||||
|
disabled: !colorAccessibilityFiltersEnabled,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "filter-protanopia",
|
id: "filter-protanopia",
|
||||||
title: "Map (protanopia)",
|
title: "Map (protanopia)",
|
||||||
|
disabled: !colorAccessibilityFiltersEnabled,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "filter-tritanopia",
|
id: "filter-tritanopia",
|
||||||
title: "Map (tritanopia)",
|
title: "Map (tritanopia)",
|
||||||
|
disabled: !colorAccessibilityFiltersEnabled,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "filter-achromatopsia",
|
id: "filter-achromatopsia",
|
||||||
title: "Map (achromatopsia)",
|
title: "Map (achromatopsia)",
|
||||||
|
disabled: !colorAccessibilityFiltersEnabled,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -201,7 +213,7 @@ export default class Toolbar extends React.Component {
|
||||||
<select onChange={(e) => this.handleSelection(e.target.value)} value={currentView.id}>
|
<select onChange={(e) => this.handleSelection(e.target.value)} value={currentView.id}>
|
||||||
{views.map((item) => {
|
{views.map((item) => {
|
||||||
return (
|
return (
|
||||||
<option key={item.id} value={item.id}>
|
<option key={item.id} value={item.id} disabled={item.disabled}>
|
||||||
{item.title}
|
{item.title}
|
||||||
</option>
|
</option>
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,25 +13,28 @@ class NumberInput extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
value: props.value
|
editing: false,
|
||||||
|
value: props.value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static getDerivedStateFromProps(props, state) {
|
static getDerivedStateFromProps(props, state) {
|
||||||
return {
|
if (!state.editing) {
|
||||||
value: props.value
|
return {
|
||||||
};
|
value: props.value
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
changeValue(newValue) {
|
changeValue(newValue) {
|
||||||
|
this.setState({editing: true});
|
||||||
const value = parseFloat(newValue)
|
const value = parseFloat(newValue)
|
||||||
|
|
||||||
const hasChanged = this.state.value !== value
|
const hasChanged = this.state.value !== value
|
||||||
if(this.isValid(value) && hasChanged) {
|
if(this.isValid(value) && hasChanged) {
|
||||||
this.props.onChange(value)
|
this.props.onChange(value)
|
||||||
} else {
|
|
||||||
this.setState({ value: newValue })
|
|
||||||
}
|
}
|
||||||
|
this.setState({ value: newValue })
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid(v) {
|
isValid(v) {
|
||||||
|
@ -52,6 +55,7 @@ class NumberInput extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
resetValue = () => {
|
resetValue = () => {
|
||||||
|
this.setState({editing: false});
|
||||||
// Reset explicitly to default value if value has been cleared
|
// Reset explicitly to default value if value has been cleared
|
||||||
if(this.state.value === "") {
|
if(this.state.value === "") {
|
||||||
return this.changeValue(this.props.default)
|
return this.changeValue(this.props.default)
|
||||||
|
|
|
@ -14,13 +14,16 @@ class StringInput extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
|
editing: false,
|
||||||
value: props.value || ''
|
value: props.value || ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
static getDerivedStateFromProps(props, state) {
|
||||||
if(this.props.value !== prevProps.value) {
|
if (!state.editing) {
|
||||||
this.setState({value: this.props.value})
|
return {
|
||||||
|
value: props.value
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,11 +54,15 @@ class StringInput extends React.Component {
|
||||||
placeholder: this.props.default,
|
placeholder: this.props.default,
|
||||||
onChange: e => {
|
onChange: e => {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
editing: true,
|
||||||
value: e.target.value
|
value: e.target.value
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onBlur: () => {
|
onBlur: () => {
|
||||||
if(this.state.value!==this.props.value) this.props.onChange(this.state.value)
|
if(this.state.value!==this.props.value) {
|
||||||
|
this.setState({editing: false});
|
||||||
|
this.props.onChange(this.state.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import LayerIcon from '../icons/LayerIcon'
|
import LayerIcon from '../icons/LayerIcon'
|
||||||
|
import {latest, expression, function as styleFunction} from '@mapbox/mapbox-gl-style-spec'
|
||||||
|
|
||||||
function groupFeaturesBySourceLayer(features) {
|
function groupFeaturesBySourceLayer(features) {
|
||||||
const sources = {}
|
const sources = {}
|
||||||
|
@ -28,7 +29,64 @@ function groupFeaturesBySourceLayer(features) {
|
||||||
class FeatureLayerPopup extends React.Component {
|
class FeatureLayerPopup extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
onLayerSelect: PropTypes.func.isRequired,
|
onLayerSelect: PropTypes.func.isRequired,
|
||||||
features: PropTypes.array
|
features: PropTypes.array,
|
||||||
|
zoom: PropTypes.number,
|
||||||
|
}
|
||||||
|
|
||||||
|
_getFeatureColor(feature, zoom) {
|
||||||
|
// Guard because openlayers won't have this
|
||||||
|
if (!feature.layer.paint) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const paintProps = feature.layer.paint;
|
||||||
|
let propName;
|
||||||
|
|
||||||
|
if(paintProps.hasOwnProperty("text-color") && paintProps["text-color"]) {
|
||||||
|
propName = "text-color";
|
||||||
|
}
|
||||||
|
else if (paintProps.hasOwnProperty("fill-color") && paintProps["fill-color"]) {
|
||||||
|
propName = "fill-color";
|
||||||
|
}
|
||||||
|
else if (paintProps.hasOwnProperty("line-color") && paintProps["line-color"]) {
|
||||||
|
propName = "line-color";
|
||||||
|
}
|
||||||
|
else if (paintProps.hasOwnProperty("fill-extrusion-color") && paintProps["fill-extrusion-color"]) {
|
||||||
|
propName = "fill-extrusion-color";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(propName) {
|
||||||
|
const propertySpec = latest["paint_"+feature.layer.type][propName];
|
||||||
|
|
||||||
|
let color = feature.layer.paint[propName];
|
||||||
|
|
||||||
|
if(typeof(color) === "object") {
|
||||||
|
if(color.stops) {
|
||||||
|
color = styleFunction.convertFunction(color, propertySpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
const exprResult = expression.createExpression(color, propertySpec);
|
||||||
|
const val = exprResult.value.evaluate({
|
||||||
|
zoom: zoom
|
||||||
|
}, feature);
|
||||||
|
return val.toString();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Default color
|
||||||
|
return "black";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This is quite complex, just incase there's an edgecase we're missing
|
||||||
|
// always return black if we get an unexpected error.
|
||||||
|
catch (err) {
|
||||||
|
console.error("Unable to get feature color, error:", err);
|
||||||
|
return "black";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -36,21 +94,33 @@ class FeatureLayerPopup extends React.Component {
|
||||||
|
|
||||||
const items = Object.keys(sources).map(vectorLayerId => {
|
const items = Object.keys(sources).map(vectorLayerId => {
|
||||||
const layers = sources[vectorLayerId].map((feature, idx) => {
|
const layers = sources[vectorLayerId].map((feature, idx) => {
|
||||||
return <label
|
const featureColor = this._getFeatureColor(feature, this.props.zoom);
|
||||||
key={idx}
|
|
||||||
className="maputnik-popup-layer"
|
return <div
|
||||||
onClick={() => {
|
key={idx}
|
||||||
this.props.onLayerSelect(feature.layer.id)
|
className="maputnik-popup-layer"
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<LayerIcon type={feature.layer.type} style={{
|
<div
|
||||||
width: 14,
|
className="maputnik-popup-layer__swatch"
|
||||||
height: 14,
|
style={{background: featureColor}}
|
||||||
paddingRight: 3
|
></div>
|
||||||
}}/>
|
<label
|
||||||
{feature.layer.id}
|
className="maputnik-popup-layer__label"
|
||||||
{feature.counter && <span> × {feature.counter}</span>}
|
onClick={() => {
|
||||||
</label>
|
this.props.onLayerSelect(feature.layer.id)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{feature.layer.type &&
|
||||||
|
<LayerIcon type={feature.layer.type} style={{
|
||||||
|
width: 14,
|
||||||
|
height: 14,
|
||||||
|
paddingRight: 3
|
||||||
|
}}/>
|
||||||
|
}
|
||||||
|
{feature.layer.id}
|
||||||
|
{feature.counter && <span> × {feature.counter}</span>}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
})
|
})
|
||||||
return <div key={vectorLayerId}>
|
return <div key={vectorLayerId}>
|
||||||
<div className="maputnik-popup-layer-id">{vectorLayerId}</div>
|
<div className="maputnik-popup-layer-id">{vectorLayerId}</div>
|
||||||
|
|
|
@ -166,14 +166,18 @@ export default class MapboxGlMap extends React.Component {
|
||||||
if(this.props.inspectModeEnabled) {
|
if(this.props.inspectModeEnabled) {
|
||||||
return renderPopup(<FeaturePropertyPopup features={features} />, tmpNode);
|
return renderPopup(<FeaturePropertyPopup features={features} />, tmpNode);
|
||||||
} else {
|
} else {
|
||||||
return renderPopup(<FeatureLayerPopup features={features} onLayerSelect={this.props.onLayerSelect} />, tmpNode);
|
return renderPopup(<FeatureLayerPopup features={features} onLayerSelect={this.props.onLayerSelect} zoom={this.state.zoom} />, tmpNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
map.addControl(inspect)
|
map.addControl(inspect)
|
||||||
|
|
||||||
map.on("style.load", () => {
|
map.on("style.load", () => {
|
||||||
this.setState({ map, inspect });
|
this.setState({
|
||||||
|
map,
|
||||||
|
inspect,
|
||||||
|
zoom: map.getZoom()
|
||||||
|
});
|
||||||
if(this.props.inspectModeEnabled) {
|
if(this.props.inspectModeEnabled) {
|
||||||
inspect.toggleInspector();
|
inspect.toggleInspector();
|
||||||
}
|
}
|
||||||
|
@ -185,6 +189,12 @@ export default class MapboxGlMap extends React.Component {
|
||||||
map: this.state.map
|
map: this.state.map
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
map.on("zoom", e => {
|
||||||
|
this.setState({
|
||||||
|
zoom: map.getZoom()
|
||||||
|
});
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -1,11 +1,28 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import {throttle} from 'lodash';
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { loadJSON } from '../../libs/urlopen'
|
import { loadJSON } from '../../libs/urlopen'
|
||||||
|
|
||||||
|
import FeatureLayerPopup from './FeatureLayerPopup';
|
||||||
|
|
||||||
import 'ol/ol.css'
|
import 'ol/ol.css'
|
||||||
import {apply} from 'ol-mapbox-style';
|
import {apply} from 'ol-mapbox-style';
|
||||||
import {Map, View} from 'ol';
|
import {Map, View, Proj, Overlay} from 'ol';
|
||||||
|
|
||||||
|
import {toLonLat} from 'ol/proj';
|
||||||
|
import {toStringHDMS} from 'ol/coordinate';
|
||||||
|
|
||||||
|
|
||||||
|
function renderCoords (coords) {
|
||||||
|
if (!coords || coords.length < 2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return <span className="maputnik-coords">
|
||||||
|
{coords.map((coord) => String(coord).padStart(7, "\u00A0")).join(', ')}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default class OpenLayersMap extends React.Component {
|
export default class OpenLayersMap extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -13,53 +30,137 @@ export default class OpenLayersMap extends React.Component {
|
||||||
mapStyle: PropTypes.object.isRequired,
|
mapStyle: PropTypes.object.isRequired,
|
||||||
accessToken: PropTypes.string,
|
accessToken: PropTypes.string,
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
|
onLayerSelect: PropTypes.func.isRequired,
|
||||||
|
debugToolbox: PropTypes.bool.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
onMapLoaded: () => {},
|
onMapLoaded: () => {},
|
||||||
onDataChange: () => {},
|
onDataChange: () => {},
|
||||||
|
onLayerSelect: () => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
zoom: 0,
|
||||||
|
rotation: 0,
|
||||||
|
cursor: [],
|
||||||
|
center: [],
|
||||||
|
};
|
||||||
|
this.updateStyle = throttle(this._updateStyle.bind(this), 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStyle(newMapStyle) {
|
_updateStyle(newMapStyle) {
|
||||||
if(!this.map) return;
|
if(!this.map) return;
|
||||||
|
|
||||||
|
// See <https://github.com/openlayers/ol-mapbox-style/issues/215#issuecomment-493198815>
|
||||||
|
this.map.getLayers().clear();
|
||||||
apply(this.map, newMapStyle);
|
apply(this.map, newMapStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate(prevProps) {
|
||||||
this.updateStyle(this.props.mapStyle);
|
if (this.props.mapStyle !== prevProps.mapStyle) {
|
||||||
|
this.updateStyle(this.props.mapStyle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.updateStyle(this.props.mapStyle);
|
this.overlay = new Overlay({
|
||||||
|
element: this.popupContainer,
|
||||||
|
autoPan: true,
|
||||||
|
autoPanAnimation: {
|
||||||
|
duration: 250
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
target: this.container,
|
target: this.container,
|
||||||
layers: [],
|
overlays: [this.overlay],
|
||||||
view: new View({
|
view: new View({
|
||||||
zoom: 2,
|
zoom: 1,
|
||||||
center: [52.5, -78.4]
|
center: [180, -90],
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
map.on('pointermove', (evt) => {
|
||||||
|
var coords = toLonLat(evt.coordinate);
|
||||||
|
this.setState({
|
||||||
|
cursor: [
|
||||||
|
coords[0].toFixed(2),
|
||||||
|
coords[1].toFixed(2)
|
||||||
|
]
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
map.on('postrender', (evt) => {
|
||||||
|
const center = toLonLat(map.getView().getCenter());
|
||||||
|
this.setState({
|
||||||
|
center: [
|
||||||
|
center[0].toFixed(2),
|
||||||
|
center[1].toFixed(2),
|
||||||
|
],
|
||||||
|
rotation: map.getView().getRotation().toFixed(2),
|
||||||
|
zoom: map.getView().getZoom().toFixed(2)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.map = map;
|
this.map = map;
|
||||||
|
this.updateStyle(this.props.mapStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
closeOverlay = (e) => {
|
||||||
|
e.target.blur();
|
||||||
|
this.overlay.setPosition(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <div
|
return <div className="maputnik-ol-container">
|
||||||
ref={x => this.container = x}
|
<div
|
||||||
style={{
|
ref={x => this.popupContainer = x}
|
||||||
position: "fixed",
|
style={{background: "black"}}
|
||||||
top: 40,
|
className="maputnik-popup"
|
||||||
right: 0,
|
>
|
||||||
bottom: 0,
|
<button
|
||||||
height: 'calc(100% - 40px)',
|
className="mapboxgl-popup-close-button"
|
||||||
width: "75%",
|
onClick={this.closeOverlay}
|
||||||
backgroundColor: '#fff',
|
aria-label="Close popup"
|
||||||
...this.props.style,
|
>
|
||||||
}}>
|
×
|
||||||
|
</button>
|
||||||
|
<FeatureLayerPopup
|
||||||
|
features={this.state.selectedFeatures || []}
|
||||||
|
onLayerSelect={this.props.onLayerSelect}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="maputnik-ol-zoom">
|
||||||
|
Zoom level: {this.state.zoom}
|
||||||
|
</div>
|
||||||
|
{this.props.debugToolbox &&
|
||||||
|
<div className="maputnik-ol-debug">
|
||||||
|
<div>
|
||||||
|
<label>cursor: </label>
|
||||||
|
<span>{renderCoords(this.state.cursor)}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>center: </label>
|
||||||
|
<span>{renderCoords(this.state.center)}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>rotation: </label>
|
||||||
|
<span>{this.state.rotation}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div
|
||||||
|
className="maputnik-ol"
|
||||||
|
ref={x => this.container = x}
|
||||||
|
style={{
|
||||||
|
...this.props.style,
|
||||||
|
}}>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
53
src/components/modals/DebugModal.js
Normal file
53
src/components/modals/DebugModal.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import React from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
|
import Modal from './Modal'
|
||||||
|
|
||||||
|
|
||||||
|
class DebugModal extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
isOpen: PropTypes.bool.isRequired,
|
||||||
|
renderer: PropTypes.string.isRequired,
|
||||||
|
onChangeMaboxGlDebug: PropTypes.func.isRequired,
|
||||||
|
onChangeOpenlayersDebug: PropTypes.func.isRequired,
|
||||||
|
onOpenToggle: PropTypes.func.isRequired,
|
||||||
|
mapboxGlDebugOptions: PropTypes.object,
|
||||||
|
openlayersDebugOptions: PropTypes.object,
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <Modal
|
||||||
|
data-wd-key="debug-modal"
|
||||||
|
isOpen={this.props.isOpen}
|
||||||
|
onOpenToggle={this.props.onOpenToggle}
|
||||||
|
title={'Debug'}
|
||||||
|
>
|
||||||
|
<div className="maputnik-modal-section maputnik-modal-shortcuts">
|
||||||
|
{this.props.renderer === 'mbgljs' &&
|
||||||
|
<ul>
|
||||||
|
{Object.entries(this.props.mapboxGlDebugOptions).map(([key, val]) => {
|
||||||
|
return <li key={key}>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" checked={val} onClick={(e) => this.props.onChangeMaboxGlDebug(key, e.target.checked)} /> {key}
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
{this.props.renderer === 'ol' &&
|
||||||
|
<ul>
|
||||||
|
{Object.entries(this.props.openlayersDebugOptions).map(([key, val]) => {
|
||||||
|
return <li key={key}>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" checked={val} onClick={(e) => this.props.onChangeOpenlayersDebug(key, e.target.checked)} /> {key}
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DebugModal;
|
|
@ -11,6 +11,7 @@ class SettingsModal extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
mapStyle: PropTypes.object.isRequired,
|
mapStyle: PropTypes.object.isRequired,
|
||||||
onStyleChanged: PropTypes.func.isRequired,
|
onStyleChanged: PropTypes.func.isRequired,
|
||||||
|
onChangeMetadataProperty: PropTypes.func.isRequired,
|
||||||
isOpen: PropTypes.bool.isRequired,
|
isOpen: PropTypes.bool.isRequired,
|
||||||
onOpenToggle: PropTypes.func.isRequired,
|
onOpenToggle: PropTypes.func.isRequired,
|
||||||
}
|
}
|
||||||
|
@ -23,19 +24,9 @@ class SettingsModal extends React.Component {
|
||||||
this.props.onStyleChanged(changedStyle)
|
this.props.onStyleChanged(changedStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
changeMetadataProperty(property, value) {
|
|
||||||
const changedStyle = {
|
|
||||||
...this.props.mapStyle,
|
|
||||||
metadata: {
|
|
||||||
...this.props.mapStyle.metadata,
|
|
||||||
[property]: value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.props.onStyleChanged(changedStyle)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const metadata = this.props.mapStyle.metadata || {}
|
const metadata = this.props.mapStyle.metadata || {}
|
||||||
|
const {onChangeMetadataProperty} = this.props;
|
||||||
const inputProps = { }
|
const inputProps = { }
|
||||||
return <Modal
|
return <Modal
|
||||||
data-wd-key="modal-settings"
|
data-wd-key="modal-settings"
|
||||||
|
@ -78,7 +69,7 @@ class SettingsModal extends React.Component {
|
||||||
<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={this.changeMetadataProperty.bind(this, "maputnik:mapbox_access_token")}
|
onChange={onChangeMetadataProperty.bind(this, "maputnik:mapbox_access_token")}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
|
|
||||||
|
@ -86,7 +77,7 @@ class SettingsModal extends React.Component {
|
||||||
<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={this.changeMetadataProperty.bind(this, "maputnik:openmaptiles_access_token")}
|
onChange={onChangeMetadataProperty.bind(this, "maputnik:openmaptiles_access_token")}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
|
|
||||||
|
@ -94,7 +85,7 @@ class SettingsModal extends React.Component {
|
||||||
<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={this.changeMetadataProperty.bind(this, "maputnik:thunderforest_access_token")}
|
onChange={onChangeMetadataProperty.bind(this, "maputnik:thunderforest_access_token")}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
|
|
||||||
|
@ -106,9 +97,10 @@ class SettingsModal extends React.Component {
|
||||||
['ol', 'Open Layers (experimental)'],
|
['ol', 'Open Layers (experimental)'],
|
||||||
]}
|
]}
|
||||||
value={metadata['maputnik:renderer'] || 'mbgljs'}
|
value={metadata['maputnik:renderer'] || 'mbgljs'}
|
||||||
onChange={this.changeMetadataProperty.bind(this, 'maputnik:renderer')}
|
onChange={onChangeMetadataProperty.bind(this, 'maputnik:renderer')}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,10 @@ class ShortcutsModal extends React.Component {
|
||||||
key: "m",
|
key: "m",
|
||||||
text: "Focus map"
|
text: "Focus map"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "!",
|
||||||
|
text: "Debug modal"
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
//OPENLAYERS
|
//OPENLAYERS
|
||||||
.maputnik-layout {
|
.maputnik-layout {
|
||||||
.ol-zoom {
|
.ol-zoom {
|
||||||
top: 10px;
|
top: 40px;
|
||||||
|
right: 10px;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ol-rotate {
|
||||||
|
top: 94px;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
left: auto;
|
left: auto;
|
||||||
}
|
}
|
||||||
|
@ -20,3 +26,57 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.maputnik-ol {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maputnik-ol-popup {
|
||||||
|
background: $color-black;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.maputnik-coords {
|
||||||
|
font-family: monospace;
|
||||||
|
&:before {
|
||||||
|
content: '[';
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
content: ']';
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.maputnik-ol-debug {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: smaller;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 10px;
|
||||||
|
background: rgb(28, 31, 36);
|
||||||
|
padding: 6px 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maputnik-ol-zoom {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 10px;
|
||||||
|
background: #1c1f24;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 6px 8px;
|
||||||
|
color: $color-lowgray;
|
||||||
|
z-index: 9999;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maputnik-ol-container {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,15 @@
|
||||||
.maputnik-popup-layer {
|
.maputnik-popup-layer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maputnik-popup-layer__swatch {
|
||||||
|
display: inline-block;
|
||||||
|
width: 5px;
|
||||||
|
align-content: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maputnik-popup-layer__label {
|
||||||
display: block;
|
display: block;
|
||||||
color: $color-lowgray;
|
color: $color-lowgray;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -11,7 +22,7 @@
|
||||||
|
|
||||||
.maputnik-popup-layer-id {
|
.maputnik-popup-layer-id {
|
||||||
padding-left: $margin-2;
|
padding-left: $margin-2;
|
||||||
padding-right: $margin-2;
|
padding-right: 1.6em;
|
||||||
background-color: $color-midgray;
|
background-color: $color-midgray;
|
||||||
color: $color-white;
|
color: $color-white;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ module.exports = {
|
||||||
var result = browser.executeAsync(function(done) {
|
var result = browser.executeAsync(function(done) {
|
||||||
window.debug.get("maputnik", "styleStore").latestStyle(done);
|
window.debug.get("maputnik", "styleStore").latestStyle(done);
|
||||||
})
|
})
|
||||||
return result.value;
|
return result;
|
||||||
},
|
},
|
||||||
getRevisionStore: function(browser) {
|
getRevisionStore: function(browser) {
|
||||||
var result = browser.execute(function(done) {
|
var result = browser.execute(function(done) {
|
||||||
|
@ -34,15 +34,16 @@ module.exports = {
|
||||||
modal: {
|
modal: {
|
||||||
addLayer: {
|
addLayer: {
|
||||||
open: function() {
|
open: function() {
|
||||||
var selector = wd.$('layer-list:add-layer');
|
const selector = $(wd.$('layer-list:add-layer'));
|
||||||
browser.click(selector);
|
selector.click();
|
||||||
|
|
||||||
// Wait for events
|
// Wait for events
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.waitForExist(wd.$('modal:add-layer'));
|
const elem = $(wd.$('modal:add-layer'));
|
||||||
browser.isVisible(wd.$('modal:add-layer'));
|
elem.waitForExist();
|
||||||
browser.isVisibleWithinViewport(wd.$('modal:add-layer'));
|
elem.isDisplayed();
|
||||||
|
elem.isDisplayedInViewport();
|
||||||
|
|
||||||
// Wait for events
|
// Wait for events
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
@ -58,7 +59,8 @@ module.exports = {
|
||||||
id = type+":"+uuid();
|
id = type+":"+uuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
browser.selectByValue(wd.$("add-layer.layer-type", "select"), type);
|
const selectBox = $(wd.$("add-layer.layer-type", "select"));
|
||||||
|
selectBox.selectByAttribute('value', type);
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.setValueSafe(wd.$("add-layer.layer-id", "input"), id);
|
browser.setValueSafe(wd.$("add-layer.layer-id", "input"), id);
|
||||||
|
@ -67,7 +69,8 @@ module.exports = {
|
||||||
}
|
}
|
||||||
|
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
browser.click(wd.$("add-layer"));
|
const elem_addLayer = $(wd.$("add-layer"));
|
||||||
|
elem_addLayer.click();
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,12 @@ describe('maputnik', function() {
|
||||||
"geojson:example",
|
"geojson:example",
|
||||||
"raster:raster"
|
"raster:raster"
|
||||||
]));
|
]));
|
||||||
browser.alertAccept();
|
browser.acceptAlert();
|
||||||
browser.execute(function() {
|
browser.execute(function() {
|
||||||
localStorage.setItem("survey", true);
|
localStorage.setItem("survey", true);
|
||||||
});
|
});
|
||||||
browser.waitForExist(".maputnik-toolbar-link");
|
const elem = $(".maputnik-toolbar-link");
|
||||||
|
elem.waitForExist();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,9 @@ describe("layers", function() {
|
||||||
"geojson:example",
|
"geojson:example",
|
||||||
"raster:raster"
|
"raster:raster"
|
||||||
]));
|
]));
|
||||||
browser.alertAccept();
|
browser.acceptAlert();
|
||||||
browser.waitForExist(".maputnik-toolbar-link");
|
const elem = $(".maputnik-toolbar-link");
|
||||||
|
elem.waitForExist();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
helper.modal.addLayer.open();
|
helper.modal.addLayer.open();
|
||||||
|
@ -33,7 +34,8 @@ describe("layers", function() {
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
browser.click(wd.$("layer-list-item:"+id+":delete", ""));
|
const elem = $(wd.$("layer-list-item:"+id+":delete", ""));
|
||||||
|
elem.click();
|
||||||
|
|
||||||
styleObj = helper.getStyleStore(browser);
|
styleObj = helper.getStyleStore(browser);
|
||||||
assert.deepEqual(styleObj.layers, [
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
@ -54,7 +56,8 @@ describe("layers", function() {
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
browser.click(wd.$("layer-list-item:"+id+":copy", ""));
|
const elem = $(wd.$("layer-list-item:"+id+":copy", ""));
|
||||||
|
elem.click();
|
||||||
|
|
||||||
styleObj = helper.getStyleStore(browser);
|
styleObj = helper.getStyleStore(browser);
|
||||||
assert.deepEqual(styleObj.layers, [
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
@ -83,7 +86,8 @@ describe("layers", function() {
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
browser.click(wd.$("layer-list-item:"+id+":toggle-visibility", ""));
|
const elem = $(wd.$("layer-list-item:"+id+":toggle-visibility", ""));
|
||||||
|
elem.click();
|
||||||
|
|
||||||
styleObj = helper.getStyleStore(browser);
|
styleObj = helper.getStyleStore(browser);
|
||||||
assert.deepEqual(styleObj.layers, [
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
@ -96,7 +100,7 @@ describe("layers", function() {
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
browser.click(wd.$("layer-list-item:"+id+":toggle-visibility", ""));
|
elem.click();
|
||||||
|
|
||||||
styleObj = helper.getStyleStore(browser);
|
styleObj = helper.getStyleStore(browser);
|
||||||
assert.deepEqual(styleObj.layers, [
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
@ -147,11 +151,13 @@ describe("layers", function() {
|
||||||
// Setup
|
// Setup
|
||||||
var id = uuid();
|
var id = uuid();
|
||||||
|
|
||||||
browser.selectByValue(wd.$("add-layer.layer-type", "select"), "background");
|
const selectBox = $(wd.$("add-layer.layer-type", "select"));
|
||||||
|
selectBox.selectByAttribute('value', "background");
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
browser.setValueSafe(wd.$("add-layer.layer-id", "input"), "background:"+id);
|
browser.setValueSafe(wd.$("add-layer.layer-id", "input"), "background:"+id);
|
||||||
|
|
||||||
browser.click(wd.$("add-layer"));
|
const elem = $(wd.$("add-layer"));
|
||||||
|
elem.click();
|
||||||
|
|
||||||
var styleObj = helper.getStyleStore(browser);
|
var styleObj = helper.getStyleStore(browser);
|
||||||
assert.deepEqual(styleObj.layers, [
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
@ -169,11 +175,13 @@ describe("layers", function() {
|
||||||
it("id", function() {
|
it("id", function() {
|
||||||
var bgId = createBackground();
|
var bgId = createBackground();
|
||||||
|
|
||||||
browser.click(wd.$("layer-list-item:background:"+bgId))
|
const elem = $(wd.$("layer-list-item:background:"+bgId));
|
||||||
|
elem.click();
|
||||||
|
|
||||||
var id = uuid();
|
var id = uuid();
|
||||||
browser.setValueSafe(wd.$("layer-editor.layer-id", "input"), "foobar:"+id)
|
browser.setValueSafe(wd.$("layer-editor.layer-id", "input"), "foobar:"+id)
|
||||||
browser.click(wd.$("min-zoom"))
|
const elem2 = $(wd.$("min-zoom"));
|
||||||
|
elem2.click();
|
||||||
|
|
||||||
var styleObj = helper.getStyleStore(browser);
|
var styleObj = helper.getStyleStore(browser);
|
||||||
assert.deepEqual(styleObj.layers, [
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
@ -190,9 +198,11 @@ describe("layers", function() {
|
||||||
it("min-zoom", function() {
|
it("min-zoom", function() {
|
||||||
var bgId = createBackground();
|
var bgId = createBackground();
|
||||||
|
|
||||||
browser.click(wd.$("layer-list-item:background:"+bgId))
|
const elem = $(wd.$("layer-list-item:background:"+bgId));
|
||||||
|
elem.click();
|
||||||
browser.setValueSafe(wd.$("min-zoom", "input"), 1)
|
browser.setValueSafe(wd.$("min-zoom", "input"), 1)
|
||||||
browser.click(wd.$("layer-editor.layer-id", "input"));
|
const elem2 = $(wd.$("layer-editor.layer-id", "input"));
|
||||||
|
elem2.click();
|
||||||
|
|
||||||
var styleObj = helper.getStyleStore(browser);
|
var styleObj = helper.getStyleStore(browser);
|
||||||
assert.deepEqual(styleObj.layers, [
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
@ -220,9 +230,11 @@ describe("layers", function() {
|
||||||
it("max-zoom", function() {
|
it("max-zoom", function() {
|
||||||
var bgId = createBackground();
|
var bgId = createBackground();
|
||||||
|
|
||||||
browser.click(wd.$("layer-list-item:background:"+bgId))
|
const elem = $(wd.$("layer-list-item:background:"+bgId));
|
||||||
|
elem.click();
|
||||||
browser.setValueSafe(wd.$("max-zoom", "input"), 1)
|
browser.setValueSafe(wd.$("max-zoom", "input"), 1)
|
||||||
browser.click(wd.$("layer-editor.layer-id", "input"));
|
const elem2 = $(wd.$("layer-editor.layer-id", "input"));
|
||||||
|
elem2.click();
|
||||||
|
|
||||||
var styleObj = helper.getStyleStore(browser);
|
var styleObj = helper.getStyleStore(browser);
|
||||||
assert.deepEqual(styleObj.layers, [
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
@ -238,9 +250,11 @@ describe("layers", function() {
|
||||||
var bgId = createBackground();
|
var bgId = createBackground();
|
||||||
var id = uuid();
|
var id = uuid();
|
||||||
|
|
||||||
browser.click(wd.$("layer-list-item:background:"+bgId));
|
const elem = $(wd.$("layer-list-item:background:"+bgId));
|
||||||
|
elem.click();
|
||||||
browser.setValueSafe(wd.$("layer-comment", "textarea"), id);
|
browser.setValueSafe(wd.$("layer-comment", "textarea"), id);
|
||||||
browser.click(wd.$("layer-editor.layer-id", "input"));
|
const elem2 = $(wd.$("layer-editor.layer-id", "input"));
|
||||||
|
elem2.click();
|
||||||
|
|
||||||
var styleObj = helper.getStyleStore(browser);
|
var styleObj = helper.getStyleStore(browser);
|
||||||
assert.deepEqual(styleObj.layers, [
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
@ -484,4 +498,3 @@ describe("layers", function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,14 +7,16 @@ var helper = require("../helper");
|
||||||
|
|
||||||
function closeModal(wdKey) {
|
function closeModal(wdKey) {
|
||||||
browser.waitUntil(function() {
|
browser.waitUntil(function() {
|
||||||
return browser.isVisibleWithinViewport(wd.$(wdKey));
|
const elem = $(wdKey);
|
||||||
|
return elem.isDisplayedInViewport();
|
||||||
});
|
});
|
||||||
|
|
||||||
var closeBtnSelector = wd.$(wdKey+".close-modal");
|
const closeBtnSelector = $(wd.$(wdKey+".close-modal"));
|
||||||
browser.click(closeBtnSelector);
|
closeBtnSelector.click();
|
||||||
|
|
||||||
browser.waitUntil(function() {
|
browser.waitUntil(function() {
|
||||||
return !browser.isVisibleWithinViewport(wd.$(wdKey));
|
const elem = $(wdKey);
|
||||||
|
return !elem.isDisplayed();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,10 +28,12 @@ describe("modals", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
browser.url(config.baseUrl+"?debug");
|
browser.url(config.baseUrl+"?debug");
|
||||||
|
|
||||||
browser.waitForExist(".maputnik-toolbar-link");
|
const elem = $(".maputnik-toolbar-link");
|
||||||
|
elem.waitForExist();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.click(wd.$("nav:open"))
|
const elem2 = $(wd.$("nav:open"));
|
||||||
|
elem2.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -37,8 +41,10 @@ describe("modals", function() {
|
||||||
closeModal("open-modal");
|
closeModal("open-modal");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("upload", function() {
|
// "chooseFile" command currently not available for wdio v5 https://github.com/webdriverio/webdriverio/pull/3632
|
||||||
browser.waitForExist("*[type='file']")
|
it.skip("upload", function() {
|
||||||
|
const elem = $("*[type='file']");
|
||||||
|
elem.waitForExist();
|
||||||
browser.chooseFile("*[type='file']", styleFilePath);
|
browser.chooseFile("*[type='file']", styleFilePath);
|
||||||
|
|
||||||
var styleObj = helper.getStyleStore(browser);
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
@ -50,8 +56,8 @@ describe("modals", function() {
|
||||||
|
|
||||||
browser.setValueSafe(wd.$("open-modal.url.input"), styleFileUrl);
|
browser.setValueSafe(wd.$("open-modal.url.input"), styleFileUrl);
|
||||||
|
|
||||||
var selector = wd.$("open-modal.url.button");
|
const selector = $(wd.$("open-modal.url.button"));
|
||||||
browser.click(selector);
|
selector.click();
|
||||||
|
|
||||||
// Allow the network request to happen
|
// Allow the network request to happen
|
||||||
// NOTE: Its localhost so this should be fast.
|
// NOTE: Its localhost so this should be fast.
|
||||||
|
@ -70,10 +76,12 @@ describe("modals", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
browser.url(config.baseUrl+"?debug");
|
browser.url(config.baseUrl+"?debug");
|
||||||
|
|
||||||
browser.waitForExist(".maputnik-toolbar-link");
|
const elem = $(".maputnik-toolbar-link");
|
||||||
|
elem.waitForExist();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.click(wd.$("nav:export"))
|
const elem2 = $(wd.$("nav:export"));
|
||||||
|
elem2.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -99,9 +107,10 @@ describe("modals", 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();
|
||||||
|
|
||||||
browser.selectByValue(wd.$("nav:inspect", "select"), "inspect");
|
const selectBox = $(wd.$("nav:inspect", "select"));
|
||||||
|
selectBox.selectByAttribute('value', "inspect");
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -109,16 +118,19 @@ describe("modals", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
browser.url(config.baseUrl+"?debug");
|
browser.url(config.baseUrl+"?debug");
|
||||||
|
|
||||||
browser.waitForExist(".maputnik-toolbar-link");
|
const elem = $(".maputnik-toolbar-link");
|
||||||
|
elem.waitForExist();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.click(wd.$("nav:settings"))
|
const elem2 = $(wd.$("nav:settings"));
|
||||||
|
elem2.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("name", function() {
|
it("name", function() {
|
||||||
browser.setValueSafe(wd.$("modal-settings.name"), "foobar")
|
browser.setValueSafe(wd.$("modal-settings.name"), "foobar")
|
||||||
browser.click(wd.$("modal-settings.owner"))
|
const elem = $(wd.$("modal-settings.owner"));
|
||||||
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
var styleObj = helper.getStyleStore(browser);
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
@ -126,7 +138,8 @@ describe("modals", function() {
|
||||||
})
|
})
|
||||||
it("owner", function() {
|
it("owner", function() {
|
||||||
browser.setValueSafe(wd.$("modal-settings.owner"), "foobar")
|
browser.setValueSafe(wd.$("modal-settings.owner"), "foobar")
|
||||||
browser.click(wd.$("modal-settings.name"))
|
const elem = $(wd.$("modal-settings.name"));
|
||||||
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
var styleObj = helper.getStyleStore(browser);
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
@ -134,7 +147,8 @@ describe("modals", function() {
|
||||||
})
|
})
|
||||||
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")
|
||||||
browser.click(wd.$("modal-settings.name"))
|
const elem = $(wd.$("modal-settings.name"));
|
||||||
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
var styleObj = helper.getStyleStore(browser);
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
@ -143,7 +157,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)
|
||||||
browser.click(wd.$("modal-settings.name"))
|
const elem = $(wd.$("modal-settings.name"));
|
||||||
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
var styleObj = helper.getStyleStore(browser);
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
@ -153,7 +168,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);
|
||||||
browser.click(wd.$("modal-settings.name"))
|
const elem = $(wd.$("modal-settings.name"));
|
||||||
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
var styleObj = helper.getStyleStore(browser);
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
@ -165,7 +181,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);
|
||||||
browser.click(wd.$("modal-settings.name"))
|
const elem = $(wd.$("modal-settings.name"));
|
||||||
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
var styleObj = helper.getStyleStore(browser);
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
@ -175,7 +192,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);
|
||||||
browser.click(wd.$("modal-settings.name"))
|
const elem = $(wd.$("modal-settings.name"));
|
||||||
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
var styleObj = helper.getStyleStore(browser);
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
@ -183,9 +201,10 @@ describe("modals", function() {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("style renderer", function() {
|
it("style renderer", function() {
|
||||||
var selector = wd.$("modal-settings.maputnik:renderer");
|
const selector = $(wd.$("modal-settings.maputnik:renderer"));
|
||||||
browser.selectByValue(selector, "ol");
|
selector.selectByAttribute('value', "ol");
|
||||||
browser.click(wd.$("modal-settings.name"))
|
const elem = $(wd.$("modal-settings.name"));
|
||||||
|
elem.click();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
var styleObj = helper.getStyleStore(browser);
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
|
|
@ -8,18 +8,16 @@ var wd = require("../../wd-helper");
|
||||||
describe('screenshots', function() {
|
describe('screenshots', function() {
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
browser.windowHandleSize({
|
browser.setWindowSize(1280, 800)
|
||||||
width: 1280,
|
|
||||||
height: 800
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("front_page", function() {
|
it("front_page", 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();
|
||||||
browser.waitForExist(".maputnik-toolbar-link");
|
const elem = $(".maputnik-toolbar-link");
|
||||||
|
elem.waitForExist();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.takeScreenShot("/front_page.png")
|
browser.takeScreenShot("/front_page.png")
|
||||||
|
@ -29,11 +27,13 @@ describe('screenshots', 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();
|
||||||
browser.waitForExist(".maputnik-toolbar-link");
|
const elem = $(".maputnik-toolbar-link");
|
||||||
|
elem.waitForExist();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.click(wd.$("nav:open"))
|
const nav_open = $(wd.$("nav:open"));
|
||||||
|
nav_open.waitForExist();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.takeScreenShot("/open.png")
|
browser.takeScreenShot("/open.png")
|
||||||
|
@ -43,11 +43,13 @@ describe('screenshots', 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();
|
||||||
browser.waitForExist(".maputnik-toolbar-link");
|
const elem = $(".maputnik-toolbar-link")
|
||||||
|
elem.waitForExist()
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.click(wd.$("nav:export"))
|
const nav_export = $(wd.$("nav:export"));
|
||||||
|
nav_export.waitForExist();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.takeScreenShot("/export.png")
|
browser.takeScreenShot("/export.png")
|
||||||
|
@ -57,11 +59,13 @@ describe('screenshots', 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();
|
||||||
browser.waitForExist(".maputnik-toolbar-link");
|
const elem = $(".maputnik-toolbar-link")
|
||||||
|
elem.waitForExist()
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.click(wd.$("nav:sources"))
|
const nav_sources = $(wd.$("nav:sources"));
|
||||||
|
nav_sources.waitForExist();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.takeScreenShot("/sources.png")
|
browser.takeScreenShot("/sources.png")
|
||||||
|
@ -71,11 +75,13 @@ describe('screenshots', 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();
|
||||||
browser.waitForExist(".maputnik-toolbar-link");
|
const elem = $(".maputnik-toolbar-link")
|
||||||
|
elem.waitForExist()
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.click(wd.$("nav:settings"))
|
const nav_settings = $(wd.$("nav:settings"));
|
||||||
|
nav_settings.waitForExist();
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.takeScreenShot("/settings.png")
|
browser.takeScreenShot("/settings.png")
|
||||||
|
@ -85,11 +91,14 @@ describe('screenshots', 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();
|
||||||
browser.waitForExist(".maputnik-toolbar-link");
|
const elem = $(".maputnik-toolbar-link")
|
||||||
|
elem.waitForExist()
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.selectByValue(wd.$("nav:inspect", "select"), "inspect");
|
const selectBox = $(wd.$("nav:inspect", "select"));
|
||||||
|
selectBox.selectByAttribute('value', 'inspect');
|
||||||
|
|
||||||
browser.flushReactUpdates();
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
browser.takeScreenShot("/inspect.png")
|
browser.takeScreenShot("/inspect.png")
|
||||||
|
|
|
@ -3,8 +3,8 @@ var fs = require("fs");
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
|
|
||||||
|
|
||||||
browser.timeoutsAsyncScript(20*1000);
|
browser.setTimeout({ 'script': 20*1000 });
|
||||||
browser.timeoutsImplicitWait(20*1000);
|
browser.setTimeout({ 'implicit': 20*1000 });
|
||||||
|
|
||||||
var SCREENSHOTS_PATH = artifacts.pathSync("/screenshots");
|
var SCREENSHOTS_PATH = artifacts.pathSync("/screenshots");
|
||||||
|
|
||||||
|
@ -16,15 +16,18 @@ var SCREENSHOTS_PATH = artifacts.pathSync("/screenshots");
|
||||||
try {
|
try {
|
||||||
browser.addCommand('setValueSafe', function(selector, text) {
|
browser.addCommand('setValueSafe', function(selector, text) {
|
||||||
for(var i=0; i<10; i++) {
|
for(var i=0; i<10; i++) {
|
||||||
browser.waitForVisible(selector);
|
const elem = $(selector);
|
||||||
|
elem.waitForDisplayed(500);
|
||||||
|
|
||||||
var elements = browser.elements(selector);
|
var elements = browser.findElements("css selector", selector);
|
||||||
if(elements.length > 1) {
|
if(elements.length > 1) {
|
||||||
throw "Too many elements found";
|
throw "Too many elements found";
|
||||||
}
|
}
|
||||||
|
|
||||||
browser.setValue(selector, text);
|
const elem2 = $(selector);
|
||||||
var browserText = browser.getValue(selector);
|
elem2.setValue(text);
|
||||||
|
|
||||||
|
var browserText = elem2.getValue();
|
||||||
|
|
||||||
if(browserText == text) {
|
if(browserText == text) {
|
||||||
return;
|
return;
|
||||||
|
@ -39,7 +42,7 @@ try {
|
||||||
})
|
})
|
||||||
|
|
||||||
browser.addCommand('takeScreenShot', function(filepath) {
|
browser.addCommand('takeScreenShot', function(filepath) {
|
||||||
var data = browser.screenshot();
|
var data = browser.takeScreenshot();
|
||||||
fs.writeFileSync(path.join(SCREENSHOTS_PATH, filepath), data.value, 'base64');
|
fs.writeFileSync(path.join(SCREENSHOTS_PATH, filepath), data.value, 'base64');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue