├── .gitignore ├── .babelrc ├── .editorconfig ├── src ├── js │ ├── index.js │ └── MapController.js ├── css │ └── style.scss └── index.html ├── tests ├── MapController.spec.js └── main.js ├── LICENSE ├── README.md ├── package.json ├── karma.conf.js ├── .eslintrc.json ├── dist ├── js │ ├── index.js │ └── MapController.js └── index.html └── gulpfile.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode 3 | coverage -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015-without-strict"], 3 | "plugins": ["transform-es2015-modules-simple-amd"] 4 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /src/js/index.js: -------------------------------------------------------------------------------- 1 | import MapController from 'app/MapController'; 2 | 3 | const mapNode = document.createElement('div'); 4 | mapNode.id = 'map'; 5 | document.getElementById('app').appendChild(mapNode); 6 | 7 | const mc = new MapController(mapNode); 8 | 9 | document.getElementById('changeBasemap').addEventListener('click', () => { 10 | mc.changeBasemap('osm'); 11 | }); -------------------------------------------------------------------------------- /src/css/style.scss: -------------------------------------------------------------------------------- 1 | @import "../../node_modules/bootstrap/scss/bootstrap.scss"; 2 | 3 | html, body { 4 | margin: 0; 5 | padding: 0; 6 | height: 100%; 7 | width: 100%; 8 | } 9 | 10 | // Padding for top navbar 11 | body { 12 | padding-top: 3.5rem; 13 | 14 | .container-fluid { 15 | padding: 0; 16 | height: 100%; 17 | } 18 | } 19 | 20 | #map { 21 | width: 100%; 22 | height: 100%; 23 | } -------------------------------------------------------------------------------- /src/js/MapController.js: -------------------------------------------------------------------------------- 1 | import Map from 'esri/Map'; 2 | import MapView from 'esri/views/MapView'; 3 | 4 | class MapController { 5 | constructor(node) { 6 | this._map = new Map({ 7 | basemap: 'streets' 8 | }); 9 | 10 | this._mapView = new MapView({ 11 | container: node, 12 | map: this._map 13 | }); 14 | } 15 | 16 | changeBasemap(newMap) { 17 | this._map.basemap = newMap; 18 | } 19 | } 20 | 21 | export default MapController; -------------------------------------------------------------------------------- /tests/MapController.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-env jasmine, browser */ 2 | /* eslint no-var: "off" */ 3 | define([ 4 | 'app/MapController' 5 | ], function ( 6 | MapController 7 | ) { 8 | 9 | describe('MapController tests', function () { 10 | it('Should create a map upon creation', function () { 11 | var mapNode = document.createElement('div'); 12 | document.body.appendChild(mapNode); 13 | var mc = new MapController(mapNode); 14 | expect(mapNode.classList.contains('esri-view')).toBeTruthy(); 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 Alex Urquhart 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ArcGIS JavaScript API Starter 2 | 3 | - ArcGIS JavaScript API v4 4 | - Bootstrap v4 5 | - ES6 code transpiling using Babel 6 | - Testing w/ Karma & Jasmine 7 | 8 | ## Install 9 | ``` 10 | > npm install 11 | ``` 12 | 13 | ## Develop 14 | ``` 15 | > gulp watch 16 | ``` 17 | 18 | Navigate to [http://localhost:8080/index.html](http://localhost:8080/index.html) 19 | 20 | Install [LiveReload](https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei?hl=en) plugin, or add 21 | livereload script to `index.html`. 22 | 23 | ## Test 24 | ``` 25 | > gulp test 26 | ``` 27 | 28 | ## Build production copy 29 | ``` 30 | > gulp 31 | ``` 32 | 33 | ## Custom Bootstrap Styles 34 | 35 | Edit override variables in `src/css/style.css` 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "es6-dev", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "babel": "^6.23.0", 13 | "babel-plugin-transform-es2015-modules-simple-amd": "^0.3.0", 14 | "babel-preset-es2015-without-strict": "0.0.4", 15 | "bootstrap": "^4.0.0-alpha.6", 16 | "del": "^2.2.2", 17 | "eslint": "^3.18.0", 18 | "gulp": "^3.9.1", 19 | "gulp-babel": "^6.1.2", 20 | "gulp-livereload": "^3.8.1", 21 | "gulp-sass": "^3.1.0", 22 | "gulp-sourcemaps": "^2.4.1", 23 | "gulp-uglify": "^2.1.2", 24 | "jasmine": "^2.5.3", 25 | "karma": "^1.5.0", 26 | "karma-chrome-launcher": "^2.0.0", 27 | "karma-coverage": "^1.1.1", 28 | "karma-dojo": "0.0.1", 29 | "karma-jasmine": "^1.1.0", 30 | "st": "^1.2.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Configuration file from: https://github.com/tomwayson/esri-karma-tutorial 2 | module.exports = function(config) { 3 | config.set({ 4 | basePath: '', 5 | 6 | frameworks: ['jasmine', 'dojo'], 7 | 8 | files: [ 9 | 'tests/main.js', 10 | {pattern: 'dist/**/*.js', included: false}, 11 | {pattern: 'tests/*.js', included: false} 12 | ], 13 | 14 | reporters: [ 15 | 'dots', 16 | 'coverage' 17 | ], 18 | 19 | coverageReporter: { 20 | type : 'html', 21 | dir : 'coverage/' 22 | }, 23 | 24 | preprocessors: { 25 | 'dist/**/*.js': ['coverage'] 26 | }, 27 | 28 | port: 9876, 29 | 30 | // proxy for cross domain requests 31 | // proxies: { 32 | // '/arcgis/': 'http://imagery.arcgisonline.com/arcgis/' 33 | // }, 34 | 35 | // cli runner port 36 | runnerPort: 9100, 37 | 38 | colors: true, 39 | 40 | logLevel: config.LOG_INFO, 41 | 42 | autoWatch: true, 43 | 44 | browsers: [ 45 | 'Chrome' 46 | ], 47 | 48 | plugins: [ 49 | 'karma-dojo', 50 | 'karma-jasmine', 51 | 'karma-chrome-launcher', 52 | 'karma-coverage' 53 | ], 54 | 55 | singleRun: false 56 | }); 57 | }; -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "parserOptions": { 4 | "sourceType": "module" 5 | }, 6 | "env": { 7 | "browser": true, 8 | "node": true, 9 | "amd": true, 10 | "es6": true 11 | }, 12 | "rules": { 13 | "consistent-return": 2, 14 | "curly": [1,"all"], 15 | "default-case": 2, 16 | "dot-notation": [2,{"allowKeywords":true}], 17 | "dot-location": 2, 18 | "eqeqeq": 1, 19 | "guard-for-in": 1, 20 | "no-else-return": 1, 21 | "no-labels": 2, 22 | "no-eq-null": 2, 23 | "no-eval": 2, 24 | "no-floating-decimal": 2, 25 | "no-loop-func": 1, 26 | "no-multi-spaces": 1, 27 | "no-native-reassign": 2, 28 | "no-new-wrappers": 1, 29 | "no-new": 1, 30 | "no-return-assign": 1, 31 | "no-useless-call": 1, 32 | "no-void": 2, 33 | "strict": 1, 34 | "no-undef-init": 2, 35 | "brace-style": [1,"1tbs",{}], 36 | "camelcase": [1,{"properties":"always"}], 37 | "comma-style": 1, 38 | "consistent-this": [1,"self"], 39 | "indent": [1,2], 40 | "no-array-constructor": 1, 41 | "no-nested-ternary": 2, 42 | "no-trailing-spaces": [1,{"skipBlankLines":false}], 43 | "no-unneeded-ternary": 1, 44 | "quotes": [1,"single","avoid-escape"], 45 | "semi": [1,"always"], 46 | "no-var": 2, 47 | "no-console": 0 48 | } 49 | } -------------------------------------------------------------------------------- /dist/js/index.js: -------------------------------------------------------------------------------- 1 | define(['app/MapController'], function (MapController) { 2 | 3 | var mapNode = document.createElement('div'); 4 | mapNode.id = 'map'; 5 | document.getElementById('app').appendChild(mapNode); 6 | 7 | var mc = new MapController(mapNode); 8 | 9 | document.getElementById('changeBasemap').addEventListener('click', function () { 10 | mc.changeBasemap('osm'); 11 | }); 12 | }); 13 | //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImpzL2luZGV4LmpzIl0sIm5hbWVzIjpbIk1hcENvbnRyb2xsZXIiLCJtYXBOb2RlIiwiZG9jdW1lbnQiLCJjcmVhdGVFbGVtZW50IiwiaWQiLCJnZXRFbGVtZW50QnlJZCIsImFwcGVuZENoaWxkIiwibWMiLCJhZGRFdmVudExpc3RlbmVyIiwiY2hhbmdlQmFzZW1hcCJdLCJtYXBwaW5ncyI6IlFBQTBCLG1CLGFBQW5CQSxhOztBQUVQLE1BQU1DLFVBQVVDLFNBQVNDLGFBQVQsQ0FBdUIsS0FBdkIsQ0FBaEI7QUFDQUYsVUFBUUcsRUFBUixHQUFhLEtBQWI7QUFDQUYsV0FBU0csY0FBVCxDQUF3QixLQUF4QixFQUErQkMsV0FBL0IsQ0FBMkNMLE9BQTNDOztBQUVBLE1BQU1NLEtBQUssSUFBSVAsYUFBSixDQUFrQkMsT0FBbEIsQ0FBWDs7QUFFQUMsV0FBU0csY0FBVCxDQUF3QixlQUF4QixFQUF5Q0csZ0JBQXpDLENBQTBELE9BQTFELEVBQW1FLFlBQU07QUFDdkVELE9BQUdFLGFBQUgsQ0FBaUIsS0FBakI7QUFDRCxHQUZEIiwiZmlsZSI6ImpzL2luZGV4LmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IE1hcENvbnRyb2xsZXIgZnJvbSAnYXBwL01hcENvbnRyb2xsZXInO1xuXG5jb25zdCBtYXBOb2RlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG5tYXBOb2RlLmlkID0gJ21hcCc7XG5kb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYXBwJykuYXBwZW5kQ2hpbGQobWFwTm9kZSk7XG5cbmNvbnN0IG1jID0gbmV3IE1hcENvbnRyb2xsZXIobWFwTm9kZSk7XG5cbmRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjaGFuZ2VCYXNlbWFwJykuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB7XG4gIG1jLmNoYW5nZUJhc2VtYXAoJ29zbScpO1xufSk7Il19 14 | -------------------------------------------------------------------------------- /tests/main.js: -------------------------------------------------------------------------------- 1 | (function (window) { 2 | 3 | let allTestFiles = []; 4 | let TEST_REGEXP = /.*spec\.js$/; 5 | 6 | for (let file in window.__karma__.files) { 7 | if (TEST_REGEXP.test(file)) { 8 | allTestFiles.push(file); 9 | } 10 | } 11 | 12 | const API_LOCATION = 'http://js.arcgis.com/4.3/'; 13 | 14 | 15 | window.dojoConfig = { 16 | packages: [ 17 | // local pacakges to test 18 | { 19 | name: 'app', 20 | location: '/base/dist/js' 21 | }, 22 | 23 | // esri/dojo packages 24 | { 25 | name: 'dgrid', 26 | location: API_LOCATION + 'dgrid' 27 | }, { 28 | name: 'dijit', 29 | location: API_LOCATION + 'dijit' 30 | }, { 31 | name: 'esri', 32 | location: API_LOCATION + 'esri' 33 | }, { 34 | name: 'dojo', 35 | location: API_LOCATION + 'dojo' 36 | }, { 37 | name: 'dojox', 38 | location: API_LOCATION + 'dojox' 39 | }, { 40 | name: 'put-selector', 41 | location: API_LOCATION + 'put-selector' 42 | }, { 43 | name: 'util', 44 | location: API_LOCATION + 'util' 45 | }, { 46 | name: 'xstyle', 47 | location: API_LOCATION + 'xstyle' 48 | }, { 49 | name: 'moment', 50 | location: API_LOCATION + 'moment' 51 | } 52 | ], 53 | async: true 54 | }; 55 | 56 | /** 57 | * This function must be defined and is called back by the dojo adapter 58 | * @returns {string} a list of dojo spec/test modules to register with your testing framework 59 | */ 60 | window.__karma__.dojoStart = function () { 61 | return allTestFiles; 62 | }; 63 | })(window); 64 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const babel = require('gulp-babel'); 3 | const sass = require('gulp-sass'); 4 | const uglify = require('gulp-uglify'); 5 | const sourcemaps = require('gulp-sourcemaps'); 6 | const del = require('del'); 7 | const Server = require('karma').Server; 8 | const livereload = require('gulp-livereload'); 9 | const st = require('st'); 10 | const http = require('http'); 11 | 12 | gulp.task('babel:debug', () => { 13 | return gulp.src('src/**/*.js'). 14 | pipe(sourcemaps.init()). 15 | pipe(babel()). 16 | pipe(sourcemaps.write()). 17 | pipe(gulp.dest('dist/')). 18 | pipe(livereload()); 19 | }); 20 | 21 | gulp.task('babel:prod', () => { 22 | return gulp.src('src/**/*.js'). 23 | pipe(babel()). 24 | pipe(uglify()). 25 | pipe(gulp.dest('dist/')). 26 | pipe(livereload()); 27 | }); 28 | 29 | gulp.task('sass:debug', () => { 30 | return gulp.src('src/css/style.scss'). 31 | pipe(sourcemaps.init()). 32 | pipe(sass().on('error', sass.logError)). 33 | pipe(sourcemaps.write()). 34 | pipe(gulp.dest('dist/css')). 35 | pipe(livereload()); 36 | }); 37 | 38 | gulp.task('sass:prod', () => { 39 | return gulp.src('src/css/style.scss'). 40 | pipe(sass({ 41 | outputStyle: 'compressed' 42 | }).on('error', sass.logError)). 43 | pipe(gulp.dest('dist/css')). 44 | pipe(livereload()); 45 | }); 46 | 47 | gulp.task('clean', (done) => { 48 | return del(['dist/**/*']).then(() => done()); 49 | }); 50 | 51 | gulp.task('copy', () => { 52 | return gulp.src('src/**/*.!(js|scss)'). 53 | pipe(gulp.dest('dist/')). 54 | pipe(livereload()); 55 | }); 56 | 57 | gulp.task('server', (done) => { 58 | http.createServer( 59 | st({ 60 | path: `${__dirname}/dist`, 61 | index: 'index.html', 62 | cache: false 63 | }) 64 | ).listen(8080, done); 65 | }); 66 | 67 | gulp.task('watch', ['server'], () => { 68 | livereload.listen({ 69 | basePath: `${__dirname}/dist`, 70 | }); 71 | gulp.watch('src/**/*.js', ['babel:debug']); 72 | gulp.watch('src/**/*.scss', ['sass:debug']); 73 | gulp.watch('src/**/*.!(js|scss)', ['copy']); 74 | }); 75 | 76 | gulp.task('test', (done) => { 77 | const s = new Server({ 78 | configFile: `${__dirname}/karma.conf.js` 79 | }, done); 80 | s.start(); 81 | }); 82 | 83 | gulp.task('default', ['babel:prod', 'sass:prod', 'copy']); 84 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 |